OmniAICreator/Qiita-1.07M huggingface dataset:
Linuxの設定等で、不意にnanoで編集が始まり、「キーッ！」とならないための設定

1. 以下のコマンドで、設定を変更する。
    ```bash
    update-alternatives --config editor
    ```


1. 使いたいエディタを選択する。
    ```
      alternative editor (/usr/bin/editor を提供) には 5 個の選択肢があります。
    
      選択肢    パス              優先度  状態
    ------------------------------------------------------------
    * 0            /bin/nano            40        自動モード
      1            /bin/ed             -100       手動モード
      2            /bin/nano            40        手動モード
      3            /usr/bin/nvim        30        手動モード
      4            /usr/bin/vim.basic   30        手動モード
      5            /usr/bin/vim.tiny    15        手動モード
    
    現在の選択 [*] を保持するには <Enter>、さもなければ選択肢の番号のキーを押してください: 4
    update-alternatives: /usr/bin/editor (editor) を提供するためにマニュアルモードで /usr/bin/vim.basic を使います
    ```
1. 再び、以下のコマンドを実行すると、設定が変わっていることが確認できる。
    ```bash
    update-alternatives --config editor
    ```

    ```
      alternative editor (/usr/bin/editor を提供) には 5 個の選択肢があります。
    
      選択肢    パス              優先度  状態
    ------------------------------------------------------------
      0            /bin/nano            40        自動モード
      1            /bin/ed             -100       手動モード
      2            /bin/nano            40        手動モード
      3            /usr/bin/nvim        30        手動モード
    * 4            /usr/bin/vim.basic   30        手動モード
      5            /usr/bin/vim.tiny    15        手動モード
    ```
Podman Desktopを使って、商用無償なコンテナ環境を作ろう

# Podman Desktopとは？

一言でいうと __Docker Desktopの代わりになる、無償で商用利用可能なソフトウェア__ です。

2022年10月24日にRed Hat社から発表され、__Docker Desktopのようなコンテナの起動・停止などの基本的な操作をGUI上で行うことができます。__

__コマンドラインの使い勝手も Docker と同じ使い勝手__  です。つまり、

> docker xxx

というコマンドは、

> podman xxx 

として利用できます。

Podman DesktopはWindows上でコンテナを開発する上でとても便利なツールになるでしょう。

# Podman Desktop インストール

