OmniAICreator/Qiita-1.07M huggingface dataset:
特定の範囲に入った際にオブジェクトの色と音を変える処理

## 概要

特定の範囲に入った際にオブジェクトの色と音を変える処理についての備忘録

元記事の喪失の可能性や現時点との差異がないことの証明のために作業手順を列挙する

## 今回の仕様
- 対象Aは操作が可能
- 一定の範囲に入ると対象Aと対象Bは色が変わる
- またその際に音声が出力される

## Inspector側ですること
- 対象Aには**Add Component**より**Rigidbody**を追加する
デフォルトでチェックされている**Use Gravity**のチェックを外す
- 対象Bには**Add Component**より**Audio Source**を追加する
デフォルトでチェックされている**Play On Awake**のチェックを外す
**AudioClip**に音声ファイルをドラッグアンドドロップする

以下のコードのスクリプトを作成する
なお今回ファイル名とオブジェクト名は作成しているアプリに依存するため利用される場合は適宜修正して下さい

```BusyuMove1.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class BusyuMove1 : MonoBehaviour
{
    public bool isArea;
    public float speed;
    private GameObject target;
 
    void Start()
    {
        speed = 3.0f;
        target = GameObject.Find("Busyu");
    }
    void Update()
    {
        if (Input.GetKey (KeyCode.UpArrow)) {
            transform.position += transform.up * speed * Time.deltaTime;
        }
        if (Input.GetKey (KeyCode.DownArrow)) {
            transform.position -= transform.up * speed * Time.deltaTime;
        }
        if (Input.GetKey(KeyCode.RightArrow)) {
            transform.position += transform.right * speed * Time.deltaTime;
        }
        if (Input.GetKey (KeyCode.LeftArrow)) {
            transform.position -= transform.right * speed * Time.deltaTime;
        }
        if (Input.GetKey (KeyCode.W)) {
            transform.position += transform.forward * speed * Time.deltaTime;
        }
        if (Input.GetKey (KeyCode.S)) {
            transform.position -= transform.forward * speed * Time.deltaTime;
        }


        
        if(target.GetComponent<BusyuMove1>().isArea == true) {
            GetComponent<Renderer>().material.color = Color.blue;
        }
        else {
            GetComponent<Renderer>().material.color = Color.white;
        }
    }
 
    void OnTriggerStay(Collider other)
    {
        if (other.gameObject.name == "KanziArea" )
        {
            isArea = true;
        }
    }
 
    void OnTriggerExit(Collider other)
    {
        if (other.gameObject.name == "KanziArea" )
        {
            isArea = false;
        }
    }
}
```

```BugaiMove.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class BugaiMove : MonoBehaviour
{
    private GameObject target;
    // Start is called before the first frame update
    void Start()
    {
        target = GameObject.Find("Busyu");
    }

    // Update is called once per frame
    void Update()
    {
        if(target.GetComponent<BusyuMove1>().isArea == true) {
            GetComponent<Renderer>().material.color = Color.blue;
            GetComponent<AudioSource>().Play();
        }
        else {
            GetComponent<Renderer>().material.color = Color.white;
        }
    }
}
```

## 実際の動きの様子
https://twitter.com/N1809031125/status/1604999808435228673?s=20&t=hGsIygrq3A2nMB4BWO2lBw

## 終わりに
if文の中に処理を書いていけば一定の範囲に入った際に何か処理をすることが可能になる
応用例としては範囲内でオブジェクトの動きが変わるとかゲームオーバーの処理を流すなどが考えられる

## 参考サイト

https://futabazemi.net/unity/collider_stay_chase

https://miyagame.net/audiosource/
Nugetパッケージの復元エラーをコマンドライン環境下で解決する方法

# はじめに

Nuget を利用したソリューションを新規環境でビルドしようとすると、パッケージの復元エラーが発生することがある。
本書は、その解決方法の覚書である。

# 統合開発環境の場合
VisualStudioの統合開発環境でのビルドならば、

https://learn.microsoft.com/ja-jp/nuget/consume-packages/package-restore-troubleshooting

に説明された手順とおりに、

1．メインメニュー [ツール] > [NuGet パッケージ マネージャー] > [パッケージ マネージャー設定] でオプションダイアログを開く。
2. パッケージの復元 のチェックボックス２つをオンにして、OKをクリックする。
3. プロジェクトを再ビルドする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130677/8a50ca45-a975-7af2-157e-23ec06d10bb7.png)

これにてパッケージの復元が実行される。

# コマンドライン環境の場合
Makefile や jenkinsなどのコマンドライン環境下のビルドならば、

https://learn.microsoft.com/ja-jp/nuget/consume-packages/package-restore#restore-using-msbuild

に説明されているが、具体例に乏しくわかりにくい。
Makefile に記載する依存関係も含めて正解をここに記す。

```Makefile
# update packages folder
packages: packages.config
    msbuild /nologo /p:platform=x86 /p:configuration=Release /t:restore /p:RestorePackagesConfig=true MYPROJ.sln
```

これにて packages フォルダが無い場合や、packages.config変更時にパッケージの復元が実行される。
手動復元したい場合はコマンドラインに ```nmake packages``` と打ち込めば良い。

msbuild のかわりに nuget.exe を使う方法もあるが本書では割愛する。
nuget.exe を使う方法は下記リンクを参照されたい。

https://learn.microsoft.com/ja-jp/nuget/consume-packages/package-restore#restore-by-using-the-nuget-cli

# END
【V】video属性をvideo非対応環境に配慮して使う方法

今どきvideo非対応環境を使っていることのほうが少ないと思いますが知っといて損はないはず

## 複数の動画ファイルを指定

videoタグは複数の動画ファイルを指定できます。
複数指定した場合、読み込めるファイルの中で一番上に書かれているものが表示されます。
mp4は非対応だがaviは対応している、みたいなブラウザがあったときに役に立つ気がします。

```html
<!-- 一つだけならこれでいい -->
<video src="example.mp4"></video>

<!-- 複数指定する場合はこれ -->
<video>
    <source src="example.mp4">
    <source src="example.avi">
</video>
```

## videoタグ非対応時の代替テキストを指定

videoタグ非対応時は中身に書いてある対応しているタグが見えるようになります。
これに限らず非対応タグは全部できるらしいです

```html
<video>
    <source src="example.mp4">
    <source src="example.avi">
    <!-- こういうふうにするとvideoタグ非対応時に文章が表示できる -->
    <p>動画を再生するには、videoタグをサポートしたブラウザが必要です。</p>
</video>
```
Apexで日時型の計算をする

数式ではよく質問がでます。Apexではと聞かれて悩みました。

