OmniAICreator/Qiita-1.07M huggingface dataset:
Reactで初歩的なinput/outputをしてみて気づいたこと

# 概要

掲題の通り、React学習の初めの一歩として「学習記録のログアプリ」を実装してみての感想について記します

# やったこと

* モダンなJavaScriptの記法・Reactの文法について最低限の内容をUdemyで学ぶ
    * [じゃけぇさんの講座](https://www.udemy.com/course/modern_javascipt_react_beginner/?couponCode=BASIC20241201)で学習させていただきました
* 学習成果を生かして、勉強事項と勉強にかかった時間を記録 & 累積学習時間を確認できる簡潔なアプリを作ってみる

## 成果物

ご覧の通り、入力欄を1項目1行にするための最低限の装飾を除き、ほぼCSSを書いていない、React・JavaScriptの記述にフォーカスした、ごく素朴なWebアプリです。

![課題1の成果物.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3625609/cbeb1c5a-add1-49a3-dd26-ff00a77348c0.png)


学習事項を記録するDBの類もないので、ブラウザをリロードするとリセットされます

# 感想

## 座学について

Reactそのものというよりは、ECMAScript5以降のモダンな記法についてのレクチャーが印象に残りました。

私がReactに敷居の高さを感じていた理由の一つに、なんでこんな書き方になるのか・この書き方は文法的にどう説明がつけられるのかよくわからない・・・ということがありました

例えば以下のようなコードです

```
const name = 'taro';
const age = 30;

const myProfile = { name, age };
const { name2, age2 } = myProfile;

const DisplayPersonInfo = ({ name, age }) => {
  console.log(`${name}は${age}歳です`);
};

DisplayPersonInfo(myProfile);
```

昔上記のようなReactのコードを読んで以下のようなことを感じた記憶があります

* なんでオブジェクトを表すはずの中括弧({})が、キーバリューじゃない形式で、配列みたいな記法で変数代入の右辺にいるのか
    * 変数代入だけでなく、関数の引数にいたりもする。どういう意味これ？
* 中括弧({})とか角括弧（[])が変数代入の左辺にいる式見たことない、きもい・・・

Udemyの動画では混乱を招く可能性のある記法・React中でよく使われる記法について焦点を絞って紹介されています。いずれについても、座学を通じてしっかり説明がつくようになったので、非常にスッキリしました

Reactをいち早く学びたい気持ちを抑えて、「Reactでよく使われるJavaScriptの記法」を学んでおくことで、上記のようなことに対する引っ掛かりを抑えられるように備えておくことは非常に大切なことと思います（Udemy講師のじゃけぇさんも同趣旨のことをおっしゃっていました）

## 実際に書いてみて

### 書く上でもやはりJavaScriptの基礎知識は大事

モダンな記法については、コードを読む・学習する際のストレスを下げるだけではなく、実装効率を上げることも身にしみて感じました

以下のようなことを講座中では教わったのですが「学んだことだから、せっかくだから使おう」と強く意識するまでもなく、自然と全部使う機会がありました

* テンプレート文字列
* アロー関数
* 分割代入
* オブジェクトの省略記法
* スプレッド構文
* 配列に対するmap()やfilter()の利用