[こちら](https://podman-desktop.io/)　からダウンロードしてインストールしましょう。

詳細なインストールは、下記の記事から。

https://qiita.com/ynagashi/items/3d853c5189383dc98270

# Composeを使う

Podmanにはdocker composeに相当する機能も備えられています。ですが、最初から有効化されているわけではありません。

Setting　-> ResoucesメニューからComposeを有効にする必要があります。

![setting_resource.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35954/47e2fa40-499c-2cec-5d57-afe8ee1376c6.png)

下記のComposeをsetupしてください。

![compose.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35954/ff34103c-df58-45ff-ea3a-0174a516629d.png)


# Docker Composeを使ってみる。

それではDockerと本当に互換性があるのかを実際に動作させて確認してみましょう。今回、動作させるツールはAIワークフローをGUIで構築できるDifyとします。

[DifyのGitHubサイト](https://github.com/langgenius/dify)をチェックアウトするか、リポジトリをzipでダウンロードします。コマンドプロンプトを開き、dify/dockerフォルダに移動して、以下のコマンドを入力します。

> podman compose up -d

を行うとイメージの取得が始まりました。

![cli_dify.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35954/03c0fb72-a555-7851-733a-f4d7ae0575bc.png)


localhostにアクセスすると、Difyが起動しています。

![dify.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35954/f61360b6-068b-0d95-1604-83c0cdaf2a2c.png)

Docker Desktopを使わない場合は手がかかるものでしたが、こんなにアッサリできて良いものかと思えるほど簡単でした。驚きですね！
【Vue3】refとreactiveで管理できるものを理解していなかった話

## はじめに
コードを書く中で「あれ？これってref、reactiveどっちで定義すればいいんだ？オブジェクトだからreactive？」ということがあり、何も理解していなかったので備忘録として残したいと思います。（理解したとは言っていない）
以下認識誤り等ありましたら、ご指摘いただけると幸いです🙇‍♂

### 環境
- Vue3 , Nuxt3
    - Composition API
- TypeScript



## 結論
**オブジェクトだからといって、必ずしもreactiveで定義する必要はない（refでもOK）**

## 勘違いしていたこと
学習する中で、何故か`ref=プリミティブ`、`reactive=オブジェクト`と思い込んでおり、「オブジェクトを定義するときはreactiveで定義しなきゃ」という思考になっていました。
reactiveがプリミティブNGなだけで、refは何でもOKでした。

※[プリミティブ](https://typescriptbook.jp/reference/values-types-variables/primitive-types#%E3%83%97%E3%83%AA%E3%83%9F%E3%83%86%E3%82%A3%E3%83%96%E5%9E%8B%E3%81%AE%E7%A8%AE%E9%A1%9E)＝ざっくり、オブジェクト以外の文字列や数値などのこと

|  | プリミティブ | オブジェクト |
|:-:|:-:|:-:|
|**ref**|◯| ◯|
|**reactive**|✕|◯|

## プリミティブ
```vue
<script setup lang="ts">
// reactiveは使えない
let refCount = ref(0);
let reactiveCount = reactive(0); //NG
</script>
```
## オブジェクト
```vue
<script setup lang="ts">
//　ref, reactiveどちらでもOK
let refUser = ref({
  name: "Ref",
  age: 20,
});

let reactiveUser = reactive({
  name: "Reactive",
  age: 30,
});
</script>
```

## ref, reactiveどちらを使うか
細かい説明は割愛しますが、いろいろな方の意見を総合すると、とりあえずrefでよさそうです。（参考参照）
個人的にも、オブジェクト全体を更新する際にreactiveだとプロパティ別に更新する必要があるので、refでいいかなと思っています。

### オブジェクト全体を更新する例
```vue
<template>
  <div>
    名前：{{ refUser.name }}&nbsp;年齢：{{ refUser.age }}
  </div>
  <div>
    名前：{{ reactiveUser.name }}&nbsp;年齢：{{ reactiveUser.age }}
  </div>
  <div>
    <button @click="refIncrement">RefAge+</button>
  </div>
  <div>
    <button @click="reactiveIncrement">ReactiveAge+</button>
  </div>
  <button @click="allChange">allChange</button>
</template>
<script setup lang="ts">
let refUser = ref({
  name: "Ref",
  age: 20,
});

let reactiveUser = reactive({
  name: "Reactive",
  age: 30,
});

const refIncrement = () => {
  refUser.value.age++;
};

const reactiveIncrement = () => {
  reactiveUser.age++;
};

const allChange = () => {
  // refだと一括更新できる
  refUser.value = {
    name: "Ref Taro",
    age: 40,
  };

  // reactiveで下記はNG（リアクティブなオブジェクトではなくなる）
  reactiveUser = {
    name: "Reactive Taro",
    age: 60,
  };

  // 下記のように個別更新であればOK
  // reactiveUser.name = "Reactive Taro";
  // reactiveUser.age = 60;
};
</script>
```

## まとめ
- reactiveではプリミティブがNG
- オブジェクトを扱う際はref, reactiveどちらでも問題ない（個人的にはref）


## 参考
https://zenn.dev/comm_vue_nuxt/articles/ref-vs-reactive

https://qiita.com/Yametaro/items/2a37f18fb52f7565b2cb

https://qiita.com/sygnas/items/672709d6dad6bcfea43f

https://typescriptbook.jp/reference/values-types-variables/primitive-types#%E3%83%97%E3%83%AA%E3%83%9F%E3%83%86%E3%82%A3%E3%83%96%E5%9E%8B%E3%81%AE%E7%A8%AE%E9%A1%9E
技術カンファレンスは良いコンテンツが集まるので効率が良い

## はじめに

◆この記事は何？
技術カンファレンスのコストパフォーマンスの高さを紹介する記事

◆対象は？
技術カンファレンスに参加したことがない方

◆この記事のねらい
技術カンファレンスへの参加に迷っている方の背中を押すこと

## 先に結論
- 技術カンファレンスに集まるコンテンツの質が高い、人のレベルも高い
- 単に視野が広がる、視座が高くなるのではなく、そのコストパフォーマンスが高いと考えます。
- その質も高く、大げさに言えば、エンジニア人生に影響を与える可能性があります。

## 視野が広がる理由

技術カンファレンスに参加すると、視野が広がります。

代表的な理由は次のとおりです。
- 詳しく知らなかった技術を知れるため
    - 例：難しいと思っていた技術が実現できるようになっていた
- 企業ブース等で詳しく知らなかった企業やサービスを知れるため
- 社外の方と交流すると、自社の常識が通用しないことがあり、他社の常識に触れることができるため

例えば、お恥ずかしながら、私は「生成AIでのテストケース作成はまだ難しい」と懐疑的な立場でした。
しかし、カンファレンスで実演されている様子を見て、考え方を改めました。

技術カンファレンスでは、新鮮で質の高い情報を効率的に収集できます。

## 視座が高くなる理由

技術カンファレンスに参加すると、視座が高くなります。
理由は各社の経営層や優秀な人材による講演が多いためです。

その結果、自分の役職や立場からは考えていなかったような視点で発表されることがあります。

例えば、私は「エンジニアリングマネージャー」に強く興味が湧きました。
エンジニアリングマネージャーの方から話を聞かなければ、興味はわかなかったと思います。

社外の人の講演はより効果的です。社内の人の話は義務的に感じられることがあるからです。

社外の方の講演を聞くことで、より効果的に伝わります。
社外の方々に効率よく交流できるのが技術カンファレンスです。

## おわりに

この記事では、技術カンファレンス参加のメリットとその高いコストパフォーマンスを紹介しました。

技術カンファレンスの参加を迷っている人の参考になれば幸いです。
「AWS認定クラウドプラクティショナー」受験

Y子です。

「AWS認定クラウドプラクティショナー」の試験を受けてきました。今日はその話です。

# 結果
最初に書いてしまいますが、「不合格」でした！あちゃー。
完全に、経験不足・準備不足・勉強不足でした。
今回の試験料金16500円を無駄にしないためにも、次は受かりたいです。

# 経緯
これまでAWSは全く未経験でしたが、最近仕事で触るようになりました。
触れる前に、初心者向けの参考書を読み通して、主要サービスはどんなものがあり、それが何を担当しているのか、ぐらいはわかる状態になりました。
そこからは、わかる人に聞いて、EC2を立ち上げたり、セキュリティグループを設定したり、Step Functionsの動きを見守ったり…なんてことをしてました。

そんな感じなんですが、上司との面談で「AWSの資格を取る」と 
言わされて
 宣言してしまったので、とりあえず「クラウドプラクティショナー」の試験を受けてきた、という流れです。

# 勉強
クラウドプラクティショナー試験対策の参考書も買いましたが、いろいろ自分に言い訳して、しばらく「積ん読」状態でした。これはよくないと思い、先に試験を申し込んでしまうことに。

結果的に、やったことはこんな感じでした。全部で3時間ぐらいだと思います。
* 各章末の練習問題を解く　…これは全部やった
* 誤答があった章の説明を読む　…1/4ぐらいで時間切れ、試験日到来

# 試験の申込
金曜の昼休みに、試験の実施時期や申し込みについて調べてみると、試験の24時間前まで申し込めるとのこと。
2日後の日曜に時間があったので、とにかくそこで1回受けてしまおうと決めました。

AWS認定アカウントを作成し、クラウドプラクティショナーの受験許可申請をし、試験予約ページへ。

日曜の試験について、自宅から近い会場がいい感じに空いていることを確認できたので、料金支払いの前にいったん仕事に戻って、夕方に改めてその会場を確認してみると…空いてない！満席になってしまったようで…。ちょっと離れてる別の会場が空いていたので、そこを選択してお金を払いました。

【感想】
[AWSの公式サイト](https://aws.amazon.com/jp/certification/certified-cloud-practitioner/ "AWS 認定クラウドプラクティショナー")を見ても、「試験内容を理解する」「試験内容を確認して練習する」「お客様の声」などと書いてあるばかりで、試験がいつ・どこで行われるのかが全然わからないですよね。ここでくじける人、いるんじゃないかなあ…。

私は、上記公式サイトの「試験のスケジュールを立てる」という黒いボタンから「AWS認定」というページに入り、そこから「AWS Builder ID」を作成したら、AWS認定アカウントのページから試験の登録などができるようになりました。


# 試験会場
試験会場には、試験開始15分前に到着しましたが、手続き含めちょうどいいくらいでした。

受付で、アンケートを記入し、身分証明書を2点（運転免許と健康保険証）提示し、その場で顔写真を撮られて、手続き完了。眼鏡以外のすべての荷物をロッカーに収納して、試験室へ。スマホだけでなく、財布・腕時計・ハンカチ・家の鍵などもダメと言われたので、心細かったです。眼鏡も、顔から外して内側など確認されました。ズボンのポケットは、中をひっくり返して見せました。

スタッフさんに連れられて試験室に入室。驚いたのは、その「テストセンター」という会場では、英検もマイクロソフトの試験も実施しており、それが同じ部屋で、それぞれのタイミングで行われているということ。衝立に囲まれたブースに、1人1台のPCがあり、それぞれのタイミングで試験が開始されるというのが、大学の試験や、以前受けた情報処理の試験と違っていて、今はこんな感じなんだと感心しました。スタッフさんの操作でPCが使えるようになり、すぐに試験が開始しました。

# 試験
試験時間は90分。前に不正をしない宣誓5分、後に試験のアンケート5分の時間がとられているので、計100分。すべてマウス操作で、選択肢から選んでいくスタイルです。
試験は、直前に読んだ参考書とピッタリ同じ問題があって爆速で回答したり、まるで分らず悩んだ末に適当に選んだりしながら、全65問を解き進めていきます。残り24分で回答を終えたので、平均1問1分といったところ。回答中に「見直し」のフラグを設定でき、私はこれが39件ありました。半分以上ですね…。残り時間でこれらを見直し、4問ほど回答を変えました。室内にも画面にも時計はなく、画面の残り時間表示だけが時間の手がかりです。それが「00分00秒」になったところで、回答操作ができなくなり、アンケートへと進みます。
アンケートは14問。受験体験が良かったかどうかなどを聞かれ、最後に「これでアンケートを終わっていいですか？」に「Yes」と答えると…いきなり試験の結果が表示されました。

「評価：不合格」

ああ、やはり。わからなくて雰囲気で選んだ設問、結構あったもんなあ。
5営業日以内に、成績の連絡が届くそうで、そこで点数なんかもわかるんでしょうか。

# 次回へ向けて
正直、「参考書1冊読んだし、一番下の試験なら受かるのでは」という思いで臨みましたが、そんな甘いものではなかったですね…。
そういう危機感をもらえたのが、今回の収穫。
2週間開ければまた受けられるようなので、さっさと対策本を読み込んで受かってしまいたいと思います。

がんばります！
アルゴリズムの計算量コードにしてみた！！

# 計算量O記法

以下にアルゴリズムの計算量をコードを記述しました。
勉強の記録として残します。

## プログラム記述

```python
# O(log(n))
def func2(n):
    if n <= 1:
        return
    else:
        print(n)
        func2(n/2)

# O(n)
def func3(numbers):
    for num in range(numbers):
        print(num)

# O(n * log(n))
def func4(n):
    for i in range(int(n)):
        print(i, end=' ')
    print()
    
    if n <= 1:
        return
    func4(n/2)
    
# O(n**2)
def func5(numbers):
    for i in range(len(numbers)):
        for j in range(len(numbers)):
            print(numbers[i], numbers[j])
        print()
        
```

## 実行結果

下記は、計算結果を実行したものになります。
最後のO(n**2)は表示するデータが多いため除外しています。
実行結果が気になる方は、以下のデータを引数で渡して実行してください。

```
func5([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
```

O(log(n))
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2759758/708e2398-49c3-8e61-58b6-cb19e03e0df7.png)

O(n)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2759758/399be47d-e4c3-9868-facd-83697703884c.png)

O(n * log(n))
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2759758/82fda52b-14ed-d145-9a9e-2a15644b2280.png)
WinTpicで描いた図形をepsで出力する

# 背景

WinTPicでeps出力しようとすると，以下のエラーが表示されてepsを保存できないケースがあります。

`gswin32c.exe can not execute.`
`can not rename: C:.../_wintpic001.eps to C:.../_wintpic001.__k. gswin32c.exe does not terminate.`

このメッセージの原因は大きく2つあり，

* gswin32c.exeをインストールしていない
* WinTpic側の設定をghostscriptの最新版に対応させていない

ということが挙げられます。
この記事では，これらの問題を解決することでWinTPicからeps出力ができるようにします。

# 前提

WinTpic（記事を書いた人はWinTpic4.32aを使用）と，Tex LIveを導入していることが前提となります。

# 解決策

## gswin32c.exeのインストール

まず，Ghostscriptのダウンロードページに行きます。
[Ghostscriptのダウンロードページ](https://ghostscript.com/releases/gsdnld.html)

 Ghostscript ... for Windows (32bit)のGhostscript AGPL Releaseを選ぶと，インストーラ（gs...w32.exe）がダウンロードされますので，インストーラを起動し，手順に従ってGhostscriptをインストールしてください。
特にいじらなければ，C:\Program Files (x86)\gs\gs...\binにgswin32c.exeがいるでしょう。

#### システム環境変数の確認

Winキー→検索欄で「システム環境変数の編集」を開き，「環境変数」＞システム環境変数の枠の変数「Path」をダブルクリックしてください。
環境変数名の編集として，現在設定されている環境変数の一覧が表示されます。この中に，C:\Program Files (x86)\gs\gs...\binがいることを確かめてください。もし無ければ，「新規」からパスを書き加えてください。下図のように追加されていれば大丈夫です。
![systempath.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3797205/b37f7abe-4e86-4e3f-c37e-e57752c9dd6f.png)

## WinTpicの設定

次に，WinTpicを起動します。

ウィンドウ上部 その他＞設定 Option＞PDFと進み，次の2つを設定します。
* gswin32c.exeの項目を，`C:\Program Files (x86)\gs\gs...\bin\gswin32c.exe`とする
* CommandLine / PDF->(E)PSの項目を，`-q -r20480 -dNOPAUSE -dBATCH -dSAFER -sDEVICE=eps2write -sOutputFile="#OUTPUTFILE#" -c save pop -f "#INPUTFILE#"`とする


# 結果

ここまで正常に設定が完了していれば，epsを出力できるはずです。
ウィンドウ上部 ﾌｧｲﾙ＞EPSの出力と進むと，確認のメッセージが出ます。OKを選んでしばらく待つと，EPSを保存する場所を指定する画面に切り替わります。
「正常に終了しました(EPS)」のメッセージが出たら保存完了です。

# おわりに

本記事では，Ghostscriptの導入とWinTpicの設定を確認することによって，WinTpicのeps出力ができるようにしました。
Fusion360で物体の総質量を正確に見積もりたい

# はじめに
Fusion360を使っていると、コンポーネントの重量を求めたい時があります。このような時は、デザイン画面で左のツリーから対象のコンポーネントやボディを右クリックしてプロパティを選べば、そのコンポーネントやボディの質量が確認できます。

![Fusion360でボディのプロパティを確認.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3781638/11e87a99-1a61-2b9d-a358-c4a007c9cbec.png)

# 困ること

コンポーネントの質量を確認したい場合、その中身がすべて単一の材質でできた部品なら、単に個々の部品の材質をちゃんと物理マテリアルで指定していれば問題ないのですが、複数の材質でできた部品（下図のようなモータなど）が含まれている場合は問題となります。

例えば下図のモータの場合、ケースはアルミだと思うのですが、内部にはコイルや磁石、シャフトが入っている＝銅や鉄（や空洞）が含まれているので、このモータの物理マテリアルとして単にアルミを指定していると総質量が小さく計算されてしまいます。

このようなモータのような製品では、分解でもしない限り中身はブラックボックスで、中身の形状や材質は不明であるケースがほとんどだと思います。製品のデータシートに記載されている総重量を参考にするか、製品の実物を購入して総重量を測るか。そのくらいが通常です。

![物理マテリアルが問題となるケース（複数材質が含まれる製品）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3781638/28574473-8a5e-7b33-b1b6-efd21e52e4f1.png)

どうやればこのような複数材質が含まれる製品の総重量をちゃんと設定できるでしょうか？私は3種類ぐらい方法があるかなと思いましたので、こちらで紹介します。

# やり方

3種類の方法について以下でご紹介します。

- カスタム物理マテリアルの適用
- 物体を内部に隠して質量調整
- 内部を空洞にして質量調整

## カスタム物理マテリアルの適用

まず思いつく方法です。これが一番素直な方法だと思います。

物理マテリアルのフォーム上部には現在そのプロジェクト内で使われている物理マテリアル一覧が表示されていますが、これらのマテリアルを右クリック→複製して内部の各種パラメータを調整することでカスタムマテリアルを作成することができます。これを利用します。

![各物理マテリアルはは右クリックから編集や複製画可能.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3781638/d7917887-d5e9-ce00-fb10-c3ec177529d7.png)

対象とする物体の外形寸法から体積が計算できますから（プロパティ画面から確認できる）、この体積と理想質量から密度を計算し、カスタムマテリアルにこの密度を設定することで、その物体の質量を任意の値に合わせることができます。

下図は、アルミの物理マテリアルを複製し、密度を0.004g/mm^3に修正したカスタムマテリアルを作成した例です。詳細ボタンから色などの設定も可能です。

![カスタム物理マテリアルを作り適用する方法.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3781638/19eb8cf4-0c26-a956-7c0a-b92017a8e12c.png)

## 物体を内部に隠して質量調整

カスタム物理マテリアルを作りたくない事情がある（？）場合は、次の方法もあります。
既存の物理マテリアルで作成した物体を内部に隠して、全体の質量を調整する方法です。

下図は、モータのケースより一回り小さな円柱モデルを作成し、既存の物理マテリアルを適用、プロパティで円柱の質量を見ながら円柱の高さで質量を微調整したあと、移動コマンドでモータ内部に組み込んだ様子を示しています。

![重量合わせ用の物体を製品内部に隠す方法.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3781638/ade3ce80-86de-dc6d-83e9-4bb23779289f.png)

## 内部を空洞にして質量調整

カスタム物理マテリアルを作りたくない事情がある（？）場合は、次の方法もあります。
既存の物理マテリアルでわざと全体の質量を少し理想値より大きめに設定し、物体内部を必要なだけ空洞にして、全体の質量を調整する方法です。

# 補足

## 物理マテリアルの適用方法

物理マテリアルは、左のツリー上で対象のコンポーネントかボディの名称を右クリック→物理マテリアルからパレットを表示し、そのパレットから適用したい物理マテリアルを探して 対象物のモデル or ツリー上の対象物の名称 にドラッグアンドドロップして適用します。

## 物理マテリアルの色設定は外観でオーバーライド可能

物理マテリアルをモデルに適用すると、そのマテリアルの色も反映されますが、別途、外観を設定することによって見た目を上書きすることができるようです。

下図のように、マテリアルは鋼なのに外観はプラスチック、みたいな設定も可能です。マテリアルと外観を混同しないようにご注意ください（私は最初混同していて、外観だけ設定すればよいと思っていました…）。

![外観設定と物理マテリアルは連動しない.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3781638/f5837755-73b7-f2de-f41b-1598ee68e841.png)

# さいごに
以上、複数材質でできた部品が含まれるコンポーネントの総質量を正確に見積もるための方法をいくつかご紹介しました。

メカ設計を仕事でされている方にとってみれば既知の内容である気もしなくもないのですが、自分が最初困ったのと、ナレッジとして残す意味もあるかなと思い、記事にしてみました。

少しでも参考になれば幸いです。最後まで読んで下さりありがとうございました。

# 参考リンク
[Fusionでカスタムマテリアルを追加する](https://www.autodesk.co.jp/support/technical/article/caas/sfdcarticles/sfdcarticles/JPN/Adding-Custom-Materials-in-Fusion-360.html)
[Vue3]Supabaseで簡単にMFAログインを実装する

## TL;DR
### 実装したコード
```vue
<script setup lang="ts">
import { supabase } from '@/utils/supabase';

const targetEmail = 'ユーザーが入力した自分のメールアドレス';
const redirectURL = 'リンクをクリックするとリダイレクトされるページ';

const login = async () => {
  try {
    const { error } = await supabase.auth.signInWithOtp({
      email: targetEmail,
      options: {
        shouldCreateUser: false,
        emailRedirectTo: redirectURL,
      },
    });
    
    alert('入力したメールアドレスにログイン確認メールを送信しました.');
    router.push('/');
  } catch (error) {
    alert(error.message)
  }
};
</script>
```
## Magic Linkの編集

Supabseメニューの「Authentications」

![スクリーンショット 2024-06-30 16.08.46（小）.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3754242/189cb9a2-45c7-be9d-e15f-2c898e4c06c6.jpeg)

「Email Templates」-> Magic LinkでHTMLメールが修正できる。

![スクリーンショット 2024-06-30 16.08.58（小）.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3754242/d554dc68-7b72-726a-0714-72394aebd2c2.jpeg)


## 終わりに
結局公式ドキュメントに書いてある通りではある。
しかし普通に調べているとすぐ見つからなかった。React向けのページは多いけれども...

https://supabase.com/docs/guides/auth/auth-email-passwordless
[初学者向け]テーブル定義に最低限必要な知識

## [初学者向け]テーブル定義に最低限必要な知識
今回初めてテーブル定義を行ったので、テーブル定義を行う前に知っておきたい単語をまとめておきたいと思います。

## 目次
- データベース（DB）
- テーブル
- マスターデータ
- トランザクションデータ
- 主キー（プライマリーキー）
- 外部キー 

## 
### データベース（DB）
まず、テーブルはデータベースの中に格納されています。
データベースとは簡単にいうと色々なデータが入っている箱のようなものです。
そしてその中に、テーブルというデータが入っている箱のようなものがあります。
Excelで例えると、データベースがブック。テーブルがシート（もしくは表）です。

### テーブル
テーブルとは、データベースの基本的な構造で、行（レコード）と列（カラム）で構成されます。列は特定のタイプのデータ（例：名前、年齢など）を表し、行はそのデータの特定の値（例：すずき、25歳など）を表します。

### マスターデータ
基礎となるものが入っているデータで、
システムを動かす前から入れておく必要のあるものです。
そのデータを入れるテーブルのことをマスターテーブルといいます。

### トランザクションデータ
システムを動かすことによって蓄積されていくデータです。
そのデータを入れるテーブルのことをトランザクションーテーブルといいます。

### 主キー（プライマリーキー）
データベースのデータ（行、レコード）を一意に識別するための項目です。
出席番号をイメージすると分かりやすいかもしれません。
出席番号が分かればその番号の人の名前や性別が分かるように、
「その値さえ分かれば他の情報も分かる」項目が主キーです。

### 外部キー
これはテーブル定義を進めてみないと分かりづらいかと思いますが、
テーブルは複数あることが多いです。
そしてその複数のテーブルの中でも依存関係にある2つのテーブルを結びつける項目が外部キーです。

少し難しいので、イメージするのにぴったりなサイトを共有します↓
https://wa3.i-3-i.info/word1992.html
##
以上でテーブル定義に最低限必要な知識を終えます。
このほかにも関数従属、推移的関数従属、推移的関数従属などもあるらしいのですが、
これはテーブル定義を進める途中に必要な知識な上、まだ理解が浅いのでまた今度まとめます。
Pythonコードの実行時間を計測する

# 1. なんでそんなことするの？
Kaggleでニューラルネットとか使う創薬コンペに取り組んでいるのですが、Kaggle Notebookのランタイムの制約と戦っています（12時間/回）。ギリギリ時間切れでoutputが出て来ず、時間を何時間も無駄にするのは避けたいところ。
各コード・セルの処理時間を計測したいと思ったので、やり方のメモをします。
# 2. やり方
まずライブラリをインポートします。
```
import time
```
次に、処理時間を計測したいコードをtime.time()で挟みます。
time.time()は1970年1月1日 00:00:00 UTC（協定世界時）からの経過時間を秒単位で返します。
```
# 実行時間の計測開始
start_time = time.time()

#*  処理  *#
#*  処理  *#
#*  処理  *#

# 実行時間の計測終了
end_time = time.time()

# 実行時間の表示
elapsed_time = end_time - start_time
print(f"経過時間: {elapsed_time:.2f} seconds")

```
end_time − start_timeで経過秒数が分かります。

# おわりに
他にも関連するtipsあれば教えてください！
【VSCode】Rubyでコードジャンプする方法

# ✅ はじめに
本投稿では、VSCodeでRubyのコードジャンプを提供してくれる拡張機能の導入方法を解説してます。

## 対象者
- VSCodeでRubyの開発を行っていて、JSなどと同様にコードジャンプしたい方
- 拡張機能をインストールしたものの、期待通りにコードジャンプが動作しなかった方

# ✅ 拡張機能
Rubyのコードジャンプを提供してくれる拡張機能として、ダウンロード数の多い以下の2つを導入して、軽く動作確認しました。

- Ruby Solargraph
- Ruby LSP

## 現時点の感想

現時点でコードジャンプ用途であれば、`Ruby Solargraph`のほうが使いやすいと感じた。

拡張機能 | 現時点の感想
--- | ---
Ruby Solargraph | クラス、メソッドいずれもジャンプできた。コードジャンプ用途ならこちらのほうが使いやすいと感じた。
Ruby LSP | コードジャンプできる箇所が限られており、やや不便と感じた。（インスタンス化したクラスのメソッド呼び出しから、定義元クラスの先頭にしかジャンプできなかった）<br><br>コードジャンプの動作を確認していたところ、コメントに日本語が含まれている場合に、それまで動作していたコードジャンプが動作しなくなることがあった。

<br><br>

# ✅ Ruby Solargraph

![solargraph.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/141934/ea07e4d3-23ee-957e-10ee-80fa8a18b1f1.png)

## インストール
VSCodeの拡張機能マーケットプレイスからインストールします。

## 準備

拡張機能をインストールしただけではコードジャンプが動作せず、`solargraph`をインストールする必要があります。

```
$ gem install solargraph
```

## 起動
VSCodeでRubyのプロジェクトを開くと、`cmd + クリック`でコードジャンプができるようになってます。

※ `solargraph`をインストールした直後は、プロジェクトの開き直しが必要でした。

![solargraph-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/141934/9f45104a-f66a-e97c-6408-10498a609f47.png)

## 感想
クラス、メソッドいずれもジャンプできた。コードジャンプ用途ならこちらのほうが使いやすいと感じた。

<br><br>

# ✅ Ruby LSP

![ruby-lsp-5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/141934/5d5bdfd1-09de-74df-93a2-5e5392ff9fa6.png)

## インストール
VSCodeの拡張機能マーケットプレイスからインストールします。

`Ruby LSP`単体でもインストールできますが、`Ruby`をインストールすると合わせて`Ruby LSP`もインストールされます。

![ruby-lsp-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/141934/433bcba0-09f4-2d41-0e5c-c6866680c7bd.png)

## 準備
拡張機能をインストールしただけではコードジャンプが動作せず、`ruby-lsp`をインストールする必要があります。

VSCodeで開いてるディレクトリに`lockファイル`が存在してない場合、`lockファイル`を作成します。

```
# Gemfileを作成する
$ bundle init

# Gemfile.lockを作成する
$ bundle install
```

VSCodeで開いてるディレクトリに`lockファイル`が存在してる場合は、`.ruby-lsp`ディレクトリが作成されるので、その配下で`bundle install`します。


```
# .ruby-lspディレクトリに移動
$ cd .ruby-lsp

# インストール
$ bundle install
```

## 起動
`Ruby LSP`の起動状態はVSCode下部で確認できます。

![ruby-lsp-3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/141934/fbd0eb4f-d6ec-45ea-f42e-bb0934a1ab0a.png)


`Ruby LSP`が起動してない場合は、`コマンドパレット(cmd + shift + P)`から`Ruby LSP: Start`コマンドを実行します。

![ruby-lsp-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/141934/03004a57-b9e8-ec77-d8ee-9a1b3882f92a.png)

`Ruby LSP`が起動してると、`cmd + クリック`でコードジャンプができるようになります。

![ruby-lsp-4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/141934/de76091a-961d-e0fa-55af-f1c744fc9fc1.png)

## 感想
コードジャンプできる箇所が限られており、やや不便と感じた。（インスタンス化したクラスのメソッド呼び出しから、定義元クラスの先頭にしかジャンプできなかった）

コードジャンプの動作を確認していたところ、コメントに日本語が含まれている場合に、それまで動作していたコードジャンプが動作しなくなることがあった。
CPU、GPU、TPUの違いについて

似た名称なので、整理するためにまとめます。
## CPU
Central Processing Unitの略。よく、パソコンの頭脳と呼ばれます。
主な役割はプログラムを実行したり、数値計算などです。CPUの性能が高いと、プログラムや演算を早く行うことができるため、快適にPCを操作できるようになります（ただし、CPUだけ性能が高いとボトルネックが発生し、十分に性能を発揮できません）。
## GPU
Graphics Processing Unitの略。主な役割はグラフィックスのレンダリングや並列計算などです。要するに映像や行列演算に関する処理をしています。GPUの性能が高いと、ゲームをするときに、動作が軽くなったり、動画編集を快適におこなうことができます。また、機械学習では行列演算を行うため、機械学習の分野でも活躍します。
## TPU
Tensor Processing Unitの略。Googleが設計した機械学習（主にニューラルネットワーク）に特化したものです。
主な役割は、行列演算です。GPUでも、行列演算は可能ですが大規模な行列演算を行うときはTPUのほうが高速に処理できるそうです。

## まとめ
CPU→PCの頭脳で、プログラムの実行や全体的な制御をしている。
GPU→映像、ゲーム、機械学習の分野で活躍。
TPU→機械学習に特化していて、大規模な行列演算ではGPUより優秀。
これらは、略称が似ていますが、役割が全く違います。

参考:https://cloud.google.com/tpu/docs/intro-to-tpu?hl=ja
[Java] apache commons mathで行列演算(ベクトル編)

行列編はこちら→https://qiita.com/AlliumAllium/items/b05bd5195f1b68041ab9

# コード
```Java
import org.apache.commons.math4.legacy.linear.RealVector;
import org.apache.commons.math4.legacy.linear.MatrixUtils;

public class Test {
    public static void main(String[] args) {
        // 宣言
        RealVector vector1 = MatrixUtils.createRealVector(
                new double[] { 1, 0, -2 });
        System.out.println("v1 =");
        System.out.println(vector1);
        RealVector vector2 = MatrixUtils.createRealVector(
                new double[] { 1, 1, 1 });
        System.out.println("v2 =");
        System.out.println(vector2);
        double s = 3;
        System.out.println("s =");
        System.out.println(s);

        // 次元
        System.out.println("次元 =");
        System.out.println(vector1.getDimension());

        // ノルム(大きさ)
        System.out.println("ノルム||v1|| =");
        System.out.println(vector1.getNorm());

        // L1ノルム
        System.out.println("L1ノルム||v1||_1 =");
        System.out.println(vector1.getL1Norm());

        // 正規化
        System.out.println("正規化 v1/||v1||_1 =");
        System.out.println(vector1.unitVector());

        // 和
        System.out.println("和 v1+v2 =");
        System.out.println(vector1.add(vector2));

        // 差
        System.out.println("差 v1-v2 =");
        System.out.println(vector1.subtract(vector2));

        // 要素の積
        System.out.println("要素の積 {v1_i * v2_i}_i =");
        System.out.println(vector1.ebeMultiply(vector2));

        // 内積
        System.out.println("v1・v2 =");
        System.out.println(vector1.dotProduct(vector2));

        // 外積
        System.out.println("v1 × v2 =");
        System.out.println(vector1.outerProduct(vector2));

        // スカラー倍
        System.out.println("v1*s =");
        System.out.println(vector1.mapMultiply(s));

        // 距離
        System.out.println("d(v1, v2) = ");
        System.out.println(vector1.getDistance(vector2));

        // v1をv2へ射影
        System.out.println("v2への射影ベクトル = ");
        System.out.println(vector1.projection(vector2));

    }
}

```

## 結果

``` java
v1 =
{1; 0; -2}
v2 =
{1; 1; 1}
s =
3.0
次元 =
3
ノルム||v1|| =
2.23606797749979
L1ノルム||v1||_1 =
3.0
正規化 v1/||v1||_1 =
{0.4472135955; 0; -0.894427191}
和 v1+v2 =
{2; 1; -1}
差 v1-v2 =
{0; -1; -3}
要素の積 {v1_i * v2_i}_i =
{1; 0; -2}
v1・v2 =
-1.0
v1 × v2 =
Array2DRowRealMatrix{{1.0,1.0,1.0},{0.0,0.0,0.0},{-2.0,-2.0,-2.0}}
v1*s =
{3; 0; -6}
d(v1, v2) =
3.1622776601683795
v2への射影ベクトル =
{-0.3333333333; -0.3333333333; -0.3333333333}
```
監視項目を決めていく時のとっかかり

## この記事の目的
- 監視項目を考える時の進め方に悩んだ時、参考にする
    - ナレッジを貯めていく

## 監視項目の整理の流れ
![機能ベースでの監視項目の整理.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3293400/6819694d-b92d-13c7-cd5b-631ca5583397.png)
- このサンプルはクロール＆スクレイピングをする機能の監視項目を考える時に作ったもの
    - 基本は機能として保守・運用者がキャッチしないといけない事を言語化し、それを掘り下げていく
    - 原因・起因はできるだけ詳細に
        - なにが発端となったかによって取るべきアクションも定義できればGood

- リソース監視は、また別の整理方法あるはずなので別途追記
LeetCode挑戦日記：Day23

# はじめに

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

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

# [Medium] 2352. Equal Row and Column Pairs

0インデックスの` n x n` 整数行列`grid`が与えられたとき、行`ri`と列`cj`が等しいペア`(ri, cj)`の数を返してください。

行と列のペアが等しいと見なされるのは、それらが同じ要素を同じ順序で含む場合です（すなわち、同じ配列である場合）。

## 素直に解いてみる

### 考え方

1. 列と行をそれぞれ比較し、同じものをカウントする

### コーディング

```typescript
function equalPairs(grid: number[][]): number {
    let counter = 0;

    const n = grid[0].length;
    for (let i = 0; i < n; i++) {
        for (let j = 0; j < n; j++) {
            let isBreaked = false;
            for (let k = 0; k < n; k++) {
                if (grid[i][k] !== grid[k][j]) {
                    isBreaked = true
                    break;
                }
            }
            if (!isBreaked) {
                counter++;
            }
        }
    }

    return counter;
};
```

### 結果

Runtime：128ms
Beats 29.63%

Memory：55.86MB
Beats 97.64%

## 改善：ループを減らす

### 考え方

1. 各列と行を1度`string`にすることで、ループ数を減らす

### コーディング

```typescript
function equalPairs(grid: number[][]): number {
    let counter = 0;
    const n = grid[0].length;
    const rows = new Map<string, number>();

    grid.forEach((row) => {
        const str = JSON.stringify(row);
        const count = rows.get(str) ?? 0;
        rows.set(str, count + 1);
    });

    for (let i = 0; i < n; i++) {
        const col = grid.map((row) => row[i]);
        const count = rows.get(JSON.stringify(col)) ?? 0;
        if (count) {
            counter += count;
        }
    }

    return counter;
};
```

### 結果

Runtime：89ms
Beats 93.60%

Memory：58.69MB
Beats 78.11%
Rustのクロスコンパイルでerror: linking with `cc` failedが出る

## TL;DR
リンカーを導入して/.cargo/configに指定する。
## 遭遇したエラー
Ubuntu on Docker(amd64)で`cargo build --target armv5te-unknown-linux-musleabi`を実行したところ、`error: linking with `cc` failed`が発生した。
## 対処
1. リンカーをインストールする。
    ```bash
    $ apt-get update; apt-get install gcc-arm-linux-gnueabi binutils-arm-linux-gnueabi
    ```
1. リンカーを指定する。
    ```toml:.cargo/config
    [target.armv5te-unknown-linux-musleabi]
    linker = "arm-linux-gnueabi-gcc"
    ```
🔰 Googleフォームの通知よ、スラックにおいで！！！

## 初めに
ある業務でアンケート取ることになったのですが、
アンケートって実施するかどうかはする側の自由だし、
いつ答えてくれるかわからないし、
実施したかのチェックは面倒だし、
通知してくれないかな〜。しかもスラックのチャンネルにくれるといいな〜。

こんなわがままを叶える方法を記載してくれている記事があったので紹介します！

## Googleフォームって？
とても簡単にアンケートやフォームを作成することができるやつです！
詳しくはこちら↓

https://www.google.com/intl/ja_jp/forms/about/#overview

## Slackって？
超便利なコミュニケーションツール！
決まった時間に通知して！とかもできる優れもの！
詳しくはこちら↓

https://slack.com/intl/ja-jp

## 参考にした記事やサイト　【感謝】

* 全体

https://zenn.dev/tam_tam/articles/395cbd2038bf4d

*  Slack公式サイト

https://api.slack.com/quickstart#webhooks

## 最後に
「楽してこうぜ」日々の業務！！
初めてのGoogle Apps Scriptで麻雀記録表を作成する

# 初めに
こんにちは、小川です。
今回は友達と麻雀をしている際に、結果を記録して残しておきたい。
また、よく5人で麻雀をして2人ペアとなって東南戦で分けて麻雀をするということが多いため、一般的な麻雀記録表のアプリでは対応していないので、独自に麻雀記録表を作成してみることにしました。

# つけたい機能
今回つけたい機能は以下の2つです。
1.1半荘毎の結果を記録
2.日毎の結果、平均順位を記録

また、ITリテラシーの低い人でも使えるようシンプルかつ、だれでも使えるようにするため、GoogleスプレッドシートのGoogle Apps Scriptを使って作成することにしました。
GoogleスプレッドシートならURLを知っていれば、簡単に見たり編集することができます。

# 実際にGoogle Apps Scriptを使ってみる
まずはメニューバーの拡張機能の中にある、Apps Scriptを押す。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3780649/17a9e39c-0b1b-6337-53b8-9663205b5e4a.png)

スクリプトエディタが起動しますので、ここに処理を書いていきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3780649/165c3c63-dfb8-98e8-c458-d837aabb8d4a.png)

まずはボタンを押すと本日の日付が表示される処理を作成してみる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3780649/900b14c6-82ef-9dbe-50ee-9fb0157e749a.png)

