OmniAICreator/Qiita-1.07M huggingface dataset:
Firebaseを使ったデータベースにリアルタイムで変更

**今回はFirebaseのonSnapshotを使ったリアルタイムでの変更について記事にしたいと思います。
onSnapshotは、Firestoreデータベースにリアルタイムで変更を反映するための便利なメソッドです。リアルタイムでデータが更新されるため、チャットアプリや掲示板などのアプリで非常に役立ちます。**


# Firebase Firestore の onSnapshot メソッドとは？
**onSnapshot メソッド**は、Firestoreデータベースでのデータの変更をリアルタイムで監視できるメソッドです。このメソッドを使うと、データの追加・更新・削除などの変更があるたびに通知を受け取り、アプリのUIに即座に反映させることができます。

例えば、チャットアプリで新しいメッセージが投稿されたときや、掲示板に新しいコメントが追加されたときに、ページをリロードせずに即座に表示することが可能です。

**onSnapshot の基本的な使い方**
Firestoreからのデータをリアルタイムで取得するためには、onSnapshotを使います。主にコレクションやドキュメントに対して利用されます。

**コレクションの監視**
以下の例では、messagesコレクションを監視し、新しいメッセージが追加されるたびにコンソールに出力します。

```javascript
import { db } from './firebase'; // Firebaseの初期化済みインスタンス
import { collection, onSnapshot } from 'firebase/firestore';

const messagesRef = collection(db, 'messages');

onSnapshot(messagesRef, (snapshot) => {
  snapshot.docs.forEach((doc) => {
    console.log(doc.data());
  });
});
```

**ドキュメントの監視**
特定のドキュメントのみを監視する場合は、以下のように記述します。ここでは、usersコレクションのuserIDドキュメントをリアルタイムで監視しています。

```javascript
import { doc, onSnapshot } from 'firebase/firestore';

const userRef = doc(db, 'users', 'userID');

onSnapshot(userRef, (doc) => {
  console.log("Current data: ", doc.data());
});
```

**onSnapshot でのデータ変更の検知**
onSnapshotを使用すると、次の3つの変更タイプを検知できます。

**added：新しいドキュメントが追加されたとき**
**modified :既存のドキュメントが変更されたとき**
**removed：ドキュメントが削除されたとき**
これらの変更タイプを利用して、効率的にUIを更新できます。たとえば、新しいメッセージが追加されたときだけUIに反映させたり、削除されたメッセージを画面から消したりすることが可能です。

```javascript
onSnapshot(messagesRef, (snapshot) => {
  snapshot.docChanges().forEach((change) => {
    if (change.type === 'added') {
      console.log('New message: ', change.doc.data());
    }
    if (change.type === 'modified') {
      console.log('Modified message: ', change.doc.data());
    }
    if (change.type === 'removed') {
      console.log('Removed message: ', change.doc.data());
    }
  });
});
```

**リアルタイム監視のメリットとデメリット**

**メリット**
リアルタイムでのデータ反映：アプリ内でデータが即座に更新されるため、最新の情報をユーザーに提供できます。
ユーザー体験の向上：リロード不要でデータが反映されるため、スムーズな体験が可能です。

デメリット
リソース消費：リアルタイムのデータ取得はリソースを消費するため、トラフィックが多い場合はパフォーマンスが影響を受ける可能性があります。
コスト増加：Firebaseの無料プランでは、データの読み取り数が制限されているため、大量の読み取りが発生する場合は追加のコストがかかります。
onSnapshot を使用する際の注意点
メモリリーク防止：リアルタイムリスナーは不要になったら解除する必要があります。ReactのuseEffectフックやVueのbeforeDestroyライフサイクルフックでunsubscribe()を呼び出して、リスナーを削除しましょう。

```javascript
const unsubscribe = onSnapshot(messagesRef, (snapshot) => {
  // ...データ処理
});

// リスナーの解除
unsubscribe();
```
エラーハンドリング：onSnapshotはエラーハンドリングも行えます。ネットワークの接続エラーやパーミッションの問題が発生した場合、エラーハンドラーを設定しておくと便利です。

```javascript
onSnapshot(messagesRef, (snapshot) => {
  // データの変更処理
}, (error) => {
  console.error("Error fetching snapshot: ", error);
});
```

**まとめ**
onSnapshotは、Firestoreのリアルタイム機能を活用するための強力なメソッドです。リアルタイムのデータ更新が必要なアプリケーションにとって、ユーザー体験を向上させるための重要な要素です。しかし、データ取得回数やリソース消費を考慮し、必要に応じて使い分けることが重要です。

チャットアプリやタスク管理アプリなど、リアルタイムで更新されるデータを扱うアプリケーションで活用してみましょう！

**最後までよんでいただきありがとうございます。
@y-t0910をフォロー,いいねしていただけると嬉しいです！**
CATALINA_BASE環境変数を利用してTomcatを複数起動する方法

## 1. はじめに

JavaのWebアプリ開発でServletエンジンとして Apache Tomcat が使われることが多いのではないでしょうか。一般的な書籍や研修等で簡単な使い方は教わりますが、同一ホスト上で複数のTomcatインスタンスを起動させる方法はあまり知られておらず、若手メンバがよく質問されるので今回はその方法について説明したいと思います。なおTomcatはサービスではなく、利用時にコマンドで起動させるZip版を対象とします。

## 2. 環境変数を定義する

Java開発では`JAVA_HOME`、`MAVEN_HOME`等、`XXX_HOME`というディレクトリを指定する環境変数がよく使われます。Tomcatの場合も同様でTomcatのインストールディレクトリは`CATALINA_HOME`となります。
複数Tomcatを起動させるポイントは`CATALINA_HOME`に加えて`CATALINA_BASE`という別のTomcatインスタンス用の環境変数を定義することです。

| 変数 | 値 | 説明 |
|:---:|:--:|:----|
| JAVA_HOME | C:¥tools¥corretto¥jdk17.0.12_7 | JDKのインストールディレクトリパス<br >例はCorretto 17.0.12_7
| CATALINA_HOME | C:¥tools¥apache-tomcat-10.1.26 | Tomcatのインストールディレクトリ<br >例はTomcat10.1.26 |
| CATALINA_BASE | C:¥tools¥apserver_2 | ２つ目のTomcat起動用のディレクトリ<br >例はC:¥tools¥apserver_2<br >このディレクトリに別Tomcatで必要なファイル等を格納する | 

## 3. ディレクトリ構成

Tomcatの実行に必要なファイル（bin,lib）は`CATALINA_HOME`配下のものが使われます。`CATALINA_BASE`は別Tomcatインスタンスの起動に必要なものだけ準備する構成になります。ディスク容量も節約できる素晴らしい構成ですね。

```bat:CATALINA_HOME
CATALINA_HOME
 |-- bin
 |-- conf
 |-- lib
 |-- logs
 |-- temp
 |-- webapps
 |-- work
```

```bat:CATALINA_BASE
CATALINA_BASE
 |-- conf # CATALINA_HOME/confをコピー
 |-- logs # 存在しない場合、自動で作成される
 |-- temp # 存在しない場合、自動で作成される
 |-- webapps # 実行させたいWebアプリを格納する
 |-- work # 存在しない場合、自動で作成される
```

## 4. 設定ファイルをコピー＆修正する

複数Tomcatを起動させる上で考慮すべきことは、ポート番号やログファイル等のリソースの競合です。あるプログラムがリッスンしているポートを別のプログラムでリッスンしようとすると`Address already in use`のエラーになります。ログファイルについてもオープンしてロックをしているので、他のアプリから同じログファイルに書き込むことはできません。

Tomcatではこれらの設定はconfディレクトリ内のファイルで設定しているため、`CATALINA_HOME/conf`を`CATALINA_BASE/conf`にコピーしてリソース競合の箇所を別Tomcat用に変更します。

ポート番号で変更すべき箇所は`8005`、`8080`の２箇所、ApacheとTomcatを連携するためにAJP13を利用している場合は`8009`も加えて３箇所になります。

```xml:CATALINA_BASE/server.xml
<Server port="8005" shutdown="SHUTDOWN">
↓
<Server port="⭐️8005から被らない他のポート番号に変更" shutdown="SHUTDOWN">

<Connector port="8080" protocol="HTTP/1.1"
↓
<Connector port="⭐️8080から被らない他のポート番号に変更" protocol="HTTP/1.1"

<Connector protocol="AJP/1.3"
           address="::1"
           port="8009"
↓
<Connector protocol="AJP/1.3"
           address="::1"
           port="⭐️8009から被らない他のポート番号に変更"
```

