OmniAICreator/Qiita-1.07M huggingface dataset:
Bluetoothモジュールのアンテナ

2Fに置いたBLE温湿度計のアドバタイズが1Fで受信できないのでいろいろ試しました。

![BT-ANT (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/b829fe09-dfb3-0a3e-f9d8-a4e450968166.png)

Bluetoothドングルやモジュールの基板上のアンテナはその同心円状に指向性があるようです。なので、窓に向けで水平に置くと受信しにくくなり、斜めにすると受信しやすくなりました。

我が家は古い木造住宅で、2Fの畳の床を電波が透過できているが、かなり減衰するようです。当初勘違いしていたのですが、窓の方から回折して入ってくるのはゲインは小さいようです。

AndroidのアプリのnRF Connectで見ると2Fの部屋の中で-68dbmくらいで、1Fの部屋では不安定で-82dBmくらいでした。

思い出したのですが、JJYの受信もバーアンテナの向きが重要でした。電波が弱まっているのでアンテナの向きが重要になるのではないかと思います。

ESP32よりCSRのUSBドングルの方が受信状況が良かったです。

ちょっと置く場所を変えたり、角度を変えたりするとかなり状況が変わります。

1対1の通信なのでどうにかなったが、2Fに複数のBLE温湿度計を置いて通信することは難しいと思う。

AndroidのBLEはUSBドングルより感度が良いようです。なんか設定が必要なのかな？

一時間ごとの受信回数のグラフを作ってみました。

![filename(24).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/c7b0ec31-9ae6-2601-ec2a-63f263b50aaa.png)

モジュールをまったくいじらなくても何らかの影響で大きく変動します。

![filename(30).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/ab7d3767-8cba-dbbe-a2a0-56ac62982ec3.png)

![filename(29).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/c011e990-7b6e-2826-ea6c-768e277bf729.png)

変動が大きいので調整が難しく、ある程度安定したら、触らないほうが良さそうです。

なんかとんでもなく減ってます。

![filename(3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/7434f80f-2fb3-2c9a-9d3e-0d4850eb8931.png)

確認のために受信しているUSBドングルの20cmくらいの所に温湿度計を置いてみました。安定しています。

![filename(1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/d0b1e76b-cc44-a0f4-fce6-8dd919c63c91.png)
Database基礎

**今回はDB基礎について記事にしたいと思います。**

**まずはテーブルを作成します。**
テーブルとは、データベース内でデータを整理して保存するための基本的な構造です。表のような形をしていて、**行（row）と列（column）**で構成されています。
![DB.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3823687/45b63c14-efe0-d4f0-8fce-a4468fa8937e.png)

**データ型**
Javaと同じようにデータベースにもデータ型が存在します。データ型は列に対して指定します。また、登録できる文字数や小数点以下第何位まで登録するかといったサイズ、精度指定も行います。
```Java
属性	データ型	解説
文字	VARCHAR	最大サイズ指定可変長文字列
文字	CHAR	固定長文字列
文字	TEXT	制限なし可変長文字列
数値	INTEGER	4バイト整数型
数値	DECIMAL	可変精度数値型
日付	DATE	日付型
```

**制約**
データベースに格納される制約条件をつけるもの

**制約名: NOT NULL**
説明: NOT NULL制約は、単一の列に対して定義されるルールで、この列のNULL値（値がない）の入力を禁止するという制約。つまり、テーブルのすべての行で必ずその列にNULL以外の値が登録されるように制限する制約。

**制約名: 一意性 (UNIQUE)**
説明: 一意性制約は、列、または複数の列の組み合わせに対して定義されるルールで、それらの列で値が一意（ユニーク）であるデータに限りデータの挿入・更新を許可する制約。UNIQUE KEYとも呼ばれる。

**制約名: 主キー (PRIMARY KEY)**
説明: 主キー制約は、列、または複数の列の組み合わせに対して定義されるルールで、表の中の行を一意（ユニーク）に識別するための制約。一意性制約と違って、主キーは一つのテーブルに一つしか設定できない。また、主キー制約は、一意性制約にNOT NULL制約が加わったものとして見ることができる（つまり、定義された列、または複数の列は重複が許されず、NULLも許されない）。

**制約名: 外部キー (FOREIGN KEY)**
説明: 外部キー制約は、テーブルとテーブルの間をテーブル内の列（または列の組み合わせ）で参照という関連付けを定義するルールをいう。外部キー制約はテーブル同士の関連付けを行い、子テーブルは親テーブルを参照し、子テーブルの参照列を外部キーと呼ぶ。親テーブルと子テーブルの間でデータの整合性を保つ。子テーブルに入力される値は親テーブルに存在する値かNULLでなければならない。参照整合性制約やREFERENCE KEYなどとも呼ばれる。

**制約名: チェック (CHECK)**
説明: チェック制約は、入力条件を定義した制約で、列に条件を満たす値のみ入力が許可される。



**構文**
```Java
SELECT カラム名, カラム名, ... FROM テーブル名;
```

SELECT: これは「選ぶ」という意味です。どのデータを取り出したいかを指定する命令です。
カラム名: ここには、取り出したい情報（データ）の種類を書きます。たとえば、名前や年齢といったデータです。複数の種類をコンマ（,）で区切って書くことができます。
FROM テーブル名: どこからデータを取り出すか、つまりデータが保存されている場所（テーブル）を指定します。

例:
もし「生徒」というテーブルに「名前」と「年齢」のデータが保存されていたとします。この場合、名前と年齢の情報を取り出したいなら、こう書きます。
```Java
SELECT 名前, 年齢 FROM 生徒;
 SELECT文、WHERE句、INSERT文
 ```
SELECT文: データベースから必要なデータを取り出すために使います。
WHERE句: SELECT文などで、特定の条件に合うデータだけを取り出すための部分です。
INSERT文: 新しいデータをデータベースに追加するための方法です。


データ操作言語 (DML: Data Manipulation Language文)
```Java
SELECT文
表に登録されているデータの取得を行う。

INSERT文
表にデータを登録する。

UPDATE文
表に登録されているデータの更新を行う。

DELETE文
表に登録されているデータの削除を行う。

トランザクション制御文
COMMIT文
トランザクションの確定を行う。

ROLLBACK文
トランザクションの取消を行う。

データ定義言語 (DDL: Data Definition Language文)
CREATE文
データベースのオブジェクトを作成する。

ALTER文
データベースのオブジェクトの定義を変更する。

DROP文
データベースのオブジェクトを削除する。

データ制御言語 (DCL: Data Control Language文)
GRANT文
オブジェクトを操作する権限をユーザーに付与する。

REVOKE文
オブジェクトを操作する権限をユーザーから剥奪する。
```

簡単にデータベースの基礎についてまとめてみました。
Fast-forwardマージと非Fast-forward（no-ff）マージ

こんにちは。駆け出しエンジニアのtaiyoです。

今回はFast-forwardマージと非Fast-forward（no-ff）マージの違いと、「マージコミット」について勉強したので、まとめた内容を発信したいと思います。

まずマージには、Fast-forwardマージと非Fast-forwardマージがあります。

### Fast-forwardマージ（枝がまっすぐな場合）

**Fast-forwardマージ**は、**変更に枝分かれの状態がなく、単に一続きの履歴として変更をまっすぐに追加できる**場合に適用されます。

例えば、`main`ブランチに、前回マージから**変更が加えられていないとき**に、`dev`ブランチをそのまま後ろに追加するような形です。

このとき、`dev`ブランチに追加の変更を加えた後、`main`にマージしようとすると、**単純に`dev`の変更とコミット履歴がそのまま`main`に追加されます。**

```
main: A --- B  (前回マージ)
	         \
dev:          C --- D  (新しいコミット)

結果 (Fast-forwardマージ):
main: A --- B --- C --- D  (すべて直線で追加される)
```

ちなみに、”Fast-forward” は直訳すると「素早く、前に進んで」という意味で、Fast-forwardマージは、前回の変更の後に続いて、単にまっすぐ変更履歴を追加するだけで、内部処理が素早く終わることからこの名前がついているそうです。

### 非Fast-forward（no-ff）マージ（枝分かれがある場合）

一方で、**2つに枝分かれした変更を統合する**（つまり、`main`と`dev`が異なる履歴を持っている）場合、Fast-forwardをすることはできません。

この場合は、devでの変更とコミット履歴に加えて、**マージコミット**が作成され、2つの枝を1つにまとめます。

```
main: A --- B --- E  (mainに新しい変更が加わった)
             \
dev:          C --- D  (devで新しい変更)

結果（マージコミット）:
main: A --- B --- E --- M  (Mはマージコミット)
             \         /
              C ----- D
```
### マージコミットとは？

「マージコミット」とは、**2つ以上のブランチ（分岐した履歴）を統合するために作成される特別なコミット**です。

普通のコミットは1つの親コミットを持ち、つまりそのコミットの前にあった1つの状態（親）からの変更を記録しますが、**マージコミット**は、2つ以上の親コミットを持ちます。つまり、複数の異なる履歴からの変更を統合しているので、どの履歴からマージされたのかを記録します。

また、普通のコミットでは、開発者が自分でコミットメッセージを記述しますが、**マージコミット**では、Gitが自動的に「**Merge branch 'ブランチ名' into 'ブランチ名'**」のようなメッセージを生成します。ただし、手動でコミットメッセージを追加することも可能です。

また、マージコミットは、**ファイルの競合を解決した後の状態**を記録します。もし2つのブランチで同じファイルに異なる変更があった場合、Gitは自動的に統合できないため、開発者が手動で競合を解消する必要がありますが、その解決結果がマージコミットには含まれます。

### 変更がないブランチにもマージコミットを記録する方法

先程も書いたように、もしマージ先のブランチに前回のマージから変更が加えられていないなら、マージはデフォルトで**Fast-forwardマージ**になります。

```bash
git merge dev -m "devをmainにマージします"
```

そのときはこのように、自分でコメントを残さない限り、特にマージした形跡が残りません。

マージ先のブランチに変更が加えられていないときもマージコミットでしっかりとマージした記録を残したい場合は、Fast-forwardをoffにするために、`-—no-ff`コマンドを追加します。

```tsx
git merge --no-ff dev
```

これにより、このマージは`dev`ブランチのコミット記録がそのまま`main`ブランチにも反映されるだけではなく、**マージコミットも追加されます**（`Merge branch 'dev' into 'main’`）。



 ご参考になれば幸いです！
形態素解析で読み解くコロナ禍の危機感：MecabとTwitter分析の実践

## 概要
:::note warn
本調査は大学1年時の前学期に行ったもので、専門的な知識がまだ未熟な段階での取り組みです。温かい目でご覧いただけると幸いです。
:::
2022年、コロナウイルスの影響がまだ大きかった頃、大学の授業で簡単な調査を行いました。当時の私は、プログラミングやデータ分析の知識がほぼない状態で、形態素解析ツールのMecabを使って「飲み会」に関するTwitter投稿を分析しました。

結果は一つの仮説として軽く読んでもらえればと思いますが、感染者数の増加と人々の危機感の変化には興味深いパターンが見つかりました。本記事では、その調査結果や手法について簡単に紹介します。

## データ収集と解析手法
### データ収集方法
本調査では、2020年における日本国内の新型コロナウイルス感染者数の推移に着目し、「飲み会」に関連する人々の危機感の変化を調べるために、Twitter上の投稿を収集しました。

データ収集は、2020年3月から2022年4月までの間に「飲み会」を含む投稿を対象に行いました。当時はAPIについてもよくわかっていなかったため全て手動で検索結果からツイートを収集しました。

・各月55ツイートづつ、計1430ツイートを対象ツイートとした。
・収集したツイートは以下のようにExcelにまとめた。
<img width="500" alt="収集方法" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693349/6eb029c4-5278-3874-6522-fd33036f7a07.png">

### 解析手法
#### 1.Mecabのインストール
```
brew install mecab
brew install mecab-ipadic
```

#### 2.収集したデータの形態素解析
- Excelデータをテキストデータとして保存しmecabを実行
- 出力されたテキストファイルをExcelにドラッグ&ドロップ
- Excelの「ピポットテーブル」を使いキーワードの出現頻度の表を作成
- mecabによる分書データを作成
- 同時出現表を作成

<img width="400" alt="形態素解析" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693349/a7f43689-9fbe-5302-0e10-7ce57d316126.png">

### 危機感度数の算出

次に、危機感度数を以下の式で算出しました。

$$
危機感度数 = \frac{\text{指定キーワードを含むツイート数}}{\text{総ツイート数}} \times 100
$$

各月における「オンライン」や「リモート」を含むツイートの割合を計算することで、その月の人々の危機感を定量的に評価しました。この結果は、感染者数の増加と人々の危機感の変動との関係を調べるための基礎データとなりました。

## 結果と考察
### 危機感度数と感染者数との比較
![スクリーンショット 2024-09-29 12.32.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693349/85fee635-1a3a-9c8c-634a-7f7e605aa50d.png)

*横軸が時系列、縦軸が危機感度（%)

感染者数推移は以下を参考

https://www3.nhk.or.jp/news/special/coronavirus/data/

### 結果
感染者数が急増した月やその次の月は比較的、危機感が高まっている傾向にある。
感染者数が増加していく一方で危機感度数は減少している

### 考察

今回の調査では、2020年3月から2022年4月にかけてのTwitterデータをもとに、「飲み会」に関連する投稿から人々の危機感度数を算出し、感染者数との関係を分析しました。その結果、感染者数が急増している期間には危機感が高まる一方、感染が長期化するにつれて危機感が減少する傾向が見られました。

#### 1. 危機感の変動に対する解釈
この結果から、パンデミック初期には感染に対する恐怖や不安が強く表れており、オンラインやリモートといった方法で飲み会を行うなど、感染リスクを回避しようとする意識が高まっていたことが示唆されます。しかし、感染が長引くにつれて、生活が新たなリスクに慣れ、危機感が低下していく「リスク慣れ」という現象が現れたと考えられます。これは、長期間にわたる危機的状況に対する人々の心理的適応が影響している可能性が高いです。

また、社会的な制約が緩和されると同時に、実際には感染が拡大しているにもかかわらず、危機感が低下している点は、政府やメディアの影響もあると考えられます。メディアの報道が緩和され、日常生活が再開することで、人々が「もう大丈夫だ」と感じる心理的な要因も作用しているのかもしれません。

#### 2. 調査の限界
今回の調査にはいくつかの限界もあります。まず、データの収集が「飲み会」という特定のキーワードに依存しているため、他の状況に関する投稿や人々の行動全体を網羅的に分析できたわけではありません。また、手動でのツイート収集のため、データ量に偏りが生じる可能性があります。

#### 3. 今後の展望
今回の結果は、感染者数の推移と人々の危機感の変動に一定の相関があることを示しましたが、より広範なデータを用いたさらなる研究が必要です。今後は、他のキーワードや異なるSNSプラットフォームも含めた調査を行い、人々の行動や意識の変化をより深く理解することが期待されます。また、調査結果をリアルタイムで可視化することで、危機管理や公衆衛生対策に活用することが可能であると感じました。


## 用語解説
### Mecab
Mecab（メカブ）は、日本語の文章を形態素解析するためのオープンソースのライブラリです。形態素解析とは、文章を単語ごとに分割し、それぞれの単語の品詞（名詞、動詞、形容詞など）をタグ付けする作業のことです。特に日本語は、英語のように単語ごとのスペースがないため、形態素解析を使って文章を正確に分割する必要があります。

https://qiita.com/venect_qiita/items/5123b266478c4796db02

### 形態素解析
形態素解析とは、文章を単語単位に分割し、それぞれの単語がどのような品詞（名詞、動詞、形容詞など）であるかを識別する自然言語処理の手法

https://udemy.benesse.co.jp/data-science/ai/morphological-analysis.html
レビューを出す時は、レビュワーが見やすいようにブランチを分けてください

# ブランチを分けてプルリクエスト(P-R)を作成する方法

背景
先輩にコードレビューを依頼した時に、「レビュワーが見やすいようにブランチを分けてください」と言われた。
でもどうすればいいんだ...困った！！💦

---

### 今回の例: hogeブランチのmainとの変更差分をfrontendディレクトリとbackendディレクトリで分ける

#### 1. 新しいブランチを作成する

まず、`main`ブランチから新しいブランチを作成します。

```bash
git checkout main
git checkout -b hoge_frontend_changes_branch
```

#### 2. `frontend`ディレクトリの変更を取り込む

`hoge`ブランチから`frontend`ディレクトリの変更を現在のブランチに取り込みます。

```bash
git checkout hoge -- frontend
```

#### 3. 変更をステージングしてコミットする

取り込んだ変更をステージングし、コミットします。

```bash
git add frontend
git commit -m "Apply frontend changes from hoge"
git push origin hoge_frontend_changes_branch
```

これで、`hoge`と`main`の`frontend`ディレクトリ間の差分が、新しいブランチ`hoge_frontend_changes_branch`に反映されました。
バックエンドも同様に行えばOKです！
[Python] 最大公約数を求める

# 最大公約数とは
皆さんご存じのように、最大公約数とは**２つ以上の正の整数の共通の約数のうち最大の数**のことです。
# 愚直に求める方法
2つの整数をa、bとします。aの約数のリスト、bの約数のリストをそれぞれ作成し、2つのリストに共通する要素の中で最大のものを求めます。
~~~Python:gcd1.py
def gcd(a, b):
    a_div = []
    b_div = []
    
    div = 1
    while a > div:
        if a % div == 0:
            a_div.append(div)
        div += 1

    div = 1
    while b > div:
        if b % div == 0:
            b_div.append(div)
        div += 1

    c, d = 0, 0
    gcd_list = []
    for c in a_div:
        for d in b_div:
            if c == d:
                gcd_list.append(c)

    return max(gcd_list)

gcd = gcd(28, 42)
print("最大公約数は", gcd)
# 出力結果
# 最大公約数は 14
~~~
# ユークリッドの互除法を使用する
ユークリッドの互除法の手順は次の通りです。

ステップ1. 2つの整数をa、bとする。
ステップ2. aをbで割った余りを求める。
ステップ3. bをステップ2で求めた余りで割り、その余りを求める。
ステップ4. 以下同様に繰り返すと余りが必ず0となる。余りが0になったときの割る数が最大公約数になる。
~~~Python:gcd2.py
def gcd(a, b):
    while b: # bが0(False)になると終了
        a, b = b, a % b
    return a # 終了したとき最大公約数はa

gcd = gcd(28, 42)
print("最大公約数は", gcd)
# 出力結果
# 最大公約数は 14
~~~
# 再帰的なユークリッドの互除法を使用する
再帰とは、ある関数が自分自身を呼び出すプロセスのことですね。
こんな感じです。
~~~Python:gcd3.py
def gcd(a, b):
    if b == 0:  # 無限ループにならないための終了条件
        return a

    r = a % b
    d = gcd(b, r) # ここで再帰を使用
    return d

gcd = gcd(28, 42)
print("最大公約数は", gcd)
# 出力結果
# 最大公約数は 14
~~~
# 三項演算子を使って簡潔に書く
変数 = (条件が真のときに返す値) if (条件) else (条件が偽のときに返す値)というように三項演算子を使用しています。
~~~Python:gcd4.py
def gcd(a, b):
    return gcd(b, a % b) if b else a

gcd = gcd(28, 42)
print("最大公約数は", gcd)
~~~
# Pythonの標準関数を使用する
Pythonには、mathモジュールにgcd()という最大公約数を求める便利な標準関数があるので、それを使うのが一番簡単です。
~~~Python:gcd5.py
import math

gcd = math.gcd(28, 42)
print("最大公約数は", gcd)
# 出力結果
# 最大公約数は 14
~~~
# 私が最初に書いたコード
「最大公約数を求めよ」という課題に対して私が最初に書いたコードがこちらです。
いちおうユークリッドの互除法を使っていますが冗長な部分がありますね。でも懐かしいです。
~~~Python:gcd_saisho.py
def gcd(a, b):
    while a != 0 and b != 0:
        if a > b:
            c = a % b
            a = c
        else:
            c = b % a
            b = c

    if a == 0 or b == 0:
        if a != 0:
            return a
        else:
            return b 

gcd = gcd(28, 42)
print("最大公約数は", gcd)
# 出力結果
# 最大公約数は 14
~~~
# 最小公倍数も求めてみる
正の整数a, bに対して、それらの最大公約数をgcd、最小公倍数をlcmとおくと、**gcd(a, b) * lcm(a, b) = a * b**
の関係が成り立つことを利用します。
最大公約数を求める関数も違う書き方で定義してみます。
~~~Python:gcd_lcm.py
def gcd(a, b):
    x = max(a, b)
    y = min(a, b)
    if x % y == 0:
        return y
    else:
        while x % y != 0:
            z = x % y
            x = y
            y = z
        else:
            return z

def lcm(a, b):
    return int(a * b / gcd(a, b))

print(gcd(24, 18)) # 出力結果は6
print(int(lcm(24, 18))) # 出力結果は72
~~~
chrome拡張機能 現在のタブのタイトルとURLを取得

公開しているchrome拡張機能をManifestV3に対応するためバージョンアップ作業をしている際に、現在のタブのタイトルとURLを取得するために使用していたchrome.tabs.getSelectedが動かなくなっていて苦戦したのでメモ

旧バージョン
```
chrome.tabs.getSelected(null, function(tab) {  
  let Data = {"Title": "", "URL": ""}; 
  
  Data.Title = tab.title; 
  Data.URL = tab.url;
```

修正したバージョン
```
chrome.tabs.query({active:true, lastFocusedWindow:true}, tabs => {  
  let Data = {"Title": "", "URL": ""}; 
  
  Data.Title = tabs[0].title; 
  Data.URL = tabs[0].url;
```

tabs.queryを使うと出来るようになる
AND、OR、XORを計算で求める


$x=$1と $y=$１ のAND演算は$xy=$1から 1
と求まります。ところが、OR演算は1$+$1$=$1
です。これは直感に反する。

そこで、OR$=x+y-xy$とすると、うまくいきます。

ちなみに、XOR$=x+y-$2$xy$という数式になります。

$z=x+y-$2$xy$は$xyz$空間における曲面を表します。

![Screenshot from 2024-10-24 19-53-03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3886431/1d4a0835-4b8e-8cfd-d54c-4a57d6ec9f3f.png)


$x,y$に1か0を代入するとAND、NAND、OR、NOR、XOR、XNOR演算の結果を返すPythonプログラムを作ってみました。
    

```py
import tkinter

root = tkinter.Tk()
root.title("NANDGAME")
root.minsize(800, 450)
top = tkinter.Label(root, text="\nNANDGAME\n", font=("メイリオ", 16, "bold"))
top.pack()
top = tkinter.Label(root, text="1か0を入力してください", font=("メイリオ", 12, "bold"))
top.pack()

e1 = tkinter.Entry(root)
e1.pack()
e2 = tkinter.Entry(root)
e2.pack()
button = tkinter.Button(root, text="１か0を入力")
button.pack()


def nandgame():
    x = int(e1.get())
    y = int(e2.get())
    display = "AND=" + str(x*y) + "です\n""NAND=" + str(1-x*y) + "です\n""OR=" + str(x+y-x*y) + "です\n""NOR=" + str(1-x-y+x*y) + "です\n""XOR=" + str(x+y-2*x*y) + "です\n""XNOR=" + str(1-x-y+2*x*y) + "です\n"
    top["text"] = display



button["command"] = nandgame
root.mainloop()
```
![Screenshot from 2024-09-29 20-16-29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3886431/7141037c-d30a-29b7-bea8-88f75b3290c6.png)

Windows版ダウンロード(C++)
https://github.com/biohack5079/nandgame/blob/main/nandgame.exe
Web版(Python)
http://kabuka.s1007.xrea.com/nand/

純代数なフリをして実は、AND関数にもOR関数にも$xy$という非線形な項が隠されています。

このあたりの論理について考察している記事があったので紹介しておきます。

参考

https://www5f.biglobe.ne.jp/kimmusic/kaiki.html
SG90のサーボー信号を計算してみる


x 過去ログを見よ!!!
x M5nanoC6にサブマイコン(STM32L010)を通す
x arduinoは、電子工作なので
x 予定は、未定

![o_coq464.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/1b55d407-b39d-dc63-faed-522821d2f150.jpeg)


オンラインコンパイラを使用


```c++

#define V_0    500
#define V_180 2400
#define HH  ((V_180-V_0)*1024)/180
#define SO(AA) (V_0+(((AA)*(HH))>>10))

#include <iostream>
using namespace std;
int main(void){
    // Your code here!
    int a;
    for(int i=0;i<(180+1);i++){
        a = SO(i);
        //a = SO(180-i);
        printf("[%d]<%d>\n",i,a);
    }//for
}//main

```


```


[0]<500>
[1]<510>
[2]<521>
[3]<531>
[4]<542>
[5]<552>
[6]<563>
[7]<573>
[8]<584>
[9]<594>
[10]<605>
[11]<616>
[12]<626>
[13]<637>
[14]<647>
[15]<658>
[16]<668>
[17]<679>
[18]<689>
[19]<700>
[20]<711>
[21]<721>
[22]<732>
[23]<742>
[24]<753>
[25]<763>
[26]<774>
[27]<784>
[28]<795>
[29]<806>
[30]<816>
[31]<827>
[32]<837>
[33]<848>
[34]<858>
[35]<869>
[36]<879>
[37]<890>
[38]<901>
[39]<911>
[40]<922>
[41]<932>
[42]<943>
[43]<953>
[44]<964>
[45]<974>
[46]<985>
[47]<996>
[48]<1006>
[49]<1017>
[50]<1027>
[51]<1038>
[52]<1048>
[53]<1059>
[54]<1069>
[55]<1080>
[56]<1091>
[57]<1101>
[58]<1112>
[59]<1122>
[60]<1133>
[61]<1143>
[62]<1154>
[63]<1164>
[64]<1175>
[65]<1186>
[66]<1196>
[67]<1207>
[68]<1217>
[69]<1228>
[70]<1238>
[71]<1249>
[72]<1259>
[73]<1270>
[74]<1281>
[75]<1291>
[76]<1302>
[77]<1312>
[78]<1323>
[79]<1333>
[80]<1344>
[81]<1354>
[82]<1365>
[83]<1376>
[84]<1386>
[85]<1397>
[86]<1407>
[87]<1418>
[88]<1428>
[89]<1439>
[90]<1449>
[91]<1460>
[92]<1471>
[93]<1481>
[94]<1492>
[95]<1502>
[96]<1513>
[97]<1523>
[98]<1534>
[99]<1544>
[100]<1555>
[101]<1566>
[102]<1576>
[103]<1587>
[104]<1597>
[105]<1608>
[106]<1618>
[107]<1629>
[108]<1639>
[109]<1650>
[110]<1661>
[111]<1671>
[112]<1682>
[113]<1692>
[114]<1703>
[115]<1713>
[116]<1724>
[117]<1734>
[118]<1745>
[119]<1756>
[120]<1766>
[121]<1777>
[122]<1787>
[123]<1798>
[124]<1808>
[125]<1819>
[126]<1829>
[127]<1840>
[128]<1851>
[129]<1861>
[130]<1872>
[131]<1882>
[132]<1893>
[133]<1903>
[134]<1914>
[135]<1924>
[136]<1935>
[137]<1945>
[138]<1956>
[139]<1967>
[140]<1977>
[141]<1988>
[142]<1998>
[143]<2009>
[144]<2019>
[145]<2030>
[146]<2040>
[147]<2051>
[148]<2062>
[149]<2072>
[150]<2083>
[151]<2093>
[152]<2104>
[153]<2114>
[154]<2125>
[155]<2135>
[156]<2146>
[157]<2157>
[158]<2167>
[159]<2178>
[160]<2188>
[161]<2199>
[162]<2209>
[163]<2220>
[164]<2230>
[165]<2241>
[166]<2252>
[167]<2262>
[168]<2273>
[169]<2283>
[170]<2294>
[171]<2304>
[172]<2315>
[173]<2325>
[174]<2336>
[175]<2347>
[176]<2357>
[177]<2368>
[178]<2378>
[179]<2389>
[180]<2399>


```
女性プログラマーの歴史

![](https://storage.googleapis.com/zenn-user-upload/af3831a0de98-20240929.jpg)
現在、女性プログラマーは少数派であり、「女性は遺伝的にプログラマーに向いていない」という誤った考えも一部で広まっています。しかし、実際にはプログラミングの歴史をたどると、女性の重要な役割が見えてきます。今回は、少し過去にさかのぼって、女性プログラマーの歴史に触れてみたいと思います。

![](https://storage.googleapis.com/zenn-user-upload/fe0f79ff64ad-20240929.jpg)
実は、世界で最初のプログラマーとされているのは女性なんです。その人物はエイダ・ラブレス。彼女は19世紀前半のイギリスの貴族で、数学を得意とし、あの有名なプログラミング言語「Ada」の名前の由来にもなっています。当時、まだ現代のようなコンピューターは存在していませんでしたが、歯車で動く「機械式コンピューター」の設計が進んでいました。残念ながら技術的な問題で完成には至りませんでしたが、理論上は今のコンピューターと同じ計算能力を持つものでした。

エイダ・ラブレスは、その機械のためのプログラムを設計し、後世に残しました。

![](https://storage.googleapis.com/zenn-user-upload/3bc0f34ba7c2-20240929.jpg)
こちらがエイダが設計したプログラムです。テキストデータという概念がなかった時代なので、表形式で書かれていますが、しっかりプログラムになっています。

![](https://storage.googleapis.com/zenn-user-upload/cc54a3f0c7ba-20240929.jpg)
時代は少し進み、20世紀半ば。世界初の実用コンピュータ「ENIAC」のプログラムを書いた6人のエンジニアも、実は全員が女性でした。彼女たちの名前は以下の通りです。

- キー・マクナルティ
- ベティ・ジェニングス
- ベティ・スナイダー
- マーリン・ウェスコフ
- フラン・バイラス
- ルース・リターマン

6人とも、Wikipediaに載っているので、ぜひ調べてみてください。旧姓とは違う姓で掲載されている人も多いので、名前が少し違うかもしれません。

![](https://storage.googleapis.com/zenn-user-upload/af49899c5991-20240929.jpg)
つまり、世界初のプログラマーだったエイダ・ラブレスと、世界初のコンピュータ・プログラマーだった6人は、全員が女性だったということです。最初のプログラマー7人が全員女性だった、と言っても過言ではありません。（厳密な話をすると少し込み入ってきますが、ここでは簡潔に伝えますね。）

![](https://storage.googleapis.com/zenn-user-upload/a438fc485735-20240929.jpg)
エイダ・ラブレスが貴族だったことを除くと、残りの6人が女性であった背景には、当時の社会的な要因がありました。あの時代、女性が就ける職業は限られており、その中に「計算手（コンピューター）」という職業がありました。今で言うコンピューターとは違い、手計算や簡単な計算機を使って、ひたすら計算をする仕事です。当時、頭の良い女性の間で人気のある職業だったようで、このためにプログラミングという分野にも自然と女性が進出したのです。

その7人の後もしばらくは、コンピュータの歴史には多くの女性が貢献しています。中には、女性が男性よりも細やかな作業に適しているという意見もあったようです。

![](https://storage.googleapis.com/zenn-user-upload/489fd2bf5c80-20240929.jpg)
中でも特に有名なのは、グレース・ホッパーでしょう。彼女はCOBOLというプログラミング言語を開発し、軍のコンピューターに深く関わり、最終的には准将の階級まで上り詰めました。また、彼女の名誉を称えた軍艦も存在します。

では、どうして現在、プログラミングが男性主流の職業になってしまったのでしょうか？生まれつきの能力の違いだという主張では、歴史的に女性プログラマーが減少してきた理由を説明できませんし、脳科学の研究でも、そのような大きな差は見つかっていません。

実は、女性プログラマーが減少し始めたのは1980年代のことだと言われています。この時代、何が起こったのか？おそらく、パソコンが普及し始めたことが大きな要因です。パソコンが「男の子の遊び道具」というイメージが強まったことで、自然と女の子がプログラミングに興味を持ちにくくなり、それが職業としても影響を及ぼしたのでしょう。

このようにして女性プログラマーが減った背景を考えると、今もプログラミングに才能を持ちながら、その可能性を生かせずにいる女性たちが多いはずです。多様性を活かした社会を実現するためにも、女性が再びプログラマーとして活躍できる環境を整えることが重要です。


(編集協力：ChatGPT 4o様)  
(当記事はZennにもマルチポストされます)
[Zenn](https://speakerdeck.com/player/d6d45f62456f467abed6a0d1f627e2a1)
(スライド全体はこちら)  
[speakerdeck](https://speakerdeck.com/hrmstrsmgs/nu-xing-puroguramanoli-shi)
C++におけるポインタ渡しと参照渡しの違い

# サンプルコード

```c++
#include <iostream>

// 値渡し
int method1(int value){
    return ++value;
}

// ポインタ渡し
void method2(int* value){
    *value = 102;
}

// 参照渡し
void method3(int& value){
    value = 103;
}

int main(){
    int value = 100;
    // 値渡し
    printf("値渡し:");
    printf("%d\n", method1(value));
    
    // ポインタ渡し
    printf("ポインタ渡し:");
    method2(&value);
    printf("%d\n", value);

    // 参照渡し
    printf("参照渡し:");
    method3(value);
    printf("%d\n", value);
}

```

※一応の前提として、Cではポインタ渡ししかできない。
C++ではポインタ渡しに加え、参照渡しも可能。

# ポインタ渡しと参照渡しの共通点

呼び出し先関数で、呼び出し元の変数を変更できる。

# ポインタ渡しと参照渡しの文法上の違い

### ポインタ渡しの書き方
・呼び出し元関数からは、変数のアドレスを引数として渡す。`method2(&value);`
・呼び出し先関数の仮引数は、ポインタ型変数として宣言する。`void method2(int* value){`
・呼び出し先関数内でポインタの指す先の値にアクセスするために、間接参照演算子を使う。`*value = 102;`

### 参照渡しの書き方
・呼び出し元関数からは、アドレスではなく変数そのものを引数として渡す。`method3(value);`
**※つまり値渡しと同じ書き方である。このため、関数の呼び出し元だけ見ても、値渡しか参照渡しかは判断できない。判断するには、呼び出し先の定義を見る必要がある。**
・呼び出し先関数の仮引数は、参照型（&）として宣言する。`void method3(int &value){`
・間接参照演算子やアドレス演算子を使わずに、通常の変数と同じように、参照された変数を操作できる。`value = 103;` 
**ポインタ渡しに比べて、アドレス演算子や間接参照演算子、宣言子の記述が少なく済むため、書き方がわかりやすい。** 参照渡しは、変数を関数で受け渡す際の「ポインタ」の記述を簡易的に行えるようにするための機構と言える。


# ポインタ渡しと参照渡しの機能面での違い

### nullptrが渡されるか？
参照渡しでは、関数に渡す引数として参照型変数を使用する。文法上、「参照」は必ず有効なオブジェクトや変数を指すように初期化する必要があり、無効な値（nullptr）は格納できない。
つまり、参照渡しでは、呼び出し側が参照を渡すときに「無効な状態（nullptr のようなもの）」は発生しないという前提が成り立つ。
**そのため、参照渡しはポインタ渡しよりも安全である。**

**ただし、（ややこしいのだが）参照渡しであれば、呼び出し先関数に 「絶対に」nullptrが渡され得ない、ということではない。**
例として、以下のコードでは、参照型変数ではなく、ポインタ型変数（の値）を渡している。↓
```c++
// 参照渡し
void method3(int& value){
    value = 103;
}

int main(){
    int* ptrValue = nullptr;

    // 参照渡し
    printf("参照渡し:");
    method3(*ptrValue);
    
    printf("%d\n", *ptrValue);
}
```

`int* ptrValue = nullptr;`
`method3(*ptrValue);`

これにより、実行時に`value = 103;`の箇所でSegmentation faultが発生することになる。

**呼び出し元メソッド側では、あくまで「ポインタ（の値）」ではなく、「参照」を渡すことで、無効な値（nullptr）が渡され得ないことを文法上保証できる。**

# まとめ

| 特徴 | ポインタ渡し | 参照渡し |
|:-----------|------------:|:------------:|
| 引数の型       | ポインタ (int*)        | 参照 (int&)         |
| 渡す値     | 変数のアドレス (&value)      | 変数そのもの (value)       |
| アクセス方法       | 間接参照演算子でアクセス        | そのまま通常の変数としてアクセス         |
| 可読性         | & や * が多く、複雑          | 値渡しとほぼ変わらず、簡素           |
| nullptrが渡されるか？         | nullptrを渡せる          | 参照を渡す限り、nullptrは来ない    |
git filter-repoの扱いには気をつけろ！

# はじめに
事の始まりは，Git LFSの容量制限に引っかかり，特定のオブジェクトを削除する必要が出てきたこと．
厄介なことに直前のcommitだけでなく，既にpushをはじめとした諸々の操作をした履歴全てから，当該ファイルを削除する必要があります．とはいえ，入り組んだ履歴から手動で削除するのは大変すぎる……

そんな時に使えるのが`git filter-repo`で，サードパーティ製ながら公式でも推奨[^1]されているOSSライブラリがあります．

[^1]: https://git-scm.com/docs/git-filter-branch


# 事件の経緯
`git filter-repo`を用いて，Git LFSのuninstallの後処理をしていました．
ChatGPTやGithub Copilotに訊きながら進めていたところ，以下のようなコマンドを実行するように求められました．

```bash 
~$ git filter-repo --path-glob '*.zip' --invert-paths
```

流石に，初めて見るコマンドだったので，安易に実行することはせずにブログなどを調べてみて，その動作内容を調べてから実行しました．
ところが，意図していた動作とは異なる動作であることに気づいた時には後の祭り．当該ファイルは全て削除されてしまっていました．

:::note
求めていた動作は，ローカルからはファイルを削除せずに，git / Githubの履歴からのみ削除するというものでした．
:::

resetも試しましたが，どうにもならず……


# どうすればよかったのか
`git filter-repo`の取り扱いは，便利な分だけ気をつけなければならないことに身をもって気付かされたところで，本記事の本題である，どうするべきであったかを復習していきたいと思います．

## バックアップを作成してから作業をおこなう
どんな操作についても言えることですが，特に破壊的な処理をおこなう際にはバックアップを作成しておくことが最適です．
幸いにも，今回削除してしまったファイルは別にオリジナルがあるデータだったため，手間はかかったものの，復元することができました．

オリジナルが別にある復元可能なデータであったこと，作業し始めたばかりの新しめのリポジトリであったことから，大雑把な処理をしてしまいましたが，これが重要なデータであったと思うとゾッとします．

## 新しいリポジトリを作成して作業をおこなう
破壊的な処理をおこなったリポジトリをpushなどで上書きすることは望ましくないようです．[^2][^3]
可能な限り`git filter-repo`を実行する前に，それまでの変更をpushした状態で作業をするべきとのことです．

[^2]: https://qiita.com/propella/items/7b149c8e979b0d9fe416
[^3]: https://docs.github.com/ja/enterprise-cloud@latest/authentication/keeping-your-account-and-data-secure/removing-sensitive-data-from-a-repository

また，`git filter-repo`はデフォルトでremoteの情報が削除されるようになっているようです．
そうした仕様も上書きを防止するというところから来ているようです．

## `--dry-run`を用いる
実行予定の操作が意図したものと異なっていないかを確認するためのオプションとして，`--dry-run`というものがあるようです．[^4]
これを用いることで，私のような悲しい事故を減らすことができるかもしれません．

[^4]: https://htmlpreview.github.io/?https://github.com/newren/git-filter-repo/blob/docs/html/git-filter-repo.html


# 最後に
今回は，`git filter-repo`を用いた結果，発生してしまった悲しい事故について，その再発防止のための復習をおこないました．
上記に挙げたものが全てではないと思いますが，パッと調査した限りではこのような感じでした．

gitは多くの場面で決まった操作しかしない一方で，それ以外の操作となるとまだまだ知識不足であると痛感しています．
ニーズ思考とシーズ思考

![](https://storage.googleapis.com/zenn-user-upload/24fcf508d244-20240928.jpg)

商品を開発して販売するためには、「ニーズ」と「シーズ」の両方が必要です。  
このうち、ニーズは消費者目線でとても分かりやすいので、多くの人が理解しています。  
その結果、ニーズばかりが注目されがちです。

でも、シーズも同じくらい重要です。開発者はシーズに目を向けるべきなのですが、うまく言語化できないため、その大切さが伝わっていないことが多いんですね。  
ここでは、ニーズとシーズの違いを対比しながら、どちらも必要だということを解説していきます。

![](https://storage.googleapis.com/zenn-user-upload/e872c274fc69-20240928.jpg)

**ニーズ**は、消費者が求めているものや必要性です。  
**シーズ**は、メーカーが持っている特別な技術や材料を指します。

![](https://storage.googleapis.com/zenn-user-upload/8be89c4f949b-20240929.jpg)

もっとシンプルに言うと、  
**ニーズ**は「ユーザーが買いたいもの」で、  
**シーズ**は「メーカーが売れるもの」です。

![](https://storage.googleapis.com/zenn-user-upload/0f5d1bbebe45-20240929.jpg)

よく「ニーズとシーズのどちらが大事か？」なんて議論がありますが、実際にまとめてみると、どちらか片方ではダメだということが分かります。  
どちらもないと話になりません。

ニーズがなければ、買う人がいないので売れませんし、シーズがなければ作れないか、作ったとしても高くなって売れません。

![](https://storage.googleapis.com/zenn-user-upload/2b5bf1d5f235-20240929.jpg)

商品を売り出すには、ニーズもシーズも揃っていることが前提なんですね。

![](https://storage.googleapis.com/zenn-user-upload/e370b23fc0fe-20240929.jpg)

よくあるパターンとして、「作りたいから作ったけど、誰も欲しがらない」というのは、シーズだけがある場合です。

![](https://storage.googleapis.com/zenn-user-upload/66fd12726c89-20240929.jpg)

逆に、ニーズだけがあっても、似たような問題があります。  
みんなが欲しがっているものを思いついても、作れなければ意味がありません。  
また、適切な価格で作れなければ、たとえ作れても高くて売れないことになります。

![](https://storage.googleapis.com/zenn-user-upload/0348cad2c17d-20240929.jpg)

さて、シーズについて少し掘り下げましょう。  
シーズは、開発者が持つ技術や知識ですから、細かく分析し、厳密に考える必要があります。  
ニーズは消費者の要望なので、あまり深く分析するのは難しいですが、シーズは専門的に考えることができる分野です。

シーズがしっかりと分析されていないと、ニーズに対応する商品でも、コストが高くなって売れないケースがよくあります。  
シーズの専門家が意思決定に関わらないと、効率の悪い方向に進んでしまうことがあるんですね。

![](https://storage.googleapis.com/zenn-user-upload/3ec4cd425420-20240929.jpg)

ニーズは常に変化しているので、細かく分析し続けるよりも、最新のニーズを素早くキャッチしていくことが重要です。

![](https://storage.googleapis.com/zenn-user-upload/02e5d480eb7c-20240929.jpg)

一方で、シーズはしっかり準備しておく必要があり、これには長い時間がかかります。  
シーズを手抜きで準備すると、その製品は売れません。

ニーズが分かってからシーズを用意しても遅いので、事前に計画的に準備し、どんなニーズが来ても対応できるようにしておくことが大切です。  
また、広い範囲に対応するためには、戦略的に対応を進める必要があります。

![](https://storage.googleapis.com/zenn-user-upload/af233db366fb-20240929.jpg)

シーズを準備する戦略は、ある意味「陣取り」に似ています。  
例えば、まずはMVCを覚える。

![](https://storage.googleapis.com/zenn-user-upload/2fca516d0a5c-20240929.jpg)

次に、関数型プログラミングも勉強する。

![](https://storage.googleapis.com/zenn-user-upload/18a807426bc7-20240929.jpg)

さらに、TypeScriptも習得しておく。

![](https://storage.googleapis.com/zenn-user-upload/5fa68bbb71a7-20240929.jpg)

これで、Reactが必要になった時も、比較的簡単に対応できるようになります。

![](https://storage.googleapis.com/zenn-user-upload/02fd5f96d1a2-20240929.jpg)

MVCや関数型プログラミング、TypeScriptを勉強することで、他の技術も習得しやすくなるため、効率的にシーズを蓄積できます。  
このように、戦略的に学習の順番を考え、今後必要になるスキルを計画的に準備しておくことが大切です。

このようにして、日々の努力でどんなニーズが来ても対応できる準備をしておくことで、いざニーズが発生したときにすぐに応じることができるのです。

(編集協力：ChatGPT 4o様)  
(当記事はZennにもマルチポストされます)
[Zenn](https://zenn.dev/hrmstrsmgs/articles/2202dd6a7eec3c)
(スライド全体はこちら)  
[speakerdeck](https://speakerdeck.com/player/73d9abd781c546d480d4c2a896c7c29d)
LangChainを使ったRAGの実装がわかる（初心者向け）

# はじめに
LangChainは、言語モデルと外部リソースを組み合わせて使用するための柔軟なフレームワークです。ここでは、LangChainを使用したRAG（Retrieval-Augmented Generation）の実装について以下の内容を説明します。

- 指定したドキュメントの読み込みと分割
- 分割したドキュメントのベクトルストアへの登録
- クエリ実行による類似文書の検索

主にLangChainライブラリを使用し、ベクトルストアにはChromaDBというオープンソースソフトウェア（OSS）を利用し、埋め込み生成にはAWSのBedrockサービスを用います。

こちらも参考にして下さい

https://qiita.com/Kahiro/items/56545a93bb99d8bdd8e3

# 筆者のレベル
- RAGについて基本的な理解を持っている
- RAGを実装することで、さらに詳しく学びたい
- プログラムを書く経験はあまりないが、RAGを実装してみたい

# 全体の構成
以下の流れでプログラムを構成しています。
1.	必要なライブラリのインポート
2.	ドキュメントの読み込みと分割
3.	埋め込みの作成
4.	ベクトルストアの作成
5.	ドキュメントの追加
6.	クエリの実行

## 1. 必要なライブラリのインポート
最初に、必要なライブラリをインポートします。これには、Boto3、ChromaDB、LangChainの各モジュールが含まれます。

```python
import boto3
import chromadb
import pprint
from langchain_community.document_loaders import TextLoader
from langchain_text_splitters import CharacterTextSplitter
from langchain_aws import BedrockEmbeddings
from langchain_chroma import Chroma
```

## 2. ドキュメントの読み込みと分割
次に、ドキュメントを読み込み、指定されたサイズで分割する関数を定義します。LangChainでドキュメントをスプリット（分割）する際には、TextSplitterを使うことが一般的です。これは、長いドキュメントをチャンク（小さなセクション）に分割し、効率的に処理するための手法です。LangChainには、さまざまなTextSplitterクラスがあり、以下の目的に応じて使用されます。
- CharacterTextSplitter: 特定の文字数で分割する
- RecursiveCharacterTextSplitter: 文や段落単位で分割するが、文字数の制約も考慮する
- ~~NLP-based splitters: 自然言語処理に基づいて文を分割する~~

ここでは、CharacterTextSplitterを使用した例を示します。

```python
text_splitter = CharacterTextSplitter(chunk_size=chunk_size, chunk_overlap=chunk_overlap)
source_text = TextLoader(file_path).load()
documents = text_splitter.split_documents(source_text)
print('\nソースデータの分割結果: \n')
pprint.pprint(documents)
```

## 3. 埋め込みの作成
次のステップでは、Bedrockを使用して埋め込みを作成する関数を定義します。この関数では、Boto3クライアントを利用してAWSのBedrockサービスにアクセスします。

```python
embeddings = BedrockEmbeddings(
    client=boto3.client("bedrock-runtime", region_name=client_region),
    model_id=model_id,
    region_name=client_region
)
```

## 4. ベクトルストアの作成
Chromaを使用してベクトルストアを作成する関数も定義します。この関数では、指定されたコレクション名と埋め込み関数を使用してベクトルストアを作成します。

clientは、ChromaDBへの接続を管理するクライアントオブジェクトを指定します。ここでは、PersistentClientを使用しており、データが指定されたパス（この場合は.tmp/）に永続的に保存されます。これにより、プログラムを再実行した場合でも、以前に保存したデータを引き続き利用可能です。

```python
vectorstore = Chroma(
    collection_name=collection_name,
    embedding_function=embeddings,
    client=chromadb.PersistentClient(path='.tmp/')
)
```
## 5. ドキュメントの追加
ドキュメントをベクトルストアに追加する関数を定義します。

```python
vectorstore.add_documents(documents=documents, embedding=embeddings)
```
## 6. クエリの実行
指定したクエリを実行し、その結果を返す関数を定義することにより、類似の文書を検索します。

query:
ここで指定するのは、検索を行うためのテキストクエリです。このクエリに基づいて、ベクトルストア内の文書が比較されます。

k:
取得したい類似文書の数を指定します。例えば、k=3と設定した場合、最も類似している上位3つの文書が返されます。

result:
この変数には、検索結果が格納されます。通常、結果は類似文書のリストと、それぞれの類似度スコアのペアで構成されます。

```python
result = vectorstore.similarity_search_with_score(query=query, k=k)
print('\n結果: \n')
pprint.pprint(result)
```

## 7. まとめ
LangChainを利用してRAGの実装を行うための基本的な流れを説明しました。具体的には、ドキュメントの読み込みと分割、埋め込みの生成、ベクトルストアへの登録、そしてクエリを通じた類似文書の検索について詳しく見てきました。LangChainとChromaDB、AWSのBedrockを組み合わせて実装することで、RAGシステム構築の理解が深まれば幸いです。
vSphere ClientのイベントをCSV出力する方法

## 想定している読者
この記事は以下のような方を想定読者としています。
* vSphere基盤の開発/運用を行っている方
* PowerCLIの基本的な使い方を理解されている方
* イベントの期間指定エクスポートがないバージョンのvSphere基盤を利用されている方(vSphere8.0では`高度なエクスポート`という機能があり、GUIからでも時間指定でイベント抽出できるようです)
* vSphereのイベントをGUIで漁るのに辟易されている方

## vSphere Clientのイベントとは？
この記事で触れているイベントとは、vSphere Clientから各オブジェクト(クラスタ/ESXiホスト/VM)を選択後、`監視`>`タスクとイベント`>`イベント`から確認できる情報を指しています。
※以下は、VMware HOL(Hands On Lab)の画面です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3683658/b97a80c5-fd6e-e344-b1cd-40907a1402c6.png)

## なぜCSV出力したいのか
vSphere ClientのGUIで情報を確認する場合、1ページ内に表示できるイベントの上限数は100件までです。
101件より以前のイベントを確認するには、ページ送りで確認する必要があります。
障害発生の時刻がわかっていれば、その時刻まで振り返ってイベント一覧を確認したいですよね。
その場合、地獄のページ送りを連発して、対象の時刻まで移動する必要があり、非常に大変です。

## PowerCLIでイベントを取得する方法

### クラスタのイベントを取得する方法(標準出力)
```powershell:PowerCLI
$cluster = Get-Cluster -Name "クラスタ名"
Get-VIEvent -Entity $cluster -Start 20240401T15:50:20 -Finish 20240402T15:50:20 | ForEach-Object{"{0};{1};{2}"} -f $_.CreatedTime, $_EventTypeId, $_.FullFormattedMessage}
```
以下のようなエラーが出た場合は、開始時刻と終了時刻をGet-Dateを利用して変数に格納してから、オプションの引数として渡してみましょう。
```
Get-VIEvent: Cannot bind parameter 'Start'. Cannnot convert Value "20240401T15:50:20" to type "System.DateTime". Error: "String '20240401T15:50:20' was not recognized as a valid DateTime."
```
以下のように変数格納し、`Get-VIEvent`に渡しましょう。
もっと美しいやり方があるような気もしますが、YYYYMMDD表記でない環境でもうまく動くので、この方法で日付を指定しています。
VMware HOL環境はMMDDYYYY表記ですが、以下の方法でちゃんと動作します。
```powershell:PowerCLI
$start = Get-Date -Year 2024 -Month 4 -Day 1 -Hour 1 -Minute 50 -Second 20
$finish = Get-Date -Year 2024 -Month 4 -Day 2 -Hour 1 -Minute 50 -Second 20
Get-VIEvent -Entity $cluster -Start $start -Finish $finish | ForEach-Object{"{0};{1};{2}"} -f $_.CreatedTime, $_EventTypeId, $_.FullFormattedMessage}
```
これでイベント一覧を標準出力することが可能になりました。

### クラスタのイベントを取得する方法(CSV出力)
次にCSV出力をするために情報を整形します。
例として、"C\User\Administrator\result.csv"のパスにcsvを出力する場合のコマンド例を記載します。
```powershell:PowerCLI
Get-VIEvent -Entity $cluster -Start $start -Finish $finish | Select-Object @{Name="CreatedTime"; Expression={$_.CreatedTime}}, @{Name="EventTypeId"; Expression={$_.EventTypeId}}, @{Name="FullFormattedMessage"; Expression={$_.FullFormattedMessage}} | Export-Csv -Path C\User\Administrator\result.csv -NoTypeInformation -Encoding UTF8
```

## ESXiホスト/VMのイベントを取得する方法
利用するコマンドは、クラスタと同じく`Get-VIEvent`です。
`Get-VIEvent`の利用方法を書くのは冗長ですので、差分だけ書きます。
### ESXiホストのイベントを取得する方法
`Get-VMHost`でESXiホストのエンティティを取得し、`Get-VIEvent`に渡します。
```powershell:PowerCLI
$esxi = Get-VMHost -Name "ESXiホスト名"
Get-VIEvent -Entity $esxi -Start $start -Finish $finish | ForEach-Object{"{0};{1};{2}"} -f $_.CreatedTime, $_EventTypeId, $_.FullFormattedMessage}
```
### VMのイベントを取得する方法
こちらも同じですね。
`Get-VM`でESXiホストのエンティティを取得し、`Get-VIEvent`に渡します。
```powershell:PowerCLI
$vm = Get-VM -Name "VM名"
Get-VIEvent -Entity $vm -Start $start -Finish $finish | ForEach-Object{"{0};{1};{2}"} -f $_.CreatedTime, $_EventTypeId, $_.FullFormattedMessage}
```
perplexity を使ってみた。　~ばいばいハルシネーション~

# 背景
AWS のEC2インスタンスの性能比較って昔はECUという指標がありましたが、最近のインスタンスには情報がなくなっていた。このため、Savings Plansの予算を取るために見積もりを取る時、おのずと安い古いM5とかを使う羽目になる。私としては、インスタンスファミリーをコストパフォーマンスが良い構成にしたいのだが比較する情報が新世代が出るたびに何%改善したとかの情報になってしまい、結果今使ってるm5よりどれくらい効率が良くなっているかがわからない。AWSにチケットきったけど明確な方法が分からなかった。そういった情報はperplexityを使った方がよいと地権者から聞き、調べたところソフトバンク系(Softbank、Ymobile、LINEモバイル）は1年間のProプランが無料らしい(キャンペーン期間：2024.6.19~2025.6.18)。

# 早速登録
とりあえずキャンペーンページをまとめてみた
## Softbank
https://www.softbank.jp/mobile/service/perplexity-ai/
## Ymoble
https://www.ymobile.jp/service/perplexity-ai/
## LINEモバイル
https://www.linemo.jp/service/perplexity-ai/
## その他回線の利用者は、Pro以外か有償のProプラン
https://www.perplexity.ai/

# 使ってみた
## 質問内容
ec2インスタンスのm5.largeを1とした際のm6i.largeおよび、m7i.largeのcpuおよびメモリの性能を教えてください

## 回答
共有する際にURLが出るのもうれしい
https://www.perplexity.ai/search/ec2insutansunom5-largewo1tosit-WjkXWJ0XSJuBanC5p7cWQw

# 感想
よくググるを終わらせる的なことを書かれているが、確かにperplexityを一回使うとGoogleさんに聞いて100サイトくらい回っていた過去が馬鹿らしくなってくる。回答に対して、関連記事がついているのでソースを下の方から探して、読んで記事のどこに対するソースなのかを判断しなくてもいいのは楽すぎる！！
【初心者向け】linuxコマンド～for文～

## Bashのfor文はどういうときに使える？

1. **データ処理**: 複数のファイルやデータを一括で処理したいときに、for文を使って効率的に操作できる

2. **自動化**: 定期的なタスク（バックアップやログの整理など）を自動化する際に、繰り返し実行するコマンドを簡単に記述できる

3. **計算や集計**: 数値のリストを使って合計や平均を計算する場合など、繰り返し処理が必要な場面で活躍する
4. **インストールや設定**: 複数のソフトウェアやパッケージを一度にインストールするスクリプトを書くときに便利

これらの用途により、for文は日常的な作業を効率化し、時間を節約するのに役立ちます。

## Bashにおけるfor文の基本構文

```bash
for variable in list
do
    コマンド
done
```

例えば、1から5までの数を表示するには、次のように書きます：

```bash
for i in {1..5}
do
    echo $i
done
```

このスクリプトは、変数`i`に1から5までの値を順に代入し、それを`echo`コマンドで表示します。for文を使うことで、繰り返し処理が簡単に実現できます。

## Bashのfor文の応用編の具体例

### 1. 複数ファイルのバックアップ
指定したディレクトリ内のすべてのファイルをバックアップするスクリプトです。

```bash
for file in /path/to/source/*; do
    cp "$file" /path/to/backup/
done
```

### 2. サーバーへの一括SSH接続
複数のサーバーに一度にコマンドを実行する場合です。

```bash
servers=("server1" "server2" "server3")
for server in "${servers[@]}"; do
    ssh user@"$server" 'uptime'
done
```

### 3. 数値の集計
1から10までの数の合計を計算する例です。

```bash
sum=0
for i in {1..10}; do
    sum=$((sum + i))
done
echo "合計: $sum"
```

### 4. 環境変数の設定
複数の環境変数を一括で設定する例です。

```bash
for var in VAR1 VAR2 VAR3; do
    export $var="value_of_$var"
done
```

### 5. 複数のディレクトリの作成
指定した名前のディレクトリを一度に作成します。

```bash
for dir in "dir1" "dir2" "dir3"; do
    mkdir "$dir"
done
```

## ループ処理

Bashのfor文では、ループ変数を使用する際には`$`をつける必要がありますが、変数を定義する際にはつけません。具体的には次のようになります。
```bash
for i in {1..5}; do
    echo $i  # ここでは$が必要
done
```

- **ループ変数の使用**: `echo $i` のように、変数の値を参照する場合には`$`が必要
- **変数の定義**: `for i in {1..5};` のように、ループ変数`i`を定義する際には`$`は不要

要するに、変数を参照するときには`$`をつけ、定義する際にはつけないというルールです。
## 最後に
SHLなしでも効率化が進みますね！
Next.jsの`error.tsx`や`not-found.tsx`の`use client`の有無について

## はじめに

Next.jsで`erorr.tsx`と`not-found.tsx`のファイルを作成した際に、どちらもサーバーコンポーネントとして作成してbuildしたところ、`erorr.tsx`のみ`use client`ディレクティブが必要とエラーをはかれてしまいました

個人的には`useState`、`useEffect`、`onClick`、`onChange`等を使ってないので、サーバーコンポネントで十分なのかと思ったのですが、、、

そのため、この記事ではなぜ`erorr.tsx`のみクライエントコンポーネントである必要があるのかについて調べたことをまとめます

## `not-found.tsx`と`error.tsx`について

### `not-found.tsx`

not-foundエラーは存在しないリソースへのリクエストだということを知らせるもののため、クライエントサイドの処理を必要としない

### `error.tsx`

このファイルではサーバーサイドだけではなく、クライエントサイドのエラーも補足して、動作します
そのため、Next.jsのファイルの規則として、クライエントサイドでも動作することを保証する必要があるため、`use client`ディレクティブを使う必要がある
redirect_to current_userのパスの指定先

## 初めに

疑問に思ったことや上手くいかなかったことのアウトプットをしています。
自分なりの理解でアウトプットしていきます。初学者なので誤りもあると思います。
その際はご指摘いただけると幸いです。

# 疑問点
redirect_toで指定するのってurlやpathなのでは？
どうしてこのコードで大丈夫なのか？

# 調べた結果
current_userメソッドは、通常現在ログインしているユーザーのインスタンスを返します。
つまり、
redirect_to @xxx 
などと同様に、省略されているということです。
Railsが推察して、
redirect_to user_url(current_user.id)となるわけです。
@がついてないのでインスタンスと頭の中で繋がりませんでしたが、redirect_toの省略の仕方がわかれば簡単なことでしたね。
[AWS]EC2とは何か[第1回]

## はじめに

はじめまして！「クラウドエンジニア@ITあるある」です。
これが私の初Note公開となります！

もともとはスーパーの店員として働いていましたが、現在はAWSインフラエンジニアとして活動しています。AWS認定資格12種、Google認定資格10種を持ち、今年でエンジニア経験は3年目になります。

このNoteは、IT業界未経験者やこれからクラウド技術を学びたい方に向けて、わかりやすく解説するために作成しました。これを読めば、AWSやEC2の基本がしっかり身につきます！
## Amazon Elastic Compute Cloud (EC2) の概要
Amazon Elastic Compute Cloud（EC2）は、Amazon Web Services（AWS）が提供する中核的なクラウドコンピューティングサービスです。EC2は、クラウド上で仮想サーバーを提供し、ユーザーが必要に応じてコンピューティングリソースを柔軟に利用できるようにします。

🔳EC2の主な特徴：

①スケーラビリティ：需要に応じて瞬時にリソースを拡大縮小できる

②多様なインスタンスタイプとオペレーティングシステムを選択可能

③コスト効率：従量課金制で、使用した分だけ支払う

④信頼性：複数のデータセンターにわたる高可用性を実現

EC2は、ウェブアプリケーションのホスティング、バッチ処理、機械学習の実行、データベースサーバーの運用など、多岐にわたる用途に活用されています。

## クラウドコンピューティングの基本概念
クラウドコンピューティングは、インターネットを通じてコンピューティングリソースを提供するモデルです。EC2を理解する上で、以下の基本概念が重要です：

①仮想化：

物理的なハードウェアリソースを複数の仮想インスタンスに分割する技術

EC2はこの技術を使用して、1台の物理サーバー上で複数の仮想サーバーを実行

②オンデマンドリソース：

必要なときに必要な量のリソースを即座に利用可能

EC2では数分で新しいサーバーインスタンスを起動可能

③APIによる自動化：

プログラマブルなインターフェースを通じてリソースを管理

EC2はAWS CLIやSDKを通じて操作可能

④マルチテナンシー：

複数のユーザーが同じ物理インフラストラクチャを共有

EC2は適切な分離とセキュリティを確保しつつ、効率的なリソース利用を実現

これらの概念により、従来のオンプレミスインフラストラクチャと比較して、より柔軟で効率的なコンピューティング環境を実現しています。

## EC2の主要な特徴と機能
EC2は豊富な機能セットを提供し、多様なユースケースに対応します。以下に主要な特徴と機能を示します：

①インスタンスタイプ：

様々なCPU、メモリ、ストレージ、ネットワーキング容量の組み合わせ

汎用、コンピューティング最適化、メモリ最適化、ストレージ最適化、高速コンピューティングなど

②Amazon Machine Images (AMI)：

インスタンスの起動に必要な情報を含むテンプレート

OSやアプリケーションがプリインストールされたAMIを選択可能

③Elastic Block Store (EBS)：

EC2インスタンス用の永続的ブロックストレージボリューム

インスタンス停止後もデータを保持、スナップショット機能でバックアップ可能

④セキュリティグループ：

インスタンスへのトラフィックを制御する仮想ファイアウォール

インバウンド/アウトバウンドトラフィックのルールを詳細に設定可能

⑤Elastic IP：

インスタンスに割り当て可能な静的パブリックIPアドレス

インスタンスの再起動やリプレイスにかかわらず同じIPアドレスを維持

⑥Auto Scaling：

需要に応じて自動的にEC2インスタンスの数を調整

パフォーマンスを維持しつつ、コストを最適化

⑦Elastic Load Balancing：

複数のEC2インスタンス間でトラフィックを分散

アプリケーションの可用性と耐障害性を向上

⑧スポットインスタンス：

未使用のEC2容量を割引価格で利用可能

中断可能なワークロードに適した低コストオプション

⑨専用ホスト：

物理サーバーを完全に専有

ライセンスコンプライアンスや規制要件に対応

⑩インスタンスメタデータとユーザーデータ：

インスタンス自体に関する情報を取得可能（メタデータ）

インスタンス起動時にスクリプトや設定を渡せる（ユーザーデータ）

これらの特徴と機能により、EC2は幅広いアプリケーションやワークロードに対応し、ユーザーのニーズに合わせた柔軟なクラウドインフラストラクチャを提供しています。

EC2を効果的に活用するには、これらの機能を理解し、適切に組み合わせることが重要です。次のセクションでは、これらの機能をより詳細に解説し、実践的な使用方法を紹介していきます。

## さいごに
最後まで、ご視聴いただき、ありがとうございます。
次回の記事は「EC2のメリットと使用シナリオ」について
書きたいと思います！初学者の方に向けてより詳細に
実践的な内容の記事も記載出来たらと思います。
最後まで読んでいただいた方、ありがとうございました！

Xアカウント：@a0530b0530
openrecallをubuntu起動時に自動実行する

`~/.config/autostart/openrecall.desktop`を作成

```
[Desktop Entry]
Type=Application
Exec=/your-python-env-path/bin/python3 -m openrecall.app
Hidden=false
NoDisplay=false
X-GNOME-Autostart-enabled=true
Name=OpenRecall
Comment=Run OpenRecall at startup
```

これでいけます。
当然、your-python-env-pathはいい感じにしておいてください。
killコマンドが効かない時の対処法

# killコマンドが機能しない????

devcontainerでgolangを使ってweb開発を行っているときに事が起きました.

デバッグ中に何度かサーバの実行と停止を繰り返していたところ, 停止ができなくなり, psコマンドでIDを確認後強制的に停止を図ったのですが, 何度killコマンドを叩いても停止することができませんでした.

```shell
vscode ➜ /workspaces/xxx (main) $ ps
  PID TTY          TIME CMD
  421 pts/0    00:00:00 bash
14093 pts/0    00:00:00 go
14214 pts/0    00:00:00 main
15416 pts/0    00:00:00 ps
vscode ➜ /workspaces/xxx (main) $ kill 14093
vscode ➜ /workspaces/xxx (main) $ ps
  PID TTY          TIME CMD
  421 pts/0    00:00:00 bash
14093 pts/0    00:00:00 go      <----killされていない!
14214 pts/0    00:00:00 main
15514 pts/0    00:00:00 ps
```


# 解決方法
この問題の対処法としてはkillコマンドに-9オプションを付け加えることでkillすることが来ます.

```shell
kill -9 <PID>
```



kill -9 コマンドの -9 は、シグナル番号 9（SIGKILL）を指定しています。これは、プロセスを強制終了するためのシグナルです。通常の kill コマンド（デフォルトではシグナル 15 (SIGTERM) を送信）はプロセスに終了を要求しますが、プロセスが応答しない場合があるみたいです。

SIGKILL はプロセスに対して強制的に終了を命令し、プロセスがこのシグナルを無視することはできません。以下に具体的なコマンドを示します。
windowsのコマンドプロンプトでsleepsortするバッチ例

単発小ネタ　Windowsバッチ

# 20240929_windowsのコマンドプロンプトでsleepsortするバッチ例  
  
## 機能  
- あるソートアルゴリズムの実装例です。
- 以下の二つのバッチを同じ階層に置いて、キッカーの方を起動すると、ランダムな整数を生成してソートします。

```sleeper_kicker_v001.bat
@echo off
color 1E
rem **** **** **** **** **** **** **** **** **** **** **** 
rem **** **** **** **** **** **** **** **** **** **** **** 
echo.
echo ################################################################
echo.
echo sleep sort バッチです。実行しますか？
echo 中止する場合はCtl+C
echo 実行する場合は
pause

echo.
echo 実行します
echo.
echo ################################################################
echo.
color 3F
echo.
echo ************ 処理開始 ************
echo.

rem **** **** **** **** **** **** **** **** **** **** **** 
rem **** **** **** **** **** **** **** **** **** **** **** 
rem 時間取得
set CDATE=%date:~-10,4%-%date:~-5,2%-%date:~-2,2%
set CTIME=%time: =0%
set CTIME=%CTIME:~0,2%-%CTIME:~3,2%-%CTIME:~6,2%

rem ログファイル設定
set CDIR=%~dp0
set LFILE=%CDIR%sleepsort_%CDATE%_%CTIME%.txt

echo. >> %LFILE%
echo start  : %DATE% %TIME% >> %LFILE%
echo ******************************************** >> %LFILE%

rem **** **** **** **** **** **** **** **** **** **** **** 
rem **** **** **** **** **** **** **** **** **** **** **** 

SETLOCAL enabledelayedexpansion
set /a RN1=%RANDOM%*11/32768+1
set /a RN2=%RANDOM%*11/32768+1
set /a RN3=%RANDOM%*11/32768+1
set /a RN4=%RANDOM%*11/32768+1
set /a RN5=%RANDOM%*11/32768+1
set /a RN6=%RANDOM%*11/32768+1
set /a RN7=%RANDOM%*11/32768+1
set /a RN8=%RANDOM%*11/32768+1
set RNALL=%RN1%,%RN2%,%RN3%,%RN4%,%RN5%,%RN6%,%RN7%,%RN8%
echo randnum : %RNALL%
echo randnum : %RNALL% >> %LFILE%
echo.

start /MIN %CDIR%sleeper_v001.bat %RN1% %LFILE%
start /MIN %CDIR%sleeper_v001.bat %RN2% %LFILE%
start /MIN %CDIR%sleeper_v001.bat %RN3% %LFILE%
start /MIN %CDIR%sleeper_v001.bat %RN4% %LFILE%
start /MIN %CDIR%sleeper_v001.bat %RN5% %LFILE%
start /MIN %CDIR%sleeper_v001.bat %RN6% %LFILE%
start /MIN %CDIR%sleeper_v001.bat %RN7% %LFILE%
start /MIN %CDIR%sleeper_v001.bat %RN8% %LFILE%

echo. >> %LFILE%
echo ******************************************** >> %LFILE%
echo end    : %DATE% %TIME% >> %LFILE%
echo by %0 >> %LFILE%
echo ******************************************** >> %LFILE%
echo. >> %LFILE%
echo ** ↓ sorted ↓ ** >> %LFILE%
echo. >> %LFILE%

rem **** **** **** **** **** **** **** **** **** **** **** 
rem **** **** **** **** **** **** **** **** **** **** **** 
echo.
echo ************ 処理終了 ************
echo.

color
echo 10秒後に閉じます。ソート結果は数秒後に確認して下さい。
ping 127.0.0.1 -n 10 2> nul 1>&2
exit
```

```sleeper_v001.bat
@echo off

ping 127.0.0.1 -n %1 2> nul 1>&2
echo %1 >> %2

exit
```

## その他
- 色々なアルゴリズムがソートの速度を競う中で、lazy sortとかsleep sortとか呼ばれる凄い発想のアルゴリズムです。個人的には、その発想はなかった( ﾟДﾟ)ってなって試してみたものです。

以上
「アップロード前に画像を圧縮する」ときの落とし穴

## 忙しい向けの人へのまとめ

1. [ImageMagick](https://imagemagick.org/index.php#google_vignette)はアップロード後に圧縮するから要件的にNGだった
2. [browser-image-resizer](https://www.npmjs.com/package/browser-image-resizer)は、画像の幅、高さが小さくなりすぎる場合もある
3. [pica](https://www.npmjs.com/package/pica)は幅、高さを指定できて、なんとかなった

## ImageMagickがダメだった話

~~ちゃんと設定しないとセキュアじゃないし、インストールコマンドが急に動かなくなることがあるし、インストールにかかる時間も長いけど、これ以上に万能な画像加工ライブラリを私は知らない~~

日頃IT業に従事する諸兄らには俄かに信じ難い話かもしれないが、数メガバイトの画像アップロードが「重たすぎる（遅すぎる）」というお言葉を頂戴した

そこで、アップロード後にサーバで圧縮する方法（ImageMagick）は廃止し、ブラウザ（フロントエンド）で画像を圧縮する運びとなった

## browser-image-resizerもやめた話

フロントエンドで画像を圧縮できるライブラリを探していたところ、[browser-image-resizer](https://www.npmjs.com/package/browser-image-resizer)というライブラリを見つけた。数メガバイトの画像ファイルを数十キロバイトまで圧縮することができる優れモノであった

しかし、画像の高さ、幅がガラパゴスケータイ時代のサイズになってしまうケースがあり、難アリという話が上がってしまい、画像の幅、高さをある程度指定できるライブラリを探すことになった


## pica様と出会った話

[pica](https://www.npmjs.com/package/pica)を発見し、使ってみたところ、上記の課題を解決することができた。当然と言えば当然であるが、型はFile→Image→Canvas→Blobに変換してゆく必要がある
~~仕方ないことだと頭では理解しているものの、上記の変換処理の存在は、あまりにも異質というか、自然言語から離れすぎた実装になっている気がして大変気に食わない。どうにかしたいが、私はそれが解決できるほどオブジェクト指向をマスターしていない！~~ ひとまず課題は解決できたのでヨシッとする

## ソースコード

ChatGPT 4oにpicaで画像圧縮する方法を聞けば、確実に教えてくれるため割愛する
アスペクト比の考慮や小さすぎるファイルは圧縮しないように伝えておくとよいだろう

## さいごに

このpica様、**最終公開が3年前**である

問題なく動いているが、将来メンテナンスされてゆくのか心配であり、他ライブラリを探すべきなのかもしれない

ところでフロントエンドで画像を含むファイル圧縮は対応している拡張子は少ない気がする。とはいえ、多すぎても何かしら困りそうだ

コメント欄に有識者が批判と一緒に良いライブラリや方法を書いてくれるかもしれないし、ライブラリの批判を書くのはエンジニアの恥、自分で開発すべきなのかもしれないがそんな時間の余裕も知識もない。ライブラリ開発者各位、誠にありがとうございます
Ubuntu 24.04でLocalStackを動かす

## はじめに

AWSの勉強をするときに、AWSの実環境を使って構築してもよいのですが、料金が心配です。
そこで、ローカル環境でAWSを利用することができるLocalStackを使って、気軽にAWSのリソースを作成できるようにしました。
Ubuntu 24.04上に構築したので、その手順をまとめておきます。

## 環境情報

| コンポーネント | バージョン | 備考 |
|-|-|-|
| PC | Intel® NUC Kit NUC11PAHi7 | SSD: 2TB<br>Memory: 64GB|
| OS | Ubuntu 24.04  |   |
| Docker | 24.0.7 | |
| LocalStack | 3.7.2 | |
| awscli | 2.17.61 | |
| awscli-local | 0.22.0 | |

## 構築手順

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

環境構築に必要なパッケージをインストールしておきます。
```bash
sudo apt install docker.io python3-full pipx curl groff
```

### dockerの実行権限を追加

コンソールにログインしているユーザーがdockerを実行できるように権限を設定します。
```bash
sudo usermod -aG docker $USER
```
上記コマンド実行後は一度コンソールからログアウト&ログインしてください。

### LocalStackにサインアップする

以下のサイトからLocalStackにサインアップしてください。
https://www.localstack.cloud/

### LocalStack CLIをインストール

LocalStack CLIをインストールします。
今回はtar.gzから直接インストールします。
```bash
curl --output localstack-cli-3.7.2-linux-amd64-onefile.tar.gz \
    --location https://github.com/localstack/localstack-cli/releases/download/v3.7.2/localstack-cli-3.7.2-linux-amd64-onefile.tar.gz
sudo tar xvzf ~/Downloads/localstack-cli-3.7.2-linux-*-onefile.tar.gz -C /usr/local/bin
```

### 環境変数の設定

以下の環境変数を設定します。

```bash
export LOCALSTACK_AUTH_TOKEN="サインアップした際に発行されるPersonal Auth Token"
export AWS_ACCESS_KEY_ID="test"
export AWS_SECRET_ACCESS_KEY="test"
export AWS_DEFAULT_REGION="us-east-1"
export AWS_ENDPOINT_URL=http://localhost:4566
```

### awscliのインストール

awscliをインストールしてawsコマンドを利用できるようにします。
```bash
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install
```

### awscli-localのインストール

awscliだけだと、実行時に毎回endpoint urlを指定しないといけないため、awslocalコマンドを利用できるようにします。
```bash
pipx install awscli-local
export PATH=/home/$USER/.local/bin:$PATH
```

### LocalStackを起動

LocalStackを起動します。
```bash
localstack start
```

### S3バケットを作成して、ファイルをアップロードしてみる

環境構築ができたか確認するために、S3バケットを作成してファイルをアップロードしてみます。
```bash
$ awslocal s3 mb s3://hoge
make_bucket: hoge
$ touch test.txt
$ awslocal s3 cp test.txt s3://hoge
upload: ./test.txt to s3://hoge/test.txt
$ awslocal s3 ls s3://hoge/
2024-09-29 00:03:31          0 test.txt
$
```

## 最後に

LocalStackを使ってAWSのリソースを気軽に作成できる環境を構築しました。
LocalStackで使えるサービスは実環境と比べて少ないですが、AWSに慣れていない人が気兼ねなく触れる環境の一歩としては良いと思います。
この環境を使ってAWSのサービスについて理解を深めていきたいです。

## 参考情報

- https://www.localstack.cloud/
- https://docs.docker.com/engine/install/linux-postinstall/
- https://docs.localstack.cloud/getting-started/installation/#localstack-cli
- https://docs.localstack.cloud/getting-started/auth-token/
- https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html#cliv2-linux-install