日付を入力というボタンを作成したかったが、リサーチ不足でボタンに処理を紐づける方法が見つからなかったため、チェックボックスを作成してそのチェックボックスにチェックが入ったら処理を行うように実装。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3780649/66ac1bdb-e2bd-03e7-5c7a-499e5bb8568b.png)
うまく日付が入力されました。※一度ついたチェックは自動で外れるようにしています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3780649/9b207b2b-62c9-12a4-1bad-f7710a5dcde7.png)

# 基本的な処理

・アクティブなシートを取得する
var sheet=SpreadsheetApp.getActiveSheet();

・getRangeメソッドで操作するセルの範囲を指定する
var range=sheet.getRange("A1:A5");

・getRangeメソッドで指定したA1を起点（相対パス）に、getCellメソッドで行番号と列番号を指定してセルの値を取得
var cell=range.getCell(1,1).getValue();

他にもいろいろな処理がありますが、これらを使って麻雀記録表を作成していきます。

# 1半荘毎の結果を記録する処理を作成
まずは記録するための表を作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3780649/1af1776a-8115-7134-20c6-bc6093838804.png)

ここに入力された結果を入力確定を押した際に下の表に反映するよう処理を追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3780649/586fafa4-9fe8-d41a-4de6-d781ba60083a.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3780649/659e8770-f24d-3bd0-839d-4fd57646ac5c.png)

