OmniAICreator/Qiita-1.07M huggingface dataset:
Azure AD

[まとめページに戻る](https://qiita.com/Keiji_otsubo/items/60afc2a8d211b6f7d89f)
[まとめA～M](https://qiita.com/Keiji_otsubo/items/f3ddedee6793bf1576f8)



+ [Azure AD プロビジョニング属性の Manager から ManagerID へのマッピング](https://trailhead.salesforce.com/trailblazer-community/feed/0D54S00000A8h4y)

現在の課題は、salesforce のユーザー テーブルには ManagerID しかなく、マネージャーのフル ネームである Manager(AD 内) を使用して salesforce の ManagerID にマッピングできないことです。これを構成する他の方法があるかどうか知りたいです。

:::note
セットアップを確認したところ、以下のマッピングによって AD -> SF からマネージャー属性のマッピングが機能していることがわかりました。とても簡単です:

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/38ef41dd-2aef-db12-90f2-dd2914708a29.png)

おそらく追加の便利な構成として、属性マッピング設定テーブルで ManagerId を Reference タイプとして指定する必要があります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/19707f8b-5a96-03a0-4fb7-6c077b144a1d.png)
:::
【Python 3】Seleniumで読み込み待ちができない場合の対処方法

# はじめに
ページを読み込み終わる前に、後続の処理を実行してしまい、処理が失敗してしまう事象が発生した。
## 環境
Python 3.12.4
Selenium 4.23.1
Windows 10 22H2
# 起きた問題
ページの読み込みが終わる前に、後続の処理を実行してしまい、処理が失敗してしまう事象が発生した。
サンプルコードは、ログインを自動化する処理のコードである。
サンプルコードでは、ログインID入力欄、パスワード入力欄、ログインボタンが読み込まれる前に、ログインID・パスワードを入力し、ログインボタンを押下する処理が発生する。
## サンプルコード
``` python:auto_login.py
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

def main():
	LOGUIN_URL = 'https://hoge.hoge/login'
	USER_ID = "TestUser"
	PASSWORD = "TestPassword"
	
    with webdriver.Chrome() as driver:
        driver.maximize_window()        
	    driver.get(LOGUIN_URL)

	    # ログインページを読み込み終わるまで待つ。
	    wait = WebDriverWait(driver=driver,timeout=30)
	    wait.until(EC.presence_of_all_elements_located())

	    driver.find_element(By.ID,"user_id").send_keys(USER_ID)
	    driver.find_element(By.ID,"password").send_keys(PASSWORD)
	    driver.find_element(By.ID,"login_button").click()
    
main()
```
# 原因
下記を読み込み待ちに利用していたこと。
``` py
wait.until(EC.presence_of_all_elements_located())
```
# 対処方法
読み込まれる必要がある要素の分だけ、下記を実行し、読み込み待ちを行う。
``` py
wait.until(EC.presence_of_element_located((By.ID,"hoge")))
```
## サンプルコード
``` diff_python:auto_login_修正.py
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

def main():
	LOGUIN_URL = 'https://hoge.hoge/login'
	USER_ID = "TestUser"
	PASSWORD = "TestPassword"

    with webdriver.Chrome() as driver:
        driver.maximize_window()
        driver.get(LOGUIN_URL)

	    # ログインページを読み込み終わるまで待つ。
	    wait = WebDriverWait(driver=driver,timeout=30)
-       wait.until(EC.presence_of_all_elements_located())
+       ELEMENT_IDS = ["user_id","password","login_button"]
+       for element_id in ELEMENT_IDS:
+           wait.until(EC.presence_of_element_located((By.ID,element_id)))

-       driver.find_element(By.ID,"user_id").send_keys(USER_ID)
-       driver.find_element(By.ID,"password").send_keys(PASSWORD)
-       driver.find_element(By.ID,"login_button").click()
+       driver.find_element(By.ID,ELEMENT_IDS[0]).send_keys(USER_ID)
+       driver.find_element(By.ID,ELEMENT_IDS[1]).send_keys(USER_ID)
+       driver.find_element(By.ID,ELEMENT_IDS[2]).click()

main()
```
# さいごに
本記事では、下記に示すコードで、処理に必要な要素の読み込みが終わるまで処理待ちをする方法を示した。
``` python
wait.until(EC.presence_of_element_located((By.ID,"hoge")))
```
## 備考
本記事は、「参考程度」と考えてほしい。
なぜなら、「サイトの作りによっては適切な方法が異なる」と思われるためである。
本記事で紹介した方法を、使わなくてもうまくいく場合と使ってもうまくいかない場合がある。
## TIPS
ページの読み込み待ちで、`time.sleep()`の利用は推奨しない。
理由は、以下の通りである。
- 指定した秒数以内で、処理に必要な要素の読み込みが終わらない場合、処理に失敗してしまう。
- 指定した秒数が長すぎると、不必要に処理時間が長くなる。
### サンプルコード
``` python
LOAD_WAIT_SECONDS = 1
time.sleep(LOAD_WAIT_SECONDS)
```
## 参考文献
https://www.seleniumqref.com/api/python/conditions/Python_presence_of_element_located.html

https://qiita.com/tomomi-kawashita/items/1a1e03d5ee590823b92e

https://www.teru2teru.com/python/selenium/do-not-time-sleep/

https://www.selenium.dev/ja/documentation/webdriver/interactions/windows/
[Hardware] 一覧表

# 一覧表
|名称|詳細|
|:--|:--|
|コイル|電流を一定に保つ|
|ダイオード|電流を一方向に流す|
|コンデンサ|電荷を蓄え放出する|
|抵抗器|電流を変化させる|
|インバータ|直流電力を交流電力に変換する|
|AC/DCコンバータ|交流電力を直流電力に変換する|

# 参考リンク
- [令和4秋21](https://www.ap-siken.com/kakomon/04_aki/q21.html)
OpenAI API Timeout処理の方法（2024/8/10現在）

## 概要
OpenAIでAPIリクエストを送っても，responseが得られずに固まってしまう現象に困っている方へ．

Timeout時間を設定し，一定時間返答がなければリクエストをやり直すことで回避できます．


## 環境
python=3.8
openai=1.38.0

## ChatCompletionのキホン
PythonでGPTを使いたければ次の型がキホンですね．
openaiライブラリのバージョンによって変わってくるので環境に注意です．
```python
from openai import OpenAI

client = OpenAI() #必要に応じてapi_keyなど設定

messages = [
                {"role": "system", "content": "You are helpful assistant."},
                {"role": "user", "content": "Hey ChatGPT, how are you?"}
]

response = self.client.chat.completions.create(
                        model = "gpt-4o",
                        messages=messages
                    )

response_text = response.choices[0].message.content
```

## タイムアウト処理の設定
タイムアウトは最初のクラスのインスタンスを定義するところで設定します．
エラー処理は，`openai.APITimeoutError`を用いるのに注意です．

```python
from openai import OpenAI
import httpx

client = OpenAI(api_key=api_key, timeout=httpx.Timeout(15.0, read=5.0, write=10.0, connect=3.0))

try:
    response = self.client.chat.completions.create(
        model = "gpt-4o",
        messages=messages
    )
    
except openai.APITimeoutError as e: #普通のTimeoutErrorではないことに注意
    print(e, flush=True)
```

httpx.Timeout の read, write, connect という引数は，HTTPリクエストの特定の段階におけるタイムアウトの制限時間を設定するものです．それぞれの数字は秒数を表しています．

- **read (読み込みタイムアウト)**: サーバーからのレスポンスデータを受け取る際の最大待機時間を秒単位で指定します．例えば，read=5.0 と設定すると，サーバーが5秒以内にレスポンスを送信しない場合，タイムアウトとしてリクエストが失敗します．
- **write (書き込みタイムアウト)**: クライアントからサーバーへデータを送信する際の最大待機時間を秒単位で指定します．例えば，write=10.0 と設定すると，データが10秒以内に送信されない場合，タイムアウトとしてリクエストが失敗します．
- **connect (接続タイムアウト)**: サーバーへの接続が確立されるまでの最大待機時間を秒単位で指定します．例えば，connect=3.0 と設定すると，サーバーへの接続が3秒以内に確立されない場合，タイムアウトとしてリクエストが失敗します．
python `operator.attrgetter` でオブジェクトの複数の属性を取得する

## はじめに
Pythonでオブジェクトの属性を取得する際、通常は直接 `object.attribute` のような形でアクセスします。しかし、複数の属性を動的に取得したい場合や、高階関数で属性を扱う場合には、`operator.attrgetter` が非常に便利です。この記事では、`operator.attrgetter` の使い方と、複数の属性を一度に取得する方法を紹介します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/6824dc5d-a18c-da15-3668-41af69f9b45d.png)

## `operator.attrgetter` とは

`operator.attrgetter` は、Pythonの標準ライブラリ `operator` モジュールに含まれる関数です。この関数は、指定された属性名（複数可）に基づいてオブジェクトから属性を取得するためのcallableオブジェクトを返します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/5bb0b419-2f7c-01d8-6633-5e3641398808.png)

## 基本的な使い方

