OmniAICreator/Qiita-1.07M huggingface dataset:
importmapのhelpで出てくるコマンドを試してみた

## はじめに
railsのimportmapを使っていて、そういえばpin以外にどういうコマンド使えるのかと思ったので、使ってみたいと思います。

## importmapのコマンド
### importmap help [COMMAND]
利用可能なコマンド、または指定された特定のコマンドの詳細な説明を表示する。
利用可能なコマンドを表示
```bash
$ docker compose run --rm web ./bin/importmap help

Commands:
  importmap audit              # Run a security audit
  importmap help [COMMAND]     # Describe available commands or one specific command
  importmap json               # Show the full importmap in json
  importmap outdated           # Check for outdated packages
  importmap packages           # Print out packages with version numbers
  importmap pin [*PACKAGES]    # Pin new packages
  importmap unpin [*PACKAGES]  # Unpin existing packages
  importmap update             # Update outdated package pins
```
指定された特定のコマンドの詳細な説明を表示
```bash
$  docker compose run --rm web ./bin/importmap help pin

Usage:
  importmap pin [*PACKAGES]

Options:
  -e, [--env=ENV]    
                     # Default: production
  -f, [--from=FROM]  
                     # Default: jspm

Pin new packages
```

### importmap audit
プロジェクト内の依存関係に潜在的なセキュリティ問題がないかチェック
```bash
$ docker compose run --rm web ./bin/importmap audit

No vulnerable packages found
```

### importmap json
importmapの全内容をJSON形式で表示
```bash
$ docker compose run --rm web ./bin/importmap json

{
  "imports": {
    "application": "/assets/application-f3e871e7be89ccb0adccd09d1fb0f2c5f0583d0626142906e3b227e5641284be.js",
    "@hotwired/turbo-rails": "/assets/turbo.min-918a6cf2f2be8ed9555c9a11eee69c7dc2f01770802815576efc931876b327fb.js",
    "@hotwired/stimulus": "/assets/stimulus.min-dd364f16ec9504dfb72672295637a1c8838773b01c0b441bd41008124c407894.js",
    "@hotwired/stimulus-loading": "/assets/stimulus-loading-3576ce92b149ad5d6959438c6f291e2426c86df3b874c525b30faad51b0d96b3.js",
    "bootstrap": "/assets/bootstrap.min-158d51560e04dda7c718c1c8f31e72d6c2eef7028a80a158043380b15e6b5aef.js",
    "controllers/application": "/assets/controllers/application-368d98631bccbf2349e0d4f8269afb3fe9625118341966de054759d96ea86c7e.js",
    "controllers/hello_controller": "/assets/controllers/hello_controller-549135e8e7c683a538c3d6d517339ba470fcfb79d62f738a0a089ba41851a554.js",
    "controllers": "/assets/controllers/index-2db729dddcc5b979110e98de4b6720f83f91a123172e87281d5a58410fc43806.js"
  }
}
```

### importmap outdated
更新が必要なパッケージのリストを表示
```bash
$ docker compose run --rm web ./bin/importmap outdated

No outdated packages found
```

### importmap packages
プロジェクト内で使用されているすべてのパッケージの一覧が表示
```bash
$ docker compose run --rm web ./bin/importmap packages

jquery 3.7.1
```

### importmap pin [*PACKAGES]
新しいパッケージを固定する
```bash
$  docker compose run --rm web ./bin/importmap pin jquery

Pinning "jquery" to vendor/javascript/jquery.js via download from https://ga.jspm.io/npm:jquery@3.7.1/dist/jquery.js
```

### importmap unpin [*PACKAGES]
既存のパッケージの固定を解除する
```bash
$ docker compose run --rm web ./bin/importmap unpin jquery

Unpinning and removing "jquery"
```

### importmap update
 古くなったパッケージpinを更新
```bash
$ docker compose run --rm web ./bin/importmap update

No outdated packages found
```

## 終わりに
使ったことのないコマンドがほとんどでしたが、有用そうなコマンドがいくつかあったので試せてよかったです。
リポジトリのフォーク（fork）について

# はじめに
フォークされているリポジトリがあるプロジェクトへ参画することになったのですが、恥ずかしながらフォークという言葉に聞き覚えがなかったため調べてみました。

# フォーク（fork）とは？
GitHub Docsを見てみると下記のように書かれています。
>フォークとは、元の "上流" リポジトリとコードと可視性の設定を共有する新しいリポジトリです。

うーん、ピンときませんね。
一つ一つ分解して見ていくことにしましょう。

## 上流リポジトリについて
オリジナリのリポジトリのことを「**上流の**」リポジトリと呼びます。
フォークを使うと上流のリポジトリをベースとして、Github上に別のリポジトリとして新たに作成されます。

また、リポジトリをフォークした後は、上流のリポジトリから更新をフェッチしてフォークを最新の状態に保つことができ、プルリクエストを使ってフォークから上流のリポジトリに変更を提案できます。

## フォークの可視性について
フォークは「コード」と「可視性の設定」を上流リポジトリと共有するリポジトリです。
例えば、上流のリポジトリがパブリックである場合、フォークも全てパブリックになります。