入力確定押下後以下のようにうまく処理が動いてくれました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3780649/88d4a55e-8047-5968-d970-c5d624ed18eb.png)

# 日毎の結果、平均順位を記録する処理を作成
同じく記録するための表を作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3780649/17bd0d45-c69b-225f-84bf-66da8a6b480b.png)

日ごとの計算を押下した際に1半荘毎の結果が日毎の結果と平均順位が表示されるよう処理を追加
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3780649/196b881f-a0da-079a-b452-5c17421742de.png)

日ごとの計算を押下後以下のようにうまく処理が動いてくれました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3780649/c554b01b-e38b-368a-08d3-2347194b97ff.png)

# 終わりに
Google Apps Scriptは無料で使えて開発環境の構築が不要なため気軽にできるプログラミング言語です。
今回私はGoogle Apps Script使用して麻雀の記録表を作成しましたが、手作業で行っていた業務を自動化できたり、マクロの記録で普段の作業をスクリプトに自動保存できたりといろいろな使い方ができます。
みなさんも気軽にGoogle Apps Scriptに触れてみてください。

以上、小川でした。
DCプラグ

いとしのFON2405は二種類あります。細いほうが外径4mmで太いほうが5.5mmです。

![写真（2024-06-30 15.07）.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/d11da604-c0f2-6165-4e55-d46f71b5c63f.jpeg)

