OmniAICreator/Qiita-1.07M huggingface dataset:
S3のオブジェクトに対してリファラー制限をかける

弊社営業から「該当のファイルを、管理画面からのみダウンロードできるようにして欲しい」との要望があったのでs3のバケットポリシー設定メモとして残します

<br>

詳しい要件を聞いてみると

- 弊社と契約しているクライアントさんがアクセスする管理画面上からのみファイルをダウンロードを許可して欲しい」
- 弊社と契約しているクライアントさん以外は見てほしくないと思ってはいるけど、ダウンロードした後にクライアントさんが他の企業に見せてもまぁしゃーない
- 上の理由から、最悪ネット上に流出しても会社的にそんなに困らない

<br>

という超ゆるゆる要件だったため、リファラー制限だけ入れておきますかという話でまとまった。（リファラーは簡単に偽装出来るのでセキュリティ的にはイマイチ。厳しい要件では絶対に利用しないで下さいね…）

## s3 のバケットポリシーサンプル

適宜変更して利用してください

```json
{
    "Version": "2012-10-17",
    "Id": "referer policy",
    "Statement": [
        {
            "Sid": "Allowed referrers.",
            "Effect": "Allow",
            "Principal": "*",
            "Action": [
                "s3:GetObject",
                "s3:GetObjectVersion"
            ],
            "Resource": "arn:aws:s3:::[バケット名]/*",
            "Condition": {
                "StringLike": {
                    "aws:Referer": [
                        "https://[許可するリファラ1]/*",
                        "https://[許可するリファラ2]/*"
                    ]
                }
            }
        }
    ]
}
```
SVN と Git: プログラマーにとって適切なソリューションはどちらでしょうか

GitとSVNは、バージョン管理システムの2つの主要なタイプです。


## GIT 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3427598/89ce0d11-c8b9-aa8f-15ac-212a2c2d5f75.png)

Gitは分散型のバージョン管理システムであり、リポジトリ（レポジトリ）全体を各開発者のローカルマシンに複製します。
これにより、独立して作業し、オフラインで変更を管理することができます。また、ブランチ（ブランチ）やマージ（マージ）などの強力な機能を提供し、柔軟なワークフローをサポートします。

## SVN
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3427598/0ad72d9c-443d-964f-1c6f-7a450d49f36e.png)

一方、SVNは集中型で、リポジトリは中央サーバーに集中しています。開発者は中央サーバーからコードをチェックアウトして変更を行い、コミットして中央リポジトリに反映させます。

## GitとSVNの主な違いは次のとおりです
| 項目 |	Git|	SVN|
|-|-|-|
|**タイプ**	|分散型ソースコード管理| 集中型コード管理|
| **特徴**  | - 各ユーザーが完全なローカルコピー <br> - 速くて安全<br>- 簡単なリカバリ<br>- 効率的なソース履歴管理  | - 中央リポジトリにコミットして変更を管理|
| **利点**    | - クイックで安全<br>- ローカルでの復元が容易<br> - ソース履歴の管理が容易                | - 直感的 <br>- 簡単に使用  |
| **難点**           | - 学習コストが高い               | - 中央サーバーの障害に弱い <br> - コンフリクトの発生確率が高い|
|**ブランチとマージ**	|容易	|複雑|
|**リポジトリのサイズと速度**	|ローカルでの作業は高速	|初めてアクセスする際は速い|
|**ブランチとタグの扱い**	|同じように扱う	|別々のディレクトリとして扱う|

## Git と SVN リポジトリ管理コマンド
|       | Git            | SVN    |
|---|---|---|
| リポジトリの複製 | git clone | svn checkout |
| コミット| git commit | svn commit |
| ログメッセージを表示 | git show | svn cat |
| 状態確認 | git status | svn status |
| 変更内容を確認| git diff | svn diff |
| ログの確認 | git log | svn log |
| 追加 | git add | svn add |
| ブランチの作成 | git branch | svn copy  |
| ブランチの切り替え| git checkout | svn switch |
| マージ | git merge | svn merge |
| 変更の更新 | git pull / git fetch | svn update |
| リモートリポジトリに反映 | git push | svn commit  |
| 無視するファイルのリスト | .gitignore | .svnignore |

どなたの開発チームは、どちらのバージョン管理システムを使っていますか。
OCI HPC Cluster: 構築 - v2.9.2

:::note info
本ページは [OCI: HPC Cluster](https://qiita.com/itokazu/items/63d2e3cebdcdda5afce0) のサブページになります。
:::

# HPC Cluster v2.9.2 構築

##  Marketplace にアクセスする
メニュー → Marketplace → All Applications を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108605/411e38da-2c88-f680-7fbf-aff2a724983c.png)

## HPC Cluster を検索し、選択する
hpc と検索し、HPC Cluster を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108605/9a3068a8-1a57-c633-f530-a55acaab9a54.png)


## HPC Cluster の選択と構成
v2.9.2 を選択し、対象のデプロイするコンパートメントを選択し、Launch Stack をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108605/0d404d50-3148-72f6-289b-5137f7f72236.png)

以下の Create Stack 画面になるので、何も変更せず、Next をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108605/5ae40085-f96c-a215-8e83-a482a26324eb.png)

次が HPC Cluster のデプロイに関する様々な設定を指定する画面になります。
ここでは標準的な構成を想定して、デフォルトから変更する部分についてガイドを入れています。まずはそのガイドの通りに指定するのをおすすめします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108605/0f690cc7-b155-6456-8b9a-da169d67c132.png)


Next をクリックすると以下の確認画面になるので、 Create をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108605/8c153073-91d0-4faa-3549-494982e1ceef.png)


## Resouce Manager による作成が開始
Create をクリックすると、Resouce Manager の画面に切り替わりデプロイが開始されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108605/c4b6b961-926e-fb2e-5424-d576878dc182.png)

デプロイが無事に完了すると以下の画面になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108605/25527f57-5d07-94a6-5f7f-6ad08d29cb56.png)


完了したら、左側の outputs を選択し、デプロイされた Bastion(＝ログインノード)の Public IP を確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108605/c68fac6f-4145-73ff-28b3-94a87d374011.png)
クライアントから特定のレスポンスヘッダーにアクセスできない原因

# はじめに

この記事はクライアントから特定のレスポンスヘッダーにアクセスできないバグに関しての記事です。

このバグはフロントエンドにNext.jsを、バックエンドにGoを採用した学校の課題で、本番環境で動作させた時に発生しました。
POSTメソッドのレスポンスとして`Location`ヘッダーをセットしたのですが、クライアントから取得することができませんでした。

Swagger UIやネットワークタブからはレスポンスヘッダーの存在を確認できたにも関わらず、なぜか取得できなかったため、原因が中々推測できず30分ほど悩みました。

今後忘れたころにまた遭遇する可能性もありますので、ここで一旦記事にしたいと思います。

# 先に解消方法から

バグの原因はCORSの`Access-Control-Expose-Headers`レスポンスヘッダーの設定ミスでした。

`Location`ヘッダーは[セーフリスト](https://developer.mozilla.org/ja/docs/Glossary/CORS-safelisted_response_header)に含まれていないため、クライアントからアクセスするには`Access-Control-Expose-Headers`ヘッダーに加える必要がありました。

例えば今回採用したGinの場合は、

```go
        // 略
- 		c.Writer.Header().Set("Access-Control-Expose-Headers", "Content-Length")
+ 		c.Writer.Header().Set("Access-Control-Expose-Headers", "Content-Length, Location")
        // 略
```

とすることで、クライアントから`Location`ヘッダーにアクセスすることができるようになりました。

# 問題の発生状況

POSTメソッドの`Location`レスポンスヘッダーに新しいリソースのIDをセットするために、以下のようなコードを書きました。WebフレームワークとしてGinを採用しました。

```go
	c.Header("Location", fmt.Sprintf("/%s", output.ID))
	c.JSON(http.StatusCreated, nil)
```

それからしばらくして、本番環境でフロントエンドとバックエンドの疎通を確認することになりました。

Next.jsからAxiosを使ってリクエストを送信し、リソースのIDを取得してページ遷移しようとしたところ、Locationヘッダーの値を取得することができない。というエラーが発生しました。

ネットワークタブのレスポンスヘッダーを確認してみたところ、確かにLocationヘッダーとその値がセットされていました。また、Swagger UI側からも確認してみましたが、当然、Locationヘッダーがセットされていました。

しかしクライアント側から取得することができません。`console.log`でレスポンスヘッダーをコンソールに出力してみると、`Content-Length`以外の情報がありませんでした。

# Access-Control-Expose-Headersヘッダー

以前の章にもある通り、原因は`Access-Control-Expose-Headers`ヘッダーでした。

> Access-Control-Expose-Headers レスポンスヘッダーは、レスポンスの一部としてどのヘッダーを公開するかを、その名前を列挙して示します。
>
> 出典：[Access-Control-Expose-Headers - HTTP | MDN](https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Access-Control-Expose-Headers)

という内容のようです。

規定では７種類のレスポンスヘッダーが公開されるそうなのですが、この中に`Location`ヘッダーは含まれていません。

クライアントが他のヘッダーにアクセスできるようにするには、ここに公開するヘッダーを列挙する必要があります。

`Access-Control-Expose-Headers`ヘッダーの構文は以下の通りです。

```
Access-Control-Expose-Headers: <header-name>, <header-name>,
Access-Control-Expose-Headers: *
```

# まとめ

この記事ではクライアントから特定のレスポンスヘッダーにアクセスできないバグに関する記事をまとめました。
忙しい方のための Instana Advent Calendar Quiz 2023

2023年 Instana Advent Calendar 完走お疲れさまでした。
https://qiita.com/advent-calendar/2023/instana

記事を書いて頂いた方も、読んで頂いた方も多くの Knowledge を身につけられたかと思います

# 記事が多すぎて読み切れない方へ

多くの記事が公開されたので、全部読み切れない方もいらっしゃるかと思います。
そんな方のために楽しみながら情報を得られるクイズを kahoot 上に作ってみました。

遊ぶ前に、右下のギアアイコンをクリックして頂いて、自動再生がオンになっていることを確認して下さい
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/128691/1b7f4145-87ad-b269-4211-d450b79b54a1.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/128691/183fe8fb-cfc0-ce71-5a1e-9288603ed9d9.png)


