OmniAICreator/Qiita-1.07M huggingface dataset:
[Go] 並行処理を30分で理解？

# Goroutinesってなに？

[educative](https://www.educative.io/answers/what-is-a-goroutine)には、以下のように書いてあります。

>ゴルーチンとは、Goプログラミング言語における軽量の実行スレッドであり、プログラムの他の部分と同時に実行される関数です。
ゴルーチンは、従来のスレッドと比較すると、ゴルーチンを作成するオーバーヘッドが非常に小さいため、驚くほど安価です。そのため、Goでは並行プログラミングに広く使われています。
関数をgoroutineとして呼び出すには、goキーワードを使用します。

なるほど、わからん。まぁとりあえず、 **同時に実行される** ということですね。


# コードのテンプレート
2つの関数 **`heyko1()`** と **`heyko2()`** が同時に実行される（並行処理される）ための関数 **`main()`** を作成します。 


goroutinesを呼び出すときには、基本的には呼び出すところで関数の前に`go`をつけることで並行処理として利用できます。これだけで並行処理にできるというところがgoのいいところなんです。

まず、基本的に以下のような形で書きました。

```go
func main() {
    // 普通の処理（同期処理）
    normalFunc()

    // 並行処理（goroutinesとして呼び出す）
    go parallelFunc()
}
```

goをつけるかつけないかだけです。

次に、関数を2つ作り、並行処理を簡単に実装してみます。


```go: template
package main

import (
    "fmt"
    "sync"
)

// heyko1 はgoroutineで実行する最初の関数です。
func heyko1(wg *sync.WaitGroup) {
    defer wg.Done() // 関数終了時にWaitGroupのカウントをデクリメント

    // ここにheyko1の処理を書きます
    fmt.Println("heyko1 の実行中です")
}

// heyko2 はgoroutineで実行する2番目の関数です。
func heyko2(wg *sync.WaitGroup) {
    defer wg.Done() // 関数終了時にWaitGroupのカウントをデクリメント

    // ここにfunction2の処理を書きます
    fmt.Println("heyko2 の実行中です")
}

func main() {
    var wg sync.WaitGroup // WaitGroupの初期化

    wg.Add(2) // WaitGroupのカウントを2つのgoroutineの数だけインクリメント

    go heyko1(&wg) // heyko1をgoroutineとして実行
    go heyko2(&wg) // heyko2をgoroutineとして実行

    wg.Wait() // すべてのgoroutineの終了を待機
    fmt.Println("全て終了")
}


```

基本的にこのような形になります。これらを実際に時間の処理を入れてみましょう。


```go: 時間を入れた処理
package main

import (
	"fmt"
	"sync"
	"time"
)

func main() {

	fmt.Println("はじまり〜")
	var wg sync.WaitGroup

	// WaitGroupのカウンタを2つ増やす
	wg.Add(2)

	// process1をgoroutineとして実行
	go func() {
		heyko1() 
		defer wg.Done() // 処理が完了したらWaitGroupのカウンタを減らす
	}()

	// process2をgoroutineとして実行
	go func() {
		heyko2()
		defer wg.Done() // 処理が完了したらWaitGroupのカウンタを減らす
	}()

	// すべてのgoroutineが終了するのを待つ
	wg.Wait()

	fmt.Println("おわり〜")
}

func heyko1() {
	start := time.Now()
	time.Sleep(10 * time.Second)
	end := time.Now()
	fmt.Println("heyko1: ", (end.Sub(start)).Seconds())
	fmt.Println("heyko1: ", start.Format("2006-01-02T15:04:05Z07:00"), "~~", end.Format("2006-01-02T15:04:05Z07:00"))
}

func heyko2() {
	start := time.Now()
	end := time.Now()
	fmt.Println("heyko2: ", (end.Sub(start)).Seconds())
	fmt.Println("heyko2: ", start.Format("2006-01-02T15:04:05Z07:00"), "~~", end.Format("2006-01-02T15:04:05Z07:00"))
}
```

↓ 実行結果

```
はじまり〜
heyko2:  1.27e-07
heyko2:  2024-02-23T16:13:07+09:00 ~~ 2024-02-23T16:13:07+09:00
heyko1:  10.000868864
heyko1:  2024-02-23T16:13:07+09:00 ~~ 2024-02-23T16:13:17+09:00
おわり〜
```

なぜ時間で書いたかというと、heyko1とheyko2の始まるタイミングと終わるタイミングが同じであり、処理時間が違うため、終了時間が異なることを確認するためです。

実際に
```
heyko2:  2024-02-23T16:13:07+09:00 ~~ 2024-02-23T16:13:07+09:00
```

```
heyko1:  2024-02-23T16:13:07+09:00 ~~ 2024-02-23T16:13:17+09:00
```

となっているため、始まりは一緒の```2024-02-23T16:13:07+09:00``` です。
そのあとは、10秒の差があって、終わっています。

実体験で感じれましたね！

以上！
JCPに登録してみた

# JCPに登録した経緯
先日のJJUGで、Java Community Processについてお話があったので、実際に登録してみました。
JCPについての説明はこちらの動画をご覧ください。
[JJUG ナイトセミナー JCP特集](https://www.youtube.com/live/LiFt9x3sdWs?si=A10l-u5BGWuEsKu__)
# 登録の流れ

## 1. Oracle Accountの作成

[Oracleホームページ](https://www.oracle.com/jp/)


<details><summary>画像</summary>

<img width="200" alt="ファイル名" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/622672/47f1ccd0-a832-e50a-7bf2-941451a94be5.png">
<br>
アカウントを表示 -> アカウントを作成
<br>
<img width="200" alt="ファイル名" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/622672/b6025240-7e49-66e1-05b7-9a1c9a680417.png">
<br>
<img width="200" alt="ファイル名" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/622672/c30f35b4-2aee-5da7-d890-837ba2ecac14.png">
<br>
<img width="200" alt="ファイル名" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/622672/4ac59186-2037-0492-e988-91b3f521017f.png">

</details>

    案内していただいたところ、記入内容については以下の説明をいただきました。
    #### 記入内容について
    > - 個人での参加の場合、会社名は不要
    > - 住所、氏名に関しては要英字入力

## 2. SSOでの登録

[Java Community Process](https://jcp.org/en/home/index)
<img width="80" alt="ファイル名" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/622672/64607d75-f1c7-d454-8627-138ffdd952a7.png">

Sign-in押すとOracleアカウントとSSO認証が行えます。
<details><summary>SSO認証でエラーが発生した件について</summary>

名前・住所を日本語で入力していたことが原因のようです。
[関Javaの資料](https://www.sakatakoichi.com/entry/2017/06/15/183000)
こちらの下部でご紹介されている、浜本さんに対応していただきました。
問い合わせメールを送るには、英語+日本語で送ると浜本さんに対応してもらいやすいかもしれません。

</details>

## 3. Associate MemberShipへの申し込み

Get Involved -> Becoming a JCP Member -> Instructions for Associate Membership -> Register for the site から登録が可能です。
[Associate MemberShipへの申し込み](https://jcp.org/en/participation/newMembership?type=ASSOCIATE)
また、上記リンクから申し込みが可能です。以下のようなページになります。
![スクリーンショット 2024-02-07 22.15.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/622672/a6ef5fe3-ca1e-3beb-b303-a3bc74a4aeb8.png)
申し込むと、DocSignで署名が送られてきます。
氏名+会社名(Private)を英語で書くことで、個人で対応することは完了です。

<details><summary>DocSignの感想</summary>

SSO認証エラーで時間が取られたこと以外は非常に素早く進みました。
電子署名に関しても、名前と会社名を入力するのみで完了だったため、非常に楽でした。
電子署名が英字になるのですが、筆記体の種類が何種類もあって笑えました、海外の文化なんでしょうか。
</details>
JCPの管理側のサインが完了次第、完了のメールが届きます。
JSRの作成に申し込んだりできるようになったようです。

私が本格的に貢献できるまでは先が長いかと思います。（できない可能性もあると思います。）
最新の情報の取得手段を準備しておくのは良いかと思い、登録してみました。
登録自体は無料で時間もかからないので、気が向いたら登録してみてください。
C++のライブラリboostの最新版をLinuxサーバーにインストールする方法

# はじめに
　本記事はC++のライブラリであるboostの最新版をLinuxサーバーに圧縮ファイルからインストールする方法を解説します。最新版が必要でないのであれば、yumやaptによるインストールが最もスマートです。
# 環境
・2024/02/18
・GitHub Codespace
# boostとは
　boostとはタイトルにもある通り、C++のライブラリです。オープンライブラリであり、非商用/商用に無料で利用できます。
　コミュニティとしてのboostは、ライブラリを提供しているだけに留まらず、C++のプログラム言語自体に多大な影響を与えています。boostライブラリはC++の標準機能を試験するための試験場としての役割があります。そのためboostライブラリはC++の標準機能では提供されない先鋭的な技術を提供しており、非常に有用なライブラリとして有名です。
　ChatGPTにそのライブラリの内容を聞けば、以下の通りに回答してくれます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2647158/c146c3b7-25a0-4ab5-6cb2-731469f283f4.png)

　他にも非常に有用な機能を提供しているため、詳しくはWikipediaに記される内容を参照してください。

https://ja.wikipedia.org/wiki/Boost_C%2B%2B%E3%83%A9%E3%82%A4%E3%83%96%E3%83%A9%E3%83%AA

# ダウンロード方法

　boostの公式ページに飛び、URLを取得します

https://www.boost.org/users/download/



![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2647158/539b3643-b044-e198-f786-f994e2422939.png)

　Downloadsにあるいずれかの青い文字からURLを取得してください。
　私の場合は以下のURLが取得しました。圧縮ファイルのtar.bz2です。

https://boostorg.jfrog.io/artifactory/main/release/1.84.0/source/boost_1_84_0.tar.bz2

　Linuxサーバーのターミナルで以下のコマンドを実行して下さい。URLの部分には、取得したURLを代入してください。

```
wget URL
```

# 解凍方法
## bz2をダウンロードした場合

　取得したURLの末尾にbz2と書かれている場合、以下のオプションを使用して解凍してください。xxxx部分は、ダウンロードした圧縮ファイルの名前を正確に入力して下さい。

```
tar -jxvf xxxx.tar.bz2
```

## gzをダウンロードした場合

 取得したURLの末尾にgzと書かれている場合、以下のオプションを使用して解凍してください。xxxx部分は、ダウンロードした圧縮ファイルの名前を正確に入力して下さい。

```
tar -zxvf xxxx.tar.gz
```

# bootstrapの実行

　解凍したboostのディレクトにcdコマンドを使用して入り、以下のコマンドを実行します。

```
./bootstrap.sh
```

# boostのビルド
　bootstrapの実行後にboostを使用するためにビルドが必要ですので、以下のコマンドを実行します。リカレントディレクトリは解凍されたboostのディレクトリのままです。
　 b2はBoost.Buildで管理されたプロジェクトをビルドする実行ファイルです。b2コマンドはprefixを指定することで、ビルドによる生成物の生成ディレクトリを指定できます。prefixのデフォルトは/usr/localが指定されているそうです。

```
sudo ./b2 install --prefix=/usr/local
```

　以上のコマンドをそのまま実行した場合、boostライブラリとヘッダーはそれぞれ、/usr/local/libと/usr/local/includeにビルドされる。
 　ビルド時間はライブラリの大きさ相応に長くなる。全てのboostライブラリは要らず、特定のライブラリだけを使用したい場合は、bootstrap実行時に –with-libraries のオプションを使用することで解決できます。

# example
　boostライブラリを使用した簡単なコード例をコンパイルし、実行することでboostのインストールに問題がないことを確認します。今回はexample.cppというファイルに次のコードを保存しました。

```c++:example.cpp
#include <iostream>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>

int main() {
    // UUIDを生成する
    boost::uuids::uuid uuid = boost::uuids::random_generator()();

    // UUIDを文字列に変換して表示する
    std::cout << "Generated UUID: " << uuid << std::endl;

    return 0;
}
```

　上記のコードを保存したファイルが存在するディレクトリで以下のコンパイルを実行します。/usr/localとは異なるディレクトリにboostをビルドした際は、そのディレクトリを指定してください。

 ```
g++ -o example example.cpp -I /usr/local/include/boost -L /usr/local/lib
 ```

　無事に実行できればexample実行ファイルが作成されています。実行ファイルを実行すると適当なUUIDが生成され、出力されます。

 ```
 $ ./example
 Generated UUID: c2253419-a003-4431-95cf-fe8db55938ac
 ```

 

# 参考

https://www.mathkuro.com/c-cpp/boost/install-to-centos7/

https://qiita.com/supersaiakujin/items/c6b54e9add21d375161f

https://www.baeldung.com/linux/boost-install-on-ubuntu#4-testing-the-installation
PlunkerでPhaser.Physics その2

# 概要
Plunkerで、Phaser.Physicsやってみた。
プリミティブ全部使ってみた。

# 写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/94303776-c1c5-2b67-6f4a-3cefdef9e19c.png)

# サンプルコード

```
var game = new Phaser.Game(800, 600, Phaser.CANVAS, 'phaser-example', { 
    create: create, 
    render: render 
});
var bodies = [];
var codes = [];
var codeCaption;
function create() {
    game.stage.backgroundColor = '#124184';
    game.physics.startSystem(Phaser.Physics.BOX2D);
    game.physics.box2d.debugDraw.centerOfMass = true;

    for (var i = 0; i < 7; i++)
    {
        bodies.push(new Phaser.Physics.Box2D.Body(this.game, null, 100 + i * 100, 300, 0));
    }
    bodies[0].setCircle(40);
    bodies[1].setRectangle(50, 100);
    bodies[2].setRectangle(50, 100, 0, 0, 10);
    bodies[3].setRectangle(50, 100, 0, 25, 10);     
    bodies[4].setEdge(-10, -20, 20, 60);    
    bodies[5].setChain([-10, -20, 20, 60, 35, -30, -20, -50, -40, 20, -10, 20]);    
    bodies[6].setPolygon([-10, -20, 20, 60, 35, -30, -20, -50, -40, 20, -10, 20]);
    codes[0] = "setCircle(40)";
    codes[1] = "setRectangle(50, 100)";
    codes[2] = "setRectangle(50, 100, 0, 0, 10)";
    codes[3] = "setRectangle(50, 100, 0, 25, 10)";
    codes[4] = "setEdge(-10, -20, 20, 60)";
    codes[5] = "setChain([-10, -20, 20, 60, 35, -30, -20, -50, -40, 20, -10, 20])";
    codes[6] = "setPolygon([-10, -20, 20, 60, 35, -30, -20, -50, -40, 20, -10, 20])";
    game.add.text(5, 5, 'Manual fixture creation. Move the mouse near each type to see the code used to create it.', { 
        fill: '#ffffff', 
        font: '14pt Arial' 
    });
    codeCaption = game.add.text(5, 25, '', { 
        fill: '#ffffff', 
        font: '14pt Arial' 
    });
}
function render() {
    game.debug.box2dWorld();
    codeCaption.text = "";
    for (var i = 0; i < bodies.length; i++)
    {
        if (Math.abs(game.input.mousePointer.x - bodies[i].x ) < 50 && Math.abs(game.input.mousePointer.y - bodies[i].y ) < 50 )
        {
            codeCaption.text = codes[i];
            game.debug.box2dBody(bodies[i], 'rgb(255,255,0)');
        }
    }
}




```

# 成果物

https://embed.plnkr.co/plunk/DlIdTokGxl8pImGH


以上。
PlunkerでPhaser.Physics

# 概要
Plunkerで、Phaser.Physicsやってみた。

# 写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/320018b6-96f7-9030-03bf-2fbfc3ce5cf9.png)


# サンプルコード

```
var game = new Phaser.Game(800, 600, Phaser.CANVAS, 'phaser-example', { 
    preload: preload, 
    create: create, 
    render: render 
});
function preload() {
    //game.load.image('ball', 'assets/sprites/shinyball.png');
}
var circle
function create() {
    game.stage.backgroundColor = '#124184';
    game.physics.startSystem(Phaser.Physics.BOX2D);
    game.physics.box2d.gravity.y = 500;
    game.physics.box2d.restitution = 0.8;
    game.physics.box2d.setBoundsToWorld();

    var ball = game.add.sprite(400, game.world.centerY, 'ball');
    game.physics.box2d.enable(ball);
    ball.body.setCircle(ball.width / 2);

    var circle = game.physics.box2d.createCircle(300, 300, 32);

    var square1 = new Phaser.Physics.Box2D.Body(this.game, null, 200, 130, 2);
    square1.setRectangle(50, 50, 0, 0, 0);
    square1.friction = 0.4;
}
function render() {
    game.debug.box2dWorld();
}



```

# 成果物

https://embed.plnkr.co/plunk/nPYbUfsQfM2nMDOw

以上。
備忘　Port busy　arduinoとprocessing

arduino IDEでスケッチしながら、processingにシリアル通信しようとしたら<b>Port busy</b>エラーが出た。

5時間くらい格闘した。

<h3>原因</h3>
arduinoを接続しているポートを、arduino IDEが占有していることが原因

<h3>対処</h3>
arduino IDEを閉じる


<p><b>サンプルコード</b></p>
=== arduino ===

```
void setup() {
    Serial.begin(9600);
}

int c;
void loop() {
    Serial.print(c++);
    delay(1000);
}

```
arduinoにスケッチを書き込んだら
<font color="red">arduino IDEを閉じる！</font>

=== processing ===

```
import processing.serial.*;
Serial port;

void setup(){
    port=new Serial(this,"COM5",9600);
}
void draw(){
    if(port.available()>1){
        println(port.readString());
    }
}
```
OCI最初のハマり

諸事情でOCIを使うことになり、試して最初にハマったところを記録に残しておく

# AlwaysFreeから有償プランに変更した。今までタダで使ってたインスタンスも課金される？
AlwaysFreeで使っていたものは引き続き無償で利用できる

# Yubikey登録時に ”Error: no supported key algorithms were found” と表示されて進むことができない
Bitwarden 機能拡張を入れている場合には無効化した上で、OCIからサインアウト、ブラウザを再起動してやり直す

## Yubikeyはメイン、バックアップの２つ登録する
別にOCIに限らないけどなくしたときに詰むからね。ケチケチせずに2つ買っとけ。[バイパスコードを設定しておく](https://docs.oracle.com/ja-jp/iaas/Content/Identity/users/generate-bypass-codes-user-accounts.htm)手段もあるけど組織によっては「それ盗まれたらどーすんだ」的難癖をつけるところもあるかもしれない。

## [Oracle Mobile Authenticator](https://docs.oracle.com/ja-jp/iaas/Content/Identity/mobileauthapp/overview-oma-app.htm)も設定しておいたほうがいい
仮想マシンでログインするときなど環境によってはYubikeyを使用できない場合もあるのでOracle Mobile Authenticatorで2FAする手段もバックアップとして設定しておく。Oracle Mobile Authenticatorをプライマリの手段にして毎回操作してるとタルくて憤死しそうになるのでYubikeyのほうが絶対にいい

# インスタンス作成時の見積もりに出てくるブートボリュームの価格が異様に($238/mo)高い
誤記かもしれない

# インスタンス作ってもアクセスできない
アクセス先のサブネットにSecurityListをセットする場合、明示的に許可していないアクセスは全拒否になる
SecurityListでアクセスを許可していないといけない

# Network Security Group(NSG)でアクセス拒否できない
Security Listで許可されていれば、NSGで拒否していてもアクセスが許される
逆のパターンも同じで、NSGで許可していれば、Seculity Listの中に明示的に許可がなくても、アクセスが許される
[Oracle的にはNSGの利用を推奨している](https://docs.oracle.com/ja-jp/iaas/Content/Network/Concepts/securityrules.htm#comparison)ようだが、作成時に明示的に指定する必要があり、それはそれで１手間増えて面倒くさい
安全側に倒すのであれば、OSの機能(firewalldなど)でポートの開け閉めを設定しておいたほうがいいかも

参考: [OCIのファイアウォール機能の違い](https://qiita.com/Pampus/items/502b26c2fc90eb5c4c57)

# 構築したシステムを外形監視したい

[OCI Health Checks](https://www.oracle.com/jp/cloud/networking/health-checks/)を使う
【Google Cloud】Digital Leaderにクラウド知識0から受かった話

# 基本情報
クラウド経験：ほぼ無し
保有資格：
1. 基本情報技術者試験
2. 応用情報技術者試験
3. 情報処理安全確保支援士

# 本試験にて問われる知識について
まず、Google Cloudの内容は「CS知識」+「Google Cloud特有の知識」が組み合わさっています。
その為、仮に応用情報等を所持していても落ちる可能性は多いにあります。

私の場合は、CSに関する基礎知識はある程度ありますがGoogle Cloud特有の知識が一切無かった為、絞って勉強しました。
その為、本記事ではGoole Cloud特有の知識の増やし方について記載していきます。

# 勉強方法
以下の手順を上からやっていきました。

## 1.学習本を読む
[この本](https://amzn.asia/d/2JoTJok)を利用しました。
まず、お恥ずかしながらGoogle Cloud自体があまりわかっていませんでした...。名前は知ってますけど？程度です。
その為、上記の本を利用して以下の知識を得ようとしました。
1. どんなサービスがあるのか
2. 各サービスの特徴は？

## 2.Udemy問題集を解く
[Udemy問題集](https://www.udemy.com/course/google-cloud-digital-leader6320)を使用しました。
先にいいますが、この問題集はかなり難しくDigital Leaderで問われる深さよりも1段階深いです。
その為、学習本を読んだだけだとおそらく手も足も出ません。

ただ、それで問題ありません。
1週目はおそらく全ての回でボロボロになりますが、そこで復習すれば問題ありません。
私の場合の正答率は、1週目：40-50% / 2週目：85~90%程度でした。

## 3.ExamTopicsを解く
[ExamTopics](https://www.examtopics.com/exams/google/cloud-digital-leader/view/)を使用しました。
こちらはUdemy問題集の後に解いてみてください。
そうすると、自身の知識がかなり付いていることに気づきます。
言語の壁については、翻訳すれば問題ないです。

## 復習の時にしていたこと
基本的には以下の方法を用いて復習していました。
1. ChatGPTを用いる
2. 本を読みなおす
3. [Google Cloud公式ドキュメント](https://cloud.google.com/docs)を読む

大体、ここで解決できます。

# 最後に
意外と難しいです...。
また、今後もAssociateやProfessionalも受験していきますのでその時は都度記事を書いていこうと思います。
Failed to build  gem native extension

備忘録です。

# bundle installが完了しない。
debase 0.2.4.1をインストール中でエラー
```
checking for vm_core.h    extconf.rb faild
could not create makefiile due to some reason, probably lack of necessary
libraries and/or headers. check the mkmf.log file for more details . you may need configuration options.
```
mkmf.logを見てもよくわからない。

# エラーの原因
バージョンが合ってなかったかもしれない。
出典の記事でバージョンを変更してみた。
debase 0.2.4.bata2を指定してインストール、成功。

# 出典
https://qiita.com/kobayashi-masayuki/items/1a50a627d03d50e51e45

# mysql２をインストール中エラー
```
yum install mysql_devel
```
### 気づき
意味もわからずコピペした。

# 出典
https://changineer.info/server/mysql/mysql_installation_linux.html

https://qiita.com/kawara3782/items/7244a422b4446650320c
# 余談
エラーの内容がわかる
# 出典
https://www.geeklibrary.jp/counter-attack/permission-denied/

# 感想
これからエラーを読めるようになりたい。
コマンドの意味を理解したい。
bundleinstallに成功した。
word　図の挿入とアンカー、図番号

Wordで図の挿入をするとアンカーが出てきて、勝手に場所が動いたりして、思うような図のレイアウトができなくてイライラします。ネットで検索してもよく理解できないので、いろいろ試行錯誤してわかったことを書き留めます。
Wordで図を挿入しようとするとき、カーソルは文章のどこかにありますから図はこのカーソルのあるところに挿入されます。この時にはアンカーは出てきません。　図の挿入には「行内」と「文字列の折り返し」の二つのモードがあると考えてください。　「行内」はあくまでも、行の中にまるで文字のように挿入されます。ただし、実際は図の大きさは文字よりも大きいので、不自然なレイアウトになりますが、図がページ幅の時は違和感を感じないので、そのままにしてしまいますが、文字と文字の間に挿入されているため、文章の修正・変更をすると文字数に合わせて変なことが起こります。![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427356/92f750c5-1d41-e71f-ed0e-8188d6349823.png)

これに対応する機能が「文字列の折り返し」です。これを選ぶと文字と文字の間に図が挿入されるのではなく、文章の段落にリンクして場所が自動的に決められます。　リンクしている段落の前にアンカーがつけられます。![キャプチャ4.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427356/86586adb-f128-d538-2001-fdd08b500b9e.png)

段落と図が離れすぎないようにという意味では便利な機能ですが、図が大きくて、文字とのオーバーラップしないような設定やアンカーにしている段落の長さにより、次のような不具合があります。
ページのレイアウト上、段落と少し離れてもいいから、好きなところに図を配置したいときにアンカーは勝手にリンクしている段落を変えますが、Wordはその段落と図を同じページに入れようとします。![キャプチャ5.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427356/c85bb983-3fff-6a3f-ca98-ab3ace46b557.png)![キャプチャ7.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427356/f3930485-be35-ddca-9eba-d3ac253a7f2d.png)


結果、段落の最初が図のページに移動したり、図がページ内に収まらないにも関わらず同じページになったりします。図をページ内に固定しようとして、「ページ上の位置を固定」にしてもこれはページの上とか下とかの固定であって、どのページに配置するかは自動で判別されます。この自動判別がどのように働いているかがわからず、図の配置に関して思うようにならないと感じてしまう人は多いのではないでしょうか。小さい図であれば、アンカーは便利に働きますが、大きな図を使う場合はアンカー先の段落を臨機応変に変えたり、「行内」にして文字としてレイアウトする必要が出てきます。
また、これに関連して図番の挿入をするときに、番号が前後する場合があります。それは、アンカーの位置が前後しているためで、番号の順番は図の位置ではなく、アンカーの位置で自動的に決められます。特に、同じ段落に二つ以上の図がアンカーされていると、順番が前後するこがありますので、一度アンカーの位置をずらして、図番を決めてから、またもとに戻すような工夫が必要です。
さらに、校閲のモードで変更履歴の記録をしていて、図の削除などを行っていると削除した図が変更履歴として残っているため、図番が飛ぶことがあります。　図番を確認するときは、変更履歴を確認することが必要です。
付け加えておくと、図番を挿入するときに図が「行内」に設定されていると、図番も「行内」になりますので、文章の修正で図番位置がずれることがありますので、注意してください。
pyintallerで起きたエラー文の解決[超簡潔]

### PC環境
* Windows11
* PowerShell 7 Preview
* Python 3.12.2
* Pyinstaller 6.4.0 （変更前）
* Pyinstaller 5.13.2 (変更後)

### pyinstallerのインストールとバージョンの確認
```powershell
python -m pip install pyinstaller
python -m PyInstaller -v
# 6.4.0
```

### 実行ファイルの作成

下記のコマンドで問題なく実行ファイルは出力される。

```powershell
python -m PyInstaller .\test.py
```

```python[test.py]
import tkinter
tkinter._test()
```

### コンソールを開かずにGUIを表示する
この場合はpyinstallerのバージョンを下げないとうまく処理されない。

```powershell
pip uninstall pyinstaller
pip install pyinstaller==5.13.2
python -m PyInstaller -v
# 5.13.2
```

それで下記を実行するとうまく処理されるはずである。
```powershell
python -m PyInstaller --noconsole .\test.py
```

### 参考文献
https://bakooo.com/hobby/program/pywin32error-225/

https://qiita.com/omossan7182t/items/ccc95de88a079596bf7a
念願のRaspberry Piをゲットし、Ubuntu desktopを入れました！

　前からRaspberry Piを気になっていたので、最近はReverse ssh tunnelを試したいという目標があったので入手しました。Reverse ssh tunnelに関する記事はまた今後投稿する予定です。

　まずは下記のAmazonからRaspberry Pi4を購入しました。ただ、想定外のことが起きる可能性がある前提で、いろいろ自分で調べる必要があることを念頭に置いて購入した方がいいと思います。
https://www.amazon.co.jp/gp/product/B08HVLB5GZ?ref=ppx_pt2_dt_b_prod_image

　物理セットアップはマニュアルとAmazonのページを参考して、完成しました。
![IMG_0027.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2991207/7184370b-fd80-440a-2bcc-fbd7c3dfa472.jpeg)
![IMG_5911.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2991207/7194c655-39b6-fe0f-3789-68b43407a2ac.jpeg)
![IMG_5915.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2991207/07dca41d-4458-5d1d-e407-dbe905d933af.jpeg)

　ちなみに、Amazonのレビュー欄にある他の購入者のコメントはとても参考になりました。結局自分の他の購入者とクリアケースが開けづらいとか、ファンが機能しない、プリインストールしたNOOBSも起動しないなど同じ問題に遭遇しました。取り扱い店に問い合わせるのもいいですが、やっぱり自分で調べて、手を動かすのは一番早いです！

　そのあとは、Raspberry Piを起動してOSをインストールします。
NOOBSをプリインストールした付属のSDカードを差し込んで起動するはずだったんですが、何も反応なかったので自分でUbuntuを入れようと決めました。

　豆知識として、NOOBS（New Out Of the Box Software）とは、Raspberry Piが作成し、2013年6月にリリースされたOSインストーラーです。
参照：https://jp.minitool.com/partition-disk/installing-noobs-on-sd-card.html　

　Ubuntu desktopをインストールするために参考した記事はこちらです：
　https://zenn.dev/karaage0703/articles/d99d874ff750d8

　Raspberry Pi Imagerでは最新のUbuntu Desktop23.10は利用可能なので、SDカードに焼きました。
　Raspberry Pi Imagerの操作画面からOperating System ->  Other general-purpose OS -> Ubuntu -> Ubuntu Desktop 23.10(64bit)を選択して、SDカードに焼きます。
![Screenshot 2024-02-23 at 13.03.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2991207/eeb033f5-311f-d4da-2dce-e3b17b3a7bd5.png)

　そのあとはSDカードをRaspberry Pi本体に差し込み、Ubuntu Desktop 23.10 OSをインストールします。

　外付けのアダプター経由だと、モニター、マウス、キーボードは識別されなかったため、直接付属のHDMIケーブルと事前に準備した有線マウスと有線キーボードRaspberry Pi本体に挿しました。
![IMG_5919.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2991207/d953d413-1a4f-b4ce-0946-b3f56a6045bf.jpeg)

　すると無事モニター、マウス、キーボードが無事識別されてUbuntu desktopのインストールができました！
![IMG_5921.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2991207/c7317a6d-81c2-c3e0-6372-9f26d08310a6.jpeg)

　もしRaspberry Piが起動しない（モニタが映らない）ことに遭遇したら、ぜひこちらの記事をご覧になってください：https://qiita.com/karaage0703/items/97808dfb957b3312b649

　今後SSHサーバとして利用したいため、とりあえず前に作成した記事通りパッケージopenssh-serverをインストールしました。
前に投稿した記事：https://qiita.com/totoro-suika/items/bc7203ce6a21b659b606

　そしてサーバとしてDHCPでIPが頻繁に変更されるを避けるために、固定IPに変更します。
```
$ nmap -sP Subnet
```
　上記のコマンドで空いているIPを調べて、Raspberry Piに設定しました。

　次はReverse ssh tunnelの構築に着手しますので、投稿をお待ちください！
汎用人工知能　AGI「Artificial General Intelligence」とは？

AGIが実用化される時期は、何年後なのか？
--
多くの専門家は、今後10年から50年の間に実現可能であると予測していますが、技術的な課題や倫理的な問題など、多くの障壁が存在します。ソフトバンクの孫さんは、10年以内に実現させるとおっしゃっています。

__AGIは、人間の能力を拡張し、より良い社会を作るための強力なツールとなる可能性を秘めています。__

現在、AGIはまだ実現しておらず、人類が開発したAIは特定のタスクや領域に特化したものが主流です。一般的な知識や幅広い能力を持つ真のAGIはまだ達成されていません。ただし、その方向に向けていくつかの研究やプロジェクトが進行しています。

例えば、OpenAIのGPT（Generative Pre-trained Transformer）シリーズは、大規模なデータセットを用いてトレーニングされ、多様なタスクに対応できる柔軟性を持つ言語モデルとして注目されています。しかし、これはまだ特定の知識領域に特化しており、完全なAGIではありません。

AGI「Artificial General Intelligence」と従来のAIの違い
--

__従来のAIは__
特定のタスクをこなすように設計された「特化型AI」です。
例えば、囲碁や将棋をプレイするAI、画像認識を行うAI、翻訳を行うAIなどがあります。これらのAIは、それぞれ特定の分野において人間を超える能力を発揮していますが、人間のように幅広い知的能力を持つわけではありません。

__一方、AGIは__
人間のように幅広い知的能力を持つ「汎用型AI」です。AGIは、特化型AIのように特定のタスクに特化しているわけではなく、様々なタスクを学習し、こなすことができます。

__AGIは「Artificial General Intelligence」の略称で、日本語では「汎用人工知能」と呼ばれます。これは、人間のように幅広い知的能力を持ち、様々なタスクを学習し、実行できる人工知能のことを指します。__

__特徴__
--
__汎用性__ 
特定の領域に特化せず、様々な分野の知識や技能を扱える
__学習能力__ 
経験から学習し、知識や能力を向上させることができる
__問題解決能力__ 
複雑な問題を分析し、解決策を導き出すことができる
__推論能力__ 
不完全な情報からでも、論理的に推論し、結論を導き出すことができる
__創造性__ 
新しいアイデアを生み出し、新しいものを創造することができる

__活用されうるシーン__
--
__医療__ 
診断、治療、薬剤開発など
__科学__ 
研究、開発、論文執筆など
__教育__ 
個別指導、教材作成、評価など
__ビジネス__ 
意思決定、戦略策定、顧客対応など
__製造__ 
設計、生産、品質管理など

__AGIの開発状況と、実用化に向けた課題__
--
__1. AGIの開発状況__
--
近年、AGI開発は目覚ましい進歩を遂げています。

__AlphaGo__
2016年、Google DeepMindが開発したAlphaGoは、囲碁世界チャンピオンを破り、人工知能の可能性を世界に知らしめました。
__GPT-3__
2020年、OpenAIが開発したGPT-3は、人間と見分けがつかない文章生成能力を持ち、大きな話題となりました。
__PaLM__
2022年、Google AIが開発したPaLMは、5400億のパラメータを持つ巨大言語モデルで、様々なタスクをこなす能力を示しています。

これらの技術は、AGI開発の重要なステップであり、今後さらに改良が進むと期待されています。

__2. AGI実用化に向けた課題__
--
__技術的な課題__

__学習データ不足__ 
AGIを学習させるためには、膨大な量のデータが必要です。
__汎化能力の向上__ 
AGIは、学習した知識を様々な状況に適用できる必要があります。
__安全性__ 
AGIが人間に危害を加えないようにする必要があります。

__倫理的な課題__

__責任の所在__ 
AGIの行動責任の所在は誰が負うべきか、明確な基準が必要です。
__差別__ 
AGIが人種や性別などの属性に基づいて差別しないようにする必要があります。
__雇用への影響__ 
AGIが普及すると、多くの仕事が失われる可能性があります。

__3. AGI実用化に向けた取り組み__
--
これらの課題克服に向け、世界中の研究者や企業が様々な取り組みを進めています。

__国際的な研究プロジェクト__

__Human Brain Project__ 欧州連合が主導する、人間の脳を解明するプロジェクト。
__Brain Initiative__ 米国政府が主導する、脳科学研究を推進するプロジェクト。

__企業による研究開発__

__Google AI__ AGI開発に積極的に投資している。
__OpenAI__ 非営利の研究団体で、AGI開発に取り組んでいる。
__Amazon Research__ AGIを含む様々なAI技術の研究開発を推進する組織。
__Amazon AI__ AWSが提供するAI/MLサービスの開発・提供を行う組織。

AWSのAGI開発における具体的な取り組み
--
__1. Amazon SageMaker__

Amazon SageMakerは、機械学習モデルの開発、トレーニング、デプロイを支援するサービスです。AGI開発においても、モデルの開発やトレーニングに活用できます。

__2. Amazon Rekognition__

Amazon Rekognitionは、画像や動画から物体や人物を認識するサービスです。AGI開発においても、視覚情報処理の研究に活用できます。

__3. Amazon Lex__

Amazon Lexは、自然言語処理サービスです。AGI開発においても、音声認識や対話システムの研究に活用できます。

__4. AWS DeepRacer__

AWS DeepRacerは、強化学習を用いて自動運転車を開発するプラットフォームです。AGI開発においても、強化学習の研究に活用できます。

参考
SoftBank World 2023 孫 正義 特別講演 AGIを中心とした新たな世界へ
https://www.youtube.com/watch?v=h3052XnZhVI
Unity ProCamera2Dの使い方

## ProCamera2Dとは
2Dにおける複雑化カメラ制御をおこなうためのAsset。有料。
ロックマンみたいに端に移動すると切り替わる制御
キャラクタの移動にゆっくり追従する制御
ボスと敵の両方を見やすい位置にとらえる制御
ある場所に差し掛かると拡大するような制御　
フェードインフェードアウト　などなど。

## 使い方
ImportしたAsset内のProCamera2D>ProCamera2DをMainCameraへD＆D
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2294598/90a540ba-22ee-1269-c1dc-f6be8c335335.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2294598/c9b14220-9dfd-8a7e-9a69-9e4a52b818f7.png)

カメラで追いたいゲームオブジェクトをD＆D
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2294598/1d1854f2-017e-ff16-1539-73615e869a3f.png)
EXTENSIONSのCamera Windowをクリック、コンポーネントが自動で追加される。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2294598/daa85da0-f893-6f09-588a-34c655627339.png)

Scene上に赤い四角がでてくる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2294598/13fbd2e2-c36f-32ec-283c-6c6bdbedfec3.png)
これで準備は完了。実行してゲームオブジェクトを動かしてみると。![fwfdaf.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2294598/8af7a38a-f17a-7275-ef10-394f7117f554.gif)
赤い四角にそってカメラがいい感じ動いてくれている。

EXTENSIONSはカメラの動かし方のオプションなのでいろいろ動きを変えることができる。

## 画面の揺れを追加
EXTENSIONSからShakeを追加
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2294598/9d59a1e1-55b6-9d50-f2d7-2513b5d00f2d.png)
Shake Presetsからプラスマークおして、PlayerHitを選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2294598/a8de55a3-0db3-5556-17d6-fdf82691060c.png)
実行してするとShakeボタンが押せるのでおす。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2294598/a5554fe2-8b1e-d46a-175c-448c101cd3df.png)

![shakge.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2294598/e71886fc-e4f4-ca15-10f1-f433585c8b23.gif)

## 補足
すこしつまずいたところの備忘録

### カメラがうごかない
カメラのPriorityを確認。動かしているカメラで描画しているかを確認しよう。数字が大きいカメラで描画している。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2294598/7a88c80e-f85e-0ec5-f3f4-0e43df45cfc0.png)
カメラの映している場所　Projectionの設定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2294598/b9be4fdf-cbbc-c9ea-5411-bc71be5d5b79.png)
画面上のどこに描画するかの設定OutputのViewport Rectも確認する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2294598/73826e59-34fa-1929-e89c-73a1106814d1.png)

### 赤い四角が表示されない
ギズモの表示設定を見直す
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2294598/0fe7bbbf-1ec7-cc54-6562-c33502a39572.png)
一括で設定しているつもりがスクロールするとチェックが入っていない項目があったりするので注意
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2294598/444c03bc-8a1a-6385-a16f-c7c1a13316fe.png)

### カメラの制御しているスクリプトを確認
独自のScriptでカメラを制御していないか確認しよう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2294598/a152d451-3b12-824b-3d67-78afe2b4ac40.png)


