OmniAICreator/Qiita-1.07M huggingface dataset:
LangGraphを試した①　~グラフ編~

# はじめに

最近 LangGraph を触って見たので、概念やコードの書き方について備忘録的に書いていきたいと思います。
今回はグラフの作成方法についてです。

# ステートグラフ

LangGraph は状態を保持してグラフ上を移動しながら各ノードで処理を行うことでタスクを行います。[Wikipedia](https://ja.wikipedia.org/wiki/%E3%82%B0%E3%83%A9%E3%83%95_(%E9%9B%A2%E6%95%A3%E6%95%B0%E5%AD%A6))にあるようにグラフとは
>数学のグラフ理論におけるグラフ（英: graph）とは数学的構造の一つ。対象の集合で、対象の一部が相互に何らかの脈絡で「関係している」ようなものをいう。ここで対象とは頂点（節点やノードとも）と呼ばれる抽象物であり、互いに関係のある頂点の対は辺（枝やエッジとも）と呼ばれる[1]。

であり、ノード(頂点)をエッジ(辺)で結んだものになります。

まずはグラフを定義しましょう。グラフを作るには`State`を定義する必要があります。`State`は`TypedDict`で、以下のコードのように定義されます。
```py
from typing_extensions import Annotated, TypedDict
from langgraph.graph import StateGraph

def reducer(a: list, b: int | None) -> list:
    if b is not None:
        return a + [b]
    return a

class State(TypedDict):
    x: Annotated[list, reducer]
    message: str

graph = StateGraph(State)
```

`State`は各ノードで更新されます。ノードの戻り値に含まれたキーのみ上書きされますが、`x`のように`Annotated`で reducer 関数を設定することにより、リストを加算する形で更新されます。
チャットボットを作成する場合、人間の入力や LLM の応答をリストとして保存したいので、そのための reducer 関数が用意されているのでそれを使うことが多いでしょう。
```py
from typing_extensions import Annotated, TypedDict
from langgraph.graph import StateGraph
from langgraph.graph.message import add_messages

class State(TypedDict):
    messages: Annotated[list[AnyMessage], add_messages]

graph = StateGraph(State)
```

# ノード
ノードではなんらかの処理を行い、`State`を更新します。
ノードは`State`を受け取り、`State`の更新情報の`dict`を戻り値とした関数として定義されます。
`add_node`でグラフに追加します。
```py
def add_1_node(state: State) -> dict:
    next_x = state['x'][-1] + 1
    return {"x": next_x}

graph.add_node("add_one", add_1_node)

def div_by_2_node(state: State) -> dict:
    next_x = state['x'][-1] / 2
    return {
        "x": next_x,
        "message": "div2!"
    }

graph.add_node("div_by_two", div_by_2_node)
```
開始・終了用のノードが用意されています。
```py
from langgraph.graph import START ,END
```

# エッジ

単純にノードからノードへ結ぶ場合は`add_edge`で設定できます。
```py
graph.add_edge(START, "add_one")
```
1つの始点ノードから複数の終点ノードへとエッジを結びたい場合は`add_conditional_edges`を用います。
```py
def is_even(state: State):
    return state['x'][-1] % 2 == 0

graph.add_conditional_edges("add_one", is_even, {True: "div_by_two", False: END})
```

# グラフのコンパイル
残りのエッジを追加します。
```py
graph.add_edge("div_by_two", END)
```
グラフへのノードとエッジの追加が終わったら最後にグラフをコンパイルします。
```py
app = graph.compile()
```
数字に1を足し、偶数だったら2で割り、奇数だったらそのままという処理をするグラフが作成されました。
![qiita_test_graph.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3657697/d2f8721d-ab63-3209-0a36-0bdf893ea20a.png)


# 実行
`State`の初期値を与えて`invoke`すれば実行されます。
```py
result1 = app.invoke({"x": 3})
result2 = app.invoke({"x": 4})

print(result1)
# {'x': [3, 4, 2], 'message': 'div2!'}
print(result2)
# {'x': [4, 5]}
```
期待通りの処理が行われました。

# おわりに

今回は LangGraph でグラフを作り、簡単な計算を行いました。次回はノードでLLMを利用する話を扱いたいと思います。

その②を書きました。

https://qiita.com/ssc-ymuramatsu/items/77bf574d71811df83dd9

# 参考文献
LangGraph公式
- [Conceptual Guides](https://langchain-ai.github.io/langgraph/concepts/)
- [Reference](https://langchain-ai.github.io/langgraph/reference/graphs/)
GOジェネレータとクロージャについて基本

## ジェネレータ
ジェネレータとは、遅延評価によって値を生成する関数やメソッドのことを指す。ジェネレータは通常、データのシーケンスを逐次的に生成するために使用される。

![napkin-selection (17).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3690843/4a43deba-61bc-a5db-9c61-c314b3380be1.png)




ジェネレータの実装
GoにはPythonやJavaScriptのような組み込みのジェネレータ機能はないが、チャネルとゴルーチンを使ってジェネレータのような機能を実装することができる。

```go
package main

import "fmt"

// ジェネレータ関数
func fibonacci() chan int {
    ch := make(chan int)
    go func() {
        x, y := 0, 1
        for {
            ch <- x
            x, y = y, x+y
        }
    }()
    return ch
}

func main() {
    fib := fibonacci()
    for i := 0; i < 10; i++ {
        fmt.Println(<-fib)
    }
}
```
説明
fibonacci関数は、整数を生成するチャネルを返す。
ゴルーチン内でフィボナッチ数列を生成し、生成された値をチャネルに送信する。
main関数では、ジェネレータから10個のフィボナッチ数を取得して出力する。
## クロージャ
クロージャとは、関数とその関数が作成された環境を合わせたものを指す。クロージャは、関数内で定義された変数を関数外からアクセスできるようにする。

```go
package main

import "fmt"

func incrementor() func() int {
    var x int
    return func() int {
        x++
        return x
    }
}

func main() {
    inc := incrementor()
    fmt.Println(inc()) // 1
    fmt.Println(inc()) // 2
    fmt.Println(inc()) // 3
}
```
### 説明
incrementor関数は、整数をインクリメントするクロージャを返す。
xはクロージャの中で保持される変数で、クロージャ内でインクリメントされる。
main関数では、incというクロージャを生成し、呼び出すたびにxがインクリメントされる。
## 【まとめ】
### ジェネレータ
概要: 遅延評価によって値を逐次生成する機能。
実装: Goではチャネルとゴルーチンを用いて実装する。
用途: データのシーケンスを逐次的に生成する。
### クロージャ
概要: 関数とその関数が作成された環境を合わせたもの。
特徴: 関数内で定義された変数を関数外からアクセス可能。
用途: 状態の保持やカプセル化。
LibreOfficeCalc: Python のマクロを作成、実行

## プログラム

フォルダーの作成

```bash
cd .config/libreoffice/4/user
mkdir -p Scripts/python
```

```py:.config/libreoffice/4/user/Scripts/python/hello_world.py
import uno

def hello_world():
    doc = XSCRIPTCONTEXT.getDocument()
    cell = doc.Sheets[0]['A1']
    cell.setString('12')
    cell = doc.Sheets[0]['B2']
    cell.setString('34')
    cell = doc.Sheets[0]['C3']
    cell.setString('56')
    cell = doc.Sheets[0]['C4']
    cell.setString('78')
    cell = doc.Sheets[0]['C5']
    cell.setString('910')
#
    cell = doc.Sheets[0]['E1']
    cell.setString('PythonからCalcでHello World Aug/2/2024')
    return
```

## 実行

ツール -> マクロ -> マクロの管理 -> Python(A)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/9a80658c-b685-f68f-c5c2-00ee00ac2fbe.png)

実行結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/62e2af09-da93-93dd-02a7-c943bbc38c9f.png)

## 参考ページ

[LibreOffice: Python のマクロを使う](https://qiita.com/ekzemplaro/items/d456b105aa918302e273)
Depth Completion(深度補完) 関連で使われていることのあるライブラリ

## はじめに
`pip install -r requirements.txt` などと一気にライブラリのインストールをしていると、どのライブラリが何のために使われているのかを無自覚になってしまいがち。
そこで、最近使っているrepository の中の依存ライブラリを調べてみた。

## 想定する読者
- 3Dカメラで取得したdepth(深度)を改善することに関心のある人
(日本の中に何人いるんだ？　ほぼ俺得)

## EXR 画像ファイルの読み書き用のライブラリ
画像のbit幅が8bitには収まらないような画像を扱うためのファイル形式のライブラリ
[OpenEXRとは](https://ja.wikipedia.org/wiki/OpenEXR)
画像ファイルの拡張子は.exrとなります。

```
apt install -y openexr
pip install OpenEXR
pip install pyexr
```

viewをインストールする。
```
apt install -y openexr-viewer
```
## open3d
3Dの点群データを扱うためのライブラリ

open3d はcudaをサポートしている。
[open3d.cuda.is_available](https://www.open3d.org/html/python_api/open3d.cuda.is_available.html)

[ARM support](https://www.open3d.org/docs/release/arm.html)
Open3Dは、LinuxとmacOS (Apple Silicon)で64ビットARMアーキテクチャ(arm64またはaarch64)を実験的にサポートしています。Open3D 0.14から、LinuxとmacOS用にコンパイル済みのARM64 wheelを提供します。



```
pip install open3d
```

- [備忘録：Open3DとPythonで点群を取得・表示する【Linux】](https://qiita.com/Ko_Kiduchi/items/60b8829d608d7f4317cb)
- [Open3Dの使い方：複数の点群を位置合わせするGlobal Optimization](https://qiita.com/tttamaki/items/648422860869bbccc72d)
- [OpenVINOとOpen3Dを用いて、CPUで入力動画から3次元復元する](https://qiita.com/hon_nalgo/items/7e62ccdb505b1baf181d)


## [Transforms3d](https://matthew-brett.github.io/transforms3d/)
This package is a collection of Python functions and classes to create and convert 3-dimensional transformations such as rotations, zooms, shears and reflections.

```
pip install transforms3d
```

## h5py
バイナリーデータファイルのフォーマット HDF を扱う Python ライブラリ
https://docs.h5py.org/en/stable/
```
pip install h5py
```
## imageio

imageio.imread()
imageio.imwrite()
するためのライブラリ


```
pip install imageio
```

- `import cv2` してるけど、本当にcv2を使う必要ある？
アルゴリズムの多くが、OpenCV以外のところで開発されているのを使っていると、
実は、入出力くらいにしかOpenCVを使っていないことに気づいてしまった。

imageio.imread()
https://imageio.readthedocs.io/en/v2.16.1/_autosummary/imageio.imread.html

imageio.imwrite()
https://imageio.readthedocs.io/en/v2.11.0/reference/_core_29/imageio.imwrite.html

matplotlib を使っていると
plt.imshow()を使うことで、cv2.imshow() さえ出番がない。



## [imgaug](https://github.com/aleju/imgaug)
Image augmentation for machine learning experiments.
機械学習のために画像データのaugmentationを実行するライブラリ

https://pypi.org/project/imgaug/

## shapely
https://pypi.org/project/shapely/
Manipulation and analysis of geometric objects in the Cartesian plane.

```
pip install shapely
```
- [Shapelyを使ってみよう](https://www.gis-py.com/entry/shapely)

## tqdm
プログレスバーを表示させるためのライブラリ

```
pip install tqdm
```
そこの君！機械学習やるって言って、結局やってないよね？


# はじめに
こんにちは、エイです！

あなたは、
**「機械学習やりたいけど、
　最初って何をすればいいんだろう？」**
と思ったことがありませんか？

私は最初に何をすればいいかで迷いました！
<br>
今回、
機械学習で設定する
最初の目標の1つとして

**「Kaggle LearnのXGBoost」**

を紹介したいと思います！

<br>

**Kaggle**とか**XGBoost**とか

最初にたくさん言われても
何が何やら分かりませんよね！

私も最初見たときは分かりませんでした…
なので、以下に簡単に説明したいと思います！

<br>

機械学習は、扱うデータの種類が
「数値」「画像」「音声」「テキスト」
とありますが、

この記事は「**数値**」のデータに関する内容になっています。


# Kaggleとは

Kaggleは
機械学習のモデルを作成して
その精度を競い合うプラットフォームです。

https://www.kaggle.com/

機械学習に関する職業に就いている人で
知らない人はいません！！


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2954816/ded8665a-a8d3-8932-4ffb-0197d9eed97e.png)


# XGBoostとは

今回、「数値」のデータについての
機械学習の始め方を書いていると前述しました

XGBoostは、
数値データに対して
**よく使われるモデルの1つ**と言われます

<br>
どのようなものか、については
以下の記事が分かりやすいです！

https://toukei-lab.com/xgboost


ではさっそく、
XGBoostを始める方法について
見ていきましょう！

# はじめかた

０．この記事を見てほしい人
１．Kaggleのアカウント登録
２．Learnに移動
３．Intermediate Machine Learning
４．レベル別手順

## ０．この記事を見てほしい人

今回は、
言語に関する内容ではなく、
「**機械学習とは何か**」を
知りたい方に向けて書いています。

<br>
あなたがPythonを使用したことが
無いのであれば、

以下のProgateで学習してから、
ぜひいらしてください！

基本文法について、日本語のサイトで、
無料ですので学びやすいと思います！

https://prog-8.com/courses/python

<br>
では、XGBoostに向けて
進んでいきましょう！

## １．Kaggleのアカウント登録

まずは、以下のリンクに従って
Kaggleのアカウント登録をしましょう！

https://qiita.com/makaishi2/items/0d9ca522733a6d9b1ca8

https://www.kaggle.com/



Kaggleは英語で書かれたサイトとなっています。
英語が苦手な方は、

ブラウザについたGoogle翻訳や、
Chromeであれば、
以下のような拡張機能を追加しましょう！

https://chromewebstore.google.com/detail/google-%E7%BF%BB%E8%A8%B3/aapbdbdomjkkjkaonfhkkikfgjllcleb?hl=ja

https://chromewebstore.google.com/detail/deepl%E7%BF%BB%E8%A8%B3/cofdbpoegempjloogbagkncekinflcnj?hl=ja

<br>


## ２．Learnに移動

左上からメニューを開いて、
「Learn」に移動しましょう

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2954816/ded8665a-a8d3-8932-4ffb-0197d9eed97e.png)



## ３．Intermediate Machine Learning

上から4番目の
「Intermediate Machine Learning」
をクリックしましょう！
<br>
すると、
Intermediate Machine Learningの
一覧画面に移動します

この6番目に、
XGBoostがあります！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2954816/3826f51c-f7d7-85c6-03d3-e487b0715bb6.png)




![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2954816/c406b317-1f0b-14f1-900f-ae6760fd6423.png)


### すすめかた


この「Intermediate Machine Learning」は、

**数値データのモデル作成の基本**が
詰まっています！！

<br>

1~5では、数値データの前処理や分析の仕方が
記述されているのですが、

あなたがもし「**好きなものから食べたい派**」であれば、
6のXGBoostからやってしまうのが良いと思います！

**モデルを作成していることを
一番実感しやすい**部分となっているためです！

<br>

答えを見ながら
**雰囲気を把握して学習する！**
という目的で、

6のXGBoostから、ぜひやってみましょう！

<br>

答えについて、
書籍や記事を検索しながら理解を深めましょう！

以下はおすすめの書籍と記事です

https://www.kspub.co.jp/book/detail/5190067.html

https://future-architect.github.io/




## ４．おわったあと

XGBoostが軽量化し、高速化した機械学習のモデルで、
「**LightGBM**」というものがあります！

今回、Kaggleに載っているためXGBoostを紹介しましたが、
LightGBMは非常に人気なモデルとなっています

<br>

XGBoostとの差分で学習できるので、
学習がしやすいと思います！

ぜひこれを使えるようになって
Kaggleで大会に参加しましょう！


# おわりに

今回、この記事を読んでいただき、
ありがとうございました！

実は、私も現在機械学習について学習中で、
誤った内容を紹介しているかもしれません。

その場合には、
以下のアカウントに連絡していただけると
ありがたいです。

はじめたばかりの方は、
ぜひ一緒に学習を進めていきましょう！

https://x.com/ray03j
Ubuntu 20.04 に TensorFlow 2.5.0 と jupyterlab をインストール

## はじめに
TensorFlow 2.5.0 をどうしてもインストールしないといけない状況で、jupyterlabもインストールしたらエラーが出たので、記録しておきます。

## インストール
CUDA 11.2 CUDNN 8.1 で構築していて、venvの仮想環境にpipを使用して普通にインストールします。
```
$ pip install tensorflow==2.5.0
```
別にエラーも出ずに終わりました。続いて jupyterlab をインストールします。
```
$ pip install jupyterlab

ERROR: pip's dependency resolver does not currently take into account all the packages that are installed. This behaviour is the source of the following dependency conflicts.
tensorflow 2.5.0 requires typing-extensions~=3.7.4, but you have typing-extensions 4.12.2 which is incompatible.
```

TensorFlow 2.5.0 に対して typing-extensions のバージョンが高すぎるようです。

```
$ pip install -U typing-extensions==3.7.4.3

ERROR: pip's dependency resolver does not currently take into account all the packages that are installed. This behaviour is the source of the following dependency conflicts.
anyio 4.4.0 requires typing-extensions>=4.1; python_version < "3.11", but you have typing-extensions 3.7.4.3 which is incompatible.
async-lru 2.0.4 requires typing-extensions>=4.0.0; python_version < "3.11", but you have typing-extensions 3.7.4.3 which is incompatible.
```

今度は anyio と async-lru が文句を言ってますね。。。

```
$ pip install -U anyio==4.1.0 typing-extensions==3.7.4.3

ERROR: pip's dependency resolver does not currently take into account all the packages that are installed. This behaviour is the source of the following dependency conflicts.
async-lru 2.0.4 requires typing-extensions>=4.0.0; python_version < "3.11", but you have typing-extensions 3.7.4.3 which is incompatible.

$ pip install -U anyio==4.1.0 async-lru==1.0.3 typing-extensions==3.7.4.3

Installing collected packages: async-lru
  Attempting uninstall: async-lru
    Found existing installation: async-lru 2.0.4
    Uninstalling async-lru-2.0.4:
      Successfully uninstalled async-lru-2.0.4
Successfully installed async-lru-1.0.3
```

バージョンを落としていきながら調整してなんとか入りました。

```
$ pip check
No broken requirements found.
```
自動販売機のシステムを作ってみる part2 -SQLファイルの作成-

SQLファイルの作成方法、MySQLでの実行方法をまとめる。

## SQLファイルの作成
1. Textファイルの拡張子を.sqlに変更する。
    ![extension.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3850581/cc3f31ea-256f-fe91-c202-58a7ba9bd6d1.png)
2. test.sqlにSQLコマンドを入力する。※この際、セミコロン(;)を付ける。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3850581/a613e28b-faf0-aeca-c26c-910172f42ce2.png)
3. ファイルをローカルフォルダに置く。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3850581/2dfeafba-0710-fbcd-03c5-9a48384fccf9.png)

## MySQLにてSQLファイルを実行
1. コマンドプロンプトを開く。
2. `mysql -u (ユーザ名) -p`にてMySQLにログインする。
3. `source`コマンドでsqlファイルを選択し実行する。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3850581/478ef72e-26b9-63ba-234c-c3da4ab809dd.png)
4. test.sqlの内容が実行される。

## DBを作成する。
SQLファイルを用意する。

<details>
<summary>データベース作成するファイル</summary>

```create_db.sql
SHOW databases;
CREATE DATABASE vending_machine;
SHOW databases;
```

</details>

<details>
<summary>テーブル作成するファイル</summary>

```create_table.sql
USE vending_machine;
SHOW tables;

CREATE TABLE item_info(id INT AUTO_INCREMENT, name TEXT, code TEXT, type TEXT, PRIMARY KEY (id)) DEFAULT CHARSET=utf8;
CREATE TABLE item_stock(id INT AUTO_INCREMENT, code TEXT, stock INT, PRIMARY KEY (id)) DEFAULT CHARSET=utf8;
CREATE TABLE item_price(id INT AUTO_INCREMENT, code TEXT, price INT, PRIMARY KEY (id)) DEFAULT CHARSET=utf8;
CREATE TABLE temp_type(id INT AUTO_INCREMENT, code TEXT, name TEXT, PRIMARY KEY (id)) DEFAULT CHARSET=utf8;
CREATE TABLE money_stock(id INT AUTO_INCREMENT, money INT, name TEXT, stock INT, PRIMARY KEY (id)) DEFAULT CHARSET=utf8;
CREATE TABLE purchase_history(id INT AUTO_INCREMENT, code TEXT, money INT, PRIMARY KEY (id)) DEFAULT CHARSET=utf8;

DESCRIBE item_info;
DESCRIBE item_stock;
DESCRIBE item_price;
DESCRIBE temp_type;
DESCRIBE money_stock;
DESCRIBE purchase_history;

SHOW tables;
```

</details>

<details>
<summary>money_stockテーブルにレコートを追加するファイル</summary>

```money_stock_table.sql
USE vending_machine;
SHOW tables;
SELECT * FROM money_stock;

INSERT INTO money_stock(money, name, stock) VALUES (10, '10円', 10);
INSERT INTO money_stock(money, name, stock) VALUES (50, '50円', 10);
INSERT INTO money_stock(money, name, stock) VALUES (100, '100円', 10);
INSERT INTO money_stock(money, name, stock) VALUES (500, '500円', 10);
INSERT INTO money_stock(money, name, stock) VALUES (1000, '1000円', 10);
INSERT INTO money_stock(money, name, stock) VALUES (5000, '5000円', 10);
INSERT INTO money_stock(money, name, stock) VALUES (10000, '10000円', 10);

SELECT * FROM money_stock;
```

</details>

※現在、money_stockテーブルにレコードを追加するファイルはエラーを吐く。
```
ERROR 1406 (22001): Data too long for column 'name' at row 1
```
`INSERT INTO`文で`name`カラムの値が長すぎるようであるが、1行ずつの実行では問題ないため原因は不明。

## 引用

https://style.potepan.com/articles/25532.html

## 仕様設計

https://qiita.com/H_T_6221/items/833a476007ef6754f6b5
Kubernetesのカスタムコントローラーを開発するためのツール

## 概要
Kubernetesのカスタムコントローラーを開発するためのツールを調べる

## 前提知識
オペレーター ≒ カスタムリソース + カスタムコントローラー
https://kubernetes.io/ja/docs/concepts/extend-kubernetes/operator/

## 調査対象の選定
KubebuilderとOperator SDKがよく使われていそう
https://kubernetes.io/ja/docs/concepts/extend-kubernetes/operator/#writing-operator

## Kubebuilderの使い方
https://book.kubebuilder.io/quick-start
```
$ brew install kubebuilder
$ kubebuilder init --domain my.domain --repo my.domain/guestbook
$ kubebuilder create api --group webapp --version v1 --kind Guestbook
$ make manifests install run
```

## Operator SDKの使い方
https://sdk.operatorframework.io/docs/building-operators/golang/quickstart/
```
$ brew install operator-sdk
$ operator-sdk init --domain example.com --repo github.com/example/memcached-operator
$ operator-sdk create api --group cache --version v1alpha1 --kind Memcached
$ make manifests install run
```

## KubebuilderとOperator SDKの比較
* Operator SDKがKubebuilderをライブラリとして使用している
* 初期化のコマンドや生成されるコードはほぼ同じ
* Operator SDKはより複雑なことができる
* Operator SDKは[Operator Lifecycle Manager](https://olm.operatorframework.io/)と組み合わせて使える

## まとめ
まずはKubebuilderを使ってみるのが良さそう
複数のコントローラーを運用する場合などではOperator SDKの使用を検討すると良さそう
WEB開発者がLinuxデスクトップを使うべき12の理由

### 1.Unixコマンドに日常的に慣れろ

Linuxを使っていると、結構CUI処理をしたり、困ったときにCUIでの処理をすることが多いです。それが開発に生きてきます。

実際の仕事の現場でも、一斉ファイル処理、緊急対応や顧客からの調査依頼などでCUI環境に入って操作することが多いです。他にもDockerの設定などで、aptでの各種インストールやLinuxならではのファイル構成に起因した記述などもすること多いです。

Windows Subsystem for Linuxがある?？？あんな使いづらいもの使うくらいならネイティブでLinux使いましょう。

### 2.Macに比べてDockerがくっそ速い

「Unixコマンドや環境に慣れるだけなら別にMacでもいいじゃん」まぁ、そうです。またGUI操作という点でみても、Macの方がかなり痒い所に手が届きますし、直感的です。

が、Dockerを使って開発しだすと、Mac版の遅さが物凄いストレスです。Linux(私はUbuntuを使っています)で基本的なDockerを立ち上げると超早い！そのスピードたるや段違いです。WEB開発する上で、Dockerを使って環境構築をするのは割と日常的なことだとも思うので、

### 3.MicrosoftOffice? LibreOfficeで十分です

「とはいえ、Excelとかパワポとか、MSOfficeないと業務上不便じゃないですか？」

一体貴方はいつの話をしているのでしょう？全く不便ではないです。LibreOfficeはMSOfficeとの互換性が非常に高く、それでいて無料です。

### 4.安い、速い

Macに対して一般的なゲーミングPCやゲーミングノートの方が、費用に対しての性能が高いです。ちょっと遊びでGPUを使う機械学習系のアプリ動かしたい、というときは、NvidiaのGPUを搭載したゲーミングPCを買うと、結構快適に動いてくれたりします。自宅でチョチョイって出来るの、良いです。

### 5.Webブラウザは標準化されました

IEが死に、Microsoftも独自路線を辞め、Safari,Chrome、Edgeなど、基本的にはどのブラウザでも規格は標準化されています。その結果、Linuxを使っているからWEB系で困るということもなくなりました。

ただ、ヤフー系のサービスなど、未だに一部サービスではユーザーエージェント見てLinux弾いてくる不届きサービスがいます。そんなときはブラウザのユーザーエージェントをWindows/Chromeとかに偽装したらだいたい通ります。

### 6.主要なアプリケーションは大体揃っている

VSCode、動画編集、音楽再生、痒い所に手が届くツール、Discord、Zoom、Slackといったビデオ会議やチャットツール、だいたい一通り揃っています。Linuxデスクトップだったからこれが動かなくて困った、こんな痒い思いをしている…というのは、iPhoneの同期を除くと今の所ほとんどありません。

コチラも参考にしてください。

https://qiita.com/michi_taka/items/2d11fbc88c9cd0a4aed0

### 7.周辺機器は大体使える

マウス、キーボード、ゲームコントローラー、プリンタ・スキャナ、キャプチャボード、WEBカメラ、USマイク、CD/DVDドライブ、外付けHDD、サウンドUSB DAC…etc。Linuxだから動かなかったというのは今の所ありません。相当特殊な機器で、Windowsでないとドライバが無い、みたいなことを除き普通の機器を使う分にはLinuxで大丈夫です。

### 8.カスタマイズ性が優れている→作業効率が上がる

個人的な感想ですが、Windowsよりカスタマイズ制が優れている印象を受けました。現在Logicoolのトラックボールを使っているのですが、Windowsの公式の物より圧倒的にUbuntuでやったほうが色々出来て、良い感じでした。他にも見た目を結構ドラスティックに変えたり、MacOSそっくりの外観にしたりなど、意外とやりたい放題出来ました。MacやWindowsと違い「こういう使い方をしなさい」というのが強制されていないのがいい感じです。

https://qiita.com/michi_taka/items/4ab4bf8e1dd0316dada6

### 9.みんな記事を共有してくれていて、意外と困らない

Linux、特にUbuntu界隈は、困ったことがあると、だいたい検索かけると有志の誰かが記事を書いてくれていたりします。インストールしたら画面の色がおかしいとか、サウンドの設定が毎回変わってしまうから固定したいとか、Dockやデスクトップにゴミ箱設置してほしいとか、この形式の動画を見られるようにしてほしいとか、結構みんな書いてくれています。なので、困ったときも意外と困らないのです。

### 10.実はWindowsゲームが動く？

Steamで、実はWindows専用のゲームが動いたりします。互換ツールを使用することで、なんと、信長の野望の最新作がうごいたりしました。もちろん全てのゲームで上手く行くわけではないですが、ゲームするならWindowsじゃなくてはいけない、ってことはなくなりつつあります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293892/5e477ba2-95fc-fbd1-81ee-8c84d26cea2d.png)


### 11.意外とフォントが綺麗

Ubuntu、フォントが綺麗で見やすいです。Macってフォント綺麗だよねって言われてましたが、Ubuntu意外と負けていないです。コーディングとかするときに、見やすくて作業的にもはかどります。

↓こんな見え方します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293892/9e6f8eba-468d-b63c-397e-f7f44b21a3e2.png)


### 12.困ったときはWindows?デュアルブートしちゃえ！

どうしても困ったときはWindowsとデュアルブートすることをおすすめします。このゲームが動かないとか、そういうときはWindowsとデュアルブートにしてしまいましょう！最高です！

## 実は困ること

### iPhoneの同期

iTunesのUbuntu版期待しています。こればっかりはマジで不便。

### iOSアプリ開発。特にデバッグ周り

iOSの開発がLinuxで出来ないわけではないのですが、デバッグしたりがMacに比べるとやはりやりづらいそうです。
システム問合せを受けた際、すぐにソースコードを調べてはいけない（戒め）

# 背景

自分は開発のみ担当で、リリース後のシステムには関わらない生活を10年ほど送っていました。

今回初めてユーザー対応をすることになりました。

最初はよくわからず対応してましたが、半年ほどでだいぶ要領がつかめてきました。
今回は自分が心掛けていたことを紹介します。

# 想定する環境

・自分が部分的に修正、機能追加してるシステムへの問い合わせ
・問い合わせてくるのは同社の別部門

# 問い合わせ発生

ユーザー「xxxシステムで、xxxをすると〇〇〇になるんですけど、どうしてですか？」

大抵はこんな感じでかかってきます。

自分が心掛けていた調査手順はこんな感じです。

１：ユーザーの理想状態と、現状を把握する
２：ユーザーの勘違いを疑う
３：データを疑う
４：プログラムを疑う

## ユーザーの理想状態と、現状を把握する

まずは「xxxをする」の部分を具体化します。
「xxxの画面で、xxxと入力して[決定]をクリックする」くらいに落とし込めればOKです。

入力内容は口頭だと正確に伝わらないので、ログを確認します。
（半角全角、スペース、アルファベットの綴りなどは伝達ミスが起こり得ます）

つぎに「理想状態」を具体化します。
「入力内容に関連したxxxリストが出てほしい」みたいな感じです。

ここまで聞いたら、調査に入ります。


## ユーザーの勘違いを疑う

自分は長年開発したやってこなかったせいか（もしくは仕事できないせい）、初手で「プログラムにミスがあるのではないか」と考えてしまってました。

しかし、プログラムは基本的にテストをされた後にリリースされています。プログラムミスの可能性はかなり低いです。
システムの操作マニュアルを見て、想定された使い方なのか確認しましょう。

ユーザーが使い方を熟知していないケースは結構あります。
年に数回しか使われない機能の場合、ユーザーが正しい使い方を忘れている可能性もあります。
または新人が、現場のリーダーが休みで質問できず、システム部に問い合わせる場合もあります。


## データを疑う

想定外のデータが入っていないか確認します。主には「全角スペース」「半角スペース」「改行」です。
僕が担当したシステムでは「ユーザーが入力したデータをチェックせずにDBへ入れる」というケースがあったため、想定外データが入るケースは多かったです。


## プログラムを疑う

ここまで来たら、ようやくプログラムを見ていきます。
プログラムの見方は他の記事を参考にしてください（おい
LibreOffice: Python のマクロを使う

次のページを参考にしました。
[LibreOffice CalcでPythonマクロを使う(1) ](https://takacity.blog.fc2.com/blog-entry-214.html)

## 環境構築

Ubuntu 24.04 のデフォールトの LibreOffice の環境では、Python のマクロは使えません。

次を実行して下さい。

```bash
sudo apt install libreoffice-script-provider-python
```
## サンプルの実行

Calc を立ち上げて

ツール -> マクロ -> マクロの管理 -> Python(A)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/0428ab54-37d0-5038-d1db-34f34ef89304.png)

HelloWorldPython を実行させます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/407f0d26-6e6f-b10b-473b-b3821ac935b7.png)

    Writer が立ち上がって、次のように表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/ae650408-febd-9fd5-463a-c7f5f50254bb.png)