IO DATAやNECの製品でセンターにピンがあるEIAJ4というものが使われているものがあります。外径は5.5mmです。

![写真（2024-06-30 15.08）.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/cd875934-22a9-347a-af47-28e2eecfa496.jpeg)

これのジャック側はこうなってます。

![写真（2024-06-30 15.09）.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/2d7763e4-677f-61ad-3b30-095960c33245.jpeg)

ジャックが丸く開いた穴に出ます。

![写真（2024-06-30 15.11） #2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/d764f8fc-23da-6ab9-8bda-336eec26e7cd.jpeg)

EIAJ4なアダプタはあまり手持ちがないので、普通のプラグ使うためにジャックを交換するには四角い穴を開ける必要があります。

長い事いろいろ思案していたのですが、秋月で買ったジャックが机の上にあり目に留まりました。外径4mmのジャックです。

![写真（2024-06-30 15.12）.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/f1dfe3a9-54ea-e1b8-9233-aa1c4afeb4cb.jpeg)

これを付けてみます。

![写真（2024-06-30 15.13）.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/3d91f475-299b-3560-f416-f77888d7e6a0.jpeg)

まだ試してないのですが、実際に使う時は基板のジャックを外して、リードで結線すると良さそうです。

HardOffで110円で買ってきたモジュールに、300円とかの変換プラグはへんなので、こうするのが良さそうです。

参考：[マルツの説明のページ](https://www.marutsu.co.jp/contents/shop/marutsu/mame/15.html)

EIAJ4は秋月で100円なのでプラグを付け替えたほうが良いかもしれません。
Goのnet/httpでサーバーのハンドラー処理を作ってみる

## はじめに
net/httpパッケージを使って、サーバーのハンドラー処理を書いてみた。

handler1、handler2、handler3、handler4、どれも書き方は若干違うが、最終的にhttp.Handle()が呼び出され、ルーティングが登録されるため同義となる。

http.Handle()の第2引数では、http.Handler型が指定されており、http.Handlerはインターフェイスで、ServeHTTPメソッドの実装を期待しているので、それを実装した型を入れてやると動く。

http.HandlerFunc()は、http.ResponseWriterと*http.Requestを引数に持つ関数が指定されており、実行するとhttp.HandlerインターフェイスのServeHTTPメソッドを実装した、http.HandlerFunc型になるので、それをhttp.Handle()に渡す。

```go
package main

import (
	"net/http"
)

type handler3 struct{}

func (h *handler3) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("Test Handler 3"))
}

func handler4(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("Test Handler 4"))
}

func main() {
	handler1 := func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("Test Handler 1"))
	}
	http.HandleFunc("/test1", handler1)

	handler2 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("Test Handler 2"))
	})
	http.Handle("/test2", handler2)

	handler3 := &handler3{}
	http.Handle("/test3", handler3)

	http.HandleFunc("/test4", handler4)

	http.ListenAndServe(":8080", nil)
}
```

## 動かしてみる

```
go run main.go

curl http://localhost:8080/test1
Test Handler 1%

curl http://localhost:8080/test2
Test Handler 2%

curl http://localhost:8080/test3
Test Handler 3%

curl http://localhost:8080/test4
Test Handler 4%
```

## 参考
- https://pkg.go.dev/net/http#hdr-Servers
- https://qiita.com/BitterBamboo/items/6119f7986a04c5a0ac57
コメントについて今一度考えてみた

# はじめに
開発している中で、コメントについてコードレビューを受ける機会があり、ここで今一度コメントのあり方について考えたことを執筆しようと思います。

# コメントには必要なものと不要なものがある
業務の中で、ここはコメントしておいてほしい、このコメントは不要なので消しておいてくださいといったレビューをこれまで受けてきました。これまで受けてきた上記のレビュー傾向から、不要なコメント、必要なコメントそれぞれについて**独断と偏見に基づいて**以下にまとめます。

# 不要なコメント
不要なコメントの種類として、以下の２つが挙げられるかと思います。
### 1. 自己説明的なコメント
自己説明的なコメントとは、その言葉が示す通り、「**コードの内容や役割を説明しているコメント**」のことを指します。このようなコメントが望ましくない理由は、主に以下の２つかなと思います。
#### メンテナンスされない可能性が高い
当たり前ですがコードの内容が変更されたときに、コメントもそれに応じて更新する必要があります。しかし、我々は人なので、コードだけ直してコメントを直し忘れるという事態は往々にして発生します。コメントとコードの内容が一致していない状態は、その後のエンジニアを困らせる要因になってしまいます。
#### DRY原則に反する 
DRY原則は「Don't Repeat Yourself」の略で、重複を避け、コードの再利用を促進することを目的とした設計原則です。この原則に従うことで、メンテナンスが容易になり、エラーの可能性が減少し、全体的な開発効率が向上します。**コメントがコードの内容を重複して説明している**場合は、DRY原則に反してしまいます。

以下に、自己説明的なコメントの例を示します。
```Ruby
class UserFilter
  # 初期化
  def initialize(users)
    @users = users
  end

  # 年齢でユーザーをフィルタリングする
  # 指定された年齢以上のユーザーを配列として返却。
  def filter_by_age(min_age)
    @users.select { |user| user.age >= min_age }
  end

  # アクティブなユーザーのみをフィルタリングする
  # アクティブな状態のユーザーのみを配列として返却。
  # アクティブとは、`active` 属性が true であることを意味する。
  def active_users
    @users.select { |user| user.active }
  end
end
```
これらのコメントは、変数名やメソッド名、ロジックから処理内容を把握することができるため、全て不要です。
### 2. メソッドや変数の命名の不適切さを補うためのコメント
コメントの中には、「この命名さえわかりやすければ要らないのにな〜」といったものがあります。コメントを書き足す時には、**命名で何とかならないものか今一度検討する**習慣をつけたいですね。
例えばこのメソッド。確かにこのメソッド名では、どのようにユーザーを絞っているのかわからないのでコメントで補足するほかありません。
```Ruby
# 未成年のユーザーを除外する
def filter_users(users)
  users.reject {|user| user.age < 20 }
end
```
しかし、メソッド名を以下のように変更することでコメントを抹消することができます。
```Ruby
def reject_minors(users)
  users.reject {|user| user.age < 20 }
end
```

# 必要なコメント
では、どんなコメントが望ましいのでしょうか。それは、**コメント以外で表現できない作成者の意図を残すためのコメント**かなと思います。
もう少し具体的に言うと、「なぜそのように書かれているのか？」や「最終的に何が達成されるのか？」といった内容です。これらは、のちにそのコードを読むことになるエンジニアにとって、「だからこう書いてあるのか！」という理解につながるので、その後のメンテナンスのことを考えると書いておいた方が親切といえます。
```Ruby
def valid_all?
  # 全てのバリデーションチェックを走らせるために、一度変数に入れる
  is_profile_form_valid = valid?
  is_request_form_valid = @request_form.valid?(:send_request)
  is_bank_account_form_valid = @bank_account_form.valid?(:register_bank_account)
  
  is_profile_form_valid && is_request_form_valid && is_bank_account_form_valid
end
```
上記のコメントは、以前弊社のコードレビューをしている時に見ていいなと思ったものの一例です。
is_profile_form_valid = valid?の部分をあえて変数に格納している理由を書いているので、読む側からすると非常にわかりやすいですね。

# 社内での規則がある場合は例外
ただ、社内でコーディング規則がある場合にはそれに従うべきです。
もしその規則が「これはどうなん？」という感じなのであれば、規則自体を改定できるよう動きたいですね。

# まとめ
いかがでしたでしょうか。コメントは、プロダクトの動き自体にはあまり影響がありませんが、のちにそのコードを読むことになるエンジニアへ我々の意図を伝える重要な成果物の一つです。彼らが混乱したり誤った修正を加えてしまったりしないよう、十分に注意を払いたいものです。

# 参考元
以下のサイトを参考に記事を書かせていただきました。

https://zenn.dev/solxyz_bso/articles/7c45bb3d30ecb8

https://next.rikunabi.com/journal/20131216_t21_iq/

https://zenn.dev/aoyagi816/articles/92b83685c15e49
ITパスポート タイムマネジメント

・アローダイアグラム（PERT図）
作業の順序や作業の関連性を図で表したもの
記号と意味
→（矢印）作業を表す。矢印の上に作業名、矢印の下に所要日数を記入する
〇（丸）作業と作業の結合点（ノード）を表す。先行するものから順に番号を付ける
--→（点線矢印）ダミー作業で、作業の順序関係だけを表す。所要日数が０の作業
複数の先行作業
全ての先行作業が完了してから後続作業が開始できる

・最早開始日
全ての先行作業が完了し、最も早く後続作業を開始できる時点
「先行作業の最早開始日＋作業日数」で求める
複数の作業が集まる結合点の最早開始日は、最も遅い作業に合わせることがポイント

・最遅開始日
全ての後続作業の日程が遅れないように、先行作業が完了していなくてはならない時点
「後続作業の最遅開始日－作業日数」で求める
複数の作業が分岐する結合点の最遅開始日は、最も早い作業に合わせることがポイント

・クリティカルパス
最早開始日と最遅開始日が等しい結合点で結んだ経路
全ての経路のパターンを拾い上げ、その中で最も日数がかかる経路

・ガントチャート
作業別に作業内容とその実施期間を棒状に図示したもの

・マイルストーン
開始と終了を明確にし、ある意思決定をする時点

・バーンダウンチャート
時間と残作業量の関係を表した図
グラフは右肩下がりとなり、予定の時間内にどれだけ作業が進んでいるのかを視覚的に把握できる

・グラフ理論
ノード（頂点・接点）と、そのつながりであるエッジ（枝）で表された対象をグラフと呼び、このグラフの性質を分析すること
インデックスシグネチャと型安全性

## インデックスシグネチャとは
インデックスシグネチャとは、オブジェクトの型を宣言する際に使用できる構文で、任意のプロパティキーに対して、プロパティの型を設定することができます。

オブジェクトの型を宣言するときにはプロパティのキー名が必要になりますが、プロパティに変数を使ってアクセスする場合など、型を宣言する時点ではプロパティキーがなにか判明していない場面などで有用です。

`{[key: T]: U}`という構文で表され、プロパティキーの型`T`とプロパティ値の型`U`を設定できます。

:::note warn
Mapped Types の構文`{ [key in T]: U } `と見かけが似ているので、混同しないよう注意が必要です。
:::


```ts
type Fish = {
  [name : string]: string
}
```
上の例の`Fish`型は、プロパティキー、プロパティ値がともに`string`型であるオブジェクト型となっています。

`number`型のプロパティ値をもつオブジェクトリテラルを`Fish`型の変数に代入しようとすると、以下のように`string`型に合致していない旨の型エラーを出してくれます。
```ts
const fish: Fish = {
  name: 'Tuna',
  age: 20
}
```
```
Type 'number' is not assignable to type 'string'.(2322)
input.tsx(2, 3): The expected type comes from this index signature.
```

## 通常のプロパティと一緒に使う
インデックスシグネチャは通常のプロパティと一緒にオブジェクト型の記述に使用可能です。
ただし、使用できるプロパティには、**インデックスシグネチャで指定した型の部分型**という制約がつきます。
```ts
type Fish = {
  [name : string]: string
  habitat: 'sea' | 'river'
}
```
`sea`|`river`型は`string`型の部分型ですので、上の例では問題なく使用できます。
インデックスシグネチャのみのままでも型エラーは出ないのですが、プロパティのキー名で指定することによって`Fish`型の値が`habitat`プロパティを必ず持っていなければならないことを型で明示できるので、より厳格な型チェックができるようになっています。


```ts
type Fish = {
  [name : string]: string
  age: number
}

```
一方で上の例のように、インデックスシグネチャの型に合致しない`number`型のプロパティ`age`を追加することはできません。
```
Property 'age' of type 'number' is not assignable to 'string' index type 'string'.(2411)
```

## 型安全性が損なわれるケースに注意
インデックスシグネチャはプロパティ名の判明していないプロパティを型に入れるときなどに有用ではありますが、型安全性を損なう面を持ち合わせていることを意識しておく必要があります。

インデックスシグネチャではプロパティ名を指定せずに型が定義できるので、存在しないプロパティへアクセスした場合にも型エラーが出ないといったことが起こり得ます。

以下のように存在しないプロパティへ`string`型の変数でアクセスするコードを考えてみます。
```ts
type Fish = {
  [name : string]: string
  habitat: 'sea' | 'river'
}

const fish: Fish = {
  name: 'Tuna',
  habitat: 'sea'
}

const key = 'foo'

console.log(fish.key)
console.log(fish.bar)
```

`Fish`型の変数`fish`には`foo`というプロパティは存在しないのですが、インデックスシグネチャによって任意の`string`型のプロパティキーをもつことが認められているため、存在しないプロパティへのアクセスを型エラーで検知できなくなってしまっています。

インデックスシグネチャには以上のような型安全性を損なう面もあるため、使用に際しては注意が必要です。

インデックスシグネチャが必要になった際には、より安全な方法として`Map`の使用を検討してみてもいいかもしれません。
python勉強記録①

pythonの勉強中で、作りたいものが無いためとりあえず
CPU使用率、memory使用率を取得しDBへ保存するプログラムを作成してみました。

**目的**
- DBの学習
- sqlalchemyの使い方


```text
Package                   Version
------------------------- -----------
altair                    5.3.0
pip                       24.0
psutil                    6.0.0
pytz                      2024.1
SQLAlchemy                2.0.31
streamlit                 1.36.0
```


```python:moniter.py
# pip install psutil
# pip install sqlalchemy
# pip install pytz

import psutil
import datetime
import pytz
import time
import os   
from sqlalchemy import create_engine, Column, Integer, Float, DateTime
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker


Base = declarative_base()

class Moniter(Base):
    __tablename__ = 'moniter'
    id = Column(Integer, primary_key=True, autoincrement=True)
    # timestamp = Column(DateTime, default=datetime.datetime.now(pytz.timezone('Asia/Tokyo')))
    timestamp = Column(DateTime, default=lambda: datetime.datetime.now(pytz.timezone('Asia/Tokyo')).replace(microsecond=0))
    usage_percent = Column(Float)
    memory_usage = Column(Float)

    def __repr__(self):
        return f"Moniter(id={self.id}, timestamp={self.timestamp}, usage_percent={self.usage_percent}, memory_usage={self.memory_usage})"


# データベースファイルのパス
db_path = 'sqlite:///moniter.db'


# データベースファイルが存在しない場合のみ新しいデータベースを作成
if not os.path.exists('moniter.db'):
    # log無効
    engine = create_engine(db_path, echo=False)
    Base.metadata.create_all(engine)
else:
    engine = create_engine(db_path, echo=False)

Session = sessionmaker(bind=engine)
session = Session()

try:
    while True:
        cpu_usage = psutil.cpu_percent(interval=1)
        memory_usage = psutil.virtual_memory().percent
        print(f"CPU Usage: {cpu_usage}%")
        print(f"Memory Usage: {memory_usage}%")
        print("-----------------")
        session.add(Moniter(usage_percent=cpu_usage, memory_usage=memory_usage))
        session.commit()
        time.sleep(60)
except KeyboardInterrupt:
    print("プログラムを終了します。")
finally:
    session.close()

```
なぜ拡張子は3文字が多いのか？　3文字が招く問題について。

`.txt`, `.exe`, `.jpg`, `.bat`, `.png`, `gif`, `.mp4`, `.pdf`, `php`, `csv`...

**世の中の拡張子は3文字に溢れています。**

拡張子とは、ファイル名の最後につけられる文字列で、そのファイルの形式を示しているものです。

しかし、3文字の拡張子が非常に多いです。

# 3文字で起こる問題がある

**文字数によって発生する問題ってどういうこっちゃ**と思われるかもしれませんが、
素敵なエンジニアライフを送られている皆様方なら一度は目にするでしょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1927831/ae024cc6-bb63-2989-987b-4f585cb72604.png)

**.htm**拡張子。

いや、これはただのhtmlファイルなんですが、**私としてはなんだかムズムズします。**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1927831/0787e95e-c961-8722-80f5-e31ca4a2789f.png)

