OmniAICreator/Qiita-1.07M huggingface dataset:
OptunaのintegrationにあるLightGBM Tunerのデフォルト探索範囲

# はじめに
Optunaにはimportして使うだけでLightGBMのパラメータ探索までやってくれる便利なモジュールが存在する。それがOptunaのintegrationに入っている。しかし、公式ドキュメントを見てもGitHubのコードに飛ばされるだけで、どのパラメータをどの範囲で探索しているのかは公開されていない。

そこでデフォルトの探索範囲をしっかり確認してみようと思う。

# 結論
```python:パラメータ探索範囲
{
    "lambda_l1": {"min": 1e-8, "max": 10.0, "log": True},
    "lambda_l2": {"min": 1e-8, "max": 10.0, "log": True},
    "num_leaves": {"min": 2, "max": 16},
    "feature_fraction": {"min": 0.4, "max": 1.0 + 1e-12},
    "bagging_fraction": {"min": 0.4, "max": 1.0 + 1e-12},
    "bagging_freq": {"min": 1, "max": 7},
    "min_child_samples": {"min": 5, "max": 100}
}
```

# 説明

まず、`pip show optuna`を使用して、パッケージをインストールしているディレクトリに移動する。

`.../site-packages/optuna/integration/lightgbm_tuner/optimize.py` というファイルがあると思うので、この198行目から226行目あたり（バージョンによっては違うかも）に`_preprocess`という関数が定義されている。

定数として45, 48行目くらいに、`_DEFAULT_TUNER_TREE_DEPTH = 8`と、`_EPS = 1e-12`と定められています。

これらの部分からパラメータを抽出すると、以上のような結果になります。
AccessのVBAで外部テキストファイルを1行ずつ読み込み

# 概要

txtやcsvなど **テキストエディターで開けるファイル** を1行ずつ読み込んで処理。

# 参照設定

Microsoft ActiveX Data Objects 2.8 Library
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/de519680-e332-a52c-eee6-74bf7c120841.png)

# サンプル（1行目だけ）

```vb:
'フォームにbtn_1というボタンがあり、そのクリックイベントという想定。
Private Sub btn_1_Click()


    Dim stream_ As New ADODB.Stream
    
    'OpenはLoadFromFileより前に行っておく必要があるので注意。
    'LoadFromFile ⇒ Openの順だと例外になります。
    stream_.Open

    stream_.Charset = "UTF-8"
    'SJISの場合は下記。
    'stream_.Charset = "SJIS"
    
    'キャリッジリターンラインフィード来た = 行末まで来た　と判定。
    stream_.LineSeparator = adCRLF
    
    'Accessと同じフォルダーにあるtes.txtを読み込む。
    stream_.LoadFromFile CurrentProject.Path & "\tes.txt"
    
    '1行目だけ取り出して内容確認。
    Dim first_row_ As String
    first_row_ = stream_.ReadText(adReadLine)
    Debug.Print first_row_
    
    stream_.Close

    
End Sub
```

tes.txtが下記の時…
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/de2a93e2-4a68-4dfc-389c-9d69bd0897e1.png)

実行結果。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/403f635f-52d5-942b-5dca-c01b77d61083.png)

# サンプル（全行）

```vb:
Private Sub btn_1_Click()


    Dim stream_ As New ADODB.Stream
    stream_.Open
    stream_.Charset = "UTF-8"
    stream_.LineSeparator = adCRLF
    stream_.LoadFromFile CurrentProject.Path & "\tes.txt"

    Do Until stream_.EOS
        Debug.Print stream_.ReadText(adReadLine)
    Loop
    
    stream_.Close

    
End Sub
```

# 参考サイトさん

https://qiita.com/msht0511/items/34e8edea81a0c3ebb349

http://officetanaka.net/excel/vba/file/file10.htm

# バージョン

Microsoft Windows [Version 10.0.19045.4239]
Microsoft Access for Microsoft 365 MSO (バージョン 2403 ビルド 16.0.17425.20138) 32 ビット
情報系専門学校に入学して3年目で得たこと

# 専門学校に入学して3年目で得たこと

## はじめに

この記事では、私が専門学校に入学して3年目に得たことについて紹介します。
学んだ技術、取得した資格、取り組んだことなどを取り上げます。

## 取得した資格・認定

専門学校に入学して3年目に取得した資格は、以下の通りです。

- 2024/01/15：AWS Certified Solutions Architect – Associate

1つの資格試験に合格することができました。
1年目では7つ、2年目では3つ、3年目は1つとだんだんと取得する量は減ってきましたが、
だんだんと、「本を買って問題集で勉強」から「実際にコードを書いたり、サーバを立てたりしてみる」
というスタイルに変わってきているので、資格取得の量が減っても技術力は上がっていると感じています。

## 勉強した技術

専門学校に入学して3年目に勉強した技術は、以下の通りです。

### 学校で学習

- C#
- Swift
- Python
  - Flask
  - OpenCV
  - Matplotlib etc...
- Windows Server
  - Active Directory
- Kintone
- Power Automate

### 個人で学習

- TypeScript
- AWS
- Docker
- Python

以下が3年目で利用したUdemyの講座です。