## プログラム

サンプルは次のフォルダーにあります。

```text
/usr/lib/libreoffice/share/Scripts/python
```

```text
$ tree
.
├── Capitalise.py
├── HelloWorld.py
├── InsertText.py
├── NamedRanges.py
├── ScriptForgeHelper.py
├── SetCellColor.py
└── TableSample.py

1 directory, 7 files
```

ソースコード

```py:HelloWorld.py
# HelloWorld python script for the scripting framework

#
# This file is part of the LibreOffice project.
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
# This file incorporates work covered by the following license notice:
#
#   Licensed to the Apache Software Foundation (ASF) under one or more
#   contributor license agreements. See the NOTICE file distributed
#   with this work for additional information regarding copyright
#   ownership. The ASF licenses this file to you under the Apache
#   License, Version 2.0 (the "License"); you may not use this file
#   except in compliance with the License. You may obtain a copy of
#   the License at http://www.apache.org/licenses/LICENSE-2.0 .
#

def HelloWorldPython():
    """Prints the string 'Hello World (in Python)' into the current document.
    """

    # Get the doc from the scripting context which is made available to all
    # scripts.
    desktop = XSCRIPTCONTEXT.getDesktop()
    model = desktop.getCurrentComponent()

    # Check whether there's already an opened document.
    # Otherwise, create a new one
    if not hasattr(model, "Text"):
        model = desktop.loadComponentFromURL(
            "private:factory/swriter", "_blank", 0, ())

    # get the XText interface
    text = model.Text

    # create an XTextRange at the end of the document
    tRange = text.End

    # and set the string
    tRange.String = "Hello World (in Python)"

    return None

# vim: set shiftwidth=4 softtabstop=4 expandtab:
```
vitestでテストを実行する

