OmniAICreator/Qiita-1.07M huggingface dataset:
MINRES法を実装してみた。

# MINRES法とは？

MINRES法（最小残差法）とは、krylov部分空間法と言われる手法の一つです。
以下のように、正方対称行列の正規方程式を扱う計算です。


```math
Ax = b,\;\; A \in \mathbb{R}^{n \times n} :: \text{Symmetric}
```

# 実装

JuliaでのシンプルなMINRES法の実装は以下の通りです。
この実装はちゃんと収束しますが、かなりNaiveです。
また、実際には、`k_max`までで収束しない場合に解の改善を行うようにすべきですが、この実装は短いコードで作りたかったので削減しています。

[参考](http://www.jicfus.jp/wiki/index.php?MINRES%20%E6%B3%95)
[自ページ](https://ay-aki.github.io/julia-learning/page-julia-numericalanalysis-MINRES.html)

```julia
using LinearAlgebra

function simple_minres(
      A::AbstractMatrix
    , b::AbstractMatrix
    ; k_max = 10
    , tol   = 1e-7
    , n     = size(A, 2)
)
    pprev, prev, cur, next = 1, 2, 3, 4

    #    k-2           k-1           k             k+1
    #    -1            0             1             2           (k=1)
    x = [zeros(n, 1) , rand(n, 1)  , zeros(n, 1) , zeros(n, 1) ]
    v = [zeros(n, 1) , zeros(n, 1) , b-A*x[prev] , zeros(n, 1) ]
    β = [0.0         , 0           , norm(v[cur]), 0           ]
    γ = [0.0         , 1           , 1           , 0           ]
    σ = [0.0         , 0           , 0           , 0           ]
    ω = [zeros(n, 1) , zeros(n, 1) , zeros(n, 1) , zeros(n, 1) ]
    α = [0.0         , 0           , 0           , 0           ]

    rknorm = η = β[cur]
    
    for k = 1:k_max
        v[cur]  = (1 / β[cur])*v[cur]
        Av      = A*v[cur]
        α[cur]  = ((v[cur]')*Av)[]
        v[next] = Av - α[cur]*v[cur] - β[cur]*v[prev]
        β[next] = norm(v[next])
        δ       = γ[cur]*α[cur] - γ[prev]*σ[cur]*β[cur]
        ρ1      = √(δ^2 + β[next]^2)
        ρ2      = σ[cur]*α[cur] + γ[prev]*γ[cur]*β[cur]
        ρ3      = σ[prev]*β[cur]
        γ[next] = δ / ρ1
        σ[next] = β[next] / ρ1
        ω[cur]  = (v[cur] - ρ2*ω[prev] - ρ3*ω[pprev]) / ρ1
        x[cur]  = x[prev] + γ[next]*η*ω[cur]
        rknorm  = abs(σ[next])*rknorm
        η       = - σ[next]*η

        if (rknorm < tol) println("n_ittr = $k"); break; end

        pprev, prev, cur, next = prev, cur, next, pprev
    end
    return x[prev]
end
;
```

以下のようにすると実際に収束することが確認できる。

```julia
A = Symmetric(rand(10, 10)); b = rand(10, 1); 
x = simple_minres(A, b, k_max=20)

norm(A*x - b)
```
端的に話すための4STEP

# はじめに
仕事において、簡潔に報連相したり、相手に伝わりやすいような言い回しにしたりすることは非常に重要です。
ただ、上司から「**で、結局何が言いたかったの？**」と言われた経験がある方も多いんじゃないでしょうか？
そんな方に参考になるような以下の書籍から「**端的に話すための4STEP**」をご紹介します。

**１分で話せ/伊藤 羊一：著者**

https://www.sbcr.jp/product/4797395235/

# STEP1 伝えるための基本事項
### **伝える相手はどんな人か？**
**立場**/**興味**/**求めるもの**/**専門的知識の理解度**/**何に対してネガティブな反応を示すか**などを意識すれば、おのずと言葉選びや話しの構成、説明の具体性などが定まって伝えやすくなります。

### **ゴールは何か？**
仕事において、話を相手に理解してもらうためだけに会話をすることは多くありません。
ですので、その先のゴールが何になるのかを明確にする必要があります。
例えば、書籍の中ではこんな例が挙げられていました。
>**A「営業部と連動して、より欠品に対して迅速に対応できるシステムを開発したいのです。」
B「営業部と連動して、より欠品に対して迅速に対応できるシステムを開発したいのです。つきましては、営業部長の〇〇さんに部長からもお話しいただけませんか。」**

この例では、話におけるゴールは営業部長の〇〇さんに部長からお話しをしてもらうことですね。
聞き手がこの話を聞いて何をしたらいいのか、明確なアクションを示すことです。

# STEP2 1分で伝える　左脳が理解するロジックを作る

### てっぺんのないピラミッドになっていないか
![ピラミッド.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3065056/d733cdba-c4a1-835d-3abe-9ce9c3672f54.png)

いわゆる**ピラミッドストラクチャー**と言われるもので、ロジカルシンキングを勉強した人は多くがご存じかと思います。
話が伝わりにくい人はこのてっぺんとなる「**主張**」が抜けていることが多いです。
「お得意さんが喜んでました！」とか「売り上げがこれだけ上がりました！」とかはデータ(根拠)であって、主張ではないです。その根拠は何の主張に繋がるのかを意識して伝える必要があります。

### 事実やデータは結論ではない
では、主張(結論)ってなんでしょう？
多くの人はこれを勘違いしていて、「**知識**」もしくは「**情報**」を結論と思い込んでいます。
知識は「**自身の経験から既に自分の中にあるデータ**」。
情報は「**自分の外にあるデータ**」。
書籍での例を引用します。

>**たとえば仕事をしていて眠い時。「情報」として「あれ、僕は今、眠いぞ」と気づく。
でも、寝てはいられない。「知識」として、「カフェインをとると、眠気がとれる」ということを知っている。で、この2つの、「情報」と「知識」を頭の中でがっちゃんこして「よし、(カフェインが入っている)コーヒーを飲もう！」と決めて、行動するわけです。**

つまり、知識と情報を加工してこんなアクションをしようと決めたことが結論になるわけです。

### 頑張ったことは話すな
>**報告するにせよ、提案するにせよ、私たちはつい「自分が頑張ったこと」を話し始めます。
でも、それは、相手が聞きたいことでしょうか？**

タスクに関する**プロセス**を話しても上司からしたら要らない情報になることが多いです。
頑張ったプロセスではなく、その結果から何を報告するべきかを意識しましょう。

# STEP3 相手を迷子にさせないために「スッキリ・カンタン」でいこう
### 言葉もスライドも「スッキリ」が鉄則
>**私たちは、何か熱量を持って伝えようとする時、ついつい、多くの言葉を使おうとします。ただ、聞き手が集中して聞いてくれていなければ、多くの言葉を使うと逆にノイズになっていまいます。**

書籍の中では「**人はあなたの話の80%は聞いていない**」と断言しています。
20%しか聞いてくれていないのに、情報をたくさん伝えようとしても無駄なのは分かりますよね。
そこでカギとなるのが、**スッキリ**です。
スライドにおいては「**読まずにすっと**」言葉が入ってくるかが一つの基準として非常に大事になってきます。

### カンタン -中学生が理解できる言葉しか使わない
横文字たくさんのプレゼンって頭に入ってこないですよね？
難しい言葉を使うことによって、その意味を脳内で変換する必要があるので、聞き手が話についていけなくなる「**迷子**」になってしまうのです。
専門用語を除いて、カンタンな言葉にできるものは**中学生が理解できる**を基準に考えましょう。

# STEP4 右脳を刺激してイメージを想像させよう
### ピラミッドは、3段で作ろう -「結論」→「根拠」→「たとえば」の3段ピラミッド
![3段ピラミッド.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3065056/4eb71de8-75d5-fac1-8d7e-780bdf8aa862.png)
聞き手がイメージがしやすい話し方をすることで各段に物事が伝わりやすくなります。
そのために大事なことはピラミッドストラクチャーを3段用意することです。
そして、その**3段目には事実(例)を挙げる**ことが大事です。

# おわりに
いかがだったでしょうか。
今回は紹介しませんでしたが、書籍の中では実践編ということで実際のシチュエーションに分けた会話例が書かれていて非常にイメージしやすく、勉強になりました。
伝え方に悩んでいる方はぜひ読んでみてください。
#03 J-STAGEから論文タイトルで検索をしてcsvファイルでDL

# はじめに
J-STAGEに建築学会の黄表紙も公開されるようになったので、都市計画論文集と並んで検索とかがしやすくなりました。ただし、既往研究をあさるときになかなかリストにしにくいと思っていた（コピペは面倒）ので、APIを使って楽に既往研究のリストを作ることができるようにしようと思ったのがきっかけ。

仕様は以下のHPに割と丁寧に書いてある。
https://www.jstage.jst.go.jp/static/pages/JstageServices/TAB3/-char/ja

APIは結局XMLを返してくるので、ブラウザでURLを入れてXMLをエクセルで加工としていたんだけどめんどくさくなってきたので以下のプログラムを作成。

# プログラム
```python
### 利用するライブラリのインポート
# インストールしてなければ
# !pip install xmltodict
import xmltodict
from collections import defaultdict
import pandas as pd
import requests as re

### APIからXMLの取得
# 検索対象にする雑誌(都市計画論文集→2185-0593、日本建築学会計画系論文集→1881-8161)
ISSN = "1881-8161"
# 検索ワード
word = '"立地適正化"'
# 取得するためののURL
URL = "https://api.jstage.jst.go.jp/searchapi/do?service=3&issn=" + ISSN + "&article=" + word
# 取得
result = re.get(URL)

### 取得データの加工（著者、年、タイトル、雑誌名、巻号、ページ数、doi）
xml_dict = xmltodict.parse(result.content)
data = defaultdict(list) 

# 取得データからリストに変換
for article in xml_dict["feed"]["entry"]:
  data["name"].append(article["author"]["ja"]["name"])
  data["pubyear"].append(article["pubyear"])
  data["title"].append(article["article_title"]["ja"])
  data["journal"].append(article["material_title"]["ja"])
  data["vol"].append(article["prism:volume"])
  data["No"].append(article["prism:number"])
  data["page_s"].append(article["prism:startingPage"])
  data["page_f"].append(article["prism:endingPage"])
  data["doi"].append(article["prism:doi"])

# データをデータフレームにしてpandasでcsvとして保存
df = pd.DataFrame.from_dict(data)
df.to_csv("result.csv")
```

検索ワードとISSNは適宜変更してください。

# 参考
・API仕様書
https://www.jstage.jst.go.jp/static/pages/JstageServices/TAB3/-char/ja
・J-STAGE WebAPIで「ポルノ」論文567本のデータを取得する【Python】
https://note.com/h_keisuke/n/n92c2396231cf

# 困りごと（今後解決したい）
・論文タイトルは取得できるが副題が取得できない。APIでは取得できなそう？

それでは
AWS上のUbuntuインスタンスに接続する方法 - 初学者向け


## ステップ 1: AWSでUbuntuインスタンスを作成する

インスタンスとは、一つの仮想サーバーのことを指します。Amazon Web Services（AWS）のEC2サービスを使用することで、簡単にインスタンスを作成し、任意の操作を実行することができます。ここでは、UbuntuのOSがインストールされたインスタンスを作成します。

1. AWSのマネージメントコンソールにログインします。
2. 「サービス」から「EC2」を選択します。
3. 「インスタンス」ページに移動し、「インスタンスの作成」をクリックします。
4. Ubuntu Serverを選択し、インスタンスの詳細設定を行います。

## ステップ 2: キーペアの生成とダウンロード

キーペアとは、公開鍵暗号方式に基づいて生成される一対の鍵のことを指します。一方の鍵を公開鍵、もう一方を秘密鍵と言います。公開鍵で暗号化されたデータは対応する秘密鍵でしか復号化できないため、この鍵の組み合わせを使って安全に情報を交換します。AWSでは、インスタンスへのログイン認証に公開鍵暗号方式を利用します。そのため、インスタンスを作成する際にキーペアを生成し、秘密鍵（.pemファイル）をダウンロードします。この秘密鍵はインスタンスに接続する際に必要となるため、絶対に紛失しないように保管してください。

1. インスタンスの作成時に、新しいキーペアを生成してダウンロードします。このキーペアはインスタンスに接続するための鍵となります。ここではキーペアの名前を「AWS-Ubuntu」とします。

## ステップ 3: インスタンスへの接続

まずは、ターミナルを開きます。ターミナルとは、コマンドラインから操作を行うためのツールです。Macでは「ターミナル」アプリケーション、Windowsでは「コマンドプロンプト」や「PowerShell」がこれに該当します。

1. ダウンロードした.pemファイル（ここでは「AWS-Ubuntu.pem」）へ

のパーミッションを変更します。この操作は、.pemファイルを安全に使用するために必要です。以下のコマンドを実行します（「[path_to_pem_file]」はダウンロードした.pemファイルのパスに置き換えてください）：

```
chmod 400 [path_to_pem_file]
```

2. sshコマンドでAWSのUbuntuインスタンスに接続します。sshとは、遠隔地のサーバーに安全に接続するためのプロトコルです。以下のコマンドを実行します（「[path_to_pem_file]」はダウンロードした.pemファイルのパス、「[public_IP]」はAWSから割り当てられたインスタンスの公開IPアドレスに置き換えてください）：

```
ssh -i [path_to_pem_file] ubuntu@[public_IP]
```

また、ここで使用される「ubuntu」は、接続先のユーザー名を指します。AWSのUbuntuインスタンスのデフォルトユーザー名は「ubuntu」なので、このように接続します。

## ステップ 4: インスタンスでの作業

コマンドラインで接続が成功すると、以下のような表示が出てきます。

```
Welcome to Ubuntu 22.04.2 LTS (GNU/Linux 5.19.0-1025-aws x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage
```

これは、AWSのUbuntuインスタンスへの接続が成功し、操作が可能な状態であることを示します。インスタンスで作業が必要な場合は、この状態で任意のコマンドを実行できます。

作業が終わったら `exit` コマンドでインスタンスからログアウトします。なお、必要なデータは適切に永続化しておいてください。それ以外のデータはインスタンス停止時に失われますので注意してください。

以上で、AWS上のUbuntuインスタンスに接続し、作業する方法の説明を終わります。インスタンスの管理やデータの永続化など、さらに詳しい操作が必要な場合は、AWSの公式ドキュメントや、それを解説した教材を参照してください。

また、本記事で言及したIPアドレスは実際にはAWSから割り当てられたIPアドレスを使用してください。IPアドレスとはインターネット上の端末を一意に識別するためのアドレスで、IPv4では「172.16.254.1」のように4つの数値（0〜255）で構成されます。これにより、世界中のどのデバイスからでも特定のデバイスやサーバーに接続することが可能となります。

これで終わりです。AWS上のUbuntuインスタンスに接続して作業を行う手順について理解できたことを願っています。
北陽電機製2D-LiDAR（UTM-LX-30）をROSで動かす方法ー２

# はじめに
Ubuntu 18.04 LTS
ROS melodic
https://qiita.com/yacht0425/items/594ba89deddca9b18e34
でurg_nodeはインストール済み

https://qiita.com/yacht0425/items/41e54a0e5eade05b7479
でROSのワークスペースは構築済み

# １．ソースコードを追加する
urg_node_test.cppという名前のソースコードを追加した

```php:~/ros_ws/src/urg_node_test.cpp
#include <ros/ros.h>
#include <geometry_msgs/Twist.h>
#include <sensor_msgs/LaserScan.h>

void cbScan(const sensor_msgs::LaserScan::ConstPtr &msg)
{
  int i = msg->ranges.size() / 2;
  if (msg->ranges[i] < msg->range_min || // エラー値の場合
      msg->ranges[i] > msg->range_max || // 測定範囲外の場合
      std::isnan(msg->ranges[i])) // 無限遠の場合
  {
    ROS_INFO("front-range: measurement error");
  }
  else
  {
    ROS_INFO("front-range: %0.3f",
      msg->ranges[msg->ranges.size() / 2]);
  }
}

int main(int argc, char** argv) {

  ros::init(argc, argv, "urg_test_node");
  ros::NodeHandle nh;

  ros::Subscriber sub_scan_ = nh.subscribe("scan", 5, cbScan);

  ros::spin();

  return 0;
}

```


# ２．CmakeLists.txtも忘れずに編集
以下の２つを追加
```php:~/ros_ws/CmakeLists.txt
add_executable(urg_test_node src/urg_test_node.cpp)

target_link_libraries(urg_test_node
  ${catkin_LIBRARIES}
)

```

# ３．ターミナルを開き以下を実行
```php:terminal 1
rosrun
```
```php:terminal 2
rosrun urg_node urg_node _serial_port:=/dev/ttyACM0
```
```php:terminal 3
rosrun rosrun utm_lx_30 urg_test_node
```

urg_nodeはシリアルに権限を与えるのを忘れないこと


# 参考文献
https://at-wat.github.io/ROS-quick-start-up/ros-urg.html
【Linux】Bluetooth HCIスヌープログの取り方

# はじめに
LinuxでBluetoothのHCIスヌープログを取得する方法をまとめました。

※Androidで取得する方法もあります → https://qiita.com/KentaHarada/items/42ed619e8f571d1de845


# 確認環境
* Ubuntu 22.04.2 LTS
* Thinkpad X260
* WireShark v3.6.2


# Bluetooth HCIスヌープログとは？
HCI(Host Controller Interface)はBluetoothのプロトコルの一種で
BluetoothプロトコルスタックとBluetoothのチップ間のプロトコルです。
エアーを飛んでいるパケットとは異なりますが、高価なアナライザーを用いずにBluetoothの低レイヤの解析を行うことができます。

<img width="726" alt="スクリーンショット_2020-05-04_15_30_20.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/102273/62ab7869-086e-c4f3-eab7-732ffd4c2e63.png">

# どんな時に使うの？
Bluetoothデバイスの接続不良などの問題解析に使うことがあります。

例えば・・・
* LEのAdvertiseのデータが飛んでいない
* 接続したけどすぐに切断されてしまう
といったシチュエーションで使うことが多いです。

# 1. WireSharkをインストールする
取得したログを解析するために使うソフトウェアです。以下のコマンドでインストールします。

```
$ sudo apt install wireshark
```
![Screenshot from 2023-06-28 13-08-49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/102273/3b941016-79f5-5621-1f1d-8f6faac5ca27.png)


# 2. Bluetoothをオンする

Ubuntuの設定画面からBluetoothをオンにします。
![Screenshot from 2023-06-28 13-27-22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/102273/2e69d191-21b9-cc1e-cbfd-7034aed40b05.png)


# 3. HCIスヌープログの取得
`btmon`コマンドでログの取得を開始します。指定したファイルの中にログが記録されます。

```sh
$ sudo btmon -i hci0 -w hcidump.log
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/102273/5eb1882c-f9c2-9ed7-3fa0-3d54e6360aec.png)

# 4. ログを取りたいBluetoothの操作を行う
Linux端末とBluetooth機器を使って目的のログを取るための操作を行います。


# 5. 取得したログの確認
コマンド `btmon -r` でログを確認することができます。

```sh
$ btmon -r hcidump.log
```

![Screenshot from 2023-06-28 13-17-15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/102273/5e651d2d-8d41-97a7-76dc-c2ecaab9f5b7.png)

# 6. Wiresharkでログを確認する
取得したログが時系列で表示されます。
ログの詳しい意味を知りたい時は [Bluetooth Core Spec](https://www.bluetooth.com/specifications/specs/?keyword=core+specification) を参照してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/102273/7382c495-0d27-3e99-1fe3-2e51f9eb386d.png)
シェアボタンのアイコンはどれを使えばいいのか問題

![Screenshot from 2023-06-27 14-48-13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151137/53a810cf-8e29-04a4-f98b-130795f24ab0.png)

ウェブサイトやアプリでよく見かける「シェア」ボタンですが、
そのアイコンについては、未だ**OSやサービス間で統一されておらず**、どれを使うべきか悩ましい問題です。


# 歴史

「シェアボタン」という存在自体が登場しはじめた頃、各所で色々なアイコンが生み出されました。

![Screenshot from 2023-06-27 14-53-07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151137/98ede5b9-3b78-3e9e-33a5-bdb816a76123.png)

当時はどのアイコンも何の機能のためのボタンなのか理解できず、いちユーザーとしても不便だった覚えがあります。

なぜシェアボタンだけこんなにアイコンが生み出されてしまったかというと、恐らく「シェア」というものが、現実世界に物理的な状態で存在しないものだからじゃないかと思います。

現実世界に物理的に存在するものであれば、例えば、「音量調整」なら「スピーカー」のアイコン、「バッテリー残量」なら「乾電池」のアイコンといったように簡単なわけです。

![Screenshot from 2023-06-27 14-53-07_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151137/57e32c2e-346c-98bc-1fa0-61d73a8748c5.png)

やがて少しずつ収束していき、現在では主にiOSとAndroidで採用されていたアイコンが生き残っているようです。

# 有名サイトではどちらが使われているか

傾向を示せるほどサンプルを集めるのは大変なので辞めましたが、
ざっと見たところ、iOS方式、Android方式どちらのアイコンが使われているケースも見られました。

また、User-Agentによって、OSごとに表示するアイコンを分岐させているケースもあるようです。

# アンケート

代わりに、Twitterでアンケートをとってみました。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">お願いします！</p>&mdash; らいね (@Laineus) <a href="https://twitter.com/Laineus/status/1673495749848616960?ref_src=twsrc%5Etfw">June 27, 2023</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

結果は、**Android方式のアイコンが63.5%で最も馴染みがある**ようです。

日本のOSシェアは2023時点で7割がiOSだそうですので、
それに逆転する形の結果が出ていることから、Android方式のアイコンは利用OS問わず認知されていると考えられます。

*※これは単なる自己申告のアンケートですので、アプリ画面上で行うようなユーザーテストとは違う結果を示す可能性があります。*

# どうするべきか
OS間で統一されていない以上、**OSごとにアイコンを出し分けるのは無難**な選択です。

しかし、アンケートの結果の通り、**一般に認知されているであろうAndroid式のアイコンに統一しても問題ないんじゃないか**と思います。

また、②のiOS式のアイコンはアップロードボタンと被っている点が問題だと思われます。
③も、「新しいタブで開く」のアイコンと似ている気がします。

恐らくこのような状況でも、Appleは頑なに自社規格を使い続けるでしょうから、この先もしばらくは両方のアイコンが混在すると予想されます。

アイコンは、ユーザーが一目で理解できるものを選択する必要があります。
参考になれば幸いです。

# 参考

- [[Shortudy] Why use different share icon in iOS and Android?](https://medium.com/@berryverylucky/shortudy-why-use-different-share-icon-in-ios-and-aos-a273be04aacc)
- [【2023年2月】OSのシェア率ランキング](https://www.qbook.jp/column/1593.html)
- [&quot;Share&quot; Icon - Download for free &ndash; Iconduck](https://iconduck.com/icons/68205/share)
タグマネジャーのプレビューをChromeで行った際にスマホ表示にする

- DevToolsを起動
- [︙] 
- [その他のツール]
- ［ネットワーク状態］

ユーザーエージェント
- [ ] ブラウザのデフォルトを使用　←　チェックを外す
- ユーザージェントを選択する
よく使うMavenのコマンド

# 環境
- JDK 17
- Maven
- macOS Ventura
- Spring Boot 3.1.1

> 多少バージョンが違ってても同じだと思います。

# Mavenのインストール
```shell
brew install maven
```

# JARへのパッケージング
```shell
mvn clean package
```

テストの実行をしたくない場合は👇

```shell
mvn clean package -DskipTests=true
```

# コンパイル成果物の削除
```shell
mvn clean
```

# テストの実行
```shell
mvn clean test
```

# Spring Bootアプリの実行
```shell
mvn spring-boot:run
```

# ライブラリのダウンロードだけ行う
```shell
mvn dependency:copy-dependencies
```

# ライブラリの一覧を見る
```shell
mvn dependency:tree
```

# 実行
```shell
mvn exec:java -Dexec.mainClass=メインクラス名
```

更に詳しいことは[CLOVER](https://kazuhira-r.hatenablog.com/entry/20131103/1383485235)へ
ABC練習

ABC289B
```diff_python
#答えリストと保持用リストの2つを用意(？リストを用意する場所)
#tmpリストにいったん格納
#リストaの中に数値があれば続行、
#なければtmpリストを逆順にansリストに格納し、tmpリストを空にする
#これをnまで繰り返す

n,m = map(int,input().split())
a=list(map(int,input().split()))
tmp=[]
ans=[]
for i in range(n):
  tmp.append(i+1)
#iは0から始まるため+1
  if i+1 in a:
#i+1 in aはリストaが整数の要素のみを持つ場合に使える。空白であったりするとエラーに。
    continue
  else:
    tmp.reverse()
    ans+=tmp
    tmp=[]
print(*ans)
#*ansとすることでリストの要素をスペース区切りで出力
```
**ABC273B**
10で割ることを繰り返すことで第何桁とかを気にしなくてよくなるのか。これは賢い。覚えておこう。小数点の部分が目印になるのね。
```diff_python
x, k = map(int, input().split())
for i in range(k):
    if x % 10 >= 5:
        x = x // 10 + 1
    else:
        x = x // 10
print(x * 10 ** k)
```
**ABC275B**
これは特に問題なし。しいて言えば計算量について勉強しておきたい。
PHPのvar_dumpをconsole.logに出力する

# はじめに
PHPの`var_dump`の結果を`console.log`に出力する備忘録です。
`console.table`等への変換は各自でお願いします。
なお、元々エラーウィンドウを表示させる場面で作成したので、`echo`が汚れるのは悪しからず。

流し見たんですが、全く同じ投稿は無かったようなので投稿。
もし先駆者様いらっしゃったら誠にごめんなさい。

---

# ソース
```php:php
$ary = array(
    'key' => 'value',
);

ob_start();
var_dump($ary);
$out = ob_get_clean();
$out = str_replace(PHP_EOL, '\n', $out);

$out = htmlspecialchars($out);
//$out = str_replace('"', '\"', $out);
//特殊文字がなさそうならダブルクォートのみの変換でもいい

echo "<script type=\"text/javascript\">console.log(\"{$out}\");</script>";
```

---

# 履歴
2023/06/28 初稿
ABC307 - B - racecar 自己解法

# 問題
https://atcoder.jp/contests/abc307/tasks/abc307_b

# 考察
文字列を組み合わせて回文を作ることができるか判定してくださいという問題です。$N≦100$であることから、全探索しても十分間に合いそうです。2重ループなどを使用して回文ができる文字列があるか全探索していきましょう。
注意したい点として、組み合わせる文字列の添え字$i$,$j$は異なる者同士である点に注意してください。2重ループで回すときはそこだけループをスキップすればいいです。
回文判定については下記の記事が参考になります。

https://www.delftstack.com/ja/howto/cpp/cpp-palindrome/


# 提出コード(コンテスト後)

https://atcoder.jp/contests/abc307/submissions/43016725

ご不明点などがあれば教えていただけると幸いです。

# 参考

https://www.delftstack.com/ja/howto/cpp/cpp-palindrome/
ESP-NOWで三路スイッチモドキを作る(スイッチ側)

ブログの日記にて三路スイッチのＩＯＴ化について書いたのですが、時々ご覧になる方が
いる様なので、スイッチ側の簡易コードをESP-NOWで書きましたので参考にして頂けたら幸いです。
スイッチ側は押しボタンを想定して電源ONで１メッセージ投げてDeepSleepに移行する仕組みです。
電源ON⇒１メッセージ投げ⇒DeepSleepの所要時間は100mSec以下なので、余分な回路が無ければ
電池運用で階段の照明スイッチや玄関チャイムとして数年は使えると思います。

#実行に必要なリソース
　　ArduinoIDE開発環境
　　ESP32/ESP8266
　　ESP-NOWで三路スイッチモドキを作る(リレー側)
　　"espnow_pack.h" ：　記事「ESP-NOWの送受信関数群とサンプルです」で紹介

#機能
　　ESP-NOWで「/TOGGLE」のテキストコマンドを送信します。
　　esp_now_send_mac_address　に送信先MACアドレスを設定します。 
　　0xff,0xff,0xff,0xff,0xff,0xff はbroadcast送信されるのでコノママでも動く・と言えば動きます。
　　＃＃リレー側のMACアドレスはコンパイルログもしくは起動時のSTA MAC:ログにて確認して転記します。


```ino:ESPNOWSwitch.ino:
if defined(ESP8266)
#include <ESP8266WiFi.h>    // ESP8266
#else
#include <WiFi.h>           // ESP32
#endif

#include "espnow_pack.h"
#define ESP_NOW_CH 0
const uint8_t esp_now_send_mac_address[6] =  { 0xff,0xff,0xff,0xff,0xff,0xff }; //送信先アドレス

void setup(){
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);
  WiFi.disconnect();
  if( esp_now_begin( ESP_NOW_CH )!=0 ){
    Serial.println("ESP-NOW Init Failed");
    ESP.restart();
  }
  Serial.printf("\n\nSTA MAC: %s\n", WiFi.macAddress().c_str() );
  char *COMMAND = "/TOGGLE";
  esp_now_send_data( (uint8_t *)esp_now_send_mac_address, (uint8_t *)COMMAND, (strlen(COMMAND)+1) );
  ESP.deepSleep(1000 * 1000000 );                 //1000秒ほどDeepSleepに移行する(復帰用の配線が無ければDeepSleepしたままです)
}

void loop() {
}
```



あとがき
　どなたか岡山：倉敷近辺でオッサンでも加入可能なそんなArduino系な集まり誘ってくれませんか？　（ぷ
M5stackの画面がつかなかった問題について。

# ディスプレイに文字が出力されない
最初に、ガチの初学者のため憶測多めです。
m5stackbaseとm5stickcで通信をするために、いろいろサンプル引っ張ってこねこねしようとするも画面がつかない。
具体的には全体がうっすら光ってはいるものの文字が出力されない。

一行ずつ確認したところ
結果的には以下のコードが原因だった模様

```Arduino:問題のコード
pinMode(10, OUTPUT);
```
存在しないpinを指定していたため動作しなかった。
![MicrosoftTeams-image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3491996/9fe375e0-c746-0759-44ad-87524054edf7.png)

おそらく使えないpin(？)のためショートしてハード的に(？)再起動を繰り返していたのだと思う。
## 結論
使えないpinを使用していた。
【ChatGPT無】サンプルデータ→CSV・XML・SQL・JSON化

:::note info
本記事は、ChatGPT（無料版）で
行なっております。GPT4での確認
はできておりません。あしからず。
:::

　どうも、カーブミラーです。

　今回は、
　　以前に
[【ChatGPT無】人物のサンプルデータをいじくる。](https://qiita.com/kabumira/items/b6b8b42e9871a1604024)
　　で、サンプルデータを作りました。
　　　そのデータを
　　　　Excel等に
　　　　　コピペしやすいように
　　　　　　CSV化します。

　　　　また、
　　　　　XMLやSQLやJSONにもして
　　　　　　コピペできます。

　まぁ、CSV化とはいえ、
　　たいしたことはしません。
　　　サンプルデータを
　　　　マークダウンの
　　　　　コードブロックに
　　　　　　出力するだけです。

　以下が、そのプロンプトです。
　すでに、
　　データが出力されているとします。
　　　XMLやSQLやJSONの際は、
　　　　フォーマットのCSVを
　　　　　書き換えてください。
```Text: データのコード化プロンプト
上記データを下記フォーマットで、マークダウン記法のコードブロックに出力してください。

フォーマット: 
CSV

フォーマットにマークダウン記法の記述は必要ありません。
コードブロックは必要です。
```

　次に、使用例です。
　　まずは、サンプルデータ。

| 姓名       | 性別  | 年齢 |
| ---------- | ---- | ---- |
| 田中 太郎  | 男性 | 25   |
| 山田 花子  | 女性 | 30   |
| 鈴木 一郎  | 男性 | 40   |
| 佐藤 美咲  | 女性 | 22   |
| 伊藤 健太  | 男性 | 35   |

　上記プロンプトを使用した結果

```Text: 使用結果
姓名,性別,年齢
田中 太郎,男性,25
山田 花子,女性,30
鈴木 一郎,男性,40
佐藤 美咲,女性,22
伊藤 健太,男性,35
```

　これならば、作表したあとの
　　コピペが楽になりますね。

　さらに、フォーマットを
　　「姓名（性別）年齢」という風に
　　　変えると、
```Text: 使用結果
田中 太郎（男性）25
山田 花子（女性）30
鈴木 一郎（男性）40
佐藤 美咲（女性）22
伊藤 健太（男性）35
```
　　　ということも
　　　　できます。

　あと、同じCSVでも
　　「**各列の名前とタブ区切りのCSV**」
　　　とすると表をコピペした内容と
　　　　同じになります。
***
　本記事とは、関係がありませんが、
　ここで、ひとつ謝罪させてください。

　先日、
[【ChatGPT無】で四則演算できた！](https://qiita.com/kabumira/items/1e3e35ecc699b95f4d85)
　　をアップしましたが、
　　　2023/06/27になって、
　　　　計算結果が間違う、
　　　　　という事象が
　　　　　　発覚しました。

　記事の削除はせずに、
　　計算結果が間違うことを
　　　書き込みました。

　また、タイトルも修整し、
[【ChatGPT無】で四則演算できた！（あとからダメと判明）](https://qiita.com/kabumira/items/1e3e35ecc699b95f4d85)
　　に変更しました。

　記事を残すことにしましたのは、
　　何かしらの参考になれば、
　　　という気持ちからです。

　どなたかの
　　糧になれば、
　　　幸いです。

　お騒がせしてしまい、
　　申し訳ありませんでした。
自分のデータセットの特徴マップを可視化する

# 目標
特徴マップを可視化する

# 実装
```python3
import timm
import os
import matplotlib.pyplot as plt
import torch

def main():
    os.makedirs("result", exist_ok=True)

    DEVICE = "cuda" if torch.cuda.is_available() else "cpu"

    # datasetは特徴マップを見てみたいデータセットを使う
    dataset = YourDataset()
    loader = torch.utils.data.DataLoader(dataset, batch_size = 1, shuffle = False, pin_memory=True, num_workers = 1)

    print("train size: ", len(dataset))
    
    # netは特徴マップを見てみたいモデルを使う
    net = YouModel()
    net.load_state_dict(torch.load("your_pretrained_model_path.pth"), strict = True)
    # timmを使っても良い
    # net = timm.create_model(model_name, in_chans = 3, features_only=True, pretrained=True, out_indices = (0, 1, 2, 3, 4))
    net = net.to(DEVICE, non_blocking=True)
    net.eval()

    with torch.no_grad():
        for count, item in enumerate(loader):
            # 素のRGB画像がpre_transform_imageに，pytorchのtensorがimage_tensorに格納されていると仮定
            # 必要であれば，ココを書き換えてもらえればOK
            pre_transform_image, image_tensor = item
            processed = []

            # 素のRGB画像を格納する
            # pytorchのtensorの場合は以下のコメントアウトのようにすれば良いはず
            # processed.append(image_tensor.squeeze(0).permute(1, 2, 0).contiguous().numpy())
            processed.append(pre_transform_image.squeeze(0))

            # 出力した特徴マップは複数あると想定する
            # timmのout_indices = (0, 1, 2, 3, 4)をするように複数の特徴マップを可視化したい場合は有効
            image_tensor = image_tensor.to(DEVICE, non_blocking=True)
            outputs = net(image_tensor)

            for feature_map in outputs:
               # チャンネル方向の平均値を特徴マップとする
               # 必要であれば，チャンネルごとの特徴マップも出力できるが，チャンネル数が512とかあると大変なので，妥協した
               feature_map = feature_map.squeeze(0)
               gray_scale = torch.sum(feature_map, 0)
               gray_scale = gray_scale / feature_map.shape[0]
               print(gray_scale.shape)
               processed.append(gray_scale.cpu().numpy())

            # figsize = ()で画像サイズを適宜変えること
            # figsize = (height, width)であることに注意
            fig = plt.figure(figsize = (320, 180))
            for count_, fm in enumerate(processed):
                a = fig.add_subplot(1, len(processed) + 1, count_ + 1)
                imgplot = plt.imshow(fm)
                a.axis("off")
            
            # 直接確認したければ，下のコードのコメントアウトを外すこと
            # plt.show()
            plt.savefig(f"result/{count}.png")
            plt.clf()
            plt.close()
```
ESP-NOWで三路スイッチモドキを作る（リレー側）

ブログの日記にて三路スイッチのＩＯＴ化について書いたのですが、時々ご覧になる方が
いる様なので、リレー側の簡易コードをESP-NOWで書きましたので参考にして頂けたら幸いです。
三路スイッチ以外にもイロイロと使い道はあるのですが、その辺は日記の方で模索していきます。

#実行に必要なリソース
　　ArduinoIDE開発環境
　　ESP32/ESP8266
　　ESP-NOWで三路スイッチモドキを作る(スイッチ側)
　　"espnow_pack.h" ：　記事「ESP-NOWの送受信関数群とサンプルです」で紹介

#機能
　　ESP-NOWで「/TOGGLE」「/ON」「/OFF」のテキストコマンドを受け付けます。
　　「/TOGGLE」　RELAYPINの出力を反転する
　　「/ON」　　　RELAYPINの出力を1にする
　　「/OFF」　　　RELAYPINの出力を0にする
　　＃＃ソースでは#defineでRELAYPINを2に設定してあります＃＃
　　＃＃本機のMACアドレスはコンパイルログもしくは起動時のSTA MAC:ログにて確認できます。


```ino:ESPNOWRelay.ino:
#if defined(ESP8266)
#include <ESP8266WiFi.h>    // ESP8266
#else
#include <WiFi.h>           // ESP32
#endif
#define RELAYPIN 2
#include "espnow_pack.h"
#define ESP_NOW_CH 0
int RELAYSTATUS;

void setup(){
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);
  WiFi.disconnect();
  if( esp_now_begin( ESP_NOW_CH )!=0 ){
    Serial.println("ESP-NOW Init Failed");
    ESP.restart();
  }
  Serial.printf("\n\nSTA MAC: %s\n", WiFi.macAddress().c_str() );
  pinMode( RELAYPIN, OUTPUT );
  RELAYSTATUS = 0;
  digitalWrite( RELAYPIN, RELAYSTATUS );
}