まず、簡単な例から見ていきましょう。

```python
from operator import attrgetter

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

p = Person("Alice", 30)

# 単一の属性を取得
get_name = attrgetter('name')
print(get_name(p))  # 出力: Alice

# 複数の属性を取得
get_name_and_age = attrgetter('name', 'age')
print(get_name_and_age(p))  # 出力: ('Alice', 30)
```

実行結果:
```
Alice
('Alice', 30)
```

## 複数オブジェクトの属性を取得する

`attrgetter` は、リストやタプルなどの複数のオブジェクトに対しても使用できます。これは、`map` や `sorted` などの関数と組み合わせる際に特に便利です。

```python
people = [
    Person("Alice", 30),
    Person("Bob", 25),
    Person("Charlie", 35)
]

# 名前のリストを取得
names = list(map(attrgetter('name'), people))
print(names)  # 出力: ['Alice', 'Bob', 'Charlie']

# 年齢でソート
sorted_people = sorted(people, key=attrgetter('age'))
for person in sorted_people:
    print(f"{person.name}: {person.age}")
```

実行結果:
```
['Alice', 'Bob', 'Charlie']
Bob: 25
Alice: 30
Charlie: 35
```

## ネストされた属性の取得

`attrgetter` は、ドット記法を使用してネストされた属性にもアクセスできます。

```python
class Address:
    def __init__(self, city):
        self.city = city

class Person:
    def __init__(self, name, address):
        self.name = name
        self.address = address

p = Person("Alice", Address("Tokyo"))

get_city = attrgetter('address.city')
print(get_city(p))  # 出力: Tokyo
```

実行結果:
```
Tokyo
```

## まとめ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/63fb49bf-118b-fd97-1dc0-131ee5b7a55d.png)

`operator.attrgetter` は、Pythonでオブジェクトの属性を柔軟に取得するための強力なツールです。特に以下のような場面で活躍します：

1. 複数の属性を一度に取得したい場合
2. 属性名を動的に指定したい場合
3. `map`、`filter`、`sorted` などの高階関数と組み合わせて使用する場合
4. コードの可読性を高めたい場合

`attrgetter` を使いこなすことで、より簡潔で効率的なPythonコードを書くことができます。ぜひ、日々のプログラミングに取り入れてみてください。

## 参考情報

より詳細な情報や公式ドキュメントについては、以下のリンクを参照してください：

- [Python公式ドキュメント: operator.attrgetter](https://docs.python.org/ja/3/library/operator.html#operator.attrgetter)
- [Python公式ドキュメント: operator モジュール](https://docs.python.org/ja/3/library/operator.html)

これらの公式ドキュメントでは、`attrgetter` の詳細な使用方法や、`operator` モジュールに含まれる他の便利な関数についても解説されています。
【基礎から】PythonでExcel扱えるようにする (2) Excelファイルのデータ構造

### 目的
OpenPyxlで扱うExcelファイルのデータ構造を示す。

### データ構造図

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/176596/5ed2583d-4d18-f7be-63f5-1ef2fa146987.png)

### ワークブック(Workbook)
1) Pythonで扱っている間はRAM上にデータがある
2) 保存するときは、saveする
3) アクセスが終わったら、closeをする

### ワークシート(Worksheet)
1) 異なるファイルのシートにはアクセスできない
2) 新規作成時は、"sheet"という空のシートが１つ作成される

### セル(Cell)
1) 縦方向をrow, 横方向をcolumnで座標を示す
2) "A1"と(1,1)は同じ座標を指す
3) Cell内に属性を変更/更新することでデータが書き換わる

#
[本編へ戻る](https://qiita.com/YossyIto/items/ae822beb7350338e89fb)

### 履歴
2024/08/10 新規作成 

### リンク
[1] openpyxl 3.1.5
https://pypi.org/project/openpyxl/
[2] openpyxlでよく使う操作についてのまとめ
https://qiita.com/YukiYamam/items/d0e38921f5b51a950c40


### eof
PyOTPでAWS IAMのMFAを突破する

# はじめに
MFAについて調べている過程でPythonのPyOTPというライブラリを見つけました。PythonからOTP(ワンタイムパスワード)の6桁の数字を生成するものです。

https://github.com/pyauth/pyotp

これを使うとMicrosoft AuthenticatorやWinAuthなどを使うのと同じことがPythonでできることが分かりました。他のMFAにも利用できると思います。

OTP は RFC6238 という規格で標準化されている模様。 

https://tex2e.github.io/rfc-translater/html/rfc6238.html

# 準備

Pythonを実行できる環境が必要です。今回はEC2にPythonを入れて利用します。

https://qiita.com/talomina/items/20fd7f1575fe30f9f23a

PyOPTを利用するために必要なライブラリを用意します。

```bash:pyotpのインストール
sudo pip3 install pyotp
```

:::note
名前が似ていますがpyo**tp**とpyo**pt**は全くの別物です。
:::

# 手順

* マネコンからIAMのMFA設定のページへ行きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940466/682d9ee0-eed7-832f-45b7-1b92984e9bab.png)

* MFAデバイスは「認証アプリケーション」を選択して次へ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940466/f2e7c590-8a77-75b3-a63f-2d8f1f565503.png)

* デバイスの設定でQRコードではなく「シークレットキーを表示」を押すと出てくる64文字の英数字をメモします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940466/365e588e-8d48-c653-da37-8c3fd640daae.png)

:::note
シークレットキーはOTPの生成に必要な秘密情報であり、非常に重要なセキュリティ要素です。公開されるべきではなく、機密情報として扱う必要があります。
:::

* 上記でメモしたシークレットキーを```SECRET_KEY```と仮定して下記のようにPythonで実行することで、6桁のMFAコードを出力します。
```python:PyOTPで実行するプログラム。
# PyOTPライブラリのインポート
import pyotp

# SECRET_KEYを引数としてインスタンス生成
totp = pyotp.TOTP('SECRET_KEY')      

# SECRET_KEYに対応するワンタイムパスワードを生成
totp.now()
```

* 30秒後に再度Pythonコードを実行して2つのMFAコードをそれぞれマネコンで入力してMFAを追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940466/e99e3654-5134-8420-42a6-5cf194657278.png)

* 下記のようにメッセージが表示されれば登録OKです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940466/95ff51cf-6b3e-c6c4-2f48-6e09dafc48a7.png)

このプログラムでは、OTPの値は30秒ごとに更新されます。TOTP（Time-Based One-Time Password）アルゴリズムのデフォルト設定では、30秒のタイムステップを使用してOTPが生成されます。したがって、30秒ごとに新しいOTPが生成され、前のOTPは無効になります。

# ログインしてみる
設定したIAMユーザーでログインしてIDとパスワードを入力するとMFAコードが要求されるので、同じプログラムを実行して6桁のMFAコードを入力します。

# おわりに

物理的なOTP機器がインターネット通信もしないでMFAができることに「もやっ」としていたこれまでに比べて、OTPの仕組みが多少クリアになりました。

あまり実用的な用途が思い浮かびませんが、次のような条件が揃ったら選択肢に挙げてもよいかもです。
* スマホが持ち込めないような場所でMFAが必要
* 物理OTPデバイスも利用できない
* WinAuthも利用できない
【基礎から】PythonでExcel扱えるようにする


### 目的
一定の形式のテキストデータをエクセルに取り込み、閲覧できるようにする。

### 想定する対象者
1) 何かのプログラム言語を触ったことがある
2) データの整形作業に時間を使っていて、困っている

### 目的を達成するためのステップ
1) テキストファイルからデータを抽出する
2) 必要な部分のデータを整形する（不要な情報を間引く）
3) エクセルファイル上の対象セルにデータをコピーする
4) エクセルファイルを保存する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/176596/231c1cf5-5c22-04d5-7684-107269db0555.png)

#### 目的発見から達成までのステップ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/176596/119b621f-3d3c-a973-484e-80b0600d780e.png)


### 準備物
1) PC(Excelが編集できること)
2) めんどくさいという気持ち