# vitestのテスト実行
package.jsonのscriptsに下記を記載します。

```json
    "test": "vitest run",
```

## テストを全件実行する場合

テストコマンドを実行するたけです。
```bash
yarn test
```

## テストをファイル単位で実行する場合

テストコマンドの後に、ファイルの相対パスを指定します。
```bash
yarn test src/app/hello.test.ts
```
【React】create-react-appのデフォルトアプリがどうやって回転しているのか

## 動機
ただ，こいつがどうやって回転しているのか気になったのでコード眺めたというだけの話。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3718390/d474daf0-640b-980e-e672-bb61cda25ea4.png)

---

## どうやって動いているのか
結論
- App.cssに回転の設定がある。jsとかで動いているわけではない。
- App.tsxのアイコンのclass名にこの設定が適用されている。

### App.cssの説明

```App.css
@media (prefers-reduced-motion: no-preference) {
  .App-logo {
    animation: App-logo-spin infinite 20s linear;
  }
}
```
この部分が該当部分です。`App-logo`に対してanimationのプロパティを設定しています。
- `App-logo-spin`: アニメーションの名前
- `infinite`: 無限ループ
- `20s`: 1サイクルの時間。試しに1sにしたら爆速で回転した。
- `linear`: 線形でアニメーションんが進行する。[animation](https://developer.mozilla.org/ja/docs/Web/CSS/animation)見るとeaseとかease-in等いろいろオプションがありそう。

補足: [`@media prefers-reduced-motion`](https://developer.mozilla.org/ja/docs/Web/CSS/@media/prefers-reduced-motion)はユーザがページの動きを少なくする設定時の動作を規定しており，no-preferenceになっているので該当時にはアニメーションは動きません。

---

この`App-logo-spin`に関して追加で回転範囲の設定が入っています。

```App.css
@keyframes App-logo-spin {
  /* 360度回転する*/
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}
```
[@keyframes](https://developer.mozilla.org/ja/docs/Web/CSS/@keyframes)はキーフレームを制御するため，fromとtoでアニメーションの始まりと終わりを定義しています。

## App.tsxの設定

```App.tsx
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
```
こんな感じでlogo画像にCSSのclassName`App-logo`を指定することで適用しています。
他の部分も同じ設定にすれば回転させられるはず。

---

## 感想
Web系のデザインとかあまりやったことないですが，CSSにも細かいオプションがたくさんあるんだなと改めて感じ，CSSは自前で1から書くのは現実的で無いなと思いました。
k8sでゲートウェイPodを介して複数のserviceへ一度にport-forwardする方法

`kubectl port-forward`は指定したpodのポートをローカルマシンに開いてくれる便利な機能なのですが、例えばpostgres:5432とmemcache:11211を一緒に開けたい場合には二つのpodに別々にport-forwardしなければならず、さらにこれを増やそうとすると面倒な事になります。

そこで、望みのサービスのポートを転送してくれるゲートウェイとなるPodを作ってそれを踏み台にしてport-forwardすることで任意の数の転送を一回のport-forwardで済ませてしまいましょう。

```yaml
apiVersion: v1
kind: Pod
metadata:
  name: gw
spec:
  terminationGracePeriodSeconds: 0
  containers:
  - name: alpine
    image: alpine:latest
    command: ["sh", "-c", "while true; do sleep 3600; done"]
  restartPolicy: Never
```

例えばこんな感じにゲートウェイとなるPodを作成して `kubectl exec -it gw -- sh`で `socat`をインストールします。

```sh
apk add socat
```

続いて socatを使って望みのserviceにポートを転送します

```sh
socat TCP-LISTEN:5432,fork TCP:postgres:5432 &
socat TCP-LISTEN:11211,fork TCP:memcached:11211 &
exit
```

あとはローカル環境から

```sh
kubectl port-forward gw 5432:5432 11211:11211
```
とやれば一度にポートフォワードできます。

転送するサービスを増やしたい時には `kubectl exec -it gw -- sh`で `socat ...`を足してやればokです。

まあ最初から kubectl port-forward が sshのように

```
kubectl port-forward gw 5432:postgres:5432 11211:memcached:11211
```
みたいに書けたら良かったんですけどね
LibreOfficeCalc: Basic のマクロを使う

## プログラムの作成

ルール -> マクロ -> マクロの編集

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/fc1c4d80-44ef-a94d-28d0-a51b20e22320.png)

```text
Sub Main

  Dim oCell1 As Object
  
  oSheet = ThisComponent.Sheets(0)
  oCell1 = oSheet.getCellRangeByName( "A1" )
  oCell1.Value = 12
  oCell1 = oSheet.getCellRangeByName( "B2" )
  oCell1.Value = 34
  oCell1 = oSheet.getCellRangeByName( "C3" )
  oCell1.Value = 56
  oCell1 = oSheet.getCellRangeByName( "C4" )
  oCell1.Value = 78
  oCell1 = oSheet.getCellRangeByName( "C5" )
  oCell1.Value = 910
End Sub
```

## マクロの実行

ツール -> マクロ -> マクロの管理 -> Basicマクロ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/7c1ac059-86d9-06e9-6f5e-d214d7b93fe3.png)

## 実行結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/dd9bdf0a-80d0-fb8b-a14f-495a86aa9b0c.png)
3Dスキャナーにおける光学ズームの応用

遠くにある古城をカメラで撮影していると想像してください。壁のレンガから塔の彫刻に至るまで、あらゆる細部を観察できるようにしたいと考えています。そんなときに便利なのがカメラの光学ズーム機能です。光学ズームを使用すると、これらの細部に「近づく」ことができるだけでなく、画像の高品質を維持することもできます。では、光学ズームとは一体何なのでしょうか？ 3Dスキャナーではどのように使用されますか?一緒に探検しましょう！

光学ズームの基本
光学ズームは、レンズ内のレンズ群を物理的に移動させることで焦点距離を変える技術です。このテクノロジーは、レンズの位置を調整することで、画質を損なうことなく遠くの物体や近くの物体を見ることができるという点で望遠鏡や顕微鏡に似ています。光学ズームは、画像を拡大することによってのみズーム効果を実現するデジタル ズームとは異なり、多くの場合、画像のぼやけや歪みが生じます。
![20181213001752.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3823693/2a61eb9f-b151-cbe2-e755-e840fef9e68d.jpeg)

光学ズームの仕組み
光学ズームの原理は、レンズ内の複数のレンズの位置を変えることです。カメラのズームリングやボタンを調整すると、レンズが動き、レンズの焦点距離が変わります。たとえば、ズームインすると (焦点距離が長くなり)、カメラが捉える画角は小さくなりますが、逆にズームアウトすると (焦点距離が短くなり)、カメラはより小さな画角を捉えることができます。表示されませんが、詳細は縮小される場合があります。

3Dスキャナーにおける光学ズームの応用
3D スキャナーでの光学ズームの適用も同様に重要です。 3D スキャナーは、物体の表面の形状と詳細をキャプチャし、デジタル 3D モデルを生成できるデバイスです。 3D スキャン プロセス中に、光学ズームを使用すると、表面の詳細をより詳細にキャプチャし、スキャンの精度を向上させることができます。
  ![F5D3C214-3271-4044-A7B6-441643EC92EF.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3823693/79468f76-97dc-93be-f302-bc1dafe9efa3.png)

スキャン精度の向上
光学ズームにより、3D スキャナはさまざまな距離でも高解像度を維持できます。これは、オブジェクトのサイズに関係なく、スキャナーが焦点を調整して最も鮮明な細部をキャプチャできることを意味します。たとえば、小さな彫像をスキャンする場合は、光学ズームで細部にズームインして彫刻のあらゆるニュアンスを捉えることができ、車をスキャンする場合は、ズームアウトして全体的な形状をキャプチャすることができます。

スキャン範囲を拡張する
光学ズームはスキャン精度を向上させるだけでなく、スキャナの適用範囲を拡大します。光学ズームを使用するこのスキャナーは、小さな部品から大きな建物に至るまで、さまざまな複雑なスキャン作業を処理できる柔軟性を備えています。これにより、3D スキャン技術は工業デザイン、文化財保護、医療診断などの分野でさらに広く使用されるようになりました。

ユーザーエクスペリエンスの向上
光学ズーム機能により、ユーザーは頻繁にスキャナを移動したり、スキャン対象の位置を調整したりすることなく、必要に応じてフォーカスを調整できます。これにより、作業効率が向上するだけでなく、特に考古学やリバース エンジニアリングなど、高精度のスキャンが必要な一部の専門分野において、運用の複雑さが軽減されます。
![B9F5945F-EEA0-4b57-9C76-A9D772424C0F.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3823693/d221b633-5916-0d9c-9d9e-95b1192cd6cf.png)


今後の展望
科学技術の継続的な進歩により、3D スキャン分野における光学ズーム技術の応用の可能性はさらに広がるでしょう。将来の 3D スキャナーは、より高速で正確なスキャンを実現するために、人工知能や自動化テクノロジーと組み合わせて、より高倍率の光学ズーム機能を備えていると予測できます。同時に、光学ズームモジュールはより小型化および統合され、より多くの種類の機器およびアプリケーションシナリオに適応します。

要約する
光学ズームはレンズの位置を調整することで焦点距離を変える技術で、写真撮影だけでなく、3Dスキャンの分野でも重要な役割を果たします。光学ズームにより、3D スキャナは物体表面の詳細をより正確にキャプチャし、その適用範囲を拡大し、ユーザーの操作エクスペリエンスを向上させることができます。技術の継続的な発展により、光学ズームは 3D スキャンの分野にさらなる革新と画期的な進歩をもたらすでしょう。楽しみに待ちましょう。

https://www.revopoint3d.com/products/portable-3d-scanner-pop3
メモ7

当然，可以使用不通过 AJAX 的方式来实现这个需求。可以通过提交表单时设置一个隐藏字段，然后在提交后使用 JavaScript 打开新窗口。下面是一个示例：

### JSF 页面

```html
<h:form id="mainForm">
    <h:commandButton id="forwardButton" value="Forward" action="#{bean.forwardToPage}" 
                     onclick="document.getElementById('newWindowField').value='true';" 
                     oncomplete="openInNewWindow();"/>

    <h:inputHidden id="newWindowField" value="#{bean.newWindow}" />

    <h:outputText id="newUrlOutput" value="#{bean.newUrl}" style="display:none;" />

    <h:outputScript>
        function openInNewWindow() {
            var newWindow = document.getElementById('newWindowField').value;
            var newUrl = document.getElementById('newUrlOutput').innerText;

            if (newWindow === 'true' && newUrl) {
                window.open(newUrl, '_blank');
                document.getElementById('newWindowField').value = '';
            }
        }
    </h:outputScript>
</h:form>
```

### 后端 Bean

```java
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;

@ManagedBean
@ViewScoped
public class Bean {
    private String newUrl;
    private String newWindow;

    public void forwardToPage() {
        // 调用外部 API 获取 URL
        newUrl = callExternalApiAndGetUrl();
    }

    public String getNewUrl() {
        return newUrl;
    }

    public void setNewUrl(String newUrl) {
        this.newUrl = newUrl;
    }

    public String getNewWindow() {
        return newWindow;
    }

    public void setNewWindow(String newWindow) {
        this.newWindow = newWindow;
    }

    private String callExternalApiAndGetUrl() {
        // 模拟调用外部 API 并返回 URL
        return "https://example.com";
    }
}
```

### 解释

1. **JSF 页面**:
   - `<h:commandButton>` 设置了 `onclick` 和 `oncomplete` 属性。`onclick` 中设置一个隐藏字段 `newWindowField` 的值为 `true`，表示需要在新窗口中打开 URL。
   - `oncomplete` 中调用 `openInNewWindow` 函数。
   - `openInNewWindow` 函数检查隐藏字段 `newWindowField` 的值，如果为 `true`，并且有有效的 `newUrl`，则在新窗口中打开该 URL，并重置隐藏字段的值。

2. **后端 Bean**:
   - `forwardToPage` 方法调用外部 API 并设置 `newUrl` 属性。
   - `newWindow` 属性用于控制是否在新窗口中打开 URL，通过隐藏字段与前端交互。

这种方法不依赖 AJAX，而是通过标准的表单提交和隐藏字段来传递信息，确保在新窗口中打开动态 URL。
自動販売機のシステムを作ってみる part1 -仕様とDB設計-

自動販売機のシステムに必要な事項を並べる。

## 仕様
* 購入サイド
    * 商品一覧を表示
    * 商品の冷たいとあったかいを表示
    * 商品の金額を表示
    * 入れたお金を表示
    * おつりを返す(おつりボタン)
    * 商品を購入できる(商品毎に購入ボタン)
    * うりきれの時は購入できない
    * 連続購入できる
* 販売サイド
    * 自動販売機内のお札と小銭の数を表示
    * 商品の在庫数を表示
    * 売上金額を表示
    * 価格設定ができる
    * 商品補充ができる

## DB設計
データベース名(vending_machine)とする。
レコードは例とする。
テーブル名、カラム名はそのまま使う。

### 商品情報 (item_info)
| id | name | code | type |
|----|------|------|------|
| 1 | コーラ | cola | cold |
| 2 | お茶 | green_tea | cold |
| ： | ： | ： | ： |

### 商品在庫 (item_stock)
| id | code | stock |
|----|------|-------|
| 1 | cola | 10 |
| 2 | green_tea | 10 |
| ： | ： | ： |

### 商品価格 (item_price)
| id | code | price |
|----|------|-------|
| 1 | cola | 180 |
| 2 | green_tea | 140 |
| ： | ： | ： |

### 種別 (temp_type)
| id | code | name |
|----|------|-------|
| 1 | cold | 冷たい |
| 2 | hot | あったかい |

### 貨幣在庫 (money_stock)
| id | money | name | stock |
|----|-------|------|-------|
| 1 | 10 | 10円 | 10 |
| 2 | 50 | 50円 | 10 |
| 3 | 100 | 100円 | 10 |
| 4 | 500 | 500円 | 10 |
| 5 | 1000 | 1000円 | 10 |
| 6 | 5000 | 5000円 | 10 |
| 7 | 10000 | 10000円 | 10 |

※1円、5円硬貨、2000円紙幣は使用できない

### 購入履歴 (purchase_history)
| id | code | money |
|----|------|-------|
| 1 | cola | 180 |
| 2 | green_tea | 140 |
| 3 | water | 100 |
| ： | ： |

## 引用
https://qiita.com/cont_connect/items/d4d14c03bc74ae67f5fd
LaravelのbladeでVue.jsを使用する際、npmでVueを導入する方法（CDN使わない）

blade内にvueを定義しています。
CDNでの導入は簡単でしたが、npmでの導入は詰まったのでやり方残します。

## パッケージの導入

```
npm install vue
npm install @vitejs/plugin-vue
```

## vite.config.jsの追記

```
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import vue from '@vitejs/plugin-vue';

export default defineConfig({
    plugins: [
        vue(), // 追記
        laravel({
            input: [
                'resources/sass/app.scss',
                'resources/js/app.js',
            ],
            refresh: true,
        }),
    ],
    resolve: {
        alias: {
            vue: 'vue/dist/vue.esm-bundler.js', // 追記
        },
    },
});

```


## resources/js/bootstrap.jsの追記

```
// vue.jsの導入（これで各bladeではcreateAppで呼び出せる）
import { createApp } from 'vue';
window.createApp = (options) => {
    return createApp(options);
};
```

## 各bladeにvueを記載する方法

```
<script type="module">
        createApp({
            data() {
                return {
                    selectedType: 10,
                };
            },
            methods: {
            },
        }).mount('#app');
    </script>
```

以上となります。
npm run devでご確認ください。
【メモ】AtCoderで使えそうなSTL

- `gcd`, `lcm`：最大公約数、最小公倍数を返す関数（コメント参照）
- `count`：配列内の指定した区間内に含まれる、指定した要素の個数を返す関数
- `find`：配列内の指定した区間内で、指定した要素を保持する最初のイテレータを返す関数
```C++
#include <bits/stdc++.h>
using namespace std;

int main() {
  cout << gcd(8, 12) << endl; // -> 4
  cout << lcm(8, 12) << endl; // -> 24
  
  vector<int> a = { 1, 2, 2, 1, 1 };
  cout << count(a.begin(), a.end(), 1) << endl; // -> 3
  
  int pos = find(a.begin(), a.end(), 2) - a.begin();
  cout << pos << endl; // -> 1
}
```
RDSにアクセスするだけなら、踏み台サーバは不要。Cloud Shellを使ったRDSアクセス


## 結論
CloudShellがVPC内で使用可能になり、CloudShellを通じてアクセスすることで、踏み台サーバーの必要性はなくなりました。

## CloudShell とは
2020年12月16日にAWSのコンソールに追加された機能で名前の通りシェルが使えます。
AWS CLIなどがあらかじめインストールされており、AWS CLIを使うのに便利です。事前にログインしているIAMの権限がそのまま使えるので、アクセスキーの設定などの初期設定が不要です。mysqlクライアントなどよく使うコマンドはあらかじめ入っています。
https://docs.aws.amazon.com/ja_jp/cloudshell/latest/userguide/welcome.html

## RDSアクセス時の踏み台
昨今のコンテナ化により、webサーバのシェルに触れることが少なくなってきました。こうなると困るのが、web経由でなく直接クエリをRDSに入れたい場合などに、どこからクエリを入れるかです。サーバを自前で持っていた時はwebサーバにmysqlコマンドを入れて、webサーバとDBへの踏み台機能を兼ねるといったことができましたが、コンテナでは難しいです。
場合によってはコンテナ内に入りmysqlクライアントをインストールすることで対応することもできますが、コンテナにシェルが入っていないことも多く、あまり現実的ではないです。

## CloudShellのVPCサポート(CloudShell VPC environment)
CloudShellはVPC内に設置されないため、プライベートネットワーク内のリソースにアクセスすることはできませんでしたが、2024/06/26のアップデートでVPC内のサブネットに上でCloudShellを動かせるようになりました。また、セキュリティグループを持つこともできるのでRDSのセキュリティグループでよくやる、特定セキュリティグループを持つリソースからのアクセスのみを許可するといった設定がされているRDSにも設定変更なしでアクセスすることができます。
https://aws.amazon.com/jp/about-aws/whats-new/2024/06/aws-cloudshell-amazon-virtual-private-cloud/

## 実際に使ってみる
* CloudChellを起動
![スクリーンショット 2024-08-02 13.17.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1418615/0078c194-9472-010f-9cc1-4a4f979e5f26.png)
* VPC内CloudShellを作成
![スクリーンショット 2024-08-01 15.35.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1418615/ef5e4c76-cb02-1261-9aa8-0cdd956ccea4.png)
* 作成するCloudShellのネットワークを設定、Createをクリック
![スクリーンショット 2024-08-01 15.38.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1418615/21db137e-f2a4-10e9-4426-79178f59f23f.png)

* mysqlコマンドでRDSにアクセス
![スクリーンショット 2024-08-02 13.37.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1418615/e0b80f1f-d3e8-848a-5beb-380c90ce2adc.png)

## 困りどころ
上記の通り、RDSにアクセスする環境を比較的簡単に作成することができましたが、これで万事完結とはいきません。

### ローカルツールからのアクセス
mysqlには多くのクライアントツールがありますし、場合によってDBの情報をローカルで処理して結果を取得するコマンドなど作っている場合もあります。こうしたツールはSSHを使った踏み台には対応していますが、CloudShellのことまでは想定していないと思います。またCloudShell自体もブラウザからのアクセスのみを想定しているのか、SDKやCLIが提供されていません。
なのでローカルツールからアクセス必要がある場合は引き続き踏み台サーバが必要になります。

### ファイルのダウンロード、アップロードができない
S3を経由してダウンロード、アップロードするなど回避策はありますが、CloudShellのようにアクションからファイルをダウンロード、アップロードできません。

### 最大2つまでしか設定を保存できない
1つのIAMアカウントあたり2つしか設定が保存できません。なので3つ以上のVPCを使っている場合、必要に応じて削除して作り直す必要があります。自分の場合、環境ごとにVPCを分けており3環境あるので、CloudShell VPC environmentを作ってない環境に接続しようとするたびに設定を削除して作り直しが必要なので、地味に不便です。

## まとめ
制限はあるものの、特に問題なければ踏み台にはCloudShell VPC environmentを使うのが便利だと感じました。自分たちで踏み台サーバを作る場合、踏み台サーバのセキュリティ対応など自分たちサーバの面倒を見なくてはならなず、せっかくコンテナ化しても管理しなくてはいけないサーバが残ってしまっていました。またコスト面でも、使う度サスペンドするか、諦めてサーバを常時立ち上げておくか、Cloud9(サービス終了予定)を使うかなど、といった細かい工夫が必要なり手間をかかるか、コストを呆れめるかの二択でした。CloudShellは基本的には無料なので、コスト面でもメリットがあります。
連載：若手エンジニアのナラティブポエム (3)　～大阪での最終面接 と 新たな挑戦への扉～

どうも
パナソニック アドバンストテクノロジー株式会社（以後、PAD）の @nakamura_tatsuya です。

さて、前回はPADとの初対面と入社を決意した瞬間についてお話ししました。
今回は、大阪での最終面接と、新たな挑戦への扉を開く瞬間について語ります。

更新頻度は某漫画のようですが、連載中です！

* バックナンバー
  [連載：若手エンジニアのナラティブポエム (1)　～自己紹介 と 僕がPADを知ったきっかけ～]
  [連載：若手エンジニアのナラティブポエム (2)　～PADとの初対面 と 入社決意の瞬間～]

[連載：若手エンジニアのナラティブポエム (1)　～自己紹介 と 僕がPADを知ったきっかけ～]: https://qiita.com/nakamura_tatsuya/private/ec1f059c974bc5e848f4
[連載：若手エンジニアのナラティブポエム (2)　～PADとの初対面 と 入社決意の瞬間～]: https://qiita.com/nakamura_tatsuya/items/7461ccd2c5e1a8c8d1e0



# 大阪での最終面接

初対面での感動が冷めやらぬまま、僕はすぐにオープンカンパニーに応募しました。
応募が受理され、無事に参加することができ、新卒採用の選考を受けようと思いました。

なんやかんや選考は進み、ついに最後の時を迎えました。大阪での最終面接です。

新幹線に乗って大阪へ向かう道中、緊張と期待が入り混じる気持ちを抱えながら、これまでの自分の研究や経験を振り返っていました。**ただ、この日の朝、自分史上最もスムーズにネクタイが綺麗に結べたので、「今日イケるなぁ」とも思っていました (笑)**

大阪の本社に到着し、エントランスをくぐると、どこか懐かしさと新鮮さを同時に感じました。まだこの会社で働いたことないのに、妙にしっくりくるような感じです。案内された会議室で自分の番を待つ間、心の中で自己紹介や質疑応答のシミュレーションを何度も繰り返しました。

そしてついに、「あちらの部屋にノックをしてお入りください」と人事の方に促されました。



# 面接官との対話

部屋に入ると、3人の面接官が座っていました。会社のホームページ等について、よく調べていたので、誰なのかはすぐに分かりました。その内の1人が実際にお会いすると、とても大きな方で驚きました。後に話すと、かなり筋トレをやられていることが判明 (ですよね) 。オフィスを歩く姿は別格の雰囲気を誇っていました。

面接は少しピリッとしながらも、終始和やかな雰囲気で進み、研究内容や志望動機などについて熱心に聞いていただけました。

面接官の一人から、**「あなたの研究が弊社のプロジェクトにどう貢献できると思いますか？」** と尋ねられた時、僕は自分なりに考えたビジョンを精一杯伝えました。自動化技術やセンシング技術の応用について具体的な例を挙げながら、自分の知識と経験がどのように役立つかを説明しました。その熱意が伝わったのか、面接官たちはうなずきながら真剣に聞いてくれました。

A氏との初対面から始まって最終面接までの全体を通して感じたことですが、学生であるが故に、社会的にも、会社で必要な専門技術的にも未熟である僕の考えを、頭ごなしに否定せずに**まずはちゃんと聞こうとしてくれる姿勢**が凄く良かったです。

<br>

「傾聴力」という言葉がありますが、社会に出ると自分の上司や部下、顧客のように、自分と立場が違う相手とお仕事していくことになりますので、信頼構築のためには、やはり必要不可欠なスキルですね。

ただ、ソフトウェア開発の仕事をやっていると"聞くだけ"ではダメで、企画・提案力も大事になってきます。要望を汲み取る中で、相手が気づいていないことに気づき、期待をさらに超えるような案を発想して、それをどれだけお客さんに提案し、開発を推進していけるのか。この部分に世の中に多く存在しているソフトウェア開発会社としての差が出てくると思っています。

私個人の理想としては、お客さんの実現したいシステムの想いを傾聴し、そのシステムが適用される未来を想像しながら、利用者が最高の体験を得られるような企画・提案を行い、どんなアイデアも実現する技術力を持つ。そして、開発の進め方などでもリードできる。この部分で他社を凌駕し、**「色んな会社があるけどPADに依頼したい」** と言ってもらえる会社でありたいと考えています。

幸いなことに、弊社には多様な分野で培ってきた知見や技術力がありますので、この会社でなら出来ると信じて日々邁進中です！



# 新たな挑戦への扉

面接が終わり、手ごたえは感じていたものの、内心では不安と期待が入り混じっていました。本社から出て独りになった瞬間、「やれることはやった」と自分に言い聞かせました。そして、何か新しい挑戦が始まる予感が胸を高鳴らせました。

数日後、合格の連絡が来ました。その瞬間、喜びとともに、「これからが本当の挑戦だ」という気持ちが湧いてきました。PADでの新しい日々が、僕にとってどれほど意義深いものになるかを考えると、胸が高鳴りました。

この面接を通じて、僕はこの会社が提供する環境やプロジェクトが、自分の成長に最適であると確信しました。新しい仲間とともに、技術の最前線で挑戦し続ける日々が始まるのです。

次回は、「PADでの初仕事」についてお話しします。それでは、また！

<br>

※ PADに興味を持ってくださった方、どんな小さな疑問でも構いません。私たちのことをもっと知りたいと思ったら、ぜひWebサイトからお問い合わせください。あなたからの連絡を楽しみにしています！
[paiza]みんな大好きFizzBuzz

# ループ・分岐を1度に学ぶならコレ
とりあえず新しい言語を始める時にHelloWorldの次ぐらいにやるのがFizzBuzz。
コレでループとifの書き方を理解してってやるのが下手な教科書で研修やるより1番いい気がする。

https://paiza.jp/works/mondai/c_rank_skillcheck_sample/fizz-buzz

# 面倒くさいので画面パタメータをListでもらった後のFunctionだけ
ちなみに引数のListを作ってる箇所は[こっちの記事](https://qiita.com/AsilHatake/items/842548e48ae4a0eae119)に書いてあるYO!!

```javascript:fizzBuzz.js
// [問題文（原文）]
// 整数 N が入力として与えられます。
// 
// 1からNまでの整数を1から順に表示してください。
// 
// ただし、表示しようとしている数値が、
// 
// ・3の倍数かつ5の倍数のときには、"Fizz Buzz"
// ・3の倍数のときには、"Fizz"
// ・5の倍数のときには、"Buzz"
// 
// を数値の代わりに表示してください。
function fizzBuzz(lines) {
  // 入力は以下のフォーマットで与えられます。
  // 
  // N
  // 
  // N は1以上N以下の整数です。
  if (!Array.isArray(lines) || lines.length !== 1) {
    console.log("1行入れろや！");
    return;
  }
  const repCnt = Number(lines[0]);
  if (!Number.isInteger(repCnt) || repCnt < 0 || repCnt > 100) {
    console.log("1～100の整数入れろや！");
    return;
  }
  Array.from({ length: repCnt }, (v, k) => {
    let num = k + 1;
    console.log((num % 15 === 0) ? 'FizzBuzz' :
      (num % 3 === 0) ? 'Fizz' :
        (num % 5 === 0) ? 'Buzz' : num);
    return num;
  })
}

module.exports = {
  fizzBuzz
};
```

まぁFor文もif文も使ってなんかやらないけどな！
配列を作る流れの中で出力をするという力技。

もっと見やすく（ちゃんとした処理の流れ通りに）書くとかであれば、
Array.fromで数字だけの配列を作った後にForEachで出力って感じになるんだろうけど。

```javascript:Array.fromの所だけ直したやつ
  Array.from({ length: repCnt }, (v, k) => k + 1).forEach(num => console.log((num % 15 === 0) ? 'FizzBuzz' :
    (num % 3 === 0) ? 'Fizz' :
      (num % 5 === 0) ? 'Buzz' : num));
```

問題としては、0始まりとかにすれば0除算問題にも対応できただろうに、なんで1からとかいう甘っちょろい条件にしてくれたんだろう。。。
Mac & VSCode で Windowsで編集されたスクリプトを開くとき

# この記事の対象となる人
- WindowsとMacを行き来している。
- それぞれのOSで編集されたスクリプトを開く機会が多い。
- VSCodeを使っている。
- 今回はUnityのC#スクリプトでお話しています。

# VSCodeあるある
## Macの場合とくに
- Windowsをつかっている人からスクリプトをもらうと、文字化けでコメントが読めない。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191635/8840a327-7d72-da6b-2ec6-9073d7e0edb3.png)

## 文字コードをクリックする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191635/f7103b7d-ec01-be6b-0ba1-0581b6100b91.png)

## 一覧の文字コードからShiftJISをクリックする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191635/23e15879-edde-c889-9aa2-a459982cec87.png)

## 解決
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191635/4cbe3698-e2d1-37eb-544c-000b4dfb8231.png)
お名前.comDDNSクライアントをNode.jsで実装