void loop() {
  delay(1);
  if( esp_now_receive!=true )    return;
  esp_now_receive = false;
  Serial.printf( "recv:%s\n", esp_now_receive_data );
  if( strcmp( "/TOGGLE", esp_now_receive_data )==0 ){
    RELAYSTATUS = ((RELAYSTATUS==1)?0:1);
    digitalWrite( RELAYPIN, RELAYSTATUS );
  }
  if( strcmp( "/ON", esp_now_receive_data )==0 ){
    RELAYSTATUS = 1;
    digitalWrite( RELAYPIN, RELAYSTATUS );
  }
  if( strcmp( "/OFF", esp_now_receive_data )==0 ){
    RELAYSTATUS = 0;
    digitalWrite( RELAYPIN, RELAYSTATUS );
  }
}
```



あとがき
　どなたか岡山：倉敷近辺でオッサンでも加入可能なそんなArduino系な集まり誘ってくれませんか？　（ぷ
アンパック(…演算子)とarray_merge()の違いがわからない


## PHPのバージョン
PHP 7.4 以降のバージョンが対象となります。

## アンパック(…演算子)とarray_merge()は同じなのか
配列を結合したい場合、array_merge()以外にも『...演算子』を使う方法があります。（下記参照）
```php
<?php
$array1 = [1, 2];
$array2 = [3, 4];

