OmniAICreator/Qiita-1.07M huggingface dataset:
VSCodeでPoetryのプロジェクトをデバッグする方法

# 概要
Poetryを使ってデバッグするときの初期構築に手間取ったので手順を載せておきます。

# launcher.jsonの作成
例えば以下のプロジェクト内の`skybrush-server/src/flockwave/server/launcher.py`をデバッグしたいとします。
```
skybrush-server
├─.venv
├─.vscode
├─doc
├─etc
├─src
│  └─flockwave
│      ├─gateway
│      ├─proxy
│      └─server
│          ├─command_handlers
│          ├─ext
│          ├─middleware
│          ├─model
│          ├─registries
│          ├─show
│          ├─tasks
│          ├─utils
│          ├─launcher.py
│          └─__pycache__
├─.dockerignore
├─.gitattributes
├─.gitignore
├─.pre-commit-config.yaml
├─CHANGELOG.md
├─LICENSE.txt
├─poetry.lock
├─poetry.toml
├─pyproject.toml
├─pytest.ini
├─README.md
├─tbump.toml
├─tox.ini
└─test
    └─fixtures
```

その場合**skybrush-server直下**で下記の手順を実施します。
1. デバッグ実行画面からlaunch.jsonファイルを作成する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2584877/87c89f5b-5f6d-4fae-6953-778ad90b55d5.png)

2. launch.jsonファイルの設定に下記を入力します。

```
{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "flockwave",
            "type": "python",
            "request": "launch",
            "cwd": "${workspaceFolder}",
            "module": "flockwave.server.launcher",
            "args": []
        }
    ]
}
```

# settings.jsonの作成
このままだとpoetryの仮想環境が読み込めなかったので、`settings.json`を設定して自動で読み込むようにします。

1.Poetryのプロジェクトフォルダ内で以下のコマンドを実行し、仮想環境があるパスを取得します。

```
poetry config virtualenvs.path
```

2.コマンドパレットから`Open Workspace Settings(JSON)`を起動します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2584877/c4d48ad6-3d09-2ec8-aeaa-f81391bcc453.png)


3.仮想環境の設定を行います。
```settings.json
{
    "python.pythonPath": 取得したパス
}
```

# 実行
実行ボタンを押して完了です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2584877/10c26f38-51bc-c2c6-1a2f-03b0c032c553.png)

↓ターミナルの表示の例
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2584877/90fdbaa8-9599-aa70-9833-7064badc6daa.png)
Go言語でConfigファイルをビルド時に埋め込む方法: embedパッケージの活用

## はじめに

Go言語の強みの一つにポータブル性があります。
Go言語はビルドをするとシングルバイナリになるため、ビルドしたバイナリをコンテナやらサーバーに持ち運ぶだけで簡単に実行できます。

多くのアプリケーションでは設定情報などをコンフィグファイルとして外出ししている場合がありますが、そのような場合はビルドしたバイナリファイルはコンフィグファイルに依存してしまって、デプロイ時にコンフィグファイルも一緒に持ち運ぶ必要が出てきます。