そうはいっても、記事も多いので問題数が多くなってしまい、そこそこの時間がかかります。お時間のあるときにお楽しみください

※一人でクイズに参加するためには、kahoot のアカウントが必要です
https://play.kahoot.it/v2/?quizId=a2189ffb-0b01-4fe3-b34d-a17039e97cea
初めてLINEAPIを使用してLINEとGeminiを繋げてみた

***
この記事ではLINEAPI初心者の僕が実際にLINEのメッセージをGemini proに通した出力を返信できるLINEbotを制作した話をつらつら書いてきます〜最後にコードも置いときます〜
##### ここはこうしたほうが良かった？みたいなのは気軽にコメントしてね〜

# LINE と Gemini 連携の始め方
- [1. LINEのbotアカウントを制作する](#1-lineのbotアカウントを制作する)
- [2. callback用のドメインを用意する](#2-callback用のドメインを用意する)
- [3. GeminiとLineを繋ぐPythonスクリプトを書こう](#3-geminiとlineを繋ぐpythonスクリプトを書こう)
- [4. 実際に動かしてみよう！](#4-実際に動かしてみよう)


## 1. LINEのbotアカウントを制作する

[LINE Developers](https://developers.line.biz/ja/docs/line-developers-console/) のサイトからコンソールにログインしてぺぺぺっとLINE の bot アカウントを制作します。

[このページ](https://developers.line.biz/en/docs/messaging-api/getting-started/#step-one-log-in-to-line-developers-console)を参考にuserがメッセージを送信する公式アカウントを作成しましょう！

## 2. callback用のドメインを用意する
この部分で躓いた。。。
アカウントを制作するとWebhook URLという一般公開されたドメインを作らないといけない、用意しないといけません。
![スクリーンショット 2023-12-26 10.41.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3661787/8dabe395-871b-9691-7700-8c1c93ffc111.png)
この黒塗りの部分にドメインを記載しないといけない。僕はサービスとしてではなく、なんとなく開発をしたいのでlocalhostでいいんだけど！！！←ダメでした笑
ということで今回はlocalhost5000番をドメイン化して一般公開できるアプリ[ngrok](https://ngrok.com/)を使いました。このアプリはlocalhostと公開ドメインをトンネルで繋ぐアプリだと感じています。このアプリをダウンロードして`Setup&Installation`の項目を見ながらセットアップしましょう！
私はMacですのでbrewからngrokを使用できるようにしました〜↓↓↓
>Install ngrok via Homebrew with the following command:
>```
>$ brew install ngrok/ngrok/ngrok
>```
>Run the following command to add your authtoken to the default ngrok.yml >configuration file.
>```
>$ ngrok config add-authtoken YOUR_TOKEN
>```
>deploy your app(5000portを指定)
>```
>ngrok http 5000
>```
これを実行することでlocalhost:5000をドメイン化して取得できるという優れもの！！free planでも最初は問題なし
実際に`ngrok http 5000`を実行すると
![スクリーンショット 2023-12-26 11.07.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3661787/c3f901de-b8e1-5dd1-2e02-a11332412804.png)
`ここ`に書かれているurlがlocalhost:5000番に対応するドメインになりますが私はここでlocalhost:5001番を使用しているので画面には5001と表示されております。
本当は`127.0.0.1:5000`が`localhost:5000`に対応しているはずなのに`127.0.0.1:5000`を立ち上げても`localhost:5000`にアクセス拒否されるというよくわからん現象に陥り、１日ぐらい無駄にしていました。いまだに原因がよくわかってないのでこれじゃね？見たいのあったら教えていただけると嬉しいです。
```
lsof -i :5000  
```
これ実行したら何個かlistenになってたから5000番を何かで使ってるのかな〜と思ったけど詳細はよくわからず。。

話は戻って、うまくいけば`ここ`のurlに`/callback`を追加したものをWebhook URLに追加してverifyしましょう！
## 3. GeminiとLineを繋ぐPythonスクリプトを書こう
Gemini と Line を繋ぐ Python スクリプトを作成します。
- まずはLINEで送信したメッセージをそのまま返信できるという機能を実装してみましょう
ここができていないとGeminiに情報が正しく送信されているかを確認できないんでね
[LINEスタートキット](https://developers.line.biz/ja/docs/messaging-api/line-bot-sdk/#official-sdks)として公式から公開されているんでこれを使いましょう！自分はpythonで実装したので[これのReadme](https://github.com/line/line-bot-sdk-python)参考にオウム返しbotを実装！！

- GeminiAPIキーを発行してGeminiの出力を引っ張ってこよう！
ここまでできたらもう少しだ意外とgeminiの出力を持ってくるのは簡単で
```
import google.generativeai as genai
genai.configure(api_key="GEMINI_API_KEY")
def get_gemini_response(prompt):
    # GeminiのAPIのバージョンを指定
    model = genai.GenerativeModel('gemini-pro')
    response = model.generate_content(f"{prompt}")
    return response
```
これで取って来れちゃう

## 4. 実際に動かしてみよう!
作成した Python スクリプトを実行して、実際に動作を確認します。
[ソースコード](https://github.com/ryo09020/linetogemini)
このreadmeから自分のAPIキーを入れて実行してみましょう！
【ChatGPT無】で翻訳。少し具体的な設定を追加。でも失敗。

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

　今回は、翻訳です。ただし、ちょっとした設定を加えます。

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

　ふつうに
　　「日本語を英語に翻訳して」
　　　でも、いいのですが、
　　　　ロール（役割）とかを
　　　　　指定した方が
　　　　　　良さげに思えました。

　文章を書いているのが
　　男性なのか女性なのか
　　　年齢はいくつか。

　ペルソナまではいかずとも
　　ちょっとした設定を
　　　すれば、結果が
　　　　変わりそうです。

　Promptは
　　やり取りに含めました。

　どうぞ。

　まずは、ふつうに翻訳。
***
***User***
翻訳をお願いします。

***ChatGPT***
そのフレーズは「Good morning」と英語で表現されます。

***User***
「ゆうべは、飲み過ぎたわ」

***ChatGPT***
それは英語で「I drank too much last night」になります。

***User***
「もう、お酒は飲まない」

***ChatGPT***
それは英語で "I won't drink alcohol anymore" になります。
***
　次に、
　　NewChatして、
　　　設定を入れます。
***
***User***
18歳日本人女性が、英語で相手に伝えたいと考えています。

彼女の発言を同じ年齢の英語圏の女性の発言になるように、翻訳をお願いしたいのですが。

できますか？

***ChatGPT***
もちろんです！彼女が伝えたいことを教えてもらえますか？それを同じ年齢の英語圏の女性がどのように言うか、お手伝いしますよ。

***User***
ではお願いします。
「おはようございます」

***ChatGPT***
「Good morning!」

***User***
「ゆうべは、飲み過ぎたわ」

***ChatGPT***
"I drank too much last night."

***User***
「もう、お酒は飲まない」

***ChatGPT***
"I won't drink alcohol anymore."
***

　例文がシンプル過ぎたか、
　　違いが出ませんでした。

　残念です。

　今回は、ここまで。
FreeCADでホゾ形状を作成

## FreeCADでホゾ形状を作成
ホゾ（面からの凸）形状を変更しやすく作る
※スケッチを流用して他の押し出し用のスケッチに関連付ける
自分用の忘備録です

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287430/2d61d706-831a-6b89-6f5f-1b8674af278c.png)

ポイント
・ホゾの中心を面の中心にする
・ホゾの寸法を変更しても、ホゾの中心が面の中心と一致したまま

## スケッチ１
「Part Design」にする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287430/434c6702-66e3-d0ea-cd88-5a405e9dff82.png)新規スケッチを作成する
四角形と点を配置し、四角形の頂点に点を![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287430/0dda12ea-14fc-5d73-2926-c30e58ffd325.png)で対称拘束させる
もしくは、![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287430/e9262f8b-a5e2-aa4d-9f5c-8a117c9a35a6.png)中心配置長方形で作成

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287430/cb14da1e-df17-609f-85b1-c1dd7c4ed1e0.png)

## 押し出し１
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287430/1b41ed9f-bd09-1418-2e9d-bc6601cf057e.png)で押し出し

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287430/f9e6c753-7e92-e372-1403-d3ef02142f24.png)

## スケッチ２
凸を作りたい面を選択し、![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287430/ee4e4395-4568-0698-3168-5e3145a87d4a.png)新規スケッチを作成

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287430/71e76368-bdba-1a49-f30e-4b05f7fde8f9.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287430/09bca63d-9efb-2fb3-f8d2-ff22c4904abc.png)カーボンコピーを作成を押し、コンボビューのモデル内にあるスケッチ１のファイルを選択

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287430/9a1726e5-81e4-33c5-063f-03dfa8d91347.png)

スケッチ１の内容が反映されたが、欲しいのは中心点の位置のみのため、他の線を補助線に変更する

四角形の辺を選択し、![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287430/8fa219f9-170b-53dd-01d7-2f1b6befd534.png)構築ジオメトリーへの切り替えを押す
緑線が青線に変わる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287430/296dbe87-591b-8ab9-6f2c-5b2960417032.png)

スケッチ１の中心点と基準に、![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287430/242c39fd-aef0-1df8-ae05-bd0f28a15cc3.png)中心配置長方形で四角形を記入

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287430/f65df6e5-0541-ff06-f24b-a3bb3438e262.png)

