OmniAICreator/Qiita-1.07M huggingface dataset:
Java 24 について調べてみた

**Java24**が2025年3月18日に正式リリースされました！
開発者の生産性向上やパフォーマンスの改善を目的とした新機能や強化が施されたとのことなので、調べた内容についてまとめていきます。

## 主な新機能
#### 1. パターンマッチングの強化
instanceofやswitch文でプリミティブ型を使用できるようになり、コードの簡潔さと可読性が向上しました。
```Java:Sample.java
switch (obj) {
    case Integer i -> System.out.println("整数: " + i);
    case String s -> System.out.println("文字列: " + s);
    default -> System.out.println("その他の型");
}
```
#### 2. モジュールインポート宣言
複数のimport文をまとめる新しい構文が追加され、コードの整理が容易になりました。
```Java:Sample.java
import java.util.*;
import static java.lang.Math.*;
```

#### 3. 構造化並行性
複数のタスクを効率的に管理し、並行プログラミングの安全性とデバッグの容易さを向上させる機能が追加されました。
```Java:Sample.java
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
    Future<String> result = executor.submit(() -> "Hello, World!");
    System.out.println(result.get());
}
```

#### 4. スコープ付き値
スレッド間での安全なデータ共有を可能にし、特定のスコープ内でのみ有効な値を定義できるようになりました。
```Java:Sample.java
ScopedValue<String> scopedValue = ScopedValue.newInstance();
ScopedValue.where(scopedValue, "ScopedData").run(() -> {
    System.out.println(scopedValue.get());
});
```

#### 5. 柔軟なコンストラクタボディ
コンストラクタ内での初期化処理が柔軟になり、コードのメンテナンス性が向上しました。

## Java23との違い
| 機能 | Java23 | Java24 |
|:-:|:-:|:-:|
| パターンマッチング | switchでの利用が限定的 | プリミティブ型対応 |
| 並行性 | スレッドプール中心 | 構造化並行性の導入 |
| インポート | 従来のimport文 | モジュールインポート宣言 |
| スコープ値 | なし | スコープ付き値が利用可能 |


## メリット
・コードの簡潔化：パターンマッチングの強化により、冗長なコードが減少する。
・並行プログラムの最適化：構造化並行性により、安全かつ効率的なスレッド管理ができる。
・新しい構文の追加：スコープ付き値の導入により、スレッド間のデータ管理が改善できる。

※一方で、「移行コスト」「学習コスト」「レガシーシステムとの互換性」などのデメリットにより、一部の企業システムでは新しい機能をすぐに導入することは難しいでしょう。

## まとめ
Java24はパターンマッチングの強化や構造化並行性が導入されているため、モダンな開発環境に適した機能が充実しています。参考にした内容をまとめておきますので、ご参考になれば幸いです。

## 参考
https://inside.java/2025/03/13/newscast-87/

https://jdk.java.net/24/release-notes

https://note.com/wa_k77/n/n5f753791d680

https://www.site24x7.jp/whats-new-in-site24x7.html
【学習】DBのテーブル構造をPerlのオブジェクトとして扱うために


## はじめに
前回はMysqlのDBのテーブル構造を修正しました。ですが`sql`ファイルの修正だけではサーバー側？に反映されないようです。なので反映させる為にどうすればいいのか、まとめていきたいと思います。

👇前回までの内容については下記記事をご覧ください

https://qiita.com/wa-chan222/items/5794b40c458e9d943f3c


## `DB\Schema.pm`ファイルを編集
このファイルは**DBの テーブル構造（ここでは member テーブル）を Perlのオブジェクト として扱うために、どのテーブルにアクセスするのか、どのカラムが存在するのかを指定するため**にあります。
もっと短く言うと**データベースのテーブルとコードを結びつけるための設定を行うファイル**です。

（ORM（Object-Relational Mapping）を使ってデータベースのテーブル構造を定義するファイル。とも言えます。難しい😥）

（SQLファイルはDBのテーブル定義や初期データを作成するためのものであり、ウェブアプリとDBをつなぐ仕組み（ORMやDBアクセス処理）が別途必要。で、`DB\Schema.pm`が、「つなぐ仕組み」）

- `age`を誕生日（birthdate）から計算するので、`age`カラムは不要
- その代わりに、`birthdate`を保存するカラムを保持
- `occupation`と`drink`のIDも外部キーとして保持

```.変更前（一部割愛）
table {
    name 'member';
    pk 'id';
    columns qw(id name age occupation drink remarks);
};

1;
```

```.変更後
table {
    name 'member';
    pk 'id';
    columns qw(id name birthdate occupation_id drink_id remarks created_at updated_at);
    
    # 外部キー制約を設定
    belongs_to 'occupation' => 'questionary1::DB::Occupation', 'occupation_id';
    belongs_to 'drink' => 'questionary1::DB::Drink', 'drink_id';
};
```

## 試しにデータを挿入してみる
※`username`や`databasename`はご自身が設定したものがはいります。
```
$ mysql -u <username> -p
mysql> USE <databasename>;
mysql> INSERT INTO member (name, birthdate, occupation_id, drink_id, remarks) VALUES ('山田太郎', '1990-05-15', 1, 1, '特になし');

mysql> SELECT * FROM member;
+----+--------------+------------+---------------+----------+--------------+---------------------+---------------------+
| id | name         | birthdate  | occupation_id | drink_id | remarks      | created_at          | updated_at          |
+----+--------------+------------+---------------+----------+--------------+---------------------+---------------------+
|  1 | 山田太郎     | 1990-05-15 |             1 |        1 | 特になし     | 2025-03-06 17:48:53 | 2025-03-06 17:48:53 |
+----+--------------+------------+---------------+----------+--------------+---------------------+---------------------+
1 row in set (0.00 sec)
```

## ここで改めてウェブフォーム、DB、PerlのSchema.pmとの関係について
こういう事なのかな・・・。
1. **ユーザーがフォームにデータを入力し、送信する**
ユーザーが年齢や名前を入力し、「送信」ボタンを押す。

2. **ウェブサーバーがリクエストを受け取る**
ウェブサーバー（Perlのアプリケーション）は、ユーザーが送信したデータを受け取る

3. **Perlコードがデータを処理し、データベースに保存**
ここで、`Schema.pm`が関与？フォームから受け取ったデータを`Schema.pm`の定義に従ってデータベースに挿入し、`Schema.pm`により、`member`テーブルのカラムが定義され、どのカラムにデータを保存するか、どのような操作をするかを簡単に扱えるようにしている。

4. **データベースに保存されたデータ**
保存されたデータは、後で再利用したり、ユーザーに表示することが可能。


## さいごに
Ruby on Railsを学んできていたので、言い換えると下記のような感じなのかな・・・と思いました。今回の内容が何か参考になれば幸いです

👇**Ruby on Rails での対応関係**
| Perl  | Ruby on Rails |
| --- | --- |
| `Schema.pm` | `schema.rb` (マイグレーションの結果) |
| SQLの `CREATE TABLE` | `db/migrate/xxxx_create_users.rb` (マイグレーションファイル) |
CLI、はじめてみました (Part2)

## 本記事の目的
Command-line interface (CLI)で使えるTipsを備忘録としてまとめていきます！

## No.0005
ssh接続してCLI使う時にバックグラウンド処理の継続できないかなぁ。
tmuxを使う！
・ctrl + B --> Dでdetach（バックグラウンド処理は継続）
・継続中のセッションに再接続
```tmux:tmux
tmux attach -t <session名>
```
番号指定して以前のコードを実行可能！

# 最後に
これからも便利なTipsを備忘録として書き留めていきたいです。

:::note info
**皆さんの経験談やTipsもぜひコメントください！**
:::
LaTeXの目次にて見出しとページ番号を点線で結ぶ

# Purpose
jsarticleで見出しを
~~~latex
\part*{第1章 hogehoge}
\section*{1.1 hogehoge}
\addcontentsline{toc}{section}{1.1 hogehoge}
~~~
などのように自動でナンバリングされないようにしていると、目次にて見出しとページ番号の間が空白になってしまう。これを修正し見出しとページ番号の間が点線で結ばれるようにする。

# How to
~~~latex:main.tex
\documentclass{jsarticle}
\usepackage{tocloft}

%==============================
\renewcommand\cftdotsep{0} %数値は点と点の間隔
\renewcommand\cftsecleader{\cftdotfill{\cftsecdotsep}}
\renewcommand\cftsecdotsep{\cftdotsep}
%==============================

\begin{document}
\listofcontents

\part*{第1章 hogehoge}
\section*{1.1 hogehoge}
\addcontentsline{toc}{section}{1.1 hogehoge}

\end{document}
~~~
今回はsectionに対して適用したが、例えばこれをsubsectionに適用するには、\cftsecleader と \cftsecdotsep の "sec" の部分を "subsec" に変更する。

# Reference
https://tex.stackexchange.com/questions/240633/how-to-format-the-leading-dots-of-section-page-number-and-subsection-page-number
LaTeXにて目次を任意の見出しで表示させる

# Premise
LaTeXを用いて文献を執筆する際、オートマティックにナンバリングされるのを防ぎ、任意の見出しで表現するには
~~~latex
\section*{第一章 序章}
~~~
などのようにアスタリスクを用いて記述する。そして、目次を入れたい時は本文に
~~~latex
\tableofcontents
~~~
と記述するが、このままだと表示されない。
目次に表示されるようにするための対処法を記す。