## 参考サイト

https://kan-kikuchi.hatenablog.com/entry/ProCamera2D

https://temoshiblog.com/procamera2d/
React Routesでページ遷移しなかった話

## 始めに
現在Udemyの講座でReactを学習しているのですが、React Routerがv5からv6に変わった関係でRoutesの使い方がわからず...
ネットで調べてもよくわからず苦戦した話と、その内容を記載します！

## 今回の間違い
```react
    <BrowserRouter>
      <div className="App">
        <p>
          HOMEは<Link to={`home`}>こちら</Link>
        </p>
        <Routes>
          <Route path={`home`} element={<Home />} />
          <Route path={`page1`} element={<Page1 />}>
            <Route path={`detail1`} element={<Page1DetailA />} />
            <Route path={`detail2`} element={<Page1DetailB />} />
          </Route>
          <Route path={`page2`} element={<Page2 />} />
        </Routes>
      </div>
    </BrowserRouter>
```

このコードを記述することによって、page1に記述されているdetail1・detail2のページリンクから、それぞれのページにリンクすると思っていました。
ですがurlは変わるけど、実際のページ遷移がしない...

## 正しいコード
```react
    <BrowserRouter>
      <div className="App">
        <p>
          HOMEは<Link to={`home`}>こちら</Link>
        </p>
        <Routes>
          <Route path={`home`} element={<Home />} />
          <Route path={`page1`}>
            <Route index element={<Page1 />}/>
            <Route path={`detail1`} element={<Page1DetailA />} />
            <Route path={`detail2`} element={<Page1DetailB />} />
          </Route>
          <Route path={`page2`} element={<Page2 />} />
        </Routes>
      </div>
    </BrowserRouter>
```