## 押し出し２
スケッチ２を、![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287430/1b41ed9f-bd09-1418-2e9d-bc6601cf057e.png)で押し出し

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287430/2d61d706-831a-6b89-6f5f-1b8674af278c.png)

## 完成
ホゾの寸法を変更しても、ホゾの中心は面の中心と一致
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287430/8298c9b0-3b55-c13b-b872-c24c5d2a4704.png)
AI-102試験対策のまとめ「Azure AI Faceサービスの各機能とAPI」

## はじめに
Azure AI Engineer Associate(AI-102)取得に向けた勉強でまとめた内容を本記事では投稿しています。
試験範囲の内容を私が勉強していく中で、
・忘れてしまっていた内容
・他の知識と絡めて理解した方が良い内容
・Microsoft Learnの読解に苦戦した内容
などをできるだけ分かりやすく簡潔にまとめることを意識しています。
Azureの勉強を一から始め、AI-102取得を目指している方の参考になれば幸いです。
※本記事の内容が必ず試験に出るわけではないこと、ご注意ください
※勉強しながら投稿しているため、追加で学んだことがあれば随時投稿内容を更新します。

## 試験対策のまとめ
### Azure AI Faceサービスの各機能とAPI
* 顔検出と分析：Detect API
* 顔認識の識別(1対多照合)：Identify API
* 顔認識の検出(1対1照合)：Verify API
* 似た顔の検索：Find Similar API

#### **顔検出と分析**
* 画像に含まれている人の顔を検出し、その位置の四角形の座標を返す
* 保存されている顔データを表す一意のID(Face ID)も返される
* 使用する顔検出モデルにより顔のランドマークも座標として返すことが可能
    - 顔のランドマーク：瞳孔、鼻の先端など顔の中の見つけやすいポイントのセット(既定で27個)
* オプションとして、下記の属性も抽出可能
    - アクセサリ：顔のアクセサリの有無
    - ぼかし：顔のぼかしの程度
    - 露出：顔の露出の程度
    - 眼鏡：顔の眼鏡の有無
    - 頭部姿勢：3次元空間での顔の向き
    - マスク：顔のマスクの有無
    - ノイズ：顔の画像で検出された視覚ノイズ
    - オクルージョン：顔のパーツをブロックするオブジェクトの有無
    - QualityForRecognition：画像が顔認識するのに充分であるか否かを表す品質

#### **顔認識**
* 識別(Identify)では、画像内の1つの顔を、事前に作成しトレーニングした顔のグループに対して照合  
    ⇒顔がグループ内のpersonとして識別された場合、そのpersonオブジェクトが返される
* 検証(Verify)では、画像内の顔を他の写真などの1つの顔と照合  
    ⇒2つの顔が同じ人物であるかどうかを確認  
    例：自撮りと身分証明書の写真を使った本人確認
* 3種類のコンテナデータ構造を使用して、Personオブジェクトの形式で顔認識データを保持
#### **顔識別で使用されるデータ構造**
* PersonGroup
    - 最小のコンテナデータ構造
    - 作成時に認識モデルを指定する必要あり(顔が追加されるときにモデルが使用される)
    - 無料サブスクリプションでは最大1,000人を保持可能
    - S0有料サブスクリプションでは最大10,000人を保持可能
    - PersonGroupPerson：識別されるユーザーを表し、最大248個の顔を保持可能
* LargePersonGroup
    - 大規模なデータをサポートするように最適化された最新のデータ構造
    - S0有料サブスクリプションで最大100万人を保持可能
    - PersonGroupの機能の大部分を共有している
* PersonDirectory
    - より大きなスケールとより高い精度をサポートする最新のデータ構造
    - 各Azure Faceリソースには、既定の1つのPerson Directoryデータ構造がある
    - 最大7,500万個を保持可能
    - PersonDirectoryPerson
        - 識別されるユーザーを表す
        - 異なる認識モデルの顔を同じ人物に追加可能
        - Identify操作では同じ認識モデルで取得した顔のみ照合可能
    - DynamicPersonGroup
        - PersonGroupPersonを動的に参照できる軽量のデータ構造
        - トレーニング操作は不要
        - データ更新後、すぐにIdentify操作で使用する準備が整う
    - in-place person ID list
        - Identify操作で使用可能
        - 識別するグループを絞り込んで指定できる
    - 上記データ構造を同時に使用した場合の例(フライト搭乗システム)
        - PersonDirectory：航空会社のすべての顧客を表す
        - DynamicPersonGroup：特定のフライトの乗客のみを表す
        - in-place person ID list：直前に変更を行った乗客を表す

#### **似た顔の検索**
* Find Similar操作では、ターゲットの顔と候補となる一連の顔との間で顔照合を実施  
    ⇒ターゲットの顔によく似ている一連の顔が検索される
* Find similarでは2つの動作モードをサポート
    - matchPerson：Verify APIを使用して同一人物フィルター処理後、似た顔が返される
    - matchFace：同一人物フィルターを無視して、似ている顔の候補リストが返される

#### **Find Similarで使用されるデータ構造**
* Find Similar APIは、Personの登録設定が困難なアプリケーションで使用するように設計されている
    - FaceList
        - 永続化された顔のフラットなリストを表す
        - 最大1,000個の顔を保持可能
    - LargeFaceList
        - 最大1,000,000個の顔を保持できる新しいバージョン

<br>

* 参考
    - https://learn.microsoft.com/ja-jp/azure/ai-services/computer-vision/overview-identity
    - https://learn.microsoft.com/ja-jp/azure/ai-services/computer-vision/concept-face-detection
    - https://learn.microsoft.com/ja-jp/azure/ai-services/computer-vision/concept-face-recognition-data-structures

## 学習内容をまとめたページの一覧

https://qiita.com/fsd-jume/items/65aba5d5514e023fd66d
Laravel Intervention Imageが使えない

Laravelに
```zsh
composer require intervention/image
```
で
Intervention Image
をインストール後、
```php:config/app.php
    'providers' => ServiceProvider::defaultProviders()->merge([
        ...
        Intervention\Image\ImageServiceProvider::class,
    ])->toArray(),

    'aliases' => Facade::defaultAliases()->merge([
        ...
        'Image' => Intervention\Image\Facades\Image::class,
    ])->toArray(),
```
を追加しましたが、
```
Class "Intervention\Image\ImageServiceProvider" not found
```
というエラーが発生し使用できませんでした。
どこを修正すれば使用できるようになりますでしょうか。

Laravelのバージョンは
Laravel Framework 10.38.2 です。

よろしくお願いします。
Pythonでいずれやりたいこと

やりたいことを思い付きっぱなしで放置しがちなので、メモとして残しておきます。

## まじめな方
・コラージュ川柳作り
・筋トレと有酸素運動のスケジュールの最適化
・People in the boxの歌詞分析
・音声機械学習でベースtab譜を生成する
・サザエさんのじゃんけんのデータセットで遊ぶ
http://park11.wakwak.com/~hkn/
・タイタニック号のデータセットで遊ぶ

## 長期的な課題
・自分の孤独死管理システム
・性犯罪サバイバーサポートIoTシステム

## お笑い関連
・ジャルジャル「国名わけっこ」実装
・画像機械学習でジャルジャル後藤淳平＆さや香・新山を判定する

https://x.com/modelpress/status/1739518590737682746?s=20
https://x.com/miyashin_prg/status/1738401914793107613?s=20

## HUNTER×HUNTER関連
・HUNTER×HUNTER グリードアイランド編の実装
・HUNTER×HUNTER ヒソカ対クロロ戦の実装(？)
・HUNTER×HUNTER 暗黒大陸編でなんか



## 言い訳
「どうでもいい正解を愛するよりも面白そうなフェイクを愛せよ(令和ロマン)」のノリの気質の非エンジニアであるためこうなってしまう
https://m.youtube.com/watch?v=mPMcWNPlTro&embeds_referring_euri=https%3A%2F%2Ftwitter.com%2F&source_ve_path=Mjg2NjY&feature=emb_logo
Best VLSI Blogs