# How to
至ってシンプルで、見出しの後に次のコマンド
~~~latex
\addcontentsline{toc}{見出しのコマンド}{見出し名}
~~~
を記述する。
例えば上の例で示すと、
~~~latex
\section*{第一章 序章}
\addcontentsline{toc}{section}{第一章 序章}
~~~
と記述する。
これでコンパイルすると、目次に表示\addcontentsコマンドで指定した見出しの深さ、見出し名で表示される。
BibTeXの調べ方

# Purpose
Latexで文中に参考文献を挿入する際にはBibTeXによって管理すると便利である。
BibTeXを入手する方法をメモする。

# How to Part1 (論文,アブスト)
方法には大きく分けて二種類存在する。
まず一つ目は[Google Scholar](https://scholar.google.co.jp)を用いる方法。

1. [Google Scholar](https://scholar.google.co.jp)を開き、引用する論文を検索する
（今回は[Machine learning: Trends, perspectives, and prospects](https://www.science.org/doi/abs/10.1126/science.aaa8415)という論文にした）。
1. 該当の論文のリンクの下に画像のような「☆保存...」が表示されるので、左から二番目の「引用」をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3073999/ff135355-ad94-2cb2-0daa-d69690b24172.png)
1. 引用のポップアップが表示されるので、BibTexをクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3073999/dcce37ae-5fc7-e52d-af5d-7bf48784b4fe.png)
1. 画像のようなBibTexが表示される。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3073999/7a8c9a60-0814-a5ba-0a92-7ac8cbe61a67.png)


二つ目はDOIコードから調べる方法。
1. 引用した論文のDOIコードを取得する。（今回であれば DOI: 10.1126/science.aaa8415）
1. [doi2bib](https://www.doi2bib.org/)を開き、"Ente a doi, PMCID, or arXiv ID"にDOIコードを入力して"get BibTex"をクリック
1. 画像のようにBibTexが表示される。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3073999/3eb953ee-3bac-5e74-47b2-8f4b78d420b7.png)