しかし[go:embed](https://pkg.go.dev/embed)を使うことでコンフィグファイルもビルド時にバイナリに含めることができてしまうのです!

## 前提

- go1.16以上

## ディレクトリ構成

```plantuml
@startuml
salt
{
  {T
   + demo
   ++ config
   +++ config.go
   +++ config.json
   ++ go.mod
   ++ main.go
  }
}
@enduml
```

プロジェクト全体を見たい人はGitHubに公開していますので[そちらをご覧ください](https://github.com/gracefulm/go-config-example-with-embed)。

## コンフィグファイルの埋め込み方法

```json:config/config.jsoon
{
  "logLevel": "DEBUG",
  "server": {
    "host": "localhost",
    "port": 8080
  }
}
```

今回はこのようなJSON形式の設定ファイルをバイト配列型の変数`rawConfig`に埋め込みます。

`embed`パッケージをブランクインポートして、埋め込みたい変数に`go:embed <ファイル名>`とコメントをするだけでファイルをバイナリとして埋め込むことができます。

```go
import _ "embed"

//go:embed config.json
var rawConfig []byte
```

これでビルド時に`rawConfig`に`config.json`の中身が反映されます。

### 構造体に変換する

せっかくなので、埋め込んだJSONを構造体に変換して表示するところまでやってみましょう。

```go:config/config.go
package config

import (
	_ "embed"
	"encoding/json"
	"log"
)

//go:embed config.json
var rawConfig []byte

type Config struct {
	LogLevel string       `json:"logLevel"`
	Server   ServerConfig `json:"server"`
}

type ServerConfig struct {
	Host string `json:"host"`
	Port uint   `json:"port"`
}

func (cfg Config) String() string {
	m, err := json.Marshal(cfg)
	if err != nil {
		log.Fatalln(err)
	}

	return string(m)
}

func Load() (Config, error) {
	cfg := new(Config)
	if err := json.Unmarshal(rawConfig, cfg); err != nil {
		return Config{}, err
	}

	return *cfg, nil
}
```

`rawConfig`はJSON形式のデータなので`json.Unmarshal()`を使って構造体に変換できます。

`String()`メソッドは読み込んだ`Config`を表示する際に見やすくするために[Stringer Interface](https://go.dev/tour/methods/17)を実装しているだけなので気にしなくてOKです。

`config.go`の実装が終わったら、実際に出力してみましょう。

```go:main.go
package main

import (
	"demo/config"
	"log"
)

func main() {
	cfg, err := config.Load()
	if err != nil {
		log.Fatalln(err)
	}
	log.Printf("config=%s", cfg)
}
```

### 動作確認

以下のコマンドでビルドすると、`./build/show-config`というバイナリが生成されます。

```sh
$ go build -o ./build/show-config ./main.go
```

生成されたバイナリを実行するとちゃんと`config.json`の内容が反映されていることがわかります。

```sh
$ ./build/show-config
2023/10/14 15:53:42 config={"logLevel":"DEBUG","server":{"host":"localhost","port":8080}}
```

## さいごに

go:embedを活用して設定ファイルをビルド時のバイナリに含める方法を紹介しました。
今回はJSONを例に紹介しましたが、サードパーティのパッケージを使えばYAMLで記述された設定ファイルも同様に扱えると思います。

今回の記事が少しでも参考になれば幸いです。
機械学習用の画像のデータレイクを作る

機械学習用のデータの撮影・保存についてリモートストレージにデータを保存する自作のツールを作ったので概略の考え方を示す。

## 理由
- 学習用画像を選択してアノテーションをすることとは別に、撮影したデータにユニークな名前を付けて保存しておきたい。
- データは、リモートストレージに置きたい。
- リモートストレージにおいてあるデータの要約を簡単に知りたい。


## 持つべき機能
```
  --uniq                
    撮影した時点でユニークな名前になっていない場合に、ユニークな名前に変更する。
  --show_local        
    ローカルデータのディレクトリを示す。
  --show                
    リモートストレージにおいてあるディレクトリを示す。
  --push ローカルデータのディレクトリ          
    ローカルデータのディレクトリ　をリモートストレージにコピーする。
  --safe_remove ローカルデータのディレクトリ
    リモートストレージに該当のデータがあることを確認して、ローカルデータのディレクトリを削除する。
  --get 該当のシーンのフォルダ
    リモートストレージの該当のシーンのフォルダをローカルにコピーする。
```

## 実装上留意したこと
- クライアントのPCの側に全てのデータをコピーしてしまうなどの、大量のディスクスペースを使う方式にしてはならない。
- バージョン管理をしない。
- データはリモートストレージに追加するだけであって、改変もしないし、削除もしない。
- そのような単純さを持ち込むことで、管理を楽にする。
- フォルダのデータの特徴を知る手段を提供すること

## 画像データの場合
- フォルダにある画像の要約を、ランダムに選択した画像を時系列順序で縮小して並べて表示する。（ちょうどネガフィルムの小さなまま表示する。）
- そうすることで、そのデータの時系列を見やすくする。


## 手作業でcsvファイルを作らない。
- データがどこに何があるかをcsvファイルを主体として手作業で作成するのはやめよう。
- どうせ、どこかでメンテナンスされなくなるんだ。


## データレイク・データウェアハウスなどを説明している書籍の例
[ビッグデータ分析の　システムと開発がこれ1冊でしっかりわかる教科書](https://gihyo.jp/book/2019/978-4-297-10881-6)

 個人単位で機械学習をしてきたエンジニアの場合、ビッグデータの扱いに不慣れな場合があります。
 いま扱おうとするデータが大量にあって、今後とも組織で引き継ぎをしていく必要があれば、
 データの管理に対してもっと労力をさく必要を生じます。
【ExcelVBA】別シートへの代入時エラーについて（親オブジェクト省略の落とし穴）


ExcelVBA初心者がつまづきがちな「**別のシートへの代入時エラー**」について、エラーコード例を交えて解説します。（本稿掲載の各コードは同じ処理の書き換えです）

```vb
Sub 非アクティブシートへの代入時エラー例()
    Dim 配列()
    Sheet1.Activate
    配列 = Range(Cells(1, 1), Cells(5, 5))
    Sheet2.Range(Cells(1, 1), Cells(5, 5)) = 配列
End Sub
```
↑のサンプルコードは、実行すると`Sheet2.Range(Cells(1, 1), Cells(5, 5)) = 配列`の行が原因で実行時エラーが発生します。

このコードは「`Sheet1`のセル範囲の値を動的配列に格納し、`Sheet2`のセル範囲に代入する」という意図のものですが、問題の箇所では**Cellsの親オブジェクトが省略**されています。
これにより、OSは**Cellsの親オブジェクトをActiveSheet(= Sheet1)だと認識する**ため、
**Cellsとその入れ子先であるRangeで親オブジェクトが異なる状態になってしまう**ことがエラーの原因です。

問題の箇所はOS側には↓のように認識されています。
`Sheet2.Range(ActiveSheet.Cells(1, 1), ActiveSheet.Cells(5, 5)) = 配列`
※例えるなら「目的地は千葉県にある東京都千葉市」というような誤ったコーディングとなっています。


このコードを正常に動作するよう修正すると、
```vb
Sub 非アクティブシートへの代入()
    Dim 配列()
    Sheet1.Activate
    配列 = Range(Cells(1, 1), Cells(5, 5))
    Range(Sheet2.Cells(1, 1), Sheet2.Cells(5, 5)) = 配列
End Sub
```
となります。

Rangeの親オブジェクトを省略しているので、OS側に
`ActiveSheet.Range(Sheet2.Cells(1, 1), Sheet2.Cells(5, 5)) = 配列`
のように認識されてしまいそうな所ですが、
入れ子構造は内部から順に特定されていく(`Cells`を特定 → `Cells`が入れ子された`Range`を特定の順)ため、問題は生じない模様です。(`Sheet2.Cells`の入れ子によって表現される`Range` → `Sheet2`が親オブジェクトだと認識される)

なお、実際のコーディングでは「With構文による親オブジェクト記述の省略」を用いると、「どのシートで何をしているか」が明白になり、可読性が上がりエラー防止にも繋がります。
```vb
Sub 別シートへの代入()
    Dim 配列()
    With Sheet1
        配列 = Range(.Cells(1, 1), .Cells(5, 5))
    End With
    With Sheet2
        Range(.Cells(1, 1), .Cells(5, 5)) = 配列
    End With
End Sub
```
※`Sheet1.Activate`は代入動作上不要になるので削除しました。

なお、「別のシートへの代入」には`Resize`を使ったやり方もあります。
```vb
Sub Resizeによる別解()
    Dim 配列()
    With Sheet1
        配列 = Range(.Cells(1, 1), .Cells(5, 5))
    End With
    With Sheet2
        .Cells(1, 1).Resize(5, 5) = 配列
    End With
End Sub
```
どちらを採用するかはケースバイケースですが、  
慣れるとResizeの方が楽かもしれません。
GitHub Actionsにおけるpull_requestイベントのアクティビティの種類

## 概要

この記事では、GitHub Actions におけるワークフロートリガーイベントのひとつである `pull_request` のアクティビティ（ワークフローの発火条件）について説明します。

## 対象読者

- GitHub で Pull Request に対する操作を条件に GitHub Actions を動かしたい人

## 17種類のアクティビティ

`pull_request` に用意されているアクティビティは下記17種類です。

| アクティビティ | 概要 |
|:--|:--|
| `assigned` | ユーザーが Pull Request に割り当てられたとき |
| `unassigned` | ユーザーが Pull Request の Assign から外されたとき |
| `labeled` | Pull Request にラベルが登録されたとき |
| `unlabeled` | Pull Request からラベルが削除されたとき |
| `opened` | Pull Request が作られたとき（Draftを含む） |
| `edited` | Pull Request のタイトル・本文・ベースブランチが変更されたとき（Draftを含む） |
| `closed` | Pull Request が Close されたとき（マージも含む） |
| `reopened` | Pull Request が Close された状態から再度 Open になったとき |
| `synchronize` | Pull Request にコミットが追加されたとき |
| `converted_to_draft` | Pull Request が Draft になったとき（Draft で作成したときも含む） |
| `ready_for_review` | Pull Request が Draft から Open になったとき |
| `locked` | Pull Request がロックされたとき |
| `unlocked` | Pull Request のロックが解除されたとき |
| `review_requested` | ユーザーにレビューがリクエストされたとき |
| `review_request_removed` | ユーザーがレビューリクエストから削除されたとき |
| `auto_merge_enabled` | Pull Request の自動マージが有効になったとき |
| `auto_merge_disabled` | Pull Request の自動マージが無効になったとき |

## まとめ

GitHub Actions のワークフロートリガーイベント `pull_request` に用意されているアクティビティ17種類をご紹介しました。  
Pull Request にまつわる GitHub Actions を作成する際にお役に立てれば幸いです。

間違いがあればコメントまたは編集リクエストをください。

## 参考

- [ワークフローをトリガーするイベント - GitHub Docs > pull_request](https://docs.github.com/ja/actions/using-workflows/events-that-trigger-workflows#pull_request)
- [Github Actions: a deep dive into pull_request](https://frontside.com/blog/2020-05-26-github-actions-pull_request/)
初心者が初心者に教える初心者のためのGitHub3

# はじめに
こんにちは。今の会社に転職してから早2週間が経ちました。サイトの画面修正を行った後にプッシュしておいてと言われたので、良く分からないままプッシュしたら見事にコンフリクトしました(爆)
なので今回はマージやらなんやらを勉強してきました。

# ブランチとはなんぞ
そもそもブランチってなんやねんという感じだと思います。GitやらGitHubをコマンドラインで操作している時にディレクトリの横に下の写真の赤線で引いてるようなものがいると思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3553857/06a47789-b078-72eb-702c-58941e649b62.png)
これがいわゆるmainブランチというもので基本的にブランチを作らなければmainブランチで作業をしていくと思います。

# 別のブランチで作業してみる
さっそく別のブランチを作成していこうと思います。まずは二つのファイルを作成してコミットしていきます。
~~~html:hello.html
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8" />
        <title>ハロー</title>
    </head>
    <body>
        <h1 style="color: red">こんにちは</h1>
    </body>
</html>
~~~
~~~html:company
<!DOCTYPE html>
<html>
    <head>
        <title>会社</title>
        <meta charset="UTF-8" />
    </head>
    <body>
        <h1>会社概要</h1>
    </body>
</html>
~~~
~~~
$ git add hello.html
$ git commit -m "hello commit"
$ git add company.html
$ git commit -m "company commit"
~~~

これで二つのコミットログが出来ました。
次に新しいsubブランチを作成していきましょう。先ほどの画像でも確認できる通り現在のブランチはmainブランチだけとなっています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3553857/533fc295-5321-b2c1-4dee-1da99bd2ea5e.png)
上記の画像のように、mainブランチからsubブランチに切り替わり、mainブランチの内容も持ってきているのがわかります(git.pyという余計なファイルがあるのは気にしないでください)。

ブランチの作成に関しては二通りの方法があるのですが、
~~~
$ git branch sub
$ git checkout sub
### これはbranchコマンドでsubブランチを作ってから、checkoutでブランチを移動するやり方です

$ git checkout -b sub
###　こっちは上記の画像のやり方で、ブランチの移動とブランチの作成を同時に行っています。
~~~

ここでsubブランチにnew-hello.htmlというファイルを作成してコミットしておきます。logは下記の通りになります
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3553857/51d85166-3b95-0b9b-6f30-2fdc81045c6b.png)



もう一度mainブランチに戻ってhelloファイルを変更してからコミットする作業を行います。(ファイル変更は事前にテキストエディタで行っています）
その際のログを表示させると、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3553857/4f122870-005b-88fc-f6a2-6c31d53ec350.png)
このようにsubブランチでコミットしたものは枝分かれしているのがわかります。(logのオプションで--all --graphとするとこのように分かりやすく表示されます)

# 最後にマージしてみる
では最後にこの二つのブランチをマージしましょう。下記のコマンドでマージします。
~~~
$ git merge sub --no-edit
~~~
するとマージされた旨のメッセージが出るのでそのあとにlogを確認すると、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3553857/3b717274-57f1-d0e4-cb13-0010308e82ff.png)

lsで見るとmainブランチにsubブランチで作成した、new-hello.htmlが入っているのが確認できます。
logでもグラフでマージされてるのが視覚的に分かりますね。

# 感想
最初にコンフリクトしたと嘆いていたのに、コンフリクトに関しては何も書いてない記事になってしまいました(反省します)
コンフリクトしたときの対処は次の記事で書きたいと思います。ではでは。
テスト105

```vb
Public Sub CellNum_Check()

Dim i As Long
Dim j As Long
Dim sh As Worksheet
Dim Last_Row As Long
Dim Last_Col As Long

Set sh = ThisWorkbook.Sheets("入力表")

'(･ω･)<メモです！

With sh

    Last_Row = .Cells(Rows.Count, "B").End(xlUp).Row
    Last_Col = .Cells(2, Columns.Count).End(xlToLeft).Column
    
    For j = 3 To Last_Col   '列方向
    
        For i = 3 To Last_Row    '行方向
            
            If .Cells(2, j).Value = "列" Then

                 '列のアルファベットのチェック
                If Trim(.Cells(i, j)) Like "*[A-ZＡ-Ｚ]*" Then

                    On Error Resume Next
                    
                    .Cells(1, Trim(.Cells(i, j))).Value = 1
                    
                    If Err.Number <> 0 Then
                    
                        MsgBox .Name & "シートの" & Replace(.Cells(i, j).Address, "$", "") & "セルの値が列の正しいアルファベットではありません。確認をお願いします。" _
                        , vbCritical, "中止"
    '                    End
                    
                    End If
                    
                    On Error GoTo 0
                    
                Else
                
                    MsgBox .Name & "シートの" & Replace(.Cells(i, j).Address, "$", "") & "セルの値が列の正しいアルファベットではありません。確認をお願いします。", _
                    , vbCritical, "中止"
'                    End
                    
                End If
        
            ElseIf .Cells(2, j).Value = "セル" Then
                'セル番地のチェック
                .Range("A1").Formula = "=ISREF(" & .Cells(i, j).Value & ")"
                
                If .Range("A1").Text <> "TRUE" Then
    
                    MsgBox .Name & "シートの" & Replace(.Cells(i, j).Address, "$", "") & "セルの値が正しいセル番地ではありません。確認をお願いします。" _
                    , vbCritical, "中止"
'                    End
                    
                End If

            End If
        
        Next i
    
    Next j

End With

End Sub
ドブル (Dobble / Spot it!) 自作 (3): 生成ツールの紹介

## はじめに

ボードゲーム [ドブル](https://amzn.to/45XW20t) (Dobble / Spot it!) を Python 実装した **[dobble-maker][dobble-maker]** の解説です。

https://github.com/youce23/dobble-maker

本記事では、実際に画像ファイルから印刷用PDFを作る**生成ツールの紹介**をします。

- [ドブルデッキの構築][art1]
  - 任意の 2 枚のカードを選んだ時に、必ず共通するシンボルが 1 つだけ存在するような組み合わせを決定する
- [カード内でのシンボルのレイアウト][art2]
  - シンボル間の重なり無く、程よくランダムに配置する
- **生成ツールの紹介**
  - 画像ファイルから印刷用 PDF まで生成するツールの紹介
  - **仕組みはいいから作りたい！** という方はこちらです
- [2 枚に 2 つのシンボルが共通するデッキ][art4]
  - 通常ドブルとは異なる特性を持ったデッキを作ります
- [3 枚に 1 つのシンボルが共通するデッキ][art5]
  - また別の特性を持つデッキです
- [派生版のアイデア帖][art6]
  - デッキの解釈を変えて新しいデッキについて考えてみます

[dobble-maker]: https://github.com/youce23/dobble-maker
[art1]: https://qiita.com/youce/items/e67b0bf50d955a98c70e
[art2]: https://qiita.com/youce/items/0cf902357b183500fb45
[art3]: https://qiita.com/youce/items/8cb30104759c1fe5f10f
[art4]: https://qiita.com/youce/items/aebd114ab01a8d0d4292
[art5]: https://qiita.com/youce/items/96497bcf5db616268685
[art6]: https://qiita.com/youce/items/547d732995be7c8ef839

## ツールの入手

1. **[dobble-maker - GitHub][dobble-maker]** にアクセスし、画面右の`Releases`から`Latest`のバージョン番号を選択して、
   <img width="350" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3562294/d52d85f4-acdf-bf04-5c2f-6b418f08b731.png">

1. `Assets`から`dobble_maker_gui_v*.zip`をダウンロードし、任意のフォルダに解凍します。
   <img width="250" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3562294/147ac219-f78f-4f15-443e-f36927da989d.png">

## 実行

解凍したフォルダに含まれている`dobble_maker_gui.exe`を実行してください。

実行後の画面のパラメータは **[GitHub][dobble-maker]** の説明を参照してください。
起動した画面でそのまま`計算実行`ボタンを押してしばらく待つと、`samples`フォルダにある画像をシンボル画像として、`output`に以下のファイルが生成されます。

* カード毎の画像 (`{数字}.png`)
* 各カードのシンボルの組み合わせ表 (`pairs.csv`)
* 印刷用PDF (`card.pdf`)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3562294/e0244d5c-e8a8-9a6f-312b-4f0d86d12702.png)

生成されたPDFを厚紙に印刷してカッターで切れば遊べますし、意外とコピー用紙でも問題なく遊べるので、ぜひ試してみてください。

## 画像の準備について

上記のツールには動作確認用に以下のサンプル画像が同梱されていますが、シンボル画像を変えたい場合は、必要数の画像 (`PNG` あるいは `JPG`) を自分で準備する必要があります。

<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3562294/b3915222-7b13-8bc5-40ae-e8b3a1ce8bf2.png">


例えば、カード 1 枚当たりのシンボル数を`8`にするなら `8 * (8 - 1) + 1 = 57` 枚、シンボル数 `10` なら `91` 枚の画像が必要です。

また画像は「背景が白、あるいは透明」であることが望ましいです。

* 素材集（[いらすとや](https://www.irasutoya.com/)さん等）を使う
* 好きな画像をWebで収集してペイントで加工する[^contents_license]
    * Google 画像検索 の場合、`ツール`から、色を`透明`、種類を`クリップアート`にすると適切な画像が見つかりやすいです
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3562294/eeaafafb-4fe2-7553-2439-36af63b2f2c6.png)

## おわり

[^contents_license]: 著作権法上、私的利用でしたら[利用可能](https://www.bunka.go.jp/seisaku/chosakuken/seidokaisetsu/gaiyo/chosakubutsu_jiyu.html)です
【学習メモ】CodeDeployのデプロイライフサイクルイベント（AppSpecの各hook）を調べた

# 「hooks」 セクションの構造
```ruby:
hooks:
   - deploymentLifecycleEventName:
     - location: script-location
       timeout: timeout-in-seconds
       runas: user-name
```


## ECS デプロイ

```ruby:
hooks:
  #Startする
  - BeforeInstall: "BeforeInstallHookFunctionName"
  #Installする
  - AfterInstall: "AfterInstallHookFunctionName"
  #AllowTestTrafficする
  - AfterAllowTestTraffic: "AfterAllowTestTrafficHookFunctionName"
  - BeforeAllowTraffic: "BeforeAllowTrafficHookFunctionName"
  #AllowTrafficする
  - AfterAllowTraffic: "AfterAllowTrafficHookFunctionName"
  #Endする
```

## Lambda デプロイ
デプロイ対象がLambdaの場合は、インストールイベントがなく直接AllowTrafficに入る
```ruby:
hooks:
   #Startする
   - BeforeAllowTraffic: "BeforeAllowTrafficHookFunctionName"
   #AllowTrafficする
   - AfterAllowTraffic: "AfterAllowTrafficHookFunctionName"
   #Endする
```

## EC2 デプロイ(LoadBalancerなし)
デプロイ対象がEC2の場合、まずはApplicationStopでEC2を停止する必要がある
最後は「ValidateService」でデプロイが正常に完了したことを確認できる
```ruby:
hooks:
   #Startする
   - ApplicationStop: "ApplicationStopHookFunctionName"
   #DownloadBundleする
   - BeforeInstall: "BeforeInstallHookFunctionName"
   #Installする
   - AfterInstall: "AfterInstallHookFunctionName"
   - ApplicationStart: "ApplicationStartHookFunctionName"
   - ValidateService: "ValidateServiceHookFunctionName"
   #Endする
```

## EC2 デプロイ(LoadBalancerあり)
LoadBalancerを使う場合は、最初BlockTrafficでトラフィックを停止する必要があり、デプロイ完了後またAllowTrafficする
```ruby:
hooks:
   #Startする
   - BeforeBlockTraffic: "BeforeBlockTrafficHookFunctionName"
   #BlockTrafficする
   - AfterBlockTraffic: "AfterBlockTrafficHookFunctionName"
   - ApplicationStop: "ApplicationStopHookFunctionName"
   #DownloadBundleする
   - BeforeInstall: "BeforeInstallHookFunctionName"
   #Installする
   - AfterInstall: "AfterInstallHookFunctionName"
   - ApplicationStart: "ApplicationStartHookFunctionName"
   - ValidateService: "ValidateServiceHookFunctionName"
   - BeforeAllowTraffic: "BeforeAllowTrafficHookFunctionName"
   #AllowTrafficする
   - AfterAllowTraffic: "AfterAllowTrafficHookFunctionName"
   #Endする
```

# 参考サイト
https://docs.aws.amazon.com/ja_jp/codedeploy/latest/userguide/reference-appspec-file-structure-hooks.html#appspec-hooks-server
M5Atom Liteでタクトスイッチメモ




```main.cpp
#include <M5Atom.h>

#define IN_SW 25

CRGB dispColor(uint8_t r, uint8_t g, uint8_t b) {
  return (CRGB)((r << 16) | (g << 8) | b);
}

void setup() {
  M5.begin(true, false, true);
  M5.dis.drawpix(0, dispColor(0, 0, 0));
  
  pinMode(IN_SW, INPUT);
}

void loop() {
  M5.update();

  if (digitalRead(IN_SW) == LOW) {
    M5.dis.drawpix(0, dispColor(0, 0, 255));
  } else {
    M5.dis.drawpix(0, dispColor(20, 20, 20));
  }

  delay(100);
}

```
Livewire3.0にアップグレードするとモデルのプロパティを直接バインドできない件

## Livewireでモデルのプロパティを直接バインドする
Livewireでは、Eloquentモデルのプロパティを直接バインドできる。書き方はこんな感じ。

```
//コンポーネント
use App\User;
 
class UserForm extends Component
{
    public User $user;
 
    protected $rules = [
        'user.name' => 'required|max:100',
        'user.email' => 'required|email',
    ];
 
    public function save()
    {
        $this->validate();
 
        $this->user->save();
    }
}
```
```
//View
<form wire:submit.prevent="save">
    <input type="text" wire:model="user.name">
    <input type="email" wire:model="user.email"> 
    <button type="submit">Save</button>
</form>

```

## Livewire3.0でハマる

ある日、新しいプロジェクトで同じようにやってみるとバインドがうまくいかない。
ブラウザのコンソールで確認すると以下のようにエラーが出ている。
`livewire.js?id=XXXXXXXXX:XXX Uncaught TypeError: Cannot read properties of null (reading 'name')`

自分の凡ミスを疑ってしまい、かなりハマる。

## Livewire3.0での解消法
[Livewireのアップグレードガイド](https://livewire.laravel.com/docs/upgrading#eloquent-model-binding)見たらちゃんと書いてあったね。

　解消方法は次のとおり。

1. まず以下のコマンドを叩く。
`php artisan livewire:publish --config`

2. config/livewire.phpが生成されるのを確認。
3. livewire.phpの以下をtrueに変更する。
`'legacy_model_binding' => false,`

これでとりあえず解決した！

アップグレードする時はちゃんとドキュメント読まなきゃね。（ある意味凡ミスよね。）

ちなみに今回このような仕様変更があったのは、どうも3から追加したフォームオブジェクトを推したいという意図がありそう。

2からの移行は一旦これでOKやけど、新機能のフォームオブジェクトを使うとプロパティやらバリデーション関連を別のクラスに分離できるというメリットもあるみたいなので、そっちを試してみるのもありかも！（こちらはやったらまた追記します。）

## [追記]emitも使えなくなってる！
`emit()`も使えなくなっていた。もちろんこれも[Livewireのアップグレードガイド](https://livewire.laravel.com/docs/upgrading#events)みたらちゃんと書いてる。
`emit()`と`dispatchBrowserEvent()`が`dispatch()`という一つのメソッドに統合されたらしいので`$this->emit('my-event')`みたいに書いていたところは、全部`$this->dispatch('my-event')`のように書き換えないといけない。

プロパティの直接バインドは設定ファイルの項目を一つ変更するだけで解決できるけど、これの方が厄介。稼働中のLivewire2.x -> Livewire3アップグレードは慎重に検討した方がいいと思う。
無相関検定（母相関係数=0の検定）の逆

## 無相関検定（母相関係数=0の検定）の逆

### 無相関検定

無相関検定は，サンプルサイズと標本相関係数を与えて，母相関係数=0 の検定を行い $p$ 値を返す。
(R には cor.test() がある）


```R
rtest = function(n, r) {
#    引数
#        n: サンプルサイズ
#        r: 標本相関係数
#    戻り値
#        検定統計量 t0 と p 値（両側検定）のタプル
    t0 = abs(r)*sqrt(n - 2)/sqrt(1 - r^2)
    return(c(t0=t0, p.value=2*pt(t0, n - 2, lower.tail=FALSE)))
}
```

サンプルサイズが 10，標本相関係数が 0.5 のときの $p$ 値（両側検定）


```R
print(rtest(10, 0.5))
```

           t0   p.value 
    1.6329932 0.1411133 


### 無相関検定の逆

サンプルサイズと有意水準 $\alpha$ を与えて，無相関検定で帰無仮説が棄却される標本相関係数の下限値を求める。

無相関検定において検定統計量 $t_0$ は以下の式で与えられる。

$$
t_0 = \frac{|r|\ \sqrt{n - 2}}{\sqrt{1 - r^2}}
$$

この式を $r$ について解くと，$t$ 分布において $\Pr\\{t \gt t_0\\}$ となる $r$ を求めることができる。 

$$
r = t_0\ \sqrt{1/(n + t_0^2 - 2)}
$$

サンプルサイズと有意水準 $\alpha$ を与えて標本相関係数の下限値を返す関数を定義する。


```R
threshold = function(n, alpha=0.05) {
#    引数
#        n: サンプルサイズ
#        alpha: 有意水準。デフォルト値は 0.05
#    戻り値
#        検定統計量 t0 と 標本相関係数の下限値のタプル
    t0 = qt(alpha/2, n - 2, lower.tail=FALSE)
    return(c(t0=t0, r0=t0*sqrt(1/(n + t0^2 - 2))))
}
```

サンプルサイズが 10 のときの標本相関係数の下限値を求める。


```R
print(threshold(10))
```

           t0        r0 
    2.3060041 0.6318969 


得られた結果を，前述した rtest 関数で評価してみる。


```R
print(rtest(10, 0.631896864719834))
```

          t0  p.value 
    2.306004 0.050000 


有意確率（$p$ 値）が 0.05 になった。
npm publish を子プロセス上で実行すると認証が通らない場合の対応

# 問題

`npm publish` をする際、認証を通すために `npm adduser` すると思います。

普通にシェル上でそれぞれのコマンドを叩くなら特に問題ありませんが、例えば package.json の scripts で `npm publish` コマンドを使っていたり、何らかのシェルスクリプトで実行する場合、親プロセス上で `npm adduser` をしていても認証が通りません。
`npm adduser` も同じプロセス上で実行すれば良いんですが、そうすると今度は毎回実行の度にログインあるいはワンタイムパスワードの入力を1回か2回実行する必要があり非常に面倒です。

# 対応

https://docs.npmjs.com/cli/v10/configuring-npm/npmrc

.npmrc という npm の挙動を制御する仕組みがあり、ここにアクセストークンを記載することができます。
そのレポジトリに .npmrc を用意し、アクセストークンを記載しておくと子プロセス上でも認証が通るようになります。

```.npmrc
//registry.npmjs.org/:_authToken=YOUR_ACCESS_TOKEN
```

これだけです。

アクセストークンは [npmjs.com](https://npmjs.com) のアカウントメニューの Access Tokens のページで作成できます。
【Vue】Vitestで描画された文言をチェックしようとした時にハマったエラーの解決（document is not defined）

# 背景
vueでwebサイトを制作する中で、ユニットテストを実施するためのテストコードをVitestで作成していた。
ユニットテストの内容としては、webサイト上に描画されたテキストに抜けがないか確認するための、文言チェックです。

# 実行環境
- vue：3.3.4
- vite：4.4.9
- vitest：0.34.6
- vue/test-utils：2.4.1

# テストコード
以下のコードのように必要なライブラリ等をインポートし、
`hoge`という文言がinfo.vueファイルで描画されているかのテストをする内容です。
```hoge.test.js
import { expect, describe, test } from 'vitest';
import { mount } from '@vue/test-utils';

// 外部フィアルのインポート
import Info from './src/components/info.vue';

describe(Info, () => {
    // ~
    test("描画文言テスト", () => {
        const wrapper = mount(Info);
        const allText = wrapper.text();
        expect(allText).toContain('hoge');
    });
    // ~
});
```

# エラー内容
`npm run test`で`vitest`コマンド実行時にmount部分で以下のエラーが発生。
```vue
ReferenceError: document is not defined
test("hoge test", () => {
    const wrapper = mount(Info);
                    ^
    const allText = wrapper.text();
    expect(allText).toContain('hoge');
```

# エラーの原因
`happy-dom`のインストールができておらず、実行環境をhappy-domに設定できていなかったため。

# happy-domとは
仮想DOM環境を作成するためのライブラリ。
JSDOMという同様のライブラリもありますが、Happy DOMのほうが数倍処理が速い
`jsdom`ライブラリより処理の速度が速いらしい。

- happy-dom：https://github.com/capricorn86/happy-dom
- jsdom：https://github.com/jsdom/jsdom

# 解消方法
happy-domをインストールし、Viteプロジェクトでテスト環境を構成するための設定を変更。
具体的には、vite.config.jsファイル内のテストに使用する環境を `happy-dom`として設定。

### 1. happy-domのインストール
以下のコマンドを実行後にhappy-domをインストールするのかについてyes/noで聞かれます。
`y`を選択しhappy-domをインストールします。

```
npx vitest --dom
```
試してはないですが、以下のコマンドでもインストールできるのではないかと思ってます。
```
npm i -D happy-dom
```
インストールが完了すると、package.jsonにhappy-domが追加されている事が確認できます。

### 2. vite.config.jsファイルの修正
Viteプロジェクトのテスト環境として`happy-dom`を使用するために、
以下のようにvite.config.jsファイルを修正します。
```vite.config.js
export default defineConfig({
  // ~
  test: {
    environment: 'happy-dom',
  },
  // ~
```

### 3.実行
以下のコマンドでテストを実行しすると、エラーなくテストが通りました。
```
npm run test
```
#### ◆ 補足
上記のコマンドを実行する上で、package.jsonには以下の記述がある事を想定しています。
```package.json
{
  "scripts": {
   "test": "vitest"
  }
}
```
無相関検定（母相関係数=0の検定）の逆

## 無相関検定（母相関係数=0の検定）の逆

### 無相関検定

無相関検定は，サンプルサイズと標本相関係数を与えて，母相関係数=0 の検定を行い $p$ 値を返す。


```julia
using Distributions
function rtest(n, r)
    """
    引数
        n: サンプルサイズ
        r: 標本相関係数
    戻り値
        検定統計量 t0 と p 値（両側検定）のタプル
    """
    t0 = abs(r)*sqrt(n - 2)/sqrt(1 - r^2)
    return (t0, 2ccdf(TDist(n - 2), t0))
end;
```

サンプルサイズが 10，標本相関係数が 0.5 のときの $p$ 値（両側検定）


```julia
println(rtest(10, 0.5))
```

    (1.6329931618554523, 0.14111328125000003)


### 無相関検定の逆

サンプルサイズと有意水準 $\alpha$ を与えて，無相関検定で帰無仮説が棄却される標本相関係数の下限値を求める。

無相関検定において検定統計量 $t_0$ は以下の式で与えられる。

$$
t_0 = \frac{|r|\ \sqrt{n - 2}}{\sqrt{1 - r^2}}
$$

この式を $r$ について解くと，$t$ 分布において $\Pr\\{t \gt t_0\\}$ となる $r$ を求めることができる。 

$$
r = t_0\ \sqrt{1/(n + t_0^2 - 2)}
$$

サンプルサイズと有意水準 $\alpha$ を与えて標本相関係数の下限値を返す関数を定義する。


```julia
function threshold(n, alpha=0.05)
    """
    引数
        n: サンプルサイズ
        alpha: 有意水準。デフォルト値は 0.05
    戻り値
        検定統計量 t0 と 標本相関係数の下限値のタプル
    """
    t0 = cquantile(TDist(n - 2), alpha/2)
    return (t0, t0*sqrt(1/(n + t0^2 - 2)))
end;
```

サンプルサイズが 10 のときの標本相関係数の下限値を求める。


```julia
threshold(10)
```




    (2.3060041352041662, 0.631896864719834)



得られた結果を，前述した rtest 関数で評価してみる。


```julia
rtest(10, 0.631896864719834)
```




    (2.3060041352041667, 0.04999999999999993)



有意確率（$p$ 値）が 0.05 になった。
無相関検定（母相関係数=0の検定）の逆

## 無相関検定（母相関係数=0の検定）の逆

### 無相関検定

無相関検定は，サンプルサイズと標本相関係数を与えて，母相関係数=0 の検定を行い $p$ 値を返す。


```python
import numpy as np
from scipy.stats import t

def rtest(n, r):
    """
    引数
        n: サンプルサイズ
        r: 標本相関係数
    戻り値
        検定統計量 t0 と p 値（両側検定）のタプル
    """
    t0 = abs(r)*np.sqrt(n - 2)/np.sqrt(1 - r**2)
    return (t0, 2*t.sf(t0, n - 2))
```
サンプルサイズが 10，標本相関係数が 0.5 のときの $p$ 値（両側検定）

```python
print(rtest(10, 0.5))
```

    (1.6329931618554523, 0.14111328124999997)


### 無相関検定の逆

サンプルサイズと有意水準 $\alpha$ を与えて，無相関検定で帰無仮説が棄却される標本相関係数の下限値を求める。

無相関検定において検定統計量 $t_0$ は以下の式で与えられる。

$$
t_0 = \frac{|r|\ \sqrt{n - 2}}{\sqrt{1 - r^2}}
$$

この式を $r$ について解くと，$t$ 分布において $\Pr\\{t \gt t_0\\}$ となる $r$ を求めることができる。 

$$
r = t_0\ \sqrt{1/(n + t_0^2 - 2)}
$$

サンプルサイズと有意水準 $\alpha$ を与えて標本相関係数の下限値を返す関数を定義する。


```python
def threshold(n, alpha=0.05):
    """
    引数
        n: サンプルサイズ
        alpha: 有意水準。デフォルト値は 0.05
    戻り値
        検定統計量 t0 と 標本相関係数の下限値のタプル
    """
    t0 = t.isf(alpha/2, n - 2)
    return (t0, t0*np.sqrt(1/(n + t0**2 - 2)))
```

サンプルサイズが 10 のときの標本相関係数の下限値を求める。

```python
threshold(10)
```




    (2.306004135033371, 0.6318968646917198)



得られた結果を，前述した rtest 関数で評価してみる。


```python
rtest(10, 0.6318968646917198)
```




    (2.306004135033371, 0.05000000001333089)



有意確率（p 値）が 0.05 になった。
Hyper-V Server2019 共有フォルダの設定

まずディレクトリを作成する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2284920/2b1cc74c-5072-ed0b-4d21-184a2181106f.png)

共有フォルダとして設定する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2284920/921c75ae-2b10-28d9-8450-e5d61246d862.png)


アクセス権をつける。
今回はアドミンにフルコントロールを与える
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2284920/28fcb619-171d-1151-5341-7f5e7e69e6ae.png)


アクセスしてみる
資格情報を聞かれるのでアドミンの情報を入力
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2284920/4f3de657-a3e6-e3cd-b9cd-869dbbb63b09.png)

入れました！　ネットワークドライブに設定しておく
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2284920/5bfd1bd3-a40d-4121-2ba2-0e6db030e49f.png)
Laravelのbladeでコンポーネントを使う

これまでLaravelのbladeで複雑な画面を開発した経験がなかったのですが、近々開発することになりそうなので、コンポーネントの使い方を調べてみました。
自分用の備忘録です。

### Laravel7以降でbladeコンポーネントが使いやすくなったらしい
Laravel7以降、本記事に記載のように「x-」から始まるタグ名で呼び出せるようになったり、2種類のファイル（phpのコンポーネントクラスとblade）で実装できるようになりました。
ということで、本記事はLaravel7以降のbladeコンポーネントの使い方になります。

### コンポーネントの作成
コンポーネントは２種類のファイルから出来ています。
1.　関連ファイルの作成
 ```
 php artisan make:component ComponentTest
 ```
 これで以下の２つのファイルが作成されます。
 - `/app/View/Components`に`ComponentTest.php`
 - `/resources/views/components`に`component-test.blade.php`

2.　ComponentTest.phpを編集
- パラメータをpublicプロパティとして準備する
- コンストラクタでパラメータを初期化
- renderメソッドでbladeファイルのビューを返す
```
{
    public string $testTitle;

    public function __construct(string $testTitle)
    {
        $this->testTitle = $testTitle;
    }

    public function render()
    {
        return view('components.component-test');
    }

}
```

3.　component-test.blade.phpを編集
ここは普通のbladeファイルと同じイメージで作成すれば良いです。
コンポーネントを呼び出すbladeファイルから渡されるテキストは`$slot`で受け取ることができます。
```
<div>
    <h1>{{ $testTitle }}</h1>
    <p>{{ $slot }}</p>
</div>
```

### コンポーネント呼び出し
コンポーネントを呼び出すbladeファイルでは、タグ形式でコンポーネントを呼び出します。
タグ名はコンポーネント名をケバブケースにして頭に「x-」をつけたものになります。
（例：コンポーネント名が`ComponentTest`の場合、タグ名は`x-component-test`）
パラメータは属性として渡しますが、属性名もケバブケースで表現します。
（例：コンポーネント側のパラメータ名が`testTitle`の場合、属性名は`test-title`）

test.blade.php 
```
<x-component-test test-title="title">
    これはコンポーネントのテストです。
</x-component-test>
```

また、上記のように属性名にコロンが付いていない場合にはパラメータには**文字列のtitle**が渡されますが、下記のようにコロンを付けた場合には**変数の$title**が渡されます。
（この変数$titleはコントローラーから渡された変数です。）

test.blade.php 
```
<x-component-test :test-title="$title">
    これはコンポーネントのテストです。
</x-component-test>
```

### 結果
結果的には以下のようになります。（testTitleに文字列の"title"を渡した場合）
```
<div>
    <h1>title</h1>
    <p>これはコンポーネントのテストです。</p>
</div>
```
呼び出し側でタグの間に記載したテキストが`$slot`に渡されていることが分かります。
`$slot`で渡したテキストもプロパティとして準備することも可能ですが、あんまり長い場合は属性として渡すのは現実的ではなさそうです。

### 調べてみて
普段はフロント開発はVue(Nuxt)で行なっているのですが、bladeのコンポーネントの使い方も似たところがあるなと思いました。
その反面で、やっぱりVueって便利だなと改めて感じました。
Vueの場合はComponentTest.phpとcomponent-test.blade.phpがひとつのファイルで完結するイメージですね。
間違っているところがありましたらご指摘いただけますと幸いです。

### 参考
速習Laravel改訂2版 速習シリーズ（山田祥寛）
https://wings.msn.to/index.php/-/A-03/WGS-PHP-002/
PowerShellからOutlookでメールを送付するスクリプト

# 0. 動機
定期的にダウンロードされるファイルをメールで送付して、それをトリガーにPower Automate(PAC)でTeamsに投稿できたら色々捗るかなと思って作ってみました。

# 1. 元ネタ
下記Youtubeのスクリプトから。
こちらでは関数にメール作成の機能を入れていたり、GetInspectorプロパティでメール送信前に一度目視でメールの内容を確認したりしているのですが、スクリプト起動したらすぐメール送れるようにしました。

https://www.youtube.com/watch?v=wjTI_93VFVI

余談ですが上記miajimyuさんの一連のPowerShell講座は私のようなIT初心者にはとてもいいと思います。

# 2. スクリプト
```PowerShell
#日付の取得
$today = Get-Date -Format "yyyyMMdd"

#メールの内容記載
$To = "xxx@hotmail.com" #アドレスはサンプル
$CC = $null
$Subject = "Test Mail by PowerShell sent on $today"
$Body = "Test Message by PowerShell"

#メールの作成と送付
$outlook = New-Object -Comobject Outlook.Application
$mail = $Outlook.CreateItem(0)
$mail.To = $To
$mail.CC = $CC
$mail.Subject = $Subject
$mail.Body = $Body
$mail.Attachments.Add("C:\Users\Username\Downloads\Sample.xlsx") #添付ファイルの完全パス
$mail.Send()

#メモリ解放...間違ってたらすみません
$mail = $outlook = $null
[GC]::Collect()  

```

# 3. 出力
上記スクリプト実行すると下記のようなものが送付されます。
このメールのタイトルなどをトリガーにPACを作るとWeb系のアプリとの連携ができると思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3343332/b5fe8960-0e4f-7b86-bb86-0b805ad36c35.png)

# 4. 終わりに
基本自分用メモですがどこかの誰かの役に立てば幸いです。

作成したスクリプトをすぐに起動したい場合には下記2つの記事でできる設定をしておくと楽だと思います。

https://qiita.com/_Sasaki_/items/c8486e58df45333017d7

https://qiita.com/_Sasaki_/items/8384ba3eda0aa6fe6547
【Rails】delegateの使い方

# はじめに
Railsで便利な書き方をおしえてもらったので記録に残します。

# やりたいこと
usersテーブルとuser_profilesテーブルが存在
一対一の関係。
`User`クラスからuser_profilesのnameカラムを参照したい場合に
、最初は以下の書き方をしていました。

```user.rb
class User < ApplicationRecord
  has_one :user_profile
 
  def name
    user_profile.name
  end
end
```

```sample.rb
# 以下でよびだせる
@user = User.new
@user.name
```

# 結論
```user.rb
class User < ApplicationRecord
  has_one :user_profile
 
  delegate :name, to: :user_profile
end
```

```sample.rb
# 以下でよびだせる
@user = User.new
@user.name
```
呼び出したいカラムが複数あっても一行で済むのでめちゃ便利ですね！

# おまけ
じつは、decoratorで、すでに似たようなことをしていましたね。
`delegate_all`でモデルのメソッドを呼び出せます。
delegateとは、ざっくり委譲するという意味だそうです。

```decorator.rb
class UserDecorator < ApplicationDecorator
  delegate_all
end
```

# 参考
https://sakurawi.hateblo.jp/entry/delegate
AWSアカウント間でのドメイン移管後、証明書の検証がいつになっても終わらなかった件

# 事象
AWSアカウント間でのドメイン移管後、証明書の検証がいつになっても終わらなかった
CNAMEレコードをホストゾーンに間違いなく設定していたが24時間たってもダメ

# 原因
移管後のNSとホストゾーンのNSが不一致だった為
Django基本８～Templateにフィルター関数を使ってみる。

今回はフィルター関数を使ってみます。
指定の仕方は以下２つ
（１）特定項目にフィルタをかけるばあい
      項目の後にパーティカルライン(|)をつける
　　　　{{項目|filter名}}
（２）範囲指定したすべてにかけるばあい
　　　{% filter  filter名 %}
　　　＜ｐ＞aaaaaaa＜／ｐ＞
　　　{% endfilter %}

試しにやってみましょう
１．norizo_project4/urls.py
　　今回は～/norizo_app4/fil/としたいので
　　pathの'norizo_app4'を'norizo_app4/と修正しています。
![無題.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3571777/e5e14908-2762-5013-fe4f-8a3c0d0c59dd.jpeg)
２．norizo_app4/urls.py
    下記の部分を追加しています
![無題.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3571777/a10e9273-ffef-8e72-5df6-933fb3f0c336.jpeg)
３．vews.pyを修正する。
  　 関数filを追加しました。
　   ここで注意したいのが、日付形式の項目です。
　　  関数datetimeをインポートしています。単純設定ではなく、　　
　   「datetime.data(9999,99,99)」の形式で設定します。
　　  こうしないと後述するTemplateのdateフィルターで日付形式に表示されない
　　　ので要注意です。
　　　![無題.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3571777/2c78a4f3-d0dd-c588-f458-a1bd0c6ce567.jpeg)
４．fil.htmlを作成します。
　　・名前→capfirstを使用し1文字目だけ大文字に。ちなみにlist型の項目では
　　　　　　うまくいきませんでした。
　　・誕生日→dateを使用し年４桁,英語３文字表記,ゼロサプレスの数値表示
　　　としました
　　・楽器→upperを使用し、大文字にしました。
　　・link→urlizeを使用し、指定先へ飛べるようにしました。
![無題.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3571777/bb88f05b-0667-21db-05e2-b1983db107eb.jpeg)
以下にfilterして可能ない機能の一覧についてご参考でリンクを張っておきました。
https://office54.net/python/django/template-filter-summary#section3-1
dateの指定の仕方も参考にリンク張っておきました。
https://dot-blog.jp/news/django-template-date/
５．起動して結果を確認します。
![無題.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3571777/80170ac5-7fb8-d857-d289-cf77899f851d.jpeg)
上手くいきました
![無題.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3571777/c3356645-81fa-5a47-491c-25d57a95b5cd.jpeg)
トラブル対応メモ：複数ユーザーでのSSH利用時のエラー

あまり深く考えずにSSHを使っていたら、結構ハマったのでメモ。

#### 1. 前提 ####
筆者の現場では、作業担当者向けに次のような２つのツールを展開しています。
1)Webから指定したサーバーやネットワーク機器の構成情報を取得してSVNに登録（実行ユーザー：apache）
2)月１回、サーバーやネットワーク機器全部の構成情報をバッチで取得してSVNに登録（実行ユーザー：root）

いずれもSSHを使って各機器に接続し、構成情報を取得⇒ローカルファイルに落としてSVN登録する仕組みで、同じシェルを使っています。
***
#### 2. トラブル内容 ####
ある日突然、バッチ処理で取得していた情報のうち、いくつかの機器で構成情報の取得エラーが出始めます。
それらに共通しているのは、いずれもLinuxやミドルウエアのバージョンアップをした直後の機器ということ。
一方で、Webから該当機器の構成情報を取得しても、特に問題なく取得できてしまいます・・・

調べたところ、バッチ処理ではSSHの接続時にエラーになっているようです。
それにしても、すんごい怒られようですな:disappointed_relieved:
```
> ssh -F (SSHの共通設定ファイル) -o StrictHostKeyChecking=no (user)@(hostid)
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eabesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
The fingerprint for the ECDSA key sent by the remote host is
SHA256:・・・・・・・・
Please contact your system administrator.
Add correct host key in /root/.ssh/known_hosts to get rid of this message.
Offending ECDSA key in /root/.ssh/known_hosts:18
・・・
```
実のところ、筆者はコテコテのDB屋なのでこの辺あまり明るくなくて。
「設定ファイルを指定して実行してるのに、何でrootのファイルが云々言うてんねん(?_?)」
と頭を抱えておりました・・・
***
#### 3. 原因 ####
SSHをちょっとでも深く使われたことのある方であれば既にお気づきの通り、エラーの対象が
**「Linuxやミドルウエアのバージョンアップをした直後の機器」**
というところがポイント。
接続先機器の公開鍵情報が変わってるのに、以前の鍵情報で接続しに行ってたのが原因でした。
で、その公開鍵情報を記録しているファイル（known_hostsファイル）が別途あって、
```
##### rootのとき #####
/root/.ssh/known_hosts
##### 以外のユーザーの時 #####
/home/(user)/.ssh/known_hosts
```
と実行ユーザーによって違うので、結果Webとバッチとで挙動が異なっていたのでした。
***
#### 4.対応 ####
かくして、Webとバッチとで鍵情報を共有するための共通ファイルを使用するようにしました。
上記のような鍵の新旧云々のエラーが発生したときには、都度このファイルから該当鍵の情報を消去してリランする（⇒新しい鍵情報が追加される）運用としました。
```
> ssh -F (SSHの共通設定ファイル) -o StrictHostKeyChecking=no -O UserKnownHostsFile=(共通のknown_hostsファイル) (user)@(hostid)
```
poetry について

poetry コマンド紹介

の前に………！

このbotは全ての人を4つのレベルに割り振っています。
まあ私からの信用度みたいな感じ。
レベルが高いほど色んなコマンドを使えます。

Lv.1 出禁の人。入った瞬間蹴られます。
Lv.2 ほぼ全員ここ。普通です。
Lv.3 私が信用してる人。
Lv.4 このBotの開発に携わった人のみ。

Lv.3、4は自動キック対象から外れます。

自分のレベルは #info ってコマンドで見れます。

ーーー全員が使えるコマンドーーー

#pk ポーカーで遊べます。対戦機能はないです（）

#gacha 元素ガチャを引けます。やたら窒素と酸素が出るのは空気中の割合を確率にしてるから。アルゴンとか引けたらレアです。

#soin 334 何でや阪神関係ないやr((
334の部分は好きな数字にしてください。勝手に素因数分解してくれます、私が試して見たけど15桁くらいまではすぐできるらしいよ、、？

#help この説明のurlを表示します。つまりこれにたどり着けてるってことは使わん。

#info さっき言ったLv.を確認できます。

こんくらいかな、まだまだ追加する予定ではある。
前向きに検討します。

ーーLv.3以上が使えるコマンドーー

今は無いです（）

ーーLv.4のみ使えるコマンドーー

stp botを止めることが出来ます。


ーーーーーーーーーーーーーーーーーーーー



てな感じ！（）

追加予定の機能
・キックコマンド(そのうち)
・最大文字数変更コマンド(そのうち)
・禁止ワード、禁止トリップ追加コマンド(できたらいいなぁ)
Wireshark

<!--
2023/10/18
-->

[picoCTF][Forensics][Wireshark twoo twooo two twoo]

# Writeup
* pcapngのファイルなので、とりあえずWiresharkで。
ファイルの出力を試みる。`File` `Export Objects` `HTTP`
![flags.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/160736/70871af5-9371-3c0a-784b-3555a662496b.png)
<br>

* flagがたくさんなので、嘘っぽいですね。
中身もそれっぽくないし。そして案の定の結果に。
![flag_false.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/160736/b32dd52b-dfb8-2da2-26e2-ec17437fadb8.png)
<br>

* 他に出力できそうなファイルを探したら、メッセージっぽいものが。
該当する通信を`右クリック` `Follow` `TCP Stream`で確認。
![mes.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/160736/c54568c5-67b9-7339-354b-8434d42a9eba.png)
![mes2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/160736/372a11c3-ef47-eb5a-5b18-379856c85549.png)
![trans.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/160736/10d4df07-eed6-a923-a27e-0e0a7bf53093.png)
<br>

* 海老[Shrimp]を探すと、異なるサブドメインへの問い合わせが多い。
これは怪しいのか。
![shrimp.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/160736/735ced53-9581-43cb-f7be-fe54ba1334a5.png)
<br>

* とりあえず名前解決に関するパケットを確認してみる。
Googleは関係ないと思うし、レンスポンスを非表示にして、見る分を減らす。
`dns && ip.addr != 8.8.8.8 && ip.dst == 18.217.1.57`
![screenshot.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/160736/9e9b787b-f56b-ea2f-81ef-6d7c2a528f1e.png)
<br>

* `fQ==`って怪しいのか。末尾の`0=` `9`とかも覚えておこう。
サブドメインを繋げたいので、適当な名前を付けてテキスト出力。
`File` `Export Packets Dissections` `As Plain Text`
![screenshot 2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/160736/a6b9890a-9373-0a3e-c4ca-2d0c049f95f5.png)
<br>

* 必要な部分だけ抽出
~~~bash
cat hoge.txt | grep .reddshrimpandherring.com:| cut -d "." -f 1 > result.txt
~~~
![screenshot 1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/160736/c0ad05c1-9156-18d8-40da-72b1339d863d.png)
<br>

* CyberChefでBAKE!した。
![answer.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/160736/601cc3d4-acda-9466-65d7-3399912933dc.png)

# 参考サイト
https://ichibariki.com/entry/2018/06/03/225649
https://tech.kusuwada.com/entry/2021/04/08/121205
https://www.deepl.com/translator
「docker compose up」の際に「driver failed programming external connectivity on endpoint」エラーが発生した場合の対処

# 環境
- Docker version 24.0.6
- Docker Compose version v2.4.1

# はじめに
`docker compose up -d`コマンドでコンテナを一括起動しようとした際に、上記のエラー`Error response from daemon: driver failed programming external connectivity on endpoint (コンテナ名) (コンテナID): Bind for 0.0.0.0:3306 failed: port is already allocated`と出てしまいました。

# 原因
[Docker Composeでdriver failed programming external connectivity on endpointとなった時の対応方法](https://qiita.com/ponsuke0531/items/f3490f571b5eee16ea87)
こちらの記事によると、原因としては主に

1. 他のコンテナとポート番号が被っている
1. 作成に失敗したコンテナが残っておりそのコンテナで作り直されてしまっている

以上の2点が考えられるそうです。（自分の場合は1でした）

# 対処（上記記事参照）
## 1. docker-compose.ymlで対象コンテナのポート番号を変更
元々使用していたポート番号が既に使われていたので、ymlファイルに記載されているポート番号を変更します。
※`(ホストのポート番号):(コンテナのポート番号)`になるので、今回はホストのポート番号を変更しました。
### 変更前
``` docker-compose.yml
ports:
      - 3306:3306
```
### 変更後
``` docker-compose.yml
ports:
      - 3307:3306 # ホストのポート番号を変更
```

## 2. 作成に失敗したコンテナを削除する
ここで削除せずに起動すると、原因2の「作成に失敗したコンテナが残っておりそのコンテナで作り直されてしまっている」状態になるため、先に失敗したコンテナを削除します。

まず、`docker ps -a`コマンドで停止しているコンテナを含めた全てのコンテナのIDから、
作成に失敗したコンテナIDを確認します。
```
$ docker ps -a
> CONTAINER ID   IMAGE                COMMAND                  CREATED         STATUS                    PORTS
  2a638415a56e   mysql:5.7            "docker-entrypoint.s…"   2 minutes ago   Created                0.0.0.0:3306->3306/tcp, :::3306->3306/tcp, 33060/tcp
```
次に、見つけたコンテナIDを指定して`docker rm`コマンドで削除します
成功すれば、以下のようになります。
```
$ docker rm (対象コンテナID)
> (対象コンテナID)
```
ただ、コンテナを停止していない場合に`Error response from daemon: You cannot remove a running container (対象コンテナID). Stop the container before attempting removal or force remove`というエラーが発生する場合があります。

その場合は、`--force`オプションをつけることで強制的にコンテナを削除します。
成功すれば、以下のようになります。
```
$ docker rm --force (対象コンテナID)
> (対象コンテナID)
```

## 3. コンテナを作り直す
最後に、対象のコンテナ名を指定してイメージ構築とコンテナの起動を行います。
```
$ docker-compose up -d --no-recreate --build (コンテナ名)
```

# おわりに
ここまでご覧いただきありがとうございます！
しかし、まだdocker素人ということもあり間違った情報を載せてしまっている場合があります。
なので、間違ってる情報があればご指摘していただきたいです。
TypeScriptでオブジェクトの要素を主キーに配列を作る

# はじめに

TypeScriptでオブジェクトの主キーを利用して同じものをまとめたいという質問を受けてアルゴリズムを書いたのでまとめておきます

# 問題

以下のデータがあるとします

```ts
type Person = {
  name: string;
  code: string;
  memberId: string;
};

const people: Person[] = [
  { name: "John", code: "python", memberId: "1" },
  { name: "Jane", code: "java", memberId: "2" },
  { name: "Bob", code: "python", memberId: "3" },
  { name: "Alice", code: "javascript", memberId: "4" }
];
```

ここで、`code`が同じものを集めて以下のような構造を作ります

```
{
    python: [
        { name: "John", code: "python", memberId: "1" },
        { name: "Bob", code: "python", memberId: "3" }
    ],
    java: [
        { name: "Jane", code: "java", memberId: "2" }
    ],
    javascript: [
        { name: "Alice", code: "javascript", memberId: "4"}
    ]
}
```

# 解決方法

以下のような関数を作ってみました

```ts
export const groupBy = <T>(
  list: T[],
  getKey: (item: T) => PropertyKey,
): Record<PropertyKey, Record<PropertyKey, T[]>> => {
  return list.reduce((acc, cur) => {
    const key = getFirstKey(cur);

    if (!acc[key]) acc[key] = {};

    acc[key].push(cur);
    return acc;
  }, {} as Record<PropertyKey, Record<PropertyKey, T[]>>);
};

const groupBy = groupBy(people, person => person.code);
```

# 2つのキーを使ってまとめる

2つのキーでまとめる方法も考えました

```ts
export const groupBy = <T>(
  list: T[],
  getFirstKey: (item: T) => PropertyKey,
  getSecondKey: (item: T) => PropertyKey
): Record<PropertyKey, Record<PropertyKey, T[]>> => {
  return list.reduce((acc, cur) => {
    const firstKey = getFirstKey(cur);
    const secondKey = getSecondKey(cur);

    if (!acc[firstKey]) acc[firstKey] = {};
    if (!acc[firstKey][secondKey]) acc[firstKey][secondKey] = [];

    acc[firstKey][secondKey].push(cur);
    return acc;
  }, {} as Record<PropertyKey, Record<PropertyKey, T[]>>);
};

type Person = {
  name: string;
  code: string;
  memberId: string;
};

const people: Person[] = [
  { name: "John", code: "python", memberId: "1" },
  { name: "Jane", code: "java", memberId: "2" },
  { name: "Bob", code: "python", memberId: "3" },
  { name: "Alice", code: "javascript", memberId: "4" }
];

const grouped = groupBy(
  people,
  (person) => person.code,
  (person) => person.memberId
);
console.log(grouped);
```

# おわりに

この方法がわかるとフロントで表示するのが楽になりそうですね
【VScode・Go言語】単体テストの設定をカスタマイズして快適な開発体験を！

早速ですが、Gopherの皆さんはこちら↓のVScodeのTesting機能を活用されていますでしょうか？

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1220258/f14f0e20-2928-ce12-b0ea-35909559bea1.png)

Testing機能を活用すると、コマンドラインからテストを実行するのに比べて、以下のようなメリットがあります。

- テスト実行時
  - ボタン1つでパッケージごとにテストを実行したり、特定のテストケース一つだけを実行できる
  - つまりコマンドラインから、実行したいテストケースを特定するためのオプションを指定する必要がない
    - ルートディレクトリから対象のテストまで辿っていくのって意外に面倒...
- テスト実行後
  - より視覚的にテストの失敗箇所を特定することができる
    - コマンドラインから実行するときは、テスト結果の確認のためにターミナルの文字をスクロールして探す必要がある

ただし、実際の開発現場で使う場合には、テストを実行するために環境変数やフラグを指定する必要が往々にしてあると思うので、
今回の記事では、VscodeのTesting機能を活用する際のこれらのオプションの設定方法について紹介していきます！

# 設定方法

設定方法はシンプルです。

`ctrl + shift + p`を押してコマンドパレットを開いて、`Preferences: Open User Settings (JSON)`や`Preferences: Open Workspace Settings (JSON)`を選択します。

>多くの場合、Workspace Settingsの方に記述していくことになると思います。テストの実行オプションはプロジェクトごとに異なると思うので。

Settingsを開いたら、下記で紹介していくオプションの内、必要なものを追加していけばOKです。


## フラグ

テスト実行時にArgumentsをつける場合にこちらのオプションを使います。

```json
"go.testFlags": [
    "-v",
    "-cover"
]
```

こちらの場合は下記コマンドと同義になります。

```bash
go test ./... -v -cover
```

## envファイル

参照するenvファイルを指定します。

Vscode上で開いているディレクトリからの相対パスで指定するために、`${workspaceFolder}`を使ってこのように記述します。

```json
"go.testEnvFiles": "${workspaceFolder}/.env"
```


## 環境変数

envファイルから読み込む場合は前述の`go.testEnvFiles`を使いますが、envファイルを用意しない場合や、`ENV='LOCAL' go test ./...`のようにコマンドラインから直接環境変数を指定するような使い方をしたい場合は、こちらのオプションを使います。

```json
"go.testEnvVars": {
    "ENV": "LOCAL"
}
```


## テスト実行時にファイルを保存

テスト実行時にファイルを保存したい場合は、`testOnSave`のオプションを使います。

ただ、Vscodeの説明にもある通り、多くの方はAuto Saveを有効にしていると思うので、このオプションはあまり使わないかもしれません。

>Run 'go test' on save for current package. It is not advised to set this to true when you have Auto Save enabled.

```json
"go.testOnSave": true
```

## tagsオプション

go test実行時のtagsオプションの使い方についてはこちらの記事で分かりやすく紹介されているので、ぜひ参考にしてみてください。

https://devlights.hatenablog.com/entry/2020/09/24/011502

tagsオプションの設定方法は下記の通りです。

```json
"go.testTags": "foo"
```

## Timeout指定

デフォルトでは30秒のタイムアウトが設定されていますが、変更したい場合は下記のように設定します。

```json
"go.testTimeout": "60s"
```
GitHubの不必要なファイルを削除する方法

# はじめに

GitHub上でプルリクを送った時、GitGuardianのチェックを引っ掛かる時があります。その時に引っ掛かったsenstiveなファイルをgit履歴上から完全に削除する方法を書きます。

```console
git filter-branch --force --index-filter \
"git rm --cached --ignore-unmatch INSERT_PATH_TO_FILE_HERE" \
--prune-empty --tag-name-filter cat -- --all
```

```console:実行例
git filter-branch -f --index-filter \
'git rm --cached -rf --ignore-unmatch bin/conf.txt' \
--prune-empty --tag-name-filter cat -- --all
```

# git filter-branchで使うオプション

git filter-branchはオプションがたくさんつくので、非常に見づらいですね。
そこで、オプションの機能を一覧でまとめました。

| オプション | 機能 |
| --- | --- |
| --setup [command] | 実行直前に1回限りコマンドを実行する |
| --subdirectory-filter [directory] | 指定されたサブディレクトリに関連する履歴のみ調べる |
| --env-filter [command] | 環境変数を変更するなどコミットが実行される環境を変更する必要がある場合にのみ使用。 |
| --tree-filter [command] | 各チェックアウトに対してコマンドを実行し、結果を再コミット |
| --index-filter [command] | インデックス上で、各チェックアウトに対してコマンドを実行し、結果を再コミット |
| --parent-filter [command] | コミットの親リストを書き換えるためのフィルター |
| --msg-filter [command] | コミットメッセージを書き換えるためのフィルター |
| --commit-filter [command] | コミットごとのform用のフィルター |
| --tag-name-filter [command] | --tag-name-filter catで使用し、タグを変更せず、タグが紐付けされているコミットIDを上書きする |
| --prune-empty | 空のコミットを削除 |
| --original [namespace] | 元のコミットが保存される名前空間を設定できる |
| -d [directory] | 書き換えに使用される一時ディレクトリへのパスを設定できる |
| -f or --force | filter-branchは実行ディレクトリが一時ディレクトリである場合、refs/original/に既にバックアップが存在する場合は実行できないので、強制的に実行する必要がある |
| --state-branch [branch] | 退避用ブランチを指定できる。branchが存在しない場合は作成される |
| [rev-list options]…​ | git rev-listの引数。このオプションに含まれるすべての参照が書き換えらる |
| --all | すべてのブランチを指定 |
| HEAD | チェックアウトしている(今自分が作業している)ブランチを指定 |

※commit前に一時的にステージングする場所がindex


引用元: [git-filter-branch](https://runebook.dev/ja/docs/git/git-filter-branch)

# pushする

下記のコマンドを実行しないと、GitHubに反映されないです。

```console
git push origin --force --all
```