- [【SAA-C03版】AWS認定ソリューションアーキテクト アソシエイト試験：短期突破講座（300問の演習問題）](https://www.udemy.com/share/103K5W3@yXwOotQ6LKH1VzBxnl_W0nCrmI2QOXPbWVbalpO0RcJ7TKI7YT_40H4WsQKw4sp0uA==/)

1,2年目よりもUdenyで勉強することは少なくなったように思います。
逆に、技術記事であったり、使用する技術の公式ドキュメントを読むことが多くなりました。

[Feedly](https://feedly.com/) というアプリ、サイトを使用して、Qiita や Zenn などを購読して、片っ端から読んでいました。

また、学校で学んだ技術を使って、個人でアプリケーションを作成することが多くなりました。
Python を学んだので友達との Discord サーバで使う bot を [Discord.py](https://discordpy.readthedocs.io/ja/latest/intro.html) を使用して作成したりしました。

ただ、やっぱり型の縛りが強いほうが開発がしやすいと感じてきているので、[Discord.js](https://discord.js.org/) を使用して TypeScript で bot を作成しようと考えています。

## 読んだ書籍

- [入門モダンLinux](https://www.oreilly.co.jp/books/9784814400218/)
  - 一年目で LPIC を取得していましたが、これらの知識を使う機会がなかったので、Linux についてもう一度勉強し直しました。
- [Python チュートリアル](https://www.oreilly.co.jp/books/9784873119359/)
  - 授業でも取り扱いましたが、個人的にも使うことが多かったので、少しだけ読みました。
  - でも、Pythonについては公式かWeb記事を読むことが多かったです。
- [ハンズオン Node.js](https://www.oreilly.co.jp/books/9784873119236/)
  - まだ読み切れていませんが、いたるところで Node.js が使われているので、しっかりと勉強していきたいと思います。
- [プログラミンング TypeScript](https://www.oreilly.co.jp/books/9784873119045/)
  - まだ読み切れていませんが、TypeScript についてもっと深く知りたいと思い購入しました。
- [React ハンズオンラーニング](https://www.oreilly.co.jp//books/9784873119380/)
  - Udemy 等で React については学んできましたが、Oriley の本も読んでみたいと思い購入しました。
  - やっぱり難しい…
- [作って学べる Unity 本格入門](https://www.amazon.co.jp/dp/4297130661)
  - せっかくプログラミングを学んだのだから、ゲームも作ってみたいと思い購入しました。
  - 私の PC がスペック不足だったのか、ファンがものすごい音を立てていたので、お給料でもっといい PC を解体と思いました。

3年目は1，2年目に比べて、技術書を読む量が減りました。
ただ、読んだ本はしっかりと理解しようと思い、読み返すことが多かったです。

また、「入門！」「〇〇でもわかる！」のような本よりも少し背伸びして難しい本を読むように心がけました。

変に長い言い回しが少ないのでむしろ読みやすい箇所があったりしましたが、やっぱりまだ難しいと感じるところもありました。

## 取り組んだこと・プロジェクト

専門学校に入学して3年目に取り組んだことは、以下の通りです。

- C# を使用した Windows アプリの開発
- Webアプリのチーム開発
- Python を使用した Discord bot の開発
- Python を利用した 様々なツールの開発
  - 画像を自動でリサイズするツール
  - ファイルを自動で整理するツール
  - 画像を自動でダウンロードするツール
  - 画像をPDFに変換するツール
  - PDF同士を結合するツール

Python が簡単にかけすぎて便利だと感じて、いろんなツールを作ってみました。

## まとめ

3年目は、1，2年目に比べて資格取得の量は減りましたが、技術力は上がっていると感じています。

3年間で学んだ技術を使って、自分でアプリケーションを作成することが多くなりました。
これで私も学校を卒業して社会人となっていきますが、変わらずに学び続けていきたいと思います。
【統計検定】準1級合格記 - 不合格を乗り越えて -

★参考にしたサイトはまだ沢山あるので追加していきます！
★「試験や不合格に対する考え」が特にお伝えしたい事です！

## はじめに
30代後半のフリーランスエンジニア(3ヵ月目)です。
AWS環境でのデータ基盤の構築に関する仕事に長く携わっておりますが、
データ分析業務自体は経験がありません。

#昨年SIerを退職し沖縄県の離島在住
#理系大学院を卒業(生物学)

## 合格までの過程
・前職在職中に統計検定2級を取得
・その後統計検定1級の勉強をするも挫折(準1級は範囲が広すぎて回避)
・退職後に時間ができたので準1級の勉強を開始(2023年9月～)
・3回目にして合格(2024年3月 )
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3328060/70e9b3cb-5f0a-3509-1779-9e46275f51cc.png)


## 勉強内容
・[ワークブック](https://www.gakujutsu.co.jp/product/978-4-7806-0852-6/)を基本に勉強+過去問
・最初の1周は理解がとても大変だし、2,3周目しても新しい気づきや不明点が沢山ある(´;ω;｀)
・勉強時間は計300～350時間程度
・長い期間勉強すると理解が深まるのですが、忘れてしまう事も多くなった(年齢かな、、)

## 試験や不合格に対する考え
CBTのテストはかなり難しく感じました。
「ワークブックをほぼ解ける」+「統計学の考えをもって問題文を考える」ことが必要
⇒ワークブックや過去問の暗記では足りないと思います。

なのでCBTに落ちたり、何回か受けることは気にしなくてよいと思う。
問題によっての難易度が変わることもあるので、私も59点→31点→75点と上下しました。
#財布には痛いですが、例えば毎月8000円資格取得に充てると考えれば計画は立てられる。

**ただこれは個人の思いなのですが**
**統計検定準1級の内容とCBTの試験はとても難しいので、**
**ワークブック・過去問をある程理解した人でも何回も落ちる可能性があり、**
**ずっと合格できない場合もあると思いました。**

なので不合格後に、このまま勉強を続ける or "諦める"ことをしっかり考えた方が良いです。
統計学の知識は必要と思いますが、固執していると仕事で生かすタイミングを逃すかもしれません。

## 今後に向けて
私はデータサイエンティストとしての業務経験がないことと、
現在データ基盤エンジニアとして安定稼働しているので、ジョブチェンジなどは考えていないです。
**ただデータサイエンティストとプロジェクトを進めるには、統計学の知識はとても役に立ちます。**
個人的にはkaggleや身の回りの事に対して、統計学の知識を活用してアウトプットしていきたいです！

#データサイエンティストは答えのない問題に対してアプローチする仕事と考えており、
#目指す際には色々な情報に接した方が良いでしょう。


## 参考にしたサイト
・ワークブック全体の理解
　[あつまれ統計の森](https://www.hello-statisticians.com/toukeikentei-semi1#google_vignette)

・過去問対策
　https://mimikousi.com/statistical-certificate-pre1-book/

 ・Youtube
　https://www.youtube.com/@Yuya-Kawaguchi
　https://www.youtube.com/@AIcia_Solid
　https://www.youtube.com/@toketarou
　その他たくさんのチャンネルにお世話になりました。
messageについて


~~~java
@Configuration
public class AppConfig {

    @Autowired
    private MessageSource messageSource;

    @Bean
    public String getMessage() {
        // プレースホルダーを置換する値の配列
        Object[] args = {"John", "Doe"};
        
        // ロケールを取得
        Locale locale = LocaleContextHolder.getLocale();

        // MessageSourceResolvableを使用してメッセージを取得
        MessageSourceResolvable resolvable = new DefaultMessageSourceResolvable("hello.message", args, "Default message", locale);
        String message = messageSource.getMessage(resolvable, locale);
        
        return message;
    }

    @Bean
    public MessageSource messageSource() {
        ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
        messageSource.setBasename("classpath:message");
        messageSource.setDefaultEncoding("UTF-8");
        return messageSource;
    }
}
~~~
~~~java
@Service
public class LoggingService {

    @Autowired
    private MessageSource messageSource;

    public void logHelloMessage() {
        String helloMessage = messageSource.getMessage("logging.message.hello", null, null);
        System.out.println(helloMessage);
    }

    public void logErrorMessage(String error) {
        String errorMessage = messageSource.getMessage("logging.message.error", new Object[]{error}, null);
        System.out.println(errorMessage);
    }
}
~~~
近似最近傍探索ライブラリvoyagerのお試しメモ

# 近傍探索お試し
spotifyさんが新しく公開した近傍探索ライブラリのvoyagerを使用した類似画像検索を試してみます。

とりあえずパパっと動かしたメモなので詳細な性能検証ではないです。

https://spotify.github.io/voyager/
https://github.com/spotify/voyager

## 先に結論いろいろ

### 前提
- 約57万枚の画像を使用
- 画像を768次元の埋め込みベクトルにして利用

### 結果
- 57万のデータからインデックスを作成 → 約82.7秒 (修正・再計測中)
- クエリとなる画像を渡しtop15を取得 → 約0.23秒
    - 検索部分のみの時間です。実際の検索はクエリ画像をエンコードしたりでもう少しかかる
- 実際に検索した例は[後述](https://qiita.com/#%E6%A4%9C%E7%B4%A2%E7%B5%90%E6%9E%9C)


追記：
ミス発見。
検索時間はもう少し速かったです。上記の0.23秒は近傍探索＋必要な情報の付与（テーブルのjoin処理）を行ったものでした。
実際に利用する場合はこんなもん、という程度で見ていただければ。

### 結論
簡単。速い。すごい。


# リソース関連メモ
画像生成周りの情報も残しておきます。
案外、このへんの「個人向けPCでやると実際どのくらいかかるの？」という情報少ないので。

## PCスペック
CPU: Core i7-13700
Mem: 64GB
GPU: RTX-4070(VRAM:12GB)

2024年時点の個人向けPCとしては最高スペックではないがそこそこモリモリぐらいの性能でどうなったかの記録です。

## 画像生成

[SDXL-turbo](https://huggingface.co/stabilityai/sdxl-turbo)を使用します。

SDXLでは1024pxの画像を生成しますが、SDXL-turboは512pxのサイズになります。
そして生成速度はめちゃくちゃ速くなります。
SDXLでは一枚あたり10~20秒程度で画像を生成できましたが、turboでは↓ぐらい。

### step数の設定

SDXLは徐々に画像を生成していく動きをしますが、その生成ステップを何回行うか、の数字

> A single step is enough to generate high quality images.

SDXLでは20stepぐらい。SDXL-turboでは1ステップで十分とのこと

今回は1~5をランダムに設定（数字を増やすと比例して時間はかかる）しました


### 生成速度
- 3枚/秒ぐらい ＝1時間で1万枚ぐらい生成できた
- GPUはVRAMを8~9G程度使用
- 画像の質
    - SDXLよりは荒れる印象


### ベクトル化

CLIPの画像エンコーダを使用。
20秒/100枚ぐらい処理できました。

## voyager
### インデックス作成
検索用のインデックスを作成＆ファイルに保存をデータ量ごとに比較。

| データ量 | 処理時間 | ファイル |
|---|---|---|
| 1k | 0.12s | 2.1M |
| 10k | 0.49s | 21M |
| 100k | 9.83s | 207M |
| 575k | 82.7s | 1.2G |


## 検索速度

top15の検索を5回やって平均

| データ量 | 検索時間 |
|---|---|
| 1k | 0.092s |
| 10k | 0.097s |
| 100k | 0.11s |
| 575k | 0.24s |


## 検索結果

目視で評価。
対象に入っていない画像をクエリにして検索実験。
上側がクエリ画像、下側に９つ見えているのが検索結果です。

- 近未来っぽい車

うまく車、特に黄色っぽいのが検索できています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83530/ba57dca0-d6d2-1d96-d555-f59635310894.png)

- カラフルなオウム

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83530/79e92d45-a36f-fc7e-ea6b-3c0ff9ea9f88.png)

- 宇宙服

宇宙っぽい雰囲気を捉えた検索になってそう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83530/b8b29fad-4a0f-50e6-c52e-c75b3d7f769d.png)

- 犬のロボット
検索対象の画像に同じような機械の犬っぽい画像はないです。
そのためロボットっぽいのが検索できるかどうかを見たところうまくできてそう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83530/9b7b19db-6275-875f-9c86-30b436e236c5.png)

- スマホ

スマホ内の絵柄の方が強く反応したパターン
検索対象の画像の中にも似た構図（スマホを持っている画像）もあったが、宇宙っぽいイラストが優先された。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83530/bc1d0cc6-4687-c882-e04a-04b9b5ffd9a0.png)
CentOS7にDockerをインストールする

Dockerをインストールするためにリポジトリ情報を追加します。
yum-config-managerを使用すると、指定されたURLまたは指定されたリポジトリ・ファイル内にリポジトリを追加できます。
yum-config-managerは、yum-utilsパッケージに含まれていますので、yum-utilsをインストールします。
```
yum install -y yum-utils
```
　　
Dockerをインストールするためにリポジトリ情報を追加します。
```
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
```
　　
リポジトリを有効化します。
```
yum-config-manager --enable docker-ce-nightly
```
　　
Dockerをインストールします。
```
yum install -y docker-ce docker-cli containerd.io
```
　　
Dockerのサービスを開始します。
```
systemctl start docker
```
　
不要になったリポジトリを無効化します。
```
yum-config-manager --disable docker-ce-nightly
```

 以上です。
シニアエンジニア卒業

本日をもってシニアエンジニアを卒業します。

来月からは銀行員になります。IT部門ではありますが自ら開発を行うことはなく、今後はどのプログラミング言語やフレームワークが最も優れているかなどといった議論とは無縁の世界に身を置くことになります。

2005年に学生プログラマとしてLAMPで開発を行うようになり、2009年にはJava技術者として就職、一時的にPMOをやっていた時期もありましたが、10年以上の長きにわたりずっと生命保険専門のJava技術者として一貫してきました。

2022年、コロナ禍で仕事が減ってきていることに危機感を抱き、1級ファイナンシャル・プランニング技能士を目指して学習を開始しました。3級はずいぶん前に取得していたため2級からの挑戦となり、2022年1月に2級、6月にCFP、9月に1級を受験し、見事にストレートで合格。金融業に関する一定の知識を持っていることが公的に認められたわけですが、1級は別に取らなくてもよかったかなというのが率直な感想です。メガバンクでも持っている人は滅多にいません。

2023年4月からは外資系保険会社の業務支援として着任、ここで最大の障壁となったのが言葉の壁です。フランスやインドなどの外国人が多く、一部の人は日本語が話せず、言葉さえ通じないという有様でした。このままではクビになるのも時間の問題であったため、やむを得ず英語の学習を開始し、6月にはTOEICで730点以上が取れるくらいには上達しました。やはり人間は危機的状況に追い込まれないと成長しないようです。よい経験でした。

英語が終わったら手持無沙汰になってしまったので、10月にはプロジェクトマネージャ試験を受験、こちらも見事合格しました。言うまでもなくシニアエンジニアとしての集大成ですね。IT技術者としての高度な知識と経験が公的に認められたわけです。

これで必要な武器がすべて揃いました。

* IT技術者としての知識と経験
* 金融業に関する知識
* ビジネス英語

その後、メガバンクとご縁があり、銀行員になるのは必然でした。

エンジニア転職関連で怪しい情報商材が大量に出回っていますが、一方でこういう選択肢もあるという点は参考にしていただけたら幸いです。
wslで、最小のカーネルをコンパイル その34

# 概要
wslで、kernel.elfのコンパイル、やってみた。
さらに、上のkernel見つけたので、コンパイルしてみた。
俺言語インタープリタを、移植してみた。


# 写真

![スクリーンショット 2024-03-29 061329.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/183011f9-cbb2-da08-2bd0-95ac1f877edc.png)

# サンプルコード

```

void putchr(unsigned char c) {
	api_putchar(c);
}
void putint(int i) {
	char str[30];
	_sprintf(str, "%d ", i);
	api_putstr0(str);
}
void crlf() {
	api_putstr0("\n");
}
void HariMain(void) {
	char str[30];
	int i,
		j,
		k;
	api_putstr0("Ore Gengo v1.0\n");
	for ( ; ; )
	{
		j = api_getkey(1);
		if (j == 10)
		{
			crlf();
			WR(Ptr++, '\0');
			run();
		}
		else
		{
			putchr(j);
			WR(Ptr++, j);
		}
	}
	api_end();
}


```

以上。
wslで、最小のカーネルをコンパイル その33

# 概要
wslで、kernel.elfのコンパイル、やってみた。
さらに、上のkernel見つけたので、コンパイルしてみた。
じゃんけん、やってみた。

# 写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/983b660d-35eb-9cf1-e434-e60dc393cc48.png)

# サンプルコード

```
#include "apilib.h"
#include "stdlibc.h"

void HariMain(void) {
	char str[30];
	int i,
		j,
		k;
	for (i = 0; i < 3; i++)
	{
		api_putstr0(" janken pon (goo:1 choki:2 par:3) : ");
		j = api_getkey(1);
		j = j - 0x30;
		k = _rand() % 3 + 1;
		switch (j)
		{
		case 1:
			if (k == 1)
			{
				api_putstr0(" com : goo -- aiko");
			}
			else if (k == 2)
			{
				api_putstr0(" com : choki -- kati");
			}
			else if (k == 3)
			{
				api_putstr0(" com : par -- make");
			}
		break;
		case 2:
			if (k == 1)
			{
				api_putstr0(" com : goo -- make");
			}
			else if (k == 2)
			{
				api_putstr0(" com : choki -- aiko");
			}
			else if (k == 3)
			{
				api_putstr0(" com : par -- kati");
			}
		break;
		case 3:
			if (k == 1)
			{
				api_putstr0(" com : goo -- kati");
			}
			else if (k == 2)
			{
				api_putstr0(" com : choki -- make");
			}
			else if (k == 3)
			{
				api_putstr0(" com : par -- aiko");
			}
		break;
		default:
			api_putstr0("(1 2 3)");
		continue;
		}
		api_putstr0("\n");
	}
	api_end();
}





```

以上。
STM32C011を使い、無限回転サーボ(360)FS-90Rを角度(-90,0,90)でコントロールして遊ぶ。(map()化)(STM32C011J4M7)

目的
360サーボで遊ぶ(FS90R)
===完成202403292015===

![o_cop99g.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/90200796-4276-cf7b-b8fc-d85e9fc5bcb0.jpeg)

結果

![o_coq001.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/55fc524e-8553-5454-19a5-caa527d98ae8.jpeg)


プログラム


```c++



//PWM_Servo_C011_3


//定義
//左端 -90のステップ
#define V_M_90 2300
//中心の0のステップ
#define V_0    1500
//右端 90　計算値
//#define V_90  700

#define DD PB7    // potentiometer connected to analog pin x


//サーボ関数
//入力は、-90から90 サーボが仕様の端から端まで動く値
void Servo_S(int b) {

  int ii=map(b,-90,0,V_M_90,V_0);  
  int jj=map(ii,0,20000,0,65536);
  analogWrite(DD, jj);   // analogRead values go from 0

} //Servo_S


//初期化
void setup() {

  delay(3000);//マッポの手先、消したら、いかんぜょ(斎藤由紀風)

  //GPIOの初期化
  pinMode(DD, OUTPUT);   // sets the LED pin as output
  analogWriteFrequency(50);   //周波数
  analogWriteResolution(16);  //分解能

} //setup


//メインループ
void loop() {

  Servo_S(-90); delay(2000); //2秒待つ

  Servo_S(0);   delay(2000); //2秒待つ

  Servo_S(90);  delay(2000); //2秒待つ

  Servo_S(0);   delay(2000); //2秒待つ

} //loop


```
Windows11(WSL2)＋Debian12 de 64bit Live-Image(set NVIDEA)

自分だけのDebian12 64bitのインストールメディアが欲しかったので作る事にした。 
参考サイトは主に「https://tech.quickguard.jp/posts/debian-live-cd/」

不服なのは32bitがある事やライブイメージだと起動出来てもNVIDEAのドライバが無いから起動途中でしくじる。

いちいちドライバをインストールするには面倒なので決め打ちで。

何がしたいのか？と言うか何をさせれるのかを主張。

環境的に32bitは見捨てる
イメージでも実機でもXfce+NVIDEA
【Python】GraphQLErrorにextensionを設定する

## 概要
GraphQLの仕様ではエラーに`extention`という領域があり、柔軟に項目が設定できます。（詳細については[GraphQLのエラー設計について](https://note.com/tabelog_frontend/n/n4fc8d4e134d5)を参照)
では、PythonでGraphQLサーバーを実装するときに、このextentionをどう設定する実装が良いのか、というメモ書きです。

## 対応案
実装のやり方は色々あると思いますが、[こちら](https://stackoverflow.com/a/77087614)のstackoverflowの記事で紹介されている通り、`graphql-core`のライブラリにある、GraphQLErrorのextensionに設定するやり方が良いかなと思います。ドキュメントについては[GraphQL Errors](https://graphql-core-3.readthedocs.io/en/latest/modules/error.html)にあります。
なお、上記のstackoverflowの記事ではGrapheneを使用する際の例で紹介されていますが、graphql-core自体はStrawberryやAriadneでも使用されているようですので、大体のライブラリで使えるエラーの実装と思います。

## 前提
以下の前提で試しに実装してみました。
* 使用したpythonのバージョンは`3.12.2`です。
* 使用したgraphql-coreのバージョンは`3.2.3`です。
* graphqlのライブラリとして今回はStrawberryを使用してみました。

## 実装サンプル

```python
@strawberry.type
class Mutation:
    @strawberry.mutation
    def add_sample_user(email: str, name: str) -> AddUserResponse:
        # execの処理内容は記載割愛
        result, is_success = add_sample_user_exec(email: str, name: str)
        if is_success:
            return result
        else:
            # Errorにextensionを設定する
            return GraphQLError(message="Failed exec add user", extensions={"code": 500})
```

## その他参考
* [Python用GraphQLライブラリStrawberryのログ出力 ~スタックトレースを出力させない方法~](https://qiita.com/y_p_e/items/e7cb2c872e92ac5fbc30)
【生成AIアプリ100チャレンジ】（4）文字起こしアプリ

# 公開中サイト

https://ai.nuevo.jp/whispar/

# 開発環境

|              |              |
|:------------:|:------------:|
| Server       | lightSail    |
| Language     | Python3.11   |
| Framework    | Django       |
| DB           | sqlite3      |

ローカル環境ではPythonのvenvを使用。エディタはvs codeです。


# 目的
　WEB画面上でChatGPTと会話ができるアプリを作りたいと思っています。TTS(テキストを自然な音声にするAPI)とwhispar(音声をテキストにするAPI)を使えば、会話ができるはず。その第一弾として、whisparで音声を文字起こしするアプリを作りました。

うまくいけば、ブラウザ画面上で自然言語を話しながら人工知能と会話できるはずです。chatGPTと音声で会話したい。その目的のための文字起こしアプリです。
 

# コード
```python:qiita.rb
def index(request):
    OPENAI_API_KEY = os.environ['OPENAI_API_IMAGE_KEY']
    chat_results = ""
    if request.method == "POST":
        form = TranscribeForm(request.POST)
        if form.is_valid():
            client = OpenAI(
                api_key = OPENAI_API_KEY,
            )
            audio_file_path = settings.BASE_DIR / "uploads/uploads/recording.wav"
            audio_file= open(audio_file_path , "rb")
            transcription = client.audio.transcriptions.create(
                model="whisper-1",
                file=audio_file
            )
            chat_results = transcription.text
    else:
        form = TranscribeForm()
    domain = request.build_absolute_uri('/')
    template = loader.get_template('whispar/index.html')
    context = {
        'domain': domain,
        'chat_results': chat_results
    }
    return HttpResponse(template.render(context, request))
```

# アプリ画面
![スクリーンショット 2024-03-29 2.14.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/398694/d665b927-0e8b-a10c-fd1d-fe0b9ea489c8.png)

# 感想
文字起こし処理で力尽きてしまいました。デザインレイアウトは後で修正します。もちろん、音声データを保存し。そのデータを元に文字起こしまでは完成しました。人工知能とリアムタイム会話まであと一歩。テキストを音声化させれば、会話できます。音声を早見沙織にしたいです。「軽く死ねますね！」

苦労したのは、音声保存まではJSでわりとスムーズにいけましたが、その音声をどう処理するかが、ネットで検索してもわからなかったので、chatGPT先生（転スラでいうところのシエル先生）に相談して解決しました。ネットには虚言癖しかいないのか、と悲しくなります。やはり、コードの説明なんてしないで、公式のマニュアルに任せるべきなのでしょう。

ローカルではなにもかもうまく行きましたが、サーバでは苦労しました。音声をアップするディレクトリに権限がない状態でgit pull をしたものだから。サーバのmain branch が remote から離れてdetch状態に。音声以外のディレクトリはpullしてきているので、見たこともない変更処理が増えており、焦りました。gitでミスしても周りに迷惑をかけないのが個人開発のメリットでもあるので、普段では仕事で使ったことないような復旧方法を使ってなんとか復帰。権限がない状態でgit pull すると、こんなエラーになるのか、と初体験。もしかして、これが1番の収穫かもしれない。仕事の本番環境で同じことが起こったら、焦ってしまうこと間違いなし。

いやー、chatGPTとの会話まで一歩すすめました。
ちなみにトップページのアプリアイコンはすべて画像生成したものです。
ADHDのためのGitの使い方

ADHDエンジニアはpre-commitを入れろ。
お前らならコミットプッシュした後にやらかしに気づくことなんてしょっちゅうあるはずだ。
そんなに君にコミット前コードの記述ミスとかを教えてくれる。
やらかしコミットが減るのでマジ助かる。

https://pre-commit.com/

最後に忠告。
絶対に
「--no-verify」オプションだけはつけるなよ。
GitHub/GitLab開発ルール

最近Git初心者に開発の流れを共有することがあったのでついでに。
GitHub/GitLabでの大まかな開発の流れまとめてみました。
あくまで大まかな流れなので、Gitコマンドの使い方は各々でggrks

# 1. Issuesを作成する。(Assigneesに作業者を設定する)
- GitHub/GitLab上でIssueを作成する。
# 2.ローカルのmainブランチを最新化
```
git pull
```
または
```
git fetch
git merge [ブランチ]
```
# 3. 作成したIsuue番号でfeatureブランチを作成する
- Issue番号「#1」の場合「feature/1」
```
git checkout -b feature/1
```
# 4.コードを記述する(開発)
# 5.コミット対象を追加する
```
git add [コミット対象にするファイルまたはディレクトリ]
```
# 6. コミットする 
- コミットメッセージ例
```
#1 [add] fairuの追加
#2 [update] ふぁいるの更新
#3 [fix] コミットメッセージの修正
#4 [delete] fairuの削除
```
- コミットメッセージに「#番号」をつけることでIsuueにコミットが紐づくので記載推奨！

```
git commit -m "#1 [add] ファイルの追加"
```

# 7. pushする
```
git push origin feature/1
```

# 8. pull requestを投げる
- developブランチへfeatureブランチのプルリクエストを作成する

# 9. コードレビュー
GitHub/GitLab上でクソコードを指摘されて涙を流す。
完璧ならLGTMがもらえる。

# 10. レビュワーがApprove&Mergeする


# 番外編
開発のワークフローについて

https://www.atlassian.com/ja/git/tutorials/comparing-workflows/gitflow-workflow

https://docs.github.com/ja/get-started/using-github/github-flow
GitにGitHubの認証情報をキャッシュする

GitHubで2FA認証を有効した後のGitの設定

## ghのインストール
- Mac(Homebrew)
```
brew install gh
```
- Windows(WinGet)
```
winget install --id GitHub.cli
```
- Linux
  - Debian系(WSL)
    ```
    sudo mkdir -p -m 755 /etc/apt/keyrings && wget -qO- https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo tee /etc/apt/keyrings/githubcli-archive-keyring.gpg > /dev/null \
    && sudo chmod go+r /etc/apt/keyrings/githubcli-archive-keyring.gpg \
    && echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null \
    && sudo apt update \
    && sudo apt install gh -y
    ```
  - Fedora, Red Hat系(dnf)
    ```
    sudo dnf install 'dnf-command(config-manager)'
    sudo dnf config-manager --add-repo https://cli.github.com/packages/rpm/gh-cli.repo
    sudo dnf install gh
    ```

  - Red Hat系(yum)
    ```
    type -p yum-config-manager >/dev/null || sudo yum install yum-utils
    sudo yum-config-manager --add-repo https://cli.github.com/packages/rpm/gh-cli.repo
    sudo yum install gh
    ```

# GitHubへログイン
```
gh auth login
```


```
$ gh auth login
? What account do you want to log into? GitHub.com
? What is your preferred protocol for Git operations on this host? HTTPS
? Authenticate Git with your GitHub credentials? Yes
? How would you like to authenticate GitHub CLI? Login with a web browser

! First copy your one-time code: XXXX-XXXX
Press Enter to open github.com in your browser...
✓ Authentication complete.
- gh config set -h github.com git_protocol https
✓ Configured git protocol
! Authentication credentials saved in plain text
✓ Logged in as yourname
```
https://docs.github.com/ja/get-started/getting-started-with-git/caching-your-github-credentials-in-git

https://github.com/cli/cli/blob/trunk/docs/install_linux.md
publicにあるJavaScriptの変数をTypeScriptで型定義して読む in React + Vite

# これはなに？なにがうれしい？

`public`配下にあるJavaScriptの設定ファイルをReactで読む必要があった。
この記事ではグローバルオブジェクト`window`を使用した方法をメインに紹介する。
この方法は、提供されたJSファイルなどを型定義して読み込みたい場合に使用できる。



# 試したけどダメだった方法

- `public`に定義した変数を`src`内の`.d.ts`でアンビエント宣言(declare)
    - `public`に定義した変数と同名の変数をアンビエント宣言したからといって読み込めるわけではない
- ES Modulesの`import/export`を使用
    - `src`から`src`の外を`import`できない
    - CommonJSの`module.exports/require`はそもそもダメ


# 参考記事

https://zenn.dev/qnighy/articles/9c4ce0f1b68350

https://qiita.com/crml1206/items/1ffe928339950c4938a4

# コード

## /index.html

Viteの場合はルート直下に`index.html`がある。
対象JSは`/public/js/configs.js`とする。

```diff:index.html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vite + React + TS</title>
  </head>
  <body>
    <div id="root"></div>
+++ <script type="module" src="/public/js/configs.js"></script>
    <script type="module" src="/src/main.tsx"></script>
  </body>
</html>
```



Create React Appの場合は`public`直下にある。

```diff:/public/index.html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>React Create App</title>
  </head>
  <body>
    <div id="root"></div>
+++ <script type="module" src="%PUBLIC_URL%/js/configs.js"></script>
  </body>
</html>
```



## /public/js/config.js

オブジェクトとして定義してみる。

```javascript:/public/config.js
window.configs = {
    windowConfig1: { keyString: 'windowConfigString1' },
    windowConfig2: { keyString: 'windowConfigString2' },
};
```



## /src/@types/index.d.ts

`config.js`にあるオブジェクトの形に沿って型を定義する。
TypeScriptが`Window`インターフェースに`window`オブジェクトの持つべきプロパティやメソッドの型を定義している。
`Window`インターフェースにアンビエント宣言することで宣言マージされ、`Window`インターフェースが拡張される。



```typescript:/src/@types/index.d.ts
interface Config {
    keyString: string;
}

interface Configs {
    [id: string]: Config;
}

// ここが本題
declare global {
    interface Window {
        configs: Configs;
    }
}
```



## /src/\*.\*.tsx

読み込めていない場合を想定したほうがよい。

```tsx:/src/pages/public/Js.tsx
import { type FC, memo } from 'react';
import { EXPORT_CONFIGS } from '/public/js/configs.js';

const Component: FC = () => {
    const windowConfigs = window.configs;

    return (
        <>
            {windowConfigs &&
                Object.keys(windowConfigs).map(key => (
                    <div key={key}>{windowConfigs?.[key]?.keyString}</div>
                ))}
        </>
    );
};

export const Js = memo(Component);
```



## 出力の抜粋
```html
<div id="root">
    <div>windowConfigString1</div>
    <div>windowConfigString2</div>
</div>
```
自己紹介

### 自己紹介
初めまして。羽後です。
都内の派遣会社でIT事務員をしている男です。

主に低スキル系、情報処理系の仕事をぼちぼち続けています。
勉強したことを備忘録としてQiitaで整理していきたいと思います。

よろしくです。
【Azure】Application Insightsの通信要件

App ServiceをVnet統合し、送信方向をNSGで制限したところ、Application Insightsにログが送れなくなりました。

Application Insightsの通信要件を確認したところ、サービスタグ「AzureMonitor」で許可すればよいことがわかりました。

https://learn.microsoft.com/ja-jp/azure/azure-monitor/ip-addresses

このページを見ると細々とした許可URL、許可IPアドレスが書いてあるのですが、冒頭にさらっとサービスタグで許可すればよいよ、ということが書いてあります。

> Azure ネットワーク セキュリティ グループを使用している場合は、Azure ネットワーク サービス タグを使用してアクセスを管理できます。 ハイブリッドまたはオンプレミスのリソースのアクセスを管理している場合は、対応する IP アドレス リストを JSON ファイルとしてダウンロードできます。これは毎週更新されます。 **この記事のすべての例外に対応するには、サービス タグ ActionGroup、ApplicationInsightsAvailability、および AzureMonitor を使用します。**

* Application Insightsのログ送信・メトリック送信で関係あるのはサービスタグ「AzureMonitor」です。
* サービスタグ「ApplicationInsightsAvailability」はApplication Insightsの可用性テストで使います。受信方向に対して許可します。
* サービスタグ「ActionGroup」はアクショングループでWebhookを使うときに許可する必要があるはずです（実際に使ったことはまだないです）

NSGでApplication Insightsへの送信許可を追加するには以下のように設定すればOKです。

![01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2850747/f91c1a2c-a466-0d3f-4e5d-fe7f6ae24174.png)
【AWS-IAM】担当者の役割変更、及び、リリース時にアカウントの権限を変更したい

![【AWS-IAM】担当者の役割変更、及び、リリース時に アカウントの権限を変更したい.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3754524/0601e2db-6dd0-6506-62d2-9071540e2aca.png)



## 本記事で実現できること
担当者の役割変更、及び、リリース時にアカウントの権限を変更する

## 前提
- AWSマネコンはログイン済み
- 2024.3.28 時点でのコンソールのUIになります

## 簡単な解説
全部で9フェーズ

①ホーム画面で、画面上部検索欄に[**IAM**]と入力。
　出てくるサービスの中から[**IAM**]をクリック

![AmazonSQS 障害時DLQに転送されたキューをSQSに再送したい(DLQ再処理)のコピー (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3754524/080b3166-ce95-28ce-0536-cf33663e8816.png)


②左画面で[**ユーザー**] を選択後、対象のIAMユーザーのユーザー名をクリックする。
![【AWS-IAM】担当者の役割変更、及び、リリース時に アカウントの権限を変更したい (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3754524/494561a8-9099-4211-3403-fb42f58bea8c.png)



③[**グループ**]タブをクリックする。
![【AWS-IAM】担当者の役割変更、及び、リリース時に アカウントの権限を変更したい (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3754524/127a3228-0e38-c616-d1d4-40db411c7584.png)


④変更前のグループ名にチェックを入れ、[**削除**]をクリック
![【AWS-IAM】担当者の役割変更、及び、リリース時に アカウントの権限を変更したい (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3754524/af1962d8-334d-11f9-155e-03b78ba7a0c6.png)

⑤確認画面で、グループ名に相違がないか確認し、［**削除**］をクリックする。
![【AWS-IAM】担当者の役割変更、及び、リリース時に アカウントの権限を変更したい (4).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3754524/e003b49e-edb8-70d6-e38e-4b591b9c3c68.png)



⑥正常に削除されるとユーザーがグループから削除された旨のメッセージが出力される。
![【AWS-IAM】担当者の役割変更、及び、リリース時に アカウントの権限を変更したい (5).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3754524/5e295aa6-d6e1-9dc5-3142-3227285472ad.png)




⑦[**ユーザーをグループに追加**]をクリックする。

![【AWS-IAM】担当者の役割変更、及び、リリース時に アカウントの権限を変更したい (6).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3754524/a837de8e-6f61-3531-16ea-acd72d8c5e48.png)

⑧追加する対象のグループにチェックを入れ、[**ユーザーをグループに追加**]をクリックする。
![【AWS-IAM】担当者の役割変更、及び、リリース時に アカウントの権限を変更したい (7).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3754524/e9ae4b75-e9b6-66cb-0e16-1fef4bb87b33.png)

⑨正常に追加された旨のメッセージが出力される。
　グループ名に追加されていることを確認する。

![【AWS-IAM】担当者の役割変更、及び、リリース時に アカウントの権限を変更したい (8).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3754524/f14298a5-f113-9448-f745-5f94efef517a.png)

## まとめ
本稿が、IAMで担当者の役割変更、及び、リリース時にアカウントの権限を変更したい方の参考になれば嬉しいです。

ITエンジニア向け、AWS資格取得を目指す方向けに個人ブログで記事も投稿していますので、
合わせて読んでもらえると嬉しいです。
[ことなの学校(個人ブログ)](https://kotona-school.com)

更によりレベル感の高そうなAWS関連の発信はZennの方で行います。
こちらももしよければフォロー、ご確認いただけると嬉しいです。
[Zenn個人アカウント](https://zenn.dev/tomo_itbizblog)

Twitterでも役立つ情報を発信しますのでフォローしてもらえると嬉しいです 
→ [@tomo_ITBizBlog](https://twitter.com/tomo_ITBizBlog)
【TypeScript】オブジェクトのすべてのプロパティをreadonlyにする

`Readonly<T>`を使用するとオブジェクトのすべてのプロパティをreadonlyにできます。

```ts
type User = {
  id: number,
  name: string,
}
 
const user: Readonly<User> = {
  id: 1,
  name: '田中',
};
 
user.name = '佐藤'
// Cannot assign to 'title' because it is a read-only property.

```

:::note warn
`Readonly<T>`は再帰的に`readonly`にしません。上記の例で`name`がオブジェクト型でも`name`が持つプロパティは`readonly`になりません。
:::
WSL 上で gtest を動かしてみる

## 概要
WSL 上で GoogleTest を用いて、サンプルプログラムをテストする際の手順を記載する
ファイルの操作、コマンドの実行には VSCode を用いる

## 前提
- VSCode がインストールされていること
- WSL がインストールされていること
- WSL 上に gtest がインストールされていること
WSL に gtest をインストールする手順は下記

https://qiita.com/semiflat/items/6ec0611609993f17cd5e

## gtest 実施手順
### VSCode で WSL に接続する
VSCode を開き、左下の >< をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3749137/fd85d037-1f00-3f8a-4f7f-9562e3edadc9.png)

"WSL への接続" をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3749137/2c156253-ebb2-c58f-889a-206cf4160b03.png)

左下の表示が "WSL: Ubuntu" になれば接続完了
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3749137/74ec6580-3fb3-50fc-87da-78ac20d98396.png)

### サンプルコードの作成
VSCode の左上のアイコンをクリックして、"フォルダーを開く" をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3749137/2c3e6ba8-c995-72cb-0e52-370395813e3a.png)

任意のディレクトリパスを入力して、"OK" をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3749137/41335413-0e20-f07d-7bdf-04832f5f249b.png)

VSCode のエクスプローラー上で右クリックして、"新しいファイル..." を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3749137/b6238434-725c-2ef4-eb30-5aeeb9abf961.png)

以下の3ファイルを作成する
```c:sample.c
#include "sample.h"

int add( int a, int b ) {
    return a + b;
}
```
```c:sample.h
#ifndef SAMPLE_H_
#define SAMPLE_H_

int add( int a, int b );

#endif  /* SAMPLE_H_ */
```
```cpp:gtest_sample.cpp
#include <gtest/gtest.h>
#include "sample.h"

TEST( test_add, case_1_plus_2 ){
    EXPECT_EQ( 3, add( 1, 2 ) );
}
```

### gtest のビルドと実行
"ターミナル" タブから "新しいターミナル" を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3749137/18926bd6-4a94-a565-4a3b-f32eb7fc9d85.png)

cd コマンドで、先ほどファイルを作成したディレクトリに移動する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3749137/e79914dd-6b05-a433-173c-878a003732d6.png)

以下のコマンドを実行し、ビルドを行う
```
g++ sample.c gtest_sample.cpp -o test -g -pthread -lgtest_main -lgtest
```
成功した場合、test が作成される
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3749137/f231ca0c-2e95-600f-0c5d-5735d016ffc9.png)

以下のコマンドを実行し、test を起動する
```
./test
```
成功した場合、以下のように表示される
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3749137/675bbac9-d323-b8f8-02be-0970c50b8965.png)

## サンプルコードの解説
### sample.c について
（言うまでもないことだが、）add() は 引数 a, b を加算して返却する関数である。

### gtest_sample.cpp について
TEST() マクロを用いてテストケースを作成している。
TEST() マクロを使用するためには、gtest/gtest.h をインクルードする必要がある。
TEST() マクロの第一引数は テストスイート名、第二引数はテストケース名として扱われる。
また、EXPECT_**() マクロはアサーションである。
今回使用している EXPECT_EQ() マクロは2つの引数が等しいか比較するアサーションであり、全てのアサーションが真である場合は、そのテストケースが成功しているとログに表示される。
いずれかのアサーションが偽の場合は、そのテストケースが失敗しているとログに表示される。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3749137/9318f341-55fa-cab5-bda5-834798c707b3.png)
djnagoのプロジェクトの始め方[まとめ]※個人メモ

### 個人メモです

1.djnagoインストール

```
#venvの作成
$ python3 -m venv venv

# 仮想環境の有効化
$ source venv/bin/activate

# djnagoインストール
$ pip install django === 'バージョン'
$ pip show Django

# プロジェクトの作成
$ django-admin startproject config .

#アプリケーションの作成
$ python manage.py startapp アプリ名

#必要に応じて初期フォルダの作成も済ませておくといいかも
（secrets static templates）

```

#### プロジェクト開始のための設定

 環境変数を使用する場合はライブラリをインストールしてください
```linax
# django-environのインストール（環境変数を扱う）
$ install django-environ==0.4.5
```

2. secretsに環境変数を置くためのファイル作成
3. settings.pyの設定変更

```python:settings.py

#-------ここからは秘密情報の設定---------
import environ
# インスタンスの作成
env = environ.Env()
# rootに環境変数のpathを格納
root = environ.Path(BASE_DIR / 'secrets')


# dev
env.read_env(root('.env.dev'))

# シークレットキー 
#ここではenvの中のSECRET_KEYを文字列として取得している
SECRET_KEY = env.str('SECRET_KEY')

DEBUG = env.bool('DEBUG')

ALLOWED_HOSTS = env.list('ALLOWED_HOSTS')

#----------ここからは通常の設定-------------

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    # 追記
    '自分のアプリケーション',
]

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        # templatesを使用することを伝える
        'DIRS': [ BASE_DIR / 'templetes'],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]
# 使用するデータベース
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db.sqlite3',
    }
}
# 日本に設定
LANGUAGE_CODE = 'ja'

TIME_ZONE = 'Asia/Tokyo'

USE_I18N = True

USE_TZ = True

# STATICフォルダ（画像ファイルなど）
STATICFILES_DIRS = [BASE_DIR / 'static']
```

環境変数はgitignoreでgitにアップロードしないようにする
RSA鍵 公開鍵・秘密鍵とは

# RSA鍵の生成アルゴリズムと暗号化
##### RSAに必要な値の定義
| value | name |
|:-: | :-: |
|n  | modulus(法) |
|e | public exponent(公開指数) |
|d | private exponent(秘密指数) |

$ n=p \times q　$
$ \Phi= (p-1) \times (q-1) $

公開指数eは $ 1<e<\Phi $ であり$GCD(e,\Phi)=1$を満たす
秘密指数dは $ 1<d<\Phi $ であり$e \times d \equiv 1 \quad mod \Phi$を満たす
※GCD:greatest common divisor 最大公約数

##### RSA鍵
公開鍵は(n,e)を、秘密鍵は(n,d)をテキスト形式にエンコードをしてファイルにしている

##### 暗号化・複合化
$ c=m^e \quad mod(n) $
$ m=c^d \quad mod(n) $
元のデータをm、暗号化したデータをcとする。公開鍵で暗号化して、秘密鍵で複合化する。

##### 署名・署名認証
$ c=m^d \quad mod(n) $
$ m=c^e \quad mod(n) $
署名の場合は逆に秘密鍵で暗号化して、公開鍵で複合化する。

##### OpenSSLで鍵の内容を確認できる
```
openssl genrsa 512 | openssl rsa -text
```
Streamlitを用いたチャートの可視化

お疲れ様です。

今日は「Streamlitを用いたチャートの可視化」について部分いたします。

# line_chartを使った線グラフ

line_chartを使いStreamlitで線グラフを表示させることができます。

上記で記載したデータは以下のグラフのように表示されます。

```python
dataframe = pd.DataFrame(np.random.randn(10, 5),
  columns = ('col %d' % i
    for i in range(5)))
dataframe
st.write('This is a line_chart.')
st.line_chart(dataframe)
```

アウトプットは以下です。

![Screenshot 2024-03-28 at 11.23.13 PM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3507088/fccc87be-4c60-a62a-77dc-8f27e89c8c30.png)

# 面グラフの可視化

「area_chart」をStreamlitで使うと面グラフを表示することができます。

```
st.write('This is a area_chart.')
st.area_chart(dataframe)
```

![Screenshot 2024-03-28 at 11.24.02 PM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3507088/0f44bd32-62bb-cd6f-89ad-9e0df8266009.png)
area_chartを使った面グラフ

# ヒストグラムを表示する

「bar_chart()」を使うと、ヒストグラムが表示されます。

```python
st.write('This is a bar_chart.')
st.bar_chart(dataframe)
```

![Screenshot 2024-03-28 at 11.24.43 PM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3507088/58eb4759-e25d-b76d-eb0b-ac4bbead9c53.png)

bar_chartを使ったヒストグラム

# 地図による可視化

「st.map()」を活用すると、地図上にデータを表示させることができます。ランダムなサンプルデータを作り、サリナス（訳注：カリフォルニア州の地名）に表示させてみましょう。

```python
st.write('Map data')
data_of_map = pd.DataFrame(
  np.random.randn(1000, 2) / [60, 60] + [36.66, -121.6],
  columns = ['latitude', 'longitude'])
st.map(data_of_map)
```

![Screenshot 2024-03-28 at 11.25.22 PM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3507088/c0f33002-0f42-f047-0850-e232e72a52f0.png)

st.mapを使った地図上でのデータ表示

# まとめ

Streamlitを用いたチャートの可視化について記載しました。

- line_chartを使った線グラフ
- 面グラフの可視化
- ヒストグラムを表示する
- 地図による可視化



今日は以上です。

ありがとうございました。
よろしくお願いいたします。
DartとKotlinのsealed classを比較してみた

## sealed classを違う言語同士で比較してみた!
Dartを書くことが多いけど、sealed classを使う機会がない...
Kotlinや他の言語は、昔からsealed classがあるらしい?

どっちが書きやすいのだろうか、気になって書いてみた。コード書くの好きなのでついつい気になってしまう。

## 🎯Dart
Dart3.0から、sealed classが使えるようになった。`Fruit`というsealed classを定義して、継承して`Apple`,`Banana`,`Orange`を作ってみた。簡単すぎて参考にならないかもだけど、いきなりロジックを考えるより、動くものを作って試してから、アプリのロジックに使った方がいいかなと思っていつもサンプルコードを書くところから始めます。
```dart
sealed class Fruit {}

class Apple extends Fruit {
  final String name;
  Apple(this.name);
}

class Banana extends Fruit {
  final String name;
  Banana(this.name);
}

class Orange extends Fruit {
  final String name;
  Orange(this.name);
}

String whenFruit(Fruit fruit) => switch(fruit) {
  Apple() => 'りんご',
  Banana() => 'バナナ',
  Orange() => 'オレンジ',
};

void main() {
  final fruit = Apple('りんご');
  print(whenFruit(fruit));
}
```

**実行結果**
![スクリーンショット 2024-03-28 23.14.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2303722/2231a714-3eb3-146b-3b99-1c64c834802f.png)

## 🦜Kotlin
Kotlinだと昔からseald classがあるみたい。Enumみたいな使い方ができたりするようです。クラスの継承を制限する目的で使うから、別もんでしょうけど、Dartと同じようなロジックを書くとこんな感じです。
```kotlin
// 果物っていうインターフェースを作って、その中にApple, Banana, Orangeを作る
sealed interface Fruit
// interfaceを継承しているので、これはFruitの実装クラス
sealed class Fruits() : Fruit
// sealed classを継承して、３つのオブジェクトを作っている
data object Apple : Fruits()
data object Banana : Fruits()
data object Orange : Fruits()

fun main() {
    // whenに渡す変数の型をFruitにしている。Appleというオブジェクトを代入している
    val fruit: Fruit = Apple
    // whenの中で、Fruitの型によって処理を分けている
    when (fruit) {
        // whenの中では、isを使って型を判定している。->の後に処理を書く
        is Apple -> println("Apple")
        is Banana -> println("Banana")
        is Orange -> println("Orange")
    }
}
```

**実行結果**
![スクリーンショット 2024-03-28 23.17.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2303722/1bfbd1d9-b3b3-b188-c10d-eca9987e8f64.png)

## まとめ
DartとKotlinのsealed classを比較してみましたが、Kotlinの方がシンプルでわかりやすい気がしました。DartだとJavaぽくなるので、見づらいのかもですね。色々探求してみたい。新しい文法が出てきても他の人が読みやすいコードを書きたいな....
google formの回答をslackに送信して行う鍵の管理【安定版】

# はじめに
過去にあげていた[google formの回答をslackに送信して行う鍵の管理](https://qiita.com/keigo1110/items/d350408a62fc6674cf12)から安定して利用していた状態のものを紹介します。

# 実装
## 準備
準備でやることは以下のサイトから

https://goworkship.com/magazine/slack-usage-3/

## google form
鍵の選択リスト(複数選択可)をつくります。
![Screenshot 2024-03-28 at 22.54.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3346908/eb5e2980-8499-37fa-5cab-66827d89f865.png)

またその鍵の状態(1つ選択のみ)をつくります。
![Screenshot 2024-03-28 at 22.55.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3346908/4aea9434-ff93-b301-ea9b-8fe2cf5a84a0.png)

`デフォルトで質問を必須項目にする`と`メールアドレスを収集する`を忘れずに。

## コード
書き換え必要なところにコメント入れてます。
```javascript
function onFormSubmit(event) {
  var scriptProperties = PropertiesService.getScriptProperties();

  var email = event.response.getRespondentEmail();
  var name = getNameFromEmail(email);

  var message = "<!everyone> " + name + "\n";
  var timestamp = event.response.getTimestamp();
  var date = new Date(timestamp);
  var formattedDate = Utilities.formatDate(date, "JST", "yyyy/MM/dd HH:mm:ss" + "\n");
  message += "時間: " + formattedDate;
  message += "────\n今回の操作：\n";

  var items = event.response.getItemResponses();
  var selectedKeys = [];
  var status = "";

  for (var i = 0; i < items.length; i++) {
    var response = items[i].getResponse();
    var title = items[i].getItem().getTitle();
    if (title === "鍵の部屋番号（複数選択可）") { //google formの質問タイトル
      selectedKeys = Array.isArray(response) ? response : [response];
    } else if (title === "状態") { //google formの質問タイトル
      status = response;
    }
  }

  for (var i = 0; i < selectedKeys.length; i++) {
    scriptProperties.setProperty(selectedKeys[i], status);
    message += selectedKeys[i] + "：" + status + "\n";
  }

  message += "────\n全ての鍵の状態：\n";

  var allKeys = ["101", "102", "201", "A-1"]; //google formに用意した部屋番号
  var maxLength = allKeys.reduce((max, key) => Math.max(max, key.length), 0);

  for (var i = 0; i < allKeys.length; i++) {
    var keyStatus = scriptProperties.getProperty(allKeys[i]) || "借りてません";
    var paddedKey = allKeys[i].padEnd(maxLength, ' ');
    message += paddedKey + "：" + keyStatus + "\n";
  }

  message += "────\n";
  message += "フォーム：" + "yourgoogle_form_link" + "\n"; //メッセージにgoogle formのリンク載せる

  UrlFetchApp.fetch(
    "your_webhook_url", // Webhook URLを入れる
    {
      "method": "POST",
      "contentType": "application/json",
      "payload": JSON.stringify({ "text": message })
    }
  );
}


//// メールアドレスと名前の対応表(メールアドレス：名前）////
var emailNameMapping = {
  "aaaaaaaaaaa@qiita.ac.jp": "A田A郎",
  "bbbbbbbbbbb@qiita.ac.jp": "B下B子",
  "bbbbbbbbbbb@qiita.ac.jp": "C本C彦",
};
////////////////////////////////////////////////////

// メールアドレスから名前を取得する関数
function getNameFromEmail(email) {
  return emailNameMapping[email] || email;
}
```

## Slackに送られてくるもの
動くとこんな感じ。
![Image 2024-03-28 at 23.03.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3346908/37ca20d9-b43c-ae0a-e1c4-fe78473ab305.jpeg)

# おわりに
研究室の運用などに役立ててください。
【初学者】Javaで二重引用符（"）を文字列として表示するには？

# エスケープシーケンスを使ってみた
Javaで二重引用符(")を文字列として表示するにはどうしたら良いんだ...。

ってことで試しにコードを書いてみます。
```java:Test.java
System.out.println("私は"ちゃんを愛している")
```
二重引用符を愛している人など存在しないと思いますがそれはさておき、
上記のコードだとコンパイルエラーになってしまいますよね。

:::note info
Javaでの二重引用符は【囲った部分を文字列として示す】という
特別な意味を持った記号であるため、通常の文字列として表すにはひと手間必要になります。
:::

ではどうすれば良いのか。
## 正解は **【エスケープシーケンスを使う】** ですね。

エスケープシーケンスを使えば二重引用符などの特別な意味を持つ記号を文字列として扱うことができるようになります。

さきほどのコードを以下のように書き換えるだけです。
```java:Test.java
System.out.println("私は\"ちゃんを愛している")
```
```
私は"ちゃんを愛している
```
どこが変わったかお分かりでしょうか。

最初のコードと違い、`"`の前に`\`が入っていますね。

**この`\`がエスケープシーケンスです。**

これで二重引用符への愛を表現できるようになりました。嬉しいです。

## 最後に

愛って良いですよね。
WordCloudで使用するフォントファイルをMacのDockerに用意する。

すぐ忘れそうなので、自分用メモ

## Wordcloudをインストール
```requirement.txt
wordcloud
```

```Dockerfile:Dockerfile
FROM python:3
ENV PYTHONUNBUFFERED 1
RUN apt-get update
RUN mkdir /code
WORKDIR /code
COPY requirements.txt /code/
RUN pip install --upgrade pip && pip install -r requirements.txt
COPY . /code/
```

## 参照するフォントファイルをDocker内にコピー
1. FontBookを開く（必要ならフォントファイルをインストールする）
![スクリーンショット 2024-03-28 22.53.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/683664/852c21df-e379-d1fc-c8e5-b6a9cce965f0.png)
2. Finderで表示し、WordCloudで使用するファイルをDocker内にコピーする。
![スクリーンショット 2024-03-28 22.54.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/683664/39383758-3902-c8b9-8d48-603924e147f0.png)
3. WordCloudのfont_pathから参照する。
```python:WordCoud.py
fpath = 'ヒラギノ明朝 ProN.ttc'
wc = WordCloud(background_color='white',
                   font_path=fpath,
                   width=800, height=800,
                   stopwords=stopwords)
```

参考資料
[MacのFont Bookでフォントをインストールして検証する](https://support.apple.com/ja-jp/guide/font-book/fntbk1000/mac)
[Macにフォントを追加する方法](https://www.pc-koubou.jp/magazine/79428)
[Dockerコンテナに好きなフォントをインストールする方法](https://qiita.com/naka-j/items/032ebbbe00901979309e)
[歌詞を形態素解析→WordCloud化したら曲名が分かる…かも？](https://qiita.com/figgy-pudding/items/5e67d204a77c8fc86f70)
好きな惣菜発表cowsayを作る

ネタ記事です。

好きな惣菜発表ドラゴン、かわいいですよね。自分のterminalでも表示したい！という人も多いのではないでしょうか。
よく考えたら、Unixにはcowsayコマンドという近しいものがあるではないですか。

# cowsayコマンド
cowsayコマンドとは、牛のアスキーアート(AA)に好きなことを喋らせることができるUnixコマンドです。
fortuneコマンドと組み合わせて、格言を言わせる使い方をよく見ますよね。

標準では、以下のような牛を表示してくれます。
![スクリーンショット 2024-03-28 22.09.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/467266/0a33f356-b809-590a-04e4-6b00a5dd4a28.png)

表示されるAAには種類があり、share/cowsディレクトリに表示できるAAが.cowファイルで保存されています。
自作のAAを表示したければ、cowsディレクトリ下に.cowという拡張子でAAを追加すれば良いのです。

# 好きな惣菜発表cowsayの作り方
まず、好きな惣菜発表ドラゴンのAAを作ります。ここが一番大変です。
筆者が作ったAAを貼っておきますが、もっと上手い人は自分で作るといいでしょう。
```
          <<
     ___( ^     )
     ___         )____
        | |      _ ] _ \\
        | |_|    )
        | |_|     \\ 
        ""(   ) _ _ ^~
        _ ( _) 
```

作成する上で注意しないといけないのは、AAにエスケープ記号である「\」が含まれる場合、ひょうじされないことです。「\」を使いたい場合は二つ重ねて「\\」としてエスケープをキャンセルしましょう。

AAを作ったら.cowファイルを作成します。ここで、cowの.cowファイルはどうなっているのか見てみましょう。
![スクリーンショット 2024-03-28 22.53.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/467266/96dbc2f5-b197-e296-d642-b50b9eea1cde.png)

レイアウトが崩れていますが、牛のAAだけでなく

```
$the_cow = <<"EOC";
```

なども書かれています。これは、perl の$the_cow変数にAAを代入している処理です。この部分も踏襲して、
```
$the_cow = <<EOC;
     $thoughts
      $thoughts
          <<
     ___( ^     )
     ___         )____
        | |      _ ] _ \\
        | |_|    )
        | |_|     \\ 
        ""(   ) _ _ ^~
        _ ( _) 
EOC
```
というようなファイルを作成し、sukina_souzai_happyou_dragon.cowとかの名前でcowsディレクトリの下に追加します。

# 表示方法
cowsayに-fオプションをつけて、保存したファイル名で呼び出せば良いです。

```
$ cowsay -f sukina_souzai_happyou_dragon "からあげ"
```

![スクリーンショット 2024-03-28 22.36.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/467266/84ffc707-4156-0804-e905-384811e15dc1.png)

好き好き大好き〜

# まとめ
cowsayコマンドは標準入力を受け取って表示するので、別のコマンドと併用すればランダムな好きな惣菜を言わせることもできるでしょう。Unixコマンドって楽しいですね。

# 参考記事
[好きな惣菜発表ドラゴンのドラゴン](https://commons.nicovideo.jp/works/nc355601)
[cowsayで現場猫にヨシ！されたい件](https://qiita.com/kowori_tadano/items/3045c445d90ca37c1ee4)
【AWS-IAM】アカウント棚卸時に、新規参画者のアカウントを作成したい



![AmazonSQS 障害時DLQに転送されたキューをSQSに再送したい(DLQ再処理)のコピー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3754524/db760201-e2b0-3665-f88c-8dfec4c93dd4.png)


## 本記事で実現できること
アカウント棚卸時に、新規参画者のアカウントを作成する

## 前提
- AWSマネコンはログイン済み
- 2024.3.28 時点でのコンソールのUIになります
- AWSコンソールのパスワードは下記、パスワードポリシーに準ずる
・パスワード最小文字数：14文字
・少なくとも1つのアルファベットの大文字 (A～Z) が必要
・少なくとも1つのアルファベットの小文字 (a～z) が必要
・少なくとも1つの数字が必要
・パスワード有効期限：90日
・直近のパスワードの再利用を禁止：5回
・MFA設定：必須


## 簡単な解説
全部で7フェーズ

①ホーム画面で、画面上部検索欄に[**IAM**]と入力。
　出てくるサービスの中から[**IAM**]をクリック

![AmazonSQS 障害時DLQに転送されたキューをSQSに再送したい(DLQ再処理)のコピー (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3754524/080b3166-ce95-28ce-0536-cf33663e8816.png)


②左画面で[**ユーザー**] を選択後、右画面から［**ユーザーの作成**］をクリックする。
![AmazonSQS 障害時DLQに転送されたキューをSQSに再送したい(DLQ再処理)のコピー (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3754524/0f4e5e1b-9a8d-863e-554d-4809a0b9ecc1.png)

③以下の通りに設定し、最後に［**次へ**］をクリックする。
| 項目名 | 説明 |
|:-----------|:-----------|
|  ユーザー名 |  任意のユーザー名を入力する。 |
| AWSアクセスの種類  | ［AWS マネージメントコンソールへのユーザーアクセスを提供する - オプション］をチェック  |
|  コンソールのパスワード | [自動生成されたパスワード]を選択する。  |
| ユーザーは次回のサインイン時に新しいパスワードを作成する必要があります  |  チェックを入れる。 |

![【AWS-IAM】アカウント棚卸時に、新規参画者のアカウントを作成したい.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3754524/64cf4962-8643-6e96-8296-699cff5cbcde.png)


④［**ユーザーをグループに追加**］をクリックする。
![【AWS-IAM】アカウント棚卸時に、新規参画者のアカウントを作成したい (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3754524/e08267fc-9a92-022a-ba54-fc0ee3a35ad6.png)


⑤適切な所属グループを割り当て、[**次へ**]をクリックする。

![【AWS-IAM】アカウント棚卸時に、新規参画者のアカウントを作成したい (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3754524/c6a38904-f6ae-6beb-e847-d066e52f29c1.png)



⑥確認画面で、設定内容を確認し、［**ユーザーの作成**］をクリックする。

![【AWS-IAM】アカウント棚卸時に、新規参画者のアカウントを作成したい (4).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3754524/555d7618-9814-3e21-24a2-5c027fc00b05.png)


⑦[**.csvファイルをダウンロード**]をクリックしてcsvファイルをダウンロード、
　任意の場所に保存し、[**ユーザーリストに戻る**]をクリックする。

![【AWS-IAM】アカウント棚卸時に、新規参画者のアカウントを作成したい (5).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3754524/b8080875-42ab-c442-87c8-d55b559a130e.png)

## まとめ
本稿が、IAMで新規参画者のアカウントを作成したい方の参考になれば嬉しいです。

ITエンジニア向け、AWS資格取得を目指す方向けに個人ブログで記事も投稿していますので、
合わせて読んでもらえると嬉しいです。
[ことなの学校(個人ブログ)](https://kotona-school.com)

更によりレベル感の高そうなAWS関連の発信はZennの方で行います。
こちらももしよければフォロー、ご確認いただけると嬉しいです。
[Zenn個人アカウント](https://zenn.dev/tomo_itbizblog)

Twitterでも役立つ情報を発信しますのでフォローしてもらえると嬉しいです 
→ [@tomo_ITBizBlog](https://twitter.com/tomo_ITBizBlog)