**だって私の見知ったhtmlファイルはこっちです。**

そう、拡張子に**表記ゆれ**が発生するのです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1927831/d077cf68-868e-8472-c2bb-0c4a87ef64dc.png)

yamlファイルの拡張子に関しては業界全体で表記ゆれが発生しているように思います。
どちらもyamlファイルではあるのですが。

表記ゆれ自体が大きな問題を引き起こすわけではないのですが
* 命名に迷う
* 混乱が起こる

などのトラブルの原因になりかねないと思います。
実際、それを問題として解決するためのissueが投げられているのをたまに目にします。

https://github.com/VOICEVOX/voicevox_engine/issues/753

ちなみに、`.doc`と`.docx`はどちらもMicrosoft Wordのファイルですが、
実は仕様が異なっています。罠すぎる。


# どうしてこんなことになってしまったのか

**昔のMicrosoftのせい。**

むかしむかし、あるところにMS-DOSがありました。

MS-DOSというのは、1981年発売の古のOSです。
古のOSだからこそ、技術面に多くの制約があったため、今では理解できないような変な？仕様がたくさんあったようです。

:::note info
ちなみに、MS-DOS 4.0 は現在OSSになったらしいです。
よかったらビルドして遊んでみよう（？）
https://qiita.com/reika727/items/32a74226aea427044b41
:::