### 導入とステップ
1) [Python環境の構築](https://qiita.com/YossyIto/items/ad4096bdbda25cc7d25f)
2) [Excelファイルのデータ構造](https://qiita.com/YossyIto/items/12b0aab54824a68950b6)
3) [セルへのアクセス](https://qiita.com/YossyIto/items/6e564f902b11c98c7510)
4) [テキストデータの読み込み](https://qiita.com/YossyIto/items/2c36152a91d70f9ab990)
5) [テキストデータの読み込み～エクセルに書き込み](https://qiita.com/YossyIto/items/c12607c2811e8554b3f4)

### リンク
[1] openpyxl 3.1.5
https://pypi.org/project/openpyxl/
[2] openpyxlでよく使う操作についてのまとめ
https://qiita.com/YukiYamam/items/d0e38921f5b51a950c40
[3] インストラクターのネタ帳:Python&OpenPyxl
https://www.relief.jp/Python/OpenPyXL/
[4] プログラマーの三大○○とは？入社一年目の社員がまとめてみた
https://note.com/msoft/n/naaf8a0e489f8
[5] Pythonでファイルの読み込み、書き込み（作成・追記）
https://note.nkmk.me/python-file-io-open-with/
[6] openpyxlのオートフィルタ設定のメモ
https://qiita.com/y-tetsu/items/bfb9960edf207559c7bc
[7] Excelを操作するPythonライブラリ簡易比較
https://qiita.com/mirutsu/items/b216cb7f3d0918285f49

### 履歴
2024/08/08 新規作成
2024/08/10 (2)(3)(4)(5)追加
2024/08/16 リンク追加、(1)追加

### eof
機能紹介：BigQuery continuous queries でリアルタイムデータ分析にコミット

こんにちは。codepoet です。

## はじめに

BigQuery の新機能としてリアルタイムでデータを分析できる「BigQuery continuous queries」がプレビュー版でリリースされました。本記事では、この継続クエリの概要や特徴、活用方法について解説します。

## 目次

1.  [リアルタイム分析を可能にするとは？](#リアルタイム分析を可能にするとは？)
2.  [継続クエリの特徴と制限事項](#継続クエリの特徴と制限事項)
3.  [継続クエリの活用例](#継続クエリの活用例)
4.  [まとめ](#まとめ)
5.  [参考文献](#参考文献)

## リアルタイム分析を可能にするとは？

BigQueryはこれまで、バッチ処理によるデータ分析が主でしたが、今回リリースされた「継続クエリ」は、**SQLステートメントを継続的に実行し、リアルタイムでデータを分析**できるようにする機能です。

例えば、ログデータが BigQuery に取り込まれると同時に分析したり、センサーデータの変化をリアルタイムで検出したりといったことが可能になります。これにより、従来のバッチ処理では難しかった **時系列データの分析や、リアルタイムでの意思決定の支援** ができるようになります。

## 継続クエリの特徴と制限事項

継続クエリは便利な機能ですが、いくつかの特徴と制限事項があります。

### 特徴

* **SQLクエリによる分析：** 継続クエリは通常の SQL クエリと同じように記述できます。習得済みの SQL を活用してリアルタイム分析を実現できます。
* **出力先の柔軟性：** 分析結果は BigQuery テーブルに挿入したり、Pub/Sub や Bigtable にエクスポートできます。分析結果を他のシステムと連携させることも可能です。
* **機械学習との連携：** 一部の BigQuery ML 関数や、Vertex AI モデルを呼び出すこともできます。リアルタイムのデータ分析と機械学習を組み合わせた高度な分析が可能です。

### 制限事項

* **JOIN や集計関数などの一部の機能は利用不可：** 現状では、JOIN や集計関数、ウィンドウ関数などの一部の機能は利用できません。
* **一部のクエリオペレータや DDL/DML/DCL ステートメントも利用不可：** 利用できるクエリオペレータや各種ステートメントが制限されています。
* **Enterprise edition 以上が必要：** 継続クエリを利用するには、BigQuery の Enterprise edition 以上の予約が必要です。
* **その他の制限事項：** 他にもいくつかの制限事項があります。詳細は後述の参考文献をご確認ください。

## 継続クエリの活用例

継続クエリは以下のようなユースケースで活用できます。

* **リアルタイムの異常検知：** センサーデータやログデータから異常をリアルタイムで検出し、アラートを発生させることができます。
* **パーソナライズドマーケティング：** 顧客とのやり取りデータをリアルタイムで分析し、パーソナライズされたメッセージを配信できます。
* **データストリーミング処理：** BigQuery に取り込まれたデータをリアルタイムで加工・変換し、別のシステムに連携させることができます。

## まとめ

継続クエリは、BigQuery の機能を大きく拡張する新機能です。リアルタイムでのデータ分析や、機械学習との連携など、活用方法は多岐にわたります。データ分析の可能性を広がることに期待しましょう。

## 参考文献

* [Introduction to continuous queries](https://cloud.google.com/bigquery/docs/continuous-queries-introduction)
ubuntu 24.04 LTSで自宅サーバー構築（NTPsecの設定）

<a href="https://px.a8.net/svt/ejp?a8mat=3ZDGSF+2SMFEY+CO4+60OXE" rel="nofollow">初期費用無料、月額990円から、高速・多機能・高安定レンタルサーバー『エックスサーバー』</a>
<amp-pixel src="https://www19.a8.net/0.gif?a8mat=3ZDGSF+2SMFEY+CO4+60OXE" layout="nodisplay"></amp-pixel>
NTP サーバーの構築
taisuke@ubuntuserver:~$ sudo apt -y install ntpsec
taisuke@ubuntuserver:~$ sudo vi /etc/ntpsec/ntp.conf
24行目#tos minclock 4 minsane 3
34行目デフォルト設定はコメントにして使用したい NTP サーバーを追記
#pool 0.ubuntu.pool.ntp.org iburst
#pool 1.ubuntu.pool.ntp.org iburst
#pool 2.ubuntu.pool.ntp.org iburst
#pool 3.ubuntu.pool.ntp.org iburst
#Use Ubuntu's ntp server as a fallback.
#server ntp.ubuntu.com
pool ntp.nict.jp iburst
taisuke@ubuntuserver:~$ sudo systemctl restart ntpsec
動作確認
taisuke@ubuntuserver:~$ sudo ntpq -p
ntp.nict.jpで時刻が設定されていればokです。
<a href="https://px.a8.net/svt/ejp?a8mat=3ZDGSF+2SMFEY+CO4+60OXE" rel="nofollow">初期費用無料、月額990円から、高速・多機能・高安定レンタルサーバー『エックスサーバー』</a>
<amp-pixel src="https://www19.a8.net/0.gif?a8mat=3ZDGSF+2SMFEY+CO4+60OXE" layout="nodisplay"></amp-pixel>
PHP8の変更点まとめ

## はじめに
PHP8とそれ以前の過去バージョンを比較して変更点をまとめました。

PHPのアップデート対応をするときに参考になると思うので、ご活用ください。

## 1. コンストラクタの変更
PHP5以前のバージョンでは、クラス名と同じ名前のメソッドがコンストラクタとして使われていました。PHP7以降では、__construct メソッドがコンストラクタとして標準化されています。

修正前:

```php
class MyClass {
    function MyClass() {
        // コンストラクタの処理
    }
}
```

修正後:

```php
class MyClass {
    function __construct() {
        // コンストラクタの処理
    }
}
```

## 2. mysql_* 関数の廃止
PHP7.0で mysql_* 関数は廃止され、代わりに mysqli_* または PDO（PHP Data Objects）が推奨されています。

修正前:

```php
$link = mysql_connect("localhost", "user", "password");
$result = mysql_query("SELECT * FROM table");
```

修正後:

```php
$link = mysqli_connect("localhost", "user", "password", "database");
$result = mysqli_query($link, "SELECT * FROM table");
```

または

```php
$pdo = new PDO('mysql:host=localhost;dbname=database', 'user', 'password');
$stmt = $pdo->query("SELECT * FROM table");
```

## 3. エラーレポートの変更
PHP7.0から、エラーレポートのデフォルト設定が変更され、より厳密になっています。これにより、一部のコードがエラーを発生させる可能性があります。例えば、以前は警告として処理されていたものが、例外としてスローされる場合があります。

修正前:

```php
ini_set('display_errors', 1);
error_reporting(E_ALL);
```

修正後:

エラーハンドリングの改善やログ設定を見直してください。

## 4. 型宣言の強化
PHP7.0以降、型宣言が強化され、より厳格な型チェックが行われるようになりました。関数の引数や戻り値に型宣言を追加する必要があります。

修正前:

```php
function add($a, $b) {
    return $a + $b;
}
```

修正後:

```php
function add(int $a, int $b): int {
    return $a + $b;
}
```

## 5. null 合体演算子の追加
PHP7.0から ?? 演算子（null 合体演算子）が追加されました。これにより、変数が存在するかどうかをチェックする簡潔な方法が提供されます。

修正前:

```php
$value = isset($array['key']) ? $array['key'] : 'default';
```

修正後:

```php
$value = $array['key'] ?? 'default';
```

## 6. is_null() 関数の動作変更
PHP7.0から、is_null() 関数は厳密に NULL かどうかをチェックします。変数が未定義でも NULL として扱われますが、より明確なコードを書くことが推奨されます。

修正前:

```php
if (is_null($variable)) {
    // 処理
}
```

修正後:

変数が存在するかどうかを先に確認することが推奨されます。

## 7. __toString() メソッドの変更
PHP7.0以降、__toString() メソッドは必ず文字列を返す必要があります。文字列以外の値を返すとエラーになります。

修正前:

```php
class MyClass {
    public function __toString() {
        return 123;  // 整数
    }
}
```

修正後:

```php
class MyClass {
    public function __toString() {
        return '123';  // 文字列
    }
}
```

## 8. call_user_func_array() の変更
PHP7.0では call_user_func_array() がより厳密に型チェックを行います。関数呼び出し時に引数の型が一致するように修正が必要です。

修正前:

```php
function test($a, $b) {
    return $a + $b;
}

call_user_func_array('test', [1, 2]);
```

修正後:

型宣言を追加し、引数の一致を確認します。

## 9. 名前付き引数のサポート
PHP8.0から名前付き引数がサポートされるようになりました。関数の引数を名前で指定することができますが、PHP7.xではサポートされていません。

PHP8.0以降:

```php
function greet($name, $age) {
    echo "Name: $name, Age: $age";
}
greet(age: 30, name: "John");
```

## 10. その他の変更
* デフォルトのエラーレベルの変更
* コンストラクタのインヘリタンスの動作変更
* 抽象メソッドとインターフェースの厳格化
* セッションハンドラの動作変更

これらの変更に対処することで、PHP8へのアップデート後もコードが正常に動作し、より良いパフォーマンスとセキュリティを確保できます。アップデート前にこれらの修正点を確認し、適切な対応を行うことが重要です。
pandasでCSVファイルを読み込み・書き込みする

# pandasでCSVファイルを読み込み・書き込みする

pandasでCSVファイルを読み込み・書き込みする方法をまとめました。

IrisデータセットのCSVファイルの読み込み・書き込みを例として解説します。

## CSVファイルを読み込む

pandasでCSVファイルを読み込むときは、`read_csv()`を使用します。

CSVファイルが置かれているパスを引数として渡すことで、CSVファイルを読み込むことができます。

下記はIrisデータセットのCSVファイルを読み込んで、CSVファイルの内容を確認しています。

```python
import pandas as pd

df = pd.read_csv('./iris-dataset.csv')
df.head()
```

```shell
        sepal_length            sepal_width         petal_length	         petal_width   species
0					5.1						3.5					1.4						0.2	setosa
1					4.9						3.0					1.4						0.2	setosa
2					4.7						3.2					1.3						0.2	setosa
3					4.6						3.1					1.5						0.2	setosa
4					5.0						3.6					1.4						0.2	setosa
```

## CSVファイルを書き込む

pandasでCSVファイルを書き込むときは、`to_csv()`を使用します。

CSVファイルの出力先のパスを引数として渡すことで、CSVファイルを書き込むことができます。

新規で書き込む場合は、パスに指定したCSVファイル名でCSVファイルが作成されます。

既に同名のCSVファイルが存在する場合は、新たに書き込んだ内容が上書きされます。

下記はIrisデータセット内のラベルを抽出して、新規のCSVファイルに書き込み、書き込んだ内容を確認しています。

```python
labels = df.loc[:,'species']
labels.head()
```

```shell
0    setosa
1    setosa
2    setosa
3    setosa
4    setosa
Name: species, dtype: object
```

```python
labels.to_csv("./iris-labels.csv")

df = pd.read_csv('./iris-labels.csv')
df.head()
```

```shell
              Unnamed: 0   species
0					0		setosa
1					1		setosa
2					2		setosa
3					3		setosa
4					4		setosa
```

## 参考

* [PandasでCSVファイルを読み書き | DATUM STUDIO株式会社](https://datumstudio.jp/blog/pandasでcsvファイルを読み書き/)
* [Irisデータセットのダウンロード | Excel VBAでIris分類問題](https://liclog.net/excel-vba-deeplearning-iris-download/)
* [pandasで任意の位置の値を取得・変更するat, iat, loc, iloc](https://note.nkmk.me/python-pandas-at-iat-loc-iloc/)
Pandasでobject型の文字列内の記号・特殊文字を置換する

# Pandasでobject型の文字列内の記号・特殊文字を置換する

Pandasでは文字列内に記号や特殊文字が混在していると、その文字列のデータ型が`str`型ではなく`object`型として扱われることがあります。

```python
import pandas as pd

prices = ['$14,983.17','$15,321.76','$13,568.23']
df = pd.DataFrame(data=prices)
df
	0
0	$14,983.17
1	$15,321.76
2	$13,568.23

df.dtypes
0    object
dtype: object
```

`object`型の文字列内の記号や特殊文字を置換する場合は、`replace`メソッドに`regex=True`を指定し、置換する記号・特殊文字を正規表現として指定します。

```python
df = df.replace({'\$': '', ',': ''},regex=True)
df
	0
0	14983.17
1	15321.76
2	13568.23
```

## 参考

* [pandasのデータ型dtype一覧とastypeによる変換（キャスト）](https://note.nkmk.me/python-pandas-dtype-astype/)
* [Pandasで値を置換するreplace関数の使い方](https://deepage.net/features/pandas-replace.html)
* [PythonPandasDataFrameの一括置き換えreplaceができな... - Yahoo!知恵袋](https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q14268433589)
* [［Python］replaceを使った文字列置換の徹底解説](https://www.fenet.jp/dotnet/column/language/7276/)
* [Pandas DataFrameを徹底解説！(作成、行・列の追加と削除](https://ai-inter1.com/pandas-dataframe_basic/)
KerasのInput Shape・Output Shape・Paramの形状

# KerasのInput Shape・Output Shape・Paramの形状

KerasのInput Shape・Output Shape・Paramの各形状についてまとめました。

```python
import tensorflow as tf

model = tf.keras.Sequential()
model.add(tf.keras.layers.Dense(units=9, activation='relu'))
model.add(tf.keras.layers.Dense(units=18, activation='relu'))

model.build(input_shape=(None, 3))
model.summary()
```

```shell
Model: "sequential"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 dense (Dense)               (None, 9)                 36        
                                                                 
 dense_1 (Dense)             (None, 18)                180       
                                                                 
=================================================================
Total params: 216
Trainable params: 216
Non-trainable params: 0
```

## Input Shape

Input Shapeとは入力形状のことで、`（バッチサイズ, 入力ユニットの個数）`という形式になります。

```python
input_shape=(None, 3)
```

任意のバッチサイズを使う場合は`None`を指定します。

入力ユニットの個数は、説明変数の個数となります。

## Output Shape

Output Shapeとは出力形状のことで、`（バッチサイズ, 出力ユニットの個数）`という形式になります。

```python
(None, 9)
```

任意のバッチサイズである場合は、バッチサイズは`None`となります。

出力ユニットの個数は、目的変数の個数となります。

## Param

Paramとはパラメータのことで、`ユニット数×入力数+バイアス`という計算でパラメータ数が求められます。

### 各層のパラメータ数

#### 1つ目の層

```python
dense (Dense)               (None, 9)                 36
```

1つ目の層は、

* 9個のユニット
* 3個の入力
* 9個のバイアス

なので、`9 × 3 + 9 = 36`で36個のパラメータが求められます。

#### 2つ目の層

```python
dense_1 (Dense)             (None, 18)                180
```

2つ目の層は、

* 18個のユニット
* 9個の入力
* 18個のバイアス

なので、`18 × 9 + 18 = 180`で180個のパラメータが求められます。

## 参考

* [［第3版］Python機械学習プログラミング 達人データサイエンティストによる理論と実践 impress top gearシリーズ | Sebastian Raschka, Vahid Mirjalili, 株式会社クイープ, 福島 真太朗 | 工学 | Kindleストア | Amazon](https://www.amazon.co.jp/%EF%BC%BB%E7%AC%AC3%E7%89%88%EF%BC%BDPython%E6%A9%9F%E6%A2%B0%E5%AD%A6%E7%BF%92%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0-%E9%81%94%E4%BA%BA%E3%83%87%E3%83%BC%E3%82%BF%E3%82%B5%E3%82%A4%E3%82%A8%E3%83%B3%E3%83%86%E3%82%A3%E3%82%B9%E3%83%88%E3%81%AB%E3%82%88%E3%82%8B%E7%90%86%E8%AB%96%E3%81%A8%E5%AE%9F%E8%B7%B5-impress-top-gear%E3%82%B7%E3%83%AA%E3%83%BC%E3%82%BA-ebook/dp/B08LYWFPQ9/ref=sr_1_5?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=2VO11THRH3PPY&keywords=%E6%A9%9F%E6%A2%B0%E5%AD%A6%E7%BF%92&qid=1650856431&sprefix=%E6%A9%9F%E6%A2%B0%E5%AD%A6%E7%BF%92%2Caps%2C238&sr=8-5)
NumPy配列がTensorに変換されないときの対処方法

# NumPy配列がTensorに変換されないときの対処方法

NumPy配列をTensorに変換する際に、下記のような変換エラーが出ることがあります。

```shell
ValueError: Failed to convert a NumPy array to a Tensor (Unsupported object type int)
```

このエラーは、NumPy配列のデータ型が数値型ではなく、`objects`である場合に発生します。

```python
inputs.dtype
```

```shell
dtype('O')
```

NumPy配列には、数値型以外のデータも含まれることがあるので、データ型が`objects`になることがあります。

**このエラーは、NumPy配列を数値型に事前変換することで解決します。**

```python
inputs = inputs.astype(np.float32)
inputs.dtype
```

```shell
dtype('float32')
```

## 参考

* [Numpy配列→Tensor変換時のエラー "ValueError: Failed to convert a NumPy array to a Tensor （Unsupported ..."](https://teratail.com/questions/297753)
* [NumPyのデータ型dtype一覧とastypeによる変換（キャスト） | note.nkmk.me](https://note.nkmk.me/python-numpy-dtype-astype/)
* [【NumPy入門 np.dtype】 配列要素の型を確認・指定してみよう | 侍エンジニアブログ](https://www.sejuku.net/blog/71841)
* [python — dtype（ 'O'）とは何ですか？](https://www.web-dev-qa-db-ja.com/ja/python/dtype%EF%BC%88-%27o%27%EF%BC%89%E3%81%A8%E3%81%AF%E4%BD%95%E3%81%A7%E3%81%99%E3%81%8B%EF%BC%9F/826401703/)
MinIOでS3互換のファイルストレージプラットフォームを構築する方法

こんばんは。

今日は「MinIOでS3互換のファイルストレージプラットフォームを構築する方法」について説明します。

MinioはAWS S3と互換性のあるオブジェクトストレージソリューションで、AWS S3 APIを使用してローカルまたはクラウド環境に独自のオブジェクトストレージサービスを構築できます。MinioをAWS S3と一緒に使用したり、ローカル環境にMinioサーバーをインストールして独自のS3互換オブジェクトストレージを構築する方法について説明します。

# Minioのインストールと設定方法

## Minioサーバーのインストール
Minioサーバーはさまざまなプラットフォームで使用でき、以下の方法でインストールできます。

Linux/Unixの場合:
```
wget https://dl.min.io/server/minio/release/linux-amd64/minio
chmod +x minio
sudo mv minio /usr/local/bin/
```

## Minioサーバーの起動
Minioサーバーを起動するには、次のコマンドを使用してデータディレクトリを指定し、実行します。

```terminal
minio server /data
```

このコマンドは、/dataディレクトリを使用してMinioサーバーを起動します。他のパスを指定することもできます。

# Minioウェブコンソールへのアクセス
Minioサーバーを起動した後、デフォルトではhttp://127.0.0.1:9000 からウェブコンソールにアクセスできます。ここでユーザー名とパスワードを設定できます。デフォルトでは以下の環境変数を使用して設定します。

```bash
export MINIO_ROOT_USER=<Your-Access-Key>
export MINIO_ROOT_PASSWORD=<Your-Secret-Key>
minio server /data
```

## Minioクライアントのインストールと設定
Minioクライアント(mc)は、S3互換APIを使用してMinioサーバーにアクセスしたり、AWS S3と連携するためのツールです。インストール方法は以下の通りです。

Linux/Unixの場合:

```bash
wget https://dl.min.io/client/mc/release/linux-amd64/mc
chmod +x mc
sudo mv mc /usr/local/bin/
```

# Minioクライアントの設定
Minioクライアントを設定して、Minioサーバーに接続したり、AWS S3に接続できます。

```bash
mc alias set myminio http://127.0.0.1:9000 <Your-Access-Key> <Your-Secret-Key>
```

上記のコマンドで、myminioというエイリアスを使用してMinioサーバーに接続できます。AWS S3に接続する場合は、次のように設定します。

```bash
mc alias set s3 https://s3.amazonaws.com <Your-Access-Key> <Your-Secret-Key>
```

## MinioとAWS S3の使用
Minioクライアントを使用してファイルをアップロード、ダウンロードしたり、バケットを管理できます。

ファイルのアップロード:
```bash
mc cp myfile.txt myminio/mybucket
```
ファイルのダウンロード:
```bash
mc cp myminio/mybucket/myfile.txt .
```
バケットの作成:
```bash
mc mb myminio/mybucket
```

## 高可用性Minioクラスタの構築 (オプション)
Minioは高可用性(HA)クラスタとして設定できます。複数のサーバーでMinioインスタンスを実行し、それぞれが同じデータにアクセスするように設定することで高可用性を実現できます。

例えば、4つのディスクを使用する4ノードクラスタを設定するには、次のようにコマンドを実行します。

```bash
minio server http://host{1...4}/mnt/data{1...4}
```

このコマンドは、4つのホストでMinioをクラスタリングし、各ホストの4つのデータディレクトリを使用します。

# まとめ
Minioは簡単にインストールでき、AWS S3との互換性を提供することで、さまざまなクラウドやオンプレミス環境で使用できます。Minioを活用してS3互換ストレージを構築することで、さまざまなアプリケーションとの統合が可能になり、高可用性クラスタリングを通じて安定したサービス提供も実現できます。

今日は以上です。

ありがとうございました。
よろしくお願いいたします。
[Break-Even Analytics] 損益分析について

# 計算式
||式1|式2|
|:--|:-:|:-:|
|損益分岐点売上高|固定費/(1-変動比率)|固定費/(1-変動費/売上高)|
|利益|売上高-固定費-変動費|売上高-固定費-(売上高*変動費率)|
|限界利益|売上高-変動費||
|限界利益率|限界利益/売上高|1-変動費率|

# 参考リンク
- [令和3秋77](https://www.ap-siken.com/kakomon/03_aki/q77.html)
- [令和元秋77](https://www.ap-siken.com/kakomon/01_aki/q77.html)
VertiTab - サイドパネルの縦型タブ v2.0.0

拡張機能の名前が「Colorful Side Panel Tabs」から**「VertiTab - Side Panel Vertical Tabs」**に正式に変更され、バージョンが2.0.0に更新されたことをお知らせします。

https://chromewebstore.google.com/detail/vertitab-%E3%82%B5%E3%82%A4%E3%83%89%E3%83%91%E3%83%8D%E3%83%AB%E3%81%AE%E7%B8%A6%E5%9E%8B%E3%82%BF%E3%83%96/chejfhdknideagdnddjpgamkchefjhoi?hl=ja

新しい名前、同じ素晴らしい体験！

拡張機能の機能とビジョンをよりよく反映するために、「VertiTab - Side Panel Vertical Tabs」に名前を変更しました。

究極の垂直タブ管理拡張機能をお探しですか？もう探す必要はありません！経験豊富な垂直タブユーザーでも、初心者でも、これがあなたにとって完璧なソリューションです。

主な機能:
- タブ管理
  - サムネイルプレビュー: 各タブの内容を簡単に確認し、必要なページをすばやく見つけることができます。
  - 豊富なソートと表示オプション: タブの配置をカスタマイズして生産性を向上させます。
  - 包括的なアクションメニュー: タブを管理し、混雑を減らすためのさまざまなアクションにアクセスできます。

- カスタマイズ可能なインターフェースレイアウト
  - インターフェースのレイアウトをニーズに合わせて配置し、個別のブラウジング体験を作成します。

- パーソナライズオプション
  - カラフルな背景、背景画像などを追加して、サイドバーをユニークにし、視覚体験を向上させます。

- 検索機能
  - 最近閉じたタブや閲覧履歴を簡単に検索して、必要なものをすばやく見つけ、時間を節約します。

- ピクチャーインピクチャーモード
  - タブを切り替えたりスクロールしたりすると、自動的にピクチャーインピクチャーモードに入り、シームレスなブラウジング体験を提供し、マルチタスクの能力を向上させます。

- 再生進行バー
  - 早送り、巻き戻し、音量調整、再生速度調整などのオプションでビデオ再生を制御し、視聴体験を向上させます。

- 読書進行バー
  - 読書の進行状況をリアルタイムで追跡し、どれだけのコンテンツをカバーしたかを理解し、読書時間をよりよく管理します。

- スナップショット機能
  - ブラウザを閉じる前に、ワンクリックでブラウザタブのスナップショットを保存します。最大50個のスナップショットを保存でき、重要なコンテンツが失われることはありません。

- 強化されたボトムナビゲーションバー
  - ブックマーク、履歴、最近閉じたタブ、読書リスト、クイックアクセス、新しいタブ、スナップショットの作成、検索、グループの折りたたみなど、ボトムナビゲーションバーからより多くの機能にアクセスできます。詳細についてはオプションページを確認し、操作の利便性を向上させます。

- クイックアクセス
  - よく使用するタブをクイックアクセスにピン留めします。右クリックして「クイックアクセスにピン留め」を選択すると、簡単に見つけることができ、不要になったらピン留めを解除して効率を高めます。

- サイト設定
  - 特定のサイトに対してリンクが現在のタブまたは新しいタブで開くかどうかを制御するなどのルールを設定し、ブラウジング体験を向上させます。

- パフォーマンスオプション
  - 新しいパフォーマンス設定により、ブラウジング体験が最適化され、スムーズなブラウザ操作が保証されます。

- インポート/エクスポート機能
  - デバイス間でのタブ管理を改善するためのインポートおよびエクスポートオプションが向上し、データ移行を容易にします。

プライバシーポリシー:
- VertiTabは、適切な操作を確保するために必要なすべてのデータをユーザーのデバイスに保持し、外部にデータを送信しないため、ユーザーのプライバシーを保護します。

権限:
- tabs: ブラウザタブを管理および操作します。
- tabGroups: タブグループを管理および操作します。
- sidePanel: サイドバーを管理および操作します。
- alarms: スケジュールされたタスク（タブの閉鎖や破棄など）を設定および管理します。
- readingList: 読書リストを管理および操作します。
- cookies: タブのウェブサイトからクッキーをクリアします。
- storage: ローカルストレージを管理および操作します。
- favicon: ウェブサイトのアイコンを取得して表示します。

オプションの権限:
- history: 閲覧履歴にアクセスして管理します。
- search: ブラウザの検索機能にアクセスして管理します。
- bookmarks: ブックマークにアクセスして管理します。

VertiTab - 垂直サイドバータブマネージャーをインストールして、効率的で個別のブラウジング体験を楽しみ始めましょう！ブラウザタブの管理を改善し、仕事とエンターテインメントの効率を向上させます。
ろうとるがPythonを扱う、、（その25：tkinterでいろいろ）

# まとめてトライ
tkinter上で、下記事項をまとめて実施した記録。
- ドラッグ＆ドロップ
- ２つのファイルDiff（差分）
- HTML表示 

任意のファイル２つをtkinterで作成されたWindowにドラッグ＆ドロップし、その差分（HTML with CSS）をWindowに表示するものである。

## 最初に結果
サンプル１。
![Diff1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/55058ee2-2aff-4fb4-ab21-f938252e7b1c.png)

サンプル２。
![Diff2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/bbf8143a-e4f2-7b5a-8c5a-13fa3e1e5d68.png)

difflibで出力されるHTML(with CSS)形式を、tkinterwebを使って表示する。

## ソースコード＋解説
```python
import os
import difflib                   # HTML形式のdiff出力用
import tkinter as tk
import tkinterdnd2 as tkdnd      # tkinter上でDrag&Drop利用
from tkinterweb import HtmlFrame # HTMLをtkinter作成Windowに表示用

def DiffDisplay(event):                    # Drag&Drop時にCallされる関数
    if event.data:
        frame.load_html("<html></html>")   # 表示をHTMLにて空にする
        file1_path = event.data.split()[0] # 1番目ファイルのPath取得
        file2_path = event.data.split()[1] # 2番目ファイルのPath取得（3番目以降は無視）
        file1 = open(file1_path)           # 1番目ファイルOpen
        file2 = open(file2_path)           # 2番目ファイルOpen
        diff = difflib.HtmlDiff()          # difflibによりHTML(with CSS)形式のdiff出力
        cur_path = os.getcwd()             # 起動ディレクトリ取得
        output_name = 'diff.html'          # 結果ファイル
        output_path = os.path.join(cur_path, output_name) # 結果ファイルのPath作成
        output = open(output_path, 'w')    # 結果ファイルOpen
        output.writelines(diff.make_file(file1, file2))   # 結果ファイルへHTML書き出し
        file1.close()                      # 1番目ファイルClose
        file2.close()                      # 2番目ファイルClose
        output.close()                     # 結果ファイルClose
        root.title('Diff: ' + file1_path + '    ' + file2_path) # Windowタイトルにファイル名を入れる
        frame.load_file(output_path)       # 結果ファイルHTMLをWindowに表示
    return event.action

#####  Main  ######
root = tkdnd.TkinterDnD.Tk()               # Drag&Drag用の設定
root.drop_target_register(tkdnd.DND_FILES) # Drag&Drag用の設定
root.title("Diff 2 Files")                 # Windowタイトル（初期値）
root.geometry("800x400")                   # Windowサイズ
root.dnd_bind('<<Drop>>', DiffDisplay)     # Drag&Dragが行われたときにCallされる関数（DiffDisplay）の定義

frame = HtmlFrame(master=root, horizontal_scrollbar="auto", messages_enabled = False) # WindowをHTMLフレーム対応とする（横スクロールバー付き、縦スクロールは自動的に対応する様子）
frame.pack()                               # フレーム表示

root.mainloop()
```
なお、ファイルが１つしかDrag&Dropされなかったときの状況などのエラー処理は考慮していない。

EOF
NextjsのLayoutでスクロール位置を保持する。

## 概要
nextjsのlayout下でページ遷移を行う際、Layoutの再レンダリングは行われませんが、画面のスクロール位置はリセットされてしまうようです。Layout下でモーダルウィンドウを用いて一時的な情報を画面上に表示したい際の解決策を紹介します。

## 解決策
Layout.tsx上でスクロール位置を保持し、ページ遷移（URL変化）を検知したらスクロール位置を戻す実装を行うことで解決できそうです。
(スクロール位置をwindow.scrollYが持っているか、document.scrollingElement.scrollTopが持っているかで若干実装が異なります。)

```ts:./Layout.tsx(documentのエレメントがスクロールする場合)

export default function Layout({
    children,
}: {
    children: ReactNode;
}) {
    const pathname = usePathname();
    const [scrollPosition, setScrollPosition] = useState(0);

    const handleScroll = () => {
        setScrollPosition(document.scrollingElement.scrollTop);
        console.log(document.scrollingElement.scrollTop);
    };

    // 初期化
    useEffect(() => {
        // イベント登録
        document.addEventListener('scroll', handleScroll);

        // イベント解除
        return () => {
            document.removeEventListener('scroll', handleScroll);
        };
    }, []);

    // ページ遷移時
    useEffect(() => {
        console.log(pathname);
        document.scrollingElement.scrollTop = scrollPosition;
    }, [pathname]);

    return (
        <>
            {children}
        </>
    );

```

```ts:./modal/page.tsx

export default function Modal() {
    return (
        <>
            popup
        </>
    );

```
【Python・Java】ABC365E の解説 PDF

# 問題文
https://atcoder.jp/contests/abc365/tasks/abc365_e

# 解説
こちらから解説 PDF を入手できます。
https://github.com/NAVYSHUNTA/ABC365-E/blob/main/main.pdf

# 余談
当初は非公開でしたが、評判が良かったので公開しました。
理解を深める一助となれば幸いです。
MacのSimulatorで現在地を設定する

## はじめに
表題通り、MacのSimulatorで現在地を設定する方法を紹介します。
Simulatorだと現在地が取得できず、海外の場所を設定されたりします。現在地をもとに設定できないと検証が実施しにくくなるため、Simulatorで現在地を設定するケースがあります。

## Simulatorより現在地を設定する
Simulatorの上部のメニューバーから「Features」→「Location」を選択する。
![スクリーンショット 2024-08-10 10.40.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599049/4f8133b1-29f3-1eff-463a-406082cb40ea.png)

緯度、経度を設定する
![スクリーンショット 2024-08-10 10.41.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599049/f3dfe0f6-75bd-52d1-5946-a4cfc81ba033.png)
FLUX.1-schnell 6枚 バッチだと 3倍速いな

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54688/a4913d04-ef2a-3718-ff06-7bdcaf80db66.png)
https://huggingface.co/black-forest-labs

改造して公開している120秒版
https://huggingface.co/spaces/Akjava/FLUX.1-schnell-120sec

```
pipe.enable_sequential_cpu_offload() 
```
をしないとVRAM 16GBでは動かなかった。

## 1024x1024 １枚づつ作成
HuggingSpaceのコードそのままだとA4000の場合
```
合計 16枚の画像の生成と保存にかかった時間: 639.81秒
```

```
#@spaces.GPU(duration=120)
def infer(prompt, seed=42, randomize_seed=False, width=1024, height=1024, num_inference_steps=4,guidance_scale=0):
    
    if randomize_seed:
        seed = random.randint(0, MAX_SEED)
    generator = torch.Generator().manual_seed(seed)
    image = pipe(
            prompt = prompt, 
            width = width,
            height = height,
            num_inference_steps = num_inference_steps, 
            generator = generator,
            guidance_scale=guidance_scale
    ).images[0] 
    return image, seed

```

## 1024x1024 6枚づつ作成
8枚だとメモリー不足、偶数にしたかったので６枚
```
合計 48枚の画像の生成と保存にかかった時間: 668.82秒
```

```
#@spaces.GPU(duration=120)
def infer(prompt, seed=42, randomize_seed=False, width=1024, height=1024, num_inference_steps=4,guidance_scale=0,batch_size=1,seed_change=1000):
        
    if randomize_seed:
        seed = random.randint(0, MAX_SEED)
    generators = [torch.Generator(device).manual_seed(seed + j*args.seed_change) for j in range(batch_size)]
     
    output = pipe(
            prompt = prompt, 
            width = width,
            height = height,
            num_inference_steps = num_inference_steps, 
            generator = generators,
            guidance_scale=guidance_scale,num_images_per_prompt=batch_size
    )
    seed += seed_change*batch_size
    return output.images, seed
```
## 作ってみたい
試してみたら、256x256でも、そこそこいいのが出来るので、バッチでまとめて作って保存できるみたいなDemoを作ってみたい
OSSへの貢献/初めてのマージリクエスト

いつもはプロダクトとかOSSとかツールなど主に利用方法について記載していることが多いのですが、たまには毛色の違う話で初めてOSS（オープンソースソフトウェア）で、プルリクエストをマージしていただいた事についてお話ししたいと思います。

# 1. そもそもの発端 ～ 業務で利用していたOSS製品に興味を持ち始めて
Apache Guacamole(OSS)を社内で利用しておりました。社内のApcahce Guacamoleはデータベースへの接続を必要とする構成にしていてDBはMariaDBを使用し接続はSSL化して利用しましょうという話でまとまっていたのですが、いざ構成してみると残念ながらその時点ではMariaDB Connector/Jを使用したSSL接続はうまく機能しなかったというわけです。

そのまま放置するわけにもいかないため、SSL化を目指しソースコードの調査・改修を行い無事SSL接続もでき、問題は解決したのですが「せっかくならプロジェクトに貢献したい！」とおもい思い切ってApache Guacamoleプロジェクトへアクションをとったのが事の発端となります。


*Apache Guacamole公式ページ*

https://guacamole.apache.org/


# 2. OSS/プルリクエスト
OSSに貢献することは、単にバグを修正したり新機能を追加したりするだけではなく、自分のアイデアやコードがプロジェクトの一部となり、世界中のユーザーに役立つ事となります。また、OSSに貢献することで、他の開発者と協力し合い、自分のスキルを磨くチャンスです！

そんな素敵なチャンスをくれるプルリクエスト。自分の修正や追加機能を他の開発者に提案し、その内容が承認されれば、公式のプロジェクトに統合されます。プルリクエストは、自分の変更をコードレビューの形で他の開発者に見ていただき、フィードバックをもらうプロセスでもあります。（滅茶苦茶緊張しますね。）


# 3. プルリクエストを送るまでのステップ
ここからは実際に私がApache Guacamoleで行ったステップについてとなります。GuacamoleはApache Software Foundation(ASF)プロジェクトの一つであり、ASF管理のプロジェクトはGithub上にIssuesタブがなく、Jiraで管理しています。よってまずはJiraのチケットを起票するところから始める形になります。

:::note info
Jira（ジラ）はアトラシアンが開発したソフトウェア。主にバグトラッキングや課題管理、プロジェクト管理に用いられます。
:::

登録は以下ページより実施可能です。

https://issues.apache.org/jira/secure/ForgotLoginDetails.jspa

## 問題の報告と解決策の考案
Jiraに現状の不具合を報告。具体的には、上記で記載している問題(MariaDB Connector/Jを使用したGuacamoleとデータベース間のSSL接続不可)について記載しています。

**jiraの画面**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2335933/1e7a966c-7f58-e7f8-164a-e8ca7a281894.png)
また、以下の内容もチケットに記載しています。
- 確認したところ、MariaDB Connector/Jのデフォルト設定ではuseSsl = falseになっており、これに起因した事象であること
- MySQL Connector/Jを使った場合、SSL接続はうまく機能している
- 上記内容からソースコードの改修が必要であること
- 修正後のコードで解消した旨の報告

Jiraチケットの詳細は以下から確認できます。

https://issues.apache.org/jira/browse/GUACAMOLE-1453

## プルリクエストの提出
プルリクエストの前にプロジェクトページからForkし、修正をかけたものをプルリクエストします。

以下のページを参考にさせていただきました。

https://qiita.com/y-vectorfield/items/b955617712f3b66359f2

また、Jiraのチケット番号を基にプルリクエストを作成しています。プルリクエストを挙げた旨、Jiraチケットにも連携しています。

**プルリクエストの内容**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2335933/f56b0347-97c0-006d-47ff-c165024f7b56.png)

プルリクエストの詳細は下記から確認できます。

https://github.com/apache/guacamole-client/pull/650

## レビューとマージ
他の開発者からレビューが返ってきます。数回のやり取りを経て、最終的に修正が承認されプロジェクトにマージされました。（感無量です！）

# 4. 感想
非常に小さな修正でしたし、その割に何度もやり取りをすることになりました。またすべて英語でのやり取りであるため正直英語ダメダメな私でありますが、そこはGoogle翻訳さんをフル活用で何とかという具合だったため、時間的にはそれなりにかかった思います。

それでも大きな一歩につながった出来事であったことは疑いようがない事実でして、これ以降、他のプロジェクトにも僅かではありますが、プルリクエスト/マージをいただく機会を得ることができました。

また、プロジェクト公式ページに表示されるのは非常に光栄です！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2335933/99800120-8f9b-8fe7-2226-3cefa6d82b6a.png)

これからも色々なプロジェクトにかかわっていきたいと思います。

# 5. その他
この記事が、同じようにOSSに挑戦しようとしている方々のお役に立てれば幸いです。
[Memory Management] 実記憶管理と仮想記憶管理について

# 主(実)記憶管理
|||
|:--|:--|
|実アドレス|主記憶装置が作る記憶空間|
|発生する課題||
|フラグメンテーション|記憶領域の中に使用されていない領域の断片が多く存在する状態|
||||
||||


# 仮想記憶管理
|||
|:--|:--|
|仮想記憶方式|補助記憶(装置)を利用して、主記憶のみの容量を超えたアドレス空間を作る|
|動的アドレス変換<br>DAT|仮想アドレス(補助記憶)から実アドレス(主記憶)への変換を行う|

## 仮想記憶の実現手法
|||
|:--|:--|
|ページング方式|プログラムをページ（固定長）で分割・変換する|
|セグメンテーション方式|プログラムをセグメント（可変長）で分割・変換する|
|ページフォールト|プログラム実行中、処理に必要なページが主記憶に存在しない状態|
|ページイン|補助記憶の必要なページを主記憶に読み込む|
|ページアウト|主記憶の不要なページを補助記憶に追い出す|
|デマンドページング|ページフォルト発生→ページイン実施|
|プリページング|必要なページを予想→ページイン実施|
|発生する課題||
|スラッシング|①ページイン/ページアウトが多発し<br>②プログラムのCPU時間低下<br>③システムのスループットが低下する|
|フラグメンテーション|記憶領域の中に使用されていない領域の断片が多く存在する状態<br>- ページンング方式: 起きない<br>- セグメンテーション方式: 起きる|

# Appendix
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2955010/190f50d7-512d-1515-c767-ed919c2eff9c.png)

# 参考リンク
- [R3A16_ページング方式の仮想記憶](https://www.ap-siken.com/kakomon/03_aki/q16.html)
- [R2A18_プリページング](https://www.ap-siken.com/kakomon/02_aki/q18.html)
- [R1A18_ページフォルトの順番](https://www.fe-siken.com/kakomon/20_aki/q27.html)
- [R3S19_ページフォルトの頻度](https://www.ap-siken.com/kakomon/03_haru/q19.html)
- [R3S17_ガーベジコレクション](https://www.ap-siken.com/kakomon/24_aki/q17.html)
- [イメージで覚える！仮想記憶、ページング方式とは](https://kouoboe.com/2023/07/07/kasoukioku/)
DiscordのBANシステムについて

こんにちは、りょうです。
今回はDiscordのBANシステムについていろいろ書いていきます。
それではれっつごーー👍

## DiscordのBANシステム
Discordにはユーザーをサーバーに入れないようにするための**BAN**と呼ばれるものがあります。
荒らしであったり、迷惑な人などを追放するのによく使われる機能ですね。

## BANの上限について
**サーバー内のユーザーのBAN** →無制限
**サーバー外のユーザーのBAN** →まとめてやると200人まで

200人を超えてしまうとこいつが返ってきて止まるので、botでBANを行う際は注意してください。
時間を置くとまたできるようになります

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3818367/e9ef72af-e591-2c8d-fecc-10e513e01284.png)

## BANの方法
BANしたいユーザーの名前を長押しするとこれが出てくるので**BAN**を押してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3818367/57d0c500-c3ce-27a1-2ebf-4b51b020b816.png)

するとこのようなものが表示されるはずなので、選択、記入をしてBANボタンを押せば完了です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3818367/0fa6bdc3-cb18-1fce-47b7-b62f670a8071.png)

- - - - - - - - - - - - - - -
コマンドを使った方法も紹介しておきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3818367/0724d061-d068-cf03-a2bf-217ec96eac2f.png)

各部解説をします。

**user**
この部分にはBANするユーザーのメンションか、IDを入力します。
IDの取得方法については以前に書いているので[こちら](https://qiita.com/ryo_001339/items/10379e7e108a9f797e5e)を参考にしてもらえればいいと思います。

:::note warn
ここに書いてるような名前やユーザー名を入れてもBANは実行できないので注意
:::
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3818367/40545239-c8f7-e018-86a7-16ca12bdb074.png)

**delete_messages**
この部分は選択式になっていて、BANするユーザーのメッセージをどこまで消すかを選びます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3818367/da3b3d05-0802-73ac-3dbb-6c8dea68e185.png)

**reason**
ここはBAN理由を記入する場所です。
ログなどに残す場合に書いてあったほうがわかりやすいですが、任意です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3818367/c6479d58-dc89-207e-03f7-6c753c10b0a0.png)

## BANの解除
誤ってBANしてしまったときなどに解除の方法も書いておきます。
まず、サーバー設定に移動し、`管理 > BANしたユーザー`に移動します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3818367/aa1870fa-aaef-9404-a60d-2a78183e75de.png)

BANを解除したいユーザーを探し、見つけたらクリックします。
BANを取り消すを押せばunBAN完了です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3818367/0d53e7c1-5689-c6b4-cf7a-e53a5fcab1e5.png)

## BANの回避について
実はDiscordのBANは回避が可能です。
普通はアカウントがBANされた場合、サブアカウントも入れられなくなります。
ただVPNをつけるとサブアカウントに限り入れるようになります。
これはDiscordがIPで判別してBANを行っているからです。
詳しくはβ教祖の[この動画](https://www.youtube.com/watch?v=SgKxBgXTCXU&t=218s)参照。

これを防ぐために**Double Counter**という認証botがオススメです。
VPN検知やサブアカウント検知に特化したbotのため、そういうことが起きにくくなります。
## まとめ
今回はDiscordのBAN機能についての解説でした。
botでBANを行う場合だと、Vortexなどは一括でたくさんできるのでおすすめです。
なにかわからないことなどあればコメントしてもらえれば返答します！

**Discordに湧く荒らしの情報や対策方法の共有をしている自鯖↓**
https://discord.gg/ESRGwGQhxc
Entity Framework Coreを学ぶ　その1

# 目標
以下に書かれていることを理解する
https://learn.microsoft.com/ja-jp/ef/core/

# 補助
**ORM**

https://qiita.com/minimabot/items/0a3fcc41fd7140dfdc41

https://utouto97.hatenablog.com/entry/2021/07/21/224759

https://envader.plus/article/129

https://qiita.com/gomiryo/items/6d448c500749f91242d2

https://blog.jnito.com/entry/20100528/1274998429

**メリット**
- プログラム上でDB操作できる(メソッドを通じてDB操作)
- 可読性が向上する
- 保守しやすくなる
- OOPの活用

**デメリット**
- プログラム上でDB操作できるので、SQLを学ぶ機会が減るかも
- 学習コスト(SQL + ORM)がかかるかも
- ORMを通じて実際に実行されているSQLがどのようなものかわからないかも

賛否両論たくさんある。

**エンティティクラス**

https://pgm-knowhow.github.io/wpf/Database/7.Entity.html

データベースのテーブルに対応するオブジェクト指向プログラミングのクラス
サバイバルTypeScript個人メモ その①

# はじめに
サバイバルTypeScriptを読んでます。

https://typescriptbook.jp/

個人的なメモです！

# トップ

## Shorthand property names
プロパティの値がすでに定義されている変数である場合、そのプロパティ名を省略して記述できる(shorthand property names)。

```sample.ts
const name = "John";
const age = 20;
const obj = { name, age };
console.log(obj);
```
## 分割代入
分割代入を使うと、配列の各要素を一度に変数に代入できる(配列の分割代入)。
```sample.ts
const [a, b] = [1, 2];
console.log(a);           // ⇒ 1
console.log(b);           // ⇒ 2
```

分割代入により、オブジェクトのプロパティを個別の変数へ代入できる
***展開しながら、keyと同じ名前で変数を定義するイメージ***
```sample.ts
const obj = {
  name: "John",
  age: 20,
};
 
const { name, age } = obj;
console.log(name);         // ⇒ John
console.log(age);          // ⇒ age
```

## 分割代入引数
関数の引数に配列またはオブジェクトリテラルを展開することができる
***分割代入の応用。引数のオブジェクトを展開しながら、関数内スコープにkeyと同じ名前で変数を定義する***
```sample.ts
const printCoord = ({ x, y }: { x: number; y: number }) => {
  console.log(`Coordinate is (${x}, ${y})`);
};
 
printCoord({ x: 10, y: 20 });  // ⇒ 'Coordinate is (10, 20)'
```

## ジェネリクス
TypeScriptのジェネリクスを使用すると、型の再利用性が向上し、型の一貫性を保つことができる。
ジェネリクスを使用すると、型変数を導入でき、これにより機能の一部を一般化できる。

下記の例ではTは型を表していて、型情報を関数やメソッド使用時に確定できる。
```sample.ts
// Tが型変数
function identity<T>(arg: T): T {
  return arg;
}
 
// 型変数Tにstringを割り当てる
const output1 = identity<string>("myString");
 
// 型変数Tにnumberを割り当てる
const output2 = identity<number>(100);
```
## 参考：interfaceとtypeの使い分け
- typeはユニオン型（ string | number ）などの定義を行える。
- typeはPickやOmitなどの操作を行うことができる。
- interfaceは何度も宣言でき、拡張されていく。
- classがimplementsできるのはinterfaceのみ。

このことから、型情報は基本typeで宣言し、classを実装する際のみinterfaceで宣言するのが良いかなと思いました。

# TypeScriptのあらまし > ECMAScript
## ECMAScriptとブラウザの仕様
ECMAScriptが決めるクライアントサイドJavaScriptの仕様は部分的です。ECMAScriptが定める範囲は、言語の文法、構文の解釈方法、コアのAPIなど言語の中核部分です。たとえば、次のようなことを定めています。
- 関数宣言の書き方はこういう文法になる
- 変数が宣言されたとき、JavaScriptエンジンはこういう動作になる
- StringやArrayオブジェクトにはこういうメソッドがある

# おわりに
軽く学んだだけのTypeScriptをこの期に再入門してみようと思っています！
まずは導入までに目を通してみました。
型推論などはとても心強い機能で、読んでいてワクワクします。
この後の実践編も楽しみです！
fly.ioで既存のアプリケーションへのデプロイ

# はじめに
fly.ioでデプロイのために`fly deploy`を行った際に詰まったところとその解決方法をまとめる．

# 問題
```
Error: failed to fetch an image or build from source: Could not find image "docker.io/library/flask-tutorial-blog-app:latest"
```
これは，`fly deploy` コマンドがリモートでイメージを見つけられないことを示している．これは，Fly.ioがローカルでビルドしたイメージをリモートレジストリにプッシュできていないため．
なお，flask-tutorial-blog-appというのはflyに登録されているappの名前である．


# 解決方法

現在のローカル環境からdockerイメージをビルドし，それをfly.io上に`push`した上で，そのイメージをもとに`deploy`すればよい．以下に手順をまとめる．

## 1. fly.ioへの接続
fly.ioへログインとdockerの認証を済ませる．
```
fly auth login
fly auth docker
```

## 2. Dockerイメージのビルドとプッシュ
ローカルでDockerイメージをビルドし，Fly.ioのレジストリにDockerイメージをプッシュする．
```
docker build -t registry.fly.io/flask-tutorial-blog-app:latest .
docker push registry.fly.io/flask-tutorial-blog-app:latest
```

## 3. Fly.ioのデプロイ
イメージをプッシュした後、Fly.ioにデプロイする．この時，Fly.ioのレジストリからイメージを取得するように明示的に指定する．
```
fly deploy --image registry.fly.io/flask-tutorial-blog-app:latest
```
<br>
    ここで，単に`fly deploy`だと，リモートでイメージを見つけられないというエラーが発生し，以下のようになってしまうので注意する．
    
    Error: failed to fetch an image or build from source: Could not find image "docker.io/library/flask-tutorial-blog-app:latest"
http-proxy-middlewareを用いてlocalhostの別PORTで起動しているフロントエンドとバックエンドを束ねて統合テストを行う


localhost:8020でフロントエンドが、localhost:8000でAPIサーバーが起動しているとします。
以下のようにルーティングします。
- /api/** → PATH, METHOD問わず localhost:8000のAPIサーバーへリダイレクト
- /**(それ以外) → PATH, METHOD問わず localhost:8020のフロントエンドへリダイレクト

## 手順

1. 同じディレクトリに以下の二つのファイルを入れます
2. `npm install && npm run start`でプロキシサーバーをlocalhost:8080で起動します

app.useの出現順はマッチングの優先順位なので順序を逆にすると全部フロントエンドへリダイレクトされてしまいます。
またtargetのhttp://127.0.0.1:8000/api/ の/apiの部分を忘れると例えば/api/openapi.jsonがhttp://127.0.0.1:8000/openapi.json へリダイレクトされて意図しない動作を引き起こします。
```typescript:index.ts
import express from 'express';
import { createProxyMiddleware } from 'http-proxy-middleware';
const app = express();
app.use(
	'/api/',
	createProxyMiddleware({
		target: 'http://127.0.0.1:8000/api/',
		changeOrigin: true
	}),
);
app.use(
	'/',
	createProxyMiddleware({
		target: 'http://127.0.0.1:8020/',
		changeOrigin: true
	}),
);
const port=parseInt(process.env.PORT ?? "8080")
app.listen(port, ()=>{
	const url=`http://localhost:${port}/`
	console.log(url)
});
```

```json:proxy/package.json
{
  "name": "proxy",
  "version": "1.0.0",
  "main": "index.js",
  "scripts": {
    "start": "ts-node index.ts"
  },
  "author": "",
  "license": "ISC",
  "description": "",
  "dependencies": {
    "express": "^4.19.2",
    "http-proxy-middleware": "^3.0.0"
  },
  "devDependencies": {
    "@types/express": "^4.17.21",
    "@types/http-proxy-middleware": "^1.0.0",
    "ts-node": "^10.9.2"
  }
}
```

適当に作っていたフロントエンド+バックエンドが表示されました。フロントエンドはGET:/から、グラフのデーターはGET:/api/dataから取得できています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118083/0415f313-e5ec-db35-384c-148dc7d95d33.png)

## 最後に

貴方の御用のためにお使いください