修正箇所は以下の通りです！

```react
          <Route path={`page1`} element={<Page1 />}>
            <Route path={`detail1`} element={<Page1DetailA />} />
            <Route path={`detail2`} element={<Page1DetailB />} />
          </Route>
```

```react
          <Route path={`page1`}>
            <Route index element={<Page1 />}/>
            <Route path={`detail1`} element={<Page1DetailA />} />
            <Route path={`detail2`} element={<Page1DetailB />} />
          </Route>
```

## 終わりに
今回この箇所以外にも/を入れる箇所とそうでない箇所の違いもよくわかりませんでした...
またその解決方法についても別途記載したいと思います！
かなり基本的なことで躓きましたが、今後もまだまだつまずく予定なので、どんどん学習進めていきます！
Kali Linux on WSL の win-kex でシェルが bash から変更できない

# はじめに

WSL に Kali Linux をインストールしてデフォルトシェルを chsh で zsh へ変更して、windows terminal では問題なく zsh に変更できているのに、win-kex でターミナルエミュレータを起動すると bash になってしまう。

# 原因

`/usr/bin/win-kex/xstartup` で SHELL 環境変数が bash で決め打ちされている。
以下のように変更することで zsh になる。

```
#export SHELL=/bin/bash
export SHELL=/bin/zsh
```

