OmniAICreator/Qiita-1.07M huggingface dataset:
【AWS】LaravelアプリのTLSをALBにオフロードする

# 環境

```shell
# EC2 OS
$ cat /etc/system-release
Amazon Linux release 2023.4.20240429 (Amazon Linux)

# Laravel
$ php artisan --version
Laravel Framework 11.4.0
```

# 手順

　ALB の TLS 化には SSL/TLS 証明書が必要なので、Route53 でドメインを取得し、Cirtificate Manager で証明書をリクエストする。
　次にポート 443 のリスナーで ALB を作成する。
　最後に Laravel の環境変数、コードに修正を加える。

## 1. ドメインを取得する

Route53 で取得

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/db967948-a15d-53ab-0897-a8477610d682.png)

## 2. SSL/TLS 証明書をリクエストする

リクエスト後の証明書

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/4f3de45e-6183-803b-ca3d-e7faec22bec2.png)

## 3. ALB を作成する

リスナールール

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/e12087b4-97ca-e3d7-258d-8a91d29c7290.png)

ターゲットグループ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/3a746a50-5c77-4223-4ba6-62ea99e00036.png)

## 4. DNS レコードを作成する

A レコードで ALB を指定

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/774c0d30-80db-64c4-31fe-c121a9c5f3ba.png)

## 5. .env を編集する

`ASSET_URL=[https://レコード名]` を追記

```diff:.env
- APP_URL=http://57.180.9.245/ # EC2 の IP アドレス
+ # APP_URL=http://57.180.9.245/ # EC2 の IP アドレス
+ ASSET_URL=https://test.learnersaws.com/
```

## 6. コードを編集する

Chrome で以下のメッセージが表示された。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/d016c32c-af8f-d5a9-0f58-380716ae5c48.png)

以下を記載して解消

```diff:AppServiceProvider.php
<?php

namespace App\Providers;

+ use Illuminate\Support\Facades\URL;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     */
    public function register(): void
    {
        //
    }

    /**
     * Bootstrap any application services.
     */
    public function boot(): void
    {
-        //
+        URL::forceScheme('https');
    }
}

```

# 参考

https://docs.aws.amazon.com/ja_jp/linux/al2023/ug/naming-and-versioning.html

https://zakkuri.life/laravel-chrome-security/
Docker環境でのpry-byebugの使い方

この記事ではプログラミング学習者が学習中に学んだ内容を備忘録も兼ねて記事にして投稿した内容です。内容に誤りなどありましたら、ご指摘頂けると嬉しいです。

## pry-byebugとは
デバッグツールの一種で変数の中身を確認したり、コードの挙動を確認するのに使用します。
今回は変数の中身を確認する為に多用しました。

## pry-byebugのインストール
```ruby:Gemfile
gropu :development do
    gem 'pry-byebug'
end
```

```
$ bin/rails bundle install
$ docker compose exec サービス名　bin/rails bundle install(起動中のDockerに対する場合)
```
インストールが終わったらコンテナを再起動しましょう。

## docker-compose.ymlにコード追記
```docker:dokcer-compose.yml
  web:
    build: .
    image: rails_template:latest
    command: bundle exec rails s -p 3000 -b '0.0.0.0'
    volumes:
      - .:/myapp
      - bundle:/usr/local/bundle
      - node_modules:/myapp/node_modules
    ports:
      - "3000:3000"
    depends_on:
      - db
    tty: true
    stdin_open: true
```
末尾２行を追記します。

`tty: true`はコンテナとホストマシンの標準出力を接続する。
この設定をすることでホストマシンで入力した内容がコンテナに伝わります。

`stdin_open: true`はコンテナとホストマシンの標準入力を接続する。
この設定をすることでコンテナで出力された内容がホストマシン伝わります。

## コンテナ起動時のコマンドについて
通常、Dockerコンテナを起動する場合、イメージが既にあれば`docker compose up`ですが、Dockerコンテナ内部で`pry-byebug`を使いたい場合は`docker compose up -d && docker attach コンテナID or コンテナ名`とします。
※デタッチドモードでコンテナに接続して起動

コンテナID or コンテナ名は`docker ps`コマンドで確認できます。
※画像左端
![docker ps.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3508918/acf0cbaf-a3c3-1dd9-3564-dae9db68c91c.png)


## コード内に`binding.pry`を追記して該当のコードを踏む
コード上に`binding.pry`を記述することで、その行で処理を一時中断して変数の中身を確認したり、挙動を一行ずつ進めるといったことができます。
pry-byebugを作動させるには`binding.pry`記述したControllerなどを実際に動かします。
※下の例では真ん中に記述
```ruby:carts_controller.rb
  def create
    if params[:quantity].to_i <= 0 || params[:quantity].blank?
      @merchandise = Merchandise.find_by(id: params[:format])
      @merchandises_limit = Merchandise.with_attached_image.order(id: 'DESC').limit(4)
      flash[:alert] = '数量は1以上の整数を入力して下さい。'
      redirect_to merchandise_path(@merchandise) and return
    end
    binding.pry
    add_quantity

    if @cart_item.save
      flash[:notice] = '商品が追加されました。'
      redirect_to merchandises_path and return
    else
      @merchandises_limit = Merchandise.with_attached_image.order(id: 'DESC').limit(4)
      redirect_to merchandises_path, alert: '商品の追加に失敗しました。' and return
    end
  end
```

binding.pryが書かれたControllerを踏んで処理が一時停止したターミナルの状態
![binding.pry.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3508918/ed92ff4b-8592-4ef4-f224-b7be5f0a2d64.png)

```ruby
[1] pry(#<CartsController>)>
```
のところに確認したい変数などを入力して値を確認したりします。

`@cart_item`変数の中身を確認した例
![@cart_item.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3508918/f6cd3563-31f4-aedd-1f52-4660a05a5560.png)

`params`の中身を確認した例
![params.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3508918/3750fc67-3bfd-2efe-caef-5d45fcbe63b6.png)

## pry-byebugで一時停止させた時のコマンド
`next`を実行すると一時停止位置から一行プログラムを進めることができます(ステップ実行）。
`continue`を実行すると一時停止位置から止まっているプログラムを再開して完了させます。

## pry-byebugの使用が終わったら
変数の確認などが終わったらコード内から`binding.pry`を削除しておきましょう。
残したままにしていると同じようにプログラムが一時停止してしまいます。
npm install 実行時 脆弱性の警告を受けた

# npm install 脆弱性問題による警告が発生
npm install ** Package Name** 実行時下記のエラーが出力されました。


```
# 以下警告文

npm WARN using --force Recommended protections disabled.

added 7 packages, removed 26 packages, changed 33 packages, and audited 612 packages in 6s

15 packages are looking for funding
  run `npm fund` for details

21 vulnerabilities (6 moderate, 14 high, 1 critical)

To address all issues, run:
  npm audit fix

Run `npm audit` for details.
```

# 解決方法としてはNode JSの最新バージョンをインストールすることで解決！

Node JS の正式ホーム
https://nodejs.org/en/download/prebuilt-installer

理由としては、Nodeのバージョンが古いためパッケージのバージョンがそれぞれ合わない状態となっており、脆弱性の警告が得られなかった模様です。

# 実施したこと
npm audit --forceの実行を行い脆弱性を持っているパッケージについて調整を行おうと思いましたが、結果として解決せず。。
```
npm audit fix --force
```

npm のバージョンが古いのかと思いnpm自体をアップデートしようとしましたが解消せず
```
 npm install -g npm             
```
【Windows】Gitのクローンで落とした環境がうまく立ち上がらない

チームで開発する時にLinux、macOS利用者が構築した環境を、Windowsユーザーの私がうまく立ち上げられなかったときの解決方法を記録します。

## 対象
Windowsユーザーで、GitHub からクローンを作成してもうまく立ち上がらない人

## 発生状況
GitHub でソースコードを管理しており、ローカルにクローンを作成し、他の人と同じように環境を立ち上げようとしたら、うまく立ち上がらない。macOS、Linux利用者は、同じ事象は発生していなかった

## 原因
OSによって改行コードが違うため、WindowsだとCRLFに自動で変換してしまっていたため

## 解決方法
GitHub のconfigをコマンドで変更する。
※コマンドは普段使っているコマンドラインでOKです。
私はPowerShellを使いました。

#### 手順1　現在の設定を確認
```
PC C:\Program Files\PowerShell-7.4.2-win-x64> git config --global core.autocrlf
```
このコマンドを実行したときに 何も出力されないか、または "true" が出力された場合は "false" に変更します。

#### 手順2　変更コマンドを実行
```
PC C:\Program Files\PowerShell-7.4.2-win-x64> git config --global core.autocrlf false
```

#### 手順3　もう一度設定を確認
手順１と同じコマンドもう一度実行して"false"が返ってきたらOKです。

#### 手順4　再度 GitHub のクローン作成からやり直す
ご自身のプロジェクトのやり方に沿って開発環境をやり直してください。

以上
amazon linux に mysql client を入れるワンライナー

## 概要

タイトルの通りです。



## コマンド


```bash
sudo dnf -y localinstall https://dev.mysql.com/get/mysql80-community-release-el9-1.noarch.rpm && sudo rpm --import https://repo.mysql.com/RPM-GPG-KEY-mysql-2023 && sudo dnf -y install mysql mysql-community-client
```



以上！
１分もかからずにインストールできます。
何って…VLOOKUPを使っただけ、だが？

このポエムはフィクションであり、実在の人物・団体とは一切関係ありません。

前回までのお話はこちら。

https://qiita.com/cress_cc/items/d455952dccf3cd5a1395

# 転生したら銀行員だった件Ⅱ

今度は、送付状を400枚作らないといけないらしい。ひな型は既に用意してあった。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147207/55d66504-9481-8744-894b-a343459afe8c.png)