$unpack = [...$array1, ...$array2];
var_export($unpack);

/* 出力結果
array (
  0 => 1,
  1 => 2,
  2 => 3,
  3 => 4,
)
*/
```
それでは、多次元配列の場合はどうでしょうか。
```php
<?php
$array1 = [
    [1, 2],
    [3, 4],
];

$array2 = [
    [5, 6],
    [7, 8],
];

$unpack = [...$array1, ...$array2];
var_export($unpack);

// 出力結果はどうなる？
```
    
## 例を出して比べてみよう
    
### Q1
    
```php
<?php
$array1 = [
    [1, 2],
    [3, 4],
];

$array2 = [
    [5, 6],
    [7, 8],
];

$unpack = [...$array1, ...$array2];
var_export($unpack);
```
    
<details><summary>出力結果</summary>

```php
array(
    0 =>
    array(
        0 => 1,
        1 => 2,
    ),
    1 =>
    array(
        0 => 3,
        1 => 4,
    ),
    2 =>
    array(
        0 => 5,
        1 => 6,
    ),
    3 =>
    array(
        0 => 7,
        1 => 8,
    ),
)
```
:::note info
配列をアンパック(展開)していますが、多次元配列の状態は保っています。
:::
</details>
        
    
### Q2
    
```php
<?php
$array1 = [
    [1, 2],
    [3, 4],
];