VLSI設計(回路設計，EDA技術，PDKせっけい)で参考になるBlogを列挙してみる．単に[2つ](https://vlsibeginners.quora.com/Top-10-VLSI-Blogs-News-Websites-To-Follow-in-2020-1)の[記事](https://electronics.feedspot.com/vlsi_blogs/)から私がよく見るサイトをピックアップしただけだったり．なぜかインド人が多めです．オープンな文化なのだろうか．
## 英語のBlogコンテンツ
Semiconductor Engineering
https://semiengineering.com

VLSI Concepts
https://www.vlsi-expert.com

VLSI UNIVERSE
https://vlsiuniverse.blogspot.com

VLSI-Phyiscal Design For Freshers
https://www.physicaldesign4u.com
企業の面接で聞かれた質問がコンテンツになっていたりして面白い．

Team VLSI
https://teamvlsi.com/?utm_source=feedspot

Blog じゃないけれど．
Synopsys | Youtube
https://www.youtube.com/user/synopsys/videos

MentorGraphysics(Siemens EDA) のYoutubeチャネルもいいよ．
https://www.youtube.com/@mentorgraphics/videos

## 日本語のコンテンツ
日本だと金沢大学の北川先生，秋田先生のHPが参考になるかしら．
https://www.merl.jp/index.php?FrontPage
公開マニュアルなども読み込むとかなり力になりそう．
http://jaco.ec.t.kanazawa-u.ac.jp/edu/index.php?%E8%A8%AD%E8%A8%88%2F%E8%A9%A6%E4%BD%9CTips
授業のコンテンツも公開してくださっているのがありがたい．
http://jaco.ec.t.kanazawa-u.ac.jp/kitagawa/edu/

秋田先生の集積回路工学第二
https://ifdl.jp/akita/class_old/old/07/lsi2/index.html

3-1 FPGAによるCPU設計：金沢大学 秋田先生
http://exp1gw.ec.t.kanazawa-u.ac.jp/PCIF-2/

半導体工学：立命館大学 藤野先生
https://www.ritsumei.ac.jp/se/re/fujinolab/FujinolabHP_old/semicon/semicon_main.html

群大小林春夫先生も資料をPDFで公開してくださっているので大変勉強になる．
https://kobaweb.ei.st.gunma-u.ac.jp

最後Blogでなくて講義資料になっているけれどまあいいか．日本語のコンテンツが少ないのが日本人(特に初学者)には辛いよね．
【Java】プロパティの値が画面に表示されない（JSF）

# はじめに
JSFで初歩的な動きを確認しようとしたところ、`Managed Bean`のプロパティをバインドして表示してくれない事象が発生。解決方法をメモ。

:arrow_down: 要は`#{}`を使って画面に「Hello!」と表示したいのに、表示されない。

```index.xhtml
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://xmlns.jcp.org/jsf/html"
      xmlns:f="http://xmlns.jcp.org/jsf/core">
    <head>
        <title>FirstPage</title>
    </head>
    <f:view>
        #{myBean.message}
    </f:view>
</html>
```

```MyBean.java
package mypkg;

import jakarta.inject.Named;
import jakarta.enterprise.context.RequestScoped;

@Named
@RequestScoped
public class MyBean {

    private String message = "Hello!";

    public MyBean(String message){
        this.message = message;
    }

    /* ゲッタ */
    public String getMessage(){
        return this.message;
    }

    /* セッタ */
    public void setMessage(String message) {
        this.message = message;
    }

    /* リスナ */
    public String getIdForNextPage(){
        return "success";
    }

}
```

# 解決策
引数なしのコンストラクタを作成する。

```MyBean.java
package mypkg;

import jakarta.inject.Named;
import jakarta.enterprise.context.RequestScoped;

@Named
@RequestScoped
public class MyBean {

    private String message;

    /* 引数なしのコンストラクタ */
    public MyBean(){
        this.message = "Hello!";
    }

    /* ゲッタ */
    public String getMessage(){
        return this.message;
    }

    /* セッタ */
    public void setMessage(String message) {
        this.message = message;
    }

    /* リスナ */
    public String getIdForNextPage(){
        return "success";
    }

}
```

めでたしめでたし。

## ちなみに
引数なしのコンストラクタ作成前のコードで、`Managed Bean`にリスナを設定してもアクションがうまく機能せずに`Target Unreachable, identifier 'hoge' resolved to null`が出てしまってました。
こちらも引数なしコンストラクタの作成で解決しました。
Amazon QuickSight(アカウント/ユーザー管理、運用設計)

Amazon QuickSightのアカウント/ユーザー管理、運用設計について役に立つ情報まとめになります。

・Amazon QuickSight
アカウント/ユーザー管理におけるポイント
https://pages.awscloud.com/rs/112-TZM-766/images/%5B%E7%AC%AC%E4%B8%80%E9%83%A8%5DAmazonQuickSight%E3%82%A2%E3%82%AB%E3%82%A6%E3%83%B3%E3%83%88%E3%83%A6%E3%83%BC%E3%82%B5%E3%82%99%E3%83%BC%E7%AE%A1%E7%90%86%E3%81%AB%E3%81%8A%E3%81%91%E3%82%8B%E3%83%9B%E3%82%9A%E3%82%A4%E3%83%B3%E3%83%88_1014.pdf

・【開催報告＆資料公開】Amazon QuickSight のノウハウ総まとめ！ 〜BI設計から運用まで〜
https://aws.amazon.com/jp/blogs/news/quicksight-matome-20201014/

・Amazon QuickSightの運用設計
https://pages.awscloud.com/rs/112-TZM-766/images/%5B%E7%AC%AC%E4%B8%89%E9%83%A8%5DAmazonQuickSight%E3%81%AE%E9%81%8B%E7%94%A8%E8%A8%AD%E8%A8%88_1014.pdf

・Amazon Quicksightを利用する上でのTips集
https://zenn.dev/stafes_blog/articles/d0bd3970a43541

・Amazon QuickSightのパフォーマンスを改善したい時のTips
https://dev.classmethod.jp/articles/amazon-quicksight-improve-performance/

・データエクスポート(CSV/Excel)のTipsとベストプラクティス | Data Export - Tips and Best Practice | Japanese
https://community.amazonquicksight.com/t/csv-excel-tips-data-export-tips-and-best-practice-japanese/19927

料金体系について
https://aws.amazon.com/jp/quicksight/pricing/
Nightbotで「簡易的でない」おみくじを作る

## 配信者向けツール「Nightbot」

[Nightbot](https://nightbot.tv/)とは、Twitch、YouTubeのライブ配信で利用できる
「チャット機能」を管理するためのWebサービスです。

ライブ配信中、一定の間隔で宣伝や注意書きコメントを流すのがメインになると思いますが、
Javascriptが利用できることを活用し、コマンド経由で遊ぶこともできます。

## Nightbotで簡易的なおみくじを作る
( [Nightbot](https://nightbot.tv/) 導入の方法は省略します)

Nightbot には、独自の変数があり、
[$(eval)](https://docs.nightbot.tv/variables/eval) 変数でJavaScriptを使用できます。

コマンドを追加するには、
Nightbot の Commandos > Custom から追加できます。
青いボタン [+Add command]から、Messageに以下のコードを入力。

```javascript
$(user)の運勢は$(eval X=['大吉','吉','中吉','小吉,'末吉','凶'];X[Math.random()*X.length|0];)だよ～!
```

Command の欄には「おみくじ」と入れておきましょう。
これで、ちゃんと機能するはずです。

Nightbotを導入したライブ配信で
チャット欄に「おみくじ」を入力すると

```
せすじピンとしてますの運勢は末吉だよ～!
```

みたいなコメントが返ってくるはずです。
末吉かぁ、そうかぁ。。

## Nightbotで「簡易的でない」おみくじを作る

今回の記事の「簡易的でない」おみくじとは、
**「確率の異なる」おみくじ**にしたいと思います。

早速コードを書いていくのですが、
Command の欄は小さく、500文字以上のコードは入力できません。
それを解決するため、[Pastebin](https://pastebin.com/) を利用します。

### １．Pastebinのコード

せっかくなので、今回はおみくじではなく
**Nightbot とじゃんけん**させましょう。
（ユーザーが任意の手を出す方法もありますが、今回はランダムです）

```javascript
var X=[
[19,'グー!【YOU LOSE】俺の勝ち！負けは次につながるチャンスです！ネバーギブアップ！'],
[19,'チョキ!【YOU LOSE】俺の勝ち！たかがじゃんけん、そう思ってないですか？それやったら明日も、俺が勝ちますよ。'],
[14,'パー!【YOU LOSE】俺の勝ち！なんで負けたか、明日まで考えといてください。そしたら何かが見えてくるはずです。'],
[5,'パー!【YOU LOSE】俺の勝ち！1年間何やってたんですか？この結果はじゃんけんに対する意識の差です。'],
[1,'グー!【YOU WIN】やるやん。明日は俺にリベンジさせて。'],
[1,'チョキ!【YOU WIN】やるやん。明日は俺にリベンジさせて。'],
[1,'パー!【YOU WIN】やるやん。明日は俺にリベンジさせて。']
];
 
/* 分母 */
b=0;for(i=0;i<X.length;i++) b=b+X[i][0];
/* 乱数 */
r=Math.random()*b|0;
/* 5%でじゃんけん勝利 */
c=0;for(i=0;i<X.length;i++){c=c+X[i][0];if(r<c){A=X[i][1];break;}}
``` 
2019年にペプシのキャンペーンで行われた、
[本田圭佑とじゃんけん](https://dic.pixiv.net/a/%E6%9C%AC%E7%94%B0%E3%81%A8%E3%81%98%E3%82%83%E3%82%93%E3%81%91%E3%82%93) をするやつを使いました。

本キャンペーンの勝率は0.7%だったそうですが、
今回は妥協して勝率を5%に設定。
1列目の数字が大きいほど、その結果が出やすくなります。

最後の変数を返すため、returnは必要ないようです。
(変数Aに結果を入れています)

### ２．Nightbot の Command

Nightbot の Command は以下の通り(XXXXXXX は作成したPastebinのURL)
```javascript
$(user)の$(eval $(urlfetch json https://pastebin.com/raw/XXXXXXX))
``` 

[$(urlfetch)](https://docs.nightbot.tv/variables/urlfetch) 変数は、URLを呼び出せる変数です。
Command の欄には「じゃんけん」と入れておきます。

さて、結果は目に見えていますが、
Nightbotを導入したライブ配信で
チャット欄に「おみくじ」を入力しましょう。

```
せすじピンとしてますのパー!【YOU LOSE】俺の勝ち！なんで負けたか、明日まで考えといてください。そしたら何かが見えてくるはずです。
```

対戦ありがとうございました。
Unity デバック時のパラメータの表示管理方法

デバック時に見たいパラメータを素早く切り替え、Build時にはソースに影響を与えない方法。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2294598/45111793-9dab-c04e-e484-b39eb6eab9cf.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2294598/a2e5a056-6059-bac4-5ac6-6a40f23fd73a.png)
こんな感じで、あるリストを切り替えることで必要なデバックの情報を表示できるようにする。

## 手順

```
namespace Assets.自分の名前空間
{
    //全体で使用できる型の定義
    public enum EN_DEBAG_MODE
    {
        None,
        InputControler,
        MoveControler,
    }
}
```

全体で使用できる位置の名前空間上に、enumのデバック用リストを作成。

これを下記記事を参考にパラメータに設定する

https://qiita.com/sebunwork009/items/04510b2a751cdced7ddf

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2294598/de967cc1-9d67-fc3c-8c4a-e26d8493ea13.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2294598/b20d249e-b597-baf9-bb89-b1e015b34046.png)

Unity上ではこんな感じで選択できるなる。

この値を利用してデバック情報を表示したい箇所で下記コードを記載する。

```
        void OnGUI()
        {
#if DEBUG
            if(gamePram.EnDebagModeDisp == EN_DEBAG_MODE.InputControler)
            {
                GUILayout.Label($"buttonTest");
                GUILayout.Label($"isPressed {Gamepad.current.buttonNorth.isPressed}");
            }
#endif
        }
```
OnGUI上にデバック用に設定したリストをInputControlerにした場合のみ画面上に必要な情報が表示されるようになる。


以上。
楽しいデバッグを！！！
エクセルのメモ

```
= "/data/mail/vhosts/" & MID(B3, SEARCH("@", B3) + 1, LEN(B3)) & "/" & LEFT(B3, SEARCH("@", B3) - 1)
```

```
=MID(E8, SEARCH(":::::Maildir:", E8) + LEN(":::::Maildir:"), LEN(E8) - SEARCH(":::::Maildir:", E8) - LEN(":::::Maildir:") + 1)
```
paiza.ioでelixir その275

# 概要
paiza.ioでelixirやってみた。
練習問題やってみた。

# 練習問題
マップなリストに、CRUDを施せ。

# 方針
- リストを使い廻す。
- idを使う。
- 日付を使う。


# サンプルコード

```
now = NaiveDateTime.utc_now()
	|> NaiveDateTime.truncate(:second)
	
defmodule Ecto2 do
	def insert(db, v) do
		db = db ++ [v]
	end
	def update(db, v) do
		i = Enum.filter_map(Enum.with_index(db), fn {x, _} -> 
			x.id == v.id 
		end, fn {_, i} -> 
			i 
		end)
		|> Enum.at(0)
		db = List.replace_at(db, i, v)
	end
	def delete(db, v) do
		db = List.delete(db, v)
	end
	def print(db) do
		Enum.map(db, fn x -> 
			[ x.id,  x.name]
		end)
		|>IO.inspect
	end
end

db = [
  %{
	id: 1,
	name: "ryu",
	age: 10,
	gaku: "s",
	inserted_at: ~N[2023-10-31 05:35:23],
	updated_at: ~N[2023-11-30 05:35:37]
  },
  %{
	id: 2,
	name: "ryo",
	age: 20,
	gaku: "s",
	inserted_at: ~N[2023-10-31 05:35:23],
	updated_at: ~N[2023-11-30 05:35:37]
  },
  %{
	id: 3,
	name: "alice",
	age: 20,
	gaku: "s",
	inserted_at: ~N[2023-10-31 05:35:23],
	updated_at: ~N[2023-11-30 05:35:37]
  },
  %{
	id: 4,
	name: "kent",
	age: 30,
	gaku: "s",
	inserted_at: ~N[2023-10-31 05:35:23],
	updated_at: ~N[2023-11-30 05:35:37]
  }
]

Ecto2.print(db)
db = Ecto2.insert(db,   %{
	id: 5,
	name: "kent",
	age: 30,
	gaku: "s",
	inserted_at: now,
	updated_at: now
  }
)
Ecto2.print(db)

db = Ecto2.delete(db,   %{
	id: 5,
	name: "kent",
	age: 30,
	gaku: "s",
	inserted_at: now,
	updated_at: now
  }
)
Ecto2.print(db)

db = Ecto2.update(db,   %{
	id: 1,
	name: "yoko",
	age: 30,
	gaku: "s",
	inserted_at: now,
	updated_at: now
  }
)
Ecto2.print(db)





```

# 実行結果
[[1, "ryu"], [2, "ryo"], [3, "alice"], [4, "kent"]]
[[1, "ryu"], [2, "ryo"], [3, "alice"], [4, "kent"], [5, "kent"]]
[[1, "ryu"], [2, "ryo"], [3, "alice"], [4, "kent"]]
[[1, "yoko"], [2, "ryo"], [3, "alice"], [4, "kent"]]

```

# 成果物

https://paiza.io/projects/w_nVLc7mt0qTXiQBHXInIg


以上。
Githubのレポジトリに出現したDeploymentsの履歴を消す

## 背景
プロジェクトのデプロイ先としてGithub Pagesを選んだところ、mainブランチにpushするたび以下のように履歴が残るようになってしまいました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3092983/4550c379-9123-42d9-6ff5-fae6b0ff1f43.png)

詳細を表示するとこんな感じ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3092983/a43a2a86-b07d-4892-90e1-922af56ea29b.png)


デプロイに失敗したものも表示され続けるのは嫌だなぁと思い、調べ始めて丸2日…。
手こずりまくりながらようやく削除に成功しました。

かなり時間を無駄にしたので（単なる知識不足）、同じ状況にいる方の手助けになればと思っています。



## 使用環境
- Windows 11
- コマンドプロンプト（もしくは Windows PowerShell）



## Github CLI
まずghコマンドを使えるようにしましょう。
`Windowsキー + R`を押して、出てきた画面に`cmd`と入力します。

新しく開いた画面が「コマンドプロンプト」と呼ばれるものです。
Windowsの場合は以下のコマンドでインストールできます。
```
winget install gh
```
コピーペーストしてEnterを押してください。
エラーが何も出なければインストール成功です。



## Githubにログイン
次にghコマンドを使ってGithubにログインします。
```
gh auth login
```
これを入力すると色々と質問が出てきます。
基本的にはEnterを押し続ければ大丈夫です。

途中でGithubにアクセスを求められ、コマンドプロンプトに表示されているワンタイムコードが必要になるので、ブラウザ上で入力してください。



## Deployments：一覧取得
ここでようやく削除する準備が整いました！

まずはDeploymentsの要素を一覧表示しましょう。
```
gh api repos/OWNER/REPO_NAME/deployments
```
大文字の`OWNER`と`REPO_NAME`部分は消して、自身で書き換える必要があります。
`OWNER`はGithubのアカウント名、`REPO_NAME`は自分でつけたリポジトリの名前です。

ここでずらっと色々json形式のデータが出力されたと思います。
とりあえず一番上に戻ってみましょう。
```
[
    {
        "url": ・・・,
        "id": ・・・,
        "node_id": ・・・,
        ・
        ・
        ・
```
のようにデータが並んでいると思います。
このid部分（10桁？）をコピーします。

下の方に行くと他のidも出てくるので間違えないように注意してください。


## Deployments：削除
次に、POSTを使ってデプロイのステータスを変更します。
```
gh api -X POST -F state=inactive repos/OWNER/REPO_NAME/deployments/DEPLOYMENT_ID/statuses
```
`OWNER`,`REPO_NAME`は先ほどと同様に、
`DEPLOYMENT_ID`は一覧取得でコピーしたidを入れてください。

実行するとまたjson形式のデータが出てくると思います。
それはそのまま放置してDeleteしていきましょう。

```
gh api -X DELETE repos/OWNER/REPO_NAME/deployments/DEPLOYMENT_ID
```
これも書き換え部分は先ほどと同様です。

実行して何も表示されなければ成功です！Github上で確認してみてください。



## 最後に
ここまでお読みいただきありがとうございました。
色々試しながらやっていたので、もしかしたら上記の方法で実行しても引っかかってしまうところがあるかもしれません。
ですが少しでも問題解決のお役に立てれば嬉しいです。


## 余談
idをコピーする前に、どこかテキストボックス内でWindowsキー＋Vを押して、コピー履歴の保存が有効になっているか確認することをおすすめします。

30個くらいコピー履歴を保存してくれるので、ひたすらidをコピーしまくって、DeleteするときにWindows＋Vでidを探し出しペーストすることができます。
コマンドプロンプト上での行ったり来たりがなくなるので少し便利。

（私のレポジトリには10個以上履歴があったので、どっちにせよ眩暈がしてきていましたが）

一括削除も探したのですが、他のコマンドをインストールする必要があったりして結局面倒になってやめました。
辛抱強く頑張りましょう。

（pushするたびにこの作業やるの面倒だなぁ…）
GitHub Pagesへの公開方法を簡単に解説する

## はじめに
今回、作成したWebサイトをGitHub Pagesで公開したので<br>そのやり方をまとめてみました。
３ステップで簡単にでき、また、後半に自分が躓いた体験をもとに引っかかるポイントも解説したので、ぜひこの記事を参考にしてみてください！

## GitHub Pagesとは
- GitHubから提供されている`静的サイト`[^1]の`ホスティングサービス`[^2]のこと
- WordPressのような動的サイト（ユーザーの操作でページ内容が変化する）の公開はできません
- GitHub無料版ではprivateリポジトリで公開できない(⇨今回は無料でできる`public`リポジトリで解説します)

:::note info
プログラミング学習を始めたてで、模写コーディングなどHTML・CSSを使ってWebサイトを作ってみた方が、まず最初に公開する先として有用です！
:::



[^1]: 静的サイト：　動的なコンテンツ生成やデータベースとのインタラクションがない、プレーンなHTML、CSS、JavaScriptファイルのみで構成されるウェブサイトのこと（JavaScriptを使ったアニメーション含むサイトも公開可能）
[^2]:ホスティングサービス：　インターネット上でウェブサイトやアプリケーションのデータやファイルを保存・公開するためのサーバーを提供するサービスのこと

## 公開に向けて準備するもの
GitHub Pagesを作成するにあたって、以下の準備が必要です。
- [ ] GitHubアカウント
- [ ] HTMLファイル
- [ ] CSSファイル
- [ ] 画像ファイル(必要であれば)

また、今回はGitやLinuxコマンドに関しては一定の知識がある前提で進めます。


## 公開手順3ステップ
### 1. Webサイトを作成する
HTML・CSS(・JavaScript)を使って静的サイトを作成
※こちらは今回はスコープ外となるため、割愛します。


### 2. 作成したWebサイトをGitHubへアップする
#### 1. GitHubへログイン後、新規リポジトリを作成
![CE64FB76-8C09-4A29-97CF-5F5E74142E23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3360649/3998c509-d06e-39f4-ea3c-5b8c7d20b585.png)

#### 2.　レポジトリ設定ページ
①　`Repojitory name`を指定(ローマ字でお好みの名前で！)
②　必ず`public`にチェックが入れる
③　`Create repository`を押下
![9A610F6B-EAD0-4568-BD3A-D4FDBA1C7526.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3360649/0dd97825-e793-d2d3-cd39-8e33a6dbf544.png)
#### 3. 必要ファイルをGitHubへアップする
以下のコマンドから手元のディレクトリとファイルをアップする
```
git init
git add <ファイル名>
git commit -m <コミットメッセージ>
git remote add origin <path>
git push origin main
```


### 3. GitHub上でGitHub Pagesの設定をし公開する
GitHubへのアップロードができたら、
① `Settings`を押下
② `Pages`を押下
③ `main`ブランチ(説明画像はreplaceブランチで公開後、mainブランチにマージする予定なので、replaceブランチを指定している)
④　`Save`を押下
⑤　URLあるいは`Visit site`より作成したGitHub Pagesへ飛べる

![6F6F47F2-C23D-4D0B-8355-5B7B411CE60F.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3360649/253d9b35-5426-ef17-8137-c15d733313cf.png)


:::note warn
URL発行に10分程度時間がかかる場合があります。
:::


### 期待するページが出ない場合は？
僕にも画像のように期待するページが出ず、ずっと悩んでいた時期がありました。

![8C0A086E-5C3B-415C-B977-C22D2091C878.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3360649/3195b0e4-724e-4593-8a47-45506ee38110.png)

そんな方々に向けた解決策としては、
`表示させたいファイルが入った親ディレクトリのパス`までURLに入力することです！！
具体的に僕の例ですと、表示させたいファイルが下記のように、

![6A1CC124-862E-41E8-9B38-7FDC3BBB9DA9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3360649/92dbeb44-f26f-be83-468b-879a9a61f616.png)

<br>

```
/Users/tomopu/Desktop/hc/resume/resume/
```
にあるので、直前の親ディレクトリまでを指定すると、
<br>

![EABF070A-753C-4261-BEEE-38F41ADC624C.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3360649/59d3bd7c-1c3a-fe7d-7b14-618fb5c95ae9.png)



## まとめ
- GitHubから提供されている静的サイトのホスティングサービスのこと
- 動的サイトの公開はできない
- 公開手順は3ステップ
  - Webサイトを作成する
  - 作成したWebサイトをGitHubへアップする
  - GitHub上でGitHub Pagesの設定をし公開する
Unity　InputSystemが名前空間にない場合

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2294598/61ed55c3-7834-95a2-22ca-7632b8f2ff8c.png)
これがエラーになっている場合、assemblyにパスがとっていないかも、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2294598/b259a5b6-3853-b723-b7c0-536e042edef0.png)
自分で作成したassemblyのAssembly Definition ReferencesにUnity.InputSytemを追加することで解決する。
開発下流工程のテスターが上流工程に向かうきっかけの話

### はじめに
これは昔話です。前職の、5年ほど前の話になります。
なんでこんな話をするのかというと、
「品質というものの重要性」
「バグが無い≠良い製品」
「開発の上流にQAは入るべき/開発は上流からQAを巻き込みに行くべき」
ということを理解してもらいやすい話だと思っているのと、
そんな意識を持った人たちが開発者にも増えてほしいという願いがあります。

### 前段
新卒で入社した私は、新卒内で一番ヤバいと噂されていた製品のテスト部門に配属されました。
いろんな面からヤバかったのは事実ですが今回の本筋ではないので一旦割愛するとして、
配属されてすぐ、1日あたりテスト100ケース以上の速度で数ヶ月のプロジェクトに新卒3人でぶち込まれました。
いろいろと問題はありつつもプロジェクトは完了し、いろんなプロジェクトやお客様を担当しつつ、テスト設計者、テストマネージャーと経験をしていきました。

### 懐かしの再開
そうしているうちに、配属して初のプロジェクトを担当したお客様の追加機能案件のテストを担当することになりました。
担当コンサルさんとも懇意にさせていただいており、かなり特殊なお客様でもあるので、過去に担当した私に白羽の矢が立ったのは正しい選択でしょう。
事実、特殊なケースについても対応することができ、胸を張ってバグ0でリリースすることができました。

### 不穏な噂話
少し経ったある日、そのお客様に関しての噂話が耳に入ってきました。
どうやらそれは、私が担当した追加機能案件について「お客様が猛烈に怒っている」らしいのです。
実行したテストケースを見直し、観点不足やチェック漏れが無いのか確かめ、初プロジェクト時の資料も引っ張り出し、それでも不備は見当たりません。
自分で言うのもなんですが、特殊なケースにも対応してバグ修正をしているのでファインプレー級のはずです。
「バグが0なのに、お客様が怒る理由がわからない」
そう思っていました。

### リーダーから明かされる事実
当時のリーダーも同じ噂を聞いていたらしく、詳細を調べにいってくれていました。
そして、リーダーがお客様が怒っていた理由を教えてくれました。
それは、バグや不具合があったからではなく、
 **その機能がお客様の要望を満たしていないから** 
 でした。当然と言えば当然の話ですよね。

 ### 悟ったこと
 この瞬間、私は1つの事実を悟りました。
 それは、
  **バグが0個でも、仮に100個でも、極論私が何もしなくても、
  お客様は怒ったし、つまり私がテストをした意味は何もなかった** 
ということです。

### どうすれば防げたのか
それまで私は「テストでバグを検出してバグを0にすれば品質が良く、お客様が喜んでくれる」と考えてテストを実施、設計、指揮していました。
そして今回目の当たりにした事実は、「バグ0でも意味がないことがある≒テストだけではどうしようもない」ということです。
その時、仕様の決定は開発やコンサルで行い、下流のテスターの立場だった私たちは、上流の出した正を元にテストをするだけでした。
より上流から確認しなければ「お客様の納得するもの≒品質の良いもの」はできないのだと痛感しました。

### そして……
これは完全に偶然ですが、配属された製品のドメインについて、私は古くから慣れ親しんでおり、一般的な人より知識があったようでした。
仕様書を確認して、
「あぁ、これは知識が何もなくてちゃんと作れてないんだな」
と悟り、問題点をまとめ上げ、リーダーに進言し、ドメインのナレッジ化と普及のプロジェクトを任されました。
が、リーダーより上の上長には承認されませんでした。
結果論としてですが、文句はありません。
私の主張は「ここから2年かかっても、そこから先の品質向上には絶対必要だ」でしたが、1年ほどで製品自体が消滅したのですから……

### 今
今は、フルサイクルエンジニアの部署へと流れつき、自身も開発しつつ品質の改善を進めています。
この経験から、より品質向上を目指すのであればQA以外の人も開発に関わるべきだと考えていますが、その話はまた別の機会に。
AppServiceのカスタムバックアップ設定でエラー

# 事象
Azure App Service でカスタムバックアップを設定しようとした際に ”Requested backup frequency exceeds maximum allowed for the plan.” というエラーが発生した

### やったこと
Azure App Service のカスタムバックアップの設定を有効にしようとした。
[カスタム バックアップを作成する](https://learn.microsoft.com/ja-jp/azure/app-service/manage-backup?tabs=portal#create-a-custom-backup)

その際に、
> スケジュールの設定
バックアップの正確な時刻と繰り返しを構成します。
□ スケジュールの設定

という項目にチェックを付けて、「1 時間」に設定してみた。


### つまずいたところ
カスタムバックアップの設定を保存してみようとしたら、

> バックアップ構成の更新
バックアップ構成を保存できませんでした。:
Requested backup frequency exceeds maximum allowed for the plan.

というエラーが出た。


### 解決方法
スケジュールの設定を「1時間」から「2時間」に変更したらカスタムバックアップの設定を保存できた。


# メモ
どうやらバックアップのスケジュールの時間設定に問題があったみたい。

[Azure application back up configuration error:Failed to save Backup Configuration](https://stackoverflow.com/questions/59547653/azure-application-back-up-configuration-errorfailed-to-save-backup-configuratio)
> The Backup and Restore feature requires the App Service plan to be in the Standard tier or Premium tier. For the error message, you could upgrade the app service price tier to a higher tier. For example, you can scale up to P1 tier.
Please note that there are app service limits, The following App Service limits include limits for Web Apps, Mobile Apps, and API Apps.
For standard tier,
Scheduled backups every 2 hours, a maximum of 12 backups per day (manual + scheduled)

ずばり今回の私の環境では S1 を使ってたから、最短でも2hの設定しかできなかったっぽい。

確かに下記見ると書いてあった。
[App Service の制限](https://learn.microsoft.com/ja-jp/azure/azure-resource-manager/management/azure-subscription-service-limits#app-service-limits)



| リソース| 	Free|	共有|	Basic|	Standard|	Premium (v1 から v3)|	Isolated
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
| スケジュールされたバックアップ	|||2 時間ごとにスケジュールされたバックアップ。1 日あたり最大 12 回のバックアップ (手動 + スケジュール済み)|	2 時間ごとにスケジュールされたバックアップ。1 日あたり最大 12 回のバックアップ (手動 + スケジュール済み)|	1 時間ごとにスケジュールされたバックアップ。1 日あたり最大 50 回のバックアップ (手動 + スケジュール済み)|	1 時間ごとにスケジュールされたバックアップ。1 日あたり最大 50 回のバックアップ (手動 + スケジュール済み)
Amazon QuickSightとは(初心者向け)

Amazon QuickSightを学習する際に使用したサイト

QuickSightユーザーガイド
https://docs.aws.amazon.com/ja_jp/quicksight/latest/user/setting-up.html

・【初心者向け】Amazon QuickSightとは（QuickSightシリーズ）
https://www.sunnycloud.jp/column/20210930-01/

・Amazon QuickSightスターターパック
https://www.cloudsolution.tokai-com.co.jp/service/quicksight.html#anc-01

・Amazon QuickSight の料金表
https://aws.amazon.com/jp/quicksight/pricing/

・QuickSightの料金について(Q&A)
https://community.amazonquicksight.com/t/quicksight/20279

・Amazon QuickSight ノウハウ総まとめ！(2020年のもの)
https://pages.awscloud.com/rs/112-TZM-766/images/%5B%E3%82%A4%E3%83%B3%E3%83%88%E3%83%AD%5DAmazonQuickSight%E3%83%8E%E3%82%A6%E3%83%8F%E3%82%A6%E7%B7%8F%E3%81%BE%E3%81%A8%E3%82%81%E3%82%BB%E3%83%9F%E3%83%8A%E3%83%BC_1014.pdf


・QuickSightを用いたデータ分析の成功事例まとめ
https://nuco.co.jp/blog/article/gmQpELQz

・QuickSightを用いた成功事例２
https://aws.amazon.com/jp/quicksight/customers/
Postmanを使ってレポートのメタデータを解析する


以前にレポートの検索条件を取得したいとう質問があって、この時はforce CLIなどを使えばいいと回答しましたが、今では迷わずPostmanを推奨しますね。もう一度Postmanを使った場合について検証してみます。

:::note
１件ずつならSalesforce Reports and Dashboards REST APIでも可能ですが、これでは大変なので force CLIなどのメタデータを一括で取得できるツールを利用したほうがいいと思います。
:::

[レポートの検索条件を取得する](https://qiita.com/Keiji_otsubo/items/114b01d081a300b0d4ac)
（残念ながら質問自体は私の回答が気に入らなかったのか即削除されて今は見ることができません）


# メタデータの取得ではdescribeを使います。

```
{{_endpoint}}/services/data/v{{version}}/analytics/reports/{{reportId}}/describe
```

salesoforce側の検索条件は以下のようになっています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/9974f3e0-9ee1-33a0-451d-c829d0232bec.png)


テストスクリプトに以下を追加してみます

```
pm.test('reportFilters', () => {
    const response = JSON.parse(pm.response.text())
    console.log(response.reportMetadata.reportFilters)    
})
```


一番上のShow meを除く上から3つは標準で用意されている検索条件なので別のところに格納されています


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/b29c55be-544f-d7dc-4d41-5692756dc2c6.png)


取得できた内容

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/6ae39c80-2707-e216-294c-f529183b8c34.png)

もう一つ検索条件を追加します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/94023aa3-78b7-8d2f-aacb-cca774e8bdaf.png)

2件取得できましたね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/6c228d4a-e70d-17c7-a547-a1018fe32e6a.png)


### Show meはどこ？

以下の回答をみえると scopeらしい

+ [Standard Filters for Report](https://salesforce.stackexchange.com/questions/366955/standard-filters-for-report)

全ての商談ではorganization　になっています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/f6c7ca28-a828-37ea-c3d6-75276c3c0002.png)


私の商談では　userになっている

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/0fb5a261-24b1-1f78-2191-999679542247.png)

これらの解析結果を分かりやすい形に成形すことができればいいんですが...
もう少しPostmanの使い方を勉強する必要がありますね。
[Flutter_Web] InAppWebViewの上でダイアログのボタンが押せなかった

## やりたいこと
`InAppWebView`([flutter_inappwebview](https://pub.dev/packages/flutter_inappwebview))をほぼ全面に実装した画面で、[go_router](https://pub.dev/packages/go_router)の`onExit`を使ってページを離れてもいいか？のダイアログを出して、「キャンセル」ボタンと「離れる」ボタンを実装したい。

## 問題
`InAppWebView`の上でダイアログが開くと、ダイアログ内のボタンが反応しない。ジェスチャーが`InAppWebView`に持ってかれている感じ。

## 解決方法
https://pub.dev/packages/pointer_interceptor

`PointerInterceptor`で`AlertDialog`をラップして解決。

```dart
onExit: (context) async {
  final confirmed = await showDialog<bool>(
    context: context,
    builder: (context) => PointerInterceptor(
      child: AlertDialog(
        title: const Text('確認'),
        content: Text(
          'ページを離れてもよろしいですか？'
        ),
        actions: <Widget>[
          TextButton(
            onPressed: () => Navigator.of(context).pop(false),
            child: const Text('キャンセル'),
          ),
          TextButton(
            onPressed: () => Navigator.of(context).pop(true),
            child: const Text('離れる'),
          ),
        ],
      ),
    ),
  );
  return confirmed ?? false;
},
```

Flutter：3.16.3
flutter_inappwebview：6.0.0-beta.27
go_router：12.1.3
Certbotに「certbot.errors.MisconfigurationError: Apache is unable to check whether or not the module is loaded because Apache is misconfigured.」と言われたときの対処

# 前提
### 環境
CentOS Stream release 8
Apache/2.4.58
certbot 1.22.0

# ravenモジュールからインストールしたapache環境では、certbotが動かないらしい
ある日サーバーにcertbotをインストールしようとしたときのこと。
`certbot install`コマンドが`certbot.errors.MisconfigurationError: Apache is unable to check whether or not the module is loaded because Apache is misconfigured.`とエラーを吐いてくる。

実はcertbotの内部では`apachectl`コマンドを呼び出しており、`apachectl`コマンドの使えない環境では正しく動作しない。
自分の環境では、`apachectl`コマンドの実体は下記のようなシェルになっていた。



```bash:/usr/sbin/apachectl
~~~(略)~~~
if [ "x$1" = "x-k" ]; then
    shift
fi

ACMD="$1"
ARGV="$@"
SVC='httpd.service'
HTTPD='/usr/sbin/httpd'

if [ "x$2" != "x" ] ; then
    echo Passing arguments to httpd using apachectl is no longer supported.
    echo You can only start/stop/restart httpd using this script.
    echo To pass extra arguments to httpd, see the $SVC'(8)'
    echo man page.
    exit 1　# <--ここを削除
fi
~~~(略)~~~
```

`if [ "x$2" != "x" ] ; then　~~~ fi`に囲まれている部分の、`exit 1`の行を削除すると、動作するようになる。
【JS/ES6】JSの型の種類


# 型って？
型は変数や関数などに紐付けられるデータの種類や形式のこと。
その型にはどのようなデータなのか？どのような引数を取ってどのような返り値を返すのか？などが定義する。

# 型の種類
JSの型は大きく「プリミティブ型」と「オブジェクト型」に分けられる。

## プリミティブ型
プリミティブ型には数値や文字列など7種類がある。
- 文字列（string）
- 数値（number）
- 論理値（boolean）
- undefined
- null
- シンボル（symbol）
- 長整数（bigint）

## オブジェクト型
プリミティブ型は、配列や正規表現などが含まれ、複数の変数やプリミティブ型の値などの集合からなる。
値自体を後から変更することができるデータ型で、たくさん種類がある。
下記は代表的な型。

- オブジェクト（Object）
- 配列（Array）
- 関数（Function）
- 日時（Date）
- 正規表現（RegExp）
- マップ（Map）とウィークマップ（Weak Map）
- セット（Set）とウィークセット（Weak Set）など

# 型定義は大事！
型を定義することで、不整合を防げたりドキュメント化できたりする。
すべての変数や関数に型を定義することを心がけるようにする！
Amazon Linux 2023 にPodmanをインストール

# Podman インストール

[Amazon Linux 2023でPodmanを動かす](https://rheb.hatenablog.com/entry/podman-on-al2023) こちらを参考に進めました。

まずm6aインスタンスで試したのですが、
conmonあたりのビルドでbtrfs?のヘッダファイルが無いとエラーになり解消できませんでした。
m6aインスタンスは諦め、m5インスタンスで再挑戦。
ビルドとインストールは記載通りに行きましたが動作確認時にコンテナ起動に失敗しました。
エラー文によればiptablesが必要そうだったためインストールしました。

```sh:install iptables
# podman run quay.io/podman/hello
WARN[0000] Failed to load cached network config: network podman not found in CNI cache, falling back to loading network podman from disk 
WARN[0000] 1 error occurred:
        * plugin type="firewall" failed (delete): cni plugin firewall failed: could not initialize iptables protocol 0: exec: "iptables": executable file not found in $PATH
 
Error: plugin type="bridge" failed (add): cni plugin bridge failed: failed to locate iptables: exec: "iptables": executable file not found in $PATH
# dnf install iptables
```
EC2はデフォルトでiptablesがインストールされていないかと思いますが、
何か別に方法があるのでしょうか。

ひとまず以降は手順通りにインストールできました。

# kind インストールと動作確認

続いて [[DevOps] 次世代K8sローカルツール KindをPodmanで立ち上げる
](https://zenn.dev/amezousan/scraps/fb7cd06714add3) こちらを参考にkindを試しました。(kindについてはあまりよく理解していません。)

必要なコマンドはこちらに沿ってインストール
[kind](https://kind.sigs.k8s.io/docs/user/quick-start/#installing-from-release-binaries) [kubectl](https://kubernetes.io/ja/docs/tasks/tools/install-kubectl/#install-kubectl-on-linux)

```
# kubectl get pods -A
NAMESPACE            NAME                                         READY   STATUS    RESTARTS   AGE
kube-system          coredns-5d78c9869d-8bkcc                     1/1     Running   0          76m
kube-system          coredns-5d78c9869d-zwx5k                     1/1     Running   0          76m
kube-system          etcd-kind-control-plane                      1/1     Running   0          76m
kube-system          kindnet-jdvj7                                1/1     Running   0          76m
kube-system          kube-apiserver-kind-control-plane            1/1     Running   0          76m
kube-system          kube-controller-manager-kind-control-plane   1/1     Running   0          76m
kube-system          kube-proxy-zj2hz                             1/1     Running   0          76m
kube-system          kube-scheduler-kind-control-plane            1/1     Running   0          76m
local-path-storage   local-path-provisioner-6bc4bddd6b-hcp8r      1/1     Running   0          76m
```

起動が確認できたので多分成功です。
AndroidでL2CAP

# AndroidのL2CAPサポートについて
Androidでは、Android 10でCoCがサポートされました。

https://developer.android.com/about/versions/10/features?hl=ja#bluetooth-le-coc

従来のBLEでは、クライアントからサーバーに分かれて、少量のデータ転送やデータ通知でコミュニケーションを行ってましたが、BLE CoCでは、接続が確立されたまま、大容量なデータを連続的に送受信できるものになります。

AndroidのBLE CoCを担うものとして(おそらく)L2CAPがAPI 29から追加されているので、その使い方を説明します。

# AndroidでL2CAP接続を確立してデータを送信する
Androidから、他のデバイスへL2CAP接続を行うためには、まず対向の端末をL2CAPとして接続し、データ交換のための `BluetoothSocket` を取得する必要があります。

Androidが他端末に接続する場合、またはAndroid端末でL2CAPチャネルを開いて接続を待ち受ける場合、どちらの場合もBluetoothAdapterを使いますので、まずはBluetoothAdapterを取得します。

```kotlin XXXActivity.kt
val bluetoothManager = getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
// Bluetooth アダプターの取得
val bluetoothAdapter = bluetoothManager.adapter
```


# Androidから他デバイスへL2CAP接続

Androidから、他のデバイスへL2CAP接続を行うためには、`BluetoothDevice` を使っての接続を行います。

BluetoothDeviceは様々な取得方法があり、BLEのスキャンによって端末を取得する方法がありますが、すでにペアリングしている端末に対しては、アドレスを用いての接続も可能になります。
以下のコードは、ペアリング済み端末からBluetoothDeviceを取得して、`createInsecureL2capChannel` でL2CAP接続を行うコードになります。

https://developer.android.com/reference/android/bluetooth/BluetoothDevice#createInsecureL2capChannel(int)

対向の端末からL2CAPの識別子*PSM（Protocol/Service Multiplexer）* を取得して、その値でL2CAP接続を行います。
createInsecureL2capChannelの返り値でBluetoothSocketが帰ってきます。

```kotlin
// ペアリング済み端末のアドレス
val deviceAddress = "00:00:00:00:00:00"
val device: BluetoothDevice? = bluetoothAdapter?.getRemoteDevice(deviceAddress)

// PSMを対向端末から教えてもらう
val psm = 192
bluetoothSocket = device?.createInsecureL2capChannel(psm)!!
bluetoothSocket?.connect()
```

# 他デバイスからAndroidにL2CAP接続
他デバイスがAndroidに対してL2CAP接続をする場合、Android側でPSMを発行してL2CAPチャネルを開ける必要があります。

`listenUsingL2capChannel`を行うことで、BluetoothServerSocketが取得できます。

https://developer.android.com/reference/android/bluetooth/BluetoothAdapter#listenUsingL2capChannel()

BluetoothServerSocketはpsmを持っているので、これを対向の端末に伝えることでL2CAP接続を要求してもらうことになります。
その際、`accept()`などを行うことにより、対向端末の接続を待ち受けることが可能です。
accept()は接続完了まで処理をブロックするので非同期になるように策を講じておくことが必要です。
accept()の戻り値がBluetoothSocketになります。

```kotlin
val serverSocket = bluetoothAdapter.listenUsingL2capChannel()

// PSMを対向の端末に伝える
Log.d(TAG, "psm ${serverSocket.psm}")

lifecycleScope.launch {
    val bluetoothSocket = withContext(Dispatchers.IO) {
        serverSocket.accept()
    }
}
```

# BluetoothSocketでデータのやり取り
BluetoothSocketに備わっている、inputStreamやoutputStreamを用いてでデータのやり取りが可能です。
L2CAPはBLEよりも大容量のデータやり取りが可能です。

## データ受信

inputStreamを使ってデータを受信します。

```kotlin
while (true) {
    val buffer = ByteArray(65536)
    val inputStream = bluetoothSocket.inputStream
    val ret = inputStream.read(buffer, 0, 65536)
    if (ret > 0) {
        // データ処理
        val str = String(buffer, 0, ret)
    }
}
```

## データ送信
outputStreamを使ってデータを書き込みます。

```kotlin
val bytes = "こんにちは".toByteArray()
if (bluetoothSocket.isConnected) {
    bluetoothSocket.outputStream.write(bytes)
}
```