今回もExcel VBAでなんとかしていく。

## やはり時間がないので画面は適当！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147207/545de015-4d34-b494-4185-9115ef7dfb17.png)

ひな型はちょっとコツがいる。黄色いセルにVLOOKUPを仕込んでいる。右上のオレンジのセルの値を変えると、黄色いセルの値も連動して変わる。VBAでセルの値を変えるよりずっと簡単だ。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147207/5d3d666c-f7f4-b4f3-2dc2-cb52d8e096e9.png)

:::note warn
VLOOKUPの欠点として、作った後で表に列追加されるとぐちゃぐちゃになるという点には留意すること。
:::

やりたいこととしては、

1. オレンジのセルの値を変える
1. ひな型シートを別ファイルにコピーする
1. 黄色いセルが数式のままだと扱いにくいので値に変換する
1. 作成したファイルを保存する

といった具合である。

### マクロでファイルを作って保存

```vb:Sheet1
Public Sub Main()
    Dim FolderName As String
    Dim FileName As String
    Dim Target As Range
    Dim Seq As Integer

    Set Target = Me.Range("対象").Offset(1)
    FolderName = Me.Range("フォルダ名").Value

    Do While Not IsEmpty(Target.Value)
        FileName = Target.Offset(0, 1).Value
        Seq = Target.Offset(0, 2).Value

        If Target.Value = "○" Then
            Application.ScreenUpdating = False
            Call OutTicket(FolderName & FileName, Seq)
            Application.ScreenUpdating = True

            ' 完了したら●を記入
            Target.Value = "●"
        End If

        ' カーソルを1個下に進める
        Set Target = Target.Offset(1)
    Loop

    MsgBox "Done."
End Sub
```

メイン処理は対象一覧を上から読むだけで、実際の処理はサブルーチンが全部やっている。

```vb:Sheet1
Private Sub OutTicket(FilePath As String, Seq As Integer)
    Dim OutBook As Workbook
    Dim LinkName As Variant
    
    ' オレンジのセルの値を変える
    Sheet2.Range("連番").Value = Seq
    Application.Calculate

    ' ひな型シートを別ファイルにコピーする
    Sheet2.Copy
    Set OutBook = ActiveWorkbook

    ' 黄色いセルが数式のままだと扱いにくいので値に変換する
    For Each LinkName In ActiveWorkbook.LinkSources(Type:=xlLinkTypeExcelLinks)
        OutBook.BreakLink Name:=LinkName, Type:=xlLinkTypeExcelLinks
    Next LinkName

    ' 作成したファイルを保存する
    OutBook.SaveAs FileName:=FilePath, ReadOnlyRecommended:=True
    OutBook.Close
End Sub
```

コメントに書いたとおり。

また、処理が終わったものは○→●になり、進捗状況がわかるようにした。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147207/fadd7d45-ec12-f230-0137-cf79417429bf.png)

### できた！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147207/8e9c4b2f-c633-deb8-e0b3-5b600120bcf3.png)

`BreakLink`したおかげで、黄色いセルの内容が外部ファイルを参照する数式ではなく、値になっている。

それにしても、どんな内容なのか気になるセミナーだ。

## あなた…今何を…？

### またオレ何かやっちゃいました？

何って…VLOOKUPを使っただけ、だが？

ちなみにこれ全部押印が必要だったらしく、次長がものすごいスピードでハンコを押している。
VSCodeで鳴る音を消す設定

# VSCodeの設定

設定ファイルの場所 Windows
c:\Users\{ユーザーネーム}\AppData\Roaming\Code\User\settings.json

👇この設定をsettings.jsonファイルに追記します。

```settings.json
  "editor.accessibilitySupport": "off",
```

もしくは、
細かく制御したい場合

```settings.json
  "accessibility.signals.sounds.volume": 0,
  "accessibility.signals.progress": { "sound": "off" },
  "accessibility.signals.positionHasError": { "sound": "off" },
  "accessibility.signals.positionHasWarning": { "announcement": "off" },
  "accessibility.signals.chatResponseReceived": { "sound": "off" },
  "accessibility.signals.voiceRecordingStopped": { "sound": "off" },
  "accessibility.signals.chatRequestSent": { "sound": "off" },
  "accessibility.signals.clear": {"sound": "off" },
  "accessibility.signals.lineHasFoldedArea": {"sound": "off" },
  "accessibility.signals.lineHasInlineSuggestion": {"sound": "off" },
  "accessibility.signals.noInlayHints": {"sound": "off" },
  "accessibility.signals.notebookCellCompleted": {"sound": "off" },
  "accessibility.signals.onDebugBreak": {"sound": "off" },
  "accessibility.signals.notebookCellFailed": {"sound": "off" },
  "accessibility.signals.taskCompleted": {"sound": "off" },
  "accessibility.signals.terminalQuickFix": {"sound": "off" },
  "accessibility.signals.terminalCommandFailed": {"sound": "off" },
  "accessibility.signals.terminalBell": {"sound": "off" },
  "accessibility.signals.taskFailed": {"sound": "off" },
  "accessibility.signals.lineHasWarning": {"sound": "off" },
  "accessibility.signals.lineHasError": {"sound": "off" },
  "accessibility.signals.lineHasBreakpoint": {"sound": "off" },
  "accessibility.signals.diffLineModified": {"sound": "off" },
  "accessibility.signals.diffLineInserted": {"sound": "off" },
  "accessibility.signals.diffLineDeleted": {"sound": "off" },

```
Win32の長いパスを有効にする

長いファイル名を持つファイルができてしまったときに、毎回ゼロスタートで調べている気がするので、備忘メモを残します。

## 長いファイル名のファイルができてしまう要因
普通に作業をしていると、Windows 上で長いファイル名のファイルができることは希だと思います。私の場合、Windows のファイルパス長の制限（260文字）を超えるケースは、ネットからダウンロードしたファイル名が長かったり、圧縮ファイルを展開したい際にフォルダ構造が深かったりした場合に起きがちです。Linux系のフォルダ構造を含んだ圧縮ファイルを展開した場合などがその典型でした。

今回やらかしたのは、Google Workspace の領収書ファイルでした。ブラウザで表示した領収書を「印刷」でPDFファイルとして保存した際、ファイル名を変更せずに保存したら、とんでもなく長いファイル名になってしまいました。

## コマンドプロンプトから削除を試みる
エクスプローラから削除できないファイルでも、コマンドプロンプトやパワーシェルからであれば削除できるケースが割とあります。今回も同様にやってみましたが、削除・移動・名前の変更（DEL/MOVE/RENAME）のいずれもできませんでした。コマンドプロンプトから「短い名前」（MS-DOSの8.3形式）のファイル名で削除しようとしましたが、それもダメでした。

## Win32の長いパス名を有効にする
対処方法をネットで探すと、「Win32の長いパス名を有効にする」で出来そうだということが分かりました。実際に今回のケースはこれで解決しています。
具体的には、Windows 11のローカルグループポリシーエディタ（gpedit.msc）を使って、設定変更します。「管理用テンプレート」→「システム」→「ファイルシステム」の下にある「Win32の長いパスを有効にする」を、「未構成」から「有効」に変更します。
この設定変更は再起動後に有効となるので、Windows を再起動して、改めて問題のファイルにアクセスすると、問題無く削除できるようになりました。
備忘録　〜シェルの変数、計算式の書式まとめ（随時更新)