そのMS-DOSの変な仕様の中には、以下の制限がありました。

「**ファイル名は“8文字の名前＋3文字の拡張子”にする必要がある**」

この制限は`8.3形式`とよばれ、Windows3.x、部分的にはWindows 95以降も続くことになるファイル名の仕組みでした。

当然今では長いファイル名も可能になり、`8.3形式`は考慮する必要がなくなりました。
しかし現在の3文字拡張子は、この慣習が続いたものだと考えられます。

# （脱線）今日から~~使える~~使えない豆知識

さて、わざわざこんな記事を見に来てくださったみなさんへ、
お礼といってはなんですが、今日から使えない豆知識を授けましょう。

この8.3形式、ファイル名に空白を入れることを許さないものでした。
そう、今のwindowsに存在する`Program File`は8.3形式において正しくないファイル名なのです。

そのためか、実は`Program File`は`PROGRA~1`という**8.3形式のファイル名でも表示されるようになっています**。

batファイルなどで`start`コマンドを利用する場合、空白文字を含むような長いファイル名では正しく動作しません。空白がコマンドを区切る仕組みになっているからです。

```powershell
$ start C:\Program Files\Google\Chrome\Application\chrome.exe
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1927831/69eaa421-c168-556f-0f2d-5891f45409fd.png)

`""`で囲めばいいじゃんと思ったあなたは~~少し黙っていてください。~~
実は、```C:\PROGRA~1```にすると**正しく動作**します。

```powershell
$ start C:\PROGRA~1\Google\Chrome\Application\chrome.exe
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1927831/90183aa8-ab65-5b88-2ab5-acb0f8b8e863.png)

