OmniAICreator/Qiita-1.07M huggingface dataset:
【SOA-C02】AWS-SOAに合格できたのでやったことを書いてみる

![スクリーンショット 2024-09-21 213810.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3194659/0543524d-1401-6588-a46c-97c1ee6f1acb.png)

SysOpsに無事合格できたので、勉強方法や感想を述べていこうと思います。

[1.筆者スペック](#1-筆者スペック)
[2.学習に使用したもの](#2-学習に使用したもの)
[3.学習方法](#3-学習方法)
[4.感想](#4-感想)

# 1. 筆者スペック
4年目に突入したシステムエンジニア
AWSの実務経験無し

# 2.学習に使用したもの
AWS-CLF・SAAの取得
CloudLicense：https://cloud-license.com

# 3.学習方法
前提として、CLS・SAA未取得の方は、先にそちらを取得した方がいいかなと思います
### 1週間目
CloudLicenseの#50~100の問題を、答えを見ながら1周して確認する

### 2週間目以降
CloudLicenseの試験モードを解く　→　不正解や怪しいところは復習をする。
これを繰り返して、8割以上安定して取れたら申し込んで試験に挑む…といった感じです。

↓試験モード点数の記録
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3194659/194fcc47-0ba2-f83e-b923-04c7820d9ae9.png)


# 4.感想
ラボがある時に受けたわけではないので、SAAに合格できる知識があれば
比較的短い時間の学習で合格圏に入るのかなと思いました。

わからない箇所はChatGPTで調べるの結構おすすめです。

少し忙しくなるので、落ち着いたらDVAの資格にも挑戦して見ようと思います。
AWS Certified Solutions Architect - Professional 認定試験。。。合格！

## はじめに
お陰様でSAP無事合格しましたー ^^) _旦~~
みっちり4か月間かけて勉強してなんとか合格です。最初はなんのことやらという感じで、勉強時間がいくらあっても足りないような状況でした。

## 受験前の状態
SAAを取得した後、業務においてEC2やALBなどといったサービを中心にGlobal AcceleratorやCloudFront、CloudFormationなど触らせていただきました。
SAAの点数はおよそ830点ほどでしたでしょうか、今回のSAPの点数842点とほぼ同じです。

https://qiita.com/nikorasu277/items/aa9e0b35f5e79ffcc605

SAAの勉強時間に比べてかけた時間は感覚的に同じくらいかもしれません。つまりSAAを受けずに、いきなりSAPはキツイのかなーと思います。

## 合格のためにしたこと及び使用教材
使用教材はCloudLicenseを中心に取り組み、CloudTechは力試しに使用しました。
CloudTechは、試験1か月前に300問一気に解いて、6-7割くらいの得点で、CloudLicenseの問題より難しかったです。しかし、CloudTechは解説がしっかりしていて（恐らく模範解答の正答率も高そうだし解説がピカイチです。）、応用力が付きます。

日頃の勉強時間などについて、平日は満員電車の中でのスマホ学習が中心でした。汗だくだくの満員電車で学習、、最悪ですね季節が(・_・;)平日多くて2時間、休日4-8時間でしょうか。
平日に時間を割けない状態でしたので、休日はしっかり時間をかけて勉強していました。勉強範囲は#13-#83を5往復以上はやっていました。広い範囲の知識が必要だと思ったので、薄い知識を広く付けるために、深堀りはしすぎず、たくさん触れて、イメージ⇒パターン認識⇒理解という流れでした。#13-83のどこが一番重要かというのは正直わからないです。。広く出たように思います。
ありがたいことに、業務においても実際にAWS Global Acceleratorや、CloudFrontも触らせてもらったので、苦手意識なく試験に臨むことができました！
試験2週間前くらいでしょうか。AWS公式の模擬試験（20問）の正答率は80%で、CloudLicenseの模擬試験も正答率80%（試験直前は90%をゴロゴロ取れる状態でした。）でした。

https://explore.skillbuilder.aws/learn/course/external/view/elearning/13272/AWS-Certified-Solutions-Architect-%E2%80%93-Professional-Official-Practice-Question-Set-SAP-C02-Japanese-

## 感じた難易度
難しいの一言です。(^^;
SAAの基礎知識に加えて覚えていく感じですが、難易度が違いすぎてSAAとは別物という感覚さえありました。
SAPにもパターンがあるとは思いますが、試験で発揮できるほど記憶する必要があります。
また2択まで絞ってから正答を選択するための知識ですかね！
また試験前の体調管理が大事かなと思います。SAAで失敗しているので(^^;試験1週間前から6時間睡眠（普段はもっと少ないです。。）、あと、試験直前は、やたらとお手洗いに行きました。大好きなコーヒーも控えました泣

## 受験して感じたこと
一周したあたりで40分ちょっと時間が余り、フラグが17個ほどあって全て見直すことができました。いつもの解くスピードはかなり遅いので自信が無かったのですが、スピードを意識しつつ、一周目で難しい問題にもちゃんと解答して、見直しに入るように心がけていました。時間が無くて見直せないことを想定してのやり方です。
正直もっと点数を取れていたと思っていましたが、甘い考えでした。。


## CloudLicenseとCloudTechどっちが良い？
ここで余談ですが、CloudLicenseとCloudTech、CloudLicenseが個人的にはおすすめかもしれません。基礎力を付けて、ついでに合格も付いてくるみたいな合格を目指すならCloudTechでしょうか。少し時間に余裕がある場合はCloudTechと思います。CloudTechを完璧に仕上げたらCloudLicenseも解けると思います。


## プレッシャーとの闘い(^^;
人それぞれ。
と言ったらそれまでです。(笑)
4か月という期間をいただいて、業務でもより高度な業務をさせていただいて、試験前には業務負荷も調整いただいたと認識しています。ここまでしてもらっているのに落ちますか?そう、無理なのです。。。受験を予定されている方に贈るエールとしては、落ちても後悔がないように勉強するしかないのかなと思います！
あと私のやり方ですが、試験日はバンバン自分の口で言っちゃって、自分にプレッシャーをかけてしまうのが良いのかなと思います。試験中にプレッシャーが力になっていることに気付くはずです！

合格してしまって面白い記事にはなっていませんが(^^;
今後も役立つ技術系の記事をどんどんアップできればと思います！


では！
現在サポートされているNetBSD一覧

NetBSDで現在サポートされているものをまとめておくとちょっと便利かな、と思って。（[現在サポートされているFreeBSD一覧](https://qiita.com/koizumistr/items/d4e3107b58e5bf274a40)のNetBSD版です。）

# 10.x
10.1 (2024年 12月 16日)

https://qiita.com/koizumistr/items/95f75080b21f24392e09

# 9.x
9.4 (2024年 4月 20日)

https://qiita.com/koizumistr/items/0faeacea863b06d8103d

# サポート終了
## 10.x
### 10.0 (2024年 3月 28日)
https://qiita.com/koizumistr/items/08dfb8878c209097e4a7

## 8.x とそれ未満

# バージョンの付け方について
メジャーバージョン（x.yのxの方）がサポート対象の単位で、その最新のものにマイナーバージョン（x.yのyの方）を付けてリリース、としているようです。なので、10、9それぞれサポートされているバージョンは最新の1つずつということになります。FreeBSDだと、例えば9.3と9.4が同時にサポートされる期間というのがあるのですが、NetBSDだとあり得ない、ということで。（ということはこんなページ作る意味ほとんどなかった:sob:）
9.4が出る前に、9.3で緊急の脆弱性とかあれば9.3.1とか出るっぽいです。（ただ、その時には9.3はサポート対象外でしょうから、やはり「サポートされるのはメジャーバージョンの最新の1つ」ということだと思います。）

# おことわり
この文章の内容は、筆者が所属している会社・団体とは一切関わりがありません。いわゆる「自主的な研究の成果の発表」というものです。
長期の勾配を利用する手法の備忘録

# はじめに

最近、AdEMAMix という長期の勾配情報を利用する手法が提案されていました。
色々と違いはありますが、長期の勾配情報を利用する手法は過去にいくつか提案されているため、今後類似の手法が提案された際のために備忘録を作成します。

# AdEMAMix

論文

- https://arxiv.org/abs/2409.03137

AdamW に長期の勾配情報の利用を追加したものです。
更新式を以下に示します。weight decay と $\alpha, \beta_3$ のスケジューリングについては省略しています。

```math
\begin{align}
m_{1,0}, m_{2,0}, v_0 &\gets 0 \\
m_{1,t} &\gets \beta_1 m_{1,t-1} + (1 - \beta_1) g_t, \hat{m}_{1,t} \gets \frac{m_{1,t}}{1 - \beta_1^t}  \\
m_{2,t} &\gets \beta_3 m_{2,t-1} + (1 - \beta_3) g_t \\
v_t &\gets \beta_2 v_{t-1} + (1 - \beta_2) g_t^2, \hat{v}_t \gets \frac{v_t}{1 - \beta_2^t}  \\
\theta_t &\gets \theta_{t-1}  - \eta \frac{\hat{m}_{1,t} + \alpha m_{2,t}}{\sqrt{\hat{v}_t} + \epsilon}
\end{align}
```

$m_2$ が長期の勾配情報を保存します。そのため、$\beta3$は$\beta1$よりも1に近い大きな値を利用します。

個人的な疑問点は以下の通りです。

1. $\beta_3$ をスケジューリングする関係か $m_2$ について Adam で提案された補正を行いません($\hat{m}_2$ を使いません)
2. 長期の勾配情報 $m_2$ は $\alpha$ 倍して $\hat{m}_1$ に加算しています。$\alpha$ は [4, 10] の間で探索しているとあるため、かなり大きいです。そのため、AdamW に対して更新幅がかなり大きくなり、実質学習率を大きくするような効果があります

# Lion 

論文

- https://arxiv.org/abs/2302.06675

更新式を以下に示します。weight decay については省略しています。


```math
\begin{align}
m_0 &\gets 0 \\
c_t &\gets \beta_1 m_{t-1} + (1 - \beta_1) g_t \\
\theta_t &\gets \theta_{t-1} - \eta sign(c_t) \\
m_t &\gets \beta_2 m_{t-1} + (1 - \beta_2) g_t
\end{align}
```

$m$ に長期の勾配情報を保存します。短期の勾配情報は保存せずに、最新の勾配をそのまま利用します。

AdEMAMix との大まかな違いは以下の通りです。

1. 短期の勾配情報として AdEMAMix では $m_1$ を利用しますが、Lion では勾配そのものを利用します(AdEMAMix の $beta_1 = 0$ と等価)
2. 各パラメータに対する更新量は常に一定で、勾配情報の符号のみを利用します


# QHM/QHAdam

論文

- https://arxiv.org/abs/1810.06801

QHM の更新式は以下の通りです。
他のアルゴリズムとの関係で、論文中で g で表される変数は m と、$\nu$ で表されるパラメータは $\gamma$ と表記しました。

```math
\begin{align}
m_0 &\gets 0 \\
m_t &\gets \beta m_{t-1} + (1 - \beta) g_t \\
\theta_t &\gets \theta_{t-1} - \eta \{ \gamma m_{t} + (1 - \gamma) g_t\}
\end{align}
```

QHAdam の更新式は以下の通りです。

```math
\begin{align}
m_0, v_0 &\gets 0 \\
m_t &\gets \beta_1 m_{t-1} + (1 - \beta_1) g_t,   \hat{m}_t \gets \frac{m_t}{1 - \beta_1^t}  \\
v_t &\gets \beta_2 v_{t-1} + (1 - \beta_2) g_t^2, \hat{v}_t \gets \frac{v_t}{1 - \beta_2^t}  \\
\theta_t &\gets \theta_{t-1} - \eta \frac{\gamma_1 \hat{m}_t + (1 - \gamma_1) g_t}{\sqrt{\gamma_2 \hat{v}_t + (1 - \gamma_2)g_t^2} + \epsilon}
\end{align}
```

$m$ に長期の勾配情報を保存します。短期の勾配情報は保存せずに、最新の勾配をそのまま利用します。

AdEMAMix との大まかな違いは以下の通りです。

1. QHM は Adam 系ではなく SGD ベースなので勾配の大きさを勾配の移動二乗平均平方根(moving RMS)で補正しません
2. 短期の勾配情報として AdEMAMix では $m_1$ を利用しますが、Lion と同様 QHM/QHAdam では勾配そのものを利用します(AdEMAMix の $beta_1 = 0$ と等価)
3. QHAdam では更新量を調節するための移動二乗平均平方根(moving RMS) に対しても、$\gamma_2$ を小さくすることで最新の勾配の割合を増やすことができます。ただし、長期の勾配情報を利用するという意味合いは薄いと考えています

# AggMo

論文

- https://arxiv.org/abs/1804.00325

更新式を以下に示します。変数名は論文のものから変更しています。

```math
\begin{align}
m_{i,0} \gets 0 for all i\\
m_{i,t} \gets \beta_i m_{i,t-1} - g_t, for all i \\
\theta_t \gets \theta_{t-1} + \frac{\eta}{K} \sum_{i = 1}^{K}{m_{i,t}}
\end{align}
```

任意の数(式中ではKと表記)のモーメンタム係数を利用できます。

AdEMAMix とのおおよその違いは以下の通りです。

1. Adam 系ではなく SGD ベースなので勾配の大きさを勾配の移動二乗平均平方根(moving RMS)で補正しません
2. 勾配情報を保持するモーメンタム係数を任意の数設定できます(AdEMAMixは $beta_1$ と $beta_2$ の2つ)
3. 複数の勾配情報を混ぜる際に、重みなしの平均を使います(AdEMAMix は古い勾配情報の重みとして $\alpha$ を利用します)


以上
「その結論って、〇〇の結論と同じじゃね」

## はじめに
技術者への評価を間違える理由として、「その結論って、〇〇の結論と同じじゃね」というのがあります。

特に、〇〇の結論を知る前に、独立して判断したにもかかわらず、「その結論って、〇〇の結論と同じじゃね」として切り捨てられることがあります。
 それは、評価方法として理不尽であることを主張したいと思います。


## 本当は気づいてほしいこと
- 物事を適切に判断できる担当者であることがわかる
- 実現の可能性を優先的に考えていることがわかる
- 独自に調査し独自に判断していることで、担当者の地頭は悪くなさそうだ。


## 成功するチームに必要なこと
- 聞く耳を持つこと
人はすべて限られた経験の中で判断しています。
そのため、だれであっても判断を間違える危険性をもっています。
- 同僚に対して敬意を払おう
たとえ、いまは欠点しか見えていなくても。
- その目標を実現するためのチームのあり方を共有しよう
プロ野球のスコアをスクレイピングする

# はじめに
野球を見ていると「試合の流れ」があると言われます。
野球は素人ですが、長く試合を見ていると点が入りそうな雰囲気を分かるときがたまにあります。
セイバーメトリクスなど色々なデータがありますが、自分なりにスコアを分析してみたくなりました。

# スコアデータの取得
試合結果のデータを取得できるようなAPIは見つけられなかったので、プロ野球公式のページがからスクレイピングしてデータを取得することにします。

## elixirでスクレイピング
少し調べるとelixirでスクレイピングするには、HTTPoison, Flokiというライブラリを使えばいいようです。

手始めに3/29の阪神-巨人戦のスコアを取得してみます。（ちなみに阪神ファンです）

 https://npb.jp/scores/2024/0329/g-t-01/



``` elixir
document = HTTPoison.get!("https://npb.jp/scores/2024/0329/g-t-01/").body
|> Floki.parse_document!
|> Floki.find("div#table_linescore")
```
htmlをFlokiに渡せばmapとして取得できるようです。

## データ整形
今考えている分析に欲しい情報は、チーム名、イニングごとの得点、最終スコアなのでFlokiのセレクタを駆使して取得します。

https://hexdocs.pm/floki/readme.html#supported-selectors

``` elixir
inning = document
|> Floki.find("tr.top")

name = inning
|> Floki.find("span.hide_sp")
|> Floki.text()

scores = inning
|> Floki.find("td")
|> Enum.filter(fn {_tag, attrs, _value} ->not Enum.any?(attrs, fn{attr, _attr_val} -> attr == "class" end)end )
|> Enum.map(fn {_tag,_attr,value} -> value end)

total = inning
|> Floki.find("td.total-1")
|> Floki.text()
    
  %{name: name,scores: List.flatten(scores),total: total}
```

## スケジュールからスコアのリンクを作成

[https://npb.jp/scores/2024/0329/g-t-01/](https://npb.jp/scores/2024/0329/g-t-01/ "読売ジャイアンツ vs 阪神タイガース 1回戦")

上記のような試合速報のリンクは下記の試合結果のページから取得できます。

https://npb.jp/games/2024/schedule_03_detail.html

``` elixir
game_links = HTTPoison.get!("https://npb.jp/games/2024/schedule_03_detail.html").body
|> Floki.parse_document!
|> Floki.find("tbody a[href]")
|> Floki.attribute("href")
```
これで2024年3月の試合速報のリンクがリストとして取得できるので、データを整形します。

## JSON形式でファイル保存

取得したデータをJsonファイルに保存します。
chatGPTに聞くと次のようなコードが出てきました。


``` elixir
  case Jason.encode(data) do
      {:ok, json_string} ->
        # JSON文字列を指定したファイルに書き込み
        case File.write(file_path, json_string) do
          :ok -> {:ok, "File saved successfully!"}
          {:error, reason} -> {:error, "Failed to save file: #{reason}"}
        end
      {:error, reason} ->
        {:error, "Failed to encode JSON: #{reason}"}
    end
```

# 終わりに

分析に必要そうなファイルは保存することができたので、次はこのファイルを使って何か分析してみたいと思います。
  
## 追記
整理したソースをgithubにあげました。

https://github.com/u-akira/npb_games_crawler

下記のように実行すると2024年3月分の試合結果がscoresフォルダに作成されます。

``` elixir
NpbGamesCrawler.crawl("2024","03")
```
Laravelのbladeテンプレートを使用する場合のtitleタグ

## はじめに

Laravelのbladeテンプレートを使用する場合のtitleタグにはどの値が使用されるかついてまとめました。

## 対象者
この記事は下記のような人を対象にしています。

- Laravelのbladeテンプレートを使用する時に、titleタグには何が格納されるか知りたい方。



## 詳細

①番目
.envファイルのAPP_NAMEが使用される。
デフォルト値は、「Laravel」。

```php:.env
APP_NAME=Laravel
```

②番目
①が無ければ、
Laravelプロジェクトフォルダのconfig/app.php ファイルの
’name' => env('APP_NAME', 'Laravel'),
が使用される。
デフォルト値は、「Laravel」。

```php:app.php
'name' => env('APP_NAME', 'Laravel'),
```

③番目
②が無ければ、
app.blade.phpファイルにデフォルトで記載されている
{{ config('app.name', 'Laravel') }}
の'Laravel’が使用される。
デフォルト値は、「Laravel」。

```php:app.blade.php
<title>{{ config('app.name', 'Laravel') }}</title>

```

## おわりに
Laravelのbladeテンプレートを使用する場合、titleタグに格納される値についてまとめました。
[Standard] 品質、保守

# JIS X 25010:2013 (JIS X 0129) 
システム及びソフトウェアの品質に関する規格
|特性<br>副特性||
|:--|:--|
|機能適合性|必要な機能の実装度合い|
||機能完全性、機能正確性、機能適切性|
|互換性|ソフトウェア環境を共有する場合、構成要素を交換できる度合い|
||共存性、相互運用性|
|使用性|有効性、効率性、満足性をもって利用できる度合い|
||習得性、ユーザーインターフェース快美性|
|信頼性|明示された時間帯、条件下で明示された機能を実行する度合い|
||可用性、障害許容性、回復性|
|||
|||

## 参考リンク
- [平成26春47_使用性](https://www.ap-siken.com/kakomon/26_haru/q47.html)
- [令和元秋47_機能適合性](https://www.ap-siken.com/kakomon/01_aki/q47.html#:~:text=を表示する-,解説,に分割されています%E3%80%82)

# JIS X 0161:2008
ソフトウェア保守を対象にした規格
||||
|:--|:--|:--|
|訂正|是正保守|引渡し後、**発見された問題**の修正|
|訂正|予防保守|引渡し後、**潜在的な問題**の**運用前**の修正|
|改良|適応保守|引渡し後、**変化する環境**に対する修正|
|改良|完全化保守|引渡し後、**パフォーマンス**や**保守性**を**向上**させる修正|

## 参考リンク
- [R5A48_完全化](https://www.ap-siken.com/kakomon/04_haru/q48.html)
- [R2A48](https://www.ap-siken.com/kakomon/02_aki/q48.html)
- [H31S48_適応](https://www.ap-siken.com/kakomon/31_haru/q48.html)
makeなんちゃらで千円で買ったM5NANOC6でGroveLEDチカ(0921)


x 説明書を見よ

結果
(バッチは、#ﾋﾞｰﾙﾁｬﾝの所で貰った)

![o_coq447.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/2c217bb7-4ef4-9688-2eb8-461e3da734a8.jpeg)

![o_coq448.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/0b44da0e-ab6a-1e1e-0940-5f71d8b85eca.jpeg)

プログラム

```c++


//Grove_LED_C6_1

// the setup function runs once when you press reset or power the board
void setup() {
  // initialize digital pin LED_BUILTIN as an output.
  pinMode(1, OUTPUT);
}

// the loop function runs over and over again forever
void loop() {
  digitalWrite(1, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);                       // wait for a second
  digitalWrite(1, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);                       // wait for a second
}

```
久しぶりにAndroidプログラミングをしたら、オプションメニューが作れなかった問題

## 1.オプションメニューが作れなかった問題
３年ぶりぐらいにAndroidプログラミングを再開した。その時使っていた教科書を広げて「オプションメニュー」を作ろうとしたが、できない。アクティビティをよく見るとアクションバーがいつの間にか無くなっている!?(そういえば、最近のアプリにはアクションバーなんかないなぁ。）だから、オプションメニューが表示されないのかと納得。

![Screenshot_20240921_201756_25parcent.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/501068/bf052fa3-0118-f012-5f5b-506165e72747.png)　　![Screenshot_20240921_201418_25parcent.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/501068/c37fa0db-4ce3-f798-ff83-cf1baa10568c.png)　
図　最近のアクティビティー(アクションバーなし）と昔のアクティビティー

さて、なぜアクションバーが無いのか調べたとこを、リソースファイルの/res/themes.xmlに原因があることが分かった。
Theme.Material3.DayNight.NoActionBarとするとアクションバーが表示されず、
またTheme.Material3.DayNightとすると表示される。


```xml:/res/thermes.xml
<resources xmlns:tools="http://schemas.android.com/tools">
    <!-- Base application theme. -->

    <!-- もともとの設定(アクションバーを表示させない時)
        アクションバーを表示させるには、下の行の".NoActionBar"を削除 -->
    <!-- style name="Base.Theme.SEC_06_02_01_OpthionMenu"
        parent="Theme.Material3.DayNight.NoActionBar" -->

    <!-- アクションバーを表示させる時 -->
    <style name="Base.Theme.SEC_06_02_01_OpthionMenu"
        parent="Theme.Material3.DayNight" >

    <!-- アクションバーの表示・非表示について -->
    <!-- https://zenn.dev/hajime9109/scraps/5eac78893e58f2 -->

    <!-- Customize your light theme here. -->
        <item name="colorPrimary">@color/my_light_primary</item>

    </style>

    <style name="Theme.SEC_06_02_01_OpthionMenu" parent="Base.Theme.SEC_06_02_01_OpthionMenu" />
</resources>
```

Android Studio Flamingo(2023年4月)からアクションバーがデフォルトで非表示になったらしい(一次情報を調べたわけではないが）。

## 2.余談
3年ぶりにandroidプログラミングを再開するにあたり、AndroidStudioの開発環境が進化した分、確実に浦島太郎になっていると思い、[いきなりプログラミング Androidアプリの開発](https://www.shoeisha.co.jp/book/detail/9784798178998)を買った。内容ははじめてAndroidプログラミングをする人向けであった。オプションメニューが作れない問題に遭遇し、再び読み直したところオプションメニューを使うサンプルアプリの掲載はなかった。
Android Studio Flamingo(2023年4月)以降、アクションバーが表示されないのがデフォルトになったため、今後オプションメニューを使わないことがトレンドになるのだろう。

## 3.最後に
斎藤著「Androidアプリ開発の教科書Kotlin対応(初版)」や金田著「Kotlin対応　はじめてのAndroidプログラミング第４版」、山田著「はじめてのAndroidアプリ開発 Kotlin編」などの古い教科書で勉強されている方々に本記事を捧げます。
Azure Portal を日本語で使う場合は、自動で機械翻訳されている？ことを意識しておこう

# 結論

- サービスや機能を検索する場合には、以下があることを理解しておこう
   1. 日本語でしか検索できない
   1. 英語でしか検索出来ない
   1. 日本語・英語でも検索できる

日本語で使うからこその弊害ですね :sweat: 


# サービス検索での例

Azure Policy は「ポリシー」として日本語でしか出ない。
※時期によっては、「policy」で出てるっぽいので、機械翻訳次第？ :thinking: 

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/3ff4b6b3-eebe-9c6f-fbca-0ed98aa3cb51.png)

# RBAC での実際の例

https://qiita.com/baku2san/items/9bb425430fc3e93ea365

# あとがき

「名前」「翻訳名」と二種類用意して
表示設定で選べるようにしてくれればこんなことなくなるはずなんですがね。

|Name|Name Localized|
|-|-|
|Azure Policy|ポリシー|


Microsoftさんにしては、何故こんなことになっているのか・・
【初心者向け】Dockerfile入門

# Dockerfileとは？
- Dockerコンテナの基となる、Dockerイメージをテキスト化したもの
- DockerfileからDockerイメージを作ることができる
- 内容としては以下等をDockerfile命令という形で指定している
    - そのコンテナのベースとなるイメージ
    - そのイメージ、コンテナで実行したいコマンド
    - ホストOSからコンテナにコピーしたいファイル
    - 環境変数
- 例
```
FROM ubuntu:20.04
RUN apt-get update -y && \
    apt-get install -y nginx
CMD ["nginx", "-g", "daemon off;"] 

```

## Dockerfile命令
### FROM
- 基になるイメージを指定する
- Dockerfileの最初の命令として使用する
- 例
    - FROM ubuntu:20.04
### RUN
- イメージのビルド中にじっこうするコマンドを指定する。通常、ソフトウェアのインストールや設定変更に使われる
- 例
    - RUN apt-get update && apt-getinstall -y curl
### CMD
- コンテナが起動する際に実行するデフォルトのコマンドを指定する
- 例
    - CMD ["nginx","-g","daemon off;"]
### COPY
- ホストシステムからDockerイメージにファイルやディレクトリをコピーする
- 記法
    - COPY {ホストのファイル} {コンテナのパス}
- 例
    - COPY conf /etc/httpd/conf
### ADD
- ホストシステムだけでなく、インターネットからもファイルをイメージに追加することができる
- COPYの強化版ではあるが、公式はCOPYの使用を推奨している
    - →そもそもの考え方として、疎結合性を大事にしているから
### ENV
- Dockerイメージが生成されるタイミングで環境変数を設定する
    - DBのユーザー名
    - 動作環境
    - etc
- 固定値になってしまう（ユーザーによって変更できない）点に注意
- 記法
    - ENV {キー値} {バリュー値}
- 例
    - ENV APP_ENV="production"
# 参照
https://qiita.com/nana-solid/items/6e21302e60b23c4e24d0

https://qiita.com/nana-solid/items/423b4b056bd20b1f12a2
ベストプラクティスを聞いても私が「何が嬉しいのかわからない、、」となる原因

## 結論
- 以下のどちらかが原因かも？と思った
    - 「ベストプラクティスの題名 = 実現したいこと」とは限らない
    - ベストプラクティスを聞いた時、無意識に自分で意味を狭めている
- 後者には単に知識不足とかも内包されているので、厳密には他にも原因はある
- 解決策
    - ベストプラクティスを聞いたら、その具体例を追って、何が嬉しいのか自分で見つける(腑に落ちる)努力をする
        - そうすれば、どちらの原因も、はたまた知識不足も、理解の浅さも軽減されていくと思う

## 結論に至った経緯
- 以下の考えをまとめている時に、ふと思った

![スクリーンショット 2024-09-21 20.55.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/690075/cac8b5fb-40a2-d04f-183b-250a9f6f2acc.png)
【Blender】自動で均等にオフセットをかけてUVのラッピングを一括解消するスクリプト

# 概要
要はこういうことができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272076/9fe8331e-1799-113f-ad5a-cb19e7809a26.png)

# 用途
アルベドマップはメモリ削減のためにUVをラッピングさせて使いまわしたいけど、完全に重ねるとSubstancePainterなど外部ツールでのマップベイクで問題が起きる、みたいなときに使えるかと思います。
（なんか自動アンラップみたいな機能があるらしいですが、私のバージョンは古すぎるのかそのあたりの項目が見当たりませんでした。どっちにしろ不健全なリソースではあるのでBlender時点でこうしてしまおうという魂胆です。）

# 使用方法
ChatGPTに書いてもらいました。
まず、テキストエディタを開きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272076/48a6bd5f-5836-d643-41a0-9dc8f992282a.png)

テキストを新規作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272076/c7ec2232-fdee-0f2f-fdec-32c88d6bbdce.png)

そうしたら、以下の内容を貼り付けます。
```py
import bpy
import bmesh

# テクスチャ1枚分のオフセット値（通常は1.0が標準サイズ）
offset_value = 1.0

# アクティブオブジェクトを取得
obj = bpy.context.active_object

# UVマップが存在するか確認
if not obj.data.uv_layers:
    print("UVマップが存在しません")
else:
    # 編集モードに切り替え
    bpy.ops.object.mode_set(mode='EDIT')

    # BMeshを作成
    bm = bmesh.from_edit_mesh(obj.data)

    # UVレイヤーを取得
    uv_layer = bm.loops.layers.uv.verify()

    # 選択された面を取得
    selected_faces = [f for f in bm.faces if f.select]

    if len(selected_faces) == 0:
        print("選択された面がありません。")
    else:
        # 最初の面のUVはそのままで、2つ目以降の面のUVをオフセット
        for i, face in enumerate(selected_faces):
            offset_x = i * offset_value
            
            for loop in face.loops:
                uv = loop[uv_layer].uv
                uv.x += offset_x  # X方向にオフセットを加える

        # UVの変更を反映
        bmesh.update_edit_mesh(obj.data)

    print("UVオフセットの適用が完了しました。")


```

編集モードに入り、UVエディタの面選択モード→「Bキー」の矩形選択などでラッピングしている面を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272076/9856f317-d90c-a256-7af2-b108198b4354.png)

面を選択したら、テキストエディタの再生ボタンでスクリプトを実行します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272076/5ebcef70-3189-e59f-f06f-88bdc976f31d.png)

成功すると、以下のような結果になっていることが確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272076/73bf794d-e138-77ee-b163-303e72308692.png)

以上です。
ビジュアルプログラミングで高位合成 その6

# 概要
ビジュアルプログラミングで組み合わせ回路を組み立てて、シュミレーションして、verilogを生成します。
高位合成です。
実は、今の実装では、半加算器、全加算器が高位合成できません。
半加算器の高位合成を実装しました。検証します。
検証編

# テストベンチを書く。

```

module x(input A, input B, output Sum, output Carry);
	assign Sum = (A ^ B);
	assign Carry = (A & B);
endmodule

module test;
	reg A;
	reg B;
	x u(.A(A), .B(B), .Sum(Sum), .Carry(Carry));
	initial
	begin
		$display(" A   B   Sum Carry");
		$monitor(" %b  %b  %b  %b", A, B, Sum, Carry);
		A = 0;
		B = 0;
	#10;
		A = 0;
		B = 1;
	#10;
		A = 1;
		B = 0;
	#10;
		A = 1;
		B = 1;
	#10;
		$finish;
	end
endmodule

```

# iverilogでシュミレーション実行

```
>iverilog ha0.v

>vvp a.out
 A   B   Sum Carry
 0  0  0  0
 0  1  1  0
 1  0  1  0
 1  1  0  1
ha0.v:27: $finish called at 40 (1s)

```

以上
サーバー証明書の取得からクライアント認証までのプロセス

# はじめに
以前、[SSL/TLSについてざっくり理解してみる](https://qiita.com/yamataikoku2001/items/c02994fad3b91ed5491b)という記事を書いたときに、
 - 認証局とどのようなやり取りをして、サーバー証明書が出来上がるのか
 - クライアント側でどのように認証しているのか

具体的に書くことができなかったので、本記事ではその部分に焦点を当てたいと思います。
[SSL/TLSについてざっくり理解してみる](https://qiita.com/yamataikoku2001/items/c02994fad3b91ed5491b)で掲載した以下の図をより詳しく見ていくというイメージです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3831555/c28164cd-7df4-975e-4948-8fec2ffc376d.png)

# より詳しいプロセス
以下に上記の図をより詳細化した、サーバー証明書の取得からクライアント認証までのプロセスの図を示します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3831555/89deb5b1-9fc2-670b-9948-6cdcff924fed.png)

1. サーバーで秘密鍵と公開鍵を生成する
2. 生成した公開鍵やドメイン名などの情報を含めたCSR（Certificate Signing Request：証明書署名要求）を作成し、認証局に送る
3. 認証局が審査を行う（種類としては以下の3つがあります）
    1. ドメイン認証型（DV）
    ドメインの所有者を検証するだけ
    2. 企業認証型（OV）
    ドメインの所有者と企業の法的実在性を検証する
    3. Extended Validation（EV）
    ドメインの所有者と企業の法的実在性に加え、物理的実在性、組織の運営状況など他にも多くの項目で検証していきます
4. 認証局がサーバー証明書を発行する。（認証局は発行時に以下のことを行います）
    1. 証明書の内容全体に対してハッシュ関数を適用し、ハッシュ値を生成します
    2. 認証局は生成されたハッシュ値を認証局の秘密鍵で暗号化します。この2番の部分をデジタル署名と言います。
5. サーバー証明書を受け取ったサーバーはサーバー証明書をサーバーにインストール
6. クライアントからサーバーにSSL通信のリクエストを送信する
7. サーバーはサーバー証明書をクライアントPCに送付する
8. 4.2の所で、認証局の秘密鍵で暗号化されたデジタル署名部分の復号を認証局の公開鍵（※）で行う。同じハッシュ結果なら、正当なサーバー証明書と判断することができます。

※ 認証局の公開鍵がなぜあるのかというと、代表的な認証局のデジタル証明書の場合、クライアントPCのブラウザに認証局の公開鍵を含んだサーバー証明書がインストールされているためです。

# クライアント側の認証方法
[より詳しいプロセス](https://qiita.com/yamataikoku2001/items/1d760d357fed4cae2701#%E3%82%88%E3%82%8A%E8%A9%B3%E3%81%97%E3%81%84%E3%83%97%E3%83%AD%E3%82%BB%E3%82%B9)の `8` で書いているように、ハッシュの結果を比較して、改ざんが無いか検証しています。
具体的にどのように、認証しているかを見てみたいと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3831555/38fda8c6-0df6-3475-10d9-1b5eabe43b9b.png)
上記のように、「クライアント側で署名前証明書を署名アルゴリズムで計算したハッシュ値」と「デジタル署名を認証局の公開鍵で復号したときに得られるハッシュ値」を比較し検証することで、認証を行っています。

# まとめ
サーバー証明書の取得からクライアント認証までのプロセスをまとめていく中で、デジタル署名の意味や認証局の審査の種類など副次的に知らない知識も多く出てきて、まだまだ知らない知識や概念があることを感じました。

SSL/TLSハンドシェイクなどSSL/TLS周りでまだまだ分からない点があるため、次回以降まとめていきたいと思います。

本記事の内容に誤りがある場合はご指摘いただけると大変助かります。

# 参考文献
https://www.gmo.jp/security/ciphersecurity/not-secure/blog/ssl/

https://blog.serverworks.co.jp/understanding-ssl-tls#デジタル署名とデジタル証明書

https://www.infraexpert.com/study/security6.html
ポートを振り分けてRedmine/Gitlabを1つのマシンで構築

# はじめに
本記事はDockerを使ってRedmine/Gitlabを簡単に構築する方法を紹介します。参考文献にリバースプロキシを使って構築する方法を載せています。よければそちらも参照ください。

# 全体概要
全体の概要図を以下に示します。今回はホストOSのポートを2つ用意し、それぞれでRedmine,Gitlabを稼働させる流れになります。

![sample2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/693671/57c93cf3-8018-bcc2-cf73-bdb4208a475c.png)




# フォルダ構成
以下にフォルダ構成を示します。
```
├── docker-compose.yml
├── dockerfiles
│   ├── gitlab.Dockerfile
│   ├── mysql.Dockerfile
│   └── redmine.Dockerfile
├── gitlab
├── mysql
└── redmine
```


# 手順
以下にdocker-compose.ymlファイルの内容を示します。本手順では、ホストOSの8081ポートにアクセスしたら、Redmineが表示され、8082ポートにアクセスしたらGitlabが動作するようにします。
```
version: '3'
services:
  redmine:
    container_name: redmine_container
    restart: always
    build:
      context: .
      dockerfile: dockerfiles/redmine.Dockerfile
    networks:
      - redmine_gitlab_net
    volumes:
      - ./redmine/files:/usr/src/redmine/files
      - ./redmine/plugins:/usr/src/redmine/plugins
    ports:
      - 8081:3000
    environment:
      - TZ=Asia/Tokyo
  db:
    container_name: mysql_container
    build:
      context: .
      dockerfile: dockerfiles/mysql.Dockerfile
    networks:
      - redmine_gitlab_net
    volumes:
      - ./mysql/data:/var/lib/mysql
    environment:
      - TZ=Asia/Tokyo
  gitlab:
    container_name: gitlab_container
    build:
      context: .
      dockerfile: dockerfiles/gitlab.Dockerfile
    networks:
      - redmine_gitlab_net
    volumes:
      - ./gitlab/config:/etc/gitlab
      - ./gitlab/logs:/var/log/gitlab
      - ./gitlab/gitlab/data:/var/opt/gitlab
    hostname: 'localhost'
    ports:
      - 8082:3001
    environment:
      GITLAB_OMNIBUS_CONFIG: |
        external_url 'http://localhost:3001'

networks:
  redmine_gitlab_net:
    external: true
```

以下がredmineコンテナのdockerfileです。
```
FROM redmine

RUN apt update && apt install vim -y

ENV REDMINE_DB_MYSQL=db
ENV REDMINE_DB_PASSWORD=redmine_pass
ENV REDMINE_DB_DATABASE=redmine
ENV REDMINE_DB_USERNAME=redmine_user
```
以下がgitlabコンテナのdockerfileです。
```
FROM gitlab/gitlab-ce:12.2.1-ce.0
RUN apt update && apt install vim -y
```

以下がmysqlコンテナのdockerfileです。このコンテナはredmineのチケット情報などを格納するために用います。
```
FROM mysql:8.0

ENV MYSQL_ROOT_PASSWORD=root_password
ENV  MYSQL_DATABASE=redmine
ENV  MYSQL_USER=redmine_user
ENV  MYSQL_PASSWORD=redmine_pass
FROM redmine
```

上記ファイルの準備ができたら、docker-compose.ymlファイルが存在する階層で以下コマンドでコンテナのビルドを行ってください。
```
docker-compose up -d
```

# 結果
結果は以下のように8081ポートにアクセスしたら、redmineが表示され、8082ポートにアクセスしたらgitlabが表示されました。成功です。
![スクリーンショット 2024-09-21 12.01.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/693671/8f883229-52b0-683e-f8e4-1fee119b203e.png)

![スクリーンショット 2024-09-21 12.01.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/693671/800060d5-d9ee-e895-da46-d1dbe92cc8c2.png)

# 参考文献
[Qiita : Dockerを使ってRedmine/Gitlabの構築](https://qiita.com/loverboy/items/e95275bb43c934380017)
ELBテストでAZを表示させるページを作りたい！

### :sunny: 実現したいこと：どのAZにあるEC2なのかを表示させるページを作りたい


ELBのテストでAZが記載されているページを表示させて、「ほら、負荷分散されてますね！」と見せているデモをよく見かけるのですが、あれに憧れたのでやってみたいと思います！

<img width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3828602/81814858-3537-3d7b-ee3f-6baefa89bef9.png">

↑こんな感じ


## 1.EC2インスタンスを作成し、ユーザーデータを仕込む

今回はユーザーデータを使ってLinux上で上記のページを作っていきたいと思います。

1.いつも通りEC2インスタンスの作成ボタンをクリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3828602/54998dd7-62db-581d-d22c-36fb5123670d.png)

2.作成画面で名前などを入力していく…

::: note info
この時、**高度な詳細 > メタデータのバージョン**で**V1およびV2（トークンはオプション）** を選択
:::
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3828602/36f62c44-e4a5-72db-4a02-230d364d83a6.png)

3.**ユーザーデータ**に以下を入力してインスタンスを起動する
```
#!/bin/bash
# Install necessary packages
yum update -y
yum install -y httpd

# Start the HTTP server
service httpd start
chkconfig httpd on

# Get the availability zone
AZ=$(curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone)

# Create an HTML page to display the Availability Zone
echo "<html><body><h1>Availability Zone: $AZ</h1></body></html>" > /var/www/html/index.html
```


ALBでマルチAZ構成で冗長化する場合は別AZにもインスタンスを立てて、ALBのDNS名をブラウザに貼り付けるとAZが表示されたページが見られます！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3828602/d3c0f533-a35c-5781-bdee-425c1849e4c9.png)

<img width="500" src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3828602/b562e7f7-5f3b-be29-345c-758a724a8aeb.png'>

更新してみると…

<img width='500' src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3828602/69824c86-c26e-2f4f-6919-642b68530e46.png'>

変わっていることが確認できました！
Technical Master 98 「はじめてのAndroidアプリ開発 Kotlin編」 誤記情報 p.197 リスト4-19

[山田祥寛 著　Technical Master 98 「はじめてのAndroidアプリ開発 Kotlin編」](https://www.shuwasystem.co.jp/book/9784798065106.html)にて誤記を見つけましたので、情報共有します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/501068/95c6eeea-df08-bf0c-c2ed-29cbc15f65d4.png)


該当部分
p.197 リスト4-19
``` :Kotlin
class MyListAdapter(
    private val context: Context,
    private val data: List<ListItem>,
    private val resource: Int
) : BaseAdapter() {
    // 省略
    override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
        val item  = getItem(position) as ListItem    // <---ここをListItemでキャスト
        // val item  = getItem(position) // 元々
        val sview = convertView ?: inflater.inflate(resource, null)
        sview.findViewById<TextView>(R.id.title).text = item.title
        sview.findViewById<TextView>(R.id.tag).text = item.tag
        sview.findViewById<TextView>(R.id.desc).text = item.desc
        return sview
    }
}
```

尚、私の本は、第１版第１刷です。[掲載サンプルコート](https://wings.msn.to/index.php/-/A-07/978-4-7980-6510-6/)を確認しましたが、修正されていませんでした。

また、ListItemでキャストしていないと、以下の図のようにエラーになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/501068/1d81c486-4145-33fd-ed54-e4239e680d26.png)

この修正するにあたり、山田祥寛 著　「Technical Master 93 「はじめてのAndroidアプリ開発 第3版Android Studio3対応」(java)を参考にしました。
Rust で依存先のソースを勝手に書き換える

## 目的

Rust で依存しているクレートに（自分にとっての）不都合があった時、勝手に書き換える方法を紹介します。

使用例：勝手に feature を追加したい、一部の不要なコードを消したい

ほとんど以下の公式ドキュメントに書いてあります。

https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html

https://doc.rust-lang.org/cargo/reference/overriding-dependencies.html

## 直接依存している場合

自分の `Cargo.toml` で直接依存先として指定している場合。

1. 依存先のリポジトリを fork か clone する
1. 好きに書き換える
    - fork した場合は commit&push も
1. 自分の `Cargo.toml` の `dependency` セクションを編集する
    - before: `クレート名 = "バージョン"`
    - after (fork): `クレート名 = { git = "https://github.com/フォーク先のURL.git" }`
        - ブランチを変えたければ `, branch = ブランチ名` で指定
    - after (clone): `クレート名 = { path = "クローンしたパス" }`
1. おわり

## 間接的に依存している場合

自分の `Cargo.toml` で直接指定した依存先の、そのまた依存先のクレートを書き換えたい場合。

↑の方法を再帰的に行うこともできるが、手間がかかるので。

1. 依存先のリポジトリを fork か clone する
1. 好きに書き換える
    - fork した場合は commit&push も
    - （ここまでは同じ）
1. 自分の `Cargo.toml` に **`[patch.crates-io]`** セクションを追加する
    - ここで、各クレートの依存解決をする時の参照先を書き換えられる
1. dependency と同様に、書き換え元・先を指定する
    - fork: `クレート名 = { git = "https://github.com/フォーク先のURL.git" }`
        - ブランチを変えたければ `, branch = ブランチ名` で指定
    - clone: `クレート名 = { path = "クローンしたパス" }`
1. おわり

## まとめ

Pull Request を出せばいい話なんですが、

- ハッカソンや研究の実装だとコミュニケーションの時間・時間が惜しい
- 自分だけに必要でマージしてもらうほどではない

ようなケースが個人的にはよくあります。

そんなわけで、無理やり書き換える方法を備忘録的に説明しました。
業務のチャットで文章をすぐに作成できるようにする方法

:::note
文の作り方
1. まずは箇条書きで要点をまとめる
2. 最後に飾りをつける
:::

# 背景
連絡手段はチャットを使っています。
一つのチケットの開発を様々な人を巻き込んで進めています。
その際にチャットでまめに連絡が必要になってきます。
すぐに文章の作成ができず苦戦していた所、社内の方々からフィードバックをもらえました。

# 文の作り方
1. まずは箇条書きで要点をまとめる
2. 最後に飾りをつける

敬語などの飾りを最初から入力すると、一旦消す際に要点も消えてしまいます
これによってロスが発生します

# 少々粗くても早く送った方が良い
- 文章作成に毎回、5分かかっていたとしてこれが積み重なると業務の妨げになります
- 相手に早く情報を伝えられます
- 早く送った分、相手からのレスポンスが早く来やすくなり、自分の仕事が早く進められます

# 最後に
文章の気配りに時間をかけるよりは、まずは要点を絞って相手に早く、簡潔な文を送りたいです
一見当たり前かもしれないのですが、一つずつこなして最短で結果が出せるようになりたいです

所属企業に興味ある方は以下ご覧ください！

https://www.courier.jpn.com/recruit/
ChatGPT開発入門

## GPTのAPI基礎知識

### 料金
- トークンに対してお金がかかってくる。
    - トークンは日本語よりも英語の方がカウント数が少なくなるので開発の時には英語を使った方がいい。

## プロンプトエンジニアリング

### 参考記事
[プロンプトエンジニアリングガイド](https://www.promptingguide.ai/jp)

### プロンプトの手法
- Few-Shotプロンプティング
質問の時にいくつか例を提供してあげると精度が上がる

- Chain-of-Thoughtプロンプティング
ステップバイステップで回答をしてもらう方法

## LangChain
### 使われている言語
Python,TypeScri pt

### ユースケース
- 文書の要約
- チャットボット
- ドキュメントへのQA

### Models
機械学習のモデルのこと

- LLMs：CompletionsAPI
- Chat Models：Chat API
- Text Embedding Models

### Chains
- 例えば、Promptを使った後にModelを使いたいなどがある場合にその流れをつなぐときに使う。
- SimpleSequentialChainを使うとChainとChainを連結することができる。
【Python】venvを利用した仮想環境

# はじめに

最近現職の同期と勉強がてらアプリ制作を始めました。
そこで初めてPythonを触って仮想環境なるものを知りました。
今回はvenvを利用した仮想環境の作成方法について備忘録として残します。

# 環境
- macOS: 15.0(24A335)
- Python: 3.12.5 (グローバル)
- Visual Studio Code : 1.93.0 (Universal)

# Pythonの仮想環境とは？

自身のPC上で、独立したPythonの実行環境を作成する仕組み。
下記のようなメリットがあるようです。

> （１）環境ごとに異なるバージョンのPythonを使える
> （２）環境ごとに異なる外部ライブラリをインストールできる
> （３）環境ごとに異なるバージョンの外部ライブラリをインストールできる

引用元: [実務で必須の「Python仮想環境」について学ぼう！](https://www.insource.co.jp/python-gakuin/mail-backnumber/vol30.html)

# 仮想環境の作成と利用方法
仮想環境を作成する方法はいろいろあるようですが、今回は`vnev`を利用する方法で作成します。

### 1. 仮想環境を作成する

適当なディレクトリで、下記コマンドを実行します。
<仮想環境の名前>は適宜置き換えてください。

```bash
python3 -m venv <仮想環境の名前>
```

今回は仮想環境の名前を`test`にして実行
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2513223/71f2b663-8936-52eb-bf55-c1c3a265e59c.png)

実行すると関連ファイルが作成されました。
![Code 2024-09-21 19.06.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2513223/4bddcf66-b1bc-03d4-a39b-7f7256109d51.png)


### 2. 仮想環境を起動する

下記コマンドを実行すると作成した仮想環境を起動できます。

```bash
source 仮想環境の名前/bin/activate
```

仮想環境を実行中は、コマンド？プロンプト？の頭に作成した仮想環境の名前`(test)`が表示されるようになります。
![image-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2513223/d32bebd4-3b4d-5c0c-f50b-c49bd1fffb14.png)

### 3. 仮想環境を終了する
下記コマンドを実行することで仮想環境を終了できます。
```
deactivate
```
終了すると、`(test)`の表示がなくなりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2513223/73d0465d-12ef-799f-5399-77d106122179.png)

# さいごに

今回は、Python仮想環境について書いてみました。
細かい設定とかあるんだろうけど、一旦ここまで。
これから少しずつ覚えていきたいと思います。

# 参考記事

https://qiita.com/fiftystorm36/items/b2fd47cf32c7694adc2e

https://www.acrovision.jp/career/?p=2254

https://www.insource.co.jp/python-gakuin/mail-backnumber/vol30.html
RSSとAtom 記事一覧の取得方法の話

# はじめに
複数のプラットフォームから記事一覧を取得したい！
なるべく処理を共通化したい！

# RSS1.0 / RSS2.0 / Atom
https://medifund.jp/seo/rss-atom/

こちらの記事がとても参考になります。
記事情報の取得（**Feed**）のための仕組みは３種類あるようです。

| 仕組み | 採用プラットフォーム | タイトルの取得方法 |
| :-: | :-: | :-: |
| RSS1.0| | |
| RSS2.0 | Zenn / しずかなインターネット / note | `channel > item > title`|
| Atom | Qiita / Github（コミット情報）| `entry > title` |

同じ仕組みを採用している場合、処理を共通化することができます。

# 共通化した処理
プラットフォームごとのURLを受け取り、共通化された処理を行います。

返り値は`{title:string, link:string, published:date}`です。

仕組みによりますが、以下の要素も取得可能です。
- `description`：書き出し等
- `enclosure`：見出し画像
- `author`：著者
- `updated`：更新日時
## RSS2.0の場合（GAS）

```js
const getRss2 = (url) => {
  // RSSフィードを取得
  const response = UrlFetchApp.fetch(url);
  const xml = response.getContentText();
  
  // XMLをパース
  const document = XmlService.parse(xml);
  const items = document.getRootElement().getChild('channel').getChildren('item');

  // 連想配列のリストを作成
  const feedData = items.map(item => {
    const title = item.getChild('title').getText();
    const link = item.getChild('link').getText();
    const published = item.getChild('pubDate').getText();
    
    return {
      title: title,
      link: link,
      published: published
    };
  });

  return feedData;
}
```

## Atomの場合

```js
const getAtom = (url) => {
  const response = UrlFetchApp.fetch(url);
  const xml = response.getContentText();
  
  // XMLをパース
  const document = XmlService.parse(xml);
  const entries = document.getRootElement().getChildren('entry', XmlService.getNamespace('http://www.w3.org/2005/Atom'));

  // 連想配列のリストを作成
  const feedData = entries.map(entry => {
    const title = entry.getChild('title', XmlService.getNamespace('http://www.w3.org/2005/Atom')).getText();
    const link = entry.getChild('link', XmlService.getNamespace('http://www.w3.org/2005/Atom')).getAttribute('href').getValue();
    const published = entry.getChild('published', XmlService.getNamespace('http://www.w3.org/2005/Atom')).getText();
    
    return {
      title: title,
      link: link,
      published: published
    };
  });
  return feedData;
}
```
:::note warn
## `link`の取得
RSS2.0
```xml
<link>
  https://sizu.me/kohki_takatama/posts/uw2ce6ntoa99
</link>
```
Atom
```xml
<link
  rel="alternate"
  type="text/html"
  href="https://qiita.com/kohki_takatama/items/9b319e83a00c491baf2a"
/>
```
このように、`link`の記述方法が異なり、取得方法も変わります。
Atomは`url`タグで取得することも可能です。
:::

# 参考記事
各サイトのFeed URL

https://qiita.com/Lemon73/items/8af0f6f1dce25efdb533

Feedの種類

https://medifund.jp/seo/rss-atom/
Polarsを使って、Python-MIPの数理モデルを作ってみよう

## 概要

次の記事では、pandasを使って、Python-MIPの数理モデルを作ってみました。

https://qiita.com/SaitoTsutomu/items/c7b43c2e02710749d117

本記事では、**Polarsを使って、Python-MIPの数理モデルを作成**します。
Python-MIPの使い方については、上記記事を参照してください。
Polarsについては、公式ドキュメントを参照してください。

https://docs.pola.rs/

## 諸元

参照記事と同じように倉庫や工場の諸元を作成します。
ここでは、パッと見てわかりやすいように変数名に漢字を使っています。

```python
import polars as pl
from mip import Model, minimize, xsum

def xdot(s1: pl.Series, s2: pl.Series):
    return xsum(s1.to_numpy() * s2.to_numpy())

供給 = [44, 42, 45]
需要 = [39, 23, 22, 32]
輸送費 = [17, 16, 18, 10, 13, 15, 14, 13, 13, 10, 11, 15]

df_倉庫 = pl.DataFrame({"倉庫": ["W1", "W2", "W3"], "供給": 供給})
df_工場 = pl.DataFrame({"工場": ["F1", "F2", "F3", "F4"], "需要": 需要})
```

## 数理モデル

Polarsを使って数理モデルを作成します。

```python
# 数理モデル
m = Model()

# 変数表
_vars = m.add_var_tensor((len(輸送費),), "Var")
df_変数 = df_倉庫.join(df_工場, how="cross").with_columns(
    輸送費=pl.Series(輸送費), 変数=pl.Series(_vars)
)

# 目的関数
m.objective = minimize(xdot(df_変数.get_column("輸送費"), df_変数.get_column("変数")))

# 制約条件
for _, group in df_変数.group_by("倉庫"):
    m += xsum(group.get_column("変数")) <= group.get_column("供給")[0]
for _, group in df_変数.group_by("工場"):
    m += xsum(group.get_column("変数")) >= group.get_column("需要")[0]
```

※ `xdot`の代わりに`numpy.dot`が使えますが、効率が悪いです。

## ソルバーの実行と結果表示

```python
m.verbose = 0
m.optimize()
_values = df_変数.get_column("変数").to_numpy().astype(float)
df_変数 = df_変数.with_columns(結果=pl.Series(_values))
print(df_変数.filter(pl.col("結果") > 0))
print(f"目的関数値 = {m.objective_value}")
```

```
shape: (4, 7)
┌──────┬──────┬──────┬──────┬────────┬────────┬──────┐
│ 倉庫 ┆ 供給 ┆ 工場 ┆ 需要 ┆ 輸送費 ┆ 変数   ┆ 結果 │
│ ---  ┆ ---  ┆ ---  ┆ ---  ┆ ---    ┆ ---    ┆ ---  │
│ str  ┆ i64  ┆ str  ┆ i64  ┆ i64    ┆ object ┆ f64  │
╞══════╪══════╪══════╪══════╪════════╪════════╪══════╡
│ W1   ┆ 44   ┆ F4   ┆ 32   ┆ 10     ┆ v_03   ┆ 32.0 │
│ W2   ┆ 42   ┆ F1   ┆ 39   ┆ 13     ┆ v_04   ┆ 39.0 │
│ W3   ┆ 45   ┆ F2   ┆ 23   ┆ 10     ┆ v_09   ┆ 23.0 │
│ W3   ┆ 45   ┆ F3   ┆ 22   ┆ 11     ┆ v_10   ┆ 22.0 │
└──────┴──────┴──────┴──────┴────────┴────────┴──────┘
目的関数値 = 1299.0
```

## 数式を扱うときの注意

Polarsの特徴は、実データを含まずに、式（エクスプレッション）を記述できることです。
しかし、最適化モデルの変数を含んだ数式は、エクスプレッションとして記述できません。

たとえば、次の目的関数の式は実データで内積を取っています。

```python
xsum(df_変数.get_column("輸送費").to_numpy() * df_変数.get_column("変数").to_numpy())
```

エクスプレッションが数式を扱えれば次のように書けますが、実際には書けません。

```python
df_変数.select(pl.col("輸送費") * pl.col("変数")).sum()
```

このようにPolarsで数式を扱う場合、実データを使って計算を記述しないといけないことに注意してください。

## M1/M2 macでのインストールについて補足

Python-MIP`1.15.0`までに付属するCBCは、x86_64版なので、x86_64アーキテクチャで動作させる必要があります。しかし、M1/M2 macのx86_64では、Polarsが動きません。
その場合は、`polar`の代わりに`polars-lts-cpu`をインストールすることで、x86_64でPolarsを動かせます。

※ Python-MIP`1.16.0`が出れば、arm64でそのまま動かせるようになると思われます。

## まとめ

Polarsを使って、Python-MIPの数理モデルを作成しました。
Polarsは、DataFrameとSeriesが、1つの文で独立にメソッドチェーンを組み立てられます。
これにより、シンプルな構文のまま柔軟な処理を記述できます。
また、モデル作成の処理時間が（pandasより）高速になるかもしれません。

## 参考

https://qiita.com/SaitoTsutomu/items/bbd879280f5a934b5925

以上
ビジュアルプログラミングで高位合成 その5

# 概要
ビジュアルプログラミングで組み合わせ回路を組み立てて、シュミレーションして、verilogを生成します。
高位合成です。
実は、今の実装では、半加算器、全加算器が高位合成できません。
半加算器の高位合成を実装します。
実装編

# 成果物

https://embed.plnkr.co/plunk/3dX40SUC5LEbZD7j

# 生成したverilog

```
module x(input A, input B, output Sum, output Carry);
	assign Sum = (A ^ B);
	assign Carry = (A & B);
endmodule


```

# サンプルコード

```

function make(s) {
	var i;
	var j;
	var k;
	var res = "";
	var ins = [];
	var outs = [];
	var divs = [];
	var ass = [];
	var json = JSON.parse(s);
 	var koko = document.getElementById("koko");
	for (i = 0; i < json.devices.length; i++) 
	{
    if (json.devices[i].type == "In")
    {
			ins.push({
				id: json.devices[i].id,
				label: json.devices[i].label
			});
    }
	}
	for (i = 0; i < json.devices.length; i++) 
	{
    if (json.devices[i].type == "Out")
    {
			outs.push({
				id: json.devices[i].id,
				label: json.devices[i].label
			});
    }
	}
	for (i = 0; i < json.devices.length; i++) 
	{
    if (json.devices[i].type == "XOR" || json.devices[i].type == "NAND" || json.devices[i].type == "AND" || json.devices[i].type == "OR" || json.devices[i].type == "NOR" || json.devices[i].type == "NXOR")
    {
			divs.push({
				id: json.devices[i].id,
				type: json.devices[i].type
			});
    }
	}
	res += "module x(";
	if (ins.length == 2)
	{
		res += "input " + ins[0].label + ", ";
		res += "input " + ins[1].label + ", ";
	}
	if (outs.length == 1)
	{
		res += "output " + outs[0].label + ");\n";
	}
	if (outs.length == 2)
	{
		res += "output " + outs[0].label + ", ";
		res += "output " + outs[1].label + ");\n";
	}
	for (k = 0; k < divs.length; k++) 
	{
		res += "\tassign ";
		for (i = 0; i < json.connectors.length; i++) 
		{
  	  if (json.connectors[i].to == divs[k].id + ".out0")
  	  {
				for (j = 0; j < json.devices.length; j++) 
				{
		    	if (json.devices[j].id + ".in0" == json.connectors[i].from)
					{
						res += json.devices[j].label + " = (";
					}
  	  	}
			}
		}
		for (i = 0; i < json.connectors.length; i++) 
		{
    	if (json.connectors[i].from == divs[k].id + ".in0")
  	  {
				for (j = 0; j < json.devices.length; j++) 
				{
		    	if (json.devices[j].id + ".out0" == json.connectors[i].to)
					{
						res += json.devices[j].label;
					}
  	  	}
   	 	}
		}
		if (divs[k].type == "XOR")
		{
			res += " ^ ";
		}
		if (divs[k].type == "AND")
		{
			res += " & ";
		}
		if (divs[k].type == "OR")
		{
			res += " | ";
		}
		if (divs[k].type == "NAND")
		{
			res += " ~& ";
		}
		if (divs[k].type == "NOR")
		{
			res += " ~| ";
		}
		if (divs[k].type == "XNOR")
		{
			res += " ~^ ";
		}
		for (i = 0; i < json.connectors.length; i++) 
		{
    	if (json.connectors[i].from == divs[k].id + ".in1")
  	  {
				for (j = 0; j < json.devices.length; j++) 
				{
		    	if (json.devices[j].id + ".out0" == json.connectors[i].to)
					{
						res += json.devices[j].label + ");\n";
					}
  	  	}
   	 	}
		}
	}
	res += "endmodule";
	koko.value = res;
}


```

以上
Block Annoying Google Pop-ups with Violentmonkey/Tampermonkey Browser Extensions

## Violentmonkey/Tampermonkey Scripts

### Block `Sign in with Google` Pop-up

```javascript
// ==UserScript==
// @name        Sign in with Google
// @namespace   Violentmonkey Scripts
// @match       *://*/*
// @grant       GM_addStyle
// @version     1.0
// @author      -
// @description Block the `Sign in with Google` pop-up with Violentmonkey
// ==/UserScript==
GM_addStyle(`
#credential_picker_container:has(iframe[src*="accounts.google.com"]) {
  display: none;
}
`);
```

### Block `Sign in to Google` and `Google recommends using Chrome` Pop-ups

```javascript
// ==UserScript==
// @name        Google.com
// @namespace   Violentmonkey Scripts
// @match       *://*google.com/*
// @grant       GM_addStyle
// @version     1.0
// @author      -
// @description Block the `Sign in to Google` and `Google recommends using Chrome` pop-ups with Violentmonkey
// ==/UserScript==
GM_addStyle(`
div[aria-hidden="false"]:has(iframe[src*="google.com"]) {
  display: none;
}
div[role="dialog"][aria-labelledby="promo-header"] aside {
  display: none;
}
`);
```

## [Violentmonkey Documentation](https://violentmonkey.github.io/)

- `GM_addStyle()`  
  <https://violentmonkey.github.io/api/gm/#gm_addstyle>
- Matching ( `@match` / `@exclude-match` )  
  <https://violentmonkey.github.io/api/matching/>
- `@grant`  
  https://violentmonkey.github.io/api/metadata-block/#grant

## Extension Links

### Violentmonkey Extension Links

https://addons.mozilla.org/en-US/firefox/addon/violentmonkey/

https://microsoftedge.microsoft.com/addons/detail/violentmonkey/eeagobfjdenkkddmbclomhiblgggliao

https://chromewebstore.google.com/detail/violentmonkey/jinjaccalgkegednnccohejagnlnfdag

### Tampermonkey Extension Links

https://addons.mozilla.org/en-US/firefox/addon/tampermonkey/

https://microsoftedge.microsoft.com/addons/detail/tampermonkey/iikmkjmpaadaobahmlepeloendndfphd

https://chromewebstore.google.com/detail/tampermonkey/dhdgffkkebhmkfjojejmpbldmpobfkfo
普通のWebカムで顔面点群してみたが

:::note info
最初に
- 子供の教育用に作成
- シングルカメラでそれっぽく点群したい
- 2台カメラで作ってみたが1台壊れて、ゆめ潰える
- 例によって職場ではホンモノは触らせてもらえず・いつものことですが
- 手作業が多かったので、なにか作ってみようという安易な発送
- If you expect English explanations, please check bottom github link
:::

# Open3d と Mediapipeのモデル・機能活用
- 2台あれば点群を作るスピードはそれなりにできそう(片眼 25000個/秒？）
- ただ、ノートPCで作っているので、でチューンしてみる
- なるべく学習済みモデルを活用

```Python:model_check.py
import torch

# 利用可能なモデル名を一覧表示
available_models = torch.hub.list('intel-isl/MiDaS', force_reload=False)
print("利用可能なモデル:", available_models)
```
の結果

```Ubuntu:ターミナル
Using cache found in /home/manyan3/.cache/torch/hub/intel-isl_MiDaS_master
利用可能なモデル: ['DPTDepthModel', 'DPT_BEiT_B_384', 'DPT_BEiT_L_384', 'DPT_BEiT_L_512', 'DPT_Hybrid', 'DPT_Large', 'DPT_LeViT_224', 'DPT_Next_ViT_L_384', 'DPT_SwinV2_B_384', 'DPT_SwinV2_L_384', 'DPT_SwinV2_T_256', 'DPT_Swin_L_384', 'MiDaS', 'MiDaS_small', 'MidasNet', 'MidasNet_small', 'transforms']
```

# なんちゃってな映像撮影を行う

1. その1

![Enhanced Edge Flames with Depth_screenshot_021.09.2024.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2155177/6bb2aacf-5b96-e085-6bf5-5e594601efd4.png)

2． その2
![sample_image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2155177/6eb932d4-47a1-88e3-d6a3-d2d3fab17cd4.png)


# 点群してみる

![3dimage.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2155177/e4fa4010-c3a1-d1ac-f625-a32135c6a5d5.png)

- 左側に顔面の点群の強さが顔の動きに連動して出現
- 顔を近づけると顔の面がMediapipeの効果で見えるようにできる
- Sキーを押して切り替え

# 子供の反応もよく目的は達成！？
- 大きなお友達や私自身は消化不良ですが、子供にはバカウケ
- ご近所の子供たちも喜んで、ヨシとしましょう。
- 今後はちゃんとしたものをほしい。会社は期待できないので自分でかなぁ・・・

# ネタ＊Link

https://github.com/mi-kaneyon/edge_image/tree/main
LINEのWebhookをPostmanで再現したい

# 概要

今回は、LINEの`Messaging API`を使った開発において、メッセージ（Webhook)の機能を、`Postman`を使用しパラメーターを送信することで、ローカル環境でのみテストできるようにしたいと考えています。


# メッセージ（Webhook)の仕組み

Webhookの設定をLINE Developersで指定していると、LINE上でメッセージが送信されている場合にアプリにメッセージが送信されます。（下記の図を参照）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/473097/41cc331c-d9ca-1eff-008b-06b1245e457c.png)

Webhookで使用できるイベントは、メッセージだけではなく「フォローしたとき」や「メッセージを取り消したとき」など色々と用意されています。（詳しくは、公式のAPIドキュメントを参照ください。）

https://developers.line.biz/ja/docs/messaging-api/receiving-messages/#webhook-event-in-one-on-one-talk-or-group-chat




# メッセージ（Webhook)の認証について

LINEのメッセージ(Webhook)を使ったアプリは、**署名を検証を使った**認証を実装することがLINE APIリファレンスで推奨されています。

([公式リファレンス](https://developers.line.biz/ja/reference/messaging-api/#signature-validation)から引用)

> 検証の手順は以下のとおりです。
> 1. リクエストボディのダイジェストを計算します。チャネルシークレットを秘密鍵としてHMAC-SHA256アルゴリズムを使用します。
> 2. ダイジェストをBase64エンコードし、リクエストヘッダーのx-line-signatureに含まれる署名と一致するかどうかを確認します。

下記手順は、署名を検証が実装されているアプリとして説明していきます。

# Postmanの設定

それでは、`Postman`の設定をしていきます。

## 1. コレクションの設定

### 1.1 エンドポイントの設定

エンドポイントは、以下の設定をしてください。


- メソッド：POST
- URL: 開発環境のWebhook URLを指定

**[設定イメージ]**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/473097/eab1608b-8754-5162-7edf-93dfcba93401.png)

### 1.2 ヘッダータブ設定

`Content-Type`を設定してください。
`X-Line-Signature`も設定が必要ですが、Scriptで自動生成するので不要です。

|キー|値|
|-|-|
|Content-Type|application/json|

**[設定イメージ]**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/473097/0e73129d-917d-d0bf-9c13-4e1ff85d8ed4.png)



### 1.3 ボディタブ設定

[公式のAPIリファレンス](https://developers.line.biz/ja/reference/messaging-api/)からWebhookイベントをコピーし、必要に応じてパラメータを書き換えます。

**[設定イメージ]**

以下は、`follow`のイベントを拝借しています


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/473097/019998cb-e71d-988b-82e1-5f8ec19c2c31.png)


### 1.4 Scriptsタブ設定

`Scripts`タブを開き`Pre-request`に下記コードを設定します。

```javascript
const cryptoJs = require('crypto-js');

// チャンネルシークレットとボディ（リクエストのペイロード）を指定
const channelSecret = pm.environment.get("CHANNEL_SECRET_KEY");
const body = pm.request.body.raw; // ボディはリクエストのRAWタブから取得

// HMAC-SHA256で署名を生成
const hash = cryptoJs.HmacSHA256(body, channelSecret);
const signature = cryptoJs.enc.Base64.stringify(hash);

// 署名をヘッダーに追加
pm.request.headers.add({
  key: 'X-Line-Signature',
  value: signature
});
```

**[設定イメージ]**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/473097/25691ed8-04c6-6e4d-a11f-243a7853b5d1.png)

## 2. 環境の設定

### 2.1 チャネルシークレットの設定

LINE Developerからチャネルシークレットを取得して、`CHANNEL_SECRET_KEY`を設定します。


**[設定イメージ]**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/473097/e2117a24-ad10-82fd-1176-6f64e962463c.png)


### 2.2 環境の切り替え

設定した環境へ切り替えを行います。

**[設定イメージ]**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/473097/5f2b2509-dc89-0435-a7a9-b42230485422.png)


## 3. 実行

実行ボタンを押すと、POSTのリクエストが送信されます。
作成したアプリケーションや実行結果を確認してみてください。

# 終わりに

Postmanを使用して、LINEのメッセージ（Webhook）を開発環境で実行できるようになりました。これにより、Webhook URLをネット上に公開することなく、開発環境でテストが可能になります。

Webhookイベントを変更したり、さまざまなリクエストパターンを用意することで、今後の開発やメンテナンスがより効率的になります。

最後までお読みいただき、ありがとうございました。