+ [How to finds hours between two time in apex](https://trailhead.salesforce.com/trailblazer-community/feed/0D54S00000MhBfL)

```
Long dt1Long = DateTime.now().addDays(-1).getTime();
Long dt2Long = DateTime.now().getTime();
Long milliseconds = dt2Long - dt1Long;
Long seconds = milliseconds / 1000;
Long minutes = seconds / 60;
Long hours = minutes / 60;
Long days = hours / 24;
```

https://salesforce.stackexchange.com/questions/42331/how-to-calculate-the-time-between-two-datetimes
業務の課題を改善しようと思ったらすでに解決していた

さっそくですが、普段脆弱性診断の作業をしていく際に感じた、下記の課題を解決するために試したことを書いていきます。
- 業務上の疑問があったときに、マニュアルではなく「○○さんに聞けばわかる」となることがある
- ごくたまに対応する案件で、固有の疑問が発生する


## どうしてこれが課題になるのか
>業務上の疑問があったときに、マニュアルではなく「○○さんに聞けばわかる」となることがある

「○○さんに聞けばわかる」という状態は、その○○さんがいない場合に対応ができなかったり、対応できても解決までに時間がかかってしまうことになるため、あまり良くない状態と考えています。


>ごくたまに対応する案件で、固有の疑問が発生する

業務内容の都合上、数ヶ月や一年のスパンを空けて対応する案件があります。
日々たくさんの案件の対応でチャットのやり取りが積み上がっているので、一年前の案件のやり取りを探すには深い海を潜っていくかのような気持ちになります。

## 結果
タイトルでネタバレしていますが、これから書くやり方は今の私がいるチームの状況ではそれほど必要ではありませんでした…！

すでに、困ったことがあればいつでもお互いに聞ける状態であることと、一度聞いたメンバーは他のメンバーへも積極的に共有してくれるため、属人化は回避できています。

ごくたまに対応する案件についても、案件ごとの情報を作業中からまとめるようにして、必要になればそれを確認するだけで大丈夫な状態にしています。
チャットについても、案件ごとに分けているため、調べるのもそんなにめんどくさくないようになっています。

 __そもそも上の課題は、すでに対策できていたという…！（ありがたい）__

課題設定をミスっているので、いまさら書く必要があるかどうかあやしいですが、このやり方がフィットする場合もあるかなと思うのでやったことを書いておきます！

### やったこと
まず、こんなスプレッドシートを作りました。
![list.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/141077/37c289ec-6908-9632-87d4-b639a1f075c6.png)


このメモの目的と、記載する方針には下記を設定しました。

#### 目的
 - 口伝で共有されている情報や問題解決の手順をテキストとして残す
 - マニュアルに落とし込む必要のある情報はマニュアルへ反映していく

#### 方針
 - 内容が重複していてもOK
 - どんな小さな疑問でもOK

記載する項目はあえて「いつ 何の 何が どうした？ そしてどうなった」と設定しています。
これは、普段の作業内容に照らし合わせて必要な内容だけを記載する狙いがあります。
フリーな文章で残すようにすると内容をまとめる時間がかかるし、読んで理解するときにも手間が必要になるため、楽をしました。

### 結果
まず自分ひとりで3ヶ月やってみたところ、業務で発生した疑問は100件ほどありました。
1日2～3件ほど疑問があり、それが何らかの方法で解決していっていたことになります。
また、作業マニュアルに落とし込んだ疑問は5件ほどでした。


## 雑感
このような形でメモを残しておくことで、日々の細かい疑問やつまづきやすいところを把握することが出来る効果はあるかなと考えています。
あと、集まったメモは簡易的なQ&Aとしてそのまま流用出来るかもしれません…！
Azure Administrator(AZ-104)：Azure管理者向けの前提条件「ARMテンプレートのパラメーターコード例」

Microsoft Learnを用いたMicrosoft Azure Administrator(AZ-104)の試験内容をまとめる投稿です。
この投稿ではMicrosoft Learnで学ぶ内容をできるだけ簡潔にまとめております。
Azureの勉強を一から始め、AZ-900取得後の資格としてAZ-104取得を目指している方の参考になれば幸いです。
※AZ-900の内容は本投稿では省略しております。再度復習したい方は下記をご参照ください。
[Azure Fundamentals(AZ-900)：試験合格に向けた学習内容のまとめ](https://qiita.com/fsd-jume/items/e4ec76959adb547ac5e8)

## 今回の学習内容
**◆「ARMテンプレートのパラメーターコード例」**
◇対応するMicrosoft Learn ラーニングパス
[AZ-104:Azure 管理者向けの前提条件](https://learn.microsoft.com/ja-jp/training/paths/az-104-administrator-prerequisites/)
◇対応するモジュール
[パラメーターと出力を使用して Azure Resource Manager テンプレートの柔軟性を高める](https://learn.microsoft.com/ja-jp/training/modules/create-azure-resource-manager-template-vs-code/4-add-flexibility-arm-template?tabs=azure-cli)

※前回の投稿は下記から確認できます。
[Azure Administrator(AZ-104)：Azure管理者向けの前提条件「AzureへのARMテンプレートのデプロイ」](https://qiita.com/fsd-jume/items/9a69b23b0d40d99414c6)

## ARMテンプレートのパラメーターコード例
ARMテンプレートのパラメーターの説明は下記から確認できます。

https://qiita.com/fsd-jume/items/e05bb275eba9f299a2f5

**ARMテンプレートにおけるパラメーターの使用例**
・ストレージアカウント作成時にSKUを設定するテンプレート
(パラメーターに関わる部分以外は省略)
```json:test.json(パラメーター) 
"parameters": {
        "storageAccountType": {
            "type": "string",
            "defaultValue": "Standard_LRS",
            "allowedValues": [
                "Standard_LRS",
                "Standard_GRS",
                "Standard_ZRS",
                "Premium_LRS"
            ],
            "metadata": {
                "description": "Storage Account type"
            }
        }
    }
```
**※コードの意味**
**・storageAccountType**
デプロイ時に指定するパラメーター名
**・type**
パラメーターで入力する値の型
**・defaultValue**
パラメーターを指定しなかった場合に適用される値
⇒今回の場合はデプロイ時にstorageAccountTypeを指定しなかった場合、Standard_LRSでデプロイされる
**・allowedValues**
パラメーター入力時に入力できる値を指定
**・description**
ポータル上でデプロイする際に、表示される注釈
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2851723/6b45d6c5-1a4c-e5a6-26f5-0e1e59d3650b.png)

```json:test.json(リソース) 
 "resources": [
        {
            "type": "Microsoft.Storage/storageAccounts",
            "apiVersion": "2019-04-01",
            "name": "testtemplateparameters",
            "location": "[resourceGroup().location]",
            "sku": {
                "name": "[parameters('storageAccountType')]"
            },
            "kind": "StorageV2"
        }
    ]
```
**※コードの意味**
**・type**
作成したいリソースのリソースプロバイダーを指定
**・name**
作成されるリソースの名前
**・location**
作成されるリソースのリージョン
**・resourceGroup().location**
リソースグループのリージョンを取得する関数
**・sku name**
作成されるストレージアカウントのSKUを指定
**・parameters('storageAccountType')**
デプロイ時に指定するstorageAccountTypeパラメーターの値を使用する
**・kind**
作成されるストレージアカウントの種類を指定
```powershell:PowerShell
New-AzResourceGroupDeployment `
 -Name testdeployment1 `
 -TemplateFile "test.json" `
 -storageAccountType Standard_LRS
```
**※コマンドの意味**
**・storageAccountType**
作成したパラメーターの値を指定

## 次の学習内容
**◆ARMテンプレートの出力**

https://qiita.com/fsd-jume/items/dea0e3ba45306df94e08

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

https://qiita.com/fsd-jume/items/6eda24728c9c03c36bc3
【PHP/Laravel】Carbonでの日付の扱い（加算・減算）にはご注意！

# はじめに
Carbonは、PHPで日付や時刻を扱う処理を簡単にするためのライブラリです。
Laravelには標準搭載されています。

# 想定読者
PHP/Laravel初学者

# 開発環境・前提

### 開発環境
- OS：Windows11 22H2
- PHP 8.2.0
- Laravel 9.44.0

### 前提
- ローカルにLaravel開発環境があること。

(今回の検証用)
作成したデフォルトのLaravelプロジェクトにおいて、以下の各ディレクトリにファイルをそれぞれ配置。
ファイル名は任意。

- app\Http\Controllers\MonthController.php
- resources\views\month.blade.php


# ソースコード（該当箇所のみ）
```MonthController.php
<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use Carbon\Carbon;

class MonthController extends Controller
{
    public function month() 
    {
        $month = new Carbon('20220331');
        $month->subMonth();

        return view('month')->with('month', $month);
    }
}
```

```month.blade.php
/* bodyタグの間に記述（ブラウザに日時を表示させるための記述）*/
<h1>{{ $month }}</h1>
```

```web.php
/* デフォルトのルーティングに以下を追記 */
Route::get('month', [App\Http\Controllers\MonthController::class, 'month']);
```

# 実装内容の解説
#### use Carbon\Carbon;
このuse宣言を`MonthController.php`に追記することで、MonthController内でCarbonを用いた処理を行えるようになります。

#### $month = new Carbon('20220331');
2022年3月31日を指定し、Carbonのインスタンスを作成しています。

#### $month->subMonth();
1ヶ月減算する処理です。

#### return view('month')->with('month', $month);
変数`$month`を渡した上で、ビューファイル`month.blade.php`を表示させます。

# ★注意点（メインテーマ）
上記の実装を行い、`http://localhost/month`にアクセスすると、以下のように日時がブラウザに表示されるはずです。
![qiita1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2512880/6a9da296-4729-adaf-437b-4e4960d33b6b.png)
「2022年3月31日」から1ヶ月減算すると、感覚的には「2022-02-28（うるう年以外）」のように月末になってほしいところですが、中途半端な日付になってしまいます。

これは「2022年2月31日」という日付が存在しないため、28日からあふれた3日分が加算されたことによるものです。
それでは、ぴったり月末にするにはどうすれば良いのでしょうか？

（答え）
`MonthController.php`の該当部分を以下の通りに編集すると解決します。

```diff_php
- $month->subMonth();
+ $month->subMonthNoOverflow();
```

この編集後、再度`http://localhost/month`にアクセスすると、以下のように日時が変わっているはずです。
![qiita2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2512880/b0a10e04-b2c9-7f21-07b1-85b537951edd.png)
これできれいに月末に揃えることができました！
この方がしっくりきますよね！

ちなみに加算するパターンを試すため、先程編集した`MonthController.php`を以下のように再編集すると、日時は「2022-04-30 00:00:00」になります。

```diff_php
- $month->subMonthNoOverflow();
+ $month->addMonthNoOverflow();
```
![qiita4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2512880/89a1ba71-4fac-7909-d20a-a0a050f62ca5.png)
なお、ただの`$month->addMonth();`にした場合は「2022年4月31日」が存在しないので、30日からあふれた1日分が加算されて「2022-05-01 00:00:00」になります。

# まとめ
日付や時刻を扱う処理では想定外の結果が生じる可能性が高いので、開発においては注意したいポイントです。
本記事が少しでも読者の皆様の参考になれば幸いです。

それでは良き開発ライフを！！

# 参考情報
- Carbon公式

https://carbon.nesbot.com/
FuelPHP の Pagination を読んでみた。

## FuelPHP の Pagination を読んでみた
FuelPHP の Pagination を使っているコードを読んでいて、自分で Pagination を使った実装しようかと思ったけど、その前に仕組みが気になったので、FuelPHP の Pagination の内部実装を見てみました。

https://github.com/fuel/core/blob/2c8c548a2f9f4aa08ecfe321c3e744d03472479c/classes/pagination.php

## 読む順番

Controller 側での pagination の初期化から、

```php
$pagination = \Pagination::forge('name', $config)
```

View 側での レンダー処理の順で読んでいきます。

```php
echo Pagination::instance('mypagination')->render();
// つまり
$pagination->render()
```

## Pagination を読んでみる

#### __toString
`<?php echo` や `<?= echo` で呼ばれる時など、string を cast された時に呼ばれます。[その実装によると](https://github.com/fuel/core/blob/2c8c548a2f9f4aa08ecfe321c3e744d03472479c/classes/pagination.php#L253)、render を呼び出しています。

#### render
__toString ですぐ呼ばれる関数。ここで、Pagination の HTML化を行っている。[ここ](https://github.com/fuel/core/blob/2c8c548a2f9f4aa08ecfe321c3e744d03472479c/classes/pagination.php#L274)で、次に出てくる `first, previous, pages_render, next, last` の結果をつなげています。

#### first, previous, pages_render, next, last
`first, previous, pages_render, next, last` それぞれ、Pagination の 一番左のボタン(1番目)・その右のボタン(前へ)・真ん中のボタン群・一番右から一つ左のボタン(次へ)・一番右のボタン(最後)を表示する関数。
内容は全て簡単に言えば `_make_link` を呼び出していて url を変更した html を返しているだけになります。

#### _make_link

受け取った page のインデックス と $config 内の url の情報から、リンクを生成しています。実装は [こちら](https://github.com/fuel/core/blob/2c8c548a2f9f4aa08ecfe321c3e744d03472479c/classes/pagination.php#L565) にあります。
pagination だと $config の uri_segment に数字を渡すか文字列を渡すかで挙動が違うんですが、それも [ここ](https://github.com/fuel/core/blob/2c8c548a2f9f4aa08ecfe321c3e744d03472479c/classes/pagination.php#L605-L624) に実装が載っていて、 数字だとパスに数字が、文字列だとクエリに数字が埋め込まれます。
そして最終的に、url と クエリが組み合わさります（実装だと[ここ](https://github.com/fuel/core/blob/2c8c548a2f9f4aa08ecfe321c3e744d03472479c/classes/pagination.php#L631)）。

そのHTMLの結果が `_make_link` で返ってきて、render で組み合わされることになります。

## 最後に
少し端折って説明しましたが、意外と簡単に出来ていることは分かったのではないでしょうか？
1年ででTOEIC720→825になるためにやったこと

# TOEIC800超えるとなんだか聞こえがいい

去年「３か月でTOEIC420→720になるためにやったこと」を投稿してから約１年が経過した
https://qiita.com/pome_chiwa_momo/items/5e7e247e4695f483dd4b


今年も受験したら800という１つの目安を達成できたのでやったことをメモする

## 公式問題集がおすすめ
やっぱり公式問題集が一番テスト形式で練習できる

昼休みに公式問題集の文法を解く日々を３か月ほど送った
リスニングは５回くらいやった
聞こえるっちゃ聞こえるが...くらいで
どういう問題が多いか？みたいな経験を積むことができたという程度

文法は点が取りやすいので勉強次第で伸びると感じた


## にじさんじENがおすすめ
やっぱり日常的にリスニングするのがいい
速度に耳が慣れるだけでも十分だと思った

できてないけどシャドウイングできるともっといいんだろうな

ike Evelandさんが綺麗な英語で聞きやすい配信をしているのでよく聞いています


来年は840超えてAランクに進みたい
AWS プロクシサーバ(squid)構築

# AWS プロクシサーバ(squid)構築

固定IPでコンソールに入らないといけないので、プロクシサーバを設定したときのメモ

前提条件：Elastic IPアドレスを割り当てたEC2インスタンス

## squidインストール
インストール
```yum install -y squid```

自動起動有効
```systemctl enable squid```

## 設定ファイルに接続するIPを追加

```vim /etc/squid/squid.conf```

以下を追加
※http_access deny allより前に記載すること
```
acl myip src (接続するIPアドレス)/32
http_access allow myip
```

### セキュリティグループに穴をあける。
AWS consoleのセキュリティグループのinboudにsquidのデフォルトポート：3128、接続元は自分のIPを設定する。

## 再起動
``` systemctl reload squid```

あとは、ブラウザでプロクシ設定してアクセスする。

診断くんとかでIPチェックをおこなって問題なければ終わり。


以上です。
今日から始めるROS2

最近ROS2を始めようとする人をよく見るが必ずと言っていいほど環境構築に沼っているのでそこら辺をまとめてみた。

# ROS2が動く環境
比較的簡単に環境構築できるものをまとめる。

### Docker #1
WindowsやMac上で動かしたいと人にお勧め。このリポジトリのイメージはVNCでGUIをも使えてお勧め。
※M1 Macで使う人はArm64のDockerfileから作ることを推奨。

https://github.com/Tiryoh/docker-ros2-desktop-vnc

### Docker #2
UbuntuのDockerコンテナを立ててその中で環境を作る。インストール方法はDebian binary install を参照。

https://docs.ros.org/en/humble/Installation/Ubuntu-Install-Debians.html

### Jetson Nano
OSも簡単に入るのでお勧め。ただしUbuntu 18.04なのでDashingを入れる必要あり(FoxyとかHumbleは入らない)。

https://docs.ros.org/en/dashing/Installation/Ubuntu-Install-Debians.html#

### Raspberry Pi
UbuntuServerを入れればOK。

### Ubuntu
そこら辺に落ちているPCにUbuntuを入れてROS2を入れる。これが一番安定していると思う。

### Azure
その他クラウドもOK(筆者が普段使っているのがAzureなだけ)。最大IOPSが1000以上のVMを選ぶと間違いない。

### WSL
基本的に導入時に沼る事はない。GUIやUSBを使おうとするとハマる。CUIオンリーで外界と繋ぐ予定がないなら良いかも。


### 非推奨
- MacOS
    - 依存関係構築不可のレベル。Mojave以降で動いた試しがない
- Native Windows
    - 環境構築できてもLinux系のライブラリ依存のパッケージが多いため詰む。

# サポートOSとROS2バージョン
()内はサポート期限

https://docs.ros.org/en/galactic/Releases.html

- Ubuntu 22.04
    - Humble (2027)
- Ubuntu 20.04
    - Glactic (2022)
    - Foxy (2023)
- Ubuntu 18.04
    - Dashing (EOL)
先輩からのアドバイスまとめ

# この記事の目的
コードレビューや設計審査をしてもらった際にメモにまとめているが、メモだと見づらい

そこで！
せっかくなので記事にまとめることで
わかりやすく見直しやすいメモを作ろう
 
### 筆者のプロフィール
* 社会人三年目　大手メーカーシステム開発
といいながらも２年間ほぼ研修で業務経験は１年程度
* 想定する読者
    * コード書く際に何を意識したらよいか分からない人
    * 後輩に教えているけど、何が分からないか分からない人

# 設計
* MVC
    * 一般的にModel(データ)、View(UI)、Cntrol(制御)は分けた方が良い
    * 責務を明確にする
    * 名前をしっかり定義できると責務も明確化できてよい
    *  
* カプセル化を意識
    * できたら作ったものは他に流用できた方がいい
    * そうすると、部品を用意して他から使ってもらうように考えるとよい。
    * 抽象化できてたら問題が起こった時の切り分けも楽になる
    * 
> * 先を見越してコードを書く意識がないので、こういうことが起きたらどうする？今後も使うためにはどうしたら便利かな？などで誘導してもらえるとありがたい
>* この責務は何かな？だとしたら名前は何かな？などある程度あたりを付けてもらえると考えやすい

        
# コード
* 設計がしっかりしていればその通りコードを書くだけでいいはず。これが理想
* シンプルなコードにすべき
* 仲介役みたいなものはなるべく排除
* 順番管理はさせないように
    * 意識しないでできるようにコンストラクタを活用するなど工夫する
    * 順番があるものを外部のモジュールに頼らない方が良い


# その他のメモ
* 責務といってもなかなかわかんなかったのでコメント駆動にするといいかもしれない
    * まずやりたいこと１行程度でコメント書いて、それだけシンプルに起こす

## 機嫌よく過ごすためのメモ
* おやつがあると嬉しい
* ブラインド開けると開放感がすごい
違う会社かと思ったくらい気持ちよく過ごせる
ArgoCDでデプロイしたときにDatadogのSyntheticsテストを自動実行する

## 何の話？

DatadogのSyhtheticsテスト(APIテスト、ブラウザテスト)をCIやCD内で自動実行したいってことがあると思います。
ArgoCDでアプリケーションをデプロイ後に自動実行する方法をまとめておきます。

## Syntheticsテストの自動実行

DatadogのSyntheticsテストは、CI/CDの中で自動実行することができます。
curlでAPI叩くだけで実行できます。

https://docs.datadoghq.com/ja/synthetics/ci/?tab=browsertest#%E3%83%AA%E3%82%AF%E3%82%A8%E3%82%B9%E3%83%88%E4%BE%8B

実行に必要な情報は
- API Key
- APP Key
- 実施したいSyntheticsテストのPublic ID
になります。

Public IDはDatadogの画面の ↓の部分（XXX-XXX-XXX）で分かります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3246/623e9152-b7db-e17e-033e-ccf30b1aefc0.png)

API Key、APP Keyは別途作成してください。

## ArgoCDでの自動実行

ArgoCDではResource Hooksという機能があり、Sync実行前や後にKubernetesのJobを実行させる機能があります。
https://argo-cd.readthedocs.io/en/stable/user-guide/resource_hooks/

Syntheticsテストを実行するJobを作成し、Sync成功後に実行させればデプロイ完了後にSyntheticsテストを自動実行できます。

やり方は簡単で、Jobのannotationに下記を追加して、
```yaml
metadata:
  annotations:
    argocd.argoproj.io/hook: PostSync
    argocd.argoproj.io/hook-delete-policy: HookSucceeded
```
自動実行させたいArgoCD Application内にこのJobを置くだけです。

Jobのコンテナイメージはビルドしておいてもいいですし、これくらいならcurlのイメージ使ってcommandで実行してもいいかと思います。
curlのイメージ使ったときのJobはこんな感じになります。(Secretは別途作成してください)

```yaml
apiVersion: batch/v1
kind: Job
metadata:
  name: datadog-browser-test
  annotations:
    argocd.argoproj.io/hook: PostSync
    argocd.argoproj.io/hook-delete-policy: HookSucceeded
spec:
  template:
    spec:
      containers:
      - name: curl
        image: curlimages/curl
        env:
          - name: api_key
            valueFrom:
              secretKeyRef:
                name: dd-test
                key: api_key
          - name: app_key
            valueFrom:
              secretKeyRef:
                name: dd-test
                key: app_key
          - name: public_id
            valueFrom:
              secretKeyRef:
                name: dd-test
                key: public_id
        command:
        - curl
        - -X
        - POST
        - -H
        - 'Content-Type: application/json'
        - -H
        - "DD-API-KEY: $(api_key)"
        - -H
        - "DD-APPLICATION-KEY: $(app_key)"
        - -d
        - "{\"tests\": [{\"public_id\": \"$(public_id)\", \"locations\": [\"aws:ap-northeast-1\"]}]}"
        - "https://api.datadoghq.com/api/v1/synthetics/tests/trigger/ci"
      restartPolicy: Never
  backoffLimit: 2
```

ArgoCDはテストをキックするだけで、実行結果はわからないので、Datadog上で確認するとか、アラートを飛ばすとかしてください。
【Django】defaultsから読み解くエラーハンドリング

## はじめに
Djangoのエラーハンドリングについて調べている際に、組み込みモジュールとして提供している[_defaults（django.views.defaults）_](https://github.com/django/django/blob/main/django/views/defaults.py)の中身を見る機会がありましたので確認した内容を整理してみました。

## defaultsのエラーハンドリング
_defaults_ の中でエラーハンドリングを実装しているステータスコードとデフォルトで使っているテンプレートは以下となります。

| ステータスコード  |テンプレート       |
|:------------| :------------      |
| 400（bad request）          | 400.html | 
| 403（HTTP Forbidden）          | 403.html |
| 404（page not found）        | 404.html |
| 500（server error）           |500.html |

_defaults_ のソースコードを確認すると、ステータスコードに対応するテンプレートに必要な情報を渡すというシンプルな作りになっているようです。
また、公式ドキュメントを確認するとステータスコード400/404/500は `DEBUG` が`False`の場合のみ _defaults_ で定義しているテンプレート（400.htmlなど）を使用するとの記載があります。

| ステータスコード | 仕様                                                                        |
| :------ | :---------------------------------------------------------------------------------- |
| 400（bad request） | <ul><li>とくになにもテンプレートに渡さない</li><li>`DEBUG`が`False`の場合のみ400.htmlを使用する</li></ul>             |
| 403（HTTP Forbidden） | <ul><li>exceptionの内容をテンプレートに渡す</li></ul>             |
| 404（page not found） | <ul><li>エラーになったRequestのpathとexceptionの内容をテンプレートに渡す</li><li>`DEBUG`が`False`の場合のみ404.htmlを使用する</li></ul>             |
| 500（server error） | <ul><li>とくになにもテンプレートに渡さない</li><li>`DEBUG`が`False`の場合のみ500.htmlを使用する</li></ul>             |



そのため、_defaults_ で実装しているエラーハンドリングを使用したい場合は __DEBUGモードを無効にする__ 必要がありそうです。



## DEBUGモードのエラーハンドリングについて
DEBUGフラグによって使用するエラーハンドリングの割り振りをしているのは[_exception（django.core.handlers.exception）_ ](https://github.com/django/django/blob/0dd29209091280ccf34e07c9468746c396b7778e/django/core/handlers/exception.py)で、`DEBUG`が`True`の場合は _defaults_ ではなく[_debug（django.views.debug）_](https://github.com/django/django/blob/0dd29209091280ccf34e07c9468746c396b7778e/django/views/debug.py)にあるエラーハンドリングが呼び出されるようです。

## 今回わかったこと
- エラーによってはDEBUGフラグによって使用するテンプレートが変わる
- _defaults_ で実装しているエラーハンドリングを使用したい場合は`DEBUG`を`False`にする
- DEBUGフラグによって使用するエラーハンドリングの割り振りをしているのは _exception_
- `DEBUG`が`True`の場合は _defaults_ ではなく _debug_ にあるエラーハンドリングが呼び出される

## おわりに
_defaults_ を読み解くことでエラーによってはDEBUGフラグによって使用するテンプレートが変わることがわかりました。
今後は _exception_ も確認し、DEBUGがTrueの場合にどのような動作をするかも確認してみたいと思います。
また、エラー時にslackに通知するなどの拡張も簡単にできるようなので試してみたいです。

## 参考
  - [公式ドキュメント](https://docs.djangoproject.com/ja/4.1/ref/views/#error-views)
  - [Djangoソースコード](https://github.com/django/django)
Amazon Connectを用いた多要素認証の構築

[Ateam Finergy Inc.× Ateam CommerceTech Inc.× Ateam Wellness Inc. Advent Calendar 2022](https://qiita.com/advent-calendar/2022/finergy-commerce-tech-wellness)の23日目は[エイチームコマーステック](https://commerce-tech.a-tm.co.jp/)(以下コマーステック)の@shimura_atsushiが担当します。

# 最初に
:::note warn
本稿はAmazon Connect導入に必要な手続き（電話番号取得 etc）についての紹介はいたしません.
:::

コマーステックの展開する自転車ECサービスである[cyma](https://cyclemarket.jp)では資格を持った整備士が整備した自転車を購入でき自宅まで配送してくれるサービスです。
cymaではお客様が訪問して自転車を選ぶサイトの他にバックヤード業務を行う管理画面がありcymaのエンジニアが保守運用をしています。
この管理画面はcymaのスタッフの他に取引先企業の担当者の方へ機能を開放しています、今回は取引先向けに実装した`Amazon Connect`を利用した多要素認証導入への取り組みを紹介します。

# なぜAmazon Connect？
多要素認証というとEmailやSMSなどでワンタイムパスワードを発行する仕組みが一般的だと思います。
認証にcymaが認めた固定電話番号を必須とし、オフィスの外から管理画面へのアクセスを遮断し、セキュリティを向上させるため、Amazon Connectを用いることにしました。
Emailの環境などITインフラがなくても大抵の企業に固定電話はあるためコンタクトセンターのサービスであるAamazon Connectへコールすることで電話口からワンタイムパスワードを通知するようにします。

# ワンタイムパスワードの発行
Amazon Connectはインスタンスを作成して起動するとコンタクトフローが組めるようになります。
以下のイメージはその様子ですが各処理を表す図を組み合わせることで架電後のフローを設定することができます。
![スクリーンショット 2022-12-21 21.57.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/311437/9fda9a1f-b45b-8383-8d66-7fd9cb613ba9.png)
静的な文言を自動音声で喋らせることができますが架電毎に動的にしたいワンタイムパスワードは架電直後に稼働するAWS Lambdaで生成しています。

## 音声の調整
生成したワンタイムパスワードは自動音声で通知することができますが例えば4桁の数字をそのままワンタイムパスワードに使うとそれぞれの桁の発生の間隔が狭く聞き取りにくいなってしまいます。
Amazon Pollyを用いて音声の調整しています、下記AWSのドキュメントを参照して試してみてください。

https://docs.aws.amazon.com/ja_jp/connect/latest/adminguide/text-to-speech.html

## ワンタイムパスワードの確保と有効期限の設定
ユーザへAmazon Connectを介してワンタイムパスワードを通知するのと同時にどんなワンタイムパスワードを発行したかを確保して置く必要があります、そのためにDynamoDBを用います。
Amazon Connectは架電番号を取得することができるのでワンタイムパスワードと紐付けて架電番号を保存しておくことでどのユーザにどのワンタイムパスワードを発行したかを関連付けすることができます。
また各レコードへTTLを設定することでワンタイムパスワードの寿命を設定することができます、UNIX時間のカラムを作成してTTLに指定することでDynamoDBがその時間にレコードを削除してくれます、これで簡単にワンタイムパスワードの有効期限を設定することが可能です。
![スクリーンショット 2022-12-20 8.26.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/311437/d2ef5bcc-4ed3-946c-bf53-fdb9202c1a32.png)



# 最後に
Amazon Connectを用いて電話を用いて多要素認証の実装を紹介しました。
アプリケーション側で発行されたワンタイムパスワードを用いたログイン認証を構築する時、アカウントに電話番号を関連付けて固定電話番号の制約をつけることでその固定電話番号がある場所にアプリケーションを利用する位置的な制限を設けることも可能です。
Amazon Connectで用いる電話番号の取得は少し手続きが面倒ですがコンタクトフローの作成は簡単でAWS Lambdaなどと連携されることでより複雑な処理もできると思います。
ただAmazon Connectのコンタクトフローはコード化やコンタクトフローのコピーができないので本番／開発で環境分けたい時は目視によるコピー＆ペーストが必要な点が大きなデメリットです。

もしEmailなどを用いた多要素認証が導入できないような環境に直面しましたらAmazon Connectを用いたワンタイムパスワード発行を試してみてはいかがでしょう、本稿がそういった方々の助けになれば嬉しい限りです。
DoD5220.22-M(米国国防総省)方式でハードディスクを削除する

# 背景
Wiki には「2001年にはトップ・シークレット情報を扱った記憶媒体の消去手法としては認定しない旨、決定された。」とありますが、仕様などでまだ求められることもあるので、実施できるようための備忘録として。

# DoD5220.22-M とは
3回上書きを行う削除方法。
3回の内訳は「ある文字」→「その補数」→「ランダムな文字」です。
また、最後に確認が入ります。
今回は「ある文字」を0としますので「その補数」は 0xff となります。

# 実施
今回は VirtualBox 上の Centos8 で検証します。

ディスクもしくは PXE ブートで起動していることを前提として勧めます。
メディアには Centos8 を使用します。
「TroubleShooting」 → 「Rescue a CentOS Linux System」 を選択します。


「3) Skip to Shell」を選択しシェルに入る。
乱数、0の補数のファイルを作成します。

```shell
sh-4.4# dd if=/dev/urandom of=rand.bin bs=1M count=100
sh-4.4# dd if=/dev/zero  bs=1m count=100 | tr "\000" "\377" > 0xff.bin
```
上記で作成したファイルを使用して dd コマンドで埋めていきます。
※0埋めは /dev/zero を使用します。

```shell
sh-4.4# dd if=/dev/zero of=/dev/sda bs=1M
sh-4.4# dd if=./0xff.bin of=/dev/sda bs=1M
sh-4.4# dd if=./rand.bin of=/dev/sda bs=1M
```
簡単にサンタさんからプレゼントをもらう方法

こちらは[コラボフロー Advent Calendar 2022](https://qiita.com/advent-calendar/2022/collaboflow) 20日目の記事です！

------------------
## はじめに
皆さんはサンタさんからプレゼントをもらう方法を知っていますか？
私は知っています。
今回この記事を読んでくれたみんなにそんな夢のような方法をご紹介します。

## プレゼントをもらう方法 :gift: :santa: 
プレゼントをもらう方法は簡単です。


結論から、

<font color="red">**皆さんが大好きな上司に心からお願いすればよいのです**</font>


たったのこれだけです。

なんと革命的なんだ！！！早速上司を捕まえておねだりだ！！
と思いましたが、残念ながらこの日、上司は家族サービスデーで会社を休んでいます。

そんな時に役立つのが、そう、[コラボフロー](https://www.collabo-style.co.jp/)です。
※コラボフローはその場ですぐに申請を出すことができる大変便利なツールです。

そんなコラボフローをカスタマイズ！えいやっ。

![スクリーンショット 2022-12-18 104955.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2952868/792ab5a5-6e06-2af2-9745-6fe1940d9a0e.png)

こんな感じで、特に抵抗感もなく(~~上司~~)**サンタさん**にお願いをすることができます。

「サンタさんからもらいたいもの」は、
コラボフローの[テーブルパーツ](https://collaboflow.zendesk.com/hc/ja/articles/360000403675)で作られているので、
最大5個までお願いできるような仕組み。

![スクリーンショット 2022-12-18 105017.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2952868/268a59d3-27c5-6954-1463-bf182a4c2de6.png)


ちなみにサンタさん目線の申請書はこちら。
![スクリーンショット 2022-12-20 085330.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2952868/20084be0-75c6-2e27-5778-08473d1478c9.png)
こちらはちょっと物足りなさは感じるもののクリスマス仕様で良い感じではないでしょうか？！

こんな感じでちょこっとカスタマイズを加えることで自由度が広がるコラボフロー。
３０日間無料お試しも利用可能。もちろんカスタマイズも可能です。
https://www.collabo-style.co.jp/trial/

## 最後に重大発表！！ :smile: 

いかがだったでしょうか。
ここまでネタ感満載でやってまいりましたが、
今回私はコラボフローの申請書をクリスマス仕様にしてみたのですが、
全部Javascriptで書いていました。（文字の差し替えや色、特定の表示項目を非表示にさせるなど・・）

こんな感じで
```javascript
const wish_for_santa_button = (getById) => {
    const documentButton = document.getElementById(getById);
    documentButton.textContent = "☑サンタさんにお願い事をする"
    documentButton.style.background = "rgb(203 30 58)";
    documentButton.style.color = "white"
}
```

ぶっちゃけ大変です。

**そ・こ・で！！！**

今日この日、コラボフローでアップデートがありました！！（ということは？！）

▼コラボフロー 2.18.17 リリースノート
https://collaboflow.zendesk.com/hc/ja/articles/6076911558159

な、な、なんとコラボフローのフォームに「CSS」がアップロード可能になりました！！！！こりゃすごい。
（それと同時に実装してくれた方、夜遅くにメンテナンスしてくれた方に感謝を・・）
Javascriptで面倒な処理を書かなくても簡単に色味の変化など操れるようになりました :clap: 
ぜひぜひ、使ってみてくださいね！！

明日はウッチーさん（@uchiqiita）！
こちらもお楽しみに(^^)/
re:Invent2022発表された新サービス　AWS Clean Roomsについて調べてみた

# はじめに
この記事は株式会社ナレッジコミュニケーションが運営する クラウドAI by ナレコム Advent Calendar 2022 の 20日目にあたる記事になります。
本記事では、先日実施されたre:Invent2022にて発表された社外組織とのデータ共有や活用を可能とする新サービス「AWS Clean Rooms」について調べました。

# AWS Clean Roomsとは
これまで社外の組織にデータを共有する場合は、当然データそのものにアクセスできるように設定をする必要があり、データの中身を開示する必要がありました。もしくは、特定の項目にマスクを掛けるなどいずれにしても手間がかかっておりました。
今回発表された「AWS Clean Rooms」は、社外にデータを**開示せずに**共有したり、コラボレーションが可能となるそうです。

![4396CE75-BD8F-4533-A51B-8A2CBB7BE73D.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321357/771f5fc9-1ae9-7b17-a6ec-0c3f86451662.png)


# 主な特徴
## 複数の参加者を設定可能
コラボレーションしたいパートナー企業をAWSコンソール上から設定をすることで一回のコラボレーションで最大5社まで設定をすることが可能です。

## AWSの環境以外にデータをコピーすることなく利用が可能
AWSをすでに利用している沢山の企業とAWSの環境上でデータのコラボレーションが可能になります。
これまでの様にAWS以外のところにデータをコピーしたり、データを取り出して共有をするという手間がなく実施できます。

## セキュアな分析環境を実現
顧客がクエリを実行すると、AWS Clean Roomsはデータが存在する場所を読み取り、組み込みの解析ルールを適用して、データの制御を維持できるようにします。また、クエリが処理されている間でもデータを暗号化する高度な暗号化コンピューティングツールを備えています。

## 2つの分析クエリ
AWS Clean Roomsには、2つの実行クエリが備わっており、設定をすることが出来ます。
ListクエリとAggregationクエリが用意されております。
それぞれの違いについて、以下に記載致します。
**List クエリ**
複数のデータセットの交差に関する、行レベルのリストを抽出するクエリを許可
**Aggregationクエリ**
集計の統計を生成するクエリのみを許可


# まとめ
いかがでしょうか。まだプレビュー版で本稼働はまだ先になりますが、この新サービスを利用することで、社外とのコラボレーションがさらに加速して、業界共通の基盤でデータ活用が出来る日も近いかもしれないですね。


参考URL
https://aws.amazon.com/jp/clean-rooms/
ファクトリ関数とは

# ファクトリ関数
シンプルにいうと、オブジェクトを返す関数のこと。
ただ、コンストラクター関数のように`new`キーワードをつけるのではなく、関数そのものがオブジェクトを返す関数のことを意味する。

# ファクトリ関数の特徴
* `new`キーワードを使う必要がない。
* よって関数内で`this`も使う必要もない。

# ファクトリ関数の例
コンストラクター関数をもってオブジェクトを生成する際には以下のようなコードになる。
```javascript:javascript
// コンストラクター関数の書き方
function createCar(maker, carName, year) {
  this.maker = maker,
  this.carName = carName,
  this.year = year
}

const car1 = new createCar(bonda, 'プリアス', 2022)
```

上記のようにいちいち`this`を指定しておき、使う時も`new`キーワードを使わなければならない。
しかし、ファクトリ関数は以下のように表現する。

```javascript:javascript
// ファクトリ関数の書き方
function createCar(maker, carName, year) {
  return {
    maker,
    carName,
    year
  }
}

const car1 = createCar(bonda, 'プリアス', 2022)
```

# ファクトリ関数の利点
### ① 関数内でデータを加工してオブジェクトを返すことができる。
ものによっては受け取った引数をそのまま使わす、加工してからオブジェクトを返したい場合がある。
ファクトリ関数を使うと、これらができる利点がある。
もちろんコンストラクタ関数にメソットを追加して加工することも可能であるが、ファクトリ関数ではメソットを使わずに加工できるので、より簡単でもある。

```javascript:javascript
// コンストラクター関数の書き方
function createCar(maker, carName, year) {
  this.maker = maker,
  this.carName = carName,
  this.year = year
  this.inst = functions() {
    return `この車は、${year}年に${maker}が造った${carName}です。`
}

const car1 = new createCar(bonda, 'プリアス', 2022) 
const inst = car1.inst()
console.log(inst) // この車は、2022年にbondaが造ったプリアスです。
```
ファクトリ関数だと以下のようになる。

```javascript:javascript
// ファクトリ関数の書き方
function createCar(maker, carName, year) {
  return `この車は、${year}年に${maker}が造った${carName}です。`
}

const car1 = createCar(bonda, 'プリアス', 2022)
console.log(car1) // この車は、2022年にbondaが造ったプリアスです。
```

### ② スコープ内の変数を利用することができる。
以下のコードだと、`ceateBook`の関数の外に`pages`の変数があるが、こと関数を実行すると、関数内の`pages`の変数が参照される。
このことによって、関数の外と内の変数を区別して使用することができる。

```javascript:javascript
let pages = 10;
function createBook(title) {
  let pages = 1;

  let read = function() {
        console.log(`${title}を ${pages++} ページ読みました。`);
  };
  return {title, read};
}
```
[Unity]VContainerをとりあえず触ってみたい方へ

# 概要
Zenject(Extenject)と並んで注目されているDIライブラリVContainerを使ってみたので記事にまとめておきます。
# 本文
## 導入
まずUnityで新規プロジェクトを作成して一旦Unityを終了します。
Finder（Windowsならエクスプローラ）からプロジェクトの入ったフォルダを開きます。
プロジェクトフォルダ > Packages > manifest.json
![スクリーンショット 2022-12-20 6.46.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/7e085f61-07c1-3ecd-e294-342157a97936.png)
ファイルの最後の行に1行追加します。バージョンは適宜[公式ページ](https://vcontainer.hadashikick.jp/ja/getting-started/installation)を参考に修正してください。(あと、直前の行のカンマ抜けにご注意を)
```json
"jp.hadashikick.vcontainer" : "https://github.com/hadashiA/VContainer.git?path=VContainer/Assets/VContainer#1.12.0"
```

![スクリーンショット 2022-12-20 6.58.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/bdad212b-bf59-3d25-ee0d-9785df8ddd87.png)

VContainerの前準備ができたのでUnityを改めて起動します。このタイミングでVContainerがインポートされます。
![スクリーンショット 2022-12-19 22.12.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/bab530c4-977c-6384-874c-893a44c72667.png)

## 実装
以下の2つのコードを作成します。

```cs
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using VContainer;
using VContainer.Unity;

// 注入される側
public class GameManager : IStartable
{
    [Inject] private readonly ISampleModel _model;
    
    public void Start()
    {
        _model.PrintLog();
    }
}

// インターフェイス
public interface ISampleModel
{
    void PrintLog();
}

// 注入する側
public class SampleModel : ISampleModel
{
    public void PrintLog()
    {
        Debug.Log("TestMessage");
    }
}
```

```cs
using UnityEngine;
using VContainer;
using VContainer.Unity;

public class GameLifetimeScope : LifetimeScope
{
    protected override void Configure(IContainerBuilder builder)
    {
        // インスタンスを注入するクラスを指定する
        builder.RegisterEntryPoint<GameManager>(Lifetime.Singleton);
        // インスタンスをDIコンテナに登録する
        builder.Register<ISampleModel, SampleModel>(Lifetime.Singleton);
    }
}
```

Hierarchy上に空のオブジェクトを作成してGameLifetimeScopeを貼り付けます。
![スクリーンショット 2022-12-20 8.13.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/1e09e76c-c33a-53c7-11bb-b4ad421266b3.png)


SampleModelのメソッドをGameManagerのStart()で実行することが出来ました。
![スクリーンショット 2022-12-20 8.11.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/4cc689ad-fda5-48fc-ecd6-9e1b0e3b465c.png)

# 補足
こちらの記事を参考にさせていただきました。VContainerをさらに詳しく学びたい方はぜひ！
[【Unity】すごい早いという噂のDIコンテナ「VContainer」を始めて触ってみる](https://www.hanachiru-blog.com/entry/2021/06/03/190000)
ケチケチ自作Arduino基板

以前安上がりに自作したArduino互換基板です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146663/14cf0a91-6922-fe28-3960-453863361db5.png)

裏側

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146663/83a745db-923e-e8cb-e50b-6e8dd031d190.png)

書き込みはCP2102をそのまま横に挿します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146663/d1e9fba8-44a6-3f49-ceb7-376b2e5e1d2c.png)

aitendoのあちゃんでいいのをパクリですね。

https://www.aitendo.com/product/13095

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146663/679abce2-9b78-0d8b-13c2-adfc40e71011.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146663/73149b7d-7ff7-95e0-4007-5a70edba2c70.png)

面付けしたので1枚から10枚取れます（そんなにいらないwwww！）


Arduinoとして普通に書き込んで使用できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146663/0c6f4426-b24f-f74c-9646-8ee73f021be7.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146663/e3a537e6-f421-be0a-8a90-ce44d8008ea3.png)

JLCPCBの送料安いようですし、また頼んでみようかな🤔🤔
作ったの1年前ですがこんな値段でした。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146663/ee47bb34-ab45-3704-8f74-47861f5d78a9.png)


Groveコネクタつけてみてもいいかも、やっぱりピンのシルクを書いておいたらよかったなど。
今考えたら改良したくなってきました笑笑
業務をサボってつよつよプログラマになる方法

# これはなに

プログラマ三大美徳の一つに怠惰があるように、プログラマとは楽する為の努力を惜しまない生き物です。
同時にプログラマは永遠に勉強し続け無ければならない生き物でもあります。
この記事では業務で生まれる無駄な時間を減らし、サボれる時間、勉強出来る時間を増やそうというものになります。
(アイデアが思いついたり、良いコメントがあれば追記します。)

# 便利なツールやサイトを使おう

## ツール(Windows系がメインです。)

### テキストエディタ

恐らくプログラマが触る事になるソフトはテキストエディタでしょう
私の周りだけかは分かりませんが、テキストエディタにあまりこだわりが無い人も多いです。
Vim,Emacs,VScodeなど好きなテキストエディタを見つけて、ガンガンプラグインを導入したり、
設定を自分好みに変えたりして、効率化していきましょう。
テキストエディタのカスタマイズは永遠に終わらない効率化になると思います。

VScodeの拡張機能についての記事は多いですが、あまり紹介されていないものについては以下にまとめました。
[個人的オススメのVScode拡張機能](https://qiita.com/somakai_sumasi/items/e90dcfa9687b3d638f88)

### Tablacus Explorer

Windows用のファイラーになります。
使用感としてはデフォルトのエクスプローラにタブ機能が付いたような感じです。
またプラグインを追加する事で、カスタマイズの幅が広いです。
どのウィンドウでどのフォルダを探さなくて良いのはかなりの時短になるでしょう。
Windos11ではエクスプローラにタブ機能が追加されたらしいですが、
豊富なカスタマイズ性で差別化されていると思います。

### Everything

PC内の全てのフォルダ,ファイルを高速で検索出来るアプリです。
Windowsのエクスプローラの検索は気が遠くなるほど遅いので、
入れておくと何かと役に立ちます。

### Obsidian

Markdownでメモ書きする方におすすめです。
過去に作ったMarkdownを活用出来る点が良いです。
以前、Zennの記事で読ん以来気に入っています。
詳しくは以下を読んだ方が早いと思います。
[Obsidian がすごくいい](https://zenn.dev/usagizmo/articles/beb73159edbe68)

## サイト

### codic

<https://codic.jp/>  
関数名,変数名などを代わりに考えてくれるサイト
APIも提供しており、様々なテキストエディタでプラグインとして利用出来る点も良い。
コードの可読性において命名は非常に重要な要素になるが、
英語力やセンスによって時間がかかる要素になる為、こういうところで手を抜いていきたい

### Notion

<https://www.notion.so/ja-jp>　　
チームで使えるメモサービスだけど一人での利用もかなり便利
一番便利な点として簡易的なDBとして使えるところで、
これにより色んなデータを保存しておける。
またデータを複数の表示に切り替えて見れる点もよい
タイムライン,カレンダーのビューもあるので、スケジュール登録にも使える
またある程度markdown対応している点や公式APIがある点もよい
ブラウザ拡張機能のSave to Notionも活用すると宇宙になる。

# 覚える、調べる量を減らそう

プログラマにとって覚える、調べる量を減らすのは重要な事だと考えます。
複数の言語を触る方であれば、「あれこの言語で○○ってどうやるんだっけ」となる事も多いでしょう。
その度に「Python ○○　やり方」なんて調べるのば馬鹿馬鹿しいです。
この○○が簡単なものであれば良いですが、少し複雑な処理であれば覚えるのも、調べるのも時間がかかるでしょう。

## 見たサイトを全てメモする

上の解決方法として私は調べ物をした際に使ったサイトを全てメモしています。
このようにすれば二回目以降は、メモを見るだけですぐに調べたかった事が分かるでしょう。
このメモの管理が膨大になりますが、私はNotionを使用しています。
上にも書いたブラウザ拡張機能のSave to Notionを使用する事で現在見ているページを保存する事が出来ます。
この詳細については以下のページが参考になると思います。
[Notionでプログラミングノートを作ってみた](https://zenn.dev/ryuu/articles/8f7513d83f05c77d06a3)

あまりWEB上に置きたくないものはObsidianで書いて、ローカルで管理しています。

# 楽して情報を得る

プログラマにとって欠かさずに情報を得る事は重要です。
しかし、常に能動的に情報を得るとなると大変です。

## RSSを活用しよう

皆さんはRSS使っていますか?
RSSと調べるとサジェストに「RSS　衰退」なんて出てきますが、私は使い倒しています。
使い方としては技術系のサイトのRRSフィールドをSlackの個人ページに届くように設定します。
後は出社した際の空き時間やお昼ご飯中などに目を通す。これだけです。
もちろん全部見る必要は無く、気になる記事だけでもいいでしょう。
以下に私が登録しているRSSの一部をご紹介します。

Menthas #all
<https://menthas.com/all/rss>

はてなブックマーク - 人気エントリー - テクノロジー
<https://b.hatena.ne.jp/hotentry/it.rss>

Qiita - 人気の記事
<https://qiita.com/popular-items/feed>

Zennのトレンド
<https://zenn.dev/feed>

一番上に書いたMenthasというサイトは通常に見る分にもおすすめのサイトです。
以下はサイトを作られた方の記事です
[約3年かけてプログラマ向けニュース推薦アプリを作り直した](https://qiita.com/ytanaka/items/6cfad69a4c000c05be40)

# 最後に

長く拙い記事にはなりましたが皆さんのプログラマライフの役に立てれば幸いです。
コメントで他のアイデアを貰えましたら、追記していきますので、どんどんコメントを書いて頂けると助かります。
Arduino UNOにAdafruit GFXをインストール



目的
カラーOLEDのテスト


1.スケッチ
2.ライブラリ
3.ライブラリを
4.gfxを検索
5.Adafruit GFXを選択


![o_cop253.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/4234b13f-6a4e-2086-946f-ca26566f179e.jpeg)


![o_cop255.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/e2631730-43ba-6e5d-4bae-3af7401f374a.jpeg)
PICO4を有線でVirtualDesktop接続

# 概要
PICO4をPCとUSBケーブルで有線接続した状態で、VirtualDesktopを使用する方法のメモ。

PICO4をPCと接続した際に、ADBでRNDIS機能を有効化することでWifiを介さずにUSB経由で直接通信させます。

私の環境では、ネットワークで12ms程度遅延してたまにスパイクが発生していたのが、2ms程度で安定するようになりました。

正規にサポートされている方法ではないので自己責任で。

もっとこうした方がいいよって情報がありましたら連絡お願いします。

## 参考
https://www.youtube.com/watch?v=XxxweFVNyR0

上記から、RNDISを有効化するコマンドは変更しています。


# 方法
## adbをインストール
https://developer.android.com/studio/command-line/adb?hl=ja

Android Studioをインストールしても良いし、adbのみ使いたいならスタンドアロン版のAndroid SDK Platform-Toolsでも良い。

## PICO4のUSBデバッグモードを有効化
1．PICO4にて、`設定 > 一般 > デバイス情報 > ソフトウェアバージョン`を7回クリック。
1. 開発者タブが追加されているので、USBデバッグが有効になっていなければ有効化

## ADBを使ってRNDISを有効化
1．PICO4をUSBケーブルでPCに接続
2. インストールしたadbを用いてRNDISを有効化

コマンドプロンプトにて、
```
adb shell svc usb setFunctions rndis
```

RNDISを無効化したければsetFunctionsを引数無しで実行。
```
adb shell svc usb setFunctions
```

バッチファイルにしておくのをおすすめ。

## ネットワークアダプターのMetricを調整
PICO4を介してインターネットアクセスすると遅くなるのでアダプターのMetricを調整する。

コマンドプロンプトにて
```
route print
```
を実行すると、IPv4 ルート テーブルにてネットワークアダプタのメトリックを確認することができる。
普段使っているネットワークアダプタのメトリックをPICO4のアダプタのメトリックよりも小さく設定する。

Windowsの`設定 > ネットワークとインターネット > アダプターのオプションを変更する`でネットワークアダプタの一覧を表示する。

普段使っているネットワークアダプタを右クリックし、プロパティを開く。

インターネットプロトコルバージョン4(TCP/IPv4)のプロパティを開き、詳細設定から自動メトリックのチェックを外してメトリックを設定。
(IPv6もやった方がいいのかな...?)

## 注意
一度USB接続を解除すると、RNDISは無効化された状態となってしまいます。
PCに接続する度に有効化してください。

RNDISが無効な状態でVirtual Desktop接続がされると、一度Virtual Desktopを終了しないとUSB経由で通信してくれないようです。
Arduino UNOにAdafruit SSD1331をインストール


目的
カラーOLEDのテスト

1.スケッチ
2.ライブラリ
3.ライブラリを
4.ssd1331を検索
5.Adafruit SSD1331を選択


![o_cop253.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/15a519e6-bd9d-af97-8221-45bec3525c8e.jpeg)


![o_cop254.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/fd4cc17f-e77c-6f03-a0c2-e4280a6a254d.jpeg)
自分の担当する開発工程がわからなったからまとめる


# はじめに
アジャイル型とウォーターフォール型が混合した開発体制の案件で働いているとき、自分の担当工程がわからなくなりました。
特に基本設計と要件定義の境界がよくわからないため、記事にしました。

※Web系バックエンド業務を主軸としてまとめます。フロントや組み込み系、業務系では意味合いが異なるかもしれません。

※基本情報技術者などの資格勉強している方は本記事を参考にしないことを推奨します。

# 私がやっていたこと
```
①口頭指示(要求定義の原案)
↓
②画面遷移図を提供
↓
③お客様が画面遷移図の確定版を作成
↓
④画面及びAPIの作成(要件定義？～製造)
↓
⑤単体テスト
↓
以下省略
```

④⑤の作業中に新しい要求定義が追加されて、
それに対する要件定義？～製造も担当してました。

本記事では作業④について考えます。

# 一般的な開発工程
https://webrage.jp/techblog/v_shaped_mode/
システムの開発工程について、上記のV字モデルが有名です。
作業④は要件定義～基本設計に該当します。
そのため、要件定義と基本設計について考えます。

# 要件定義と基本設計の境界
### 要件定義とは
https://backlog.com/ja/blog/what-is-project-requirements-definition/#1%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E3%81%AE%E6%A6%82%E8%A6%81
https://www.pasonatech.co.jp/workstyle/column/detail.html?p=8451

上記二つを参考にすると要件定義では
* システム要件
* 機能要件
* 非機能要件
* セキュリティ
* ユーザビリティ
* 性能
* 実行計画（工数管理など）

を決めるようです。

私が作業④で担当したことは、
* 機能要件
* ユーザビリティ

でした。
セキュリティや性能について、常識の範囲（SQLインジェクション防止など）は意識してましたが、ドキュメントは作りませんでした。
システム要件はインフラの方、実行計画はリーダーが担当してました。

そのため、私は「要件定義の一部を作業していた」という表現が正しいようです。




### 基本設計とは
https://tech.hipro-job.jp/column/2478#%E3%81%A9%E3%81%93%E3%81%BE%E3%81%A7%E3%81%8C%E5%9F%BA%E6%9C%AC%E8%A8%AD%E8%A8%88%EF%BC%9F
https://rekaizen.com/article/detail/business-system/1091
上記二つを参考にすると基本設計では
* 機能一覧表
* 業務フロー図
* データフロー図
* システム機能設計
* 画面設計
* テーブル設計
* インターフェース設計

などを決めるようです。

私が作業④で担当したことは
* システム機能設計
* 画面設計

でした。
規模が小さいため上記作業だけで基本設計としては十分でした。

# まとめ
私は「要件定義と基本設計の一部を実施した」という表現が正しいようです。
しかし、アジャイル開発の観点から考えると、私が担当した作業が要件定義と言える気がします。

# 余談
ウォーターフォール型とアジャイル型を混合した開発体制と称すれば聞こえはいいですが、実情はタスク管理をせずに指示がチャットで入り乱れる案件でした。。
マネジメント体制はよろしくないですが、要求定義から構想を練るという大事な経験にはなりました。
Node.jsでMailgunを使ってメールを送信する

[Next.js + サーバーサイドTypeScript + 関数フレーバーでクリーンなアプリを作ったので実装意図とか書く Advent Calendar 2022](https://qiita.com/advent-calendar/2022/shwld)
の**20日目**。[株式会社mofmof](https://www.mof-mof.co.jp/)に生息している[shwld](https://twitter.com/shwld)です。

前日は[VitestでGraphQLとReactをテストするための環境づくり](https://qiita.com/shwld/items/312d10c3cad13cbdb14e)について書きました
# Node.jsでMailgunを使ってメールを送信する

```ts:/infrastructures/mailer/src/index.ts
import ky from 'ky';
import FormData from 'form-data';
import type { Mailer as MailerType, MailSendResult } from 'domain-interfaces';
import { Result, RuntimeError, tryCatch } from 'core-domain/src/shared';

const API_KEY = process.env.MAILGUN_API_KEY as string;
const MAILGUN_DOMAIN = process.env.MAILGUN_DOMAIN as string;

export const createMailer = (): MailerType => {
  const mailer: MailerType = {
    send(mail): Result<RuntimeError, MailSendResult> {
      const result = tryCatch(
        async () => {
          const data = new FormData();
          data.append('from', mail.from);
          data.append('to', mail.to);
          data.append('subject', mail.subject);
          data.append('html', mail.body);

          const response = await ky
            .post(`https://api.mailgun.net/v3/${MAILGUN_DOMAIN}/messages`, {
              headers: {
                Authorization: `Basic ${Buffer.from(`api:${API_KEY}`).toString(
                  'base64'
                )}`,
              },
              // @ts-ignore FIXME: error TS2322: Type 'FormData' is not assignable to type 'BodyInit | null | undefined'.
              body: data,
            })
            .json();
          const result = JSON.stringify(response);

          return {
            body: result,
          };
        },
        () => {
          return new RuntimeError('Mail Sender Error');
        }
      );

      return result;
    },
  };

  return mailer;
};
```
[https://github.com/shwld/uzumaki/blob/advent-calendar/infrastructures/mailer/src/index.ts](https://github.com/shwld/uzumaki/blob/advent-calendar/infrastructures/mailer/src/index.ts)

```ts
const mailer = createMailer()
mailer.send({
  from: 'from@example.com';
  to: 'to@example.com';
  subject: '懸命に賢明な件名';
  body: 'ボディ';
})
```

## npmパッケージを使わない理由
[npm: mailgun.js](https://www.npmjs.com/package/mailgun.js) というのがあるんですがなぜ使わなかったのか。
謎です（覚えてない）

turbopackでのバンドルが理由だった気がしますが...
謎です。

# 次回予告
明日は、[GraphQL Subscription](https://qiita.com/shwld/items/5ad8304683b3cd18e0e0)について書きます。
firestoreでmapを使ったフィールドにarrayUnionする方法

こんにちは。[virapture株式会社](https://virapture.com)でCEOしながら[ラグナロク株式会社](https://ragna-rock.com)でもCKOとして働いている[@mogmet](https://twitter.com/mogmet)です。

本日はfirestoreのtips投稿になります。

## Map型のフィールド内にある配列に値を追加したい！

そんな要望ありませんか？私はありました。
たとえばチャットの未読を管理するためにchatRoomドキュメントのunreadMapフィールドに下記のようなデータを保管していたとします。

```json
"unreadMap": {
  "userIdA": [
    "chatIdA"
  ],
  "userIdB": [
    "chatIdB"
  ]
}
```

ここにuserIdAの配列にchatIdCを追加しようとこう書くとします。

```ts
firestore.collection('chatRooms').doc('chatRoomIdA').update({
  unreadMap: {
    userIdA: admin.firestore.FieldValue.arrayUnion('chatIdC')
  }
})
```

そうすると何が起こるかというと、userIdAの値しか残らなくなります！

```json
"unreadMap": {
  "userIdA": [
    "chatIdC"
  ],
}
```
しかも前にあった値も上書きされて全然arrayUnionじゃないです。ただのupdate。

## 解決法

答えは下記で解説されていました。

https://stackoverflow.com/questions/54190855/how-update-an-array-in-a-map-using-arrayunion

mapの奥の値までkeyを指定すればよかったみたいです。

```ts
firestore.collection('chatRooms').doc('chatRoomIdA').update({
  'unreadMap.userIdA': admin.firestore.FieldValue.arrayUnion('chatIdC')
})
```

これで無事arrayUnionできました。

## まとめ

mapを使うときは.を使ったキーの指定でupdateしていきましょう。

最後に、[ワンナイト人狼オンライン](https://online.1nite-jinro.com/link/blog)というゲームを作ってます！よかったら遊んでね！

https://online.1nite-jinro.com/link/blog

他にも[Camecon](https://camecon.me/)や[Offcha](https://offcha.com/)、問い合わせ対応が簡単にできる[CSmart](https://csmart.jp/lp)、フリーランスのコミュニティの[NextFreelance](https://next-freelance.net/)といったサービスも作ってるのでよかったら使ってね！

https://camecon.me/

https://offcha.com/

https://csmart.jp/lp

https://next-freelance.net/

また、チームビルディングや技術顧問、Firebaseの設計やアドバイスといったお話も受け付けてますので御用の方は弊社までお問い合わせください。

https://virapture.com/

ラグナロクでもエンジニアやデザイナーのメンバーを募集しています！！楽しくぶち上げたい人はぜひお話ししましょう！！

https://ragna-rock.com
【完走賞ゲット-20】JavaScript の addEventListener で複数イベントを一度に追加する話（p5.js Web Editor上で Joy-Con と gamecontroller.js を用いた処理で利用）

## はじめに
こちらは、[完走賞ゲットのため小ネタを毎日投稿しようとチャレンジする Advent Calendar 2022](https://qiita.com/advent-calendar/2022/youtoy) の 20日目の記事です。

この記事の内容は、JavaScript の [addEventListener](https://developer.mozilla.org/ja/docs/Web/API/EventTarget/addEventListener) で複数イベントを一度に追加する話です。この記事の内容をやろうと思ったきっかけは、以下の内容の一部が関係しています。

●【完走賞ゲット-11】gamecontroller.js を p5.js Web Editor上で使ってみる（DualShock 4 との組み合わせ） - Qiita
　https://qiita.com/youtoy/items/1cf1fe244d992456140f

具体的には、gamecontroller.js を使う処理の中で、利用するコントローラーのボタン 1つに対して 1つ以上の EventListener を登録する感じに見える部分がありました。その部分の処理を多数のボタンに対応させようとすると、addEventListener の処理部分が面倒なことになりそうと思い、それに対して良い対処法はないかと思ったことです。

https://twitter.com/youtoy/status/1602407963356172291

## 調べて出てきた内容
そして、検索して出てきた記事などの情報で、以下が気になりました。

●【JavaScript】addEventListenerで複数イベントを一度に追加する賢い方法 | PisukeCode - Web開発まとめ
　https://pisuke-code.com/js-addeventlistener-multi-events/
![addEventListenerで複数イベントを一度に追加する賢い方法](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/4d849a31-a3b5-4d6a-1d6a-cec32c16d085.png)

gamecontroller.js を用いた処理でも、上記を参考にした処理を使ってみることにしました。

## 今回使うコントローラー
上で掲載していた Qiita の記事では、DualShock 4 を使っていましたが、今回は Joy-Con を使います。

まずは、Joy-Con を PC とペアリングし、以下のサイトで、Gamepad API で反応するイベントを調べ、今回試すボタンを選びます。

https://twitter.com/youtoy/status/1601361942098350080

とりあえず、以下のボタン 6つを使ってみることにしました。

```javascript
  "button0", // A
  "button1", // X
  "button2", // B
  "button3", // Y
  "button7", // R
  "button8", // ZR
```

## 自分が試した処理の内容
上記の記事の情報を元に、EventListener の処理をまとめて行う方法を、p5.js　Web Editor上で Joy-Con と gamecontroller.js を組み合わせた内容で試してみました。
具体的には、以下のようなプログラムを作りました。

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.5.0/p5.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/gamecontroller.js@1.5.0/dist/gamecontroller.min.js"></script>
    <link rel="stylesheet" type="text/css" href="style.css" />
    <meta charset="utf-8" />
  </head>
  <body>
    <main></main>
    <script src="sketch.js"></script>
  </body>
</html>
```

```javascript
const buttonList = [
  "button0", // A
  "button1", // X
  "button2", // B
  "button3", // Y
  "button7", // R
  "button8", // ZR
];

function setup() {
  createCanvas(400, 400);

  gameControl.on("connect", (gamepad) => {
    console.log("A new gamepad was connected!");

    buttonList.forEach((elem) => {
      gamepad.before(elem, () => {
        console.log(`${elem} pressed...`);
      });
    });
  });
}

function draw() {
  background(220);
}
```

そして、ログ出力を見てみると、Joy-Con上の 6つのボタンを押した際、意図した出力が得られているのを確認できました。
![ログ出力](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/3aec48c4-c68e-f4ff-0eee-87747ee4dd8b.png)