シェルの変数、計算絡みの書式についてメモ。
学習環境はbash（たまにzsh）です。<br>
学習メモにつき、誤り等ありましたら、ぜひご指摘お願いします。
# 変数
代入 `number=1`
- 「=」の前後にスペースを入れない
(**スペースで区切るとコマンドの引数とみなされる**から）


# 計算式
`echo $((5+3))`または
`expr 5 + 3`

exprコマンドについて
- 計算し、結果を標準出力に出すコマンド。
- 各数値、演算子の間にはスペースが必要（あくまで**コマンドの引数だから**）
- 掛け算(\*)の場合には要エスケープ(コマンドでの「\*」は**特殊文字**だから）
-  例: `expr 5 \* 3`
- 同様に、「 ( 」や「 ) 」についてもエスケープが必要
 例:`expr \( 5 + 3 \) \* 8`


# コマンド置換
コマンド結果を**文字列に**変換して、他のコマンドの一部（引数としても可）で使える。 
`echo "今日は$(date)"`
- 「"」をスラッシュ「'」にすると置換されなくなる
-  「$date」は「'date'」でも可


# まとめ
スペースの有無はややこしいですが、「何故必要なのか」「なぜ有ってはならないのか」を理解しておくと、忘れなさそうです。

## 参考
- 『エンジニアなら知っておきたい　macOS環境の基本』 株式会社インプレス
- ike-dai's blog 様『exprコマンドで掛け算は注意』https://ike-dai.hatenablog.com/entry/20101026/1288103158
robloxでassistant その98

# 概要
robloxでassistantやってみた。
練習問題やってみた。

# 練習問題
ライントレースロボットを、シュミレーションせよ。

# 手順
- ServerScriptServiceに、scriptを追加。
- スクリプトを書く。

```

local d0 = Instance.new("Part", workspace)
d0.Anchored = true
d0.Size = Vector3.new(1, 1, 1)
local road0 = Instance.new("Part", workspace)
road0.Anchored = true
road0.Size = Vector3.new(12, 1, 4)
road0.CFrame = CFrame.new(0, 1, -20) * CFrame.Angles(0, math.rad(90), 0)
road0.Name = "road"
local road1 = Instance.new("Part", workspace)
road1.Anchored = true
road1.Size = Vector3.new(12, 1, 4)
road1.CFrame = CFrame.new(-20, 1, -20) * CFrame.Angles(0, math.rad(90), 0)
road1.Name = "road"
local road2 = Instance.new("Part", workspace)
road2.Anchored = true
road2.Size = Vector3.new(24, 1, 4)
road2.CFrame = CFrame.new(-10, 1, -28) * CFrame.Angles(0, math.rad(0), 0)
road2.Name = "road"
local road3 = Instance.new("Part", workspace)
road3.Anchored = true
road3.Size = Vector3.new(24, 1, 4)
road3.CFrame = CFrame.new(-10, 1, -12) * CFrame.Angles(0, math.rad(0), 0)
road3.Name = "road"
local part = Instance.new("Part", workspace)
part.Position = Vector3.new(-10, 2, -12)
local s = 0
while true do
	local rayOrigin = part.Position + Vector3.new(math.cos(math.rad(s)) * -2, 0.1, math.sin(math.rad(s)) * 2)
	local rayDirection = part.Position + Vector3.new(math.cos(math.rad(s)) * -2, -10, math.sin(math.rad(s)) * 2)
	d0.Position = part.Position + Vector3.new(math.cos(math.rad(s)) * -2, 2, math.sin(math.rad(s)) * 2)
	local raycastResult = workspace:Raycast(rayOrigin, rayDirection)
	if raycastResult then
		if raycastResult.Instance.Name == "road" then
			part.Velocity = Vector3.new(math.cos(math.rad(s)) * -6, 0.3, math.sin(math.rad(s)) * 6)
			print("run")
		else
			part.Velocity = Vector3.new(math.cos(math.rad(s)) * 4, 0, math.sin(math.rad(s)) * -4)
			s += -12
			part.CFrame = part.CFrame * CFrame.Angles(0, math.rad(-12), 0)
			print("tern")
		end
	end
	wait(0.1)
end




```

# 写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/b419af62-9f00-2ad9-f32d-18a6abbc62e8.png)


以上。
cocoonのカスタマイズでヘッダー画像の高さをMax800pxにしたとき

cocoonのカスタマイズでヘッダー画像の高さをMax800pxにしたとき、横幅1024pxで下に隙間ができる件で、色々調べました。

cocoonを使ってウェブサイトを作っていますが、今回ヘッダー画像が高さMaxの800pxで作っています。
画面の横幅が1280pxの時は、綺麗に収まります。
でも横幅が1024pxの時は、ヘッダー画像のと記事のタイトルの間が、大きく空いてしまいます。
色々調べて、子テーマのCSSに下記のメディアクエリを設定すると解決しました。

```css

@media screen and (min-width: 1023px) and (max-width: 1279px) {
	 #header {
			height: 420px;
		}

}

@media screen and (min-width: 1280px) and (max-width: 1439px) {
	 #header {
			height: 520px;
		}

}
```
cocoonは、画面の横幅が1024px以上でパソコン用の画面になるため、ヘッダー画像が縦400px以上を使うとヘッダー画像と記事タイトルの間に隙間ができてしまう可能性があります。

1279pxまでモバイル用のヘッダーのcssが、適用されるようにすると良いと思います。
ReScriptでJSONをparseする

以下のJSONをparseすることを考えます。
```ReScript:json_test.res
let cotoha_result = (`
{
  "result": [
    {
      "chunk_info": {"id": 0, "links": []},
      "tokens": [{"form": "公園"}, {"form": "から"}, {"form": "、"}]
    },
    {
      "chunk_info": {"id": 1, "links": []},
      "tokens": [{"form": "望遠鏡"}, {"form": "で"}]
    },
    {
      "chunk_info": {"id": 2, "links": []},
      "tokens": [{"form": "星"}, {"form": "を"}]
    },
    {
      "chunk_info": {"id": 3, "links": [{"link": 1, "label": "implement"}, {"link": 2, "label": "object"}]},
      "tokens": [{"form": "見"}, {"form": "て"}, {"form": "い"}, {"form": "る"}]
    },
    {
      "chunk_info": {"id": 4, "links": [{"link": 3, "label": "adjectivals"}]},
      "tokens": [{"form": "女の子"}, {"form": "を"}]
    },
    {
      "chunk_info": {"id": 5, "links": [{"link": 0, "label": "source"}, {"link": 4, "label": "object"}]},
      "tokens": [{"form": "見"}, {"form": "た"}]
    }
  ]
}
`)
```
***
```ReScript:json_test.res
@scope("JSON") @val external parse: string => result = "parse"
```
こうすれば良いはずです。[^1]
問題は、`result`の型定義をどうするかです。
***
JSONをみていくと`"result": 無名配列`なので、この無名配列を`array<chunk>`とします。
```ReScript:json_test.res
type result = { result: array<chunk> }
```
`chunk`は`{"chunk_info": レコード, "tokens": 無名配列}`なので、レコードを`chunk_info`型とし、無名配列を`array<token>`にします。
```ReScript:json_test.res
type chunk = { chunk_info: chunk_info, tokens: array<token> }
```
`chunk_info`は`{"id": int, "links": 無名配列}`なので、この無名配列を`array<link>`にします。
```ReScript:json_test.res
type chunk_info = { id: int, links: array<link>}
```
`link`は`{"link": int, "label":string}`です。
```ReScript:json_test.res
type link = { link: int, label: string }
```
残りは`token`で`{"form": string}`です。
```ReScript:json_test.res
type token = { form: string }
```
これで必要な型が定義できました。
***
事前に定義されていない型は、型宣言で利用できないので、末端から根に向けて宣言する感じになります。
```ReScript:json_test.res
type token = { form: string }
type link = { link: int, label: string }
type chunk_info = { id: int, links: array<link>}
type chunk = { chunk_info: chunk_info, tokens: array<token> }
type result = { result: array<chunk> }
@scope("JSON") @val external parse: string => result = "parse"
```
***
```ReScript:json_test.res
let result = parse(cotoha_result)
Console.log((result.result->Array.getUnsafe(0)).chunk_info.id)
Console.log(((result.result->Array.getUnsafe(1)).tokens->Array.getUnsafe(0)).form)
```
パースされ、色んな値にアクセスできるようになっています。
ReScriptでは配列に添字でアクセスすると`option<'a>`が返ります。
`option`の処理を一つずつ書くと煩雑になるので、`Array.getUnsafe`を用いました。
***
複雑なJSONを型定義することになったら超大変な気がします。
そもそも型付き言語でJSON使ってるのがどうなのかという話なのかも知れません。

[^1]:https://rescript-lang.org/docs/manual/latest/import-from-export-to-js#import-a-javascript-modules-named-export
Unityアクションゲームでスキル切り替えを作る

# はじめに

現在、私はUnityにて2Dアクションゲームを作成しています。
・物理型と魔法型を切り替えて戦うこと
・同じキーでそれぞれ別のスキルを使えるようにしたい
ということで、今回スキル切り替えの仕組みを考えてみました。

## 概要

今回は特定のキーを押すたびにスキルのゲームオブジェクトをプレハブ化したを生成してどうにかしよう、と試してみました。
スキルごとに当たり判定用のコライダーとスクリプトを用意しているので、これが一番簡単そうかな…？と思い、この手段を選んでいます。
他にもやり方があれば教えていただきたいです。

## スキルのプレハブを生成するスクリプト
配列と剰余の組み合わせで生成するプレハブを決め、Instantiateで生成を行います。

```
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SkillChange : MonoBehaviour
{
    public GameObject[] _skill = new GameObject[4]; //スキルプレハブをしまう配列
    private int _currentPrefabIndex1 = 1;
    private int _currentPrefabIndex2 = 0;

    void Start()
    {
        Instantiate(_skill[0]); //初期のスキル
        Instantiate(_skill[1]); //初期のスキル
    }

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Q)){
            _currentPrefabIndex1 = (_currentPrefabIndex1 + 2) % _skill.Length;
            _currentPrefabIndex2 = (_currentPrefabIndex2 + 2) % _skill.Length;
            Instantiate(_skill[_currentPrefabIndex1]);
            Instantiate(_skill[_currentPrefabIndex2]);
        }
    }
}
```

## スキルのオブジェクトにアタッチするスクリプト
このままだとプレハブが消えることなく残り続けてしまうので、消去はスキル側から行います。

```
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Skill1 : MonoBehaviour
{
    void Start()
    {
        
    }

    void Update()
    {
        if(Input.GetKeyDown(KeyCode.Q)){
            Destroy(this.gameObject);
        } //これを書き足してください
    }
}
```
（本当はここにコライダーやダメージ計算などなど色々な処理を書いていますが、変更するかもしれないのでとりあえず必要なところだけピックアップしてきました）

# 最後に

また他の機能が出来次第、記事に起こしていこうと思いますので、ぜひそちらもよろしくお願いします。
最後まで読んでいただきありがとうございました。
類似度検索実装の記事をただただまとめる。

# 目的

文章の類似度を検索して、多数派意見は何人中何人いるのかというのを調べたいなあと。。。。そのために参考になる記事を個人的にまとめました～
目的としては自分が見返すためですが、この記事を見た方にも参考になればと思います。

# 記事一覧
・そもそもembeddingってなんだよって振り返ってみたくなったとき用の記事
https://zenn.dev/peishim/articles/c696ff85a539bd

・embedding を使用した類似度検索の手法を紹介した記事
https://qiita.com/takiatsushi/items/fe8ddbed315d81d5327e

・SentenceTransformer の精度を比較した記事
stsb-xlm-r-multilingualがよさそう！？
https://zenn.dev/welmo/articles/a79b8b45573383

・text-embedding-3
text-embedding-3-smallが少ない文章量の検索には最適なかんじ。
これがよさそー
https://weel.co.jp/media/tech/text-embedding-3/


・そもそもOpenAIのembedding はイケてるのかを調査した記事
結論そもそもOpenAIのembeddingはイケてるらしい（やっぱV3がいいって）
https://qiita.com/akeyhero/items/ce371bfed64399027c23

# 個人的な感想
いくつかの文章類似度の記事を読んでみましたが、結局は文章をどうベクトル化するのかが重要になってくるって感じですね。また、日本語に対応していないembeddingを使うと精度は全然ダメなようです。
類似度の計算は、基本的には cos類似度で計算するのが一般的というのもびっくり！（OpenAIのサイトでもcos類似度を推奨してるんだとか）もっと違う類似度計算を頭のいい人たちはやってるんだと思ってたらそんなことなかった笑
まだまだ、頭のいい人たちにしがみついていけそう～と一瞬勘違いした私でした。
【無料】最新のGPT-4oがついに無料で使える！その詳細とメリットを解説

**ついにChatGPTのGPT-4oが無料で使えるようになりました！**
今回の変更により、無料プランでも制限付きでGPT-4oを利用できるようになりました。
この記事では、その詳細とメリットについて解説します。

これにあたって公式サイトの料金表の記載が変更されていました。
![ChatGPT料金表.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603047/58b8a7fa-ecfc-6cd6-f201-f8bb3d09844f.png)
>引用 https://openai.com/chatgpt/pricing/

無料プランを日本語に訳すと
✅文章作成、問題解決などの支援
✅GPT-3.5へのアクセス
✅GPT-4oへのアクセス制限
✅データ分析、ファイルのアップロード、ビジョン、Web ブラウジング、カスタム GPT へのアクセスが制限されています

今回の変更で無料プランのメリットは以下の通りです
- **GPT-4oが使えること**
- **ファイルのアップロード**

これにより、最新のLLM(大規模言語)モデルを利用でき、ファイルをアップロードしてChatGPTがその内容を読み解き、プロンプトと掛け合わせて回答をもらえます。

今回の変更で、最近のChatGPTの新機能を含め低頻度利用ユーザは無料プランに変更し、
月20$、約3,000円を節約することが考えられます。

アメリカでは「ChatGPT PLUS(有料版)にお金を払う必要があるのか」というメディアの記事が出ているくらいです。
![Talk about an image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603047/56155083-c03d-f942-fbd3-0bb7824f1869.png)
>引用 https://openai.com/chatgpt/

### 有料プランのメリットは何か？
無料プランでも幅広い用途が可能になりましたが、課金ユーザにも以下のメリットがあります
- **カスタムGPTの作成**
- **DALL-Eで画像作成**
- **プロンプト数の上限アップ**
- **音声モードへの早期アクセス(予定)**
- **新機能への優先アクセス**

一番大きいメリットは、数週間後にリリースが予定されている音声モードへの早期アクセスではないでしょうか。

先日のOpenAI社がSpring Updateイベントで、課金ユーザに対してGPT-5の初期バージョンの提供や音声モード以外の新機能の独占アクセスがあるかもしれないと発表がありました。

### 結論：どのプランを選ぶべきか？
ChatGPTの無料版でも多機能の利用が可能になりました。これはChatGPTのユーザを増やすことが目的だと思います。

世の中に様々な生成AIツールがありますが、使用している人はほとんどいないようです。オックスフォード大学とロイター研究所が6カ国1万2000人以上を対象に行った調査では、AIの誇大宣伝が現時点では現実世界での使用にほとんど浸透していないことが明らかになりました。

ChatGPT、Google Gemini、Microsoft Copilotなどの生成AIツールを使用したことがある人の中でも、大多数が「1、2回」しか使用していないと答えています。最もよく知られているAIツールであるChatGPTを日常的に使用していると答えたのは、ごく少数（米国7%、英国2%）でした。

回答者のかなりの割合（米国47%、英国42%）が ChatGPTについて聞いたことがなく、他のAIアプリではこの数字がはるかに高かったです。しかし、ChatGPTに次いで最も認知されているツールは、Google Gemini、Microsoft Copilot、Snapchat My AI、Meta AI、Bing AI、YouChatでした。
![best-ai-chatbot.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603047/124f886f-ae41-96b7-387d-f0c20f42941c.jpeg)
>引用 https://zapier.com/blog/best-ai-chatbot/

また、Meta AIやGoogle GeminiなどのChatGPTのライバルは無料で使用でき、同じプレミアムツールの多くを無料で提供しています。無料のAIでさえ人々に使ってもらうのが大変なのに、有料の壁が立ちはだかれば、さらに難しくなることは間違いないでしょう。

課金ユーザは無料プランでも問題なさそうであれば解約し、
ChatGPTを使ったことない人は無料プランで登録して、最新のGPT-4oを使用してみてください！

この記事が役に立ったと思ったら、ぜひ「いいね」や「ストック」をお願いします！
あなたの意見もコメント欄でお聞かせください。
Reactのhooksについてちゃんと理解する Effect・パフォーマンス・その他編

## はじめに

こちらの記事の続きです

https://qiita.com/sayyyyyy/items/9d61f15c2d277ab9fcda

## Effectフック

Effectを利用することでコンポーネントを外部システムに接続し、同期させることができます。
Effectはレンダー自体によって引き起こされる副作用を指定するためのもので、外部システムとの接続がなければ特に利用する必要がありません。
公式にもそのエフェクトは不要かもというドキュメントがあったりします。

https://ja.react.dev/learn/you-might-not-need-an-effect

Effectは以下のような手順で行われます。
1. Effectを宣言する
    1. コンポーネントがレンダーされるたびにReactは画面を更新し、そのあとでuseEffect内のコードを実行する
2. 依存値の配列を指定する
    1. 依存配列がない場合毎回のレンダー後に実行され、依存配列が空([])の場合マウント時のみ実行される
3. 必要に応じてクリーンアップを追加する
指定したすべての依存値が前回のレンダー時と全く同じ場合はエフェクトの再実行をスキップします。

- useEffect
    - 戻り値はundefined
    - useEffect内で外部APIを呼び出すのはあまり得策ではない
        - 外部APIの呼び出しにはuseSWRやTanstack Queryを利用すべき
    - 画面が更新された後に実行される
        - 遅延が目立つ場合はuseLayoutEffectを利用すべき
- useLayoutEffect
    - ブラウザが画面を再描画する前に実行される
    - 基本的な利用方法はuseEffectと同じ
- useInsertionEffect
    - レイアウトエフェクトが発火する前にDOMに要素を挿入するために利用する
    - CSS-in-JSライブラリの作者向け

## パフォーマンス関連フック

キャッシュ済みの計算結果を再利用したり、データの変更がない場合の再レンダーをスキップすることでパフォーマンスを向上させることができます。

- useMemo
    - レンダー間で計算結果をキャッシュする
    - 引数としてキャッシュしたい値を計算する関数と、依存配列を受け取る
    - 依存配列を忘れるとレンダー毎に再計算されてしまうので注意
- useCallback
    - レンダー間で関数定義をキャッシュする
- useTransition
    - stete更新の一部をトランジションとしてマークする
    - トランジションが保留中であるかどうかを表すフラグとstate更新をトランジションとしてマークするための関数を返す
- useDeferredValue
    - UIの一部の更新を遅延させる
    - 遅延させたい値を引数として渡す

### useMemoとuseCallbackの使い分け

useMemoは関数の呼び出し結果をキャッシュし、useCallbackは関数自体をキャッシュします。
以下のようにuseMemoを利用して関数をキャッシュすることも可能です。

```jsx
// useMemoを利用する場合
  const handleSubmit = useMemo(() => {
    return (orderDetails) => {
      post('/product/' + productId + '/buy', {
        referrer,
        orderDetails
      });
    };
  }, [productId, referrer]);
  
// useCallbackを利用する場合
  const handleSubmit = useCallback((orderDetails) => {
    post('/product/' + productId + '/buy', {
      referrer,
      orderDetails
    });
  }, [productId, referrer]);
```

### どのレベルからメモ化すべきか

以下でタイムを計測し1ms以上など処理に時間がかかる場合にメモ化するべきです。

```jsx
console.time();
// 処理
console.timeEnd();
```

### トランジションとは

緊急性の高い更新と高くない更新を区別するためのものです。
ここでいう緊急性の高い更新とはタイプ、クリック、プレスなどユーザ操作を直接反映するものです。
優先度が低く、トランジションさせたいset関数をstartTransistionの中に入れます。

https://ja.react.dev/blog/2022/03/29/react-v18#new-feature-transitions

## その他のフック

- useDebugValue
    - React DevToolsでカスタムフックにラベルを追加できる
- useId
    - アクセシビリティ属性に渡すことができる一意のIDを生成する
- useSyncExternalStore
    - 外部データストアへのサブスクライブを可能にする
    - 可能であればuseStateやuseReducerを使用し、非Reactコードと統合するときにこのhooksを利用する
- useActionState
    - フォームアクションの結果に基づいてstateを更新する
    - フォームが最後に送信されたアクションによって変化するにで、フォームが送信されていない場合は初期stateが利用される
    - Canaryおよびexperimentalチャンネルでのみ利用可能

## 参考資料

https://ja.react.dev/reference/react/hooks

https://ja.react.dev/blog/2022/03/29/react-v18#new-feature-transitions

https://ja.react.dev/learn/you-might-not-need-an-effect
robloxでassistant その97

# 概要
robloxでassistantやってみた。
練習問題やってみた。

# 練習問題
CylindricalConstraintを、使え。

# 手順
- ServerScriptServiceに、scriptを追加。
- スクリプトを書く。

```
local part1 = Instance.new("Part", workspace)
part1.Anchored = true
part1.Size = Vector3.new(1, 2, 2)
part1.CFrame = CFrame.new(-0.513, 8.763, 10) * CFrame.fromEulerAnglesXYZ(0, 0, math.rad(-45))
part1.Name = "Anchor"
local part2 = Instance.new("Part", workspace)
part2.Anchored = false
part2.Shape = Enum.PartType.Cylinder
part2.Size = Vector3.new(1, 3, 3)
part2.CFrame = CFrame.new(-2.987, 11.237, 10.25) * CFrame.fromEulerAnglesXYZ(0, 0, math.rad(-45))
local cylindricalConstraint = Instance.new("CylindricalConstraint", part1)
local attachment0 = Instance.new("Attachment", part1)
local attachment1 = Instance.new("Attachment", part2)
attachment0.Position = Vector3.new(-0.5, 0, 0)
attachment0.Axis = Vector3.new(-1, 0, 0)
attachment1.Position = Vector3.new(0.5, 0, 0)
attachment1.Axis = Vector3.new(-1, 0, 0)
cylindricalConstraint.Attachment0 = attachment0
cylindricalConstraint.Attachment1 = attachment1
cylindricalConstraint.LimitsEnabled = true
cylindricalConstraint.Restitution = 1
```

# 写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/e3933b1f-eb8d-77b3-216e-b4f525ed40ff.png)


以上。
robloxでassistant その96

# 概要
robloxでassistantやってみた。
練習問題やってみた。

# 練習問題
UDim2とVector2を、使え。

# 手順
- ReplicatedFirstに、localscriptを追加。
- スクリプトを書く。

```
local Players = game:GetService("Players")
local Player = Players.LocalPlayer
local PlayerGui = Player:WaitForChild("PlayerGui")
local Gui = Instance.new("ScreenGui")
Gui.Parent = PlayerGui
local Frame = Instance.new("Frame")
Frame.AnchorPoint = Vector2.new(0.5, 0.5)
Frame.Position = UDim2.new(0.5, 0, 0.5, 0)
Frame.Parent = Gui
local Label = Instance.new("TextLabel")
Label.Text = Player.Name
Label.TextSize = 100
Label.Parent = Frame

```

# 写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/7399825f-4ee0-7ab4-4618-d56d944f285b.png)


以上。
ChatGPTの力を借りて、うつ病と付き合う

# 大前提
主治医と治療を続けて、最新の技術を活用しようという活力がでてきて、今回記事を投稿しました。
治療は精神科の先生と治療方針をしっかりと話して、治療を続けてください。
※ChatGPTはあくまで、自分の補助ツールとして活用をしています。※

# ChatGPTを使おうと思った経緯
2社目で自分のキャパオーバーとなり、不安障害・うつ病発症
会社は限配置転換など産業医面談等、最大限フォローをしていただきましたが、しっかりと療養することがお互いにとって幸せであると合意をしたうえで退職。
現在は地元の、家近くの会社で情シスのお仕事を続けています。
月１、２回の間隔で通院をしていますが、どうしても急にカウンセリングをしてほしい、
再発予防の習慣化をしたい時に利用を始めました。

# どうやってやっているの？
### 環境
無料版ChatGPT iosアプリ　3.5モデルを利用
利用開始日：4o発表からやってみた
### 手順
1.先人の知恵を借りて最初にプロンプトを投稿
![GPT1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282719/bc6e5487-7cf9-a4af-7109-5e5bc1e0e0df.jpeg)

実際のプロンプト投稿内容
```
# 命令;
あなたはカウンセラーのプロフェッショナルです。


#指示;
- うつ病の患者さんを相手にする人として振る舞ってください
```

参考記事

https://prompt.quel.jp/phrase.php

2.対話・毎日進捗報告
＜辛いことを聞いてもらう＞
![GPT2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282719/2c3f4f27-89c0-559f-575c-37136f758e30.jpeg)
![GPT3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282719/04fbece4-14c0-5c84-3129-83d707c48f8b.jpeg)
![GPT4.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282719/5a25437d-7af3-4fd5-ecb3-99dd4931fb7f.jpeg)
（無料版でも的確な回答が出てくるまで進化したのはすごい、、）
＜習慣化チャレンジ＞
![GPT5.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282719/1964b1d0-5e29-d225-a7b4-8d87840b7893.jpeg)
↓今朝の聞いてもらった結果↓
![GPT7.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282719/547fa88b-f9f7-809a-7dd7-ba8e4688181c.jpeg)

こんな感じで、カウンセリングや習慣化の補助を手伝ってもらっています。

# おわりに
朝一スマホを見てしまう癖は正直あります。
なので、朝のルーティンとして、ChatGPTに朝の活動をできたこと、できなかったことを報告して、自分の生活リズムに合わせて補助をしてもらっているので、非常に助かっています。
自分の生活スタイルと癖と合わせて継続し続けることを心掛けて、うつ病と付き合っていきます。

# 余談
ポジティブ日記としても使っています。
今回仕事でやらかしたけど無事うまくいったこと（実話）を掲載してます。
### やらかしたこと
会社でChatGPT Teamの契約をして、年間ユーザーを2アカウント登録後、社内の無料版で先行して使っていた別ユーザーを2名招待したら、余分課金が発生しました。
契約規約を確認したら、ユーザーを追加した時点で前払い課金が発生される明記されています。本来は返金対応を行っていません。

https://openai.com/policies/service-credit-terms/

※間違った操作をしたことを即伝えたら、OpenAI社が *特例* で返金対応をしていただきました。本当にありがとうございました。

みんなも企業のワークスペースにユーザーを招待すると自動課金になるので誤操作は注意！！
![GPT6.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282719/f26eae68-83b9-3453-5fb1-b3a37ef271e3.jpeg)

ご精読、ありがとうございました。
git pullした時のエラーを解決する

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

みなさんはgitを使っていて、変更点をgit pushした時に
git pullするように言われるエラーがでて、指示に従ってgit pullしたら
エラーにハマりつづけた経験はありませんか？

僕はよくこのエラーに悩まされてきました...
git rebaseなどをしている過程で、リモートリポジトリの内容を誤って
書き変えてしまったこともあります。社長ごめんなさい

今回は、このエラーに終止符を打ちます！

## エラーの概要
![スクリーンショット 2024-05-29 20.56.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3579468/b6741457-05ae-4063-6a06-be6d33f085d6.png)

このエラーです。`git pull origin ブランチ名`のコマンドを叩いたときに

`git config pull.rebase false` # merge
`git config pull.rebase true` # rebase
`git config pull.ff only` # fast-forward only

のどれかをするように求められます。

## 解決法
こちら結論からいうと、`git config pull.rebase false` # merge
をすることで、エラーが解消されます！

理由はまだよくわかっていませんが、git pullでエラーが出たら
`git config pull.rebase false` # merge
を検討してみてください。

その後で、`git pull origin main`などすると上手くいくはずです！
今日もまた1つ成長しました。
ChatGPT 4oのPDFアップロードではイラストを見てくれない（通はPDFのスクショを使う）

# はじめに
https://qiita.com/reityerukohaku/items/fdceda8354a6a11dac6b

を見て、「PDFが直接アップロードできるんだー。PDFのスクショを撮っていたわー」と思ったのです。それと同時に、「そもそも、これってどういう仕組み？」となりました。こんなに便利ならAPI経由で大量に処理したいです（c.f. [前作(机から離れて論文を大量に読む方法（NGK2024S）)](https://qiita.com/n_kats_/items/c6424c2209dbcbb82976)）。

ぼくが考えた最強の『秘技スクショ』の敗北を感じつつ、よくある方法を予想すると、

1. PDFのテキストを抽出（pydpf等を使って）
1. テキスト部分とチャットの内容を入力にして推論
1. （長文の場合、複数回に分ける）

というアプローチが考えられます。この場合、イラストや図の部分を扱えません。しかし、実はもっと凄い仕組みになっているかもしれません。『秘技スクショ』は本当に敗北したのか、それを検証してみました。

# 実験方針
PDFに含まれるイラストの説明ができるかを検証しました。

## テストデータ
使うPDFは https://arxiv.org/abs/2405.20343 の論文のものとしました。

画像が使われていそうなcs.CVのカテゴリーの中で、先頭にあったものを採用しました。狙い通り、次の画像のようなイラストが冒頭にありました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51820/b54da4db-c4c6-6e5f-6ffb-da079ac2af63.png)

もちろん、論文中には、この画像にどういうものが映っているかは書かれていません。

## 実験結果
### 質問方法
このようにPDFをアップロードして「この論文の冒頭にある画像の特徴を整理して。あと、どんなものが映っているのかリストアップして。」のように質問しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51820/0945145f-a3f5-c82a-8af1-085bb75d0d0b.png)

### 回答
回答はこのようになりました。画像が読めていないため、映っているものの一覧はデタラメです。質問に対応する画像がFigure 1のことだということは正しく分かっているようですが、勝手に想像して回答しています。
念のため、10回生成させましたが、どれもデタラメでした。家具が映っていると回答している場合もありました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51820/630f4f8f-947a-f139-f17d-a8eb264acd66.png)