**（参考）**
Tomcat毎にconfを修正するのはメンドウで同じファイルを使いたいという場合、[Tomcatのポート番号を環境変数で定義・変更する方法](https://qiita.com/5zm/items/2f8e43a0c4dd0a4a6947)を参照ください。Tomcatを起動させる際に環境変数で差分を定義できるので便利かと思います。

```bat:apserver2_startup.bat
@echo off
set JAVA_HOME=C:¥tools¥corretto¥jdk17.0.12_7
set CATALINA_HOME=C:¥tools¥apache-tomcat-10.1.26
set CATALINA_BASE=C:¥tools¥apserver_2

set SHUTDOWN_PORT=8006
set SERVER_PORT=8084
set AJP_PORT=8019

call %CATALINA_HOME%¥bin¥startup.bat
```

## 5. さいごに

今回は同一ホスト内で複数のTomcatインスタンスを起動させる方法について説明しました。わざわざTomcatを複数インストールして起動させようとしているメンバがいたので今回の記事としました。なお、複数のTomcatが起動できるようになると以下のケースで役立つのではないでしょうか。

* システム移行の対応等で異なるバージョンの新旧Tomcatを起動させ、現新比較したい
* クラスタやセッションレプリケーションを確かめたい
Databricksユーザー会イベント - JEDAI in Osaka 2024 

三連休前の金曜日、私は新幹線で大阪に向かってました。こちらのイベントの司会をするためです。

https://jedai.connpass.com/event/329313/

一年前にクローズドなイベントを行って以来、約一年ぶりです。

私が担当しているお客様は関西圏の方が多く「またユーザー会やってください」というお声がけもいただくこともあり、一念発起して企画しました。といっても、実際に登壇者の調整等々いただいたのは別のエンジニアや営業の方でした。私は司会に専念しました。

上のページにあるように、ダイハツ、クボタ、パナソニックと錚々たるメンバーです。

今回はオンラインとオンサイトのハイブリッドということもあり、音響周りで事前チェックしたいと思い、開場の2時間前に現地入りしました。会場を貸してくださったダイキン様の入る[大阪梅田ツインタワーズ・サウス](https://www.daikin.co.jp/corporate/overview/summary/locations/jp/modals/base01/01)に。大阪不慣れなので、大阪駅からどう行っていいのかワタワタ。地下道ですぐに到着できましたが。

Zoomウェビナーの設定も完了、Jabraも繋いでバッチリ(と思ってたら途中で方向修正必要になりましたが)。

![IMG_1124.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/2314dc8a-e150-2d12-ec28-1a02bd4cb639.jpeg)

現地はほぼ満席、オンラインでも50人以上の視聴が。ハイブリッドの司会やって改めて思ったのですが、オンサイトとオンラインの質問を同時に捌くのはなかなかの難易度。会場は50人規模だったのでマイクいらないかなと思ったら、人が増えるとノイズが増えて、マイクが必要に。話している途中に同僚の方からslackで教えてもらいました。それからは、登壇者と質問者にマイクをお渡ししてことなきを得ました。あとは、チャットで質問してくださいと言っておきながら、チャットをオフにしていたというポカミス。

# 発表内容ダイジェスト

以下は発表内容のダイジェストを。

- **DAIHATSU: 製造現場のAI実装におけるDatabricks活用方法** 生産ラインでのAI活用に積極的に取り組まれていることを発表いただき、AI推進部門と工場とでどのように関係性を構築するのかという質疑応答がありました。技術がどんなに進化したとしても、結局のところ人間関係大事ということで。
- **KUBOTA: 半年で実現！Databricksを使った内製スマートファクトリーへの挑戦** 半年でスマートファクトリーを実現しよと言うあつ、ゲフンゲフン。そういった中で、技術にbelieve inされている少数精鋭の方々がDatabricksを活用して、データ取り込みからBIまでエンドツーエンドで実現されたという非常に生々しさあふれるお話でした。
- **Panasonic: データサイエンティストの成長と組織力強化に向けたDatabricks活用** 「Databricksを使って社内Kaggle、そう言うのもあるのか」と思いました。正解データを参加者に公開しないようにするには、Unity Catalogの権限管理がジャストフィット、サブミットされた結果の処理もワークフローで自動化。面白い。

# 懇親会

本来の会よりも盛り上がったのはこちらの方かも(オンラインの方すみません)。色々な業種の方々が意見交換されていました。閉会の20時はあっという間でした。

(自分が勝手に言っているだけですが)JEDAI関西担当なので、また開催します！

# 余談

当日はホテルに泊まったのですが、翌日は三連休の初日、そして大雨ということであり新大阪駅はカオス状態。新幹線に乗れたと思ったら豊橋で一時間近く足止めされました。100分遅れで帰れただけでもラッキーだったのかもしれません。

![IMG_1129.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/7a7c7f14-c7d3-4a79-0d55-dbd3688e4f33.jpeg)


### はじめてのDatabricks

[はじめてのDatabricks](https://qiita.com/taka_yayoi/items/8dc72d083edb879a5e5d)

### Databricks無料トライアル

[Databricks無料トライアル](https://databricks.com/jp/try-databricks)
自動的にエスケープされる

# 5.1 安全な出力
>5.1.1 開発の動機
`HTMLテンプレートにデータを挿入する方法は、きわめて慎重に設計する必要`があります。たとえば、`@review.titleを何の工夫もなくそのままHTMLに式展開するようなことは絶対にすべきではありません`。もしこのレビューのタイトルが仮に「Flanagan & Matz rules!」だとしたら、出力はwell-formedになりません。well-formedにするには、&->&amp;のようにエスケープしなければなりません。さらに、ユーザーがレビューのタイトルに細工をして、悪意のあるHTMLをタイトルに含めれば、巨大なセキュリティホールになる可能性すらあります。このリスクの詳細については、セキュリティガイドのクロスサイトスクリプティングの節を参照してください。
* `@review.title`をHTMLに展開してはならない。
 
>5.1.2 安全な文字列
`Active Supportには「(html的に) 安全な文字列」という概念`があります。安全な文字列とは、`HTMLにそのまま挿入しても問題がないというマークが付けられている文字列`です。マーキングさえされていれば、「実際にエスケープされているかどうかにかかわらず」その文字列は信頼されます。
>
>文字列はデフォルトでは「unsafe」とマークされます。
>```rb
>"".html_safe? # => false
>```
>与えられた文字列にhtml_safeメソッドを適用することで、安全な文字列を得られます。
>
>```rb
>s = "".html_safe
>
>s.html_safe? # => true
>```
>ここで注意しなければならないのは、`html_safeメソッドそれ自体は何らエスケープを行なっていない`ということです。安全であるとマーキングしているに過ぎません。
>
>```rb
>s = "<script>...</script>".html_safe
>s.html_safe? # => true
>s            # => "<script>...</script>"
>```
>すなわち、特定の文字列に対して`html_safeメソッドを呼び出す際には、その文字列が本当に安全であることを確認する義務`があります。
* html_safeメソッドそれ自体は何らエスケープを行なっていない

>`安全であると宣言された文字列に対し、安全でない文字列をconcat/<<や+で破壊的に追加すると、結果は安全な文字列`になります。安全でない引数は追加時にエスケープされます。
>
>```rb
>"".html_safe + "<" # => "&lt;"
>```
>安全な引数であれば、(エスケープなしで)直接追加されます。
>
>```rb
>"".html_safe + "<".html_safe # => "<"
>```
>`基本的にこれらのメソッドは、通常のビューでは使わないでください`。現在のRailsのビューでは、`安全でない値は自動的にエスケープされる`ためです。
>```rb
><%= @review.title %> <%# 必要に応じてエスケープされるので問題なし %>
>```
* 上記のメソッドは使わない！
* 現在のRailsのビューでは、`安全でない値は自動的にエスケープされる`

>何らかの理由で、`エスケープされていない文字列をそのままの形で挿入したい場合は、html_safeを呼ぶのではなく、rawヘルパーをお使いください`。
>
>```rb
><%= raw @cms.current_template %> <%# @cms.current_templateをそのまま挿入 %>
>```
>あるいは、rawと同等の<%==を使います。
>
>```rb
><%== @cms.current_template %> <%# @cms.current_templateをそのまま挿入 %>
>```
>rawヘルパーは、内部でhtml_safeを呼び出します。
>```rb
>def raw(stringish)
>  stringish.to_s.html_safe
>end
>```
>定義はactive_support/core_ext/string/output_safety.rbにあります。

https://railsguides.jp/active_support_core_extensions.html#string%E3%81%AE%E6%8B%A1%E5%BC%B5:~:text=5.1%20%E5%AE%89%E5%85%A8%E3%81%AA,%E3%81%AB%E3%81%82%E3%82%8A%E3%81%BE%E3%81%99%E3%80%82

* エスケープされていない文字列をそのままの形で挿入したい場合は、html_safeを呼ぶのではなく、rawヘルパーをお使いください
* rawヘルパーとは？

### raw
>This method outputs without escaping a string. Since escaping tags is now default, this can be used when you don’t want Rails to automatically escape tags. This is not recommended if the data is coming from the user’s input.

https://api.rubyonrails.org/v7.2.1.1/classes/ActionView/Helpers/OutputSafetyHelper.html#:~:text=Instance%20Public%20methods-,raw(stringish),-Link

* もっとrubyを読めるようになりたい。

https://github.com/rails/rails/blob/main/activesupport/lib/active_support/core_ext/string/output_safety.rb

# 感想
inputタグから入力しても自動的にエスケープされるからscriptが発動しないことを知った。
しかし他の方法があるなら知りたい。（調べても探すことができなかった。）
できればコメントで教えてください。(理解できるかどうかわかりません)
tkinter を使った複数個ある bind を loop で処理する方法

## tkinterで複数個のボタンの配置

`tkinter` を使っていて、ボタンなど同じ物を複数個作成する際、1 つずつ作成していると面倒なので、`loop` を使って以下のような方法をとると思います。

```python
import tkinter as tk


root = tk.Tk()
buttons = []
# 5つのボタンを追加
for i in range(0,5):
    buttons.append(tk.Button(root, text=f"{i}番目のボタン"))
    buttons[i].pack()

root.mainloop()

```
## bind処理の追加

ここに `bind` で右クリック処理を付けます。

```diff_python
import tkinter as tk
+ from tkinter import messagebox


+ # クリック関数
+ def click(event):
+     messagebox.showinfo("情報", "クリックしました")
+     return


root = tk.Tk()
buttons = []
# 5つのボタンを追加
for i in range(0, 5):
    buttons.append(tk.Button(root, text=f"{i}番目のボタン"))
    buttons[i].pack()
+     # bind 処理追加 右クリックに処理を付ける
+     buttons[i].bind("<Button-3>", click)

root.mainloop()

```

ただ、これでは何番目のボタンをクリックしたかわかりません。
[`lambda` 関数](https://docs.python.org/ja/3.13/reference/expressions.html#lambda)を使えば関数に引数を渡せるため上手くいきそうです。

```diff_python
import tkinter as tk
from tkinter import messagebox


# クリック関数
- def click(event):
-     messagebox.showinfo("情報", "クリックしました")
+     def click(event, i):
+     messagebox.showinfo("情報", f"{i}をクリックしました")
return


root = tk.Tk()
buttons = []
# 5つのボタンを追加
for i in range(0, 5):
    buttons.append(tk.Button(root, text=f"{i}番目のボタン"))
    buttons[i].pack()
    # bind 処理追加 右クリックに処理を付ける
+     # lambda 関数で引数を渡す
-     buttons[i].bind("<Button-3>", click)
+     buttons[i].bind("<Button-3>", lambda event: click(event, i))
root.mainloop()

```

実行すると、確かに「4 をクリックしました」と表示されるので、値が送られています。ただ、どこを押しても「4 をクリックしました」となってしまいます。
これは、ボタンをクリックした際に `i` の値を参照するためで、（クリックするときは 5 つのボタンが作成された後であるため）`i` の値 `4` がすべてのボタンで表示されてしまっています。

## 解消方法

この現象を回避するためにヘルパー関数を間に挟むことで解消できます。

```diff_python
import tkinter as tk
from tkinter import messagebox


# クリック関数
def click(event, i):
    messagebox.showinfo("情報", f"{i}をクリックしました")
    return


+ # ヘルパー関数
+ def helper_lambda(i):
+     return lambda event: click(event, i)


root = tk.Tk()
buttons = []
# 5つのボタンを追加
for i in range(0, 5):
    buttons.append(tk.Button(root, text=f"{i}番目のボタン"))
    buttons[i].pack()
    # bind 処理追加 右クリックに処理を付ける
-     # lambda 関数で引数を渡す
+     # ヘルパー関数を通してクリック関数を呼び出す
-     buttons[i].bind("<Button-3>", lambda event: click(event, i))
+     buttons[i].bind("<Button-3>", helper_lambda(i))
root.mainloop()

```

これで、押された番号の `i` を参照することができました。

<details><summary>今回の最終コード</summary>

```python
import tkinter as tk
from tkinter import messagebox


# クリック関数
def click(event, i):
    messagebox.showinfo("情報", f"{i}をクリックしました")
    return


# ヘルパー関数
def helper_lambda(i):
    return lambda event: click(event, i)


root = tk.Tk()
buttons = []
# 5つのボタンを追加
for i in range(0, 5):
    buttons.append(tk.Button(root, text=f"{i}番目のボタン"))
    buttons[i].pack()
    # bind 処理追加 右クリックに処理を付ける
    # ヘルパー関数を通してクリック関数を呼び出す
    buttons[i].bind("<Button-3>", helper_lambda(i))
root.mainloop()

```
</details>

#### 参考: https://stackoverflow.com/questions/14259072/tkinter-bind-function-with-variable-in-a-loop
(QA) ACS 1.1.9.xのバージョン毎のアップデート情報を確認したい＆ダウンロードサイト

## [IBM i Access - ACS Updates](https://www.ibm.com/support/pages/ibm-i-access-acs-updates)

上記に記載があります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011394/11cff2b7-1a1b-c408-53d8-88c1a08ec0c6.png)


さらに改めて、下記ご質問も時々頂くので、

## (QA) ACSのダウンロード先は？

### [IBM i Access - Client Solutions](https://www.ibm.com/support/pages/ibm-i-access-client-solutions) のページにある、、

[このリンク](https://www.ibm.com/resources/mrs/assets?source=swg-ia)からダウンロードサイトにリンクしています

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011394/a463fd9c-9b47-68f2-0f8b-3dea6899bd47.png)

IBM IDでログインすると下記のページに飛び、I agreeをチェックして、I confirmボタンを押すと、、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011394/bf7bd921-3da6-1c84-daaf-e008c2f0943d.png)

[ダウンロードリンク](https://iwm.dhe.ibm.com/sdfdl/v2/regs2/sharee2/iacs-java/v1r1/Xa.2/Xb.Fjx4e5cjaz05DomapLLWnJgjT0dCPCUr7d5mP092t64/Xc.iacs-java/v1r1/IBMiAccess_v1r1.zip/Xd./Xf.lPr.D1vk/Xg.13063621/Xi.swg-ia/XY.regsrvs/XZ.dmiaLOzgLuQ47NpE7m0nrd4vph6Mqy5z/IBMiAccess_v1r1.zip)に辿り着きます・・ふー。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011394/3478f28e-6c5b-0a85-8189-b01f9fc59fb6.png)

上記から必要なACSのモジュールを選択してダウンロードします。
1Password CLIを使ってみる 

# はじめに

1PasswordをCLIで使用する方法について記載します。

もともと、GUIでは[1Password](https://1password.com/)、CLIでは[Pass](https://www.passwordstore.org/)を使用していたのですが、分かれているの嫌だなと思い、今回1Passwordに統一しました。

# インストール

パッケージマネージャーを使用しないでのインストールは以下になります。

```bash
ARCH="amd64"; \
OP_VERSION="v$(curl https://app-updates.agilebits.com/check/1/0/CLI2/en/2.0.0/N -s | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+')"; \
curl -sSfo op.zip \
https://cache.agilebits.com/dist/1P/op2/pkg/"$OP_VERSION"/op_linux_"$ARCH"_"$OP_VERSION".zip \
&& unzip -od /usr/local/bin/ op.zip \
&& rm op.zip
```

私の場合は、インストールをMakefileでおこなっているので次のように定義しています。

```makefile
ARCH := $(shell uname -m)
BIN_DIR := $(HOME)/.local/bin
COMPLETION_DIR := $(HOME)/.local/share/zsh-completion/completions

$(BIN_DIR)/op:
	mkdir -p /tmp/op
	$(eval DL_ARCH := $(shell if [ "$(ARCH)" = "x86_64" ]; then echo "amd64"; else echo "arm64"; fi))
	$(eval VERSION := $(shell curl https://app-updates.agilebits.com/check/1/0/CLI2/en/2.0.0/N -s | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+'))
	curl -fsLS -o /tmp/op/op.zip https://cache.agilebits.com/dist/1P/op2/pkg/v$(VERSION)/op_linux_$(DL_ARCH)_v$(VERSION).zip
	unzip /tmp/op/op.zip -d /tmp/op
	mv /tmp/op/op $(BIN_DIR)/op
	rm -rf /tmp/op
	$(BIN_DIR)/op completion zsh > $(COMPLETION_DIR)/op.zsh
```

※ インストールと合わせて入力補完用ファイルの生成も合わせておこなっています。

# サービスアカウントの発行
CLIからでもID/Passwordでのサインインが可能ですが、都度パスワードの入力を求められてしまうので、サービスアカウントを発行して使用しています。

1. [1Password](https://my.1password.com/home)にログイン
1. サイドバーから「Developer Tools」を選択
1. 「Directory」タブを選択し、「Service Account」を選択
1. 「Service account name」に任意の名前を入力
1. 「Choose vaults」から参照するVaultを選択
    - DefaultのVaultを指定することはできなので、CLI用のVaultを作成するのが良いかと思います。 
1. 「Service account token」が発行されるので記録しておいてください

# 使ってみる

まずは、サインインの設定です。
whoamiコマンドで情報が取得できればサインインできています。

```
# 環境変数にサービスアカウントトークンを設定
$ export OP_SERVICE_ACCOUNT_TOKEN=${Service account token}
# サインインアカウントの情報を確認
$ op whoami
URL:               https://your_url
Integration ID:    your_integration_id
User Type:         SERVICE_ACCOUNT
```

## Vaultの一覧表示
```
$ op vault list
ID                            NAME
xxxxxxxxxxxxxxxxxxxxxxxxxx    CLI
```

# 保存されているアイテム一覧
```
$ op item list
ID                            TITLE                  VAULT            EDITED
yyyyyyyyyyyyyyyyyyyyyyyyyy    ChatGPT API Key        CLI              4 minutes ago
```

## 特定のアイテムを取得

```
$ op item get oom2m6lj676ll6axyeyfag6p24 --vault CLI
ID:          yyyyyyyyyyyyyyyyyyyyyyyyyy
Title:       ChatGPT API Key
Vault:       CLI (xxxxxxxxxxxxxxxxxxxxxxxxxx)
Created:     8 minutes ago
Updated:     6 minutes ago by miya10kei
Favorite:    false
Version:     2
Category:    LOGIN
Fields:
  password:    [use 'op item get yyyyyyyyyyyyyyyyyyyyyyyyyy --reveal' to reveal]
```

※ アイテムを取得する場合は`--vault`オプションを付与して取得先のVaultを指定してください

### フィールドを絞りたい場合
```
$ op item get oom2m6lj676ll6axyeyfag6p24 --vault CLI --fields password --reveal
ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
```
※ パスワードフィールドの場合は`--reveal`オプションを付与することで確認可能です

# 参考
- https://developer.1password.com/docs/cli
黒本一冊で合格！ORACLE MASTER Silver DBA 2019の成功ストーリー

## 初めに

こんにちは！今回は、私が「ORACLE MASTER Silver DBA 2019」に正答率86％で合格した体験をシェアしたいと思います。合格に至るまでの勉強法や使用した教材についてお話しします。

## 資格取得のきっかけ
データベースに興味があり、キャリアアップを目指して「ORACLE MASTER Silver DBA」を受験することに決めました。Oracleのデータベースは多くの企業で利用されているため、この資格を取得することで自分の市場価値を高められると考えました。

Bronzeの資格は取得済みです。

## 使用した教材
私が使用した教材は、黒本（「Oracle Master Silver DBA 2019試験対策テキスト」）のみです。Pingtは未使用で、黒本だけに集中しました。この本はとても分かりやすく、試験範囲を網羅しています。

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

## 黒本の活用法
### 基礎知識の習得

黒本では、Oracleデータベースの基礎から応用まで丁寧に解説されています。まずは各章を読み込み、理解を深めました。

### 演習問題の解答

各章の後にある演習問題を解くことで、自分の理解度をチェックしました。間違えた問題は再度黒本を読み返し、知識を定着させるようにしました。

### 模擬試験の実施

黒本には模擬試験も含まれているので、試験前に何度か挑戦しました。実際の試験の形式に慣れることができ、自信を持って本番に臨むことができました。試験範囲が広いため演習も含めて何週もしました。

## 試験内容について
「ORACLE MASTER Silver DBA 2019」の試験は、Bronzeの試験と比べると、黒本と全く同じ問題の出題数はかなり減少しました。ほぼゼロに近い状況です。しかし、問題の意図自体は変わっていないケースが多いため、しっかりと問題文を読み込むことで対応が可能です。

## 勉強のスケジュール
私の勉強スケジュールは以下の通りです。

1ヶ月目: 基礎知識の習得と演習問題を中心に進める。
2ヶ月目: 黒本を何度も読み返し、理解を深める。
3ヶ月目: 残りの時間で苦手な分野を重点的に復習。

試験前日に章末問題＋模擬試験をすべて解いたところ全362問中2問以外はすべて正解できた状態で試験に臨みました。

## 合格の喜び
試験当日は緊張しましたが、黒本での準備がしっかりできていたおかげで、自信を持って挑むことができました。その場で合否を確認できるためかなり緊張しましたが合格できてよかったです。

## まとめ
「ORACLE MASTER Silver DBA 2019」に合格するためには、黒本をしっかりと活用することが重要です。基礎から応用までを網羅した内容なので、これから挑戦する方には自信を持っておすすめします。しっかりと準備をして挑戦してください。ぜひ、皆さんも頑張ってください！

以上、私の合格体験記でした。質問や感想があれば、ぜひコメントしてください！
ChromebookのLinuxアプリでプリンターを使用する方法

Linuxターミナルを開き、以下のコマンドを実行して、`CUPS`(Common Unix Printing System)をインストールする。私の環境ではこれだけで、Linuxアプリでプリンターが使用できるようになった。
```shell
sudo apt update && sudo apt upgrade -y
sudo apt install cups -y
```

`cups`のインストールだけで使用できるようになったので、試していませんが、もし印刷メニューにプリンターが現れなければ、以下のコマンドを実行してみると良いかもしれない。
```shell
sudo service cups start
```
または、
```shell
sudo service cups restart
```
それでも現れなければ、以下のコマンドを実行して、`system-config-printer`をインストールする。
```shell
sudo apt install system-config-printer -y
xhost + si:localuser:root
```
その後、以下のコマンドを実行して、プリンター設定にアクセスして、プリンターを検索して追加できるかもしれない。
```shell
sudo system-config-printer
```
csv ファイルをユーザ定義関数で編集する

## csv ファイルをlistで読み込み編集する

1. `import csv` で csvライブラリを使用する。 
1. csv を list で覚えておき、全体操作する。 
1. 行/列の追加、行/列の削除、特定セルの更新 関数でcsvを編集する

```python

import csv

# 編集用のデータ
INS_ROW_DATA = [ 10, 'INS_ROW', 100 ]
INS_COL_DATA = 'INS_COL'
UPDATE_DATA  = 'UPDATE'

# "行"を挿入する。
def insert_row(cells:list, row:int, ins_list:list):
    cells.insert(row,ins_list)
    return

# "列"を挿入する。
def insert_col(cells:list, col:int, data):
    # 全ての行に対して列を挿入する。
    [ row.insert(col, data) for row in cells ]
    return

# "行"を削除する。
def remove_row(cells:list, row:int):
    cells.pop(row)    # clear() 全削除 / remove() 先頭削除
    return

# "列"を削除する。
def remove_col(cells:list, col:int):
    # 全ての行に対して列を削除する。
    [ row.pop(col) for row in cells ]
    return

# セルを更新する。
def update_cell(cells:list, row:int, col:int, data):
    cells[row][col] = data
    return

# セルを表示する。
def print_cell(cells:list):
    for row in cells:
        for cell in row:
            # 改行の変わりにタブを出力し、セル情報のみ出力する。
            print(cell, end='\t')
        # 改行
        print()

# csv ファイルを読み取りで開く。
with open("./csv/sample.csv", mode="r", encoding="UTF-8") as file:

    # csv reader を取得する。(書式の指定は dialect でまとめて指定)
    reader = csv.reader(file, dialect=csv.excel_tab)

    # csv をメモリ展開（軽いファイル前提）
    cells = [ row for row in reader ]

    # 行を挿入
    insert_row(cells, 2, INS_ROW_DATA)
    print_cell(cells)

    # 列を挿入
    insert_col(cells, 1, INS_COL_DATA)
    print_cell(cells)

    # 行を削除
    remove_row(cells, 3)
    print_cell(cells)

    # 列を削除
    remove_col(cells, 1)
    print_cell(cells)

    # セルを更新
    update_cell(cells, 1,1, UPDATE_DATA)

    # 結果を表示する
    print_cell(cells)

```
csv ファイルを読み込み表示する


## csv ファイルを読み込み1セルずつprintする

1. `import csv` で csvライブラリを使用する。
1. `with open()` で csvファイルを開いて、close忘れ防止。
1. `csv.reader()` で reader を使って1行-1セルずつデータを取得してprintする。

```python
import csv

# csv ファイルを読み取りで開く。
with open(r".\sample.csv", mode="r", encoding="UTF-8") as file:

    # csv reader を取得する。
    # (書式の指定は dialect でまとめて指定する。)
    reader = csv.reader(file, dialect=csv.excel_tab)

    # 1行ずつ取得する
    for row in reader:
        for cell in row:
            # 改行の変わりにタブを出力し、セル情報のみ出力する。
            print(cell, end='\t')

        # 改行
        print()
```
RIP-2の特徴と改善点：古いRIPの弱点を克服する改良版ルーティングプロトコル

## イントロダクション
RIPは、最も古いルーティングプロトコルの一つであり、シンプルな設計が特徴ですが、古いバージョンにはいくつかの制約がありました。RIP-2では、柔軟なサブネット対応や効率的なマルチキャスト通信など、重要な改善が加えられています。本記事では、RIP-2の特徴と、RIP-1からの主な改善点について解説します。

---

## 1. RIP-2の特徴と役割
RIP-2はディスタンスベクタ型のルーティングプロトコルであり、シンプルな設計で小規模ネットワークに適しています。RIP-2は、RIP-1の制約を補い、柔軟なルーティングができるように設計されており、サブネット分割が必要な小中規模のネットワークで利用されます。

---

## 2. RIP-2の改善点

### 2.1 サブネットマスク対応で柔軟なネットワーク設計が可能に
RIP-1はクラスフルルーティングでサブネットマスクに対応していませんでしたが、RIP-2ではサブネットマスク情報を含めた経路情報を交換できるようになりました。これにより、CIDR（Classless Inter-Domain Routing）対応が実現し、サブネットの柔軟な分割と効率的なIPアドレス管理が可能です。

### 2.2 マルチキャスト対応で無駄なトラフィックを削減
RIP-1ではネットワークセグメント内の全デバイスにブロードキャストで経路情報を送信していたため、不要なデバイスにも影響が生じていました。RIP-2ではマルチキャストアドレスを使用し、RIPを受信したいルータだけが情報を受け取る仕組みに改良されています。これにより、必要なデバイスだけに経路情報が届き、ネットワークの負担が軽減され、パフォーマンスが向上しました。

### 2.3 パスワード認証でセキュリティが向上
RIP-1には認証機能がなかったため、不正なルータが経路情報を送信してしまうリスクがありました。RIP-2ではパスワード認証が導入され、指定されたルータのみが経路情報を受信できるようになりました。認証方式としては、シンプルな平文認証と、より安全なMD5認証がサポートされています。

---

## 3. RIP-2のデメリット
- **ホップ数制限（最大15）**：RIP-1と同様、最大15ホップまでの制限があるため、大規模なネットワークには不向きです。
- **収束速度が遅い**：ディスタンスベクタ型であるため、経路の変化が広がるまで時間がかかり、トラフィック増加時のパフォーマンスが懸念されます。

---

## 4. まとめ：RIP-2は小規模ネットワークで効果的
RIP-2はRIP-1の制約を克服し、サブネットマスク対応やセキュリティ強化によって、小規模から中規模ネットワークに適したプロトコルとして進化しました。マルチキャスト対応により無駄なトラフィックを抑え、認証機能で安全性も向上しています。しかし、ホップ数制限と収束の遅さから、大規模ネットワークには適していません。

---

## 最後に
RIP-2はシンプルさを保ちながらも、RIP-1からの大きな改善を取り入れたプロトコルであり、特に家庭や小規模オフィスのネットワークで便利な選択肢です。大規模なネットワークを構築する場合は、OSPFやEIGRPなど、収束が速くてホップ数制限のないプロトコルを検討すると良いでしょう。
csvファイルを新規作成する

## csv ファイルを新規作成してヘッダとデータを書き込む

1. `import csv` で csvライブラリを使用する。 
1. `with open()` で csvファイルを開いて、close忘れ防止。 
1. `csv.writer()` で writer を使ってヘッダやデータを書き込む。 

```python
import csv

# csv のヘッダ（列名）
header = [
    ['No.','Name','Point']
]

# csv の data
datas = [
    [ 1, 'Mike' , 99],
    [ 2, '山田' , 89],
    [ 3, 'Temp' , 5 ],
]

# csv ファイルを新規作成する。
with open("./sample.csv", mode="w", newline='', encoding="UTF-8") as file:

    # csv writer を取得する。(QUOTE_ALLで、全てクオート("")する)
    writer = csv.writer(file, delimiter='\t', quoting=csv.QUOTE_ALL)

    # ヘッダ（列名）を設定する。
    writer.writerows( header )

    # データを追加する。
    writer.writerows( datas )
```
RIPのサブネットマスク問題とプロキシARPでの回避方法はありえるか

## イントロダクション
- RIPはシンプルなディスタンスベクタ型ルーティングプロトコルで、今でも小規模ネットワークに使われることがある。
- しかし、サブネットマスクに対応していないため、現在のネットワーク設計では不便な点が多い。
- 今回は、RIPのサブネットマスク問題をプロキシARPで回避できるかを考察する。

## 1. RIPがサブネットマスクに対応していない問題
- RIPはクラスフルルーティングのみ対応で、CIDRに基づくクラスレスなサブネット分割ができない。
- 小さなサブネットに柔軟に分割することができず、IPアドレスが無駄になる。
- 異なるサブネットサイズを混在させた構成や、柔軟なアクセス制御が難しい。

## 2. プロキシARPの仕組みとメリット
- プロキシARPは異なるサブネット間で直接通信ができるように見せかける手法。
- RIPのサブネット問題を一部回避できる可能性がある。

## 3. プロキシARPで回避する際の問題点
- **ルーティングの柔軟性が低い** ：プロキシARPはルーティングの最適化には向かない。
- **ネットワークが混乱しやすい** ：ARPテーブルが膨らみ、ブロードキャストが増えることで混乱が生じる。
- **セキュリティリスク** ：ネットワークの境界が曖昧になり、意図しないアクセスが発生しやすい。
- **トラブルシューティングの難しさ** ：プロキシARPによる偽装が原因で、問題箇所の特定が複雑化する。

## 4. 結論
- プロキシARPで一部の問題を回避することは可能だが、リスクが多いため大規模ネットワークには向かない。
- 結果的に、CIDRに対応したOSPFやEIGRPのようなルーティングプロトコルを使う方が現実的で安全。

## 最後に
- 小規模ネットワークや教育用でRIPを使う場合、プロキシARPのような工夫も学びとしては有用。
- しかし、実運用ではセキュリティや管理面でリスクが多いため、RIPからの移行を検討するのが望ましい。
pypyをlinuxでインストールする

# この記事を書いた経緯
競プロでcpython(デフォルトのコンパイラ)が遅いのでpypyを使うのですが、ローカルにはインストールしておらずローカルではcpythonを使っていました
ですがABC378-Dでローカルでのcpythonの遅さを痛感しました(結局ACして4完しましたけどね)
ローカルテストで提出していいのかだめなのかわからなくなりローカルでもpypyをインストールしたほうがいいという結論に至りました
そのためこの記事を書きました

# 前提条件
linuxを使用しているまたはwsl
使用するツール
* wget
* tar

# tar.bz2ファイルをインストールする
pypyの[公式サイト](https://pypy.org/)のdownloadsでそれぞれのアーキテクチャにあったtar.bz2ファイルのリンクをコピーしてください
それでターミナルで以下のコマンドを実行します(tar.bz2ファイルのインストール)
```bash
wget pypy.<バージョン>.<アーキテクチャ>.tar.bz2
```
# tar.bz2ファイルの解凍
インストールしたディレクトリに移動して以下のコマンドを実行します
```bash
tar -jxvf pypy<バージョン>.<アーキテクチャ>.tar.bz2
```
これで解凍完了です

# パスを通す
そのあとsudo権限が必要なディレクトリにpypyのディレクトリを移動してパスを通します
sudo権限が必要なディレクトリのおすすめはoptです
下のサンプルではoptに移動させます

```bash
sudo mv pypy<バージョン>.<アーキテクチャ> /opt
```

.bashrcまたは.zshrcにパスを通す設定を追加してください
```bash
export PATH="$PATH:/opt/pypy<バージョン>.<アーキテクチャ>/bin"
```

これで完了です
pypyのpipを使う場合はpypy -m pipでやると使いやすいはずです
freezedパッケージでモデルクラスの数字Enumに意味を持たせたい

## Firestoreの構造
下記のようにtypeがFirestore上ではnumberで管理されている場合。
Flutter側では、数値から表示する文字列へ変換する場合がある。
| フィールド名            | 型            | デフォルト値                       | 説明                                       |
|------------------|-----------------|-------------------------------------|---------------------------------------------------|
| docId            | String          | `''`                                | ドキュメントID   |
| type             | int             | `0`                                 |0:未選択、1:タイプ１、2:タイプ２、3:タイプ3 |


## freezedで定義するクラス内で表示用メソッドを作成する
```dart
import 'package:cloud_firestore/cloud_firestore.dart';

part 'your_data.freezed.dart';
part 'your_data.g.dart';

// enumでtypeを表現
enum YourDataType {
  notSelected(0, '未選択'),
  type1(1, 'タイプ１'),
  type2(2, 'タイプ２'),
  type3(3, 'タイプ３');

  final int value;
  final String displayName;

  const YourDataType(this.value, this.displayName);

  static YourDataType fromInt(int value) {
    return YourDataType.values.firstWhere((e) => e.value == value, orElse: () => YourDataType.notSelected);
  }

  @override
  String toString() => displayName;
}

@freezed
class YourData with _$YourData {
  const factory YourData({
    @Default('') String docId,
    @Default(0) int type, // 0:未選択、1:タイプ１、2:タイプ２、3:タイプ３
  }) = _YourData;

  factory YourData.fromJson(Map<String, dynamic> json) => _$YourDataFromJson(json);
}

// 拡張関数
extension YourDataEx on YourData {
  String get typeString => YourDataType.fromInt(type).toString();
}
```

## 使用
```dart
    YourData data = YourData(type: 1);
    print(data.typeString); // "タイプ１"
```

## 感想
typeを変換するメソッドをそれぞれのviewや、utilなどで持たせるよりもクラス内で定義することによって保守性の高いコードになったかと思います
AWS Free tierで知らない間高額請求があった

## 状況
昨日何となくカード明細を見ていたら見慣れない金額の請求があった。
Amazon Web Serviceから400ドル。

特に何かのサービスを展開しているわけでもなく、LambdaやDynamoDB、Amplifyでハンズオン程度の軽いテストをするアカウントであったためそんな額払われるわけないと思い、急いでコンソールを開いた。

まずは、本当にこのアカウントから支払われているかを確認した。
請求管理のページに入ってみると案の定400ドルの記載があった。

今月の利用状況を見に行ったところ、11/2時点で11月の請求額が10ドルになっていた。このままだとどんどん請求額が増えていくため、サービスを止める必要がある。

## 調査

慌てて履歴を見てみると、RDS(Aurora)が主な使用先となっていた。

まずは、思いつく場所を全部見に行った。


### EC2, RDS
起動中のものなし

Free tierでも複数のものを起動していると課金されることを周知していたため、毎回ハンズオンをやったあとはインスタンスを終了していた。履歴に残っているそれではRDSはどこで使われているの？

### Amplify
RDSとは関係ないところだが、最近よく使っていたものであったため確認を行なった。

３つのアプリケーションが起動中、すぐ止めたかったけど、v1のバックエンド側を手動で止めないとワンボタンでは削除できない。

## 完全停止
どのサービスでどれくらいの金額が発生しているかはともかく、今の状況を完全に停止したかったため、方法を調べた。

以下二つの対応が可能とのこと。

1. Account Close（アカウント削除）
2. Resource Group

ここで、Resource Groupは使うことができなかった。
タグを元にResourceを停止する仕組みであったが、普段はタグをつけてこなかったからだ。

いつも、なんでタグなんかつけているんだろと思いながらも深く調べていなかった...

なので、まずはAccount Closeで全てを停止することにした。
どこで問題が起きているか、自分では見つからなかった上、利用料が発生し続けていたからだ。

## とりあえず停止したが...
全て停止はできたものの、アカウントが論理削除されたため、原因が何だったかを確認することができなくなってしまった。

そのため、後から何が問題だったかについて考えてみた。

### Redshift
確認を行なっていたとき、明示的に立ち上がっているRDSは確認ができなかった。
また、API Gateway・Lambda・DynamoDBの構成でサーバーレスのエンドポイントを作っていたところもあったが、今回はそこでは料金は発生していなさそうだった。

そこで、頭の中をよぎる一つのサービスがあった。
Amazon Redshift.

私は以前以下の記事で、株のダッシュボードを作るため、APIで取得したデータをRedshiftに入れる作業をした。

https://qiita.com/Procrustes5/items/83de9df05c47e488a1a0

無料のクレジットが300ドルあるから、そのまま置いていたが、もしかしたらここで料金が発生しているかもしれないと考えた。上記記事を書いてからはRedshiftを動かしてはいなかったが、もしかしたらここのものが走り続けていた可能性がある。

https://aws.amazon.com/jp/redshift/pricing/

### リージョンの設定
調査を行なっていた時には東京リージョンでだけ調査を行なった。
RDSには何も出ていなかったが、もしかしたら間違えてどこかのリージョンに（おそらくバージニア）RDSを立てて消し忘れていた可能性もあると考えた。

記事を書いているとこっちの可能性が一番高いのではないかと

## 反省点
### 確認不足
まずは、頻繁に利用状況を確認していなかったこと。
毎月請求があってからこれくらい払われているか~程度の確認を行なっていたが、そうするといきなり想定外の使用パターンに対応できなかった。

### 管理不足
上にも書いた通り、タグは必ずつけるべき。何かがあったときに探すのがとても難しかった。
また、監視機能や、利用量の上限設定なども行うべきだった。こうやって書きながらも、実際どのサービスを使ってどんなことをすればいいかわからない。今後きちんと試してみたいと思う。

## おわりに
しかし、こうやって初心者が引っかかりやすいパターンはいっぱい存在しそう。AWSの規模を考えるとこんな何百ドルなんか大したことではないかもしれないが、新卒の社会人には痛すぎる出費。

Free tierなので、もっと初心者にも優しい仕組みにしてくれないか？とAWSを恨んでしまうところもなくはない。
これも安い教わりだと思いながら、今後注意していこう..
ChipWhisperer Level1Kitでチュートリアル(STM32F3 Target Board)

# 目次
1. 購入したらすること
2. ChipWhisperer Install
3. チュートリアルを無事に動かすために

# 購入したらすること

Mouserで購入後1週間程度で届きました。
購入時は大きなダンボールに入ってくるので、それを開封し、
- TargetBoard(自分の場合赤い基盤のもの、取り外し可能なTargetBoardが付いています。以降は例としてSTM32F3を使用していきます。)
- Capture Board(黒い基盤のもの)
- マイクロUSBコード
- ボード間接続用のコード(灰色,金色の端子が付いたもの1本ずつ)

を用意し、以下のように接続します。
灰色のコードを差し込むときは少し捻る必要があるので注意してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/652252/eb1a87ac-11cb-c02a-cee9-bf934e65e72b.png)

# ChipWhisperer Install
次に、解析に必要なツールをWindows上でインストールしていきます。
基本的にhttps://chipwhisperer.readthedocs.io/en/latest/windows-install.html を参照して進めます。

1. https://github.com/newaetech/chipwhisperer/releases にアクセスし、最新のインストーラ―をダウンロードします。（2024年10月時点ではChipwhisperer.v5.7.0.Setup.64-bit.exe)
2. ダウンロードしたインストーラーを実行して、任意の場所を指定し、上のウェブサイトの通りに進めていくとインストールが完了します。
3. (デスクトップにショートカットを作った人はショートカットから)ChipWhispererを起動します。

# チュートリアルを無事に動かすために
ChipWhispererを起動するとJupyter notebookが起動します。
最初はJupyterディレクトリ内にあるチュートリアルを進めることになると思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/652252/cd413cb2-df81-ab4f-e829-4dc47fd6d876.png)

チュートリアルは

- 0 - Introduction to Jupyter Notebooks.ipynb
- 1 - Connecting to Hardware.ipynb

の二つです。0に関しては特にいうこともないので、そのまま動かしてみてください。
1はそのままだと動きません。自分の環境に合わせてコードを修正していく必要があります。
以下でSTM32F3のターゲットボードを使用した場合の修正箇所を解説します。

- Building and Uploading Firmware直下
ここではPLATFORM =, CRYPTO_TARGET=が空白になっていてうまく実行できません。そこで、PLATFORMには自分が使用しているものの名前（一度空白のまま実行すると名前一覧が出てきます）を、CRYPTO_TARGETにはTINYAES128Cなどを指定してあげると動きます。=の後は空白無しなので気を付けてください。
あと、自分の環境では%%bashでは動かなかったため、%%shに変更しています。（これについては公式からもアナウンスが出ています）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/652252/2f6f70c7-d899-63b3-71c2-5c754c6da9da.png)

その続きのコードブロックではコメントアウトされたコマンドが3行あります。ここでも自身が使用する環境に合わせてコメントアウトを外し、パスを適切なものに変える必要があります。

```
#cw.program_target(scope, cw.programmers.XMEGAProgrammer, "path/to/firmware.hex")
cw.program_target(scope, cw.programmers.STM32FProgrammer, "../hardware/victims/firmware/simpleserial-base/simpleserial-base-CW308_STM32F3.hex")
#cw.program_target(scope, cw.programmers.AVRProgrammer, "path/to/firmware.hex")

```
パスは../hardware/victims/firmware/simpleserial-base/以下にある.hexファイルです。

以上です。間違い等あればコメントください。
集約と並べ替えについて

### はじめに
初学者のアウトプット記事となります。
備忘も含め、集約関数、並べ替えについて書こうと思います。
そもそも集約関数とか意味わからんし、どうやって使うん状態だったのでお勉強しました。

### 集約関数ってなに
SQLでデータに対して、何らかの計算、操作を行う場合に「関数」を使います。
いろいろありますが、基本以下の5つを覚えておけば良さげです。

- COUNT: テーブルのレコード(行数)を数える
- SUM: テーブルの数値列の合計する
- AVG: テーブルの数値列の平均する
- MAX: テーブルの任意の列のデータの最大値を求める
- MIN: テーブルの任意の列のデータの最小値を求める

このような集計用の関数を、**「集計関数」** や **「集合関数」** といいます。
つまり「集約」ってのは複数の行を1行にまとめるって覚えればいいですね、はい簡単

### 使い方
意味は分かったけど使い方わからんってなりました。調べました。
下記表の内容は、自分の机の上にあったものなのであまり気にしないでください。
仮に商品テーブルとしましょう。

商品テーブル
| 商品ID | 商品名 | 値段 | カテゴリ |
| :-- | :-: | :-: | :-: |
| 1 | iPhone | 130000 | 電子機器
| 2 | コップ | 200 | キッチン用品
| 3 | グミ | 150 | 食品
| 4 | ティッシュ | 100 | 日用品
| 5 | プルーム・テック | 980 | 電子機器

 ### COUNT関数
 ```
SELECT COUNT(*)
FROM　商品テーブル;
```
```:実行結果
5
```
COUNT( )の中のアスタリスクは、「すべての列」を意味します。この( )の中がCOUNT関数の入力にあたります。
列(カラム)が何個あるか数えてくれます。


### SUM関数

次は合計を求めるSUM関数を使いましょう。

 ```
SELECT SUM(値段)
FROM　商品テーブル;
```
```:実行結果
131430
```
実行結果の131430という数字は値段カラムの合計を表示しています。
ちなみにNULLのレコードがある場合は0として扱われ、NULLは除外されます。

### AVG関数

次は平均を求めます。AVGはAVERAGEの略ですね。中学の時あべらげって読んでました。

 ```
SELECT AVG(値段)
FROM　商品テーブル;
```
```:実行結果
26286.0000 
```
そのまま値段の合計を商品の数(レコード数)で割って求めます。
SUMと同じくNULLは除外されます。

### MAX MIN関数
複数行から最大値、最小値を求めるにはMAX,MINという関数を使います。
はい、SUMの時から使い方は変わりません。

```
SELECT MAX(値段), MIN(値段)
FROM　商品テーブル;
```
```:実行結果
MAX 30000 
MIN 100
```
このように値段の最大値と最小値を出してくれます。
ちなみにSUM/AVGは数値型にしか適用できませんが、MAX/MINはどんなデータ型にも使えます。
日付など順序がつけられるデータであれば、最大値最小値が決まるのでこの2つの関数を適用することができます。

### GROUP BY句
先ほど使ってきた関数はテーブル全体を集約範囲としていましたが、今度はテーブルをいくつかのグループに分けようと思います。
正直このGROUP BYなどのせいでSQLが難しく感じると思います。
実際に見た方がなにやってるかわかりやすいと思うので、下記のコードを見てみましょう。

```
SELECT カテゴリ,  COUNT(*)
FROM　商品テーブル
GROUP BY カテゴリ;
```
```:実行結果
電子機器 2
キッチン用品 1
食品 1
日用品 1
```
カテゴリごとに行（レコード）の数を数えました。
このようにGROUP BYはテーブルをグループごとに分けてくれます。
注意しなければならないのは、必ずGROUP BYはFROMより後ろに書かなければいけません。
(WHEREがあるなら、WHEREの後ろ)

### HAVING句
GROUP BYでテーブルをグループ分けすることができました。
HAVINGはそのグループに対して条件を指定して選択することができます。
条件指定と聞くとWHEREが思い浮かぶかもしれませんが、WHEREは行(レコード)に対してのみしか条件を指定できないためグループに対する条件指定は使えません。

例としてカテゴリごとの合計金額が1000円以上のものだけを表示するには、次のように書きます。

```
SELECT カテゴリ,  SUM(値段)
FROM　商品テーブル
GROUP BY カテゴリ
HAVING SUM(値段) >= 1000;
```
```:実行結果
電子機器 130980 
```

### ORDER BY句
今までは、テーブルを集約したりいろんな条件をつけて加工していましたが、ORDER BYはそれらを並び替えます。
**昇順(ASC)** や **降順(DESC)**　を指定して並び替えてみましょう。

```
SELECT カテゴリ,  SUM(値段)
FROM　商品テーブル
GROUP BY カテゴリ
ORDER BY SUM(値段) DESC;
```
```:実行結果
電子機器 130980
キッチン用品 200
食品 150
日用品 100
```
カテゴリごとの合計金額の降順(大きい順)から並べ替えることができました。

### まとめ
集約関数: データを集計する（例：COUNT、SUM、AVG）。
GROUP BY: データを指定した列ごとにグループ化する。
HAVING: グループ化した結果に対して条件を指定する。
ORDER BY: 結果を並び替える。

間違ってたらすみません！
【PHP】Symfonyで画面間を遷移させるための方法

# 記事作成の背景
ページ遷移の備忘録して残します。

# 完成イメージ
こんな感じで、ページを遷移させるサンプルです。

![サンプル.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1169664/ee017a53-f485-07e4-4342-10e9a9f7e3f6.png)

↑↓

![遷移.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1169664/fb2ba6e4-e128-93f5-830e-99a0311bb152.png)

```templates/conference/index.html.twg
{% extends 'base.html.twig' %}

{% block title %}Hello ConferenceController!{% endblock %}

{% block body %}
<style>
    .example-wrapper { margin: 1em auto; max-width: 800px; width: 95%; font: 18px/1.5 sans-serif; }
    .example-wrapper code { background: #F5F5F5; padding: 2px 6px; }
</style>

<div class="example-wrapper">
    <h1>Hello {{ controller_name }}! ✅</h1>

    This friendly message is coming from:
    <ul>
        <li>Your controller at <code><a href="{{ 'C:/Users/pgrfr/Desktop/hellosymfony6/src/Controller/ConferenceController.php'|file_link(0) }}">src/Controller/ConferenceController.php</a></code></li>
        <li>Your template at <code><a href="{{ 'C:/Users/pgrfr/Desktop/hellosymfony6/templates/conference/index.html.twig'|file_link(0) }}">templates/conference/index.html.twig</a></code></li>
    </ul>
    <div>
        {{welcome_name}}
    </div>
    <div>
        <a href="/conference/second">つぎへ</a>
    </div>
</div>
{% endblock %}

```

```templates/conference/second.html.twg
<h1>{{second_page}}</h1>
<h2>
    <a href="/conference">戻る</a>
</h2>
```

```src/Controller/ConferenceController.php
<?php

namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Doctrine\ORM\EntityManagerInterface;//追加
use App\Entity\Product; // Productエンティティの名前空間を正しく指定

class ConferenceController extends AbstractController
{
    private $entityManager;

    public function __construct(EntityManagerInterface $entityManager){
        $this->entityManager = $entityManager;
    }

    #[Route('/conference', name: 'app_conference')]
    public function index(): Response
    {
        $conferencedata = 'ConferenceController';
        $welcomename = '大谷';

        $id=1;
        $memberlist = $this->entityManager->getRepository(Product::class)->find($id);
        //dd($memberlist->getName());

        $welcomename = $memberlist->getName();

        return $this->render('conference/index.html.twig', [
            'controller_name' => $conferencedata,
            'welcome_name'=>$welcomename
        ]);
    }
    
    #[Route('/conference/second',name:'app_conference_second')]
    public function secondPage():Response
    {
        $secondData = '遷移後のページ';
        return $this->render('conference/second.html.twig', [
            'second_page' => $secondData
        ]);
    }
}

```

以上です。
こんなかんじでページ遷移させることができました、。
ssh暗号方式の速度調査ワンライナー

SSH接続時の暗号化方式がCPU負荷に与える影響を確認するには、以下の手順で各暗号化方式のパフォーマンスを測定できます。


OpenSSHには、暗号化方式のパフォーマンスを測定するためのベンチマーク機能があります。以下のコマンドで、各暗号化方式のスループットを確認できます。

   ```bash
   ssh -Q cipher | xargs -I {} sh -c 'echo {}; ssh -o Ciphers={} -F /dev/null user@hostname "dd if=/dev/zero bs=1M count=1000" | pv -br >/dev/null'
   ```

このコマンドは、サポートされている各暗号化方式について、`dd`コマンドを使用してデータを転送し、そのスループットを`pv`コマンドで表示します。`pv`がインストールされていない場合は、`sudo apt-get install pv`（Debian系）や`sudo yum install pv`（Red Hat系）でインストールしてください。

実行例:
```bash
3des-cbc
Unable to negotiate with 33.33.33.33 port 22: no matching cipher found. Their offer: aes256-gcm@openssh.com,chacha20-poly1305@openssh.com,aes256-ctr,aes256-cbc,aes128-gcm@openssh.com,aes128-ctr,aes128-cbc
0.00 B [0.00 B/s]
aes128-cbc
1000+0 records ins]
1000+0 records out
1048576000 bytes (1.0 GB, 1000 MiB) copied, 3.51765 s, 298 MB/s
1000MiB [ 257MiB/s]
aes192-cbc
Unable to negotiate with 33.33.33.33 port 22: no matching cipher found. Their offer: aes256-gcm@openssh.com,chacha20-poly1305@openssh.com,aes256-ctr,aes256-cbc,aes128-gcm@openssh.com,aes128-ctr,aes128-cbc
0.00 B [0.00 B/s]
aes256-cbc
1000+0 records ins]
1000+0 records out
1048576000 bytes (1.0 GB, 1000 MiB) copied, 3.82126 s, 274 MB/s
1000MiB [ 245MiB/s]
aes128-ctr
1000+0 records ins]
1000+0 records out
1048576000 bytes (1.0 GB, 1000 MiB) copied, 2.79658 s, 375 MB/s
1000MiB [ 327MiB/s]
aes192-ctr
Unable to negotiate with  port 22: no matching cipher found. Their offer: aes256-gcm@openssh.com,chacha20-poly1305@openssh.com,aes256-ctr,aes256-cbc,aes128-gcm@openssh.com,aes128-ctr,aes128-cbc
0.00 B [0.00 B/s]
aes256-ctr
1000+0 records ins]
1000+0 records out
1048576000 bytes (1.0 GB, 1000 MiB) copied, 2.79155 s, 376 MB/s
1000MiB [ 329MiB/s]
aes128-gcm@openssh.com
1000+0 records ins]
1000+0 records out
1048576000 bytes (1.0 GB, 1000 MiB) copied, 2.69718 s, 389 MB/s
1000MiB [ 343MiB/s]
aes256-gcm@openssh.com
1000+0 records ins]
1000+0 records out
1048576000 bytes (1.0 GB, 1000 MiB) copied, 2.72741 s, 384 MB/s
1000MiB [ 338MiB/s]
chacha20-poly1305@openssh.com
1000+0 records ins]
1000+0 records out
1048576000 bytes (1.0 GB, 1000 MiB) copied, 3.17321 s, 330 MB/s
1000MiB [ 294MiB/s]
```

**注意点**：

- 測定時は、ネットワーク帯域幅やディスクI/Oの影響を最小限に抑えるため、可能であれば同一のネットワーク環境と条件でテストを行ってください

- 暗号化方式の選択は、セキュリティ要件とパフォーマンスのバランスを考慮する必要があります
- 一般的に、`aes128-ctr`や`chacha20-poly1305@openssh.com`は高速であり、CPU負荷が低いとされています。ただし、環境や要件に応じて適切な方式を選択してください

これらの手法を用いて、各暗号化方式のCPU負荷やパフォーマンスを評価し、最適な設定を選定することが可能です
【勉強】AWS VPCについて

# VPCとは

VPCとは、Virtual Private Cloudの略で、AWS上でユーザーが自分専用の仮想ネットワーク環境を構築できるサービスである。
このVPCを使用すると何が嬉しいかというと、

- AWSリソースをVPCに配置することで利用することができるようになる
    - 現在、VPCをそもそも必要としないAWSリソース以外は全てVPC上に配置される必要がある
- 自分専用の仮想ネットワーク環境を構築できるため、他のAWSアカウントやインターネットからアクセスされない、安全なネットワークを用意することができる
- また、追加でVPCの様々な機能を使用することで、他からのアクセスをこちら側で制御することができる

という点である。

# VPCの作成

VPCは特定のRegion全体に作成される。つまり、複数のAvailability Zoneをまたいで作成され、VPCを特定のAZに絞ることはできない。

VPCの作成時には、IPv4 CIDR ブロックを決めることになる。(IPv6もあるが省略)
ここで設定するIPv4 CIDR ブロックはプライベートIPアドレスの範囲にある必要があり、以下の3つのクラスのいずれかに属する必要がある。

1. `10.0.0.0/8` (10.0.0.0 〜 10.255.255.255)
2. `172.16.0.0/12` (172.16.0.0 〜 172.31.255.255)
3. `192.168.0.0/16` (192.168.0.0 〜 192.168.255.255)

より大きなCIDRブロック(/16など)は多くのIPアドレスを持つが、過剰なサイズは無駄になることがあるので注意する必要がある。

# 構成要素
## サブネット
VPCの中をさらに分けたネットワークのことを**サブネット**を呼び、これは**AZ単位**に作成される。
サブネットにはIPアドレスの範囲が割り振られ、その範囲内でサブネット内のリソースにIPアドレスが割り当てられる。

サブネットには2種類存在する。
- **パブリックサブネット**
    - 外部との接続を想定したサブネット
- **プライベートサブネット**
    - リソースやデータを外部アクセスから保護するためのサブネット

## インターネットゲートウェイ
VPCとインターネットが通信する際には、このインターネットゲートウェイを通じてやり取りされる。

## NATゲートウェイ
NATゲートウェイはプライベートサブネット内でインターネットへの通信を行いたい場合にパブリックサブネットへ設置する、中継用のゲートウェイである。
NATゲートウェイは単方向通信であり、インターネットからプライベートサブネットへの通信は許可されていない。

プライベートサブネット内のリソースがNATゲートウェイを通ることで、パブリックサブネット内でプライベートIPアドレスが、NATゲートウェイに割り当てられたElastic IPへ変換され、インターネットゲートウェイを通じて、インターネットとの通信が行われる。

## VPCピアリング接続
VPCピアリング接続は独立した2つのVPCを接続し、プライベートアドレスを使って相互に通信する。
ここで、接続する2つのVPCは同じリージョンにある必要がある。リージョンを跨いで通信する場合は、インターリージョンVPCを使用する。

## VPCエンドポイント
VPCエンドポイントは、AWSのマネージドサービスとアクセスする際に使用する。
VPCエンドポイントを使用することで、VPC外にあるAWSのマネージドサービスとインターネットを介さずにアクセスができるようになります。

# VPCのアクセス制御
## ルートテーブル
VPC内の通信では、指定されたCIDR表記のアドレスで通信をルーティングするルールセットを定義する必要があり、これを**ルートテーブル**と呼ぶ。

ルートテーブルではサブネット全体のトラフィックの経路および送信先を定義する。

例えば、サブネット内にあるEC2インスタンスにより外部APIが呼ばれたとした時、このサブネットのルートテーブルにサブネットからインターネットゲートウェイのルートが登録されていない場合はリクエストが失敗する、のである。

インターネットゲートウェイへのルートが登録されていないサブネットが**プライベートサブネット**ということになる。

## セキュリティグループ
セキュリティグループは、アクセスを許可するソースやプロトコル、ポートのルール定義を作成し、EC2やRDSなどのAWSリソースに関連づけることで、ファイアウォールとして動作させることができる。

ルートテーブルはサブネット全体リソースに対してトラフィックが送信先に到達できるかを定義したもので、セキュリティグループは個別のリソースに対してそのリソースの通信を許可・制御する。

## ネットワークACL
ネットワークACLはサブネットに関連づけられ、受信と送信の両方をサブネットレベルで制御することができる。
関連づけられたすべてのサブネットに適用されるため、セキュリティグループよりも広範囲な制御が可能である。
ただし、セキュリティグループとは異なり、通信の状態を記録せず(ステートレスに)動作するため、応答通信にも許可が必要になる。
【Ruby】irbとbinding.irbとは

# はじめに
こんにちは！現在アメリカの大学で語学を学びながら、ソフトウェアエンジニアを目指して独学しているものです。
本日は、Rubyでデバッグに使われる `irb` と `binding.irb` について詳しく解説していきます。実務で使われる機会が多いかはわかりませんが、`irb`は教材でよく登場する基本的なツールですので、使い方を知っておいて損はありません。

# `irb`とは
`irb`（Interactive Ruby）は、Rubyの対話型シェルです。
対話型シェルとは、ターミナル（黒い画面）に入力された内容をすぐに実行し、結果を表示する環境のことです。
`irb`ではRubyコードを1行ずつ実行し、即座に結果を確認できるため、コードの学習や動作確認、デバッグにとても役立ちます。

通常のプログラム実行では、コードエディタ（例：`Visual Studio Code`など）でスクリプトを書き、コマンドラインでファイルを指定して実行しますが、`irb`ではターミナル上で直接Rubyコードを入力し、結果をその場で確認できます。

### `irb`の基本的な使い方
ターミナルで次のコマンドを入力すると、`irb`が起動します。
```bash
$ irb
```
起動後、以下のようなプロンプトが表示され、コードを入力してEnterキーを押すと即座に結果が出力されます。

```ruby
irb(main):001:0> puts "Hello, Ruby!"
Hello, Ruby!
=> nil
```
`=> nil` は、`puts`メソッドの返り値が `nil` であることを示しています。
また、`irb(main):001:0>` というプロンプトは、`irb`の行番号を示しています。

`irb`を終了するには、`exit` または `quit` と入力します
Windowsの場合は`Ctrl`と`d`でも同様に終了することができます。
```ruby
irb(main):002:0> exit
```

# `binding.irb`とは
`binding.irb `は、プログラムの任意の場所で`irb`セッションを開始するメソッドです。
コードの途中に `binding.irb` を挿入すると、その場所で実行が一時停止し、周囲の変数やメソッドの状態を確認できるようになります。
特にデバッグの際に便利で、変数の値や計算の結果をその場でチェックすることが可能です。

```ruby:debug.rb
sum = 0 
outcome = {"参加費" => 1000, "ストラップ代" => 1000, "懇親会会費" => 4000}
outcome.each do |pair|
    sum += pair[1]
    binding.irb  # ここで実行を一時停止して、sumやpairの状態を確認できる
end
puts "合計 : #{sum}"
```
このコードの例で言うと、`outcome`ハッシュの中身を`each`メソッドで1要素ずつ処理し、`binding.irb`の位置で実行を一時停止できます。
1回目の繰り返しでの `pair` の値は` ["参加費", 1000] `で、`pair[1]`には`1000`が代入され、これが`sum`に加算されます。

`binding.irb`があると、その場でコードを検証でき、変数の値や状態を即座に調べられます。
```ruby:bind.rb
# 実行時のイメージ
　1: sum = 0 
　2: outcome = {"参加費" => 1000, "ストラップ代" => 1000, "懇親会会費" => 4000}
　3: outcome.each do |pair|
　4:     sum += pair[1]
=>5:     binding.irb
　6: end
　7: puts "合計 : #{sum}"

irb(main):001> sum # binding.irbで止まっている状態
=> 1000
irb(main):002> pair[0]
=> "参加費"
irb(main):003> exit

```
なお、この例は`each`ブロック内で`binding.irb`が3回実行されるため、exitを3回入力する必要があります。`Ctrl + D`でも同様に終了可能です。

もしデバッグでコードを止めたくない場合は、単に`puts`で確認する方法もあります。
```ruby
sum = 0 
outcome = {"参加費" => 1000, "ストラップ代" => 1000, "懇親会会費" => 4000}
outcome.each do |pair|
    sum += pair[1]
    puts "#{pair[0]}は#{pair[1]}円です"
end
puts "合計 : #{sum}"

# 出力例:
# "参加費は1000円です"
# "ストラップ代は1000円です"
# "懇親会会費は4000円です"
# "合計 : 6000円"
```

# まとめ
`irb`はRubyの対話型シェルで、リアルタイムでコードの動作確認ができる便利なツールです。さらに、`binding.irb`を使うことで、プログラムの任意の箇所で実行を一時停止し、変数や計算の結果を確認できます。
加算子/減算子は$i++,$i--だけじゃない

# 前談
転職して情シスから開発エンジニアに戻った
この前初出社を迎えました。
その時新卒の社員と話したところ、プログラムの話をしました。
いきなりプログラムの話とは、やっぱり開発エンジニアが150名以上いると違うんですかね。
僕の新卒は上司と二人だったので、ある意味プログラムとアニメとかの話しかしませんでしたねw

# 本編
新卒の社員とプログラムの話をした時にPHPリファレンスの話になり、加算子・減算子の話をしました。

"$i++と++$iって同じじゃないんですか？"
確かにプラスすることには変わらない。だが違うのだ。

違うのは加算されるタイミングなんだよ。
僕にはリファレンスお兄さんことA上司がいたから知っている。

テストコードは以下の通りです。
```php
<?php
    echo '$i++の場合'."\n";
    $i=5;
    var_dump($i++);
    var_dump($i);
    
    echo '++$iの場合'."\n";
    $i=5;
    var_dump(++$i);
    var_dump($i);
?>
```

出力結果：
```
$i++の場合
int(5)
int(6)
++$iの場合
int(6)
int(6)
```


# 余談
実は速度も違うらしい。僕は知らなかった。
2008年の記事なので、今のPHPのバージョンで違いはあるのか次回確かめてみよう。

https://kaworu.jpn.org/kaworu/2008-01-29-2.php
01.PHPってなに？

## PHPって何？
PHPは、バックエンドで動くプログラミング言語です。
バックエンドとは、ざっくり説明すると、データの保存や出力といったユーザーが目に見えないところで行っている処理を行っている部分のことです。(何かのデータを保存したり、取得したデータを出力したり…)

反対に、ユーザーが目に見える部分はフロントエンドといいます。(ブログやWebサイト。いわゆる画面デザインを作っているものです。)

## PHPはどこで使われている？

WikipediaやFacebook、Slackで使用されている言語です。


## PHPが得意なこと

- Webアプリの開発
- WordPressオリジナルテーマの開発

## PHPが苦手なこと

- デスクトップアプリの開発
- スマホアプリの開発

## 勉強するにあたっての前提知識

勉強する際はHTML・CSS・JavaScriptがある程度できれば問題ないと思います。

これらの勉強はProgateや、侍テラコヤというサイトで勉強するのがおすすめです。(有料)
独学で進めていける方はProgateで、自分で進めていけるか不安という方は侍テラコヤがおすすめです。

後者はサービス内で質問掲示板のようなところで質問できるサービスや、Web会議を予約すればエンジニアの方に直接質問できるサービスがあるので、これらを活用してスキルアップを目指しましょう。
Python 不動産情報ライブラリAPIを使ってみる 機能検討編

私は不動産が大好きである。
日本では空き家問題が取りざたされているが、なぜ空き家を放置してしまうのだろうか。
空き家を持て余している方の大半以上が、「相続」ではないだろうか。
そしてなぜ放置してしまうのかと考えた時に、「面倒だから」という理由はよく聞こえてくるが、本当にそうだろうか・・・
それは<strong>「空き家に価値はないから売れない」</strong>という思い込みではないだろうか。
よく「その空き家いくらで売れるかチェック」みたいなものを見かけるが、それよりも<strong>取引実績に基づいたデータを見る方が説得力がある</strong>という仮説の下、<strong>「空き家流通促進ツール」</strong>としてのアプリを考えてみる。

目次

1.API操作説明
2.目的に応じたAPIの選定
3.フレームワークの選定（GPT調べ）
4.選定理由と次回記事

1.API操作説明
-
不動産情報ライブラリでは、Webサービスや研究開発等にご活用いただくため、不動産取引価格情報や地価公示・地価調査、国土数値情報等のデータを公開APIとして提供している。
HTTPリクエストヘッダーにサブスクリプションキーを入力して利用する。
詳細についてはリンク先を参照。<a href="https://www.reinfolib.mlit.go.jp/help/apiManual/">⇒ API操作説明</a>

【用意するもの】
・HTTPクライアントツール（Pythonの場合、requests等）
・サブスクリプションキー（APIキー）

2.目的に応じたAPIの選定
-
冒頭でも書いたとおり、今回のアプリを使うことにより、所有する空き家に価値があるという認識を持ってもらうことで、行動変容させることが目的である。
行動変容するためには、利用者へのインセンティブが必要であり、
今回の場合、<strong>「有価物として認識させる」</strong>ことが最も重要であり、そのためには<strong>自分が所有している空き家周辺での不動産取引の実績</strong>を見てもらうのが一番説得力があるんじゃないかと考える。
故に、必要な情報を以下のとおり定義する。

【必要な情報】
・都道府県名、市町村名　⇒　都道府県内市町村一覧取得API
・取引価格 ⇒ 不動産価格（取引価格・成約価格）情報取得API

今回は上記２つのAPIを使った「行動変容アプリ」を作成することとして進める。

3.フレームワークの選定
-
Pythonでよく使うフレームワークとして、Django、Flask、Streamlit等があるが、
ChatGPTさんに各々のフレームワークについて解説をお願いしてみる。

【Django】
フルスタックなPythonのウェブフレームワークで、大規模なウェブアプリケーション開発に適しています。主な特徴は以下の通りです。

1.フルスタックフレームワーク: テンプレートエンジン、データベース接続、管理インターフェースなど、ウェブ開発に必要な機能が一通り揃っています。

2.MTV（Model-Template-View）アーキテクチャ: アプリケーションの構成が整理されていて、保守性が高いです。モデルを使ってデータベースと連携し、ビューでビジネスロジックを処理し、テンプレートでHTMLを生成します。

3.セキュリティ: Djangoには、クロスサイトリクエストフォージェリ（CSRF）やSQLインジェクションといった一般的な脆弱性に対する保護機能が備わっています。

4.標準的な管理画面: Djangoには、モデルのデータを簡単に管理できる管理インターフェースが標準で用意されています。

【Flask】
Flaskは、軽量で柔軟なPythonのマイクロフレームワークで、特に小規模でシンプルなアプリケーションやプロトタイピングに向いています。主な特徴は以下の通りです。

1.マイクロフレームワーク: 必須の機能が少なく、必要に応じて拡張機能を追加できるため、柔軟性が高いです。

2.シンプルで直感的: シンプルなルーティング機能やテンプレートエンジン（Jinja2）を提供し、直感的にアプリケーションを構築できます。

3.拡張性: 必要な機能を自分で選んで追加する設計なので、データベースや認証、セッション管理なども自由に設定可能です。

FlaskはAPIサーバーの構築やシンプルなウェブサイト、シングルページアプリケーション（SPA）のバックエンドなどに適しており、小規模から中規模のプロジェクトで利用されます。


【Streamlit】
Streamlitは、データサイエンスや機械学習アプリケーションを簡単に構築できるPythonのライブラリで、特にインタラクティブなダッシュボードやデータの可視化を得意とします。主な特徴は以下の通りです。

1.データ可視化向けに最適化: データフレームやプロットなどを簡単にウェブ上に表示でき、短いコードでインタラクティブなビジュアライゼーションが作成できます。

2.素早いプロトタイピング: 複雑なHTMLやCSSの知識が不要で、Pythonコードだけで簡単にウェブアプリを構築できます。

3.UIコンポーネントの豊富さ: スライダーやボタン、セレクトボックスなどのUIコンポーネントが用意されており、ユーザーからの入力を容易に受け付けられます。

Streamlitは、データ分析や機械学習モデルの結果を視覚的に示すためのアプリや、チーム内で簡単にデータを共有するためのツールとして利用されることが多いです。

4.選定理由と次回記事
-
今回のアプリは試作品レベルのものを想定しており、特に重厚感あるフレームワークは必要ないため、Pythonだけで書けて、素早いプロトタイピングが可能な <strong>Streamlit</strong> とする。

次回、コーディング編を書いていく