# おまけ

ターミナル起動時のワーキングディレクトリが `/usr/lib/win-kex/pulse` になってしまう。
`/usr/bin/kex` の中で `cd -` が期待通りの動作していないようなので、以下のように修正
pull request 出してみたけど、どうかな。

```
*** /var/tmp/kex    Fri Feb 23 12:45:40 2024
--- /usr/bin/kex    Fri Feb 23 12:57:03 2024
***************
*** 672,680 ****

  function start-sound() {
      print-verbose "Starting sound"
      cd /usr/lib/win-kex/pulse
      ./pulseaudio.exe -F config.pa >/dev/null 2>&1 &
!     cd - >/dev/null 2>&1 &
  }

  function stop-sound() {
--- 672,681 ----

  function start-sound() {
      print-verbose "Starting sound"
      cd /usr/lib/win-kex/pulse
      ./pulseaudio.exe -F config.pa >/dev/null 2>&1 &
!     cd - >/dev/null 2>&1
  }

  function stop-sound() {
  ```
LeetCode 2402. Meeting Rooms III の解き方メモ

https://leetcode.com/problems/meeting-rooms-iii/description/?envType=daily-question&envId=2024-02-18

LeetCode 2402. Meeting Rooms III の解き方メモです。それほど難しい問題ではないはずですが、問題の把握にてこずったので、考え方を共有しておきたいと思います。