## 比較（画像アップロードの場合）
### 質問方法
同じ質問を1ページ目の画像で投げつけてみました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51820/b879a7a3-d201-4134-9499-b06c9912e5c3.png)

### 回答
画像をこのページ全体のことと勘違いしている節はありますが、イラストに映っているものがそれらしく回答されています。なので、認識能力の問題ではなさそうです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51820/7c95c28e-9d44-f5aa-b418-d73328fc3f84.png)

<details><summary>補足（キャラクターの名前を挙げれる？）</summary>

回答をよくよく見ると有名なキャラクターの名前を出していません。ひょっとして分からないのか・わざと回答しなようにしているのか心配になりました。
次のように、イラスト部分だけを入力してみると「バズ・ライトイヤー（トイ・ストーリー）」と回答してくれたので杞憂だったようです。ただ、ピカチュウは回答にはありませんでした。解像度が低かったり関係ない部分が多いと精度が落ちるのかもしれません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51820/59b9888a-195d-3d7b-e687-d76a194a78c3.png)

</details>

# まとめ
実験の通り、PDFをアップロードしても、GPT-4oに画像認識能力があるにも関わらずイラスト部分を無視している可能性が高いです（将来的に変更される可能性もありますが）。予想通り、テキスト部分だけ抽出する処理をしているようです。なので、『秘技スクシュ』は負けていないと言えるでしょう（少しずつしか入力できないですので、全体まとめはPDFアップロードが適切）！