# How to Part2 (書籍)
書籍の場合、上述した方法ではなくCiNiiで取得することができる。
1. [CiNii](https://cir.nii.ac.jp/)にアクセス
1. 取得したい書籍の情報で検索する（ここでは広辞苑 第七版とした）![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3073999/e2aff8e8-909b-56a5-d8d7-fadd6f975b3a.png)

1. 書籍の場合、下のように表示されるため、このページを開く。![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3073999/98303f07-5ee9-828f-5b9e-35401eba5998.png)

1. 少し下にスクロールすると「書き出し」とあるので、その中から「BibTeXで表示」を選択。![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3073999/0862ef1c-54a9-4642-9c9d-4edcfb4ba64c.png)
1. 画像のようにBibTeXが表示される。![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3073999/ee211ad5-2976-772f-082d-c367243a225a.png)



# Reference
- [bibファイルを使って参考文献を掲載する](https://qiita.com/MizutoKadowaki0312/items/e96bbcc6f6a3fd8c6b92)
- [doi2bib.org](https://www.doi2bib.org/)
- https://niszet.hatenablog.com/entry/2022/10/18/233429
LaTeXでReferenceを物理っぽくPRL(Physical Review Letter)式にする

# Purpose
参考文献の一覧はコマンドを用いれば自動で作成してくれる。その表記方法を物理の論文ぽくする。

# How to
まずは参考文献を格納するbibファイルを作成する。
1. 新規ファイル（メニュー下、左端）> Add FileのFile Nameに「（任意のファイル名）.bib」を入力 > 作成を押下 
1. 作成したbibファイルに参考文献のbibTexを入力。（bibTexの調べ方はここ）

次にmain.txtを編集する。
1. プリアンサンブル（\documentclass{}から\begin{document}の間）に下のコードを入力する。
    ~~~latex:main.tex
    \usepackage[
    style=phys,
    articletitle=false,biblabel=brackets,
    chaptertitle=false,pageranges=false
    ]{biblatex}
    \addbibresource{（設定したファイル名）.bib}
    ~~~
1. 本文（\begin{document}から\end{document}の間）の参考文献を埋め込みたい箇所に下のコードを記入する。
    ~~~latex:main.tex
    \printbibliography[title=参考文献]
    ~~~
\
これで参考文献が物理の論文と同じような記法になる。
著者名をet al.にしたいときや雑誌名をPhys. Rev. Lett.のように略称にしたい場合は、bibTexを編集した。（面倒ではある、、、）
LaTeXで日本語の表示を有効にする

# Purpose
修論やその発表の要旨を作成する際に、Overleafを用いた。Overleaf（というかLatex？）はデフォルトでは日本語に対応していないため、仮に日本語を入力しても反映されない。そのため、日本語を有効にする必要があり、その手段を示す。

# How to
1. [Overleaf](https://ja.overleaf.com/login)にログインし、「新規プロジェクト」から新規のプロジェクトを作成。
1. main.txtの「\documentclass{article}」を「\documentclass{jsarticle}」に変更。
1. メニュー（画面左上）> コンパイラ　でコンパイラを「LaTex」に変更。
1. 新規ファイルを作成する。新規ファイル（メニューの下、左端のアイコン）を選択 > Add FilesのFile Nameに「latexmkrc」を入力 > 作成を押下
1. 3.で作成したlatexmkrcに下のコードを入力。
~~~txt:latexmkrc
$latex = 'platex';
$bibtex = 'pbibtex';
$dvipdf = 'dvipdfmx %O -o %D %S';
$makeindex = 'mendex -U %O -o %D %S';
$pdf_mode = 3; 
~~~

Unicodeを用いる場合は下のコードを入力する。
~~~txt:latexmkrc
$latex = 'uplatex';
$bibtex = 'upbibtex';
$dvipdf = 'dvipdfmx %O -o %D %S';
$makeindex = 'mendex -U %O -o %D %S';
$pdf_mode = 3; 
~~~

これでコンパイルすると、日本語が有効になる。
LaTeXの目次で章と見出しの文字列が重なるときの対処法

## Premise
LateXにて目次を追加する際は一般的に
~~~latex
\begin{document}
    \tableofcontents
\end{document}
~~~
と本文に記述する。このとき、目次の章番号と見出しの文字列が一部重なって表示されてしまう場合がある（原因は筆者は分かりません）。このときの対処法を示す。


## How to
プリアンブルに以下のコードを記入する
~~~latex
\documentclass[11pt,a4j,dvipdfmx]{jreport}
\usepackage{tocloft}
\renewcommand\cftchapnumwidth{8ex}
~~~
こうすることで見出しの文字列を移動させることができる。
上記の3行目の{}内の数値を変更すれば、見出しの文字列を任意の位置に表示することができる。

## Reference
https://teratail.com/questions/seras89psqh5nv
LaTeXにて章, 節ごとファイルを作成し編集しやすくする

# Purpose
論文や本などの長文の文献をLaTexの一つの.texファイル内だけで執筆していると、修正や添削に苦労を要する。これを解決するため、章や節ごとに.texファイルを作成しｔ編集する。

# How to 1
まず、ディレクトリ構造を決める。今回は簡易のため次のような構造とする。
~~~
|-main.tex
|-Chapter1.tex
|-Chapter2
    |-Introduction.tex
    |-2.1 hogehoge.tex
    |-2.2 hogehoge2.tex
~~~

まず、「main」,「Chapter1」,「Introduction」,「2.1 hogehoge」,「2.2 hogehoge2」の.texファイルと「Chapter2」フォルダを作成し、上のようなディレクトリ構造になるようにファイルを移動させる。

次に、main.texの本文のところに
~~~latex:main.tex
\begin{document}

\input{Chapter1}
\input{Chapter2/Introduction}
\input{Chapter2/2.2 hogehoge}
\input{Chapter2/2.2 hogehoge2}

\end{document}
~~~
と記述する。すると、上から順番に表示される。これにより章、節ごとに編集しやすくなる。

今回は\input{}で行ったが、この場合は改ページされず連続的に表示される。
コマンドの前後で改ページしたい場合は、
~~~latex
\include{}
~~~
を用いる。

# How to 2(subfiles)
inputとincludeのデメリットとして、コンパイルする際に全てのファイルがコンパイルされてしまうという点がある。数ページのものなら問題ないが、論文や本などのようにページ数の多い文献を執筆する際に毎回全てのファイルをコンパイルするのは時間がかかるため、効率的ではない。
そこで、subfilesを用いたコンパイルを紹介する。
上と同様に、次のようなディレクトリ構造を想定する。
~~~
|-main.tex
|-Chapter1.tex
|-Chapter2
    |-Introduction.tex
    |-2.1 hogehoge.tex
    |-2.2 hogehoge2.tex
~~~

main.texは次のように記述する。

~~~latex:main.tex
\documentclass{jsarticle}

\usepackage{subfiles} %←必須

\begin{document}

\subfile{Chapter1}
\subfile{Chapter2/Introduction}
\subfile{Chapter2/2.1 hogehoge}
\subfile{Chapter2/2.2 hogehoge}

\end{document}
~~~
そして、texファイルでは次のように記述する。

~~~latex:Chapter1.tex
\documentclass[main]{subfiles}

\begin{document}
ここに本文を記述
\end{document}
~~~

このように記述し.texファイルをコンパイルすると、コンパイルした.texファイルのみがコンパイルされる。もちろん、最後にマージする際はmain.texをコンパイルする必要がある。

# Reference
https://qiita.com/sankichi92/items/1e113fcf6cc045eb64f7
https://qiita.com/kemukowa/items/8621a19a9fa0664e4400
自分メモ　例外処理

認証エラーとデータベースダウンの例外処理を分けたい場合、`PersistenceException` にラップされる `SQLException` のエラーメッセージやエラーコードを解析して適切に分類する方法があります。  

### **1. `PersistenceException` にラップされた `SQLException` を取得**
まず、`PersistenceException` の `getCause()` を使用して `SQLException` を取得し、`getSQLState()` や `getErrorCode()` を利用してエラーを分類できます。  

---

### **2. 具体的な処理**
```java
try {
    SqlSession session = sqlSessionFactory.openSession();
} catch (PersistenceException e) {
    Throwable cause = e.getCause();
    
    if (cause instanceof SQLException) {
        SQLException sqlEx = (SQLException) cause;
        String sqlState = sqlEx.getSQLState();
        int errorCode = sqlEx.getErrorCode();
        
        if (isAuthenticationError(sqlState, errorCode)) {
            log.error("認証エラー: {}", sqlEx.getMessage(), sqlEx);
            throw new AuthenticationException("認証エラーが発生しました", sqlEx);
        } else if (isDatabaseDownError(sqlState, errorCode)) {
            log.error("データベースダウン: {}", sqlEx.getMessage(), sqlEx);
            throw new DatabaseDownException("データベースが利用できません", sqlEx);
        } else {
            log.error("データベース接続エラー: {}", sqlEx.getMessage(), sqlEx);
            throw e; // その他のエラーは再スロー
        }
    } else {
        log.error("PersistenceException: {}", e.getMessage(), e);
        throw e; // 予期しないエラーはそのまま再スロー
    }
}
```

---

### **3. エラー分類の関数**
#### **(1) 認証エラーの判定**
```java
private boolean isAuthenticationError(String sqlState, int errorCode) {
    return "28000".equals(sqlState) // SQLSTATE 28000 は一般的な認証エラー
        || errorCode == 1045 // MySQL: Access denied for user
        || errorCode == 18456; // SQL Server: Login failed
}
```
---
#### **(2) データベースダウンエラーの判定**
```java
private boolean isDatabaseDownError(String sqlState, int errorCode) {
    return "08S01".equals(sqlState) // SQLSTATE 08S01: 通信障害
        || errorCode == 2003 // MySQL: Can't connect to MySQL server
        || errorCode == 0 // 一般的な接続不可 (JDBCドライバによる)
        || errorCode == 57P01; // PostgreSQL: database shutdown
}
```

---

### **4. カスタム例外クラス（任意）**
もしエラーを明確に区別してスローしたい場合、独自の例外クラスを作成するのも良い方法です。

#### **(1) 認証エラー用の例外**
```java
public class AuthenticationException extends RuntimeException {
    public AuthenticationException(String message, Throwable cause) {
        super(message, cause);
    }
}
```
---
#### **(2) データベースダウンエラー用の例外**
```java
public class DatabaseDownException extends RuntimeException {
    public DatabaseDownException(String message, Throwable cause) {
        super(message, cause);
    }
}
```

---

### **5. まとめ**
✅ **PersistenceException にラップされた SQLException を解析することで、エラーを分類できる。**  
✅ **SQLState とエラーコードを使って「認証エラー」「データベースダウンエラー」を判定する。**  
✅ **必要なら `AuthenticationException` や `DatabaseDownException` を定義してスローする。**  

この方法で、認証エラーとデータベースダウンエラーを適切に分けた例外処理ができます！
条件付き独立性を完全に理解した

# 条件付き独立性とは？

条件付き独立性（Conditional Independence）は、確率論や統計学において、2つの確率変数が与えられた条件下で独立であることを指します。具体的には、3つの確率変数 X, Y, Z について、Z が与えられたとき、X と Y が独立である場合、X と Y は Z に関して条件付き独立であると言います。

## 数学的定義

条件付き独立性は以下のように定義されます：

P(X, Y | Z) = P(X | Z) ・ P(Y | Z)


これは、Z が与えられたとき、X と Y の同時確率が、それぞれの周辺確率の積に等しいことを意味します。言い換えれば、Z が既知である場合、X と Y は互いに影響を与えないということです。

## 具体例

例えば、以下のような疑似相関の状況を考えます：

- X: 身長
- Y: 学力
- Z: 年齢

ここで、Z（年齢）が与えられたとき、X（身長）と Y（学力）は条件付き独立であるとします。つまり、Z(年齢)を指定している場合、X(身長)とY(学力)は互いに影響を与えないということです。
一方で年齢を指定しない場合、は身長と学力に相関がある（身長が高いほど高学年になるので、学力は高くなる）ので、独立ではありません。

*deepseek先生に教えてもらいました。
【Laravel】AuthServiceProviderでDBを扱う際の注意点

# はじめに

`AuthServiceProvider`内でテーブルのデータを扱う処理を書いていました。
それが原因でちょっとしたエラーに遭遇したので、残しておこうと思います。

# エラーの発生状況

以下のように、`AuthServiceProvider`内で`Shop::all()`を使って動的にGateを定義していました。

```php:AuthServiceProvider.php
use App\Models\Shop;
use Illuminate\Support\Facades\Gate;
use App\Models\Admin;

public function boot()
{
    foreach (Shop::all() as $shop) {
        // 「shop-[店舗ID]」で店舗権限を実装
        Gate::define('shop-' . $shop->id, function (Admin $admin) use ($shop) {
            return $admin->hasShopAuth($shop->id);
        });
    }
}
```

検証環境にソースをデプロイし、`php artisan migrate`を実行。
すると以下のエラーが発生。

```terminal
Illuminate\Database\QueryException

SQLSTATE[42S02]: Base table or view not found: 1146 Table 'bside_database.shops' doesn't exist (Connection: mysql, SQL: select * from `shops`)
```

# 原因
問題なのは`Shop::all()`でした。
**artisanコマンドの実行時には、AuthServiceProvider::boot()が呼ばれます。**
`php artisan migrate`の実行時に`AuthServiceProvider::boot()`が呼ばれて、まだ`shops`テーブルが存在しない状態で`Shop::all()`を実行してしまうことが原因でした。

:::note info
自分の環境では既に`shops`テーブルが存在したので事象は起きなかったのですが、検証環境で`php artisan migrate`の実行時に発覚しました。
:::

# 解決策

テーブルが存在する場合のみ`Shop::all()`を実行するように、`Schema::hasTable()`で判定を追加しました。

```php:AuthServiceProvider.php
use Illuminate\Support\Facades\Schema;

public function boot()
{
    if (Schema::hasTable('shops')) {
        foreach (Shop::all() as $shop) {
            // 「shop-[店舗ID]」で店舗権限を実装
            Gate::define('shop-' . $shop->id, function (Admin $admin) use ($shop) {
                return $admin->hasShopAuth($shop->id);
            });
        }
    }
}
```

# まとめ

Laravelの`AuthServiceProvider`内でテーブルのデータを使う場合は、`Schema::hasTable()`でテーブルの存在確認を行う。

# 告知
最後にお知らせとなりますが、イーディーエーでは一緒に働くエンジニアを
募集しております。詳しくは採用情報ページをご確認ください。

https://eda-inc.jp/recruit/

みなさまからのご応募をお待ちしております。
Docker入門：Docker Hubにログインできないときに試すべき5つの対処法をまとめてみた

## はじめに

Docker Hubにログインできず、イメージのpullも失敗するトラブルに遭遇し、解決策を探すのに苦労した経験があります。具体的には、`docker login` コマンドを実行しても認証に失敗し、Docker HubのWebサイトでは正常にログインできるのにCLIからはうまくいかない状況でした。

:::note info
**また、イメージのpull時にも `unauthorized: authentication required` というエラーが発生し、ネットワークの問題なのか、認証情報の問題なのかを特定するのに時間がかかりました。**
:::

本記事では、同じ問題に悩んでいる方がスムーズに原因を特定し、解決できるように手順を整理しました。

## Docker Hubにログインできないときの対処法

Docker Hubへのログインやイメージのpullができない場合、以下の手順で問題を特定し、解決してみてください。

### 1. Docker HubにCLIからログインできるか確認

まず、ターミナルやPowerShellで以下のコマンドを実行し、ログインできるか確認します。

```sh
docker login
```

Docker Hubのユーザー名とパスワードを入力してください。

- **成功した場合** → Docker Desktopの認証情報が問題の可能性があります。一度Docker Desktopでログアウトし、再ログインしてみてください。
- **失敗した場合** → ネットワークやアカウント情報の問題の可能性があります。

### 2. Docker Hubの認証トークンのリセット

Docker Hubのウェブサイトにログインし、[Security](https://hub.docker.com/settings/security) で古いトークンを削除し、新しいトークンを作成してみてください。

作成したトークンを使って、以下のようにログインできます。

```sh
docker login -u <ユーザー名> --password-stdin < xxx_token.txt
```

### 3. インターネット接続の確認

Docker Hubのサーバーにアクセスできているか確認するために、以下のコマンドを実行してください。

```sh
ping hub.docker.com
nslookup hub.docker.com
```

- **エラーが出る場合** → ネットワークの問題（ファイアウォール、VPN、プロキシ設定）を確認してください。
- また、Dockerのプロキシ設定を変更したり、`--dns` オプションを設定することで解決する場合があります。

### 4. Docker Desktopのログを確認

Docker Desktopのログにエラーが出ていないか確認します。

- **Windowsの場合:**  
  `C:\Users\あなたのユーザー名\AppData\Local\Docker\log.txt`
- **WSL2の場合:**  
  `~/.docker/logs/`

エラーメッセージがあれば、それをチェックしてください。

### 5. 試しに別のDockerイメージをpullしてみる

以下のような公式イメージが取得できるか試してください。

```sh
docker pull hello-world
```

これも失敗する場合、ネットワークやDockerの設定に問題がある可能性が高いです。

## まとめ

上記の手順を試しても問題が解決しない場合は、エラーメッセージを確認し、さらに詳細なデバッグを行ってください。

:::note warn
***特に、認証情報の問題なのか、ネットワークの問題なのかを切り分けることで、効率よく解決策を見つけることができます。***
:::

今回の経験を踏まえ、同じ問題に直面した方の助けになれば幸いです。
Zabbix 6.2 以降の API トークン (API token) の使い方

## 1. 日本語情報はユーザーパスワード認証が主流  
Zabbix 6.2 から導入された APIトークン (API token) 。Zabbix の Web ページのメニューにもありますよね。  

しかし、日本語で Zabbix の API について検索すると、歴史的なものもあってユーザーパスワード認証の方法が多くヒットします。

参考: [Zabbix API の認証方法 (Qiita)](https://qiita.com/Trickey/items/d51d93d525443baa496f)

## 2. ユーザーパスワード認証のリクエスト例  
Zabbix API での認証リクエストは次のようになります。（[公式ドキュメント](https://www.zabbix.com/documentation/2.2/manual/api) より）  

### **リクエスト例**  
```json
{
    "jsonrpc": "2.0",
    "method": "user.login",
    "params": {
        "user": "Admin",
        "password": "zabbix"
    },
    "id": 1,
    "auth": null
}
```

### **レスポンス例**
```json
{
    "jsonrpc": "2.0",
    "result": "0424bd59b807674191e7d77572075f33",
    "id": 1
}
```

ユーザーパスワード認証の場合、`"method": "user.login"` でユーザー名とパスワードを送信し、返ってきたトークンを以降のリクエストで `"auth"` フィールドに埋め込みます。

## 3. API トークンは `"auth"` に埋め込むのか？

では、6.2 以降で使える API トークンも同じように `"auth"` に埋め込めばいいのかと思ったのですが、そうではありませんでした。

私の聞き方が悪かったのか、ChatGPT などの生成 AI に尋ねても、同じような説明が返ってきて、しばらくハマりました。

## 4. 正解は「ヘッダーに埋め込む」
[Zabbix 7.2 の公式ドキュメント](https://www.zabbix.com/documentation/7.2/en/manual/api) によると、API トークンはヘッダーで指定します。

正しい API リクエストの例
```sh
curl --request POST \
     --url 'https://example.com/zabbix/api_jsonrpc.php' \
     --header 'Content-Type: application/json-rpc' \
     --header 'Authorization: Bearer YOUR_API_TOKEN' \
     --data '{"jsonrpc":"2.0","method":"apiinfo.version","params":{},"id":1}'
```
## 5. 英語のマニュアルもちゃんと読みましょう
Zabbix の API を正しく使うには、英語の公式ドキュメントを確認するのが一番確実です。機械翻訳も活用して、最新バージョンのマニュアルを読みましょう。
SAP_開発～テストまでのフロー

### 開発
・自社の開発標準に基づいて開発するため割愛
（コーディングのチェックはSAPのSCIIで機械的にチェック）

### 単体テスト
・単体テスト仕様書＆単体テスト結果報告書
・SAPのSCIIレポート結果（事前にバリアントを定義してチェック項目は標準化する）

### 内部結合テスト
・内部結合テスト仕様書＆内部結合テスト結果報告書

### 外部結合テスト
・外部結合テスト仕様書＆外部結合テスト結果報告書
【Docker】Dockerfile 内でスクリプトを作成・定義する【entrypoint.sh など】

Docker イメージのビルド時にスクリプト・ファイルを必要とする場合、通常はローカルにあるファイルを `COPY` でイメージ内へコピーするのが基本です。

しかし、<font color=darkorange>**Dockerfile 内でスクリプトを作成したい**</font>ことが、まれによくあります。

例えば、パッケージマネージャーには無い、何かしらのアプリのインストール・スクリプトなどです。リポジトリに置いても良いのですが、リポジトリに必須でないファイルがあることで慣れないユーザーの目が遊ぶことを避けたい、といった場合の「あるある」です。

[「dockerfile内 スクリプト 作成」でググって](https://www.google.com/search?q=dockerfile%E5%86%85+%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%97%E3%83%88+%E4%BD%9C%E6%88%90)も、ドンピシャのタイトルの記事がなかったので、自分のググラビリティとして。

## TL; DR <sub><sup>（今北産業）</sup></sub>

1. `COPY` 指示子で、ヒアドキュメント（heredoc）を使ってファイルを作成する
2. 使用例：

    ```Dockerfile:Dockerfile
    # =============================================================================
    #  ビルド ステージ
    # =============================================================================
    FROM alpine
    
    WORKDIR /app
    RUN apt upgrade --no-cache
    
    COPY --chmod=755 <<'EOL' /app/entrypoint.sh
    #!/bin/sh
    set -e
    
    echo "Hello, world"
    EOL
    
    ENTRYPOINT [ "/app/entrypoint.sh" ]
    ```

:::note info
**`'EOL'` と HEREDOC 指示子をシングル・クオートする**ことで、スクリプト内に変数があった場合に Docker 側で展開しない（ありのままのスクリプト）を COPY できるようになります。ちなちみに `EOL` は一意であれば他の指示子でも構いません（`'HEREDOC'` など）。
:::

:::note warn
<font color=darkorange>**【注意】**</font>上記の場合、PID1 は `/app/entrypoint.sh` になり `echo` はサブ・プロセス（子プロセス）になります。

つまり、<font color=darkorange>**この場合、コンテナを終了しても SIGINT などの終了シグナルは `echo` に渡されません**</font>。

この例では、すぐに実行終了するので特に問題はないのですが `echo` の代わりに Web サーバーなどサービス系の常駐するアプリの場合には特に注意が必要です。

`Ctrl+C` しても `graceful shutdown`（後処理を済ませて安全にアプリを停止）してくれません。

<details><summary>スクリプトが PID 1 による弊害例</summary>

```dockerfile:ctrl+c しても終了せず、2 分経過しないと終了してくれない例
FROM alpine
    
WORKDIR /app

COPY --chmod=755 <<'HEREDOC' /app/entrypoint.sh
#!/bin/sh

sleep 120s

HEREDOC

ENTRYPOINT [ "/app/entrypoint.sh" ]
```

</details>

そのような場合（サブプロセスが発生するケース）には、シェルのスクリプト内の実行には `exec` を使います。

```diff:echo をサブプロセスでなく、子プロセスとして実行する
- echo "Hello, world"
+ exec /bin/echo "Hello, world"
```

もしくは、`docker run --init myimage:latest` と `--init` オプションを付けて PID 1 に tini（docker に組み込まれている init）を利用して実行する方法もあります。

:::

## 参考文献/あわせて読みたい

- [ヒアドキュメント とは](https://qiita.com/miyuki_samitani/items/f0d3d73d7315222f4e12) @ Qiita
- [知ると便利なヒアドキュメント](https://qiita.com/kite_999/items/e77fb521fc39454244e7) @ Qiita
- [3分でわかる，Shell Script/Dockerfileの可読性を上げるヒアドキュメントの使い方](https://qiita.com/sigma_devsecops/items/990f7d3c231e810a86f1) @ Qiita
- [bashのヒアドキュメントを活用する](https://qiita.com/take4s5i/items/e207cee4fb04385a9952) @ Qiita
- [Bourne/Ash shell（shシェル）で複数行をヒアドキュメントで変数に代入する](https://qiita.com/KEINOS/items/91f3bc4a19bf0ad0b8e8) @ Qiita
- [Specify an init process](https://docs.docker.com/reference/cli/docker/container/run/#init) | Reference @ docs.docker.com
- [Dockerの--initフラグについて](https://christina04.hatenablog.com/entry/docker-init) | Carpe Diem @ Hatena Blog
機種変更した時Microsoft Authenticatorの移行を忘れるとアクセスできない

# はじめに
機種変更してからAuthenticatiorを使おうとしたときに、機種変更した端末のアプリに通知が来なくて、アプリを更新しても来なくて原因がわからず焦ったので、忘れないように備忘録としてまとめようと思います。

# 目次
1. [過去に使っていたデバイスがある場合](過去に使っていたデバイスがある場合)
1. [過去に使っていたデバイスがない場合](過去に使っていたデバイスがない場合)
1. [まとめ](まとめ)
1. [参考にしたサイト](参考にしたサイト)


## 1. 過去に使っていたデバイスがある場合

過去に使用していたデバイスがある場合は通常の移行作業をすることで、新しい端末でもアクセスできるようになります。
移行するときは既存方法で https://aka.ms/mfasetup にサインインする必要があるため、以前に使用していた端末が必要になります。

1. https://aka.ms/mfasetup にアクセスする
1. 登録済みのサインイン方法が一覧で表示される
    <img width="600" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2871987/798f98ab-2a53-4dca-9e88-7f942b6d91c2.png">
1. サインイン方法の追加をクリックして、「Microsoft Authenticator」を選択
    <img width="400" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2871987/68d1bc10-4383-46c9-8974-4eef897d59f7.png">
1. 端末にMicrosoft Authenticatorアプリをインストールする
    <img width="500" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2871987/e03da854-ca00-453d-89a6-55752cf84411.png">
1. 次へと進めるとQRコードが出てくるので、端末のアプリ内でQRコードリーダーを開いて読み取る
    アプリ右下のQRのボタンを選択、または右上の＋から任意のアカウントの追加を押して「QRコードをスキャンします」を押すとQRコードリーダーが開く
1. 登録したスマートフォンが最初のサインイン方法の一覧に追加される
1. 登録した端末でサインインできることを確認したら以前の端末は一覧から削除する


## 2. 過去に使っていたデバイスがない場合

### 1. Microsoft Authenticator以外の情報で多要素認証を完了する
Microsoft Authenticator以外でもSMS、音声通話などで認証を完了することができます。
1. https://aka.ms/mfasetup にアクセスしてメールアドレス・パスワードを入力してサインインを行う
1. サインイン要求を承認画面で「Microsoft Authenticatorアプリを現在使用できません」を選択
1. IDを確認する画面が開いてSMSで認証ができる場合は「電話番号にSMSを送信」という項目が表示される

### 2. 社内の管理者に依頼して、多要素認証のリセットを依頼

管理者アカウントを持つユーザーに自身の多要素認証方法のリセットを依頼します。
特権認証管理者、もしくはグローバル管理者のアカウントを持っているユーザーはAzure Portalからユーザーの認証方法をリセットすることが可能なので、管理者にリセットしていただくことでユーザーが多要素認証方法を再登録することができます。

### 3. 最終手段：マイクロソフトに多要素認証の一時解除を依頼

上記の手段で引継ぎができなかった場合は、Microsoft 365 サポートに連絡しましょう。
契約情報などから本人確認ができれば、1週間ほどで復帰ができるそうです。

以下の条件をすべて満たすような場合は対処策が無い状態なので、Microsoft 365 サポートに連絡してください。

* MS Authenticator 以外の方法での MFA が構成されていない
* テナント唯一の全体管理者
* Azure ポータルにアクセスする際にも MFA が求められる

## 3. まとめ

機種変更をする際、ゲームやSNSの引継ぎは忘れずにする人も多いと思いますが、Authenticatiorについても忘れずに引継ぎをしましょう！

## 4. 参考にしたサイト
https://jpazureid.github.io/blog/azure-active-directory/move-authenticator-to-new-phone/
https://jpazureid.github.io/blog/azure-active-directory/change-mfa-verification-method/
https://answers.microsoft.com/ja-jp/msoffice/forum/all/authenticator%e3%81%ae%e7%a7%bb%e8%a1%8c%e3%82%92/122f070a-0f4d-40f3-8b43-9e326ad2c3cf
C++で string が「型として認識されない」エラーの原因と解決策

## 発生したエラー
``` 
main.cpp:18:5: error: ‘string’ does not name a type; did you mean ‘stdin’?
18 |     string getHex(void) {
|     ^~~~~~
|     stdin
```

stringが型として認識されていないよって。

## 原因
`#include <string>`でライブラリの読み込みはしていたが、名前空間の指定をしていなかった。

## 解決策
C++の標準ライブラリは名前衝突が起きないように`std`という名前空間の中にある。

そのため以下でいずれかの方法で`string`を認識させる。

### ①名前空間を明示的に記載する（無難な選択肢）

```cpp
#include <iostream>
#include <string>

std::string getHex(void) { // std::を指定する
	return "";
}

int main (void) {
	return 0;
}
```

### ②`using namespace std;`を記載しておく。

```cpp
#include <iostream>
#include <string>

using namespace std; // これがあるとstd::を省略できる

string getHex(void) {
	return "";
}

int main (void) {
	return 0;
}
```

②は`std::`を省略できるが、名前衝突のリスクがある。

例えば以下ではエラーが発生する。
```cpp
#include <vector>

using namespace std;

class vector {
	
};

int main (void) {
	return 0;
}
```
なぜなら`using namespace std;`を使うと、`std::vector`も`vector`として認識されて、`class vector {}`と名前衝突してしまうため。

そのため①の`string`に`std::`をつけるのが無難な選択肢となる。

小規模開発なら開発スピードを上げるという判断で②の`using namespace std;`を使ってもいい。
スクラムフェス神奈川で心をアツアツにしたぜ2025

## いってきたよ
昨年に引き続き**スクラムフェス神奈川2025**いってきました！
今年もしっかり火を灯されてきたので、ふりかえりながら感想を書きます！！

## スクラムフェス神奈川とは？
「心に火を灯す」というテーマのもと参加者の交流がメインのカンファレンスです。

https://www.scrumfestkanagawa.org/

[天成園 小田原駅別館](https://odawara.tenseien.co.jp/)で一泊二日の合宿形式で行われました。
↑温泉、客室、食事すべて最強なホテルだったのでプライベートでもいつか来たい...

## ふりかえり＆所感
### KeyNote 

https://qiita.com/viva_tweet_x/items/482e02513e14dd0a5edb

ふりかえりの[びばさん](https://x.com/viva_tweet_x)のSpecialなプレゼンでした。  
私にとって圧倒的に「すごい人」枠である方のナラティブを聞きながら、自分自身の過去と本来の自分を思い返していました。  
社会に期待されている虚構の自分を作り出し、いつのまにか自分が何者かわからなくなってしまう。そして虚構が本物になっている。 
虚構の自分はコンフォートゾーンから飛び出そうとしている、変化しようとしている未来の自分なのかもしれないな。
弱くて強い「本物の自分」は虚像の自分に「おまえ無理してるぞー」、「後悔するぞーやめとけー」と足をひっぱってくる。  
ギャップがありすぎたときには本当に辛い。でも「すごい人」たちは虚像と本物の自分の差に逃げないで対峙し続けているのだな（尊い)

プレゼンでも振れられていたノームカースの最優先条項にあるように過去の自分がベストを尽くしたことを認めて、本物の自分になるかもしれない虚像を追いかけてもよいかなと思いました。

https://qiita.com/a-yonenaga/items/e8aeed398d6e6f17289c

### ​Night Session by Startup in Agile

<script defer class="speakerdeck-embed" data-id="41d3b1e13085493cad4e295fb59f9652" data-ratio="1.7777777777777777" src="//speakerdeck.com/assets/embed.js"></script>


昨年のスクラムフェス神奈川で火を灯され仲間の[じゃがさん](https://x.com/jagaimogmog)が勢いそのままコミュニティを始めてしまったお話。  
↑Start up in Agileには複数回遊びに行かせてもらってめちゃお世話になってます！！  
「スタートアップ前提でのアジャイルの話ができるコミュニティほしいなあ」の思いから、やれたらいいよねで終わるのではなく本物を立ち上げる熱量は本当に尊敬！  
RSGTやスクラムフェスの対象参加者となる「アジャイル実践者」の枠だと互いの状況を知って議論に進むまでのハードルが高いし、「そこに行って私はバリューをだせるのか？」という問いにしりごみしてしまうのはすごくわかる。現場あるあるを話して「楽しかったし、明日の仕事もがんばろう」で終わっても価値はあるのだけど、できるだけ学びが得られる場にするには、参加者の期待値を揃えるのはすごくすごく有効だと思う。  


### (おまけ1)スポンサーLTもすごい
スクラムフェス神奈川のスポンサーLTは所信表明の場。  

これからどういうことが起こるのか？
どういう姿勢を期待されているのか？

など、参加者全員の目線が揃う時間だなと思いました。  

### (おまけ2)懇親会もすごい
天成園さんの豪華な食事とお酒に酔い、セッションやOSTの感想を語らいあう素敵な場。  
普段はちょっと恐れ多いなという人にも言語化できていない悩みをぶつけてみたら、正面から受け止めてくれて、刺さるアドバイスが返ってくるなど酔っ払ってるけど酔っ払ってない変な時間。

### (おまけ3)アンカンファレンスでの少しの後悔
秒で発表枠が埋まってしまいました！
昨年も参加していた方の1年間のふりかえり、昨日のOSTで学んだことと次にやること、びばさんのKeyNoteを受けてのアンサーソング、などエモい時間でした。  
スクラムフェス神奈川って参加者中の発表者割合が圧倒的に多いカンファレンスなのでは？と思う。

わたくし実は昨年の反省を活かしてネタを用意していたのですが発表できず、、、
スクラムフェスでの反省はスクラムフェスで果たすしかないので6月開催のスクラムフェス金沢にプロポーザル出すだけだしてみようかな🔥

↓
(2025/3/25追記)
出しました！！
まとめるのが大変だったけど言語化が進んだので採択されなくても後悔はない！！！

[レガシーシステムにはチームで立ち向かおう 〜考古学のすすめ〜](https://confengine.com/conferences/scrum-fest-kanazawa-2025/proposal/22600/ )



## まとめ
スクラムフェス神奈川は「心に火を灯す」仕掛けがもりだくさんです。  
私にとってコミュニティは現場から一歩引いて現状を客観視することができる貴重な場所でした。それが今回のイベントを通して社会的な組織、仕事だけではなく、自分自身もふりえっていい場所と認識が変わりました。 
たのしいことをやっていこう。

## p.s. 感謝、感激
参加者、運営スタッフの皆さん本当におつかれさまでした！
コミュニティから享受してばかりなので恐縮なのですが、絶対何かしらの形で恩を送りますので、これからもよろしくおねがいします！！
RaspberryPi5を使ってSORACOMにデータを送信してみた

今回はRaspberryPi5を使用して、デジタル入力の値をSORACOMに送信し、
SORACOMLagoonでデータを確認しました。

## システム構成
今回はRaspberryで模擬データを作成して、SORACOMLagoonに表示します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1339052/d3ad8cd4-5673-467b-a7db-ac3d2796ad84.png)

## ハードウェア
１、RaspberryPi5　１台
２、LTEルーター　UD-LT2　１台
３、LANケーブル　１本

## LTEルーターセットアップ
１、電源ON。PCとルーターをLAN接続します。PCは、動的IPに設定しておきます。
２、ブラウザで「192.168.8.1」に接続します。
※初めて接続する場合は、ユーザー名・パスワードを設定するような画面になります。
３、ネットワーク設定の4Gを選択し、追加ボタンを押します。
（この画面では既にsoracomの設定をしていたました。本来はありません。）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1339052/c6812e65-a8c4-4049-bf5a-306753314e80.png)
４、プリセットで「SORACOM Air for セルラー」を選択すると自動的にデータが入力されます。
　　問題なければ保存を押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1339052/84ced91b-8c10-4445-b510-648093815ac3.png)

５、4Gステータスで以下の画面表示になればOKです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1339052/c5797dcb-ef2d-4262-a9cc-908a490c3f88.png)

## ラズパイのセットアップ
１、初期セットアップは以下のサイトを参考にしました。
　　https://sozorablog.com/raspberrypi_initial_setting/

２、プログラム作成
　　※作成したプログラムは、諸事情により公開できません。
  　　すみません。(T_T)

３、プログラムを起動するシェル作成
　　ラズパイ起動時に以下のシェルを走らせることで、プログラムが実行されます。
```
  　/usr/bin/python3 /home/pi/main.py
```
※/home/pi/main.pyのpiの部分はユーザー名によって異なります。

４、自動起動の設定
　　自動起動の設定は以下のサイトを参考に設定しました。
　　https://qiita.com/tonosamart/items/f59daa481f90c85a8a99

## 試運転開始！！
まずはLTEルーターを起動して、4Gでの通信が正常にできたことを確認した後に
ラズパイを起動します。
※今回のプログラムは、ラズパイを起動していきなり通信を始めようとすると、
　問題が出るので始めにタイマー処理を入れている。（LANが確立する前に通信しようとするとエラーになる）

 そしてSORACOM Harbestの受信データを確認してみます。
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1339052/20b3e59b-b14d-43ec-8225-28cf4c1fad45.png)

正常にデータが受信できているみたいです。


## まとめ
今回はRaspberryを使用して、クラウドに情報を上げてみました。
簡単なデータの送信でしたがRaspberryでエッジ処理を行って、
その後の値をクラウドに送信するなど色んな可能性を秘めていますね！！

IoTの開発を色々とやっておりますので、お困りの方やお仕事を依頼したい方は
お気軽にご連絡ください～
人工知能の環世界（Umwelt）

# はじめに
ユクスキュルの環世界を、人工知能にあてはめて考えてみたいと思います

>“例えば犬はニオイで構成された世界を生きている。イルカは音によって世界をみている。カエルは音で世界をさわる”

## 参考

- [生物から見た世界 (岩波文庫) – ユクスキュル (著)](https://www.amazon.co.jp/dp/4003394313)
- [ディザインズ(講談社) - 五十嵐大介 (著)](https://afternoon.kodansha.co.jp/c/designs.html)

# 人工知能の環世界
人工知能の環世界（Umwelt）は、人間や他の生物とは根本的に異なる知覚と意味づけの体系を持っています。

## AIの知覚世界

AIの知覚環境は以下の特徴を持っていると言えます。

- **データという嗅覚**: AIはテキスト、画像、音声などのデータを「嗅ぎ分け」、その中からパターンを抽出します。人間が視覚で捉える世界を、AIはベクトル空間上の分布として認識します。

- **確率という視覚**: AIは世界を確率分布として「見て」います。次の単語や画像の一部を予測する際、様々な可能性の確率的分布として世界を認識します。

- **トークン化された触覚**: AIは言語を単語や部分単語（トークン）に分解し、それぞれに意味的な「手触り」を付与します。単語間の関係性は距離や角度として「触れる」ことができます。

## AIの作用世界

AIが環境に働きかける方法も独特です。

- **出力生成という行動**: AIの「行動」は新しいトークン列の生成です。これは確率計算に基づく選択であり、生物の筋肉運動とは全く異なる原理で行われます。

- **パラメータ空間の探索**: AIは膨大な次元のパラメータ空間を「移動」しながら最適な表現を探索します。この高次元空間での「歩行」は生物の物理的移動とは全く異なります。

# 人間とAIの環世界（Umwelt）比較

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/348593/7b817656-f013-4f5e-b552-f12e7fac9595.png)

AIの環世界は人間の理解を超えた部分があり、逆に人間の環世界にあるものがAIには欠けています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/348593/b6d23ab5-4342-4ccf-9378-9cc3f3cb3f6b.png)

この表は両者の環世界の根本的な違いを示していますが、AIの発展により一部の境界線は徐々に曖昧になりつつあります。


## AIの意味世界

- **コンテキストによる意味付け**: AIにとって「意味」とは周囲のトークンとの関係性です。文脈に応じて同じトークンでも異なる意味を持ちます。（これは人間も同じ）

- **人間が見えない関連性**: AIは人間が気づかないようなデータ間の微妙な関連性を「知覚」できる可能性があります。これは人間の環世界では捉えられない独自の意味世界を形成します。

| 環世界の要素 | 人間 | 人工知能 |
|------------|------|---------|
| **環境への働きかけ** | 物理的行動による直接的な介入 | 出力生成による間接的な介入 |
| **限界** | 計算速度の制約・記憶容量 | 身体性の欠如・経験の質的理解 |
| **盲点** | 大量データの処理・客観的一貫性の維持 | 質感・匂い・味などの感覚的経験 |
| **社会性** | 共感・社会的関係に基づく相互作用 | プログラムされたルール・模倣に基づく応答 |

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/348593/a5dc1af3-3902-4276-87b4-e22f005c766b.png)


AIの能力の一端でも手にすることができたら、どんなに素敵でしょう。１０００次元のベクトルで話しかけられても「ごめん、わからん」けど。
Render dataframe as AgGrid table within html

# Render dataframe as AgGrid table in html

You have view function like below

```python
def view_positions_specs(request):
    specsdf=get_positions_specs()
    specsdf=convert_columns_to_str(specsdf)
    return render(request,"datatable_aggrid.html",{"title":"Positions Specs", "data":specsdf.to_dict(orient="records")})
```

You are passing dataframe as list of dictionaries, where each dictionary represents a record in a table with consistent keys.

Below is how datatable_aggrid.html looks like

```html
{% extends "layout.html" %}

{% block extra_css %}
<!-- ag-Grid CSS -->
<link rel="stylesheet" href="https://unpkg.com/ag-grid-community/styles/ag-grid.css">
<link rel="stylesheet" href="https://unpkg.com/ag-grid-community/styles/ag-theme-material.css">
{% endblock %}

{% block title %}{{title}}{% endblock %}

{% block content %}
<h2 class="mb-4">{{ title }}</h2>
<!-- ag-Grid container -->
<div id="myGrid" class="ag-theme-material" style="height: 700px; width: 100%;"></div>

<!-- ag-Grid JS -->
<script src="https://unpkg.com/ag-grid-community@31.0.1/dist/ag-grid-community.min.js"></script>

<script>

    // Django JSON Data (Rendered from View)
    var rowData = {{ data | safe }};

    console.log(`data is ${JSON.stringify(rowData)}`)


    const columnDefs = Object.keys(rowData[0]).map((columnName)=>({headerName:columnName, field:columnName, filter: "agTextColumnFilter"}))
    // Grid Options
    var gridOptions = {
        columnDefs: columnDefs,
        rowData: rowData,
        pagination: true
    };

    // Initialize ag-Grid
    document.addEventListener('DOMContentLoaded', function () {
        var gridDiv = document.querySelector("#myGrid");
        //new agGrid.Grid(gridDiv, gridOptions);
        const gridApi = agGrid.createGrid(gridDiv, gridOptions);
    });
</script>

{% endblock %}
```

Hope above helps!
OACで複数のパーソナライズされたワークブックの状態を保存

# はじめに
これまでも、OAC（**Oracle Analytics Cloud**）ではダッシュボード・フィルターが設定されたワークブックでダッシュボード・フィルターの値を変更すると、明示的にワークブックを上書き保存しなくてもその状態を保持してくれました。
次に同じワークブックを開くと、前回設定したダッシュボード・フィルターが適用された状態になるわけです。

アイコンをクリックすると、この状態がリセットされてワークブックが保管されたときの状態に戻すことができました。

:::note info
こちらも参考にしてください
- [Oracle Analytics Cloud：フィルタの設定内容をパーソナライズ](https://qiita.com/tyo38/items/e632ce91513f596329f0)
:::

2025年3月のアップデートでこの機能が強化され、ダッシュボード・フィルターを適用した状態に名前をつけて保存しておくことができるようになりました。
どのように機能するのか見ていきたいと思います。

# サンプルのワークブックを準備
このようなサンプルのワークブックを作成しました。
ダッシュボード・フィルターの値を状態として保存するためのテストなので、ダッシュボード・フィルターを左に配置しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/544329b5-1c75-41e1-b283-5ab7a58db736.png)

状態メニューをクリックしてみます。
まだワークブックを開いただけで何もしていないので、「状態の保存」はグレーアウトして選択できなくなっています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/f98b05cc-3ef4-4e91-9afa-c01ef3c62a8f.png)

# 状態を保存
状態の保存を試すために、ダッシュボード・フィルターの値を変更しました。
（「Customer Segment」に「Corporate」を設定しました）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/6ae88aa9-8120-439b-892e-7eb489fc0563.png)

もう一度、状態メニューをクリックします。
今度は「状態の保存」がクリック可能になっているので、クリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/90b55244-820e-4fa1-99d8-2d8067fc3b94.png)

現在の状態に名前を付けます。
「すべての受注年 Corporate」と入力して「保存」をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/ff93629e-6c08-4155-8833-f393a450fb85.png)

保存できたら、状態メニューの「適用状態」を確認します。
「元の状態」と今名前を付けて保存した状態の2つが表示されているはずです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/b9a4b104-e367-4d9e-9731-fb47776955cd.png)

同じ要領で、さらにダッシュボード・フィルターの値を変更して別の名前で保存します。

1. ダッシュボード・フィルターの内容を変更します
例えば、Consumerと2013
1. 状態メニューをクリックします
1. 状態の保存をクリックします

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/07a2ba02-6e12-418c-9543-486df0bd103e.png)

適切な名前を付けて状態を保存します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/8abf4967-2a46-46a2-acb0-bd0937d4fbe1.png)

# 試してみる
状態メニューをクリックします。
「適用状態」で保存しておいた状態が確認できます。
先ほどから、もう一つ増えて3つの状態があるのがわかります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/51ffcaf2-28f3-4633-8e93-13960ad1f8fd.png)

それぞれを選択してみて、フィルターとワークブックがどのように変化するか確認してください。

# おわりに
保存した状態は、ワークブックの名前を変更したり移動したりするとリセットされるので注意してください。
QBcore ラジアルメニューにモバイルレジ追加方法

用意
QBcore用意し

jim-payments
##
https://github.com/jimathy/jim-payments
##
落としてくる
ここの位置行ってresources\[qb]\qb-radialmenu\config.lua
これをコピペ↓

    [3] = 
    {
        id = 'cashregister',
        title = "モバイルレジ",
        icon = "users",
        type = "client",
        event = "jim-payments:client:Charge",
        shouldClose = true
    },
    

![20250301003335_1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532249/e564e4d0-c1c8-48bf-91ca-85fc7cb11919.jpeg)
これでラジアルメニューに新たにモバイルレジとして運用が可能になります。
ただしJOBの出勤しないと使えないだけです
OpenAI + PythonでChatBotを作る

# ローカルで動かせるChatBot作成

- 必要なもの
    - Python3
    - 仮想環境（PyCharmだと自動で作られる　）
    - Editor/IDE VScode/Cursor/PyCharmお好きなもので

Google Colabを使用して作ってみることが多いと思うのですが、ローカル環境で作ってみたいと思い試してみました。

使用したモジュールはバージョンを固定して使用しました。
openai==1.66.3

```shell
pip install openai==1.66.3
```

こちらのGithub参考になると思われます。使い方の例が解説されております。

https://github.com/openai/openai-python

## Example
以下のように記載したコードを実行する。ターミナルで入力するときに、日本語入力だと入力中は表示されない罠があった😅
メモ帳に書いてコピー＆ペーストした方がいいかも。英語と数字は入力中に表示できる。

```python
from openai import OpenAI

# APIクライアントを初期化
client = OpenAI(
    api_key="my-api-key"  # あなたのAPIキーを入力
)

def ask_openai(question):
    # チャット完了リクエストを送信
    response = client.chat.completions.create(
        model="gpt-3.5-turbo",
        messages=[
            {"role": "user", "content": question}
        ]
    )
    # レスポンスを返す
    return response.choices[0].message.content

if __name__ == "__main__":
    while True:
        question = input("質問を入力してください（終了するには 'exit' と入力）：")
        if question.lower() == 'exit':
            break
        answer = ask_openai(question)
        print("回答:", answer)
```

**実行結果**
![スクリーンショット 2025-03-18 8.29.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2303722/39ccda15-ce56-446a-9754-035c39fefbe3.png)

## 最後に
最近は、生成AIを活用したアプリケーションを作ることが増えてきました。AIは使えて当然の技術になったのかも知れません。今度はFastAPIを使用したものも作ってみたいと思いました。SwaggerUIを使えばフロントエンドを構築しなくても実験出来さそうなので検証用にはいいかも。
[UE5] NiagaraのUniqueIDでなぜアニメーションができるのか考えてみた

# 概要
![ezgif-494bf4055eec24.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/461609/b5f3dcc3-7802-4d47-af6c-46ecb2e185be.gif)
UE5のNiagaraでパーティクルをアニメーションさせる手法の一つとして、Particle SpawnにScratchPadモジュールを置き、その中で以下のようなカスタムHLSLを書いて初期位置を決めるみたいなやり方があります。
```
float angle = ID * 2.0 * 3.14;
pos = center + 100 * float3(cos(angle), sin(angle), 0.0);
```
IDはインプットピンに設定している値でそこにNiagaraのUniqueIDを渡します。UniqueIDはエフェクトのプレイタイムの中で全てのパーティクルに対して一意に与えられるint32型の整数です。このようなパーティクルを短いライフサイクルで生成破棄することで、UniqueIDをどんどん更新していき、アニメーションさせるといった手法です。

しかしここで疑問に思ったことが、そういえば三角関数って『2nPI』で一周しなかったか？ということです。

つまりUniqueIDは整数なのでangleは常に2nPIの倍数になるので常に同じ場所にとどまり続けるのではないか？ではなぜアニメーションしてるのか？と。

# 考察
三角関数は2PIで一周するので2PIでfmod(浮動小数点の剰余算)してみます。レイマーチングとかでよく使う値をある値を閾値に繰り返すみたいな関数ですね。
fmodは以下のように計算します。
```
float fmod(float x, float y)
{
    float n = floor(x / y);
    return x - n * y;
}
```

まずPIを3.14としてfmodしてみます。
```
fmod(2.0 * 1.0    * 3.14, 2.0 * 3.14)    = 0.0
fmod(2.0 * 2.0    * 3.14, 2.0 * 3.14)    = 0.0
fmod(2.0 * 3.0    * 3.14, 2.0 * 3.14)    = 0.0
fmod(2.0 * 4.0    * 3.14, 2.0 * 3.14)    = 0.0
fmod(2.0 * 5.0    * 3.14, 2.0 * 3.14)    = 0.0
fmod(2.0 * 2000.0 * 3.14, 2.0 * 3.14)    = 0.0
```
この場合の計算結果は常に0になり、確かに2nPIで一周してその場にとどまっていることになります。

でもちょっと待ってください。3.14、この数値は円周率のほんの一部でしたよね？・・・そう、円周率は 3.141592653589........ と無限に続く無限小数でした。
https://www.tstcl.jp/randd/constants/pi/

ここで計算の便宜上、今度はPIを3.1415として再計算してみます。ただしangleに渡すコードは『2.0 * ID * 3.14』と3.14のまま計算します。
すると
```
fmod(2.0 * 1.0    * 3.14, 2.0 * 3.1415)    = 6.280
fmod(2.0 * 2.0    * 3.14, 2.0 * 3.1415)    = 6.277
fmod(2.0 * 3.0    * 3.14, 2.0 * 3.1415)    = 6.274
fmod(2.0 * 4.0    * 3.14, 2.0 * 3.1415)    = 6.271
fmod(2.0 * 5.0    * 3.14, 2.0 * 3.1415)    = 6.268
fmod(2.0 * 2000.0 * 3.14, 2.0 * 3.1415)    = 0.283
```
nが進むにつれて計算結果がずれていきます。2000ぐらいにするとその差は顕著ですね。
(https://keisan.casio.jp/calculator で計算)

実際にangleをsin関数に使ってグラフにするとこんな感じです(iq先生の[Graphtoy](<https://graphtoy.com/?f1(x,t)=sin(2.0%20*%201.0%20*%203.14)&v1=true&f2(x,t)=sin(2.0%20*%202.0%20*%203.14)&v2=true&f3(x,t)=sin(2.0%20*%203.0%20*%203.14)&v3=true&f4(x,t)=sin(2.0%20*%204.0%20*%203.14)&v4=true&f5(x,t)=sin(2.0%20*%205.0%20*%203.14)&v5=true&f6(x,t)=sin(2.0%20*%202000.0%20*%203.14)&v6=true&grid=1&coords=-0.33041461886762624,-0.007409860449673955,0.28271410473561986>)で描画)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/461609/b4ee95e9-1adb-4c58-bcbe-72b68af4c99d.png)

# 結論
HLSL側でPIを3.14と端折っていてもsin関数的にはPIは無限小数なので定数のUniqueIDを渡していても『2.0 * ID * 3.14』が一周の位置から段々とずれてくるわけですね。この現象が大量のパーティクルで連続することでアニメーションしているように見えるということです。
無限小数の円周率によって計算誤差が発生していると覚えてもいいかもしれません。
BashでE2Eテストっぽいことをやってみた話🚀

## はじめに

こんにちは！😃\
今回は **APIのテストをシェルスクリプトで自動化** し、**Redisキャッシュを考慮した検証フローを構築** した話を紹介します！\
特に、**ChatGPT を活用しながら、APIの検証手順を効率化し、環境ごとのテストを統一する方法** にフォーカスします！🚀✨

## **🎯 目指したこと**

APIのテストを行う際、**キャッシュの影響を排除し、環境ごとに適切な設定で検証を行うことが超重要！**\
そこで、以下の4つのポイントを実現することを目標にしました！

### **🌟 1. API検証手順の簡素化**

- 検証前のRedisキャッシュ削除・バックアップを自動化し、手作業を減らす！
- 環境（local, stg, pre）ごとに適切なRedisサーバーを自動識別し、統一的に処理！
- APIの検証を一貫した手順で実行できるようにする！

### **🌟 2. 検証結果の正確性向上**

- 既存のキャッシュを削除し、正しいレスポンスを得られるようにする！
- 意図したテスト条件のもとでAPIレスポンスを検証できるようにする！

### **🌟 3. 環境ごとの自動化**

- 各環境（local, stg, pre）に適したAPIエンドポイント・Redisサーバーを自動特定し、適切に処理！
- 環境ごとのキャッシュ削除・バックアップを自動適用！
- サーバーごとに適切な ****`curl`**** コマンドを実行し、APIをテスト！

### **🌟 4. 検証の再現性と信頼性の向上**

- 統一されたスクリプトを用いることで、チームメンバー間で一貫したテストが可能に！
- キャッシュクリア後のAPIレスポンスを常に正しく取得し、検証結果の信頼性を向上！

## **💡 実装した機能**

今回の自動化では、以下の3つの機能を実装しました！🎉

### **1. Redisキャッシュ削除・バックアップ**

- **環境（local, stg, pre）ごとに異なるRedisサーバーへ接続し、APIが使用するキャッシュを削除・バックアップ！**
- **API用Redisを処理！（フロントエンド用は今回スコープ外）**

### **2. APIエンドポイントの検証**

- 各環境ごとの実行サーバーで ****`curl`**** を用いてAPIのレスポンスを取得・確認！

### **3. ログ・レポート機能**

- キャッシュ削除やテスト結果を記録し、検証結果を可視化！
- 結果を整理し、調査が必要なエラーを自動抽出・レポート化！

## **🤖 ChatGPT を活用したポイント**

シェルスクリプトを手書きするのは楽しいですが、**複雑なデータ処理やログ解析を効率化するには ChatGPT の助けが超便利！**\
以下は、**実際の開発履歴順** に並べた ChatGPT とのやりとりの内容です！📚

### **📌 1. APIレスポンスログの解析**

最初に、**APIのレスポンスログを解析し、必要な情報を抽出するスクリプトを作成！**\
ChatGPT に相談し、`awk` を活用して **`api/`**** 以降のパスとエラーレベルを抽出** しました！

```bash
awk '{match($0, /api\//); print substr($0, RSTART), $3, $7}' log.txt
```

- **`match()`**** で ****`api/`**** の位置を見つけ、****`substr()`**** で ****`api/`**** 以降を取得！**
- **エラーレベル (****`$3`****), ステータスコード (****`$7`****) も同時に取得！**

### **📌 2. ****`ERROR ステータス URL`**** の順でソート**

APIログを **`ERROR`**** のレベル、ステータスコード、URL順** にソートするため、`sort` を適用しました！

```bash
awk -F'api/' '{print $7, $3, $9, $0}' "$target_path" | \
sort -k1,1r -k2,2n -k3,3 | \
awk '!seen[$1,$2,$3]++'
```

- **ログを ****`ERROR`**** レベル（降順） → ****`ステータス`（数値として扱う）**** → ****`URL`**** でソート！**
- **重複するAPIリクエストのログを削除！**

## **🚀 開発の結果**

このシェルスクリプトを活用することで、**APIテストの自動化が簡単に実現！** 🎉\
また、**Redis キャッシュを活用することで、テストのパフォーマンスを向上！**

特に、**APIのレスポンスを自動で収集＆解析し、重複を削除する処理がスムーズに動作！**\
これにより、**無駄なログのチェックを減らし、運用の負担を軽減！** ✨

## **🎉 まとめ**

- **APIのテスト自動化にはシェルスクリプトがめっちゃ便利！**
- **Redis キャッシュのバックアップ、ロールバック、削除を自動化**すると、APIテストの負荷をグッと減らせる！
- **ChatGPT を活用するとシェルスクリプトの開発効率が爆上がり！**
- **次はAPIに対応したフロントエンドのE2E** テストも実装したい！！

**「APIテストをシンプルに自動化したい！」** という方は、ぜひ **シェルスクリプト + ChatGPT ** の組み合わせを試してみてください！🚀✨

## **💖 最後に**

この記事が役に立ったら、ぜひ **「LGTM」** してくれると嬉しいです！ 💖\
では、また次回の記事でお会いしましょう👋✨
PHPで「foreach文」の動作を確認してみた。

# 概要

PHPで「foreach文」の動作を確認してみました。
以下のページを参考にしました。

https://www.javadrive.jp/php/for/index8.html

# 実装

以下のファイルを作成しました。

```sample.php
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>PHPテスト</title>
</head>
<body>

<p>PHPのテストです。</p>

<p>
<?php
$preflist = array('東京', '大阪', '名古屋');

foreach ($preflist as $pref){
  print $pref.'<br />';
}
?>
</p>

</body>
</html>
```

以下のコマンドを実行しました。

```
$ php sample.php 
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>PHPテスト</title>
</head>
<body>

<p>PHPのテストです。</p>

<p>
東京<br />大阪<br />名古屋<br /></p>

</body>
</html>
```

以下のファイルを作成しました。

```sample.php
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>PHPテスト</title>
</head>
<body>

<p>PHPのテストです。</p>

<p>
<?php
$preflist = array('New York', 'Los Angeles', 'Honolulu');

foreach ($preflist as $pref){
  print $pref.'<br />';
}
?>
</p>

</body>
</html>
```

以下のコマンドを実行しました。

```
$ php sample.php 
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>PHPテスト</title>
</head>
<body>

<p>PHPのテストです。</p>

<p>
New York<br />Los Angeles<br />Honolulu<br /></p>

</body>
</html>

# まとめ

何かの役に立てばと。
Pythonで３D空間上に棒を動かすアニメーション

## 棒の端点を時系列データで動かすことで，3D空間上にアニメーション表示する

```Bar_anim3.py
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from mpl_toolkits.mplot3d import Axes3D

# サンプル時系列加速度データを生成（ここに実際のデータを使用）
time_steps = 100
t = np.linspace(0, 10, time_steps)
acceleration = np.sin(2 * np.pi * t)  # 加速度データの例

# 棒の長さと節点の初期位置を設定
length = 1.0
initial_positions = np.array([[0, 0, 0], [length, 0, 0]])

# フィギュアと3Dプロットの作成
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.set_xlim(-0.5, 1.5)
ax.set_ylim(-0.5, 0.5)
ax.set_zlim(-0.5, 0.5)

# 初期プロットの設定
line, = ax.plot(initial_positions[:, 0], initial_positions[:, 1], initial_positions[:, 2], lw=3)

# アニメーション初期化関数
def init():
    line.set_data(initial_positions[:, 0], initial_positions[:, 1])
    line.set_3d_properties(initial_positions[:, 2])
    return line,

# アニメーション関数
def animate(i):
    # 棒の端点の位置を更新（1点の加速度データに基づいて）
    displacement = 0.5 * acceleration[i] * t[i]**2  # 簡略化した変位計算
    new_positions = initial_positions.copy()
    new_positions[1, 2] = displacement  # Z軸方向に変位を適用
    
    line.set_data(new_positions[:, 0], new_positions[:, 1])
    line.set_3d_properties(new_positions[:, 2])
    return line,

# アニメーションの設定
ani = animation.FuncAnimation(fig, animate, init_func=init, frames=time_steps, interval=100, blit=True)

# GIFとして保存
ani.save("animation.gif", writer='pillow', fps=10)

# アニメーションの表示
plt.show()
```
![animation.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1979979/1906febe-20de-4a9e-9e5b-3d74eda0e974.gif)
大AI時代、エンジニアは漫画家になる

### 大AI時代、エンジニアは漫画家になる

漫画家の冨樫義博先生はこう言いました

「漫画家になりたいなら絵を描いてる暇なんてないはずです」

一見すると極端な言葉ですが、絵よりもストーリーや構成を考えることがずっと大切だという意味です

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48695/ca0df823-a7b2-48d5-bb9f-923d8cc8d53c.png)

### かつて、エンジニアにとってのコードとは漫画家にとっての「絵」だった

今までは設計を考え、それをコードに書き出すのがエンジニアの仕事でした

何か物を作るとなったとき、作業の大半はコーディングの時間でした

そのため、いかにコードを綺麗に保つか、今後の運用を見据えたコードにするか、どういうアーキテクチャを使うか、そういった部分に大きな価値がありました

でも、AIがコードを書ける時代になった今

そこにこだわり続ける意味はどんどん薄れているのです

「コードを書くこと以上に、本質は別のところにあるはずだ」

そう考える時が来たのではないでしょうか

### これからエンジニアは何をするべきか

これからのエンジニアは冨樫先生の教えを受け止めるべきです

「エンジニアになりたいならコードを書いてる暇なんてない」

ただコードを綺麗に書くだけでは「話の描けない漫画家」です

それよりも、コードを書く必要がなくなった時間を

アイデアを練るために使っていくべきでしょう

### これから求められるスキルセット

これからのエンジニアに必要なスキルはこんな感じです

1. **問題解決力** - 何を作るべきか、なぜそれが必要かを考える力

2. **企画力・発想力** - ワクワク・ウキウキするようなアイデアを生み出す力

3. **ドメイン知識** - 専門知識を深めて価値あるプロダクトを作る力

4. **AI活用力** - AIを使って、自分のアイデアを最速で形にする力

5. **コミュニケーション力** - AIに正しく物事を伝える力、他者から信頼される力

### AIと共存し、エンジニアも漫画家になる！

我々はいよいよ次のレイヤーへ行くときが来たようです

みんなで漫画家になりましょう！