作ったアプリは冒頭で画像を引用した通りかなりちゃちいアプリですが、そのちゃちぃアプリだけでも上記のような文法はすべて使う余地があるということです（もっとも、作ったアプリは [JISOU](https://projisou.jp/) が用意したお題に基づくものなので、座学編の良い応用となるよう多少意識・工夫してくれたお題なのかもしれません）

これらの文法を使うか使わないかではそれなりにコードの文量・シンプルさが違ってきます。本格的なWebアプリを作る場合であれば尚更でしょう。ので、知識を身につけるだけでなく、早くいいコードを書く上でもやはり「Reactでよく使われるJavaScriptの記法」の知識は初期の時点であった方が良いのだろうと思います

# おわりに

「座学について」のセクションで紹介したコードや、「書く上でもやはりJavaScriptの基礎知識は大事」のセクションで列記した文法事項についてわからない・理解に自信がない方については、焦らずにぜひその点の理解をして地固めしてから、Reactを学び始めることをおすすめします

今は結構React周りの教材は充実してきている感があるので、最適解は一つではないかもしれませんが、少なくとも [じゃけぇさんの講座](https://www.udemy.com/course/modern_javascipt_react_beginner/?couponCode=BASIC20241201) はばっちりな内容でした

また、そういう良い教材を選定してくれており、かつ間髪入れず実践させる良いコンテンツ・文化がある [JISOU](https://projisou.jp/) もぜひご検討ください・・・という宣伝でもって今回の雑記は締めたいと思います

# JISOUのメンバー募集中！

プログラミングコーチングJISOUでは、新たなメンバーを募集しています。
日本一のアウトプットコミュニティでキャリアアップしませんか？
興味のある方は、ぜひホームページをのぞいてみてくださ！
▼▼▼

https://projisou.jp
JavaScript プロトタイプチェーンの位置関係図

## はじめに

プロトタイプチェーンの位置関係を調べて位置関係図を作りました。

## プロトタイプチェーンの位置関係図

プロトタイプチェーンの位置関係を調べて作った図がこちらです。

![プロトタイプチェーンの位置関係1](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/311399/9842ce14-9085-7237-e63e-dc8593e15f2c.png)


黒い実線の上向きの矢印がプロトタイプチェーンの方向です。`Object.getPrototypeOf(X)` もしくは `X.__proto__` の先が示す方向です。

中央下の`String` と `function() {}` と `Number` は関数です。

図を作って思ったのですが、 `typeof Function.prototype` が `object` にならないのは仕様ミスではないでしょうか。

## newとconstructorを加えた図

さらに `new` 演算子と `constructor` プロパティを調べて作った位置関係図がこちらです。

![プロトタイプチェーンの位置関係2](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/311399/bb8bc48a-876f-16a1-40f3-50711da8708f.png)


`T.prototype.constructor` は `T` です。

`T.prototype.constructor.constructor` は `Function`　です。

`Object.getPrototypeOf(Function)` は `Function.prototype`　です。

この図を見ながら MDN の [オブジェクトのプロトタイプ](https://developer.mozilla.org/ja/docs/Learn_web_development/Extensions/Advanced_JavaScript_objects/Object_prototypes) にある `Object.create` や `Object.assign` でオブジェクトのプロトタイプを設定する例を読むと、効果的に学習できると思います。

## さいごに

プロトタイプチェーンの位置関係図を示しました。

JavaScript では関数やプロパティをプロトタイプチェーンを辿って探します。 `"abc".func()` において、関数 `func` が `"abc"` 上に存在しなくても、プロトタイプチェーン上に `func` が存在すれば、その関数が実行されます。

なので、プロトタイプチェーンの位置関係がどうなっているかは、JavaScript を理解する上で重要な知識です。

しかし、プロトタイプチェーン上に関数やプロパティを設定することは **プロトタイプ汚染** と呼ばれ、推奨されておりません。初級者がこの知識を使う機会はほとんどないと思います。ですが知っておいても損はないと思います。

この位置関係図で JavaScript の理解が深まれば幸いです。
インターフェース Java

はじめに
--
インフラの分野でも、Iac化が進んで行くと考えています。そこで、ノウハウが体系だっているものが学び易いと考えて、Javaを学びはじめました。

今回は、**インターフェース** にフォーカスしました。
ラムダ式を使って `Algorithm` インターフェースを実装し、`Service` クラスに設定して処理を実行するケースで、インターフェースの使い方を整理してみました。

` perform`  メソッドを定義。

```java
interface Algorithm {
    void perform(String name); // メソッド定義
}
```

`setLogic` メソッドでロジックを設定し、`doProcess` メソッドで処理を実行。

```java
class Service {
    private Algorithm logic; // Algorithm型のインスタンスを保持

    // setLogicメソッドでロジックを設定
    public void setLogic(Algorithm logic) {
        this.logic = logic;
    }

    // doProcessメソッドで処理を実行
    public void doProcess(String name) {
        System.out.println("start");  // 処理の開始を表示
        this.logic.perform(name);     // ロジックの実行
        System.out.println("end");    // 処理の終了を表示
    }
}
```

`Main` クラスで、ラムダ式を使って `Algorithm` インターフェースを実装。このラムダ式は、`name` を受け取って `"hello, "` と結合して表示。その後、`Service` クラスのインスタンスを作成し、ロジックを設定して処理を実行。

```java
public class Main {
    public static void main(String[] args) {
        // Lambda式を使ってAlgorithmインターフェースを実装
        Algorithm algorithm = (name) -> {
            System.out.println("hello, " + name);  
        };

        // Serviceインスタンスを作成
        Service s = new Service();
        s.setLogic(algorithm); // ロジックをセット
        s.doProcess("Lambda"); // "Lambda"という名前を渡して処理実行
    }
}
```

### 実行結果

```
start
hello, Lambda
end
```

## 複数の異なるアルゴリズムを設定したい場合

 `Algorithm` インターフェースを使って異なるロジックを定義し、切り替えることができる。

```java
public class Main {
    public static void main(String[] args) {
        // 1つ目のロジック
        Algorithm algorithm1 = (name) -> {
            System.out.println("hello, " + name);
        };

        // 2つ目のロジック
        Algorithm algorithm2 = (name) -> {
            System.out.println("goodbye, " + name);
        };

        // Serviceインスタンスを作成
        Service s = new Service();

        // 最初のロジックを設定して実行
        s.setLogic(algorithm1);
        s.doProcess("Lambda");

        // 2番目のロジックを設定して実行
        s.setLogic(algorithm2);
        s.doProcess("Lambda");
    }
}
```

### 実行結果

```
start
hello, Lambda
end
start
goodbye, Lambda
end
```

`Service` クラスに設定する `Algorithm` を切り替えることで、処理を柔軟に変更することができますね。
lambdaのメモリに対する割当コア数の対応表

# 結論

|メモリ|CPU|
|-|-|
|128|2|
|256|2|
|512|2|
|1024|2|
|2048|2|
|3072|3|
|4096|3|
|5120|3|
|6144|4|
|7168|5|
|8192|5|
|9216|6|
|10240|6|

# 調査方法

## 条件
調査日：2024年1月3日
アーキテクチャ：x86_64
ランタイム：Python 3.13
コード
```python
import multiprocessing

def lambda_handler(event, context):

    # TODO implement
    return {
        'statusCode': 200,
        'body': multiprocessing.cpu_count()
    }

```
Arduino -RaspberryPI picoのテンプレート-

# はじめに
これは自分用の記録です。

~~Boardは　 "Arduino Mbed OS by RP2040 Board by arduino"~~ INPUT_PULLUP動作せず。
Boardは　"Raspberry Pi Pico/RP2040/RP2350 by Earle F. Philhower, III "を使用
環境のURLsに、以下を追加
https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json
マニュアルは、
https://arduino-pico.readthedocs.io/en/latest/rp2040.html

# 事前準備
## USB-COMボード
https://circuitpython.org/board/raspberry_pi_pico/ からUF2ファイルをダウンロード
Bootを押しながらPCに接続　
RP2050 のドライブにUF2ファイルをドラッグ＆ドロップ

## 書込みが出来なくなった場合
Bootモードで書き込み

# template1(WDT)
```
//#include "mbed.h"

#define SW1 2
#define SW2 3
#define SW3 4
#define SW4 5
#define LED1 6
#define LED2 7
#define LED3 8
#define LED4 9
#define DO1 10
#define DO2 11
#define DO3 12
#define DO4 13

volatile bool MODE1 = false;
volatile bool MODE2 = false;
volatile bool MODE3 = false;
volatile bool MODE4 = false;


//mbed::Watchdog &wdt = mbed::Watchdog::get_instance();

void isr1(void) {
  Serial.println("push1");
  MODE1 = !MODE1;
  digitalWrite(LED1, MODE1);
}
void isr2(void) {
  Serial.println("push2");
  MODE2 = !MODE2;
  digitalWrite(LED2, MODE2);
}
void isr3(void) {
  Serial.println("push3");
  MODE3 = !MODE3;
  digitalWrite(LED3, MODE3);
}
void isr4(void) {
  Serial.println("push4");
  MODE4 = !MODE4;
  digitalWrite(LED4, MODE4);
}

void setup() {
  Serial.begin(9600);
  pinMode(SW1, INPUT_PULLUP);
  pinMode(SW2, INPUT_PULLUP);
  pinMode(SW3, INPUT_PULLUP);
  pinMode(SW4, INPUT_PULLUP);
  pinMode(LED1, OUTPUT);
  pinMode(LED2, OUTPUT);
  pinMode(LED3, OUTPUT);
  pinMode(LED4, OUTPUT);
  pinMode(DO1, OUTPUT);
  pinMode(DO2, OUTPUT);
  pinMode(DO3, OUTPUT);
  pinMode(DO4, OUTPUT);

  attachInterrupt(digitalPinToInterrupt(SW1), isr1, FALLING);
  attachInterrupt(digitalPinToInterrupt(SW2), isr2, FALLING);
  attachInterrupt(digitalPinToInterrupt(SW3), isr3, FALLING);
  attachInterrupt(digitalPinToInterrupt(SW4), isr4, FALLING);
  interrupts();
  //wdt.start(1000);
  rp2040.wdt_begin(1000);
}

void loop() {
  //wdt.kick();
  rp2040.wdt_reset();
  
  digitalWrite(DO1, MODE1);
  digitalWrite(DO2, MODE2);
  digitalWrite(DO3, MODE3);
  digitalWrite(DO4, MODE4);

  Serial.print(millis());

  Serial.print(" Mode1=");
  Serial.print(MODE1);
  Serial.print(" Mode2=");
  Serial.print(MODE2);
  Serial.print(" Mode3=");
  Serial.print(MODE3);
  Serial.print(" Mode4=");
  Serial.println(MODE4);
  delay(500);
}
```
raise_errorマッチャー

#### `raise_error`マッチャー
># raise_error matcher

エラーを起こすコードのブロックを明示するために`raise_error`マッチャーを使う。最も基本形はどんなエラーが投げられても通ります
>Use the raise_error matcher to specify that a block of code raises an error. The most basic form passes if any error is thrown:
```rb
  expect { raise StandardError }.to raise_error
```
その言葉づかいの方を好むならば代わりとして`raise_exception`を使える
>You can use raise_exception instead if you prefer that wording:
```rb
  expect { 3 / 0 }.to raise_exception
```
`raise_error`と`raise_exception`は機能的に互換性があるのでどのようなコンテキストでも最も意味のある方を使う
>raise_error and raise_exception are functionally interchangeable, so use the one that makes the most sense to you in any given context.

上記の基本形に加えて、エラー・例外の詳細を明示するための方法のいくつかある
>In addition to the basic form, above, there are a number of ways to specify details of an error/exception:
```rb
  expect { raise "oops" }.to raise_error
  expect { raise "oops" }.to raise_error(RuntimeError)
  expect { raise "oops" }.to raise_error("oops")
  expect { raise "oops" }.to raise_error(/op/)
  expect { raise "oops" }.to raise_error(RuntimeError, "oops")
  expect { raise "oops" }.to raise_error(RuntimeError, /op/)
  expect { raise "oops" }.to raise_error(an_instance_of(RuntimeError).and having_attributes(message: "oops"))
```
#### どんなエラーも期待する
>### Expecting any error
```rb
RSpec.describe "calling a missing method" do
  it "raises" do
    expect { Object.new.foo }.to raise_error # 定義されていないメソッドを使用によってエラーが起こると考える
  end
end
```
```
Run options: include {:full_description=>/calling\ a\ missing\ method/}
WARNING: Using the `raise_error` matcher without providing a specific error or message risks false positives, since `raise_error` will match when Ruby raises a `NoMethodError`, `NameError` or `ArgumentError`, potentially allowing the expectation to pass without even executing the method you are intending to call. Actual error raised was #<NoMethodError: undefined method `foo' for #<Object:0x000000010d928818>>. Instead consider providing a specific error class or message. This message can be suppressed by setting: `RSpec::Expectations.configuration.on_potential_false_positives = :nothing`. Called from /Users/hyoudoumasatomo/Repos/garden/spec/models/user_spec.rb:17:in `block (2 levels) in <top (required)>'.
1 example, 0 failures, 1 passed
```

https://rspec.info/features/3-13/rspec-expectations/built-in-matchers/raise-error/
numpyでのカラー画像合成


# 前提

```Python
>>> imR.dtype
dtype('bool')

>>> im0.dtype
dtype('uint16')
```

imRは1bit画像、im0は16bit画像。
im0を適切にモノクロ画像として、imRを赤色で塗る。

# 実例

```Python
from skimage.io import imsave
import numpy as np

byW = np.where(im0>1024,255,im0/4).astype('uint8')
byR = 255*imR.astype('uint8')

by = np.zeros((byW.shape[0],byW.shape[1],3),'uint8')
by[:,:,0] = np.where(byR==255,255,byW)
by[:,:,1] = np.where(byR==255,0,byW)
by[:,:,2] = np.where(byR==255,0,byW)

```
np.whereで直接`numpy`配列を操る。
作ったゲームのキャラと喋りたい

# 背景

以下で作ったゲームキャラをAIアバター化して会話してみる試み  
今や何番煎じかわかりませんが、やっぱりゲームや漫画のキャラと会話したいよね

https://qiita.com/megumu-u/items/2df41c7b10986e4324e0


# 作る

## 構成

こんな感じです。
ローカルにFastAPIで作った簡易APIサーバーと、Dify（Docker）を立てます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201603/a62553ca-b3f4-e89c-f2bc-9880015fd04c.png)


## 実装

### Realtime API

公式ドキュメントのほぼコピペで動きます。

https://platform.openai.com/docs/guides/realtime-webrtc

本当はinputが音声でoutputがテキストにしたかったのですが、現在はできないのかも？（実装間違ってただけかもしれませんが）
`/session`で`modalities: [ "text" ]`を指定しても話しかけたら音声が返ってきました。

ということで、とりあえずoutputはテキストだけにしたかったので公式サンプルのこの部分を実装しないようにします。
（outputの音声は作られていると思うので無駄なトークンを消費してますが・・・）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201603/2fd2b92d-fd07-ddc2-90ef-94faa3202342.png)



### 音声合成

にじボイスのAPIを呼び出します。
2024年の年末に試した感じだと同時に1件しか音声を作れないようなので（音声を生成中にもう1件投げたらエラーになった）、1件ずつAPIを投げるようにキューイングしながら処理してあげます。

待ち時間軽減のため、ChatGPTの応答内容全文を一気に音声合成するのではなく、ストリーミング的に文節単位で音声合成をした方が良いのですが今回はその部分は未実装です。


### ナレッジ検索

Difyを使った簡易実装です。
「ナレッジを作成」からお手製の原作シナリオと設定を書いたテキストを登録してナレッジを作ります。
使えるRerankのモデルを持ってないので単純なハイブリット検索です。
何も考えずにとりあえずデータ突っ込んだだけなの、正直このままだとプロダクションで使える精度ではなさそうという感想です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201603/4b51242c-5118-75f1-4b31-7ef2727076b6.png)

Difyで作ったナレッジはAPI公開できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201603/4147af06-61f2-dded-96f4-4c611faf07ee.png)


### 表情やモーション

これは以下で開発したものをそのまま利用。

https://qiita.com/megumu-u/items/2df41c7b10986e4324e0


### Toolsの設定

Toolsの設定はsession作成時のパラメータで与えることができます。

https://platform.openai.com/docs/guides/realtime-model-capabilities#function-calling

Toolの呼び出しは`response.function_call_arguments.done`で処理します。

````typescript
  switch (message.type) {
    case "response.function_call_arguments.done":
      if (message.name === "retrieve_knowledge") { // Toolの種類を判定
        const obj = JSON.parse(message.arguments); // Toolの引数を取得
        const result = await fetchKnowledgeContent(obj.query); // ナレッジ取得のAPI呼び出し
        dc.send( // 結果を返す
          JSON.stringify({
            type: "conversation.item.create",
            item: {
              type: "function_call_output",
              call_id: message.call_id,
              output: JSON.stringify(result),
            },
          })
        );
        dc.send(JSON.stringify({ type: "response.create" })); // 処理完了
````

# 結果

## 表情とモーションのサンプル

https://x.com/megyo9/status/1875085045385568355

## RAGのサンプル

https://x.com/megyo9/status/1875005245543321971


# 気づいたことなど

（2024年1月初旬）

* 弱小OpenAIユーザーなのでRealtime APIのRate limitにすぐに引っかかりました。テストで動かす程度であれば金額自体はたいした額にはならないです。
* OpenAIの音声は日本語がちょいちょい間違っていて、スクリプトとは違うことをけっこう喋る。にじボイスの方が日本語は良かった。
* にじボイスのクレジットはどんどん消費しちゃいます。
* Tool呼び出し中の待ち時間、なんか喋っていて欲しいのだけど無口なことが多い（たまに喋ってくれるけど）。`conversation.item.create`で「実行中」とか送ってみたけど効果あるのか不明だった。
* OpenAIとAOAIとでRealtime APIのイベントオブジェクトの構造が微妙に違う。

Gemini nanoのようなプラットフォーム同梱のSLMで動かせるようになるともっとワクワクしそう。
Cloud Flareで取得したドメインをXServer上のWordPressで使用 & SSL化する

## 目的
- CloudFlareで取得したドメインをXServerで使用する
- 登録したドメインをWordPressで使用 & SSL化する

WPのサイトと管理画面が無限リダイレクトしてハマったので、手順を残す。

## 手順概要
CloudFlareにXServerのCNAMEとネームサーバーを登録し、WordPressのURLを`https://example.com`に変更する。

## ①CloudFlareコントロールパネル
### 1. DNS設定
下記レコードを追加する。

※XServerホスト名（sv?????.xserver.jp）は[サーバーパネル](https://secure.xserver.ne.jp/xapanel/login/xserver/server/)
トップに記載されている。
※XServerのネームサーバーは、[公式マニュアル](https://www.xserver.ne.jp/manual/man_domain_namesever_setting.php
)を参照。


| CNAME | example.com | sv?????.xserver.jp | Proxied |
|:-:|:-:|:-:|:-:|
| CNAME | `www.example.com` | `example.com` | Proxied |
| NS | `example.com` | ns1.xserver.jp | DNS only |
| NS | `example.com` | ns2.xserver.jp | DNS only |
| NS | `example.com` | ns3.xserver.jp | DNS only |
| NS | `example.com` | ns4.xserver.jp | DNS only |
| NS | `example.com` | ns5.xserver.jp | DNS only |

### 2. SSL設定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540076/a4848a18-9376-889a-242b-948bf5558882.png)

Custom SSl/TTL > Full（Strict）を選ぶ。

## ②XServerコントロールパネル
### CloudFlareで取得したドメインを追加
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540076/0cacea24-8d6b-d749-e2c9-9f81ce702008.png)

無料独自SSL、ブラウザキャッシュ、Xアクセラレータにチェックを入れておく。
すでにドメインを追加している場合は、ドメイン設定からチェックを入れる。

## ③WordPressダッシュボード
### 管理画面とサイトのURLを変更
設定>一般から変更できます。

| WordPress アドレス (URL) | `https://example.com` |
|:-:|:-:|
| サイトアドレス (URL)  | `https://example.com`  |
openai apiをGUIから実行できるWebアプリが素晴らしかった

# 背景
OpenAI APIをChatGPTのように使ってみたかった。
モデルをGUIを使って変更できたら便利だと思っていた。

# 方法

以下のGithubリポジトリに書いてある通り実施するだけ。
[GitHub - elebitzero/openai-react-chat: Chat webapp frontend to OpenAI's API with similar features to ChatGPT. Written in React, TailwindCSS, and Typescript..](https://github.com/elebitzero/openai-react-chat?tab=readme-ov-file)

画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/610591/0f8ce116-8240-e453-8f2e-77fa1cc4d99e.png)

# 感想
- 上記画像の左カラムにあるように新しいチャットというボタンもあり普通のChatGPTっぽい（ちゃんとChatGPTを使ったことはないが）
- 上記画像のように、リクエスト間で会話の内容を覚えているところがすごかった。（ChatGPTでは普通でもOpenAIAPIでは普通ではない。）なぜ、これができるのか聞いてみたら下記のような回答が返ってきた。つまり、アプリ側で工夫して前のメッセージも送ったうえで回答しているらしい。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/610591/b0b685a4-a48f-ffe5-2693-618428bd94da.png)
- ファイルアップロードのボタンもあるから試してみたい
- 普通のChatGPTは確か月額で費用がかかるが、APIだったら使った分だけ費用がかかるのでたまに使用するだけの人にはこちらの方が良い
- Webサーバーを止めて（＝`npm run start`を止めて）から再度起動しても前の会話が保存されているのがすごい。データ保存もしている。。
MMSegmentation学習時のエラー：correct = correct[:, target != ignore_index]

### エラー内容
MMSegmentationを使用していると以下のようなエラーがでることがある。

```sh
  File "/workspace/mmsegmentation/mmseg/models/losses/accuracy.py", line 49, in accuracy
    correct = correct[:, target != ignore_index]
              ~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^
RuntimeError: CUDA error: an illegal memory access was encountered
CUDA kernel errors might be asynchronously reported at some other API call, so the stacktrace below might be incorrect.
For debugging consider passing CUDA_LAUNCH_BLOCKING=1.
Compile with `TORCH_USE_CUDA_DSA` to enable device-side assertions.
```

### 解決法

チュートリアルにも記載があるが、以下のように`SyncBN`を`BN`に、Configファイルを変更する。

```python:変更前
cfg.norm_cfg = dict(type='SyncBN', requires_grad=True)
```

```python:変更後
# Since we use only one GPU, BN is used instead of SyncBN
cfg.norm_cfg = dict(type='BN', requires_grad=True)
```
Minecraftのリソースパックを作る②

「[Minecraftのリソースパックを作る①](https://qiita.com/tester09/items/347285d9ff547733fc80)」の続きです。

[Minecraft wiki](https://ja.minecraft.wiki)のチュートリアルを見れば見るほどゼロからオリジナルのものを作成するのは大変そうなので、まずはバニラのリソースを踏み台に勉強します。

### ベースにするリソースファイルを展開する
① %AppData%/.minecraft/versionsを開く
② 使用バージョンのフォルダから.jarファイルを任意のディレクトリへコピー

私は1.20.2を使用しているので、1.20.2.jarを新規作成したresourceDataフォルダへコピーしました
<img width="200" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703624/91078160-8a89-1509-aac6-3dc273ce725c.png">

③ 1.20.2.jarを展開
<img width="200" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703624/12064b43-b1b2-d95c-312e-e72cd0770efa.png">


④ 展開したデータの中から、assetsフォルダ以外を全部削除
<img width="200" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703624/6cb57d69-dfc2-8619-6828-e4239bb19931.png">

Minecraft wikiではクリーパーのテクスチャを変更する例があるので、そのまま試してみます。

⑤ assets\minecraft\textures\entity\creeperフォルダを開く

<img width="450" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703624/b19d99a8-779d-a09e-f6a5-453ffdfcd523.png">

⑥「[Minecraftのリソースパックを作る①](https://qiita.com/tester09/items/347285d9ff547733fc80)」で作成したリソースパックフォルダ(TestResourcePack)を、下図のフォルダ構成(assets\minecraft\textures\entity\creeper)になるようフォルダを作成してから、⑤のフォルダにあるcreeper.pngを貼り付ける
<img width="450" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703624/5f14c21d-a961-8385-3450-43e6be05ae6c.png">

⑦ creeper.pngファイルを描画ツールで開いて描きかえる
　※どこがどのパーツになるかは、[Minecraft wiki](https://ja.minecraft.wiki)を確認してください

私はチークを塗ってあげました♡
<img width="450" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703624/542492c8-332b-1c2c-5acf-fbcb54eacb49.png">

#### 動作確認
① Minecraftを起動後、[Options...]→[Resource Packs...]をクリックし、作成したリソースパック(TestResourcePack)を選択
<img width="450" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703624/6f5f08c8-39e0-379b-51f2-29aa411619ec.png">

(選択したリソースパックが[Selected]側に)
<img width="450" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703624/44ac47e0-c441-797d-e919-2a9119c25895.png">

② [Done]を選択し、起動

頬紅を塗った、かわいらしいクリーパーが登場しました♡
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703624/c7e9fa6d-f1a9-1610-0681-3c77db4ca21f.png)

#### 感想
子どもとの会話を求めてリソースパックをいじってみましたが
これだけでは会話ははずみませんでした。

私「お母さんの画面のクリーパー、可愛くない？」
子「あー、はいはい」
(以上)

次は何しよう...
rubocopの設定がオーバーライドされて、ルールを設定するのに時間がかかった話

## 読んで欲しい人
- `.rubocop.yml`で、外部（gem、URL、共用のルールなど）ルールを設定しているが、一部のファイルを除外したいので`AllCops:`の`Exclude:`を使用すると、そのルールが上書きされてしまって困っている人
- `inherit_from`って何だよって人
- `inherit_gem`って何だよって人
- `inherit_mode`って何だよって人
- 過去の俺

## 困ったこと、何をしたのか
`.rubocop.yml`に`inherit_gem`メソッドを使用して、gemに設定してあるrubocopのルールを使用していたが、除外したいファイル（自動生成ファイルとか）を`AllCops`の`Exclude`を使用すると、`inherit_gem`で使用していたルールが上書きされてしまった。

```.rubocop.yml
inherit_gem:
  rubocop rule gem: ./.rubocop.yml # こんなgemないす

AllCops:
  Exclude:
    - 'db/hogehoge.rb' # 除外したいファイル
```

### inherit_gemって何だよ

- 現在のプロジェクト以外（外部）のgemからの設定を自分の`.rubocop.yml`に継承させることができるメソッド

```rubocop.yml
inherit_gem:
  my-shared-gem: .rubocop.yml
```

※`my-shared-gem`の`.rubocop.yml`を継承している


### ちなみに`inherit_from`というメソッドもあります

`inherit_from`とは、

他に設定した複数ファイルの設定をここで読み込ませることができます。

使い方としては、プロジェクトのルートディレクトリに下記のようなファイルを設定したとします。

```.rubocop.yml
AllCops:
  Exclude:
    - 'db/schema.rb'
```

プロジェクトのサブディレクトリに下記のようなファイルを作ります

```.rubocop.yml
inherit_from:
  - '../.rubocop.yml'

AllCops:
  Exclude:
    - 'db/migrate/*.rb' # サブディレクトリ内の特定ファイルを除外
```

これで、サブディレクトリの`.rubocop.yml`はルートにある`.rubocop.yml`を継承した状態になります。

注意点としては、`inherit_from`の後に記述する設定については、`inherit_from`で継承した内容をオーバーライドしてしまいます。

## ルールが上書きされた原因

`AllCops:`の`Exclude:`が`inherit_gem`で継承した内容をオーバーライドしてた

## 解決策

`inherit_mode`で設定内容をマージした

```.rubocop.yml
inherit_gem:
  sgcop: rails/rubocop.yml

inherit_mode:
  merge:
    - Exclude

AllCops:
  Exclude:
    - 'db/hogehoge.rb' # 除外したいファイル
```

### inherit_modeって何だよ

> The optional directive inherit_mode specifies which configuration keys that have array values should be merged together instead of overriding the inherited value.

`inherit_mode`は設定を上書きではなく、配列の値を持つ設定キーをマージするために使用されます。

だそうです。

## 感想

- ここは意外と融通が効かないんだなぁと思いました

## 参考
https://docs.rubocop.org/rubocop/configuration.html#merging-arrays-using-inherit_mode
畳み込みとフーリエ変換による積分

**ディリクレ積分**
```math
\int_{-\infty}^{\infty}\frac{\sin{x}}{x}dx=\pi
```

とかを畳み込みとフーリエ変換で考えよう。畳み込みとフーリエ変換はそれぞれ次のように定義する。

**畳み込み**

```math
(f*g)(x)=\int_{-\infty}^{\infty}f(t)\cdot g(t-x)dt
```

**フーリエ変換**

```math
\mathcal{F}[f](x)=\int_{-\infty}^{\infty}f(t)\cdot e^{-ixt}dt
```

**フーリエ逆変換**

```math
\mathcal{F}^{-1}[f](x)=\frac{1}{2\pi}\int_{-\infty}^{\infty}f(t)\cdot e^{ixt}dt
```

このとき、次の関係が成り立つ。

```math
\mathcal{F}[f*g]=\mathcal{F}[f]\cdot\mathcal{F}[g]
```

(証明は[高校数学の美しい物語](https://manabitimes.jp/math)さんにあったので[こちら](https://manabitimes.jp/math/2751)から。ありがとうございますほんとにいつもお世話になってます。)

こいつを両辺フーリエ逆変換してあげると、

```math
f*g=\mathcal{F}^{-1}[\mathcal{F}[f]\cdot\mathcal{F}[g]]
```

すなわち

```math
\int_{-\infty}^{\infty}f(t)\cdot g(t-x)dt=\frac{1}{2\pi}\int_{-\infty}^{\infty}\mathcal{F}[f](t)\cdot\mathcal{F}[g](t)\cdot e^{ixt}dt
```

となる。唐突だがディラックのデルタ関数$\delta(x)$について考えよう。

```math
\begin{align}
    \mathcal{F}[\delta](x)&=\int_{-\infty}^{\infty}\delta(t)\cdot e^{-ixt}dt \\
    &=e^{-ix\cdot0} \\
    &=1
\end{align}
```

なので、$\delta(x)$と$1$はフーリエ変換対とかいうやつになります。よって今回の定義では

```math
\mathcal{F}[1](x)=2\pi\delta(x)
```

ということになります。数学的には微妙な表記かもですが、まあ$1$と$2\pi\delta(x)$が対応するってことです。よって$g(x)=1$とおくと、

```math
\begin{align}
    \int_{-\infty}^{\infty}f(t)\cdot 1dt&=\frac{1}{2\pi}\int_{-\infty}^{\infty}\mathcal{F}[f](t)\cdot2\pi\delta(t)\cdot e^{ixt}dt \\
    &=\int_{-\infty}^{\infty}\mathcal{F}[f](t)e^{ixt}\cdot\delta(t)dt \\
    &=\mathcal{F}[f](0)e^{ix\cdot0} \\
    &=\mathcal{F}[f](0)
\end{align}
```

となります。よって

```math
\int_{-\infty}^{\infty}f(x)dx=\mathcal{F}[f](0)
```

が得られました。つまり$f(x)$のフーリエ変換が分かればこの積分も解けるわけです。$f(x)=\dfrac{\sin{x}}{x}$の場合を考えてみましょう(ディリクレ積分)。次の関数$h(x)$を考えます。

```math
h(x)=
\begin{cases}
    1 \quad&\text{if}\ |x|\le1\\
    0 &\text{otherwise}
\end{cases}
```

このときフーリエ変換を考えます。

```math
\begin{align}
    \int_{-\infty}^{\infty}h(x)dx&=\int_{-1}^{1}1\cdot e^{-ixt}dt \\
    &=\left[-\frac{e^{-ixt}}{ix}\right]_{-1}^{1} \\
    &=\frac{e^{ix}-e^{-ix}}{ix} \\
    &=\frac{2\sin{x}}{x} \\
    &=2\,\text{sinc}\,x
\end{align}
```

最後はオイラーの公式を使いました。よってこれらはフーリエ変換対なので

```math
\mathcal{F}[\text{sinc}](x)=\pi h(x)
```

となります。以上より$\dfrac{\sin{x}}{x}$のフーリエ変換がわかりました。よって

```math
\begin{align}
    \int_{-\infty}^{\infty}\frac{\sin{x}}{x}dx&=\mathcal{F}[\text{sinc}](0) \\
    &=\pi h(0) \\
    &=\pi
\end{align}
```

が得られました。めでたしめでたし。ちなみに同様にフーリエ変換が分かれば

**ガウス積分**
```math
\int_{-\infty}^{\infty}e^{-x^{2}}dx=\sqrt{\pi}
```

も解けるはずです。やってないからわかんないけど。まあというわけでこの記事は以上だ。以降は君たちの手でこの公式を使ってくれ。じゃあな。

P.S. ただの数学好きの一学生が初めて書いた記事なので一部間違ってても許して！
小さな個人開発テーマ一覧

:::note info
個人開発をしていくにあたってテーマを設定していく
TypeScriptを使ったはじめての個人開発の場合、シンプルな構成で始めるのが良く使用すると難易度が跳ね上がる可能性があるので最初はTypeScriptに慣れることを目的とし必要になったら導入する
:::


## プロジェクトのアイデア

- タスク管理ツール
簡単な To-Do リストを作成し、タスクを追加、削除、完了状態を切り替えられるようにする

- カウンターアプリ
ボタンをクリックしてカウントを増減させるシンプルなアプリ

- 簡単なゲーム
数字当てゲーム、クリックゲーム、石取りゲームなど

- 計算機
足し算、引き算、掛け算、割り算ができるシンプルな電卓

- API を使ったアプリ
天気情報やニュースを取得して表示する
2025年は毎日ベッドメイキングだけやればいい。

# 世界を変えたいならベッドメイキングから始めましょう

この言葉は、私がよく視聴しているYouTubeチャンネル「もりおルーティーン」で初めて知りました。

![スクリーンショット (20).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3351724/6c84fe8d-b6a2-db10-6efc-a188cf15992e.png)

このフレーズは、元アメリカ海軍大将ウィリアム・マクレイヴン氏が「世界をより良くするにはどうすればよいか」をテーマにした卒業式のスピーチの一節で、とても有名です。

https://youtu.be/UgSu9Z6O8tw?feature=shared

動画を直接視聴するのが最も理解しやすいですが、簡単に説明すると「朝起きたら、最初に面倒でもベッドメイキングをしなさい」というメッセージです。  
この行動には「朝一番に面倒なタスクを片付けることで、小さな成功体験から一日を始めよう」という意味が込められています。
まずは「今日もきちんとできた」という小さな成功体験から始まり、また1日面倒くさいことをひとつひとつ積み上げていきます。

---

私自身、多くのタスクを同時に進めるのが得意ではありません。  
本を読み続けたり、転職活動、仕事、プライベートなど、多くのことに手を付けた結果、どれも中途半端に終わってしまったことがあります。
そのため自分で決めたタスクに対しても「めんどくせぇ...」と思いながら取り組んでいました。

# Shut the Fuck Up and Write Some Code

そんな中、Twitterである言葉を見つけました。  
**「Shut the fuck up and write some code」**  (訳: 黙ってコードを書け)

強い表現なので嫌悪感を抱く方もいるかもしれませんが、私はとても良いと思っています。
面倒なことが次々と降りかかる日常ですが、結局のところ、やらなければ物事は終わりません。だからやるしかないのです。

このフレーズの面白い点は、「Shut the fuck up and write some code」だけが表示されるWebサイトが存在することです。  
https://stfuawsc.com/

---

私も、この精神を思い出せるように、自分のために簡単なWebサイトを作りました。
**「if you want to change the world, start off by making your bed.」** (訳: 世界を変えたいなら、まずベッドメイキングから始めよう。)
https://making-your-bed.pages.dev/

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3351724/ec451eb2-e808-2512-a74f-72cc54457306.png)

---

毎日、面倒なことの連続ですが2025年は「毎朝ベッドメイキングをする」という小さな行動から継続してみませんか？
Minecraftのリソースパックを作る①

リソースパックの作成に挑戦してみました。

リソースパックとModの違いさえも分かっていないMinecraft素人です。
子どもがMinecraft好きで、子どもと会話するために頑張ってみました。

リソースパック作成で一番参考になるのはMinecraft wikiにあるチュートリアルです：https://ja.minecraft.wiki

ここではチュートリアルをかいつまんで作ってみた結果を記述しています。詳細が必要な場合はチュートリアルをご確認ください。


#### パックフォルダを開く
チュートリアルに従いリソースパックのフォルダを開きます。

① Minecraftを起動して[Options...]をクリック
<img width="450" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703624/81c1377f-9c54-b409-87f5-3e2b4fe7d4b8.png">

② [Resource Packs...]をクリック
<img width="450" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703624/6c612a18-a702-f275-b61d-b0247fd5be8c.png">

③ [Open Pack Folder]をクリック
<img width="450" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703624/6f77fc1a-e328-362f-fdde-1a87f8c76556.png">

④ 空のresourcepacksフォルダが開く
<img width="450" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703624/c5079698-e388-3c47-40e5-6e2872490914.png">

⑤ 任意の名称のフォルダを作成する（TestResourcePackで作成してみました↓）
<img width="450" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703624/2bded381-67d1-1ae2-e3d8-f52554838d23.png">

#### リソースパックを作る
① 作成したフォルダを開き、pack.mcmetaという名称のファイルを作成する
このファイルがMinecraftにリソースパックであることを認識させてくれるとのこと。
<img width="450" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703624/0ec33788-bdb1-3beb-2043-d0f2238bdf55.png">

② エディタでファイルを開き、おまじないを書く
```
{
  "pack": {
    "pack_format": 18,
    "description": "Tutorial Resource Pack"
  }
}
```
**pack_format**：
記載する数字は先ほどのwikiで調べてください。私のForgeバージョンは1.20.2なので18を指定しています。
**description**：
リソースパックの説明

(注意)
文字コードはUTF-8とのこと。私のエディタはShiftJSがデフォルトなので文字コードを変換しました。

#### ちょっと動作確認
Minecraftを起動して[Options...]→[Resource Packs...]を選択すると、作成したリソースパック(TestResourcePack)が見えます。もちろん中身は空なので使えませんが...
<img width="450" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703624/3a77fc2d-c154-df77-88dd-0e3fa4e59c9d.png">

#### サムネイルを作る
チュートリアルには128x128が最適と記載されていたので、そのサイズで作成してみました。
① ペイントを起動
② Ctrl+wで画面設定を開き、[ピクセル]を選択して水平、垂直を128にしてOKをクリック
<img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703624/38253e66-807e-d8ab-9270-1e5f3c4a4050.png">

③ 適当な絵を描く
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703624/4ce79ec7-da66-cd45-cffb-249ac15e1117.png)
④ ファイル名称は「pack.png」として先ほど作成したディレクトリに保存

なお、先ほど作成したディレクトリ直下には、pack.pngファイルと、pack.mcmetaファイルのみ存在が許されています。それ以外のファイルは必ずassetsフォルダに配置します。そうしないとMinecraftから認識してもらえないようです。(チュートリアル情報)
<img width="450" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703624/6f7a07ca-295d-be23-11fb-2685451dc694.png">

#### 動作確認
あらためて、Minecraftを起動して[Options...]→[Resource Packs...]を選択すると、自分が描いたサムネイルが適用されていました。
<img width="450" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703624/aa725ba0-1265-a4a0-2645-cdad68f7452d.png">

[Minecraftのリソースパックを作る②](https://qiita.com/tester09/items/dc32e8f7deadf8eb938f)へ続く...
知らざれる、IT業界の4分野

みなさんこんにちは！
ITプロモーター勉強会です。
東京都内で、初心者向けにSE勉強会を開催しております。
ブログを今回より始めました！

https://www.stlin.net/

皆様の芸能活動やIT活動に役に立つ情報を発信してまいります!(^^)!

意外と知られてないITの分野。
## 4つあるのはご存じでしょうか？

![1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3976062/d12add9e-18c0-43a9-6933-e629b2d61c78.png)

以外と知られていないこの分野の分け方。
それもそのはず。

## 新卒の説明会でしかほぼ展開されない情報だからです。

転職組。それはずるい！って思いますよね？
しかし現実的な話です。


しかし、
自分が知ろうとしたり仕事にしようとしているのは果たしてどこなのか？
これははっきりさせておいた方がいいですね!(^^)!


僕は"インフラ"出身ですが、
その分野の特徴をしっかり押さえて、今の仕事に生かしています。

大体の人がかっこいい！と思うのはソフトの部分です！
違いが判らず、落とし穴にはまりがちです！
ぜひ、インプットをしてから技術の世界に踏み出しましょう。
動画ファイルの.cineのnumpyへのとりこみ

# まえがき
高速度カメラ`Phantom`シリーズの付属の撮影ソフトウエア`PCC`でのデフォルト拡張子`.cine`を、`python`の`numpy`配列へ入れる方法をメモしておく。
とはいっても、モジュールをつかうだけ。

なお`numpy`配列へ入れることで、`opencv`や`scikit-image`などのモジュールが使いやすくなる。

# 使用モジュール
`pims`
https://github.com/soft-matter/pims

# 読み込みの実例

```python
import numpy as np
import pims

f = pims.open("filename.cine")
```

これだけである。
厳密には、numpy配列に入ったわけではないものの、このまま同等として扱える（はず）

たとえば、

```python
type(f)
<class 'pims.cine.Cine'>

f.dtype
dtype('uint16')

f.shape
(874, 720, 1280)
```

となっている。
さらに

```python
f

<Frames>
Source: 10000fps.cine
Length: 874 frames
Frame Shape: (1280, 720)
Pixel Datatype: uint16
```
などと、メタデータも入っている。

どうしても`numpy`の純正がいいなら

```python
f2 = np.copy(f)

type(f2)
<class 'numpy.ndarray'>
```
とでもすればいい。

# scikit-imageをつかっての実例

```python
import numpy as np
import pims
from skimage.io import imsave

f = pims.open("filename.cine")

for i in range(0,f.shape[0]): 
  imsave("folderpath/"+str(str(i).zfill(5))+".tif",f[i])
```

などとすれば、`scikit-image`の`imsave()`を使って、連番の`.tif`を保存することとなる。
なお、`zfill(5)`は、0埋め5桁の名前で保存しろ、といういみ。
【React】テスト時に複数回レンダリングを実行するケースでWarning: An update to DialogRoot inside a test was not wrapped in act(...).が発生する

## はじめに

複数回レンダリングを実行するケースで`Warning: An update to DialogRoot inside a test was not wrapped in act(...).`が発生するという問題が発生しました。

前回の記事でレンダリングが実行される場合には`waitFor()`を使用してワーニングが出ないようにしたのですが再度発生してしまいました。

https://qiita.com/KM_20005/items/3e6b5c580d1bfcb6d490

問題のテストコードが下記です。

```tsx
it('should render "Title is empty error"', async () => {
  render(
    <ChakraProvider value={defaultSystem}>
      <App />
    </ChakraProvider>
  );

  // ボタンの取得
  const button = screen.getByText('新規登録');

  // ボタンクリック
  userEvent.click(button);// モーダル表示(レンダリング１回目)

  // 登録ボタンの取得
  const submitButton = await screen.findByText('登録');
  userEvent.click(submitButton);// バリデーション実行(レンダリング２回目)

  // Titleが空の時にエラーコメントが表示される
  expect(await screen.findByText('Title is required')).toBeInTheDocument();
});

```

前回との違いとしては２回待機する必要があるという点になります。

:::note warn
`waitFor()`の代わりに`findByText`を使用していますが同じような効果とお考え下さい。
:::

:::note warn
モーダル自体をコンポーネントとして切り出して、バリデーションのテストはそちらで実行する解決策もあります。その場合、これまで通りの方法でワーニングが出ないと思います。ただし「複数回のレンダリングを実行する」ケースとして今回はこのまま進めます。
:::

## 結論

テストの先頭に`globalThis.IS_REACT_ACT_ENVIRONMENT = false;`を追加する。

```diff_tsx
describe('App Page Test', () => {
+  beforeEach(() => {
+    globalThis.IS_REACT_ACT_ENVIRONMENT = false;
+  });
  
  it('should render "Title is empty error"', async () => {
    render(
      <ChakraProvider value={defaultSystem}>
        <App />
      </ChakraProvider>
    );

    // ボタンの取得
    const button = screen.getByText('新規登録');

    // ボタンクリック
    userEvent.click(button);

    // 登録ボタンの取得
    const submitButton = await screen.findByText('登録');
    userEvent.click(submitButton);

    expect(await screen.findByText('Title is required')).toBeInTheDocument();
  });
});
```

## おわりに

すべてのファイルに記載するのは手間なので一括で設定できる方法がないか引き続き調べようと思います。
この記事が皆様のコーディングライフの助けになれば幸いです。

## 参考

https://github.com/reactwg/react-18/discussions/102

https://airry.hatenablog.com/entry/globalthis_is_react_act_environment-not_working/

https://qiita.com/yumeoi_bit/items/a268524d46c959844f5e
bsearch

# 任意の値の範囲を絞っていく、無ければnilが返される
>ブロックの評価結果で範囲内の各要素の判定を行い、`条件を満たす値を二分探索(計算量は O(log n))で検索`します。`要素が見つからない場合はnil`を返します。self はあらかじめソートしておく必要があります。

>本メソッドはブロックを評価した結果により以下のいずれかのモードで動作します。

>* find-minimum モード
>* find-any モード
### find-minimum モード　ブロックの処理によって真偽が変わる
>find-minimum モード(特に理由がない限りはこのモードを使う方がいいでしょう)では、条件判定の結果を以下のようにする必要があります。
>* 求める値がブロックパラメータの値か前の要素の場合: true を返す
>* 求める値がブロックパラメータより後の要素の場合: false を返す

```rb
irb(main):139> ary = [0, 4, 7, 10, 12]
irb(main):140> ary.bsearch {|x| x >=   4 } # xが４より大きいか?
=> 4
irb(main):141> 3 >= 5
=> false
irb(main):142> ary.bsearch {|x| x >=   6 }
=> 7
irb(main):143> ary.bsearch {|x| x >=  -1 }
=> 0
irb(main):144> ary.bsearch {|x| x >= 100 }
=> nil
```
```rb
irb(main):151* if ary.bsearch {|x| x >=  -1 }
irb(main):152*   p "true"
irb(main):153* else
irb(main):154*   p "false"
irb(main):155> end
"true"
=> "true"
irb(main):156* if ary.bsearch {|x| x >=  100 }
irb(main):157*   p "true"
irb(main):158* else
irb(main):159*   p "false"
irb(main):160> end
"false"
=> "false"
```
### find-any モード 値の正負または0によって範囲を絞っていく
>find-any モードは bsarch(3) のように動作します。ブロックは真偽値ではなく、以下のような数値を返す必要があります。求める要素が配列の i 番目から j-1 番目までに入っているとします。またブロックパラメータの値のインデックスを k とします。

>* ブロックパラメータの値が求める値の範囲よりも小さい（0 <= k < i）場合: 正の数を返す
>* ブロックパラメータの値が求める値の範囲に合致する（i <= k < j）場合: 0 を返す
>* ブロックパラメータの値が求める値の範囲よりも大きい（j <= k < self.size）場合: 負の数を返す

>ブロックの評価結果が 0 になるいずれかの要素を返すか、nil を返します。
```rb
irb(main):001> ary = [0, 4, 7, 10, 12]
=> [0, 4, 7, 10, 12]
irb(main):002> ary.bsearch {|x| 1 - x / 4 }
=> 7
irb(main):003> ary.bsearch {|x| 4 - x / 2 }
=> nil
```
https://docs.ruby-lang.org/ja/latest/method/Array/i/bsearch.html
php-imapを利用できるようにする

PHP 8.4から、php-imapが、デフォルトのextensionから外れており、自分でインストールする必要がある。


## 0.事前条件
事前に、PHP8.4以降およびimap-2007fがインストールされていることが条件となります。
GSSAPIに関連付いた形でビルドされている必要があるため、OSパッケージのOpenSSL-develを元に、imap-2007がビルドされていないと、
「conftest.c:22:9: error: too few arguments to function 'utf8_mime2text'」
等のエラーが出てconfigureに失敗します。

## 1.ビルド
```
cd /usr/local/src
wget https://pecl.php.net/get/imap-1.0.3.tgz
tar xvzf imap-1.0.3.tgz
cd imap-1.0.3

#configureファイルを作成
/usr/local/bin/phpize

#Makeファイルを作成しビルド＋インストール
./configure  \
--with-imap=/usr/lib \
--with-imap-ssl=/usr/local/ssl
make
make install

#/usr/local/lib/php/extensions/no-debug-zts-20240924
#にimap.soファイルが配置されます
```

#ライブラリを利用できるようにする
```
vi /usr/local/lib/php.ini

#以下を追加する
extension=imap
```

Aoache再起動で終了
```
systemctl restart httpd
```

phpinfoで以下の拡張モジュールが表示されていれば正しく認識されている。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85495/3328d55f-c4b0-a573-2d21-e712f1856848.png)
【HTML + JS】Pointer EventsでCanvasをタッチ操作にも対応させる方法

## はじめに


以前マウスイベントとタッチイベントを併用して、Canvasを実装しました。

https://qiita.com/SoraoKosaka/items/0268872f6d9562b563a4

その際、ポインターイベント<sup>(1)</sup>の方がより簡単に汎用的な場面に適しているとコメントで教えていただき、今回はその実装の話となります。
結論めちゃくちゃ簡単に実装できます！！

## Pointer Events とは？
マウスイベントとタッチイベントを別々に書いていましたが、Pointer Events では「ポインター」という抽象化を用いることで、それぞれのデバイスを同じイベントで処理できます。

代表的なイベントは以下の通りです。

pointerdown: デバイスがアクティブになった（マウスダウン、タッチ開始など）
pointermove: デバイスが移動している（マウス移動、タッチ移動など）
pointerup: デバイスが離れた（マウスアップ、タッチ終了など）
pointerleave: デバイスが要素外に出た

## ソースコード
以下が今回実装したサンプルコードです。
```
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>Pointer Events対応サンプル</title>
  <style>
    #canvas {
      border: 1px solid black;
      touch-action: none;
    }
  </style>
</head>
<body>
  <h1>Pointer Events でお絵描き</h1>
  <canvas id="canvas" width="500" height="300"></canvas>
  <button id="resetBtn">リセット</button>

  <script>
    const canvas = document.getElementById('canvas');
    const ctx = canvas.getContext('2d');
    const resetBtn = document.getElementById('resetBtn');

    let drawing = false;

    // 相対座標取得
    function getCanvasPos(e) {
      const rect = canvas.getBoundingClientRect();
      return {
        x: e.clientX - rect.left,
        y: e.clientY - rect.top
      };
    }

    // PointerDown: ポインターがアクティブボタン状態なら描画開始
    canvas.addEventListener('pointerdown', (e) => {
      drawing = true;
      ctx.beginPath();
      const pos = getCanvasPos(e);
      ctx.moveTo(pos.x, pos.y);
    });

    // PointerMove: ポインターが移動中なら線を描画
    canvas.addEventListener('pointermove', (e) => {
      if (!drawing) return;
      const pos = getCanvasPos(e);
      ctx.lineTo(pos.x, pos.y);
      ctx.stroke();
    });

    // PointerUp: ポインターがアクティブボタン状態でなくなったら描画終了
    canvas.addEventListener('pointerup', () => {
      drawing = false;
    });

    // PointerLeave: Canvas外に出たら終了
    canvas.addEventListener('pointerleave', () => {
      drawing = false;
    });

    // リセット
    resetBtn.addEventListener('click', () => {
      ctx.clearRect(0, 0, canvas.width, canvas.height);
    });
  </script>
</body>
</html>
```
上記のコードを .html ファイルとして保存しブラウザで開くとタッチ操作でキャンバス上に絵を描けるようになっているはずです。

## おわりに
これで、スマホやタブレットのようなタッチデバイスでもお絵かきができるようになりました。

この記事が参考になりましたらぜひ「いいね」「フォロー」など励みになるのでよろしくお願いします！

## 参考文献
1. [ポインターイベント (Pointer events) - MDN](https://developer.mozilla.org/ja/docs/Web/API/Pointer_events)
【AWS】AWS IAMに再入門してみた

# はじめに

SAAを受験するため、IAMに再入門したためアウトプットとしてまとめます

# IAMとは？

IAM (Identity and Access Management)の略で、AWSを利用できるユーザを作成/削除/権限の付与を行う事ができます(簡単にいうと、AWS上のユーザ管理画面です)


# なぜIAMが必要なのか？

なぜIAMが必要かを説明するため、Aさん/Bさん/Cさんで開発・運用を行う場合を考えてみましょう
各ユーザの役割は以下とします

```
Aさん: AWSの管理者で社内で利用するAWSアカウントを作成した人
Bさん: 開発担当
Cさん: 運用担当
```

### IAMを利用しない場合

もし、IAMが存在しない場合はAさんの何でもできる強い権限をBさん/Cさんとアカウント共有をして使い回す必要があります



![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3118286/9ac02892-2d85-3fe6-9c66-480431eac081.png)



上記の運用では、以下の問題点があります

- ルートユーザのID/PWを他の人にも知られてしまう(セキュリティリスクの増加) 
- 誰が何の操作をしたのかがわからない
- 1人のミスで全てのAWSサービに影響が出る


上述したリスクを避けるために、

- **1ユーザに必要最小限の権限を付与したIAMユーザを作成** すること(最小権限の原則)
- ルートユーザを日常的に利用しないこと

が推奨されています。
また、IAMではIAMユーザを管理者のグループ・開発者のグループ・運用担当者のグループとグループ化する機能(IAMグループ)もあります
本記事では先にIAMユーザが所属するグループを先に作成していきます

# IAMグループの作成方法

IAMのページへは、AWSログイン後に虫眼鏡のマークでIAMと検索 => IAMを押下すると遷移できます


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3118286/7fbcec77-1dcd-5460-e1c5-8704889de46b.png)


管理者グループを作成してみます。
IAMを利用しない場合で例示したAさんが所属するグループです。


1. アクセス管理 => ユーザグループ => グループを作成を押下
2. 任意のユーザグループ名を入力
3. AdministratorAccessを選択し、ユーザグループを作成を押下します
    - AdministratorAccessは請求金額の確認やクレジットカード情報の変更以外、何でもできる管理者権限になります


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3118286/7a86b3ba-8dce-3edc-8367-823097496006.png)

これで、管理者グループが作成できました。

管理者グループに入っているユーザはグループに付与した権限を得る事ができます。
グループを作成することで、ユーザ毎に何度も同じ権限を設定したりすることがなくなります。


次はIAMユーザを実際に作成してみます。

# IAMユーザの作成方法

管理者グループにIAMユーザを作成して、追加してみます

1. アクセス管理 => ユーザ => ユーザの作成を押下します
2. 任意のユーザ名を入力し、AWS マネジメントコンソールへのユーザーアクセスを提供する にチェックを入れます
    - チェック不要でも良いですが、CLIでAWSを操作したい場合はチェックを入れてください
3. ユーザタイプはIAMユーザを作成しますを選択します
    - 2024年1月3日時点ではIdentity Center でユーザーを指定する方法が推奨されていますが、IAM作成のデモのため本記事ではIAMユーザを作成しますを選択します
4. 自動生成されたパスワード/カスタムされたパスワードのどちらかを選択します
5. ユーザーは次回のサインイン時に新しいパスワードを作成する必要がありますにチェックを入れます
    - チェックを入れることで、IAMユーザの初回ログイン後に新規でパスワードを入力してパスワード変更を行えます
    - AさんがIAMユーザを発行した後に、Cさんに初回ID/パスワード共有 => Cさんがパスワード再設定する事でCさんしかIAMユーザへはログインする事ができなくなり高いセキュリティを実現する事ができます
6. 先ほど作成したユーザグループを選択し次へを押下します
7. ユーザの作成を押下します


これで、管理者権限を持ったIAMユーザを作成する事ができました。
IAMユーザは必ずグループに所属必要はなく、直接権限を設定することもできます。
また、"人"に対して権限を付与してきましたが、"AWSサービス"に対して、権限を付与することも可能です(IAMロール)。

# IAMのセキュリティについて

IAMではセキュリティツールとして、

- 認証情報のレポート
- アクセスアドバイザー

を提供しています

### 認証情報のレポート

認証情報のレポートは

- アクセスレポート => 認証情報のレポート => 認証情報レポートをダウンロード

から結果をダウンロードでき、パスワードの最終変更日時やMFAの有無などセキュリティに関する情報を取得できます。

### アクセスアドバイザー

IAMユーザ単位で利用したAWSサービスを確認する事ができます。

- アクセス管理 => ユーザ => 利用したAWSサービスを確認したいユーザを押下 => 最終アクセス日時

で確認する事ができます



![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3118286/ed51495e-d467-54d6-3c60-e290aed0f578.png)


# 最後に

AWSを初めて触る方や、IAMよく分からないって方のお役に立てたらとても嬉しいです:v_tone1:
ここまで読んでくださり、ありがとうございました:bow:
【Go】Goでシーザー暗号書いてみた


## 概要


[**暗号技術入門 第3版**](https://amzn.asia/d/4EzqngT)で最初の方に出てくる暗号、`シーザー暗号`をGo実装してみた


## サンプルコード


```go
package main

import "fmt"

const (
	AlphabetSize = 26
	Shift        = 1
)

// シーザー暗号の実装
func caesarCipher(input string, shift int) string {
	// 「shift % AlphabetSize」・・・-25~25の範囲内の数値に変換
	// 「+ AlphabetSize」・・・-25~-1の値を0~25の範囲内の数値に変換。0~25だった数値は26~51となってしまう
	// 「% AlphabetSize」・・・26~51となってしまった数値を0~25の範囲内の数値に変換
	shift = (shift%AlphabetSize + AlphabetSize) % AlphabetSize // シフトを正の範囲に正規化

	var result []rune
	for _, char := range input {
		if char >= 'A' && char <= 'Z' { // 大文字の場合
			shifted := 'A' + (char-'A'+rune(shift))%AlphabetSize
			result = append(result, shifted)
		} else if char >= 'a' && char <= 'z' { // 小文字の場合
			shifted := 'a' + (char-'a'+rune(shift))%AlphabetSize
			result = append(result, shifted)
		} else {
			// アルファベット以外の文字はそのまま
			result = append(result, char)
		}
	}
	return string(result)
}

func main() {
	text := "Hello, world!"
	fmt.Printf("Original: %s\n", text)

	encrypted := caesarCipher(text, Shift) // 暗号化
	fmt.Printf("Encrypted: %s\n", encrypted)

	decrypted := caesarCipher(encrypted, -Shift) // 復号化
	fmt.Printf("Decrypted: %s\n", decrypted)
}

// 出力
// Original: Hello, world!
// Encrypted: Ifmmp, xpsme!
// Decrypted: Hello, world!
```
Node.jsパッケージマネージャーについて調べる

## 基礎知識を徹底的に叩き込もうDAY2🎉（24-25年末年始企画）

前回は「Node.js」について記事を書きました。
年末年始は体調不良であまり作業できずでした🥲挽回します。
今回は代表的な「Node.jsパッケージマネージャー」について調べてみたいと思います。
Node.jsのバージョンがフレームワークと互換性がなく動かないみたいなこと、たまにあると思います。その際に知っておきたい知識かと思います。

## Node.jsパッケージマネージャーは何がある？

npm, yarn, pnpm, etc...

今回は、特に使われているであろうnpm、yarnについて調査していきます。

## [前提] パッケージとは？

外部から利用することを目的としたクラスや関数を、モジュール（module）と呼びます。それを利用して機能として作られたものをパッケージ（もしくはライブラリ）と呼びます。
RailsでいうGemのイメージ。

## npmとは

npmは「Node package manager」の頭文字をとった名称です。その名の通り、Node.jsのパッケージを管理するシステムです。npmを介さずに直接パッケージを使おうとすると、パッケージ間の依存関係や競合関係を開発者自身が修正する必要が発生し、非常に困難です。そのため、パッケージ管理を行ってくれるnpmは不可欠なツールと言えるでしょう。

## yarnとは

2010年にnpmがリリースされたのち、2016年にyarnがリリースされました。npmとの互換性が高く、package.jsonファイルからどちらもロックファイルを生成することができます（npmはpackage-lock.json, yarnはyarn.lock）。

yarnの方がインストール速度は速いようです。調べた感じ、それ以外だと両者あまり差は無いように感じました。

## まとめ

フロントエンド開発者にとっては、パッケージを利用する上でパッケージマネージャーは必要不可欠な存在です。パッケージを普段ストレスなくインストールしてアプリケーションに組み込むことができているのは、パッケージマネージャーのおかげだったのですね。いつもありがとうございます。
すごいことは分かったのですが、では一体裏ではどうやってパッケージたちを管理しているのかが気になるところです…

次回は、Node.jsの"バージョン"管理について調べられたらと思っています。

## 参考記事

- [npmとは─Nodeのパッケージマネージャ入門講座
](https://kinsta.com/jp/knowledgebase/what-is-npm/)
- [そもそもnpmからわからない](https://zenn.dev/antez/articles/a9d9d12178b7b2)
C#でWord (Doc/ Docx) をPDFに変換 - 総合ガイド

Word文書は非常に実用的な文書フォーマットである。その操作性は非常に便利で、だからこそユーザーに愛されてきた。しかし、文書を保存する場合、文書の安定性とセキュリティのためにPDF形式を選択する人も少なくありません。この記事では、無料の.NETライブラリを使用して、**C#でWordをPDFに変換する方法**を示します。

## 無料の.NET Wordライブラリをインストールする
私たちが使っている無料のライブラリーは[**Free Spire.Doc for .NET**](https://www.e-iceblue.com/Introduce/free-doc-component.html)
です。インストール方法は2つあります。
* **方法1：** [**NuGet**](https://www.nuget.org/packages/FreeSpire.Doc)を介してFree Spire.Doc for .NETをインストールする
「ツール」>「NuGetパッケージマネージャ」>「パッケージマネージャコンソール」の順に選択し、次のコマンドを実行します。
> `PM> Install-Package FreeSpire.Doc`

* **方法2：** プログラムに手動でSpire.doc.dllファイルを導入する
[Free Spire.Doc for.NET](https://www.e-iceblue.com/Download/download-word-for-net-free.html)をローカルにダウンロードし、解凍してインストールします。インストールが完了したら、Visual Studioを開いて新しいプロジェクトを作成し、右側のソリューションエクスプローラで「参照」を右クリックし、「参照を追加」>「閲覧」を選択して、インストールパスの下のBINフォルダのdllファイルを見つけ、「OK」をクリックして、プログラムに参照を追加します。


## C#でWordをPDFに変換する
以下は具体的な操作手順です。
1. `Document`クラスのオブジェクトを作成します。
1. **`Document.LoadFromFile()`** メソッドを使用して、Wordサンプルドキュメントをロードします。
1. **`Document.SaveToFile()`** メソッドを使用して、WordドキュメントをPDFドキュメントとして保存します。

C#コード
```csharp
using System;
using Spire.Doc;
using Spire.Doc.Documents;

namespace DoctoPDF
{
    class toPDF
    {
        static void Main(string[] args)
        {
            //Documentクラスのオブジェクトを作成する
            Document document = new Document();
//Wordサンプルドキュメントをロードする
            document.LoadFromFile("Sample.docx");

            //WordをPDFに変換する
            document.SaveToFile("toPDF.PDF", FileFormat.PDF);
        }
    }
}
```
![Word2PDF.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2811193/9dd78287-d4ec-a34d-d89b-3cf88776ce55.png)



📌 Word APIはまた、**`ToPdfParameterList`** クラスを提供しており、Wordをパスワードで保護されたPDFに変換したり、しおりを含むPDFに変換したり、フォントを埋め込んだPDFに変換するなど、追加の変換設定でWordをPDFに変換することができます。以下はその例である。


### C#でWordをパスワードで保護されたPDFに変換する
```csharp
            // ToPdfParameterListオブジェクトの作成
            ToPdfParameterList parameters = new ToPdfParameterList();

            // 生成されたPDFのためのオープンパスワードと許可パスワードを設定する
            parameters.PdfSecurity.Encrypt("openPsd", "permissionPsd", PdfPermissionsFlags.None, PdfEncryptionKeySize.Key128Bit);
```
### C#でしおり付きWordをPDFに変換する
```csharp
            // ToPdfParameterListオブジェクトの作成
            ToPdfParameterList parameters = new ToPdfParameterList();

            // Wordの既存のしおりからPDFのしおりを作成する
            parameters.CreateWordBookmarks = true;

            // Wordの見出しからブックマークを作成
            // parameters.CreateWordBookmarksUsingHeadings= true;
```

### C#でWordをPDFに変換しながらフォントを埋め込む
```csharp
            // ToPdfParameterListオブジェクトの作成
            ToPdfParameterList parameters = new ToPdfParameterList();

            // 生成されたPDFにWordで使用されているすべてのフォントを埋め込む
            parameters.IsEmbeddedAllFonts = true;
```

### C#でWordをPDFに変換する際にハイパーリンクを無効にする
```csharp
            // ToPdfParameterListオブジェクトの作成
            ToPdfParameterList parameters = new ToPdfParameterList();

            // ハイパーリンクを無効にする
            parameters.DisableLink = true;
```
* * *

***参考:***

https://www.e-iceblue.com/Tutorials/Spire.Doc/Spire.Doc-Program-Guide/How-to-Convert-Word-to-PDF.html#3
unshift(可変長引数)

# 後から順にオブジェクトを配列の先頭に代入する
>unshift(*obj) -> self
prepend(*obj) -> self
指定された obj を引数の`最後から順番に配列の先頭に挿入`します。引数を指定しなければ何もしません。

>[PARAM] obj:
自身に追加したいオブジェクトを指定します。

```rb
irb(main):120> arr.unshift 0
irb(main):121> p arr             #=> [0, 1, 2, 3]
irb(main):122> arr.unshift [0]
irb(main):123> p arr             #=> [[0], 0, 1, 2, 3]
irb(main):124> arr.unshift 1, 2
irb(main):125> p arr             #=> [1, 2, [0], 0, 1, 2, 3]
[0, 1, 2, 3]
[[0], 0, 1, 2, 3]
[1, 2, [0], 0, 1, 2, 3]
=> [1, 2, [0], 0, 1, 2, 3]
```
#### 色々格納できる
```rb
irb(main):129> arr.unshift Enumerator.new {}
=> [#<Enumerator: ...>, 1, 2, [0], 0, 1, 2, 3]
```

https://docs.ruby-lang.org/ja/latest/method/Array/i/prepend.html
gets

# テキストを読み込む
>gets(rs = $/, chomp: false) -> String | nil[permalink][rdoc][edit]
gets(limit, chomp: false) -> String | nil
gets(rs, limit, chomp: false) -> String | nil
一行読み込んで、読み込みに成功した時にはその文字列を返します。 EOF に到達した時には nil を返します。

>テキスト読み込みメソッドとして動作します。

>読み込んだ文字列を変数 $_ にセットします。 IO#readline との違いは EOF での振る舞いのみです。

>limit で最大の読み込みバイト数を指定します。ただしファイルのエンコーディングがマルチバイトエンコーディングである場合には読み込んだ文字列がマルチバイト文字の途中で切れないように数バイト余分に読み込む場合があります。

>[PARAM] rs:
行の区切りを文字列で指定します。rs に nil を指定すると行区切りなしとみなします。空文字列 "" を指定すると連続する改行を行の区切りとみなします(パラグラフモード)。
[PARAM] limit:
最大の読み込みバイト数
[PARAM] chomp:
true を指定すると各行の末尾から "\n", "\r", または "\r\n" を取り除きます。
[EXCEPTION] IOError:
自身が読み込み用にオープンされていなければ発生します。

https://docs.ruby-lang.org/ja/latest/method/IO/i/gets.html
```rb
irb(main):046> gets
faa
=> "faa\n"
irb(main):047> gets
hogehoge
=> "hogehoge\n"
```
```rb
irb(main):051> gets
fafafa\nfafa\n
=> "fafafa\\nfafa\\n\n"
irb(main):052> gets
faffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeeeeeee
=> "faffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeeeeeee\n"
...
irb(main):054> $_
=> "faffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeeeeeee\n"
```
```rb
irb(main):112> gets(chomp:false)
fafa
=> "fafa\n"
irb(main):113> gets(chomp:true)
fafa
=> "fafa"
```

### $_　　getsで読み込まれたものを格納されるグローバル変数
https://qiita.com/masatom86650860/items/08e72fc9061b789592ec