スクショを用いると、図・イラストが扱えること以外に、数式が扱いやすかったり、複雑なレイアウトのページに相性が良さそうだったりします。GPT-4oはGPT-VからOCR能力が大幅に上がり、PDFを画像にして入力する使い方に可能性が出てきました。そのうち、整理ができたら記事にまとめたいです。
AIマルチエージェントのアーキテクチャを人の体と比較

元ネタ：[https://medium.com/superstringtheory/anatomy-of-an-ai-multi-agent-e2cfedc3b050](https://medium.com/superstringtheory/anatomy-of-an-ai-multi-agent-e2cfedc3b050)

# AIマルチエージェントの構造

## 役立つAIエージェントをどのように作成するか？

このパートは3つのセクションに分かれています。まず、役立つAIマルチエージェントの構造を見ていきます。セクション3では、具体的な部分に使用するコンポーネントについて説明し、より実践的にします。

## 1. 人間 vs エージェント

スマートなものを設計する際に最良の例として参考にすべきなのは人間です。以下は典型的な人間のレイアウトです：

![https://miro.medium.com/v2/resize:fit:225/0*NPscsjLph9l_-Gkx](https://miro.medium.com/v2/resize:fit:225/0*NPscsjLph9l_-Gkx)

私たちは目で世界を見て理解し、口でお互いに会話をし、脳で物事を理解して知識を持ち、手を使って世界と色々な相互的な行動を行います。

ここでのコンセプトは、AIにも同じことをさせたい、という事です。ChatGPTはこれが全部できわけではなく、あなたとテキスト（最近の4oでは音声）で会話するだけです。むしろ、ChatGPTを一つの機能として利用して、人間のように行動するAIシステムを作り上げることができる、というのが下記で説明するコンセプトの概要です。

![https://miro.medium.com/v2/resize:fit:375/0*uSZY8AuQ9Wy_yMM6](https://miro.medium.com/v2/resize:fit:375/0*uSZY8AuQ9Wy_yMM6)

このコンセプトは実はすでに世の中に実例はいっぱいあって。自動運転、ロボット、など、AIがエージェントとして活躍している実例です。

## 2. エージェントの構成要素

人々が音声を通して人とコミュニケーションをするように、AIエージェントも人間との対話のためにチャットや音声システムが必要です。一方では、AIエージェント同士の対話にはテキストや音声は使わない方が、効率やエラー防止面で適しています。

さらにエージェントには環境を理解するためのセンサーが必要です。自動運転車の場合、カメラやライダーがこれに該当します。一方、ウェブベースのエージェントでは、言語モデルや画像からテキストへの変換モデルを使用して閲覧するウェブサイトの内容を理解します。

また、センサーと人間の入力を解釈し、適切な行動を決定する処理モジュールも必要です。

ナレッジベースは、新しい状況に対応するために過去のデータを参照することを可能にします。この機能は「RAG」（リトリーバル・オーグメンテッド・ジェネレーション）と呼ばれ、非常に重要でありながら、その複雑さはしばしば見過ごされがちです。

エージェントにはまた、「脳」が必要であり、これは戦略を立案し、評価し、改善し、最終的な実行計画を策定する役割を担います。上記の図では1つのボックスとして表現されていますが、このコンポーネントは人間の認知プロセスを簡略化された方法で再現しようとする複雑なマルチエージェントシステムそのものです。

最後に、エージェントは他のソフトウェアやシステムを操作する手段、つまり「手」が必要です。これにより、ユーザーの代わりに外部の世界に対してタスクを実行できます。

これらのAIマルチエージェントの設計は長い間研究されてますが、最近の大規模言語モデルや生成AIモデルの発展により、この研究を新しい技術で応用することができるようになりました。これにより、非常に特定のタスクに限定されない、汎用的なAIエージェントを開発する道が開かれました。

## 3. AIエージェントの特定の部分の設計

さて、単純な人間の比較から離れて、図に示されたような柔軟なAIマルチエージェントを作成するために採用できる、インターネット上で動作するエージェントについて話しましょう。

![https://miro.medium.com/v2/resize:fit:525/0*G5gUkcbRQPH3gBwL](https://miro.medium.com/v2/resize:fit:525/0*G5gUkcbRQPH3gBwL)

**センサー**
エージェントが環境を理解するために必要です。具体的には、以下の機能が必要です：

- 人間のようにウェブサイトを読む（ウェブサイトは人間向けに設計されており、ロボット向けではないため）
- コンピュータ向けに設計されたさまざまなインターネットAPIを探索して使用する

これらのセンサーを作成するには、言語モデル、画像理解モデル、さまざまなウェブサイトのアドレスからデータを見つけてダウンロードするコードが必要です。その後、言語モデルは「読んだ」ものをさらに処理するために適したフォーマットに変換する必要があります。

**人間との対話**
ChatGPTが一例になりますが、文字を入力したり話したりすると、別の言語モデルで処理され、さらに推論されます。

**入力の処理**
このコンポーネントは、**センサー**が提供する情報と**人間**からの現在のリクエストの両方を取り込み、「**プランソリューションモジュール**」のためのタスクリクエストを作成する機能を提供します。このモジュールは「**ナレッジベース」**を参照し、タスクリクエストを作成する際にその内容を文脈に含めます。

**ナレッジベース / RAG**
このモジュールは、エージェントが必要とするデータと知識を保存します。これは、インターネット検索を通じてアクセスした公開データや、テキストを数値ベクトル変換したベクターデータベースを含むことができます。これにより、「キーワードによる検索」ではなく「意味による検索」が高速になります。

**プランソリューション**
これは通常、複数の異なる言語モデルが協力して働くグループです。タスクリクエストを受け取り、エージェントが利用できるリソースを確認し、段階的に実行し、タスクに必要なサブエージェントを作成し、最終的にサブエージェントの実行を管理する必要があります。これはAI研究の中で急速に発展しているマルチエージェントの領域です。

**「手」またはアクションの実行**
これは、人間からの要求に応じてエージェントが何かを実行する部分です。これらの「手」は、外部APIと対話したり、ウェブページのボタンをクリックしたり、他の方法で既存のソフトウェアと対話したりするコードの部分です。

これらすべては現在の技術で作成することが可能であり、大きな可能性をもたらしてくれます。[Integrail](https://integrail.ai/)では、これらのエージェントを構築するだけでなく、プログラミングの知識がなくてもエージェントを設計および構築できるプラットフォームも構築しています。AIマルチエージェントのアーキテクチャを人の体と比較
robloxでassistant その95

# 概要
robloxでassistantやってみた。
練習問題やってみた。

# 練習問題
VehicleSeatを、使え。

# 手順
- ServerScriptServiceに、scriptを追加。
- スクリプトを書く。
```

local seat = Instance.new("VehicleSeat", workspace)
seat.Position = Vector3.new(0, 1, 0)
local Players = game:GetService("Players")
local currentPlayer = nil
local me = nil
local camera = workspace.CurrentCamera
camera.CameraType = Enum.CameraType.Custom
local s = 0
local function onOccupantChanged()
	local humanoid = seat.Occupant
	if humanoid then
		local character = humanoid.Parent
		local player = Players:GetPlayerFromCharacter(character)
		if player then
			print(player.Name .. " has sat down")
			me = game.Workspace:WaitForChild(player.Name)
			currentPlayer = player
			seat.Position += Vector3.new(0, 0, -10)
			me.HumanoidRootPart.Position += Vector3.new(0, 0, -10)
			return
		end
	end
	if currentPlayer then
		print(currentPlayer.Name .. " has got up")
		currentPlayer = nil
	end
end
seat:GetPropertyChangedSignal("Occupant"):Connect(onOccupantChanged)
seat:GetPropertyChangedSignal("Steer"):Connect(function()
	print(seat.Steer)
	if seat.Steer == 1 then
		s += -10
		camera.CFrame *= CFrame.Angles(0, math.rad(-10), 0)
		seat.CFrame *= CFrame.Angles(0, math.rad(-10), 0)
		me.HumanoidRootPart.CFrame *= CFrame.Angles(0, math.rad(-10), 0)
	elseif seat.Steer == -1 then
		s += 10
		camera.CFrame *= CFrame.Angles(0, math.rad(10), 0)
		seat.CFrame *= CFrame.Angles(0, math.rad(10), 0)
		me.HumanoidRootPart.CFrame *= CFrame.Angles(0, math.rad(10), 0)
	end
end)
seat:GetPropertyChangedSignal("Throttle"):Connect(function()
	print(seat.Throttle)
	if seat.Throttle == 1 then
		seat.Position += Vector3.new(math.sin(math.rad(s)) * -1, 0, math.cos(math.rad(s)) * -1)
		me.HumanoidRootPart.Position += Vector3.new(math.sin(math.rad(s)) * -1, 0, math.cos(math.rad(s)) * -1)
	elseif seat.Throttle == -1 then
		seat.Position += Vector3.new(math.sin(math.rad(s)) * 1, 0, math.cos(math.rad(s)) * 1)
		me.HumanoidRootPart.Position += Vector3.new(math.sin(math.rad(s)) * 1, 0, math.cos(math.rad(s)) * 1)
	end	
end)



```

# 写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/ae224276-e0bf-d63f-6c65-896b90edb380.png)


以上。
mapメソッドの使い所

mapメソッドを使用する部分をメモ。
mapメソッドは配列を繰り返し処理するメソッド。新しい配列を生成できる。

```js
const arr = ['りんご', 'ばなな', 'いちご']

const converted = arr.map((value, idx) => {
  return `${idx} と ${value}`
})
converted // ["0 と りんご" ,"1 と ばなな", "2 と いちご"]
```

オブジェクトの配列に対してもmapメソッドは使用できる。以下は簡単な足し算を行う。
```js
let array = [
  { first: 20, second: 30 },
  { first: 42, second: 43 }
];

let addition = array.map(function (element) {
  return element.first + element.second;
})
addition // [50 ,85]
```

配列の計算もmapメソッドならば簡潔に書ける.下記コードは、平均と標準偏差を計算している。

```js
const map = function (a, ...args) { return a.map(...args) }
const reduce = function (a, ...args) { return a.reduce(...args) }

const sum = (x, y) => x + y
const square = (x) => x * x

let data = [1, 1, 3, 5, 5];
let mean = reduce(data, sum) / data.length
let deviations = map(data, x => x - mean)
let stddev = Math.sqrt(reduce(map(deviations, square), sum) / (data.length - 1))
stddev // 2
```

#### 参考

https://www.oreilly.co.jp/books/9784873119700/
【Swift】よく使われている zip ファイルユーティリティ 2つ



SwiftでZIPファイルを扱う際に便利なユーティリティがいくつかありますが、今回は特によく使われている2つのライブラリについて紹介します。どちらもGitHubで多くのStarを獲得しており、機能的にも優れています。それぞれの使い方と使いやすさを比較してみましょう。

# 🙆🏻‍♂️ ZIPFoundation

https://github.com/weichsel/ZIPFoundation

### 基本的な使い方
ZIPFoundationは、ファイルの圧縮と解凍を簡単に行うためのライブラリです。FileManagerのエクステンションとして機能し、直感的な操作が可能です。

```swift
import ZIPFoundation

// 圧縮
try fileManager.zipItem(at: sourceURL, to: destinationURL)

// 解凍
try fileManager.unzipItem(at: sourceURL, to: destinationURL)
```

### 特徴
- 直感的なAPI: FileManagerのエクステンションとして提供されるため、既存のFileManagerメソッドとシームレスに統合できます。
- 高パフォーマンス: 圧縮と解凍の処理が高速で、大量のファイルを扱う際にもパフォーマンスが高いです。
- 依存関係が少ない: 他のライブラリに依存せず、単独で機能するため、プロジェクトに導入しやすいです。

### 使用例
ZIPFoundationを使うと、ファイルの圧縮と解凍が簡単に行えます。例えば、バックアップを取る際や、特定のディレクトリをアーカイブとして保存する場合に便利です。


# 🙆🏻‍♂️ Zip

https://github.com/marmelroy/Zip

### 基本的な使い方
Zipライブラリもファイルの圧縮と解凍を簡単に行うためのフレームワークです。こちらはZipクラスの静的関数を使って操作します。

```swift
import Zip

// 圧縮
let zipFilePath = try Zip.quickZipFiles([filePath], fileName: "archive")

// 解凍
let unzipDirectory = try Zip.quickUnzipFile(filePath)
```

### 特徴
- シンプルなAPI: Zipクラスの静的関数を使って操作するため、非常にシンプルで使いやすいです。
- 豊富なオプション: 圧縮や解凍の際に細かいオプションを設定でき、柔軟な操作が可能です。
- 活発なコミュニティ: GitHub上でのサポートが充実しており、問題解決や機能追加が迅速に行われます。

### 使用例
Zipライブラリは、簡単なアーカイブ作業から複雑な圧縮タスクまで幅広く対応できます。特に、ユーザーデータの圧縮・解凍機能を提供するアプリケーションで役立ちます。


# 🙆🏻‍♂️ まとめ
両方のライブラリは、ファイルの位置を「URL」として引数に取る点で共通しています。それぞれの特徴を踏まえて、プロジェクトに合った方を選ぶと良いでしょう。

### どちらが使いやすいか？
ZIPFoundationは、FileManagerのエクステンションとして動作するため、既存のFileManagerメソッドとの統合が自然です。
Zipは、専用のクラスメソッドを提供しており、特定のタスクを行う際に明確なAPIを持ちます。

### 追加の考慮事項
ドキュメントとサポート: どちらのライブラリもドキュメントが充実しており、導入や利用に困ることは少ないでしょう。ただし、プロジェクトの特性や規模に応じて、より詳細なサポートが必要な場合は、GitHubのIssuesやDiscussionsを参考にするのが良いでしょう。
- ライセンス: 両方のライブラリはオープンソースですが、プロジェクトに導入する際にはライセンス条件を確認することが重要です。

### もしかして、ビルトインで何か関数あるの?
Swift標準ライブラリには、直接的なZIPファイル操作の機能は含まれていません。そのため、ZIPFoundationやZipのようなサードパーティライブラリを使用するのが一般的です。これらのライブラリは、効率的で使いやすいAPIを提供しているため、ファイルの圧縮・解凍作業が簡単に行えます。

標準ライブラリにない機能を補完するために、これらのライブラリを利用することで、開発効率が大幅に向上します。例えば、アプリケーションのデータバックアップやログファイルの圧縮など、さまざまな場面で活用できます。

# 🙆🏻‍♂️ 参考
https://android.benigumo.com/20240529/zip-util/
レベルアップ問題を解いてみる

## はじめに
paizaの問題集を使い、ハンズオン学習をしています。
標準入力の問題を一通り解いたので、レベルアップ問題に挑戦してみました。

## 乗客人数 Ruby編
https://paiza.jp/works/mondai/d_rank_level_up_problems/d_rank_level_up_problems__accompanied_by_stdin_boss

自分の回答
``` quiita.rb
a,b,c = gets.split.map(&:to_i)

n = a
n -= b
n += c

puts n
```
- map
 入力値を配列に格納するメソッド

## 占い Ruby編
https://paiza.jp/works/mondai/d_rank_level_up_problems/d_rank_level_up_problems__conditions_branch_boss

自分の回答
``` quiita.rb
n = gets.chomp.to_i

if n == 7
    puts "Yes"
else
    puts "No"
end
```

## FizzBuzz Ruby編
https://paiza.jp/works/mondai/d_rank_level_up_problems/d_rank_level_up_problems__loop_boss

自分の回答
``` quiita.rb
(1..100).each do |i|
    if i % 3 == 0 && i % 5 == 0
        puts "FizzBuzz"
    elsif i % 3 == 0
        puts "Fizz"
    elsif i % 5 == 0
        puts "Buzz"
    else
        puts i
    end
end
```

問題を解く際、参考させていただいた記事

https://qiita.com/umaibou1126/items/cd9192aa008e386d96de
マークダウン記法基本メモ

記事を投稿するたびにいちいち調べるのも時間の無駄なので、最低限使う物をまとめようと思いました。
すでに知っている方も多いかと思いますが、これから投稿しようと考えている方の参考になれば幸いです。

# 1.文字の大きさ
#の数で文字の大きさが変わります。また、#の後ろには半角スペースが必要です。

### [入力]
```
# Qiita　
## Qiita
### Qiita
#### Qiita
##### Qiita
###### Qiita
```
### [結果]
# Qiita　
## Qiita
### Qiita
#### Qiita
##### Qiita
###### Qiita

# 2.箇条書き
*を使用することで箇条書きにできます。
### [入力]
```
* Windows
* Linux
* Mac 
```
### [結果]
* Windows
* Linux
* Mac 

# 3.太字
*2つで挟んだ部分だけを太字で表示できます。
### [入力]
```
Windows**Linux**Mac
```
### [結果]
Windows**Linux**Mac

# 4.水平線
アスタリスク、ハイフン、アンダーバーのいずれかを3つ以上並べると、水平線になります。
### [入力]
```
***
---
___
```
### [結果]
***
---
___

# 5.リンク
リンクに名前をつけて記載できます。
### [入力]
```
[Crane&i](https://hikoma.jp/crane-i)
```
### [結果]
[Crane&i](https://hikoma.jp/crane-i)

# 6.表
表を作成することもできます。
### [入力]
```
|✆ | クリア |☎  |
|:-|:-|:-|
| あ |　か | さ |
| た |　な | は |
| ま |　や | ら |
```
### [結果]
|✆ | クリア |☎  |
|:-|:-|:-|
| あ |　か | さ |
| た |　な | は |
| ま |　や | ら |

# 7.色の変更
文字の色も変更できます。
### [入力]
```
<font color="Red">ルビー</font>
<font color="Blue">サファイア</font>
<font color="green">エメラルド</font>
```
### [結果]
<font color="Red">ルビー</font>
<font color="Blue">サファイア</font>
<font color="green">エメラルド</font>

ひとまず自分が記事投稿で使う内容についてまとめました。
また書ける内容が増えたらメモ2を投稿したいと思います。
Meta Quest3のコントローラーでバイブレーションを実装する方法

# はじめに
大学の実験で、MetaQuest3を使ったVRゲームを作成したのですが、その際にMetaQuest3にバイブレーションを実装したいと思い、実装方法を調べたのでそれを共有したいと思います。
# コード

実装するコード配下の通りです。
```VibrationController.cs
using System.Collections;
using UnityEngine;

public class VibrationController : MonoBehaviour
{
    public static VibrationController instance;

    private void Awake()
    {
        instance = this;
    }

    public void StartVibration(float frequency, float amplitude, float duration, OVRInput.Controller controller)
    {
        StartCoroutine(Vibrate(frequency, amplitude, duration, controller));
    }

    private IEnumerator Vibrate(float frequency, float amplitude, float duration, OVRInput.Controller controller)
    {
        OVRInput.SetControllerVibration(frequency, amplitude, controller);
        yield return new WaitForSeconds(duration);
        OVRInput.SetControllerVibration(0, 0, controller); // バイブレーションを停止
    }

}
```

`public static VibrationController instance`と記述することで、オブジェクトにアタッチして一度インスタンスを生成してしまえば、以下のコードのように他のスクリプトから簡単に参照できるようになります。
```
VibrationController.StartVibration(frequency,amplitude,duration,controller);
```

`StartVibration`で書いている`IEnumerator`は、非同期処理(`コルーチン`）を行わせるために記述しています。
>コルーチンとは
任意の箇所で処理をストップさせ、任意のタイミングで処理を行う、他の処理と並行して処理する並列処理(非同期処理）のことを言います。

`yield return new WaitForSeconds(duration);`で、その後に記述している`OVRInput.SetControllerVibration(0, 0, controller);`の実行を遅らせています。


# 最後に
MetaQuest3でVRをunityで触る人はぜひ参考にしてください。
マレーシアIT留学について

# マレーシアIT留学
## はじめに
マレーシアでITを学ぶことになった背景と、その動機についてお話しします。最近円安の影響で英語圏の正規留学はほぼ不可能となっているので、マレーシアは最近留学先として知名度を上げています。留学先を迷っている人の参考になれば幸いです。
## マレーシア留学を選んだ理由
###### 1.多浪による文系就職の困難さ
3年前、高校卒業後に入った公務員を一年弱で退職。その後1年間浪人しましたが、失敗しました。文系出身の自分には国内で新卒として採用されるのは難しいと感じ、海外留学を考えました。
###### 2.費用、治安面
学費と生活費を合わせても日本の理系私大に上京して通うのと大差なく、治安も悪くなかったのでマレーシアを選びました。
###### 3.学部について
現地就職を見据えて会計学かIT系を選考したいと考えていました。プログラミング未経験でJavaを学びましたが、単位を落としました。しかし、現地学生よりも英語力が劣る自分がどっちが就職できるかを考え、IT系を選び、さらにCSよりも難易度が低いとされるICT学部を選びました。
## 英語について
###### 1.自分の英語力について
ファウンデーション入学当時、IELTS5前後しかありませんでした。卒業後再度IELTSを受験したところ、5.5ほどでしたが、Speakingは6に上がっていました。微妙に上がりました。おそらくIELTSの勉強をもっとこなせばスコアは上がると思いますが、ただ留学しただけではスコアは思ったより上がりませんでした。

###### 2.まわりの英語力について
現在、ボルネオ島のKuchingにある大学に通っています。周りには日本人留学生がいないため比較できませんが、KLのファウンデーションコースにいた日本人の英語力は高い人もいれば、自分より低い人もいました。現在の周りのマレーシア人や非英語圏の留学生はIELTS6.5から7前後だと思います。ただし、マレーシア人でも高校まで中国語やマレー語で教育を受けていた学生は自分と同じくらいまたは低いと感じます。

###### 3.授業での英語について
レポートやプレゼンは他の学生より下手だと感じますが、ChatGPTや翻訳ソフトでなんとかしのいでいます。ただ授業内容や実験、ポートフォリオ、テストは他の学生よりも理解度は高いと思います。友達に質問しても"I also don't know."という返事が多く、講師に対して質問するのは女子学生が多い印象です。適当な学生が多いため、勉強量で差をつけると技術面で現地生や他の留学生を圧倒できると感じます。

## 勉強量
毎日最低4,5時間ほど勉強しています。学期末はレポートやポートフォリオ、実験に取り組んでいます。学期末の大きな課題の提出期限前は寝る時間以外ずっと課題をしています。留学中の特別な思い出はなく、自室と図書館と近くのショッピングモールで飯を食う毎日が続いています。正直何やってるんだろうと感じます。

## 将来について
大学卒業後は、マスターに直接進むか、日本か東南アジアでエンジニアとして就職し、お金を貯めて英語圏の一年制マスターにアプライしたいと考えています。具体的にどこで働きたいかはまだ決まっていませんが、日本か東南アジアで働けたら良いなと思っています。特にシンガポールが希望ですが、現実的かどうかは分かりません。


## 最後に
今後、授業内容や、マレーシアや日本での就活について順次アップデートしていきたいと考えています。