# 一つ一つアカウント情報入れるのは、煩わしい。
お名前ドットコムには[公式のダイナミックDNSクライアント](https://help.onamae.com/answer/7920)があります。しかし、私はこのソフトウェアに不満があります。

- DDNS設定を一つ追加するたびにアカウント情報を個別に入力しなければならない
- タスクバーに表示されないので、見つからなくなる
- 閉じてもバックグラウンドに残り続け、開くたびに増える

1つ目が一番の不満要素ですが、とにかくアプリケーションとして使い勝手が悪い。
そこで、自作のサーバー上で動作するダイナミックDNSクライアントを作ってみました。

# 使い方

https://github.com/JUN-SUZU/onamae-ddns-client

GitHubからダウンロードします。(starつけてくれると嬉しいです。)
以下のファイルを作ります。
```config.json
{
    "userId": "お名前ドットコムのユーザーID",
    "password": "お名前ドットコムのパスワード"
}
```

`index.js`の`hostnames`に設定するDNSのホスト名を設定し、`domain`にドメイン名を設定します。

```index.js
const interval = 1800;
const userId = config.userId;
const password = config.password;
const hostnames = ['ホスト名', 'hogehoge'];
const domain = 'example.com';
```

必要に応じて色々とカスタマイズしてみてください。

# 参考
やってること自体はほとんど同じで、pythonをjavascriptに翻訳しただけですが

https://github.com/y-otn/onamae-ddns-client

https://qiita.com/ats124/items/59ec0f444d00bbcea27d
Visual Studio Code 覚えてほしいショートカット

# はじめに
こちらは初心者向けです。
一気に全部覚えようとするのではなく、３個ずつ意識していくことが覚えるコツです！

# 1. 覚えておきたいショートカット一覧
#### 必須（全員覚えるべき）
| 名称 | ショートカット | 説明 |
|:---|:---|:---|
| コメントの切り替え | ```Ctrl + /``` | コメントアウトの切り替えが可能 |
| デバッグの実行 | ```F5``` | プログラムの実行・デバッグ |
| ターミナルを表示（非表示） | ```Ctrl + @``` | ターミナルの表示・非表示を切り替えが可能 |
| 新しいターミナル | ```Ctrl + Shift + @```  | 新しいターミナルを開く |
| ドキュメントのフォーマット | ```Alt + Shift + F``` | コードのインデント（段落）をきれいに整えてくれます。<br>※　HTML/CSS 〇　Python ×（フォーマッタの追加が必要） |

#### 推奨（エンジニアになる人は覚えるべき）
| 名称 | ショートカット | 説明 |
|:---|:---|:---|
| すべてのコマンドの表示 | ```Ctrl + Shift + P``` | VSCodeで使えるコマンドを表示して実行可能 |
| シンボルの名前変更 | ```F2``` | 変数名や関数名を一括で編集可能 |
| 一括編集 | ```Ctrl + F2``` | 選択中の要素を一括で編集可能 |
| 行を下（上）へコピー | ```Alt + Shift + ↓(↑)``` | カーソル行を下にコピー |
| 行を下（上）へ移動 | ```Alt + ↓(↑)``` | カーソル行を下に移動 |
| 編集箇所を戻る（進む） | ```Alt + ←(→)``` | 編集していた箇所を戻る（進む） |

#### +α（覚えておくと便利かも）
| 名称 | ショートカット | 説明 |
|:---|:---|:---|
| ショートカット一覧 | ```Ctrl + K``` → ```Ctrl + S``` | 登録されているショートカットの一覧を開く |

#### ※　もっと知りたい・覚えたい人はこちら（[Windows](https://qiita.com/TakahiRoyte/items/cdab6fca64da386a690b)/[Mac](https://qiita.com/naru0504/items/99495c4482cd158ddca8)）がオススメ！

## 2. 覚えておきたいショートカットの使い方
### (追記予定)

# 【参考】
- [【Windows版】VS Code キーボードショートカット一覧 （オススメ付き）](https://qiita.com/TakahiRoyte/items/cdab6fca64da386a690b)
- [【Mac版】 VisualStudioCode キーボードショートカット](https://qiita.com/naru0504/items/99495c4482cd158ddca8)
- [新人エンジニアが最初に覚えたいVisual Studio Codeのショートカットキーベスト10（Python編）](https://saycon.co.jp/archives/neta/%E6%96%B0%E4%BA%BA%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E3%81%8C%E6%9C%80%E5%88%9D%E3%81%AB%E8%A6%9A%E3%81%88%E3%81%9F%E3%81%84visualstudidocode%E3%81%AE%E3%82%B7%E3%83%A7%E3%83%BC%E3%83%88)
marpでスライドの草稿を時短で作る

## はじめに
こちらのポストで、スライドを時短で作る方法を展開されていたのでそれを試してみました。

https://x.com/SuguruKun_ai/status/1817101888892088784?t=OuWof4gWayBzox9uE8L5Qw&s=19

## 使ってみた
準備は元ポストのツリー
https://x.com/SuguruKun_ai/status/1817105258080010356?t=inYB87uHzKczNldo7dnovA&s=19
https://x.com/SuguruKun_ai/status/1817105261330583652?t=ZkDHNTIjZSgO1NTIiBXVtQ&s=19
https://x.com/SuguruKun_ai/status/1817105264249561282?t=nnNboKqadbIofZlJYZ0RUQ&s=19
を見てもらうとして、さっそく使ってみます。

まず、箇条書きの文章を用意します。
今回は[chatGPTで事業計画を時短で考える](https://qiita.com/azida8aka/items/a34f5c361116fd95ed19)のときのプロンプトを使って箇条書きのビジネスモデルキャンバスを用意しました。
![スクリーンショット 2024-08-02 175834.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3680875/c00da93e-8710-509e-f443-a5f9a250df49.png)

次に、その内容をmarpでスライド作成してくださいと頼みます。
![スクリーンショット 2024-08-02 175929.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3680875/90baa237-ecb2-93ea-c274-dc3e45ff9542.png)

最後に、それをコピーしてvscodeに張り付けて完成しました。
![スクリーンショット 2024-08-02 180449.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3680875/3dfb5810-c276-b8d9-e172-d66ab7033224.png)

あとは、矢印のところからExportすればpdfにできます。
![スクリーンショット (127).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3680875/ca7c5c53-40fd-5a88-e44b-584b6af4d548.png)
![スクリーンショット 2024-08-02 180740.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3680875/7233efa8-a2c2-601e-8c7f-6d820323530c.png)

感動の速さでした。今までパワポでポチポチやってた時間を圧倒的に短縮できます。

内容は自分で考える必要がありますが、今回のポイントは
「箇条書きの状態にさえすれば、すぐスライドに変換できる」
ということです。よって、メモでもwordでもpdfでも、一旦箇条書きに変換さえしてしまえば、そのままスライドに起こせることを知りました。

## 画像を追加する
ただ、今のままではさすがに人前に出すには少し気が引けるスライドなので、画像を足すのを試してみます。

今回はpdfから箇条書きの文章を用意しました。有名な論文「Attention is all you need」のpdfの要約です。
![スクリーンショット 2024-08-02 181404.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3680875/f31fa6c6-bdf0-becf-4b65-a9988ae15463.png)

そしてmarp指示を出すときに、画像を追加することと右半分にレイアウトさせることを命令します。
![スクリーンショット 2024-08-02 181447.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3680875/29202e35-db48-486e-227c-d275fce6b780.png)

それでできたのがこちらです。
![スクリーンショット 2024-08-02 181903.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3680875/b20d76c3-509a-6f39-a0ef-1011c45bb987.png)

ちょっと文章のレイアウトがまずいことになってます。少し調べたところ、現状の「bg right」を「bg right:25%」にしたら良い感じになりました。
![スクリーンショット 2024-08-02 182147.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3680875/dcca6dc5-388b-9827-10d6-4409ab682970.png)
![スクリーンショット 2024-08-02 182921.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3680875/654c7d1b-5450-889a-d390-a106ebc066b1.png)


これなら人前に出しても問題なさそうですね。画像は内容と全く関係ないですが、雰囲気は出ています。

## 所感
とても便利に感じました。よっぽど重要な発表の場でない限り、今度から全部これで作ればいいなと思うぐらいコスパが良いです。
とはいえ、関係ある画像にしたり、レイアウトを変えたり、Canvaまたはパワポに移すなどの改良の余地があり、そこはまだ試せてない状態です。試した人がいたら教えてもらえると助かります。

「箇条書きの状態にさえすれば、すぐスライドに変換できる」というのも強みに感じました。今の時代、箇条書きのテキストにできない媒体なんてほぼないですし、pdfも画像もYoutube動画でさえも要約文を出力でき、その場でchatGPTで足りない内容を生成・編集できるので、拡張性もありつつ時短できて便利でした。草稿を素早く作るという使い方でも良さそうです。