問題の内容はおおよそ以下の通りです。

- N個の会議室とM個の会議予定が与えられる
- ルールにしたがって、会議室予約を行う
- すべての会議室予約が完了したとき、もっとも利用数の多い会議室の番号を求める。そのような会議室が複数ある場合は、もっとも番号が若いものを答えとする

把握に苦労したのが、会議室予約のルール。問題文がややわかりずらい気もするのですが、まとめるとおおよそ以下の通りになります。

- 会議室予約は開始予定時刻の昇順で処理する
- 空室がある場合は、その部屋を使う。空室が複数ある場合は、番号がもっとも若いものを使う
- 空室がない場合は、一番最初に空室になる部屋を使う。そのような部屋が複数ある場合は、番号がもっとも若いものを使う
    - 空室ができるまで待って、それから会議を始めるイメージ。そのため、会議開始時刻が遅くなっても、もともとの会議予定時間はそのままにする必要がある
    - 例. [8, 12)という会議予定について、時刻8の時点で空室がなく、時刻10になって初めて空室ができたとする。このとき、この会議は[10, 14)の時間で開催される

これをそのまま実装すればよいです。計算量は$O(M \log M + N \times M)$。$M \log M$はM個の会議予定を最初にソートする分ですね。$N \times M$は「空室があるかないかを探す・一番最初に空室になる部屋を探す」部分で、ここがボトルネックになりそうですが、$N \leqq 10^2, M \leqq 10^5 \Rightarrow	N \times M \leqq 10^7$と制約が小さいため、すくなくともRustのような高速な言語であれば問題ありません。