リポジトリを削除したり、リポジトリの可視性を変更すると、リポジトリのフォークに影響するため注意が必要です。（※詳しくは[こちら](https://docs.github.com/ja/pull-requests/collaborating-with-pull-requests/working-with-forks/what-happens-to-forks-when-a-repository-is-deleted-or-changes-visibility)を参照してください）

## どんな時にフォークを使うのか？
フォークを活用することで、上流のリポジトリに影響を及ぼすことなく自由に変更を加えることができるため、主に以下のような用途があるようです。

### オーブンソースプロジェクトへの貢献
オープンソースプロジェクトに貢献する場合（バグ修正や新規機能の追加など）、まずリポジトリをフォークして自分のGitHubアカウントにコピーを作成します。
その後、ローカルで変更を加え、プルリクエストを通じて上流のリポジトリに変更を提案します。

### 独自のカスタマイズ
公開されているプロジェクトを自分の用途に合わせてカスタマイズしたい場合にフォークします。
上流のリポジトリには影響を与えず、自分だけカスタマイズされたバージョンを持つことができます。

例えば、ほとんどのLinuxディストリビューションは他のディストリビューションからの派生であり、その多くはDebian、Red Hat、Slackwareのどれかをフォークしたものです。

### 学習目的
他の人のコードを学ぶためにリポジトリをフォークします。
フォークしたリポジトリで自由に実験しながら、オリジナルのコードベースを参照し、コードの動作や構造を理解することができます。

自分が勉強したい言語を使っているOSSなどがあれば、非常に参考になりそうです。
01_これから目指したいもの、自己紹介兼ねて

# はじめまして。エルシアです。

開発案件に携わりたくも、スキル的に厳しい状況であると認識したため、こちらも含めて情報収集を行っています。

# 簡単な経歴
関東在住の30代前半の女性です。
経歴は、高校卒業→接客→コールセンター→事務、これらを12年ほど？やっていました。
それからエンジニアとして転職し、結合テストを1年→VBAを1年少々。
現在勤務している現場では、1人でVBAを用いたマクロツール、Accessのツールを改修・修正など保守のようなお仕事をしています。

# 現状から今後を考える
事務から転職した当初より、開発をやりたいと希望しておりました。
そこからテストなどの案件に参加させていただいておりました。
少しずつ向かいたいところへ向かえているかと思いきや全くそうでもなさそうで、開発から見ると実際はほぼ未経験という扱いになるとのこと。
そのため、次のステップへ向かうためにどのようなことをしていくのが良いのかを考えています。

# 個人でのツール作成で知識をつけたい
手っ取り早いのはポートフォリオを作成することを兼ねて、ツールを作成し言語などを勉強することかなと思いました。

現状作成を考えているツール
・家計簿記録ツールの作成
　→プロジェクトのように機能など決める資料を残す
・ゲームのデイリー・ウィークリー管理ツールの作成（ToDoリスト）
　→ 家計簿ツールと同じく記録していく。
個人的にやってるゲームが多いのでパソコンで欲しい...

# 恥ずかしながら資格を持っていません
この3つを今年のうちにとっていきたいです。
・ITパスポート
・情報処理試験
・JavaのSilver

# ひとまずここまで
ここまでお読みいただきありがとうございます。
情報収集・メモをかねての発信がメインになるかと思います。
先輩の方々からアドバイスを頂けると幸甚にございます。
どうぞよろしくお願いします！エルシアでした。
logical cpuとは

- cpuには physical cpuとlogical cpuがある
- physical cpuをhardware levelでthreadingしたのがlogical cpuだ
- logical cpuにはsoftware levelのthreadとは違くconcurrentlyせずparallellyする
- これを実現した技術はhyper threading(intel)とsimultaneous multi threading(AMD)がある
- pytestではpluginの[pytest-xdist -n option](https://qiita.com/HJ9851/items/8c8f2a25e5c54f71050e)を使う時にlogical cpuを認識してmulti processingをする
Google CloudのVertex AI SearchでサクッとRAG構築

# はじめに
実は以前、AWSのBedrockでサクッとRAG構築はやったことがありました！社内のLT会でも紹介したのですが、信じられないくらい簡単でした・・・！

今回は機会があってGoogle Cloudでも簡単に出来るよ〜というお話をいただいたので、ちょこっと遊んでみました。その備忘録になります

※因みに僕はほぼGCP触ったことがなくて、手探りで頑張りました、至らぬ点があってもご容赦くださいませ><

# 使用サービス
- Google Cloud
    - cloud storage
    - Vertex AI Agent Builder
        - cloud storageなどをデータソースとしたRAGが作れるみたいです！

# Cloud Storageにデータソースを配置する
非構造化データであっても大丈夫そうなので、テキトーにテキストファイル作成して、保存します。

## バケットの作成
コンソールからCloud Storageと検索して下記画像の通り、バケットを作成します
![CleanShot 2024-06-24 at 22.33.26@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2619923/6a539afc-7a52-e1a5-93e2-121af74ddaee.png)

:::note
- バケット名はグローバルに一意な命名となります
- リージョンは、単一でOKだと思います、東京リージョンを選択
:::


## バケットにファイルをアップロード
データソースとなるファイルになります！
非構造化データで良いので、PDFとかテキストファイルとか好きなものを入れてください！

# Agent Builder

Vertex AI Agent Builderは、Googleが提供しているAgent 開発をサポートするサーバーレスであり、フルマネージドなサービスです。（イメージで言うとAWSでいうBedrockに近いと思います（違っていたらすみません））
ノーコード・ローコードで Agent開発ができる便利屋さんです！

RAGを用いたチャットボットも割と簡単に出来るのだと思います！今回はしませんが、BigQueryと連携したりも簡単に出来るはずなので、スプシに色々まとめているケースなど便利なのかもしれないですね


因みに料金では[こちら](https://cloud.google.com/products/agent-builder?hl=en#pricing)を参照ください！

## データストアの作成
![CleanShot 2024-06-24 at 22.52.48@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2619923/10634fb5-6d1e-1863-8492-6e802ccf9e92.png)
画像の手順でデータストアを選択します！

データソースを選択する画面になりますが、
1. Cloud Storageを選択して
    ![CleanShot 2024-06-24 at 22.56.22@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2619923/aae42fd2-c93c-6332-962e-05dfe8c7228f.png)

2. 「参照」をクリックして、フォルダのパスを選択
3. 「非構造化ドキュメント」 を選択します！
![CleanShot 2024-06-24 at 22.56.58@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2619923/055f5935-2c69-8c6d-1bb0-376fac1dfb3c.png)

# アプリ作成
いよいよアプリを作っていきます！
![CleanShot 2024-06-24 at 22.58.12@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2619923/7a9117ab-39d0-c933-6d6f-f6865186d839.png)
画像から「検索」を選択してください！

「構成」はデフォルトの「汎用」でOKです

## データストアの選択
先ほど作成したデータストアを選択して「作成」をしてください
※5~10分くらい時間がかかると思いますが気長に待ちましょう！

# アプリを動かしてみよう
ここまででRAGで遊ぶ準備ができました！
「プレビュー」を押して試してみましょう
![CleanShot 2024-06-24 at 23.25.08@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2619923/dc312275-1d64-e0a8-fc22-4f7da5106a3e.png)

データソースとして与えたファイルの内容を踏まえた回答になっていそうです！
![CleanShot 2024-06-24 at 23.31.29@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2619923/e770b3a1-bfa0-469d-7120-8b4f460e7761.png)


「構成」からモデルとか選択できます！
![CleanShot 2024-06-24 at 23.26.14@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2619923/d7cfe7d6-0fb5-b37b-f08b-f1e63a34c80a.png)

しれっと選択肢がいっぱいあります！デフォルトのものからGeminiを選択することも可能です！

# 終わりに
本当はチャットやエージェントも使ってみたかったのですが、ドキュメントが英語過ぎて読むの時間かかりそうだったので次回に持ち込むことにしました！

業務でもAWSを使う機会が多かったのですが、Google Cloudも普通に使いやすかったです！
どちらが良いとかではなく、解決したい課題に対してどんなアプローチが効果的かを選択するだけだと思います。

スプレッドシートとかに依存している現場とかであればもしかすると「スプレッドシート->BigQuery->Vertex AI」という構図が威力を発揮するのかもしれないなぁ〜と思いました！

近日中に上記のフローでRAG組んでみようかなと思います！

## 参考
https://cloud.google.com/enterprise-search?hl=ja
https://cloud.google.com/products/agent-builder?hl=ja
生成AIの話でよく聞くRAGって何？

# はじめに
こんにちは、H×Hのセンリツ大好きエンジニアです。（同担OKです😉）
今回はAWS Summit Japan 2024で頻出だったRAGについて個人的に理解してまとめてみました。
誤った情報などありましたら教えていただけると幸いです。

# RAGとは？
RAGは、Retrieval-Augmented Generationの略で、日本語訳すると検索拡張生成になります。その名前の通り、言語モデル（LM）によるテキスト生成に、学習していない外部情報を加えることにより回答精度を向上させる技術です。

どういうことか説明します。
生成AIが与えられた質問に対して回答を行う際、基本的には事前学習させたLLMを用いて適した回答を用意します。

しかし、ChatGPTなどの生成AIでは一般的な情報を学習させたLLMを用いているため、専門性の高い質問や個人に基づいた質問に対しては回答精度が低くなってしまいます。

例えるならば、大学受験の勉強している人にいきなり留数定理を説明して欲しいとお願いするようなもんです。
![スクリーンショット 2024-06-24 23.18.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2653241/14c56e5d-6d64-9766-8d02-b97a082be116.png)

**受験生が今まで習ってきたのは高校数学の範囲までなのに、急に留数定理とか言う大学数学の範囲を教えてと言われても答えられませんね。**

このようにして、回答できない問題があった時あなたならどうしますか？

。。。そうですね！留数定理の公式と導き方が載っている書籍を手に取って学習することで答えてあげられます！
（何て優しい受験生、僕なら自分のことで頭がいっぱいになるのに。。。😉）

図にするとこんな感じです。
![スクリーンショット 2024-06-24 23.30.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2653241/c746bab6-a367-b75a-19d1-ee7d4d164577.png)

未学習の情報を、外部から受け取ることで質問に対しての回答が正確になりやすくなります！
上の図から、受験生を生成AI、参考書をRAGと解釈すると分かりやすいかと思います！

このように、RAGによって生成AIによる回答精度が向上する訳ですね！
ただし、デメリットももちろん存在します。
RAGは専門的な知識を要するために開発コストが掛かる点や、RAGを行うことで回答までの時間が掛かる点があるため、ユースケースによってRAGの利用は考える必要はありますね。

# おわりに
今回は自分なりに解釈したRAGの仕組みについて解説しました！
RAGは非常に便利ですが、外部情報を全て言語モデルに与えてあげればいいじゃん！と言うものでもないのが難しい所だなと感じました。🤔（文字数の制限やコスト面などが原因）

最後までご覧いただきありがとうございました！
以上、センリツでした。🤓
Pythonで主成分分析のbiplot関数を作ってみた

biplot関数とはなんぞやかと言いますと、主成分分析をやって2次元に圧縮した散布図に因子負荷量のベクトルも一緒にプロットする散布図です。

# 関数(教師あり)
```Python3
from sklearn.decomposition import PCA
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
def biplot_spv(df, y):
    for col in df.columns:
        df[col] = (df[col] - df[col].mean()) / df[col].std()
    model = PCA()
    model.fit(df)
    df_pc = model.transform(df)
    com = model.components_
    evr = model.explained_variance_ratio_
    fac = []
    for i in range(len(evr)):
        fac.append(np.sqrt(model.explained_variance_ratio_)[i] * model.components_[i])
    fig, ax1 = plt.subplots()
    ax2 = ax1.twinx()
    ax2.scatter(df_pc[:, 0], df_pc[:, 1], cmap="brg", c=y)
    ax3 = ax1.twiny()
    ylim = [abs(max(fac[1])), abs(min(fac[1]))]
    xlim = [abs(max(fac[0])), abs(min(fac[0]))]
    for i in range(len(df.columns)):
        ax3.plot([0, fac[0][i]], [0, fac[1][i]], color="#FF0000")
        ax3.text(fac[0][i], fac[1][i], df.columns[i])
    ax3.set_xlim(-max(xlim), max(xlim))
    ax3.set_ylim(-max(ylim), max(ylim))
    plt.show()
```

## 使用例
```Python3
import pandas as pd
df = pd.read_csv("iris.csv")
biplot_PCA(df.drop("category", axis=1), y=df["category"])
```
![Untitled.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2782889/7ce3b3b0-7e0c-cd4a-cc65-716a3986672d.png)



# 関数(教師なし)
```Python3
from sklearn.decomposition import PCA
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
def biplot_nonspv(df):
    for col in df.columns:
        df[col] = (df[col] - df[col].mean()) / df[col].std()
    model = PCA()
    model.fit(df)
    df_pc = model.transform(df)
    com = model.components_
    evr = model.explained_variance_ratio_
    fac = []
    for i in range(len(evr)):
        fac.append(np.sqrt(model.explained_variance_ratio_)[i] * model.components_[i])
    fig, ax1 = plt.subplots()
    ax2 = ax1.twinx()
    ax2.scatter(df_pc[:, 0], df_pc[:, 1], color="#000000")
    ax3 = ax1.twiny()
    ylim = [abs(max(fac[1])), abs(min(fac[1]))]
    xlim = [abs(max(fac[0])), abs(min(fac[0]))]
    for i in range(len(df.columns)):
        ax3.plot([0, fac[0][i]], [0, fac[1][i]], color="#FF0000")
        ax3.text(fac[0][i], fac[1][i], df.columns[i])
    ax3.set_xlim(-max(xlim), max(xlim))
    ax3.set_ylim(-max(ylim), max(ylim))
    plt.show()
```

## 使用例
```Python3
import pandas as pd
df = pd.read_csv("seiseki.csv")
biplot_nonspv(df)
```
![Untitled.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2782889/5a1dc10a-f0d7-f3d3-529c-6fd5dea53739.png)
Tabcmdを利用して、Tableau CloudにデータソースをPublishしてみた

## 前提
・Tabcmd実行マシンは、Windows OSを前提にしております。
## 参考サイト
https://help.tableau.com/current/online/ja-jp/tabcmd.htm

https://github.com/tableau/tabcmd/releases

https://help.tableau.com/current/online/ja-jp/security_personal_access_tokens.htm

## 手順
### 1.Tabcmdのインストール
#### ①以下のサイトから、Tabcmdをダウンロード
・Windows OSの場合：tabcmd.exe
・mac OSの場合：tabcmd-mac.zip

https://github.com/tableau/tabcmd/releases

#### ②Tabcmdをインストール
ダウンロードしたtabcmd.exeをダブルクリックして、インストール
インストール先など変更の場合は、以下のヘルプをご参照ください。

https://help.tableau.com/current/online/ja-jp/tabcmd.htm
### 2.Tableau CloudのPATを作成
https://help.tableau.com/current/online/ja-jp/security_personal_access_tokens.htm
#### ①Tableau Cloudの右上のプロファイルアイコンをクリックし、「マイアカウントの設定」を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562390/1d883033-f63d-8c00-90e2-a28c0c19a9a8.png)
#### ②個人用アクセストークンのトークン名を入力し、「トークンを作成する」をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562390/c0941854-f678-ca14-e9a2-39ec24b1af05.png)
※表示されるシークレットは２度と表示されないため、メモしておく
### 3.Tabcmdより、Tableau Cloudへログイン
#### ①コマンドプロンプトを起動し、tabcmd.exeをインストールしたフォルダに移動
例：
```
C:\Users\testuser>cd Downloads
```
#### ②手順2で作成したPATを利用して、Tableau Cloudへログイン
例：(日本のPodではない場合は、-sのURLを変更してください。)
```
tabcmd login -s https://prod-apnortheast-a.online.tableau.com -t サイト名 --token-name トークン名 --token-value トークンシークレット
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562390/f998e57c-0c95-fd2d-f631-0522242ac646.png)
### 4.Tableau CloudにデータソースをPublishするバッチを作成
例：
```
@echo off
cd "C:\Users\testuser\Downloads"
tabcmd publish "データソースの場所" -r "プロジェクト名" --overwrite
```
階層プロジェクトにパブリッシュする場合は、-rの代わりに以下を指定
```
--parent-project-path "Main" -r "Nested"
```
https://help.tableau.com/current/server/ja-jp/tabcmd_cmd.htm#iddf805b62-18ff-4497-9245-adc6905b2084
### 5.バッチを実行
#### ①バッチをダブルクリックして、実行
#### ②Windowsのスケジュールに登録して、自動化する場合は、以下のブログをご参考。
https://qiita.com/Richard_Roe/items/44e16841f16ee40c6113
### 6.Tablea Cloudへアクセスし、データソースがパブリッシュされてることを確認
## トラブルシューティング
#### ①プロキシ
プロキシーが途中経路上に存在する場合は、—proxy もしくは -x オプションが利用可能。
プロキシーで認証が必要な場合は、あいにく対応するオプションが実装されてないため、
プロキシーを回避してインターネット経由でTableau Cloudへ接続頂く必要がある。

https://tableau.github.io/tabcmd/docs/tabcmd_cmd.html

　（抜粋）
　-x, —proxy
　Use to specify the HTTP proxy server and port (Host:Port) for the tabcmd request.
#### ②tabcmd loginユーザ
tabcmd loginコマンドを使用する場合は、サーバーがSAMLを使用するよう構成されている場合でも SAMLシングルサインオン(SSO)を使用できない。
ログインするには、サーバー上で作成されているユーザー名とパスワードを渡す必要がある。
ユーザ名とパスワードを渡せない場合は、手順2を参考にPATをご利用ください。
node.jsのamazon-paapiでアマゾンアフィリエイトの取得ができなかった

　アマゾンのアフィリエイトでは、ブログにアソシエイトIDを貼り付けると収益化ができるもののもある。自分のサイトではそういった機能がないものもあるので、アソシエイトリンクをアマゾンのAPIを使って生成する必要がある。
 
今まではアマゾンが用意していたものをそのまま使っていたが簡単化したライブラリがあったので使ってみようと思う。

node.jsのPA-APIライブラリ「amazon-paapi」
https://github.com/jorgerosal/amazon-paapi

### インストール方法

npm install amazon-paapi --save

アクセスキーやシークレットキーは下から取得する。
https://affiliate.amazon.co.jp/assoc_credentials/home

サンプルコードがアマゾンアメリカなので日本に変える。結果が「Error: Bad Request」と出て動かなかった。サンプルコードのまま.com出やるとtoo many requestと出た。多分アメリカアマゾンでのアフィリエイト収益が出ない結果だろう。アメリカ以外の場所でテストがしていないのではないか。

```js
const amazonPaapi = require('amazon-paapi');

const commonParameters = {
  AccessKey: '<YOUR  ACCESS  KEY>',
  SecretKey: '<YOUR  SECRET  KEY>',
  PartnerTag: '<YOUR  PARTNER  TAG>', // yourtag-20
  PartnerType: 'Associates', // Default value is Associates.
  Marketplace: 'www.amazon.com', // Default value is US. Note: Host and Region are predetermined based on the marketplace value. There is no need for you to add Host and Region as soon as you specify the correct Marketplace value. If your region is not US or .com, please make sure you add the correct Marketplace value.
};

const requestParameters = {
  ASIN: 'B07H65KP63',
  Resources: [
    'ItemInfo.Title',
    'Offers.Listings.Price',
    'VariationSummary.VariationDimension',
  ],
};

/** Promise */
amazonPaapi
  .GetVariations(commonParameters, requestParameters)
  .then((data) => {
    // do something with the success response.
    console.log(data);
  })
  .catch((error) => {
    // catch an error.
    console.log(error);
  });
  ```
ODBCドライバーを使ったSQL実装

前回も似たようなの作った気がする

```powershell:odbc.ps1
# Load the required .NET assembly
Add-Type -Path "path/to/Oracle.ManagedDataAccess.dll"

# Connection string and query parameters
$connectionString = "User Id=your_user;Password=your_password;Data Source=your_data_source"
$query = "SELECT your_blob_column FROM your_table WHERE your_condition"
$outputFilePath = "path/to/output/file"

try {
    # Create and open the Oracle connection
    $conn = New-Object Oracle.ManagedDataAccess.Client.OracleConnection($connectionString)
    $conn.Open()

    # Create the Oracle command
    $cmd = $conn.CreateCommand()
    $cmd.CommandText = $query

    # Execute the query and get the data reader
    $reader = $cmd.ExecuteReader([System.Data.CommandBehavior]::SequentialAccess)

    if ($reader.Read()) {
        $bufferSize = 1024 * 1024 # 1MB buffer
        $buffer = New-Object byte[]($bufferSize)
        $fieldOffset = 0
        $bytesRead = 0

        # Create a file stream to write the BLOB data
        $fs = [System.IO.File]::Create($outputFilePath)

        do {
            $bytesRead = $reader.GetBytes(0, $fieldOffset, $buffer, 0, $bufferSize)
            $fs.Write($buffer, 0, $bytesRead)
            $fieldOffset += $bytesRead
        } while ($bytesRead -gt 0)

        # Close the file stream
        $fs.Close()

        Write-Output "BLOB data has been successfully written to the file."
    } else {
        Write-Output "No data found."
    }

    # Close the data reader and the connection
    $reader.Close()
    $conn.Close()
} catch {
    Write-Output "An error occurred: $_"
}
```
Crystal で Welcome to AtCoder を解いてみた

[Qiita Engineer Festa 2024（キータ・エンジニア・フェスタ 2024） - Qiita](https://qiita.com/official-campaigns/engineer-festa/2024)
において、約1ヶ月で38記事という大量の記事の投稿を要求されることがわかった。
そこで、あまりコストをかけずに記事数を稼ぐ方法を考えた結果、「Welcome to AtCoder を様々な言語で解く」ことを思いついた。
単に解くだけでなく、使用する言語仕様の解説を入れれば、記事として一応成立するだろう。

# Welcome to AtCoder

[PracticeA - Welcome to AtCoder](https://atcoder.jp/contests/abs/tasks/practice_1)

Welcome to AtCoder では、以下の形式で整数 $a$, $b$, $c$ および文字列 $s$ が入力として与えられる。

```text
a
b c
s
```

この入力をもとに、与えられた整数の和 $sum = a + b + c$ および文字列 $s$ を、以下の形式で出力することが求められる。

```text
sum s
```

# 今回用いる Crystal の機能

## 変数への代入と加算代入

[ローカル変数 - Crystal](https://ja.crystal-lang.org/reference/syntax_and_semantics/local_variables.html)
[代入 - Crystal](https://ja.crystal-lang.org/reference/syntax_and_semantics/assignment.html)

`変数 = 値` を用いると、右辺の値を左辺の変数に代入できる。
`変数 += 値` を用いると、右辺の値を左辺の変数の値に加算し、その和を左辺の変数に代入できる。

## 文字列の処理

[文字列 (String) - Crystal](https://ja.crystal-lang.org/reference/syntax_and_semantics/literals/string.html)
[String - Crystal 1.12.2](https://crystal-lang.org/api/1.12.2/String.html)

`""` で囲むことで、文字列を表現できる。
文字列中に `#{式}` を入れると、その式の計算結果を文字列に埋め込むことができる。

[`文字列.to_i`](https://crystal-lang.org/api/1.12.2/String.html#to_i%28base%3AInt%3D10%2Cwhitespace%3ABool%3Dtrue%2Cunderscore%3ABool%3Dfalse%2Cprefix%3ABool%3Dfalse%2Cstrict%3ABool%3Dtrue%2Cleading_zero_is_octal%3ABool%3Dfalse%29-instance-method) を用いると、文字列をそれが表す整数に変換できる。

[`文字列.split`](https://crystal-lang.org/api/1.12.2/String.html#split%28limit%3AInt32%7CNil%3Dnil%2C%26block%3AString-%3E_%29-instance-method) を用いると、文字列を空白文字で区切り、それぞれの部分について処理を行うことができる。

## 入出力

[コマンドライアプリケーション - Crystal](https://ja.crystal-lang.org/reference/getting_started/cli.html)
[|| - Crystal](https://ja.crystal-lang.org/reference/syntax_and_semantics/or.html)

`gets` を用いることで、入力を1行読み込むことができる。
読み込んだ結果は文字列で、最後に改行文字はつかない。

```crystal
line = gets
```

既に最後まで読んでいた場合は、文字列のかわりに `Nil` が返る。
以下のようにすると、`Nil` のケースを弾き、後の処理で文字列のみを扱うことができる。

```crystal
line = gets
exit if line.nil?
```

`||` 演算子を用いると、左辺が偽ならば右辺の値、そうでなければ左辺の値を得ることができる。
すなわち、左辺と右辺の両方が偽ならば偽、そうでなければ偽でない値を得ることが出来る。
これを用いて、複数行の `Nil` チェックをまとめて行うことができる。

```crystal
line1 = gets
line2 = gets
exit if line1.nil? || line2.nil?
```

`puts` を用いることで、値を出力し、さらに改行を出力できる。

```crystal
puts "hello"
```


# 提出コード

```crystal
line1 = gets
line2 = gets
line3 = gets

exit if line1.nil? ||  line2.nil? || line3.nil?

sum = line1.to_i
line2.split { |v| sum += v.to_i }
puts "#{sum} #{line3}"
```

[提出 #54907061 - AtCoder Beginners Selection](https://atcoder.jp/contests/abs/submissions/54907061)
AMIに紐づけられていないsnapshotを削除する

# 概要
バックアップ目的でAMI（とそれに紐づくsnapshot）を作ったはいいものの、AMIだけを削除してsnapshotを削除し忘れることはよくあるかと思います。
これらの忘れが積もりに積もって「EC2 その他」として請求が来てから気づくことがあります。

そんなときに使える、AMIに紐づいていないsnapshotをすべて削除するスクリプトです。

# コード
```
import boto3
import datetime

ec2 = boto3.client('ec2')

# AMIに紐づけられているスナップショットを取得
def list_used_snapshot_ids(ec2):
    response = ec2.describe_images(Owners=['self'])
    res = []
    for image in response['Images']:
        snapshot_ids = get_snapshot_ids_from_image(image)
        res += snapshot_ids
    return res

def get_snapshot_ids_from_image(image):
    snapshot_ids = []
    for device in image['BlockDeviceMappings']:
        if 'Ebs' not in device:
            continue

        id = device['Ebs']['SnapshotId']
        snapshot_ids.append(id)
    return snapshot_ids


# AMIに紐づけられていないスナップショットを取得
def list_unused_snapshot_ids(ec2,used_snapshot_ids):
    all_snapshot_ids = list_all_snapshot_ids(ec2)
    res = all_snapshot_ids
    for used_snapshot_id in used_snapshot_ids:
        if used_snapshot_id in res:
            res.remove(used_snapshot_id)
    return res

def list_all_snapshot_ids(ec2):
    response = ec2.describe_snapshots(OwnerIds=['self'])
    snapshot_ids = []
    for snapshot in response['Snapshots']:
        # 利用されていないかつ、2024年1月1日より前に作成されたスナップショットを削除
        # if snapshot['StartTime'] < datetime.datetime(2024, 1, 1, 0, 0, 0, 0, tzinfo=datetime.timezone.utc):
        snapshot_ids.append(snapshot['SnapshotId'])
        
    return snapshot_ids


# SNAPSHOTを削除
def remove_unused_ebs_snapshots(ec2,delete_snapshot_ids):   
    for snapshot_id in delete_snapshot_ids:
        time = datetime.datetime.now()
        print('delete snapshot: {0}, time: {1}'.format(snapshot_id, time))
        ec2.delete_snapshot(SnapshotId=snapshot_id)

def main():
    used_snapshot_ids = list_used_snapshot_ids(ec2)
    unused_snapshot_ids = list_unused_snapshot_ids(ec2,used_snapshot_ids)
    remove_unused_ebs_snapshots(ec2,unused_snapshot_ids)
    print("done")

if __name__ == '__main__':
    main()
```

# まとめ
AMIを削除しても、snapshotされておらず課金されてしまったので削除するスクリプトを作成してみました。
これとEBS Snapshot の[ゴミ箱機能](https://aws.amazon.com/jp/blogs/news/new-recycle-bin-for-ebs-snapshots/)を併用すれば安全に削除を進められるかと思います。
一緒に消してくれるフラグがあれば嬉しいなと思いつつ、どなたかの役に立てば幸いです。
sqlplus -> blob

```sql:blob_to_base64.sql
SET PAGESIZE 0
SET LONG 1000000
SET LINESIZE 1000
SET FEEDBACK OFF
SET HEADING OFF

DECLARE
    v_blob BLOB;
    v_clob CLOB;
BEGIN
    -- BLOBデータの取得
    SELECT your_blob_column INTO v_blob
    FROM your_table
    WHERE your_condition;

    -- BLOBデータをBase64エンコード
    v_clob := UTL_RAW.CAST_TO_VARCHAR2(UTL_ENCODE.BASE64_ENCODE(v_blob));

    -- Base64エンコードされたデータを出力
    DBMS_OUTPUT.PUT_LINE(v_clob);
END;
/
EXIT;
```
```powershell:motteru
#いつもの
sqlplus -s your_user/your_password@your_data_source @blob_to_base64.sql > base64_output.txt
```
```powershell:いつもの2.ps
# Base64エンコードされたファイルの読み込み
$base64String = Get-Content -Path "path/to/base64_output.txt"

# Base64デコード
$bytes = [System.Convert]::FromBase64String($base64String)

# ファイルに書き出し
$outputFilePath = "path/to/output/file"
[System.IO.File]::WriteAllBytes($outputFilePath, $bytes)

Write-Output "BLOB data has been successfully written to the file."
```
１．SQL*Plusの制約
　・SQLPlusはバイナリデータ（BLOB）を直接扱うのが難しいです。SQLPlusは主にテキストデータを処理するためのツールであり、バイナリデータをそのまま取り扱うことができません。
　・BLOBデータを直接ファイルに書き出すことができないため、Base64エンコードを利用してテキストデータに変換します。

２．Base64エンコードの利便性

・Base64エンコードはバイナリデータをテキスト形式に変換する方法であり、テキスト形式にすることでSQL*Plusや他のテキスト処理ツールで扱いやすくなります。
・Base64エンコードは汎用的なエンコーディング方法であり、デコードも容易です。ほとんどのプログラミング言語やツールでBase64デコードがサポートされています。

３．クライアント側での処理:
・クライアント側でBase64エンコードされたデータを取得し、適切なツール（例えば、PowerShell）でデコードしてファイルに書き出すことができます。
・Base64エンコードされたデータは文字データなので、SQL*Plusの出力として簡単に扱うことができます。
Hyper-VのVMが起動しなくなった話

# 結論
VHDXをホストにマウントしたのが原因で、チェックポイント（.avhdx）とのリンク？が切れてしまった
VMが起動している間はマウントできないが、停止中はできる
マウントしたVHDXは取り外しをしないとローカルにつながったままになる（と思う）

# 経緯
VHDXの格納場所を移動しようとしたところ、間違えてダブルクリックしてマウントしてしまった。
見た感じ普通にディスクを切り出したような感じだったからそのまま使っても問題ないのかもしれない
未検証未調査なのでわからない

記事を投稿しようと思った理由は、調べてみた感じ日本語の記事があまり出てこなかったから
もし何か記事があれば情報待ってます

# 操作概要
１，powershellを**管理者権限**で起動する
２，起動できなくなったVMのVHDXおよびAVHDXの格納場所を開く
３，hyper-vのチェックポイントのツリー最上部のAVHDXを参照する
４，VHDXに紐づけなおす

# 操作詳細
１，powershellを管理者権限で起動する
winキー + Rで「powershell」を入力、shift + ctrl + enterで開ける

２，起動できなくなったVMのVHDXおよびAVHDXの格納場所を開く
```
ps> cd -path 'フォルダパス'
```

３，hyper-vのチェックポイントのツリー最上部のAVHDXを参照する
```
ps> get-vhd -path 'AVHDX名'
```

ParentPathが元VHDXになっているAVHDXを探し当てる
```
PS> get-vhd 'C:\vhdx\test_11111111-2222-3333-4444-555555555555.avhdx'


ComputerName            : test
Path                    : C:\vhdx\test_11111111-2222-3333-4444-555555555555.avhdx
VhdFormat               : VHDX
VhdType                 : Differencing
FileSize                : 999999
Size                    : 999999
MinimumSize             : 999999
LogicalSectorSize       : 999999
PhysicalSectorSize      : 999999
BlockSize               : 999999
ParentPath              : C:\vhdx\test.vhdx
DiskIdentifier          : 666666666-7777-8888-9999-000000000000
FragmentationPercentage :
Alignment               : 1
Attached                : True
DiskNumber              :
IsPMEMCompatible        : False
AddressAbstractionType  : None
Number                  :
```
４，VHDXに紐づけなおす
```
ps> set-vhd -path 'AVHDX名' -parentpath 'VHDX名'
```
実行しても特になにもでない
```
ps>set-vhd -path 'C:\vhdx\test_11111111-2222-3333-4444-555555555555.avhdx' -parentpath 'C:\vhdx\test.vhdx'
```

# まとめ
操作には気を付けよう！

# 参考
https://learn.microsoft.com/ja-jp/powershell/module/hyper-v/get-vhd?view=winserver2012r2-ps

ほかにもあったけどどこかへ行ってしまったので、また見つけられたら追記する予定
3D model


```python
import numpy as np
from stl import mesh
import plotly.graph_objects as go

# STLファイルの読み込み
your_mesh = mesh.Mesh.from_file('3LandSat9Parts.stl')

# 頂点座標の取得
x, y, z = your_mesh.vectors.reshape(-1, 3).T

# 三角形の頂点インデックスの作成
i, j, k = np.arange(0, len(x), 3), np.arange(1, len(x), 3), np.arange(2, len(x), 3)

# Plotlyの3D図形オブジェクトの作成
mesh3D = go.Mesh3d(
    x=x, y=y, z=z,
    i=i, j=j, k=k,
    color='slategray',
    opacity=1,
)

# レイアウトの設定
layout = go.Layout(
    scene=dict(
        xaxis=dict(title='X軸', range=[-100, 100]),
        yaxis=dict(title='Y軸', range=[-100, 100]),
        zaxis=dict(title='Z軸', range=[-100, 100]),
        aspectmode='cube'
    ),
    margin=dict(l=0, r=0, b=0, t=0),
    width=1000,
    height=1000,
    hoverlabel_font_size=20
)

# 図の作成と表示
fig = go.Figure(data=[mesh3D], layout=layout)
fig.show()

```


```python

import numpy as np
import plotly.graph_objects as go
import pywavefront
import logging

# 警告を抑制
logging.getLogger('pywavefront').setLevel(logging.ERROR)

def rotate_vertices(vertices, angle_x, angle_y, angle_z):
    # 回転行列の作成
    Rx = np.array([[1, 0, 0],
                   [0, np.cos(angle_x), -np.sin(angle_x)],
                   [0, np.sin(angle_x), np.cos(angle_x)]])
    
    Ry = np.array([[np.cos(angle_y), 0, np.sin(angle_y)],
                   [0, 1, 0],
                   [-np.sin(angle_y), 0, np.cos(angle_y)]])
    
    Rz = np.array([[np.cos(angle_z), -np.sin(angle_z), 0],
                   [np.sin(angle_z), np.cos(angle_z), 0],
                   [0, 0, 1]])
    
    R = np.dot(Rz, np.dot(Ry, Rx))
    
    # 頂点に回転を適用
    rotated_vertices = np.dot(vertices, R.T)
    return rotated_vertices

# OBJファイルの読み込み
obj = pywavefront.Wavefront('GlobalHawk/GlobalHawkOBJ.obj', collect_faces=True)

# 頂点とファセット（面）データの取得
vertices = np.array(obj.vertices)
faces = np.array([face for mesh in obj.mesh_list for face in mesh.faces])

# 回転角度の設定（ラジアン）
angle_x = np.pi / 4  # X軸周りに45度回転
angle_y = np.pi / 6  # Y軸周りに30度回転
angle_z = np.pi / 3  # Z軸周りに60度回転

# 頂点を回転
rotated_vertices = rotate_vertices(vertices, angle_x, angle_y, angle_z)

# 3Dメッシュオブジェクトの作成
mesh3D = go.Mesh3d(
    x=rotated_vertices[:, 0],
    y=rotated_vertices[:, 1],
    z=rotated_vertices[:, 2],
    i=faces[:, 0],
    j=faces[:, 1],
    k=faces[:, 2],
    color='slategray',
    opacity=1,
)

# サンプルの散布図データの生成（ランダムな点）
num_points = 100
x = np.random.randn(num_points) * 500
y = np.random.randn(num_points) * 500
z = np.random.randn(num_points) * 500

# 散布図オブジェクトの作成
scatter3D = go.Scatter3d(
    x=x, y=y, z=z,
    mode='markers',
    marker=dict(
        size=5,
        color=z,
        colorscale='Viridis',
        opacity=0.8
    )
)

# レイアウトの設定
layout = go.Layout(
    scene=dict(
        xaxis=dict(title='X軸', range=[-500, 500]),
        yaxis=dict(title='Y軸', range=[-500, 500]),
        zaxis=dict(title='Z軸', range=[-500, 500]),
        aspectmode='cube'
    ),
    margin=dict(l=0, r=0, b=0, t=0),
    width=1000,
    height=1000,
    hoverlabel_font_size=20
)

# 図の作成
fig = go.Figure(data=[mesh3D, scatter3D], layout=layout)

# 図の表示
fig.show()
```
interface宣言~オブジェクト型を宣言するもう１つの方法~

## interface 宣言 とは
interface 宣言によって、オブジェクトの型を作成することができます。

`type`文（型alias）を使って、 `type Foo = { num: number }`のようにオブジェクトの型を宣言することができますが、他の方法として、`interface Foo { num : number}`の形でオブジェクトの型を宣言できます。
これがinterface 宣言です。

interface 宣言がどうしても必要となる場面はそこまでなく、基本的には`type`文を使用していて問題ないでしょう。
ただ、ライブラリの型にはinterface 宣言が使用されることも多く、どのような性質があるかを知っておくと理解の助けになる場面もあるかと思います。

## interface 宣言の構文
`interface 型名 オブジェクトの型`で宣言します。
```ts
interface Fish {
    name: string
}
```
interface 宣言はオブジェクトの型を宣言する方法の一つなので、型alias で宣言した型との交差型をとったりと、いわゆる通常の型として扱うことができます。
```ts
type Fish = {
    name: string
}

interface Age {
    age: number
}
```
`Fish`型と`Age`型の交差型`Fish & Age`の変数を以下のように宣言してみます。
```ts
const salmon: Fish & Age = { name : 'Salmon' }
```
変数`salmon`は`Age`型に必要な`age`プロパティを持たず、型エラーが発生します。
```
Type '{ name: string; }' is not assignable to type 'Fish & Age'.
  Property 'age' is missing in type '{ name: string; }' but required in type 'Age'.ts(2322)
```

基本的には型alias で宣言したオブジェクト型と同様の使い方ができます。
## interface 宣言の使い方
基本的には`type`で宣言されたオブジェクトの型と同じものだと捉えられます。`type`との差は、主に宣言する時にできることにあります。

interface の宣言時にはオブジェクト以外に型をつけられなかったり、Mapped Types が使用できなかったりと`type`文にしかできないことが多くありますが、代わりにinterface 宣言でしか使えない記法や性質もあります。
### extends
interface 宣言では`extends`によってinterface を拡張（継承）することができます。
拡張元にあたるinterface がもつ構造を拡張先のinterface がもつように制約をつけることができます。

```ts
interface Age {
    age: number
}

interface Fish extends Age {
    name: string
}
```
```ts
const salmon: Fish = { age: 2 }
```
`name`プロパティがないオブジェクトリテラルを代入しようとすると以下のように型エラーが出ます。
```
Property 'name' is missing in type '{ age: number; }' but required in type 'Fish'.ts(2741)
```
`Age`型を拡張したオブジェクト型である`Fish`型に値を代入するためには、`name`と`age`プロパティのどちらをも持つことが必須になっているわけです。

`interface Fish extends Age { name: string }`を型aliasで表す場合には、交差型を利用して `type Fish = Age & { name: string }`と表せます。
こちらの場合も`name`と`age`プロパティを持つことが必須となります。

### 構造的型付けシステム
TypeScript は構造的型付けシステム（structurally typed type system）が採用されています。
どのような構造をしているかによって型を判別するため、同じ構造をしたオブジェクト型であれば型alias で宣言した型でもinterface で宣言した型でも同じように扱うことができるわけですね。

https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#interfaces
Sequence MakerのタブがExcelから消えてしまった時の対処法（その1）

## はじめに
Sequence MakerはExcelから測定器を制御可能にするアドインです。この記事ではExcelのリボンからSequence Makerのタブが消えてしまった時の対処法を解説します。Sequence Makerについての詳細は以下の記事を参照ください。

https://qiita.com/sequencemaker/items/8e6a370ab0a793a06a3b

:::note warn
***お断り***
本記事の内容はSequence Maker開発元の公式見解ではなく、あくまでも個人が趣味の範囲内で執筆しているものです。記事の内容について開発元へ問い合わせることはお控えください。ご質問・要望などは各記事のコメント欄へお願いいたします。
:::

## 「SEQUENCE MAKER」タブ
Sequence Makerの各種操作はExcelのリボンにある「SEQUENCE MAKER」タブから行います。正常な時は以下のようなタブが表示されています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3821782/ddecb95d-a8ec-3c50-8ebd-754ea5c3d4f8.png)

## 「SEQUENCE MAKER」が消えることがある！
ある日突然、「SEQUENCE MAKER」がリボンから消えてしまう事があります。特に、Excelが何らかの原因でクラッシュしたり、強制終了してしまった後に発生しやすいです。一度消えてしまうと、Excelを再起動しても復活する可能性は低いです。これはExcelが強制終了したときに、直前に動作していたアドインが危険なものと判断し、隔離してしまうからです。はてさて、困りました。

## でも、安心してください！
リボンから「SEQUENCE MAKER」が消えても、心配しないでください。簡単な解決方法があります。それは…
**Sequence Makerを再インストールする**のです。
ほとんどの場合は、これで復活します。Sequence Makerは以下のサイトからダウンロード可能です。

https://sequencemaker.hioki.com/ja/

:::note warn
注意
Excelが起動していると、Sequence Makerのインストールができません。
Excelを終了してからインストールしましょう。
:::

## まとめ
困ったときの再インストールはとても有効なのだ！
Kotlin Fest 2024 参加メモ

# Kotlin Fest 2024
参加してきました。

**「Kotlinを愛でる♪」**
https://www.kotlinfest.dev/kotlin-fest-2024

**気になった単語**
- Lich(DIライブラリ)
- JetBrains Fleet
- CollectionとSequence
- Klint/detekt/konsist
- Mutex/AtomicHoge/synchronized
- State hoisting
pytest-xdist -n option

- `-n` optionを使えばlogical cpuの数ほどprocessを割り当てる
- logical cpuのかずを超えて設定するとthreadを割り当てる
- threadに関して、global interpreter lockにより processごと一つのjobのみ動作すると知っているが、どういう原理でmulti threadingをするのかについてまではまだ分からない。調査が必要だ
- `-n auto`を使えばpytest-xdistがlogical cpuの数を自動的に把握してその数ほどのprocessを割り当てる
- `-n auto`に設定したprocessの数を超えて`-n` 으로 process数を指定したらmulti threadingが動作するのでIO boundで遅くなるtestを改善できるが test codeにIO boundが発生する部分がなければCPU boundを解決するmulti processingのみで十分だ

Reference
[https://velog.io/@dahunyoo/파이썬의-병렬실행과-병렬테스트-Pytest-xdist](https://velog.io/@dahunyoo/%ED%8C%8C%EC%9D%B4%EC%8D%AC%EC%9D%98-%EB%B3%91%EB%A0%AC%EC%8B%A4%ED%96%89%EA%B3%BC-%EB%B3%91%EB%A0%AC%ED%85%8C%EC%8A%A4%ED%8A%B8-Pytest-xdist)
[https://velog.io/@sangyeon217/pytest-plugin-pytest-xdist](https://velog.io/@sangyeon217/pytest-plugin-pytest-xdist)
[https://pytest-xdist.readthedocs.io/en/stable/how-to.html#identifying-the-worker-process-during-a-test](https://pytest-xdist.readthedocs.io/en/stable/how-to.html#identifying-the-worker-process-during-a-test)
[https://blog.raccoony.dev/pytest-for-django-test/](https://blog.raccoony.dev/pytest-for-django-test/)
[https://qwlake.github.io/django/2020/06/05/building-django-test-environment/](https://qwlake.github.io/django/2020/06/05/building-django-test-environment/)
[https://blog.jerrycodes.com/pytest-split-and-github-actions/](https://blog.jerrycodes.com/pytest-split-and-github-actions/)
[https://pytest-xdist.readthedocs.io/en/stable/distribution.html#running-tests-across-multiple-cpus](https://pytest-xdist.readthedocs.io/en/stable/distribution.html#running-tests-across-multiple-cpus)
[https://qiita.com/yaboxi_/items/0cdc2818bf8acf6f00de](https://qiita.com/yaboxi_/items/0cdc2818bf8acf6f00de)
[https://docs.pytest.org/en/7.1.x/how-to/tmp_path.html#the-tmp-path-factory-fixture](https://docs.pytest.org/en/7.1.x/how-to/tmp_path.html#the-tmp-path-factory-fixture)
fluentdのメモリが爆発していろいろ調べたので、そのメモ

fluentdのメモリが爆発していろいろ調べたので、そのメモを残しておく

## 本番環境でのfluentdメモリの使用量とメモリ使用量を抑制するための設定
ざっくりまとめると

- chunk_limit_size は可能な限り小さく
- flush_at_shutdown を true してる場合は、受信側が処理できるぐらい大きさに total_limit_size を設定する

<!--more-->

## fluentd でのメモリの関係
送信用と受信用のインスタンスを1つずつ計2つ使って、fluentdでログを送信するような構成を組んで主に受信側のメモリについてのことを書いていく

fluentd では chunk_file という単位でデータを送信してる。その chunk_file を貯めておくバケツのことを buffer と読んでいる 

fluentd は受信したデータを buffer に書き出すまで、メモリ上に保持する。そのため、1 つの chunk_file のサイズが大きいと、メモリを相応に使用するようになる 

chunk_limit_size を設定しない場合デフォルトで 512MB になっており、さらに compress オプションをつけると、512MB に圧縮された chunk_file が受信側が処理する必要が出てくる 

GCP の e2-standard-8 のインスタンスで、chunk_limit_size を段階的に変更して、メモリの使用量を確認したのが以下の表になる

| chunk_size | メモリ使用量 |
| :--------- | :----------- |
| 512MB      | 2G           |
| 60MB       | 1.2G         |
| 24MB       | 500MB        |
| 12MB       | 300MB        |
| 6MB        | 200MB        |
| 2MB        | 190MB        |

印象としては、chunk_fileの大きさが100MB以上になってくると、受信サーバのレスポンスが極端に悪くなり、最悪はno responseエラーが出ることもある 

その状況なってしまうと、送信側にretry_forever オプションをつけている場合、レスポンスがないために再送し続けて、さらに受信側に負荷がかかるようなことが現象として起きていた 

その辺考えると、特にfluentdでニアリアルタイム性が求められる場合は、chunk_limit_size を可能な限り小さくして、送信流量を調整することが必要となる


## 設定の例 
- flush_interval、flush_thread_countは適宜調整する
- bufferはデータを一時的に貯めておく場所なので、total_limit_size は極力小さい方がいい
- flush_at_shutdownをtrueにする場合、再起動時に最大でtotal_limit_size分のデータを受信側に投げつけるので、これも小さい方がよい
- compress gzipをしている場合、1つのchunkfile(2MB)で10MB程度送信できるので、テキストのログを送信するだけの用途なら1~2MBのサイズでほぼほぼ問題ないはず
- 送信側でbufferがいっぱいになったとしても、fluentdはログの読み込みをやめるだけで、ログが送信できなくなっている事態以外の問題は起きない

```
#あくまで参考程度
  @type forward

  compress gzip
  keepalive true
  keepalive_timeout 300s
  require_ack_response true
  expire_dns_cache 60

 <buffer>
    @type file
    path PATH_TO_BUFFER

    chunk_limit_size 2MB
    total_limit_size 40MB

    flush_mode interval
    flush_interval 5s
    flush_at_shutdown true
    flush_thread_count 1

    retry_forever true
    retry_max_interval 5m
  </buffer>
```


## fluentdでメモリを抑えるための設定まとめ

- chunk_limit_size は可能な限り小さく
- flush_at_shutdown を true してる場合は、受信側が処理できるぐらい大きさに total_limit_size を設定する
高校生でも大丈夫！ IPAの試験をやってみよう

# IPAとは？
IPA（独立行政法人情報処理推進機構）は、日本のITを多方面で支えている団体です。このIPAが実施している試験として有名なものには、情報処理技術者試験やITパスポート試験があります。
このブログを見ている人ですでにこれらの資格を取得している人もいるかもしれませんね。

[IPA公式サイト](https://www.ipa.go.jp/index.html)

# なぜIPA試験を受けるのか？

## ITを体系的に学べる
あなたはプログラムが好きで、いろんなアプリやゲームを作っているかもしれません。
では、以下の質問に答えられるでしょうか。

- CPUがどのように動いているか説明してください。
- データベースの正規化とは何か、目的を教えて下さい。
- テストコードを書く際の命令網羅や条件網羅の違いを教えて下さい？そもそもテストコードの意味を教えて下さい。

これらは普段のプログラミングとは少し異なる分野かもしれません。しかし、将来IT分野で働くことを考えるならば、プログラミングだけでなく、ネットワークやセキュリティ、データベースなどの他の分野も学んでおくことが重要です。

実際に私がネットワーク関連の仕事をしているエンジニアと話した際、IPAの試験範囲の知識が非常に役に立ちました。
エンジニアとしての視野を広げるために、IPA試験は良い学習材料だと思います。

## 共通テスト対策になる
2025年からの共通テストに「情報Ⅰ」が追加されますが、実はIPAの試験勉強がこの情報テストにも大いに役立ちます。
IPAの試験勉強をしておけば、情報のテストが非常に楽になるでしょう。

# 試験方式
A科目(午前試験)とB科目(午後試験)の2つに分かれています。
A科目は4択式の問題が出題され、B科目は長文問題が出題されます。

:::note warn
### 試験方式の注意点
受ける試験によって時間や方式が異なります。
例えばスペシャリスト系の試験は 午前Ⅰ,午前Ⅱ,午後Ⅰ,午後Ⅱの4つに分かれています。
受験前には必ず詳細を確認しておきましょう。
:::

# どうやって勉強するの？

- **まずは参考書を買おう**
  私の場合、以下の参考書を購入して勉強しました。
  [参考書リンク](https://amzn.asia/d/if34ao0)

- **一通り学んだら問題を解きましょう**
  なんと過去の問題を無料で解くことができちゃいます。
　午前試験の対策として最適だと思います。
  [過去問サイトリンク](https://www.fe-siken.com/fekakomon.php)

- **次に午後試験の問題集を買いましょう**
  午後試験は難易度が高いため、別途対策が必要です。
  [午後試験問題集リンク](https://amzn.asia/d/4zPpHBq)

:::note warn
### 採点について
合格するには両方の試験で合格点を取る必要があります。
:::

# まとめ
この記事を読んで、IPA試験に興味を持っていただけたら嬉しいです。筆者のオススメは**基本情報技術者試験**です。
ITパスポート試験よりも難易度は高いですが、実際に役立つ知識はこちらの方が多いと思います。
高校生でも合格できる試験ですので、ぜひチャレンジしてみてください！
Windows環境におけるpyenv+poetryからryeへ移行方法

# pyenv+poetryからryeへ移行する

表題の通り、Windows 環境において pyenv + poetry から rye へ移行する方法を紹介します。また、移行は既存のプロジェクトを対象とします。

 
## 準備

既存のプロジェクトディレクトリで念の為pyproject.tomlのバックアップを取得しておきます。（gitで管理しているので、この作業は不要かもしれませんが。）次に`poetry export`コマンドを使用して、requirement.txtを作成します。


```bash
cp pyproject.toml pyproject.toml_bk
poetry export --without-hashes --without-urls | awk '{ print $1 }' FS=';' | save requirement.txt
```

## pyenv の削除

`where`で pyenv の実行パスを確認します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3552182/8415af94-a60d-1e6d-7ad9-13dd71006b4e.png)

確認した`.pyenv`ディレクトリを削除します。

```
rm -r .pyenv
```

最後に環境変数Pathからpyenvを削除する。

## rye をインストールする

[公式サイト](https://rye.astral.sh/guide/installation/)からインストーラーをダウンロードする。インストーラーを起動するとWindowsの SmartScreen にひかかってしまいますが、「詳細情報」の部分をクリックしてインストーラーを実行する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3552182/c865f0d6-a776-9670-5242-d9fd8d6da5b9.png)

起動すると、コマンドプロントが立ち上がり、対話形式でインストールを進めていきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3552182/9bc5f571-2084-67e7-be00-30fb76a045c4.png)

最終的なものインストール設定は以下の通り行った。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3552182/b7d1964d-5618-0423-83b1-68b08f0b0475.png)

デフォルトの Python がインストールされていることを確認します。

```py
Python 3.12.3 (main, Apr 15 2024, 17:48:16) [MSC v.1929 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> print("hoge")
hoge
>>>
```

## 既存のプロジェクトをryeでセットアップする

pyenv が作成した `.venv` フォルダを削除する。

```bash
cd <python project>
rm .venv
```

最初に作成した`requirement.txt`を基に`rye init`コマンドを実行し、`sync`コマンドで環境をセットアップする。

```bash
rye init -r requirement.txt
rye sync
```

環境をアクティベートし、実行できるか確認する。

```bash
./.venv/Scripts/activate
python hoge.py
```

最後にpoetry時代の`pyproject.toml`を適宜コピペすれば、移行完了です。
LeetCode挑戦日記：Day17

# はじめに

最近、業務で実装する時間よりも資料作成やレビューをする時間が多くなってきました。
このままでは自身のコーディング能力が落ちそうで怖いので、LeetCodeを始めてみました。

自身の学習の記録 & LeetCodeに興味のある人が挑戦しやすいように、記事に残していきます。
このような競技プログラミングをした経験がないので、ひよってEasyからやっていきます...

# [Medium] 1493. Longest Subarray of 1's After Deleting One Element

2進数の配列`nums`が与えられたとき、その中から1つの要素を削除してください。

その結果、`1`のみを含む最長の非空部分配列の長さを返してください。
そのような部分配列が存在しない場合は`0`を返してください。

## 素直に解いてみる

### 考え方

以下の記事と同様の考え方

https://qiita.com/tkmsk/items/e4b4ed34def1a079bc3c

### コーディング

```typescript
function longestSubarray(nums: number[]): number {
    let max = 0;

    let left = 0;
    let right = 0;
    let removal0Counter = 0;
    let isRemoved = false;
    while (right < nums.length) {
        if (nums[right] === 0) {
            isRemoved = true;
            while (removal0Counter === 1) {
                if (nums[left] === 0) {
                    removal0Counter--;
                }
                left++;
            }
            removal0Counter++;
        }
        max = Math.max(max, right - left + 1 - removal0Counter);
        right++;
    }

    if (!isRemoved) max--;
    return max;
}
```

### 結果

Runtime：67ms
Beats 66.56%

Memory：57.71MB
Beats 29.80%

## 改善：`0`の場所を残しておく

### 考え方

1. `left`をインクリメントしながら`0`を探さずに、事前に`0`を見つけた箇所を記憶しておく

### コーディング

```typescript
function longestSubarray(nums: number[]): number {
    let max = 0;

    let left = 0;
    let right = 0;
    let removal0Counter = 0;
    let place0 = -1;
    while (right < nums.length) {
        if (nums[right] === 0) {
            if (removal0Counter === 1) {
                removal0Counter--;
                left = place0 + 1;
            }
            place0 = right;
            removal0Counter++;
        }
        max = Math.max(max, right - left + 1 - removal0Counter);
        right++;
    }

    if (place0 === -1) max--;
    return max;
}
```

### 結果

Runtime：57ms
Beats 94.70%

Memory：57.62MB
Beats 34.77%

## 他の人の解法

### コーディング

```typescript
function longestSubarray(nums: number[]): number {
  let R = 0, L = 0, zeros = 0;

  for( ; R < nums.length; R++) {
    if(nums[R] === 0) zeros++;

    if(zeros > 1) {
      L++;
      zeros += nums[L - 1] - 1;
    }
  }

  return R - L - 1;
};
```
会議が多くて困っている人への10の質問

本記事はQmonus Value Streamの投稿キャンペーン記事です。

# 想定読者
- 出席する会議が多すぎて困っている人
- 出席すべき会議の判断基準を求めている人
- 会議が多すぎてアプリケーション開発に注力しづらい人(キャンペーンのテーマへのこじつけ)

# 本記事のゴール
会議に出席するか判断するためのフローを提案する


# もしもMTGの招待を受け取ったら
デフォルトの回答は「欠席」

# 次に、自分が出席する目的を自問する

10の質問を自分に問いかけよう。
全てがNOであれば、その会議は欠席するのがよいかもしれない。

1. 「自分の協力が必要か？」
2. 「成果に対して どのくらいの影響を与えられそうか？」
3. 「貢献できそうな時間の割合は どれくらいか？」
4. 「自分の意見を代弁してくれそうな 人がほかにいるか？」
5. 「ミーティングへの参加が 自分の存在感を高めるか？」
6. 「どのくらい決定事項が気になるか？」
7. 「行かなかったら後悔するか？」
8. 「行かなければ立場が悪くなるか？」
9. 「何か学べるか？」
10. 「ミーティングを楽しめそうか？」

# 会議への招集を断る
- 調整できないが議事録を送ってほしいと依頼する。
- オンライン会議なら、録画を共有してほしいと依頼する。
- 個人面談を行う
- メールでやり取りをする。
    - フィードバックや応答が不要の場合

## 断れなかったら
部分的に参加する
(トータルで見ると時間の節約になる)

# 参考資料
LinkedIn learning 生産的なミーティングをするコツ
https://jp.linkedin.com/learning/managing-meetings-2/738703?u=2154233

### あとがき
マネジメント寄りの仕事をしはじめ、毎日(!)4,5時間の会議をしているので記事にしました。
Sequence MakerでArduinoと通信してみる

## はじめに
Sequence MakerはExcelから測定器を制御可能にするアドインです。この記事では本来は測定器を制御するSequence Makerを使って、Arduinoを制御する方法を解説します。Sequence Makerについての詳細は以下の記事を参照ください。

https://qiita.com/sequencemaker/items/8e6a370ab0a793a06a3b

:::note warn
***お断り***
本記事の内容はSequence Maker開発元の公式見解ではなく、あくまでも個人が趣味の範囲内で執筆しているものです。記事の内容について開発元へ問い合わせることはお控えください。ご質問・要望などは各記事のコメント欄へお願いいたします。
:::

## 最初にやる設定
### Arduinoを接続する
Arduinoの開発環境一式は事前にインストールされているものとします。ArduinoとパソコンをUSBケーブルで接続したら、デバイスマネージャーを起動して、ポート（COMとLPT）の項目を確認して正常に認識されているか確認します。ついでにCOM番号も確認しておきましょう。ここではCOM3として認識されていました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3821782/609c8234-c95f-a001-d80c-a94de476f831.png)

### Sequence Makerのインターフェイス設定
Excelを起動し、Sequence Makerのインターフェイスを設定します。COMは「RS-232C/USB」として認識しますので、更新ボタンを押して先ほど確認したCOM3を選択します。スピードはとりあえず9600のままで良いです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3821782/1b417815-0ef6-c32d-eee4-26e294121805.png)

さて、ここでSequence MakerからArduinoと通信する上で、重要な設定がもう一つあります。インターフェース #1の右側の矢印をクリックして、詳細設定画面を表示します。「RS-232C/USB」の詳細設定の中の **「DSR/DTR」のチェックを外す**のです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3821782/9fae570f-b682-b215-2853-607d9aa3335b.png)

「DSR/DTR」はRS-232C通信において相手の機器がつながっているかを確認するために使用される信号線ですが、実はArduinoではこの信号線が**リセットpinに接続されている**のです。そのため、チェックを入れておくと、Sequence Makerで制御を開始する際にArduinoがリセットしてしまい、思った動きをしてくれません。チェックを外したらOKを押してウィンドウを閉じます。

:::note alert
注意
Sequence Makerは「DSR/DTR」にチェックが入っているとArduinoがリセットしてしまうので、チェックを外す。
:::

## Arduinoのスケッチ
今回はSequence MakerからArduinoに送った文字をそのままオウム返し（ECHO）するスケッチを書き込みました。

```c:sample.ino
void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
}

void loop() {
  // put your main code here, to run repeatedly:
  if (Serial.available()) {     // 受信の確認 
    char  c = Serial.read();    // データを読み取る
    Serial.write(c);            // 読み取ったデータをそのまま書き込む
  }
}
```

## 動作確認
Arduinoにスケッチを書き込んで、実行したら、Sequence Makerからデータを送信してみます。C列に送信データを書いて「コマンド送受信」を押します。Sequence Makerは送信データに「?」が含まれていないと受信動作をしないので「?」を付けておきます。Sequence MakerからArduinoに送ったデータがオウム返しされてD列に表示されました！！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3821782/577f3d0b-fdc0-773f-ef15-0b189d487259.png)


## まとめ
今回はSequence MakerとArduinoの通信について解説してみました。Arduinoと通信できると、IOボードとして使用する事ができるので、リレーを制御したり、サーボモーターを動かしたりなんかもできると思います。各種センサー類と組み合わせて、データ取りをしてみるのも面白いかもしれませんね。いろいろ工夫してみてください。
AWS上でWebアプリを個人開発する場合の注意点

# 0.はじめに

Webアプリを作って公開して終わり、ではなく、安全に運用し続けるためにはどうすればよいか。
調べた結果をまとめたいと思います。

先日、とあるWebアプリを個人で開発し、AWSにデプロイしました。

インターネット上にWebアプリを自作して公開する資料が多数あり、参考にしていたところです。
しかし、セキュリティ面の対策について併記されている資料ばかりではなかったため、
最低限、注意しておくべきことを以下にまとめます。

# 1.SSHのポートについて
EC2にRemoteSSHを利用してアクセスし、EC2上のデータを編集するというやり方が多く公開されています。
SSHの利用には22番ポートをAWS上で使えるようにする必要がありますが、
ここでインバウンドルールを **「0.0.0.0/0」にするのは危険な行為です。**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3695614/8da65422-98d4-73a1-f3c7-d35d2380f64b.png)

**上のような設定は、正当な理由なくやらないでください。**

いくらSSHでのアクセスにはキーペアが必要とはいえ、ランダムに生成されたIPアドレスや鍵がたまたま当たってしまってログインされたらアウトです。**Web改ざんのリスクが発生することになります。**

したがって、SSHでアクセスする場合は、「マイIP」を利用して、自身のIPアドレスだけからアクセス可能にするか
「カスタム」を使ってSSHを使えるIPアドレスを制限すべきと思います。

# 2.不審なリクエストは普通に飛んできます

WAF(Web Application Firewall)などを使用しない限り(あるいは使ったとしても)、変なアクセスが当たり前のように来るものだと思ってください。インターネット上、すなわち公衆の回線の上にあるのですから、何でも来るものだという認識が必要です。

### 不審なアクセスの例

- ログインページを作成していないのに、ログインページのヘッダーを取得するリクエストが送られてくる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3695614/99d93c0e-5a99-f414-60eb-a0588cf5a25b.png)

私はログインページのようなサービスは作らなかったのですが、このようなリクエストは日常的にやってきます。

- 存在しないAPIに対するリクエスト

![スクリーンショット 2024-06-24 232448.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3695614/1730b335-222b-70d2-bcb1-257588aff6fa.png)

上の図のような構造のソフトウェアを組んだ場合、バックエンド側でapiに関連する何らかの処理を行って
フロントエンドに返答をすることになります。

ところが実際にサービスを公開すると、**定義されていないようなAPIを指定するリクエストが日常的に飛んできます。**
もちろんファイアウォールで対策すべきとは思いますが、サイバー攻撃というのは未知のものもあるため、それだけで防ぎきれるかどうかは分かりません。
定義されていないapiが送られてきた場合、バックエンド側で404を返すか
何らかの例外処理を行うのが無難と思います。

![スクリーンショット 2024-06-24 234133.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3695614/b46cbf0f-7e40-1623-de7f-670f30a6cc08.png)
実際に私の公開しているサービスにはこのようなリクエストが送られてきました。

**また、apiやリクエストパラメータの中身を使ってwebページの中身を書き換えるような処理や、SQLデータベースに触れるような処理をしたいという場合は、このような不正なリクエストによってトラブルが発生しないよう、ソースコード側も含めて対策が必要です。**


- その他
この記事にあるようなリクエストがよく飛んでくる印象を受けます。
https://qiita.com/comefigo/items/e9b1bce93c1b615e5934

いずれにしても、自身のサービスで規定していないリクエストは日常的にやってきます。
これらのリクエストは、応答しないか、404を返すようにすべきだと思います。

# 3.パブリックIPアドレスは普通にアクセスできる

特に何か対策しない限り、パブリックIPアドレスには自分の公開したサービスがそのまま表示されます。
パブリックIPアドレスにアクセスされた場合、自分の設定したドメインにリダイレクトさせるなど
追加の設定を行うのが一般的です。

やり方はこちらが参考になります。
https://insource-mkd.co.jp/staff-blog/10662/

# 4.おわりに

私自身仕事ではオンプレミスしかやってないのですが、アプリケーションの構成に関わらず
上の3つについては共通して注意が必要と感じます。

これに限らず、セキュリティ面などで気を付けるべきことはたくさんあると思います。
安全性をしっかりと検証したうえで、取り入れることをお勧めいたします。


以上です。