$array2 = [
    [5, 6],
    [7, 8],
];

$merged = array_merge($array1, $array2);
var_export($merged);
```
    
<details><summary>出力結果</summary>

```php
array (
  0 => 
  array (
    0 => 1,
    1 => 2,
  ),
  1 => 
  array (
    0 => 3,
    1 => 4,
  ),
  2 => 
  array (
    0 => 5,
    1 => 6,
  ),
  3 => 
  array (
    0 => 7,
    1 => 8,
  ),
)
```
:::note info
配列を結合しています。Q1と同じ出力結果になりましたね。
:::
</details>
    
### Q3
    
```php
<?php
$array1 = [
    [1, 2],
    [3, 4],
];

$array2 = [
    [5, 6],
    [7, 8],
];

$flattened = array_merge(...$array1, ...$array2);
var_export($flattened);
```
    
<details><summary>出力結果</summary>

```php
array (
  0 => 1,
  1 => 2,
  2 => 3,
  3 => 4,
  4 => 5,
  5 => 6,
  6 => 7,
  7 => 8,
)
```
:::note info
配列をアンパック(展開)したうえで結合しています。フラットな状態になりました。
:::
</details>

## アンパック(…演算子)

[公式ドキュメント](https://www.php.net/manual/ja/language.types.array.php#language.types.array.unpacking)
 - 配列の要素を個別の引数として展開する役割を果たす。
    

## 配列の結合 array_merge()

[公式ドキュメント](https://www.php.net/manual/ja/function.array-merge.php)
 - ひとつまたは複数の配列の要素を結合し、得られた配列を返す。
 - array_merge()のほう関数の処理分だけ時間かかる。

## アンパック(…演算子)とarray_merge()は全く同じではない
多次元配列をフラットな状態へと結合したい場合、どちらかだけではうまくいきませんでした。
同じ挙動をするように見えても、要素の展開、要素の結合と、役割は違うようです。

## 最後に
誤り等があれば教えていただけると助かります！
PHPからmongodb 

almalinux 9 のPHP8つづき

```ruby:
# dnf install php-pear php-devel
(省略）
# pecl install mongodb
(省略）
Build process completed successfully
Installing '/usr/lib64/php/modules/mongodb.so'
install ok: channel://pecl.php.net/mongodb-1.16.1
configuration option "php_ini" is not set to php.ini location
You should add "extension=mongodb.so" to php.ini
```
mongodb.soの読み込みファイル
```ruby:
# vi /etc/php.d/20-mongodb.ini

extension=mongodb.so
```
PHP再起動
```ruby:
systemctl restart php-fpm.service
```
自作アナログゲームをデジタル移植する#1　環境構築編

# 前回までのあらすじ
* 自作のアナログゲームをUnityに移植しようと思った。
* 機能要件の定義を行った。
    * https://qiita.com/ONO_Keyboard/items/f26dca0a12d511e1d1b4

# 今回の記事でやること
* Unity Editor のインストールを行う。

# Unity Hubによる環境構築
このゲームに関して、私は個人の開発者なので「Unity Hub」をダウンロードして環境構築を行う。
Unity Hubのダウンロードは以下のリンクからできる。
https://unity.com/ja/download?currency=JPY

## Unity Hubのダウンロード

* Macでアクセスしても画面左上のボタンは「Windows用ダウンロード」となっている。
* 「1.1　Unity Hubをダウンロード」の項に「Mac用ダウンロード」とあるので、クリックするとdmgパッケージが落ちてくる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/610153/8dc03873-346f-86d4-2e48-e7814a818acc.png)

## Unity Hubのインストール

1. 利用規約に同意する
1. Unity Hub をインストールする。v3.5.0では439MBの空き容量が必要だった。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/610153/d34ecc84-da15-111a-74f6-8681d41d603d.png)

## Unity Hubを起動
アプリケーションにUnity Hubがあるはずなので起動する。
サインイン、またはアカウント作成を求められるので、どちらかを行う。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/610153/48c857c3-640b-37e1-6312-1f59ee08445b.png)

### パスワードがわからない時の対処
Windowsでやってた時のアカウントを使いまわそうとしたらパスワードがわからなくなったので、再発行請求をする。
右下の「Forgot Password？」から、登録しているメールアドレス宛にパスワード再設定リンクが届く。

## Unity Editorのインストール

Unity Hubへのログインができると、Unity Editorのインストールをするかどうか聞かれるので、しておく。
執筆時点での最新のLTSである2022.3.3f1をインストールする。
* すでにインストール済みのUnity Editorがある場合には、「Locate existing installation」から選択もできる様子。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/610153/9b3e2adf-95eb-3c0c-712f-c3bac9cab6f6.png)

Personal Edition Licenseに同意する。Personal Edition Licenseの条件は以下の通り。
どれにも該当する予定はないので、同意する。
```
Unity Personalを商業目的で使用しているか、社内プロジェクトやプロトタイピングに使用しているかに関わらず、年間総収入が10万ドルを超えていないこと。

10万ドルを超える資金を調達していないこと。

現在、Unity PlusまたはProプランを使用していないこと。
```

* Macの保護機能がUnityが変更を加えようとしている旨を通知するので、パスワードを入力し、承認する必要がある。

## Unity Editorのインストールが始まる。

Unity Editorのインストールが始まるので、終わるまで別の作業をする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/610153/ec005fda-9a7b-7f98-cdec-747e570004af.png)

これで今日の記事はおしまい。

# 次回予告

* プロジェクト作成
* Gitへのコミット
* ソースコードのWindowsとの共有について

ありがとうございました。
WEBマンガ更新情報まとめアプリを作ってみた

## 作ろうと思った経緯

前回の[レシピガチャを作ってみた](https://qiita.com/1seedsa/items/6f2f1aaf05bd8c56ef44)と同様、会社のメンバーで個人開発をやっていこうというイベントで作りました。

- マンガが好きなのでマンガに関連するものを作りたかった
- スクレイピングで何かやってみたかった
- 案件でvue.jsを触る機会があり、vue.jsで開発してみようと考えた

という感じです。

## 技術スタック

- ruby 3.2.2
- Rails 7.0.4.3
- vue.js 3.2.47
- nuxt.js 3.4.2
- vuetify
- 楽天レシピAPI
- Github Actions

## どんなものができたか

Webマンガ更新情報まとめアプリです。下記URLにアクセス頂くと表示できます。フロントエンドとバックエンドのサーバが分かれていて、~~初回アクセスはページ自体はすぐ表示されますがバックエンドのサーバが寝てるので起きるまでコンテンツ表示にはだいぶ時間がかかりますのでご了承ください。~~　→ サーバを寝ないようにしました。

https://web-manga.onrender.com/

![スクリーンショット 2023-06-28 10.44.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159896/6f9261d4-d763-9d13-03cd-d4d2c8fbd8a7.png)

Webマンガを出版されている各社のサイトからWebマンガの更新情報と実際のページへのリンクをスクレイピングで取得し、更新情報をまとめています。ページに表示されているカードをクリックすると、そのマンガを読めるページに飛べる仕様です。

1日に1回スクレイピングを実行して、各社のWEBマンガの更新情報を取得しています。スクレイピングについては各社のrobots.txtを確認してスクレイピング自体を禁止していないことを確認した上で、頻度は1日1回とした次第です。

画像については著作権の問題もありますので、各社のページの画像は使わず楽天の書籍APIを使って、楽天APIで書籍画像が取れたものは画像表示するという形にしています（ほとんどNO IMAGEになっているのですが、楽天のページには画像あるものも結構あるので、APIでの取得時に上手く噛み合ってないのかもしれない…）。

スクレイピング実行時の定期処理はGithub Actionsで行っています。Github Actionsでは定期実行の時間を厳密に指定することはできないので厳密な時間指定をして実行をしたい場合は使えないと思いますが、今回は1日に1回の定期実行さえできれば問題無かったので採用しました。


## 感想

- マンガが好きなので、アプリ作ってテストしながら新しいマンガを見つけられたりして楽しかったです。趣味で個人開発やるには好きな分野っていうのも大事だなと思いました
- Render.comでフロントエンドとバックエンドを分けてデプロイするのが初めてだったのでフロントエンドのnuxtをデプロイするのにRender.comのサービスを「Web Services」でなく「Static Site」を使わないといけないということに気づかず結構ハマりました
- 今回はスクレイピングしてきた情報をDBに保存する必要があったので[NEON](https://neon.tech/)を使いました。Render.comでpostgresqlを使おうとすると有料になってしまうので、無料でpostgresqlを使うことができて大変ありがたいです

:::note info
このプロダクトは、株式会社mofmofの「水曜日の個人開発」で作りました。
:::

https://indie-dev.mof-mof.co.jp
Dockerコマンド 勉強記録

Dockerの学習記録用の記事です。
チートシートとしては物足りないと思いますが、参考までに


```docker:docker terminal
$ docker ps -a
```

Docker image　から作成したDocker containerを一覧表示するときに使用する

```docker:docker terminal
$ docker system prune
```
Exited状態のDocker Containerを一括で削除できる

```docker:docker terminal
$ docker run --rm <image>
```
コンテナ作成し、exit後にそのコンテナを削除する

```docker:docker terminal
$ docker run <image>
```
Dockerイメージからコンテナを作成し、コンテナを起動する（run = create + start）

```docker:docker terminal
$ docker rm <id>
```
Dockerコンテナのidなどを指定して、コンテナを削除することができる

```docker:docker terminal
$ docker restart <container>
```
作成済みのDockerコンテナを再度起動する

```docker:docker terminal
$ docker exec -it <container> <command>
```
作成済みのDockerコンテナを指定して、実行するときに使用する
AWS CLIでRDSのバージョンアップをやった話

DBエンジニアの嫁と息子が大好きなだいちです。
ティアキンのコログですが、密かに全部集めようと考えているけど流石に攻略を見ないとつらいよなと最近思い始めてます。
ハイラルの大地に旅している皆さんはどうしてますか？

## はじめに
先日、AWS RDSのマイナーバージョンのサポートが切れるということでバージョンアップを行いました。
他のリソースと連携していることもあり、手動でアップデートを実施する必要があったのですが、マネジメントコンソールでポチポチアップデートをしてもいいのですが、弊社ではナレッジがなくてアップデートと合わせてナレッジも纏める必要がありました。
ナレッジを纏めるとなるとマネジメントコンソールのスクショを撮って貼ってをする必要があると第一に考えましたがとにかく「面倒くさい」と思ったのがスタートです。
ならCLIで完結させたらいいじゃんと考えたのです。
なぜCLIでの対応を考えたのかメリット・デメリットを纏めると以下のようになります。

### マネジメントコンソールでの対応
#### メリット
視覚的にわかりやすい

#### デメリット
UIが変わるとナレッジとの情報が一致しにくくなる（頻度多）

### AWS CLI
#### メリット
ナレッジにはコマンドを貼るだけ（スクショは必要最低限でOK）

#### デメリット
コマンドの理解に学習コストがかかる

## メリット・デメリットの比較

```
#### デメリット
UIが変わるとナレッジとの情報が一致しにくくなる（頻度多）
```
こちらマネジメントコンソールのデメリットはマネジメントコンソールを使っている限り永久不滅ですよね。
でも、AWS CLIであれば学習コストが高くても一度慣れてしまえば以降はデメリットにならないと考えます。コマンドの廃止などもありますがUIの更新よりは頻度が低いと考えてます。

```
#### デメリット
コマンドの理解に学習コストがかかる
```

これでナレッジ作成も楽になるならAWS CLIでやるべきでしょとなった次第です。

## 実際にやってみた
### 事前情報
AWS RDS for MySQL 8.0.23 → 8.0.32
aws-cli/2.11.6
ブルーグリーンデプロイでのバージョンアップ

### バージョンアップの実施

1\. RDSのARNを取得する
対象インスタンスのRDS ARNを控えておきます。

```bash
aws rds describe-db-instances --db-instance-identifier <インスタンス名> --query 'DBInstances[*].[DBInstanceArn]' --output text
```

2\. DBパラメーターグループを取得する
スタンバイインスタンスに適用させるパラメータグループを控えておきます。

```bash
aws rds describe-db-instances --db-instance-identifier <インスタンス名> --query 'DBInstances[*].[DBParameterGroups]' --output text
```

3\. 作成する
スタンバイインスタンスを作成します。

```bash
aws rds create-blue-green-deployment \
    --blue-green-deployment-name <スタンバイインスタンス名> \
    --source arn:aws:rds:ap-northeast-1:<xxxx>:db:<インスタンス名> \
    --target-engine-version 8.0.32 \
    --target-db-parameter-group-name <パラメータグループ名>
```
`--blue-green-deployment-name <スタンバイインスタンス名>`ではスタンバイインスタンスに利用するインスタンス名を指定します。
`--target-engine-version 8.0.32`では今回バージョンアップ後の値を指定しています。
変えない場合は不要です。

4\. ブルーグリーンデプロイの詳細を表示する

```bash
aws rds describe-blue-green-deployments --filters Name=blue-green-deployment-name,Values=<スタンバイインスタンス名>
```

SwitchoverDetailsのStatusで進行状況を確認します。
また、BlueGreenDeploymentIdentifierの値を控えておく

5\. 切り替えを実施する
ブルーグリーンを入れ替えます。

```bash
aws rds switchover-blue-green-deployment \
    --blue-green-deployment-identifier <BlueGreenDeploymentIdentifier> \
    --switchover-timeout 300
```

`--blue-green-deployment-identifier <BlueGreenDeploymentIdentifier>`には先程控えた値を指定します。
`switchover-timeout`は切り替えの制限時間を秒単位で指定します。デフォルトは 300 です。

6\. ブルーグリーンデプロイを削除
バージョンアップが無事に完了したらブルーグリーンデプロイを削除します。

```bash
aws rds delete-blue-green-deployment \
    --blue-green-deployment-identifier <BlueGreenDeploymentIdentifier> \
    --no-delete-target
```
`--no-delete-target`で元インスタンスを削除しないようにします。

## おわりに
今回まとめた記事はほぼ弊社でも纏めたナレッジと同じような内容になっております。
個人的にはすごくシンプルなナレッジとなって大変満足しています。
AWS CLIをこの機会に利用してみてください！
【SwiftUI Color】背景がどんな色でも常に文字を見やすくする方法

# はじめに
背景がどんな色でも常に文字を見やすくする方法を紹介します。
こちらの記事の続きです。

https://qiita.com/Shota-Abe/items/9f6c5137e3903ab2bf71

# 作るもの
色のついた背景とその色のカラーコードを表示するアプリを作ります。
タップすると、ランダムに背景色が変わります。
背景色を変更すると背景色に応じて文字色も見やすい色に変更されます。

# デモ
https://twitter.com/shota_appdev/status/1673359007158001664?s=61&t=AVZyPfi6yS5TqHUuXfIz0w

# やり方
背景色に応じて文字色を変更するには、背景色の相対輝度を求め、その値に応じて文字色を変更します。
相対輝度が0.5未満の場合は白、0.5以上の場合は黒にします。

```swift
// 前の記事で紹介した相対輝度です
extension Color {
    var relativeLuminance: CGFloat {
        // 色の相対輝度を計算する
        return 0.2126 * components.red + 0.7152 * components.green + 0.0722 * components.blue
    }
    
    private var components: (red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) {
        // 色の成分を取得する
        var redComponent: CGFloat = 0
        var greenComponent: CGFloat = 0
        var blueComponent: CGFloat = 0
        var alphaComponent: CGFloat = 0
        
        UIColor(self).getRed(&redComponent, green: &greenComponent, blue: &blueComponent, alpha: &alphaComponent)
                
        return (redComponent, greenComponent, blueComponent, alphaComponent)
    }
}
```

```swift
extension Color {
    // isLight
    var isLight: Bool {
        // 色の相対輝度が0.5以上の場合は明るい色と判定する
        return relativeLuminance >= 0.5
    }

    // random
    static var random: Color {
        // ランダムな色を生成する
        return Color(red: .random(in: 0...1),
                     green: .random(in: 0...1),
                     blue: .random(in: 0...1))
    }

    // toHex
    func toHex() -> String {
        // 色を16進数に変換する
        let components = self.components
        let red = Int(components.red * 255)
        let green = Int(components.green * 255)
        let blue = Int(components.blue * 255)
        return String(format: "#%02X%02X%02X", red, green, blue)
    }
}
```

```swift
struct ContentView: View {
    @State private var backgroundColor = Color.white

    var body: some View {
        ZStack {
            Rectangle()
                .fill(backgroundColor)
                .ignoresSafeArea()

            Text(backgroundColor.toHex())
                .font(.system(size: 56).bold())
                .foregroundColor(backgroundColor.isLight ? .black : .white)
        }
        .onTapGesture {
            // 背景色をランダムに変更する
            backgroundColor = Color.random
        }
        .animation(.easeInOut(duration: 0.3), value: backgroundColor)
    }
}
```

## ポイント
- 背景色の相対輝度を求める
- 相対輝度が0.5以上の場合は明るい色と判定する
- 背景色が明るい場合は文字色を黒に、暗い場合は白にする

# おわりに
背景色に応じて文字色を変更する方法を紹介しました。
色って面白い😆
AWS User Notificationsのうれしいポイントまとめてみた

# はじめに
先日発表された、AWS User Notifications について、どんなサービスか紹介します。

https://aws.amazon.com/jp/about-aws/whats-new/2023/05/aws-user-notifications-available/

# 概要
AWS User Notificationsを利用することで、AWSからの通知を一元的にマネジメントコンソールから確認することができます。


AWSではこのように記載されています。
> AWS User Notificationsを使用すると、AWS Health イベント、Amazon CloudWatch アラーム、EC2 インスタンスの状態変化など、AWS のサービスからの通知を一貫したわかりやすい形式で一元的にセットアップして表示できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3115411/531d8678-9e3f-bda6-5ec4-0233766d4ae6.png)

https://aws.amazon.com/jp/notifications/


複数リージョン、複数サービスから、自分に必要な通知を選択し、EメールやSNSなどに連携したり、GUIで確認することができます。

User Notificationsサービスを作成すると、裏でEventBridgeルールが作成されるような仕組みになっています。


## 設定項目
設定項目は以下のようになります。
すべて複数選択可能です。
* 通知設定
    * 通知するサービスやイベントパターン、配信チャネル（通知先）
    ※通知文面をカスタムすることはできません

* 配信チャネル
    * メール・AWS Chatbot・AWSモバイルアプリケーションが選択可能
* 通知ハブ
    * 通知データが保存され、処理されるリージョン
 


## うれしいポイント
* 通知を一元的にまとめて確認できる
    * 各サービスのコンソールに、通知を確認しにいく必要がなくなった

* 個別で作成していたEventBridgeルールを一元的に設定できる
    * 複数リージョンや複数サービスを選択し、一括でEventBridgeルールを作成できる


* Event Bridge 統合を通じて、マルチアカウント構成が可能
    * AWS アカウント間でイベントを送受信するように EventBridge を設定し、ユーザーのアカウントにて、イベントバスでイベントを送受信できる AWS アカウントを指定する
    * ユーザーは受信者アカウントを使用して、アカウント全体で通知を生成する
    ※ Organization統合はまだ実装されていないようです。


## 料金
AWS User Notifications 自体は無料ですが、裏で作成されるEventBridgeに料金がかかります。


# おわりに
通知を一元化することで、運用が楽になるうれしいサービスだということがわかりました。
今後またアップデートもありそうなので、動向に注目したいと思います！
Tensorflowで時系列データ（株価）を予測する解説

# はじめに

* 私利私欲のために、機械学習を利用して株価を予測できないかなぁ～、と探していたところ、kaggle notebookで以下を発見。
* [LSTMを使った株価予測](https://www.kaggle.com/code/faressayah/stock-market-analysis-prediction-using-lstm)
* 早速notebookをコピーして実行してみたものの、どういう処理をやっているのか理解に苦労したので、お絵描きしながら理解したことを共有したい。

# trainデータとテストデータの作成

* 簡易的に、時系列データが3,000日分あるとする。
* それを、Trainデータとテストデータに分割する。簡易的に、2,500と500に分けたとする。
    * テストデータは、後に、モデルの精度検証を行うためのもの。
* 考え方としては、直近過去60日のデータを元に61日目を予測する、という行為をめざすため、Trainデータの全区間を1日ずらしで60日ごとに区切る。
    * modelの作成のため、0 ～ 1 にスケーリングする。（該当期間の最安値を0, 最高値を1として、縮尺を変更する）
    * 各要素が60個の配列ができあがる。
* 上記でできた配列の教師データとして、y_trainを作成する。過去60日のデータを元に61日目を予測したいわけだから、x_trainで切り取った各60日の要素に対応するかたちで、61日目のデータ、62日目のデータ、という配列を作成する


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/10317/ef432eeb-35c9-6eeb-bf5f-1403dca3ee93.png)

# 予測

* 「過去60日のデータを元に61日目の株価を予測する」というモデルができあがったので、予測のためのINPUTとしては、60日分のデータを用意してあげる必要がある。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/10317/b3f7f9c8-d4c3-c09f-5dc3-35ad3b4ccb0b.png)

# モデルの検証

* kaggle notobookの例では、最後に予測データと実績データを並べて比較をしている。何をやっているか解説する。
* テストデータとして切り出した500点を、まず予測で出力する
    * 予測の2,501点目は、実績の2,441~2,500点目から予測
    * 予測の2,502点目は、実績の2,442~2,501点目から予測
        * ※2,501点目は、予測ではなく実績を使う点に注意。
    * 以降も同様に「実績の過去60日」を元に次の1日を予測することを繰り返し、500点のデータを作成する
* 作成された500点と、実績の500点のデータを比較し精度を出している。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/10317/c3f27d03-b5f2-aacb-4829-1f847eb6c774.png)

## 10日後のデータは予測できるか

* モデルの検証精度（rmse）は比較的高い値を出しているが、これはあくまで「実績を元にした翌日」という条件となる。
* したがって、10日後ともなると、前9日は予測を使わざるを得ない。
* これは、不確定な予測値を元にするわけだから、不確定要素が積み重なり、結論としては全くあてにならない、ということになる。

### （参考） 10日後を予測するコード

```python
# 最後の60日間のデータを取得
input_data = dataset[-60:]
# print(input_data)
    
# 未来10日分を予測
for _ in range(10):
    # スケーリング
    input_data_scaled = scaler.transform(input_data)
    
    # データを整形
    X_test = []
    X_test.append(input_data_scaled)
    X_test = np.array(X_test)
    X_test = np.reshape(X_test, (X_test.shape[0], X_test.shape[1], 1))
    
    # 予測
    pred_price = model.predict(X_test)
    
    # スケーリングを元に戻す
    pred_price_unscaled = scaler.inverse_transform(pred_price)
    print(pred_price_unscaled)
    
    # 予測結果を入力データに追加
    input_data = np.append(input_data, pred_price_unscaled.reshape(1, -1), axis=0)
    input_data = input_data[-60:]
```

# まとめと感想

* この例では過去の株価終値のみを使用した予測となっている。
* 株価は、関連ファクターが多すぎて終値だけでは到底予測はできないと言える。
* こんなことで株価が予測できたら、誰も苦労はしていない。甘い考えは捨てたほうがいいと思った。
セッションについてまとめ

#  はじめに
ログインが必要なサイトを構築する上で必要になるセッションの知識についてまとめました


## session（セッション）とは　
セッションは、ウェブサイトがユーザーの一連の操作（セッション）を記憶しておくための仕組みです。例えば、ログイン情報やショッピングカートの中身など、ユーザーがウェブサイトで行った操作の状態を保存します。そうすることでページを更新したり、別のページに移動した後でもログイン状態を継続したり、ショッピングカートの中身を継続したりすることができます


## sessionの保存先について
cookieはサーバーから命令されることでユーザーのブラウザに保存されます。それに対してsessionはサーバー側にデータを一時的に保存するために用います。メリットとしてサーバーに保存することでデータの改竄を防ぐことができます

### Cookeiについて

Cookeiについての詳細は次の記事を参照してください

https://qiita.com/EasyCoder/items/8ce7dfd75d05079be9d7

## sessionの有効期限について
セッションもクッキーも一時的に保存されるデータの一つです。しかしセッションは`ブラウザが閉じたらすぐに削除されるデータ`なのでPCのメモリやファイルに保存されます

## 保存されるsessionの見本

sesshionに保存されるデータは使用する言語や環境によって異なります。以下はショッピングサイトで保存されるsessionの例になります

```java
{
       "loggedInUser": { // ログインユーザー情報を保持するためのキーです。
        
        "userId": "user123", // ユーザーIDを表現するキー
        "username": "John Doe", // ユーザー名を表現するキー        
        "email": "john.doe@example.com" // 電子メールアドレス
    }, 
    
    "shoppingCart": { // ショッピングカート情報を保持するためのキーです。
        
        "items": [ // カート内のアイテム一覧を保持するためのキーです
            { 
                "itemId": "item456", //アイテムIDを表現するキー、その値が"item456"です。
                "itemName": "T-shirt", // アイテム名を表現するキー、その値が"T-shirt"です。
                "quantity": 2 // アイテムの数量を表現するキー、その値が2です            }
                ] 
            } 
        } 

```

## sessionの特徴
セッションを利用する場合はcookie(セッションcookie)に重複しない文字列を保存します。この文字列を`セッションID`と呼びます。
Javaの場合セッションIDは自動でユニーク(絶対に被らない値)な値を生成してくれます。

## 一人のユーザーに1つのセッションが作成される
Webアプリケーションにおける1ユーザーのセッションは1つです。

### 1つのセッションが作成される理由（例）
あるユーザーがショッピングサイトに訪れ、商品をカートに追加しました。このユーザーがブラウザを閉じずに別のページに移動したとき、そのカート内の商品情報をどのように保持するでしょうか？

ここで役立つのがセッションです。サーバは、ユーザーがサイトにアクセスしたときに一意のセッションIDを生成し、そのIDをユーザーのブラウザに送ります（通常はクッキーを通じて）。サーバはそのセッションIDに対応するデータ（この場合、カートの内容）を保持します。

ユーザーが別のページに移動しても、ブラウザはサーバに対してこのセッションIDを送り続けます。すると、サーバはセッションIDに基づいて、それぞれのユーザーに関連するデータ（カートの内容など）を取り出すことができます。

もし、同一のユーザーに対して複数のセッションが存在すると、どのセッションが現在のユーザーの状態を反映しているのか、どのセッションにカートの情報を保存すべきかが混乱してしまいます。したがって、一般的には、1ユーザーに対して1セッションが存在します。そのため、ユーザーが別のページに移動しても、そのユーザーの状態（カートの内容など）を正確に追跡することができます。

## あとがき

今回はsessionに関する学習内容をアウトプットしました。この記事が参考になれば幸いです。
ArduinoIDEでArduino.hがないと言われる

Arduino IDEでコンパイルしようとしたらArduino.hが見つからないと怒られた．

```bash
/private/var/folders/9k/zd0ns4tx18z12pnfjwrq14800000gn/T/arduino/sketches/0CB79E991AD93F43F51311B1B90F54F5/sketch/seeed_nRF52_madgwick.ino.cpp:1:10: fatal error: Arduino.h: No such file or directory
    1 | #include <Arduino.h>
      |          ^~~~~~~~~~~
compilation terminated.

exit status 1

Compilation error: exit status 1
```

大体こうゆうのは パスが通ってないとか, ArduinoIDEでインストールしたライブラリ・ボードプログラムがおかしいとか, そうゆう感じなのでボードマネージャから関連する`Arduino`のボードパッケージを入れ直してみる.


コンパイルできた. ただし， 再起動するたびにないと言われるので, どうやらちゃんとパスが通ってないみたい. 時間がないので, 休日に調べます

```bash
Sketch uses 100128 bytes (12%) of program storage space. Maximum is 811008 bytes.
Global variables use 46072 bytes (19%) of dynamic memory, leaving 191496 bytes for local variables. Maximum is 237568 bytes.
```
【まだ間に合う！】Microsoft Build Japan 2023 - 6月27日-28日開催

初投稿になります！
皆さんよろしくお願い致します！！

年に一度開催される、Microsoft主催の開発者向けイベント「Microsoft Build」の日本版！が今日(6/28)まで品川のMSで開催されています！

オンラインでも視聴可能ですので、視聴お薦めです！！
昨日、品川行ってきましたが、クラデベの方や開発者の方と直接会えるので楽しいです☆
また、直接話すことが出来ますので、私のように新機能の導入で開発に詰まって聞きたいことがある等悩み相談頂けるので大変助かります。

デモも沢山見れますので、実現方法などの参考になります。
AI導入もあり、開発が一層面白くなってきました☆

以下にリンク貼っておきます！！

Microsoft Build Japan (オンライン・東京会場)
https://info.microsoft.com/JA-ADAI-CATALOG-FY23-06Jun-28-Microsoft-Build-Japan-Day2-SREVM14500_Catalog-Display-Page.html

これから、ちょこちょこ発言していこうと思っています。
よろしくお願い致します！
権限昇格を防ぐ構成を検討したときの話

AWSで権限昇格を防ぐ構成を検討したときの備忘になります。

# 背景
検証用のAWSアカウントの権限管理を改善するにあたって、

- 開発のスピードを下げないように制限する権限を最小限にしたい
- 管理者以外の権限の昇格は防ぎたい

といった条件がありました。
権限の昇格を防ぎたいという要望があったので、IAMの権限は管理者以外付与しない構成を考えました。
しかしその場合、IAMポリシーやIAMロールが作成できなくなり、EC2やLambdaにアタッチするといったことも事前承認制になってしまいます。
これでは開発のスピードを下げてしまいます。
そんなわけで開発のスピードを下げることなく、権限昇格を防ぐ構成について考えることになりました。

# 今回のゴール
今回実現する構成では以下を目標にしています。
- IAMユーザ、グループに関する操作権限を制限する
- MFA設定やパスワード変更等最低限必要な権限は付与する
- それ以外のIAM権限については原則権限を付与する
- 権限管理に必要なロールやポリシーへの操作は制限する


# 現状の権限管理構成と課題
現状の権限管理構成は以下です。
![1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3310014/5b7aba07-e174-1d11-8e9c-680e92209924.png)

この構成ではIAMロール、IAMポリシーの権限を付与しているので、フルアクセス権限のIAMロールにスイッチすることで権限昇格が発生してしまいます。
![2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3310014/521e4920-1cc0-3e3a-8d97-2ce03f4eb05b.png)

# 実装した権限管理構成1
最初に以下の権限管理構成を検討しました。
![3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3310014/ef548fe2-b089-af0f-21d6-b8ecff655928.png)

IAMユーザに権限を付与して操作する構成から、IAMロールに権限を付与して操作する構成に変更されています。
この構成では、IAMユーザがスイッチできるIAMロールを制限することで、新規にフルアクセス権限のIAMロールを作成して権限昇格することを防ぐことができます。

# 構成1の問題点
先述の構成で完璧だ！と思ったのですが、以下のようなステップで権限昇格できることが判明しました。
![4.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3310014/6bc3741c-8f5b-9997-8b51-bacfd7eea349.png)

IAMユーザからスイッチして権限昇格する経路はなくなりましたが、引き続きフルアクセス権限のIAMロールを作成する権限はあります。そのため、EC2やLambdaなどIAMユーザ以外のリソースにフルアクセス権限のロールをアタッチすることで、権限昇格が発生してしまいます。
このケースでは、EC2への接続やLambdaの実行ができれば簡単に権限昇格ができてしまいます。

# 実装した権限管理構成2
構成1ではフルアクセス権限のIAMロールを利用させないというアプローチで検討しました。
その場合、少ない権限でも昇格できることが判明したので、フルアクセス権限のIAMロールを作成できないようにするアプローチを検討しました。
権限管理構成は以下です。
![5.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3310014/6e3fd811-ea4b-8e83-5316-223edbcc5745.png)

Permissons Boundaryを利用して、IAMロールを作成する際も利用者以上の権限を作成できないようにしました。
これによって、EC2やLambdaにアタッチするIAMロールが最も権限が広いものでも利用者のロールと同じになるので、権限昇格を防ぐことができます。

## Permissons Boundaryについて説明
IAMユーザやIAMロールにアタッチすることができるアクセス権限です。(IAMグループは不可)
普段アタッチしているIAMポリシー(Identity-based policy)に併せて付与することが可能です。
![6.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3310014/536cbcb1-f996-493c-9642-7b6ef65bd496.png)
画像の通りで、IAMポリシーとPermissions Bounaryの両方で許可されているものが有効な権限です。
そのため、今回のパターンではPermissions Bounaryで今回のゴールで制限するものを拒否するようにして、IAMポリシー側でフルアクセス権限があっても制限できるようにしました。
![7.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3310014/42e7e1b0-c85c-ef6d-7f76-396501d34d5c.png)

https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/access_policies_boundaries.html

# 最後に
最後までご覧いただきありがとうございます！
間違い等あればご指摘いただけると幸いです。
stable diffusion clone cleaner

# clonecleanerを使う

CloneCleanerとは、同じような顔を生成しないためのweb UI拡張機能

![00064-824037351.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/31338/5fbf1e28-6611-4383-14e0-e5c95c88dd92.png)

![00063-824037350.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/31338/ca17cf77-5e3c-7ebd-9be9-59bc09630b3b.png)

同じ seed で違う女の子が出てくる

UI > Extensions に以下のurlを入れる

```
https://github.com/artyfacialintelagent/CloneCleaner.git
```

処理が完了したら、「Extensions」内の「Installed」タブをクリック。

umprompted とか 他のプロンプトが有効になっていると動かない場合がある。