**初めて知った人は是非この記事にいいねを付けてください。（傲慢）**

:::note info
ただし、この短いファイル名は**環境依存**です。
もしかしたら`PROGRA~1`でアクセスできない環境が存在するかもしれない...
:::

# 結論

~~**やっぱ全部昔のMicrosoftが悪い。**~~
【3minで出来る】誰でもわかるpyenvで簡単にpythonを起動　　- 実践編 -

## はじめに
前回の知識編の記事で仮想環境構築理由はなんとなくでも理解はしてもらえましたか？
本記事では環境の構築方法をインストール部分から一緒にやってみましょう！（今回はpyenv編）
今回は私のPCがMacなのでmacOSの手順を説明します！

## pyenvのインストール
まずmacOSの場合はパッケージマネージャーとしてHomebrewを入れていない方は、インストールするところから始めましょう。
```bash:bash
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)
```
## pyenvのインストール
pyenvを先ほどインストールしたHomebrewを用いて、pyenvをインストールしましょう。
```bash:bash
# Homebrewのパッケージリストを最新に更新
brew update

# pyenvのインストール
brew install pyenv
```

## シェルの設定ファイルにpyenvの初期化コマンドを追加
シェル（ターミナル）の設定ファイルにpyenvを有効にするためのコマンドを追加します。
シェルでpyenvコマンドが利用できるようにするための手順です。
この設定をすることで、シェルが開いた時にpyenvが自動的に初期化され、pyenvのコマンドや設定がすぐに使える状態になります。
macOSのデフォルトシェルがbashであれば、以下の手順で実施します。

**1. ~/.bash_profileを開く**
```bash:bash
nano ~/.bash_profile
```
**2. ~/.bash_profileに環境変数を追加**
```bash:bash
# .bash_profileにpyenvの初期化コマンドを追加
#　pyenvのインストールディレクトリを環境変数に設定
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bash_profile

# pyenvのコマンドがシステムのパスに追加
echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bash_profile

# pyenvの初期化スクリプトをじっこう
echo 'eval "$(pyenv init --path)"' >> ~/.bash_profile
```
**3. 設定ファイルをリロードして変更を反映**
忘れがちでうまくいかないー！となること多いのでお気をつけて！
```bash:bash
source ~/.bash_profile
```

## pythonのインストールと設定
では次は実際にpythonをインストールしましょう！
ここでは、python3.10.0をインストールし、それをデフォルトのバージョンとして設定する方法を記載します。
デフォルト設定をしたくない場合は、skipしてください。
```bash:bash
# Python 3.10.0のインストール
pyenv install 3.10.0
# デフォルトのPythonバージョンを3.10.0に設定したい場合
pyenv global 3.10.0
```

## インストールの確認
一応以下でインストールが成功している確認をしてみましょう。
```bash:bash
# Pythonのバージョンを確認
python --version
```
成功していれば、**Python 3.10.0**と表示されます。


**ここまでで、pyenvで環境構築は完了しました。もし別のバージョンも使いたいな〜という方は、同様の方法で別のpythonバージョンも入れてみてください！**

## VScodeでの利用
1. Visual Studio Codeをインストール：まだインストールしていない場合は、公式サイトからダウンロードしてインストールしてください
2. Python拡張機能のインストール：
    - VSCodeを開いて、拡張機能（Extensions）のアイコンをクリックします。
    - 「Python」を検索してインストールします。
3. pyenvのPythonを選択：
    - VSCodeでコマンドパレットを開きます（Ctrl+Shift+PまたはCmd+Shift+P）。
    - 「Python: Select Interpreter」と入力して選択します。
    - pyenvが管理しているPython 3.10を選びます。通常、~/.pyenv/versions/3.10.0/bin/pythonのようなパスが表示されます。

これで、VSCodeでPythonのスクリプトを実行するときに、pyenvが管理するPython 3.10が使用可能になります。
秋月電子のジャンク赤外線受光モジュール(SLR-932AV-A)の試食

2024/6に秋月電子秋葉原店2Fにて、ジャンク品のリモコン受信モジュールを購入しました。型名が書いてあるため、ネットですぐデータシートが手に入るだろうと高をくくっていましたが意外と見つからず、試行錯誤して使ってみた結果の紹介となります。

# SLR-932AV-Aの外観
秋月店頭では10個入100円という破格で売られていました。20～30年ほど前の蛍光灯シーリングライトに入っていそうなレトロな見た目をしています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/602898/4fe118b2-0623-218c-9ae2-d4e460947d12.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/602898/b3f16f51-441b-c563-6486-6cd3ab3676e0.png)

殻割りをすると、これまたレトロな基板が出てきます。裏面にはドライバICが見えますが、型番は見えず詳細不明でした。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/602898/8cd04347-faad-7e91-1a5f-7989c6af3879.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/602898/f545b7d9-6003-6be7-5385-f312fbc87ec5.png)

# ピンアサイン
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/602898/95221201-16e3-8ab2-41c3-aa34e3d6cb6e.png)
画像のように見て一番右側を1番としたとき、以下の通りとなっておりました。

| ピン番号 | 機能 |
|:-:|:-:|
| 1 | Vcc (+5V) |
| 2 | DATA |
| 3 | GND |

一般的な赤外線受光モジュールと同一の配置です。
出力論理も一般的なモジュールと同様に負論理（データ受信時にL）です。

電源電圧は、4.7-5.3Vの範囲で安定して動作しました。
最近は3.3Vで動作するMCUも多く、3.3Vで動作してくれるとありがたいのですが、残念ながら安定動作はしてくれませんでした。電源電圧が3.29Vまで下がると動作しなくなるため、3.3Vではギリギリ動作したりしなかったりとなります。

# 使用例
Wemos D1 miniというESP8266搭載のMCUボードで使用してみました。今回はArduino向けのIRremoteライブラリを利用しています（https://github.com/Arduino-IRremote/Arduino-IRremote ）。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/602898/d4548709-2467-15a8-074e-411409f9c08c.png)
ESP8266では、通常5V系の信号であるDATAをIOに直結できませんが、実験時はCVCCより3.4Vというモジュールが動作するギリギリの電圧を供給することで直結を可能にしています。きちんと製作する場合は抵抗分圧回路等によりレベル変換をした方が良いと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/602898/8de81770-c3fe-caf9-9f29-305ee0ea117a.png)

サンプルプログラムを動かしたところ、赤外線リモコンから送信されたデータがきちんと表示されました。

# まとめ
1個10円と非常に安価ですが、使用電圧が5V限定という点を割り引いても有用なモジュールだと思います。
2024/6/28の段階では秋月店頭にまだ大量に在庫がありましたので、赤外線で何か作ろうと思っている方はぜひ購入をおすすめします。
MongoDBで検索結果処理中にカーソルがタイムアウトした

## エラー内容
MongDBで、検索した結果(約4万件)をforループ内でひとつづつ処理していく最中に、以下のようなエラーが発生しました。

```bash
Exception has occurred: CursorNotFound
cursor id 1180948255076503304 not found, full error: ....
```
また、実行していたPythonのコードは、次のようなものです。MongoDBのドライバはpymongoを使用しています。

```Python
with MongoClient(driver_URL) as client:
    webcamDb = client.webcam
    collection = webcamDb.webcam

    # search all information
    for webCamInfo in collection.find():
        #何らか処理
```

## 対応内容
調べたところ、上記エラーは、既に閉じられたか、タイムアウトしたカーソルを使用しようとした時に発生するエラーとのこと。対策としては、
1. データを一度に少量ずつ処理する（バッチ処理）
2. サーバー側でカーソルのタイムアウト時間を延長する
3. エラーハンドリングとリトライのロジックを実装する

等、いくつかありましたが、2のタイムアウト時間の調整は、適切な値がよくわからないこと、3のリトライはエラーの発生が前提のため気が進まなかったため、バッチ処理で1000件づつ処理するようにしました。

```python
with MongoClient(driver_URL) as client:
    webcamDb = client.webcam
    collection = webcamDb.webcam
    
    last_id = None
    query = {}
    batch_size = 1000
    while True:
        if last_id:
            query['_id'] = {'$gt': last_id}        
        
        webCamlist = list(webCamCol.find(query).sort('_id', ASCENDING).limit(batch_size))
        if not webCamlist:
            break
        
        process_batch(webCamlist) #何らかの処理
        last_id = webCamlist[-1]['_id']
```