```rust
use std::cmp::Reverse;

impl Solution {
    pub fn most_booked(n: i32, meetings: Vec<Vec<i32>>) -> i32 {
        let n = n as usize;
        let mut meetings = meetings;
        meetings.sort_unstable_by_key(|meeting| meeting[0]);

        let mut reserves = vec![0i128; n];
        let mut counter = vec![0i128; n];

        for meeting in meetings {
            let s1 = meeting[0] as i128;
            let e1 = meeting[1] as i128;

            // 空室があれば、その部屋を使う。
            // 空室が複数ある場合は、番号がもっとも若いものを使う。
            if let Some(room) = (0..n).filter(|&i| reserves[i] <= s1).min() {
                reserves[room] = e1;
                counter[room] += 1;
            } else {
                // 空室がない場合は、一番最初に空室になる部屋を使う。
                // そのような部屋が複数ある場合は、番号がもっとも若いものを使う。
                let room = (0..n).min_by_key(|&i| (reserves[i], i)).unwrap();
                reserves[room] = reserves[room] + (e1-s1);
                counter[room] += 1;
            }
        }

        // 会議の使用回数が多い部屋を選択する。
        // そのような部屋が複数ある場合は、番号がもっとも若いものを使う。
        (0..n).max_by_key(|&i| (counter[i], Reverse(i))).unwrap() as i32
    }
}
```
ドキュメントをいい具合に残そうの会

最近、『[エンジニアのためのドキュメントライティング](https://www.amazon.co.jp/%E3%83%A6%E3%83%BC%E3%82%B6%E3%83%BC%E3%81%AE%E5%95%8F%E9%A1%8C%E8%A7%A3%E6%B1%BA%E3%81%A8%E3%83%97%E3%83%AD%E3%83%80%E3%82%AF%E3%83%88%E3%81%AE%E6%88%90%E5%8A%9F%E3%82%92%E5%B0%8E%E3%81%8F-%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AE%E3%83%89%E3%82%AD%E3%83%A5%E3%83%A1%E3%83%B3%E3%83%88%E3%83%A9%E3%82%A4%E3%83%86%E3%82%A3%E3%83%B3%E3%82%B0-%E3%82%B8%E3%83%A3%E3%83%AC%E3%83%83%E3%83%89%E3%83%BB%E3%83%90%E3%83%BC%E3%83%86%E3%82%A3/dp/4800590833)』という本を読みました。
非常にためになる内容だったので、本書であがったいくつかのポイントを私なりにまとめてみました。

また、エンジニアにとってのドキュメントは種類が多く、それぞれのニーズとそれに合わせたフォーマットも違うため、 **良いドキュメントとは何か？** を一概に述べることは難しいです。
個人的には、「<INS>ほぼ知識のない人が読んでも再現できる・解決できる</INS>」ということが大事なのではないかと思っています。

そこで、本記事ではドキュメントの範囲を少し絞って、想定される読者をエンジニア寄りに考えて書いています。ご了承ください。

### 目次

本記事では

- ドキュメントを作成する前
- ドキュメントを作成する時
- ドキュメントを作成した後

それぞれのタイミングにおけるポイントを挙げていきます。


### 📑 ドキュメント作成前のポイント

:::note
フリクションログをつくる
:::

フリクションログとは、ある**ユーザー[^1]の体験を記録するログ**のことであり、「期待する振る舞い（挙動）」と「実際の振る舞い」を照らし合わせ、そのギャップをフリクション（摩擦/衝突）として記録する、というものです。

フリクションが多ければ、その箇所が **改善ポイント＝ユーザーの「ニーズ」** となり、体験を補助するためにドキュメントを作るきっかけになります。

[^1]:本書での「ユーザー」とは、開発者や顧客などにかかわらずサービスに触れるあらゆる人をイメージしていますが、本記事ではより開発者にフォーカスした人物像をイメージしています。


### 📖 ドキュメント作成時のポイント

:::note
見出しで全てを説明すること
:::

ドキュメントを読む**ユーザーの多くは、基本的に流し読み**をします。隅から隅まで読むことはしません。
そのため、ドキュメント内のブロックを明確にし、段落を分け、その内容が一目で分かるような見出しをつけておくことで、読みやすいドキュメントになります。


:::note
手順を書くこと
:::

個人的に最も大切なポイントは **「着手〜完了」のプロセスを明確にすること**です。
そうすることで、似たプロジェクトや障害に取りかかる際、「何をするべきか」に素早くリーチでき、業務の最適化に繋がります。

例えば、環境構築で踏んだ手順、バグ発生の再現手順、原因解明の調査手順など…
どのようなドキュメントでも、手順を明記しておくことは外せないでしょう。

:::note
完璧さを求めすぎないこと
:::

本書によれば、ドキュメントを作成するときの**最も大きな障害は、書き出すまでの白紙の状態**だそうです。

なにはともあれ書いてみる、という気軽さでドキュメントを作成しましょう。箇条書きでも、書きたいところから詳しく書いても、それが順不同でも、最初のドラフトでは無問題です。


### 📔 ドキュメント作成後のポイント

:::note
ドキュメントオーナーを明確にすること
:::

**ドキュメント更新の責務を明確にすること**は、良いドキュメントには欠かせない条件です。内容の更新をする担当者をつけることで、ドキュメント内の情報が古くなったまま放置される問題を防ぎます。

ドキュメント作成者が必ずしもドキュメントオーナーとは限りませんが、内容について訊かれたときの対応を考えると、なるべく揃えておいた方がよいかもしれません。


:::note
ドキュメントへの導線を考えること
:::

せっかく見やすいドキュメントを作成しても、アクセスしにくい場所に保管されていたらもったいないです。

**適切な場所にドキュメントを置くこと**は、良いドキュメントの重要な条件です。また、メンテナンスの面倒を避けるためにも、ひとつのドキュメントは一箇所に置くようにしましょう。




### さいごに
本書ではリリースノートやREADME、バグ報告レポートのテンプレート、あるいはコードに残しておくコメントの話もあり、エンジニアとして触れるすべてのドキュメントに関するtipがたくさん紹介されていました。

気になった方はぜひお手に取ってみてください📖 おすすめ本です！
railsでjava scriptやcssを使用するには？

Railsでjava scriptやCSSファイルを使用する場合、一般的には2つの方法があるそうです。（どっちを使えばいいの？と思いますが、初学者にはまだわかりません、、、）

## 1. CDNからの読み込み
外部のライブラリやフレームワークを使用する場合、そのファイルをCDNから直接読み込むことができます。これにより、アプリケーションのレスポンスタイムが改善され、ライブラリのバージョン管理や更新が簡素化されます。
※「CDN」はContent Delivery Networkの略で、**インターネット経由でファイルを配信する仕組み**のことです。

###  　例　jQueryやBootstrapを読み込む場合
```html
<!DOCTYPE html>
<html>
　　<head>
　　　　<title>sample</title>
　　　　<!-- jQuery -->
　　　　<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
　　　　<!-- Bootstrap CSS -->
　　　　<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">
　　</head>
　　<body>
　　</body>
</html>
```

    
## ２. アセットパイプラインを使用したローカルのファイル

アプリケーションで独自のコードを使用する場合、アセットパイプラインを介してローカルに保存したファイルを読み込むことができます。この場合、ファイルはapp/assets/javascriptsやapp/assets/stylesheetsディレクトリ内に配置されます。
そもそもアセットパイプラインて何、、、？って感じですよね。

[アセットパイプラインについての解説（Railsガイド）](https://railsguides.jp/asset_pipeline.html)
[アセットパイプラインについてのわかりやすい解説記事](https://qiita.com/uma002/items/9a94ebc93c5f937502cd)

### 例　jQueryやBootstrapを読み込む場合
    
- app/assets/stylesheetsにapplication.scssを作成します。application.scssに以下のように記述します
    
    ```scss
    // Bootstrapのインポート
    @import "bootstrap";
    ```
    
    - app/assets/javascripts/application.jsファイルに以下のように記述します
    
    ```jsx
    //= require jquery3
    //= require bootstrap-sprockets
    ```
    
    - RailsアプリケーションのレイアウトファイルでBootstrapのCSSとJavaScriptを使用するために、以下のように記述します
    
    ```html
    <!DOCTYPE html>
    <html>
    　　<head>
     　　 <title>sample</title>
    　　  <%= stylesheet_link_tag 'application' %>
    　　  <%= javascript_include_tag 'application' %>
   　　 </head>
   　　 <body>
   　　 </body>
    </html>
    ```
Undeliverable mail -- (Undelivered): 554 5.4.7 >>> [internal] exceeded max time without delivery

配信不能メール -- (未配信): 554 5.4.7 >>> [内部] 配信されずに最大時間を超えました

+ [Undeliverable mail -- (Undelivered): 554 5.4.7 >>> [internal] exceeded max time without delivery](https://trailhead.salesforce.com/trailblazer-community/feed/0D54S00000Brg4l)

:::note alert
Scenario 1: Email from Salesforce via Office 365 (no relay as this is not a list email): DKIM -- pass (signature was verified) 

Scenario 2: Email from Salesforce via list email (email relay) through Office 365: DKIM = none (message not signed) 

```
Original undeliverable message is:  (Undelivered): 554 5.4.7 [internal] 
>>> exceeded max time without delivery 
```

:::

:::note
I was able to figure this out but it was so long ago, I’m not really for sure. I believe it was setting the CNAME dns for Salesforce.

I see in my notes:

CNAME sfdc2023._domainkey

sfdc2023.d05ypv.custdkim.saleforce.com
CNAME mail

sfdc2023.d05ypv.custdkim.saleforce.com
CNAME sfdc2023b._domainkey

sfdc2023.d05ypv.custdkim.saleforce.com
I believe it was something with the DNS, when it was first set up it was 2019.sfdc._domainkey. We switched providers and had to reset everything in 2023.

私はこれを理解することができましたが、かなり前のことなので、実際には確信がありません。Salesforce の CNAME DNS を設定していたと思います。

私のメモを見ると次のようになります。

CNAME sfdc2023._domainkey

sfdc2023.d05ypv.custdkim.saleforce.com
CNAMEメール

sfdc2023.d05ypv.custdkim.saleforce.com
CNAME sfdc2023b._domainkey

sfdc2023.d05ypv.custdkim.saleforce.com
DNS に関する問題だったと思います。最初に設定したときは 2019.sfdc._domainkey でした。プロバイダーを変更したため、2023 年にすべてをリセットする必要がありました。
:::

+ [554 5.7.1 [HM08] Message rejected due to local policy. icloud.com email](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007eqefp)

:::note
Have you configured SPF and DKIM?

Does iCloud Mail use email authentication?

iCloud Mail authenticates all inbound emails using SPF and DKIM. We also publish SPF records for our domains and sign all of our outbound emails with DKIM.

https://support.apple.com/en-us/102322
:::
Ruby シンボルとキーについて

##   Rubyにおけるシンボルとキーについての関係性について

Railsでストロングパラメータの設定を行う際に、シンボルとキーの理解が整理できていないことに気がついたので、こちらでまとめておこうと思います。

```ruby
 def site_params
    params.require(:site).permit(:name, :subtitle, :description, :favicon, :og_image, main_images: [] )
  end
```
私が気になった点は、`:subtitle`と`main_images: []`の書き方の違い(:の位置)です。

`:subtitle`
単一のデータを所有するカラムの記載の仕方。

`main_images: []`
複数のデータを所有するカラムの記載の仕方。
ストロングパラメータに追加する際は、**末尾に追加**する。
そうでないと、Railsの規約に従っていないらしく、エラーが出る。

今回の話題は、この`:subtitle`、`main_images:`の部分について。


### キーの種類
`:subtitle`、`main_images:`
これらは、キーという。
キーの種類として①文字列と②シンボルがある。

**①文字列**

文字列をキーとして使用する場合、キーはダブルクォーテーション（**`"`**）またはシングルクォーテーション（**`'`**）で囲む。

```ruby
hash = {"name" => "John Doe", "age" => 30}
```

**特徴**

1.文字列はその都度新しいオブジェクトが作成されるため、メモリ使用量が増える。

2.文字列をキーとして使用すると、その文字列の内容が完全に一致する必要がある。



**②シンボル**

```ruby
hash = {:name => "John Doe", :age => 30}
```

```ruby
hash = {name: "John Doe", age: 30}
```

**特徴**

1.シンボルはメモリ内で一意のIDを持つため、同じシンボルを複数回使用しても、メモリ上では一つのオブジェクトを参照することになる。

2.特に大規模なアプリケーションや頻繁にアクセスされるキーに対して、パフォーマンスが向上する。

### `:`の位置の違いについて
`:name`と`main_images:`はどちらもシンボルを指しており、記載の仕方に違いがあるが、それぞれがシンボルであることに変わりはない。
```
key : value
```
上記のように、valueの記載（今回は[]）も必要なときは、`main_images:`のように、キーの後に`:`をつける方が可読性の向上面からよく使われる。


### まとめ
一般的には、上記の理由から**シンボル**が使用されることが多い。

※誤りがあれば、教えていただけますと幸いです。🙏

### 参考記事
https://zenn.dev/atsushi101011/articles/92d8b9b45d4f9d
セッションとは

### セッションとは
セッションとは、サーバー側で作られ、特定のユーザーに関連するデータを一時的にを保管します。
セッションのデータの保管先は、サーバー側になります。
セッションで調べると、大体一緒に出てくるCookieのデータはブラウザに保管されます。

### セッションを使ってみよう
PHPでは、session_start という関数があり、それを使用することで簡単にセッション関数が利用できます。
まずはPHPファイルに書き込んでみましょう。
```php:PHP
  <?php
  session_start();
  ?>
  ```
  これだけでセッション関数が利用できるようになります。
  session_start();を実行することにより、$_SESSIONというスーパーグローバル変数が利用可能になります。
  スーパーグローバル変数は、連想配列で値が格納されます。
```php:PHP
<?php
session_start();
$_SESSION['food'] = 'hamburger';
print_r($_SESSION)
?>
```
上記の記述での出力結果は Array ([food] => hamburger) になります。
### セッションを削除してみよう
```php:削除
session_start();
unset($_SESSION['food']);
print_r($_SESSION)
```
上記の記述での出力結果はArray ( ) になります。
### 利用例
session_start関数の利用することで、例えばお問い合わせフォームで入力されたデータを保存して別の画面でもデータを利用するというときにも使用することが可能です。

### 最後に
セッションについて調べてみました。
上手く扱えば非常に便利ですが、その反面で個人情報などを扱うときには漏えいのリスクがあります。リスクヘッジを行うためにもXSS対策なども勉強し、漏えいリスクの低いシステム作成を行っていきます。
Cookieって何？

最近、Cookieとセッションについて調べる機会がありました。
今回はCookieについて少し解説します。
### Cookie(クッキー)とは
Cookieとは、ログインした時の情報やそのユーザー情報をブラウザに記録する仕組みです。

### Cookieの利用で出来ること
例えばそのCookieを利用することで、ユーザーが見ているものなどを記憶し、興味があるものや広告や記事を選択し、表示させることで勝手に情報が集まりやすくなります。
また入力した情報を記憶できるので、一度入力した情報を再度入力するといったことも可能になります。

### Cokkieの注意点
非常に便利なCookieですが、個人情報なども保存できるためトラブルが起きたさいに個人情報の漏えいが起こる危険性があります。
なのでこまめにCookieを削除したり、そもそもCookieを利用しない設定にする、などの方法でユーザー側での対策も可能になります。

### 最後に
今回は短いですが、簡単にCookieについて触れてみました。
今後、僕もエンジニアとして個人情報を扱うときもあると思います。自分が作成したシステムで漏えいが起きないようにしっかり勉強していきます。
PHPとは

## PHPとは
PHPは意識してみると至る所で使用されています。
PHPはユーザーが入力した情報を取得し保管をすることもできます。
その機能を使用すれば分かりやすい所でいうと、webサイトやアプリの登録やログインのシステム作成が可能です。
また他にも、様々な会員情報を自動入力する機能を実装することでユーザーの負担を減らすことも可能です。

### PHPを書いてみよう
PHPで画面出力するには echo が必要です。
```php:php
<?php
echo "Hello world";
?>
```
この記述により画面上では、Hello world が出力されます。

またPHPはHTMLに記述も可能です。
```php:HTML
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<?php echo "Hello world"; ?>
</body>
</html>
```
HTMLに記述する際は、基本的にbodyタグの中に書きます。
上記の書き方で出力が可能です。
```php:HTML
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<h1><?php echo "Hello world"; ?></h1>
</body>
</html>
```
このように例えばh1タグで囲むことによりタグの役割を持たせることも可能です。
### 変数への代入
長い文章を入力するときに毎回入力するのは、手間になり入力ミスにも繋がります。
そんな時は変数に代入すると便利です。
```php:変数に代入
$a = "おはようございます、こんにちは、こんばんは";
echo $a;
```
echo $a; で、おはようございます、こんにちは、こんばんはが画面に出力されます。
今回は、$aという変数に代入しました。
コード量が増えたときのためにも分かりやすい変数名を付けるようにしましょう。
変数名は基本的には自由に決められますが、数字のみや数字から始まる変数名はつけることが出来ません。
また変数は再代入が出来るので、その点も注意しましょう。
```php:再代入の例
<?php
$word = 'おはようございます';
 
$word = 'こんばんは';  
echo $word; 
```
この場合だと最後に$wordに代入したこんばんはが出力されます。
別々の変数名に変更しましょう。

### 最後に
今回は簡単にPHPについて説明しました。
僕自身まだまだ勉強不足ですが、PHPを使いこなすことによって作成できるものの幅がぐっと広がるので、少しずつでも理解を深めていきます！
【書評】「技術書」の読書術

## はじめに

私は情報工学を学ぶ大学4年生で、来年度から大学院進学予定の者です。研究活動を行う学生として、技術書や論文を読むことは避けては通れません。そこで、それらを効果的に読む方法はないかと思い調べたところこの本に出会い、読むことにしました。

## 書籍情報

タイトル：「技術書」の読書術

著者：IPUSIRON、増井敏克

出版社：株式会社翔泳社

発行年月：2022年11月

ページ数：269ページ

https://www.shoeisha.co.jp/book/detail/9784798171548


## 概要

**「読書にルールはない」** ということを前提にしながら、「技術書の選び方」「技術書の読み方」「アウトプットの仕方」について著者らが各々の考え方を述べています。

## 印象的な内容

この本は「読書術」というタイトルですが、どういった基準・手順で本を選べば読書における失敗の可能性を抑えられるかといった「選書術」から述べられています。そこでは良本の定義を見直すことができました。
<br>

**良本 = 読むことで目的を達成できる本**
<br>

読書目的は読む本のジャンルによって違います。

人によって違うかもしれませんが、技術書の場合は大抵技術を習得することでしょう。

目的を達成できるような本を選ぶためには、自分のものさしで測る必要があるのです。
<br>

他の人が目的を達成できて良本だと評価したとしても、自分もまた同じように目的を達成できるわけではありません。

出来杉くんが理解できても、のび太が理解できるかわからないということです。

また、のび太が満足する内容であっても、出来杉くんが満足するかわかりません。

つまり、技術書を選ぶときはレベルを見極め、自分と合うか考える必要があるのです。
<br>

私は「入門」という言葉に釣られ、失敗したことがあります。

これからは書店に出向き、技術書のレベルを感じてから購入しようと思います。

また、レビューは「誰が」書いているかに注意して参考にしたいと思います。

- - - 

私は技術書を読んでいて、序盤は良かったものの急に内容が難しくなり、やる気が失せそのまま読むのをやめた経験があります。

この時、私は1冊で読書目的を達成しようとしていたことが問題だったのです。
<br>

**同じテーマの本を複数冊読む**
<br>

第1部の話にも繋がることですが、同じテーマに関する本はごまんとあります。

そこで、読書目的を達成するために同じテーマの本を複数冊読むのです。

すると、ある本でつまずいてしまっても別の本で理解できるかもしれません。
<br>

これからはできるだけ「入門書」「専門書」「逆引き」の3種類を読もうと思います。

- - -

重要なことはわかっていてもなかなかできないのがアウトプットです。(私だけ)
<br>

**成長したいならアウトプットする**
<br>

この本でもやっぱりアウトプットが重要だとされていました。

アウトプットは間違った理解や習熟度を確認することが目的です。

重要なことはわかっているのに、理解した気になってアウトプットをせずに学習を終わることが多々あります。

そんな私に朗報がありました。
<br>

**アウトプットに「遅すぎる」ことはない**
<br>

この言葉に救われました。

今までアウトプットしてこなかったものたちも、これから恐れずにどんどん発信していきたいと思います。

## まとめ
この本を読んで、「技術書の選び方」「技術書の読み方」「アウトプットの仕方」についてインプットすることができました。

私はアウトプットとして読書記録をつけ、ブログにまとめてみました。

タイトルは「技術書」の読書術ですが、他ジャンルの本にも応用できる内容だったので、エンジニアに限らず多くの人にオススメできる本でした。

学んだ術を使って技術書を血肉にしていきたいと思います。
【pyinstaller】tesseract-ocrを同封して、１つのexeファイルを作成する方法を解説！

## 概要
tesseractで文字認識するpythonプログラムを１つのexeファイル化する際につまづいたので、
その解決方法について紹介します。

## 先に結論！
pyinstaller実行後に作成されるspecファイルに、下記記述を追加します。
specファイルで再度pyinstaller実行すれば、Tesseractを含んだexeファイルが作成できます。

```:main.spec
binaries=[(r'C:\Program Files\Tesseract-OCR', r'tesseract')],
datas=[(r'C:\Program Files\Tesseract-OCR\tessdata', r'data/tessdata')],
```    

`C:\Program Files\Tesseract-OCR`はtesseract.exeが格納されている**フォルダ**のパスです。
ご自身の環境に合わせて、パスを変更してください。

## 作ろうとしていたもの
数字の書かれた画像ファイルから、数字と座標を認識するプログラムを作成。


## 実行環境
OS：Windows 11 Home
VScodeバージョン： 1.82.2
pythonバージョン：3.10
pyinstallerバージョン：5.13.2
pyocrバージョン：0.8.3
tesseract-ocrバージョン：5.3.1

## トラブル発生時の状況
試しにテスト用のプログラムを作成し、
pyinstallerでexeファイルを作成しました。
プログラムの内容は画像から文字を認識し、文字と座標を出力するものです。
プログラムのファイル名は`main.py`です。

<details><summary>main.py</summary>

```python
#ライブラリのインポート
#システムの利用を宣言する
import os
import sys

#PyOCRを読み込む
from PIL import Image
import pyocr
import pyocr.builders

#　メインプログラム関数
def main():
    #画像の読み込み
    file_path = "image.jpg"
    img = Image.open(file_path)

    #builderオプションの設定
    box_builder = pyocr.builders.WordBoxBuilder(tesseract_layout=6)

    #文字と座標を読み取る
    text_position = tool.image_to_string(img,lang="jpn",builder=box_builder)

    #取得した座標と文字を出力する
    for res in text_position:
        print(res.content)
        print(res.position)

if __name__ == "__main__":
    
    # Tesseractのインストール場所をOSに教える
    tesseract_path = "C:\Program Files\Tesseract-OCR"
    if tesseract_path not in os.environ["PATH"].split(os.pathsep):
        os.environ["PATH"] += os.pathsep + tesseract_path

    #OCRエンジンを取得する
    tools = pyocr.get_available_tools() 
    if len(tools) == 0:
        print("OCRエンジンが指定されていません")
        sys.exit(1)
    else:
        tool = tools[0]
    
    #　メインプログラム実行
    main()
```
</details>

１つのexeファイルにまとめるため、`--onefile`を使用します。
```
pyinstaller main.py --onefile --clean
```
pyinstallerを実行した結果、exeファイルは作成できたのですが。実行すると下記内容が出力さました。
```
Running from container, but no tessdata found !
```
tesseractが同封されていないため、出ているメッセージのようです。


## 調査
`Running from container, but no tessdata found`でgoogle検索。

@bass_clef_さんの記事を発見しました。

https://qiita.com/bass_clef_/items/1d0f7b987223f9ddc9f6

記事を参考に下記のようにspecファイルを変更したのですが、うまくいきませんでした。
```:main.spec
binaries=[(r'C:\Program Files\Tesseract-OCR\tesseract.exe', 'tesseract')],
datas=[(r'C:\Program Files\Tesseract-OCR\tessdata\jpn.traineddata', 'data/tessdata'), (r'C:\Program Files\Tesseract-OCR\tessdata\jpn_vert.traineddata', 'data/tessdata')],
``` 



## 解決策

```:参考記事の記述
binaries=[('{tesseract.exe のパス}', 'tesseract')],
datas=[('{*.traineddata のパス}', 'data/tessdata')],
```
`{tesseract.exe のパス}`にexeファイル自体のパス（C:\Program Files\Tesseract-OCR\tesseract.exe）を入れるものだと勘違いしていました。

下記のように、tesseract.exeが格納されている**フォルダ**のパスを記入するのが正解でした。
```:main.spec
binaries=[(r'C:\Program Files\Tesseract-OCR', r'tesseract')],
datas=[(r'C:\Program Files\Tesseract-OCR\tessdata', r'data/tessdata')],
```    

## まとめ
pyinstallerでtesseractを同封するときは、
specファイルにtesseract.exeが格納されている**フォルダ**のパスを記入することが重要！

---
最後まで読んでいただき、ありがとうございました。
コメントいただけるとうれしいです。

ブログ：https://pythonsoba.tech/
Qiita：https://qiita.com/yk5322
Zen：https://zenn.dev/yk5322