OmniAICreator/Qiita-1.07M huggingface dataset:
【Terraform 】windows環境での初回環境構築（ダウンロードからパスの設定まで）

# 初めに
本記事ではwindows環境でTerraformをダウンロードし、
コマンドプロンプトでTerraformのバージョンの確認まで行う方法を紹介する。

# Terraform のダウンロード
Windows > AMD64を選択しダウンロード。

https://developer.hashicorp.com/terraform/install?product_intent=terraform

# terraform.exeの配置
ダウンロードしたzipファイルを解凍し、中に入っている`terraform.exe`を適宜好きな場所に配置する。
今回はCドライブ直下に`terraform_1.7.4_windows_amd64`フォルダを作成しその中に`terraform.exe`を配置する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1247619/833c4a70-7c35-00fb-c4c6-041bf73746a0.png)

# 環境変数の設定
コントロールパネル > システム > システムの詳細設定 > システムのプロパティ > 詳細設定 > 環境変数を選択。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1247619/cb24f587-38bf-6e5a-904f-c59c718b7677.png)

ユーザの環境変数 > Pathを選択した状態で`編集`を選択。
`新規`をクリックし、`terraform.exe`を配置したフォルダのパスを入力。
入力できたら`OK`を選択して閉じる。

# コマンドプロンプトでバージョンの確認

コマンドプロンプト開き以下のコマンドを入力。

```
terraform -v
```

terraformのバージョンが出力されている事を確認できる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1247619/129b31c1-de9d-e772-d081-5853dff66853.png)
物流・ロジスティクス



## 物流
物資を供給者から需要者へ，時間的及び空間的に移動する過程の活動。一般的には，包装，輸送，保管，荷役，流通加工及びそれらに関連する情報の諸機能を総合的に管理する活動。 調達物流，生産物流，販売物流，回収物流（静脈物流），消費者物流など，対象領域を特定して呼ぶこともある。(JIS Z0111)

物流とは流通の物理的機能である「物的物流」の省略語（参考図書：ロジスティクス用語辞典）

まず、物流は経済を構成する生産、流通、消費の中の流通に位置する概念である。
流通は生産と消費のギャップを埋める機能であり、供給から需要の橋渡しである。
流通は物流と商流という２つの構成要素からなる概念で、商流は商的流通の略語、物流は物的流通の略語である。物流が純粋に生産物=商品の流れであるのに対して、商流とはその過程で生じる物の取引活動とお金の流れである。

### 物流の6大機能
「輸配送」、「保管」、「包装」、「荷役」、「流通加工」、「情報処理」

## ロジスティクス
物流の諸機能を高度化し，調達，生産，販売，回収などの分野を統合して，需要と供給との適正化を図るとともに顧客満足を向上させ，併せて環境保全，安全対策などをはじめとした社会的課題への対応を目指す戦略的な経営管理。 

・対応英語（logistics)

荷主企業でも物流事業者でもない第三者が荷主のロジスティクスを代行するサービス。倉庫，車両などの施設・設備がなくても事業化できる運営ノウハウをもとに，情報システム及び業務改革の提案を中心に長期的な管理目標を定め，達成した改善利益の配分を受けるものであるが，物流事業者が荷主企業のアウトソーシングニーズに広範に対応して一括受注するケースも含まれる。
Discordで"アクシオ"という言葉が表示された場合にマウスポインタを指定した場所に自動で移動させてみる

Discordのチャットを監視して、"アクシオ"という言葉が表示された場合にマウスポインタを指定した場所に移動させる。
”アクシオ”と聞いてすぐに意味がわかる人は友達になれる気がする。

その前に以下のライブラリをインストールしておきます。
pyautoguiとdiscord.pyの2つのライブラリを使用します。
```bush
pip install pyautogui discord.py
```

Discord部屋を監視するbotアカウントの作り方はググってください。

～試行錯誤中～
どうやってもDIscord部屋に置いたbotが"アクシオ"を認識してくれない。
"Message Content Intent" を有効にしてるんだが。。。。
誰か教えて(´;ω;｀)

```
[2024-02-25 23:57:45] [WARNING ] discord.ext.commands.bot: Privileged message content intent is missing, commands may not work as expected.
[2024-02-25 23:57:45] [INFO    ] discord.client: logging in using static token
[2024-02-25 23:57:46] [INFO    ] discord.gateway: Shard ID None has connected to Gateway
intentsの設定において、特権が正しく有効化されていないことを示しています。Discord.py v1.7.0以降では、特権の有効化が必要とされています。
先程のコードで intents.messages を True にしていましたが、恐らくその影響で特権が有効化されなかった可能性があります。
以下のように修正してみてください。
```

```python
import discord
from discord.ext import commands
import pyautogui

# Discord Botのトークンを設定
TOKEN = 'YOUR_DISCORD_BOT_TOKEN'

# ボットのプレフィックスを設定
intents = discord.Intents.all()
bot = commands.Bot(command_prefix='!', intents=intents)

# 移動させたい座標を指定
destination_coordinates = (500, 500)

# 監視したいトピックを指定
topic = 'buy'

@bot.event
async def on_ready():
    print(f'Logged in as {bot.user.name}')

@bot.event
async def on_message(message):
    if message.author.bot:
        return  # ボットのメッセージは無視

    # 指定したトピックで始まる場合
    if message.content.startswith(topic):
        # マウスポインタを指定した座標に移動
        pyautogui.moveTo(*destination_coordinates)
        print('Mouse moved to the specified coordinates.')

# Discordボットを起動
bot.run(TOKEN)
```
SPA開発をNext.js(Static Site Generation[SSG])からReact+Vite環境に乗り換える

## 現状のSPA開発

- フレームワーク：Next.js（Pages Router)
- 開発サービス：BtoB向けSaaS
- フロントインフラ：AWS S3
    - Next.jsのStatic Exportsによりルートごとに静的ファイルを生成してホスティング
        - 全てがビルド時に静的に決まるわけではないので、動的に変わるところはCSR(Client Side Rendering）で画面更新頑張る
    - 初期ロード時にファイルをS3から取得して、それ以降クライアントサイドで画面遷移

携わるシステム開発が基本フロント用のNode.jsサーバーを管理しない方針で、Node.jsサーバーありきのフレームワーク(Next.jsやRemixなど)はあっていない気がするので、フレームワークを使わない道を模索してみた。

## こんなSPA開発環境が欲しい

- ファイルベースルーティングできること
- エラーハンドリングできること
    - 独自レイアウトの404ページが表示できる
    - 独自レイアウトのランタイムエラーページが表示できる
- SSG(Static Site Generation)できること
    - ルートごとに静的ファイルを出力できること
        - フロント資材は静的ファイルをホスティングサービスに乗せるだけにしたい

Next.jsで使っていた機能といえばこのくらいなので、これが他のライブラリで実現できるのであればNext.jsを剥がしたSPA環境ができそう。

## 結論

| 機能 | 機能を提供するライブラリ |
| --- | --- |
| ファイルベースルーティング | TanStack Router |
| エラーハンドリング | TanStack Router |
| SSG(Static Site Generation) | Vike（Pre-Rendering)（これ使うならTanStack Routerではなく、Vikeのrouting機構に乗らないといけない） |

ファイルベースルーティングとエラーハンドリングは[TanStack Router](https://tanstack.com/router/latest)で代用できそう。

SSGについてはさくっとできそうな方法が見つからなかった。[VikeのPre-Rendering](https://vike.dev/pre-rendering)を使えばできなくはない気はするが、SSGのために結構手間が増えそうなので微妙と判断。（[Next.jsだとnext.config.jsにoutput: 'export'を加えるだけ](https://nextjs.org/docs/pages/building-your-application/deploying/static-exports#configuration)）ってことでSSGは厳しそうなので、`vite build`で出力されるindex.htmlとjs,css等をS3にホスティングする。ただ、rootより深いroutesを含まないので、CloudFrontやS3で設定を追加して回避しようと思う（[エラーの場合に/index.htmlにリダイレクトするやつ](https://soypocket.com/it/aws-cloudfront-s3-403error/)）。

### おまけ（感想）

- TanStack Routerよさげ
    - 認証済みでないとみれないページの実装がしやすくなる（未認証の場合はログインページにリダイレクトみたいな処理）
    - Strict Navigation
        - <Link to=”” />とかで画面遷移するときにコード補完してくれる
        - path params、search paramsも型安全に扱える
    - Structural Sharing
        - 共通レイアウトが組みやすい
        - Next.js App routerのLayoutと同じ？（厳密にはちょっと違うかも）
        - App Routerにはしたくないけど、Layoutの仕組みは欲しかったので嬉しい
- 私みたいな人のためにRemix SPAが出たみたいだけど、2024年2月現在experimentalなのと、SSGは未対応みたい
MacでWindowsにSSHする (CUDAが使いたい...)

唐突にMBPでCUDAが使いたくなった。
ちょうどRTX3060Tiを積んだWindowsが転がっている。
そうだWindowsを乗っ取ろう。


## Windowsの設定
### PowerShellの更新(任意)
下記のURLのmsiを利用してインストールする(2023/02/25現在、v7.4が最新)
https://learn.microsoft.com/ja-jp/powershell/scripting/install/installing-powershell-on-windows?view=powershell-7.4#installing-from-the-microsoft-store

###  WindowsにOpenSSH Serverをインストール
- 「スタートメニュー」->「設定」->「システム」->「オプション機能」を開く
- 「オプション機能を追加する」の右側の機能を表示を押下
- 「OpenSSH サーバー」を探してチェックをいれる
- 次へを押下してインストールする

### OpenSSH Serverの自動起動設定をする
- 「スタートメニュー」から「サービス」を検索して開く
- リストからOpenSSH SSH Serverを探す
- 右クリックでプロパティを開く
- 「スタートの種類」を自動にする
- 「適用」を押下

### OpenSSH Serverを開始
- 「スタートメニュー」から「サービス」を検索して開く
- リストからOpenSSH SSH Serverを探す
- 右クリックから「開始」を押下


### SSH ServerのデフォルトのシェルをPowershellに変更
下記コマンドの<Powershellのパス>に、PowerShellの格納パスを指定する
**msiを利用してインストールした場合は、`C:\Program Files\PowerShell\7\pwsh.exe`になっている**

```bash
New-ItemProperty -Path "HKLM:\SOFTWARE\OpenSSH" -Name DefaultShell -Value “<PowerShellのパス>” -PropertyType String -Force
```

## Macで接続テスト
下記のコマンドでSSH接続を行う
初回の場合は、知らない接続先のため確認が出る。（yesを入力）

```bash
ssh <WindowsUserName>@<WindowsIP>
```

## VSCodeの設定
- 「Extensions」から好きなSSHクライアントをインストール
- SSHの接続設定をする
- あとはお好みでどうぞ


## 参考
https://qiita.com/hiro_nico/items/48d091a7200f2012650b
https://www.server-world.info/query?os=Windows_Server_2019&p=ssh&f=5
https://learn.microsoft.com/en-us/windows-server/administration/openssh/openssh_server_configuration
https://learn.microsoft.com/ja-jp/powershell/scripting/install/installing-powershell-on-windows?view=powershell-7.4
SEO対策の具体例を忘れないための備忘録

## head内に書くべきタグ

```.html
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <meta name="format-detection" content="email=no,telephone=no,address=no">
    <meta name="robots" content="max-image-preview:large">

    <title></title>
    <meta name="description" content="">

    <!-- ogp -->
    <meta property="og:url" content="https://www.■■■■.■■■">
    <meta property="og:type" content="website">
    <meta property="og:title" content="">
    <meta property="og:description" content="">
    <meta property="og:site_name" content="">
    <meta property="og:image" content="https://www.■■■■.■■■/static/image/■■■.png">
    <meta property="og:locale" content="ja_JP">

    <meta name="twitter:card" content="summary_large_image">
    <meta name="twitter:title" content="">
    <meta name="twitter:description" content="">
    <meta name="twitter:site" content="@Twitterユーザー名">

    <!-- favicon/webclipicon -->
    <link rel="icon" href="画像URL" sizes="16x16" type="image/png">
    <link rel="icon" href="画像URL" sizes="32x32" type="image/png">
    <link rel="icon" href="画像URL" sizes="48x48" type="image/png">
    <link rel="icon" href="画像URL" sizes="62x62" type="image/png">
    <link rel="shortcut icon" href="画像URL（.ico）" type="image/x-icon">
    <link rel="apple-touch-icon-precomposed" href="画像のURL">
    <meta name="msapplication-TileImage" content="画像のURL">

    <link rel="stylesheet" href="CSSファイルのURL">
    <script src="JavaScriptファイルのURL"></script>
</head>
```

詳しい内容説明に関しては下記参考文献を読んでください
https://saruwakakun.com/html-css/basic/head
https://moshashugyo.com/media/html-head
https://developer.mozilla.org/ja/docs/Learn/HTML/Introduction_to_HTML/The_head_metadata_in_HTML
Xeonは難しい

## はじめに
少し古いことを許せばネットで探すとサーバー用パーツを入手できる。なのでPC自作感覚でサーバー、ワークステーションを組むことができる。せっかく組みあがったら何よりベンチマークするわけだが計算用CPUで組むので一般的なレンダリング系ベンチに加えて倍精度計算系のベンチも試す。すると単精度性能と倍精度性能に違いが現れ結果XeonというCPUは難しいなぁ、と感じたので感想メモ書き。

## 使用したXeon CPU
使用したXeon環境は下記。
E5-2620 v3（6C、12T、ベースクロック2.4 GHz、ブーストクロック3.2 GHz）２基
E5-2699 v（22C、44T、ベースクロック2.2 GHz、ブーストクロック3.6 GHz）２基
Silver 4116（12C、24T、ベースクロック2.1 GHz、ブーストクロック3.0 GHz）１、２基
Gold 6152（22C、44T、ベースクロック2.1 GHz、ブーストクロック3.7 GHz）２基

## Cinebench2024
Cinebench2024のCPUマルチにおいて、これらの中で最もパフォーマンスが良かったのはE5-2699 V4で1807 cb、２位はGold 6152の1745 cb。これらはCore i9-13900Kよりも高スコアである。デュアルCPU環境でともに44 C、88 T。Gold 6152の方が世代が新しいのでこの結果は意外だった。
 ![Cinebench2024#1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3636689/2cca3e1a-f7ff-568e-8c27-9092c9b44801.jpeg)

下位に移るとSilver 4116 x 2（24 C、48 T）の953 cb　＞ Silver 4116 x 1（12 C、24 T）の542 cb ＞ E5-2620 v3 x 2（12 C、24 T）の503 cbとなり、こちらの順位は世代の新しいほうが高スコアになり、その通りかなと納得した。
![Cinebench2024#2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3636689/ccbef841-7309-8871-3613-e5ba9a1a2b5d.jpeg)

これらはレンダリング演算なので単精度計算スコアである。

## Quantum Espresso (AUSURF112)
倍精度計算ベンチには[こちら](https://qiita.com/k5884/items/bdd8403cce0403f74f62 "QE bench")と同じく密度汎関数計算プログラム[Quantum Espresso](https://qiita.com/k5884/items/bdd8403cce0403f74f62 "QE") ver. 7.0を用いた。Wall Timeは計算に要した時間なので短いほど演算パフォーマンスが高いことになる。
　結果は2 x Gold 6152（44 C、88 T） ＞ 2 x E5-2699 v4（44 C、88 T）＞ 2 x E5-2620 v3（12 C、24 T） ＞ 2 x Silver 4116（24 C、48 T）だった。
 ![QE.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3636689/03e456fb-8f10-fb19-d05a-5b999fe76c2a.jpeg)

Cinebench2024の結果と比較するとSilver 4116のパフォーマンスが悪く、倍精度計算能力が低いとわかる。Silver 4116 x 2のCinenench2024スコア（953 cb）とE5-2620 v3のスコア（503 cb）を比較するとSilver 4116 x 2はE5-2620 v3の約1.9倍高性能だ。これは単精度の場合であり、倍精度演算ではコア数やクロック数のみで計算能力を単純に予測できないとわかった。

## Xeon Silverとは
こちらの[サイト](https://www.idaten.ne.jp/portal/page/out/trendnews/latestcpu.html "Xeon")を参照するとXeon Silverシリーズは「中程度のタスク向けに最適化」されたCPUとある。おそらく倍精度計算能力を削り価格を下げたシリーズだろう。とはいえ倍精度計算で古い世代かつコア数半分のE5-2620 v3に惨敗した結果には自分の目を疑った。逆により高スペックXeonなら性能が上がるか？を試したいが使用したマザボの仕様によりGold 6152が上限のため今のところこれ以上確認できない。Silver 4116、Gold 6152などの初代Scalable XeonはAliexpressから比較的安価に入手できるのでマザボ交換を考えるか？とも思い始めている。あいにく予算がないので無理なのだが。

## 最近のXeonは難しい
Scalable Xeonは非常にたくさんのモデルがある。今回用いた第一世代の一覧は[こちら](https://www.hpc.co.jp/product/cpu_intel_xeon-scalable-processors/ "Xeon 1st")。何が違うのか？もわかりにくい。目的に合わせて最適なモデルを選択できるメリットがあるだろうが詳しくない人にとっては何を選べばよいか迷うだろう。使うプログラム、想定される負荷などをよく精査して詳しい人に相談というのが現実的な対応だろう。これに予算の制約が入ると選択が難しくなるばかりだ。
　ジャンカー感覚なら遊ぶ選択肢が多いのでとっかえひっかえ比べる、という遊び方もありうると思うが、実際にやってみようとするとCPU交換が面倒というかプラ製のCPUキャリアを割ってしまいそうな感じがする。頻繁なCPU交換が想定されていない設計なのだ。いろいろ難しい感じでした。
オペレーティングシステム　第4章 コンカレントプログラミング

キーワードのまとめです。

# 4. コンカレントプログラミング

### コンカレントプログラミング

- 複数の計算あるいはアルゴリズムを、同一期間に同時実行させつつ相互に同調（コンカレント）させて、次の期間開始までに互いに完遂させるという計算形態

### 抽象データタイプ

- タイプの名称の定義、それに許される操作と内部構造によって定義される

### 集中型システム

- 一つのコンピュータなどにのみ機能を依存している処理形態

### 分散型システム

- 複数のコンピュータなどに分散して機能を持たせる処理形態

### プロセス統合機構の使いやすさ

- プロセス統合機構のモジュール化の容易さ

### プロセス統合機構の表現能力

- プロセスがリソースをアクセスして良いかどうかの条件を記述する能力
- 表現能力は基本的には以下の二つの要素で決まる
    - 条件記述に許される演算の完全度
    - 条件記述に用いることのできる情報の種類

### ガーデドコマンド

- ガードは一種の命題であり、コマンドが実行される前に真でなければならない

### select文

- select文が現れると全てのガードが評価され、値が真である分岐の一つが選ばれて実行される

### パイプ

- メッセージの流れ路

### ストリーム

- メッセージの流れ路

### チャネル

- メッセージを伝達する媒介

### ポート

- メッセージを伝達する媒介

### 入出力文

- プロセス間のデータ転送命令

### 入出力スーパバイザ

- データチャネルおよび入出力機器のモニタ
- データチャネルや入出力機器の使用を制御するとともに、チャネルと入出力機器のスケジュリングを行う

### ロッキング

- MVSに後になって採用された手法
- ロックはBOOLEANセマフォアpp

### メッセージ転送

- オブジェクト間、またはプロセス間で情報を転送すること

### モジュール化

### モニタ

- オブジェクトモデルの一つの実現法
- 主に集中型システムにおけるリソース管理に用いられる
- 抽象データタイプにリソース管理に有効な機能と制約を備えたもの

### 条件変数

- 待ち状態の理由を区別するため、”条件”という変数の型を導入している
- 条件変数は、プロセスの待ち行列として実現する

### wait

### signal

### 多重モニタコール

- モニタが別のモニタのプロシージャを呼ぶこと
- 問題点として、デッドロックの可能性がある
    - 対策としては以下の方法がある
        - 多重呼び出しを必要としないようにオペレーティングシステムの構造を定める
        - プロセスが待ち状態に入った時、そのプロセスが保有している全てのモニタの所有を解除する
        - モニタ内にホール（モニタの所有が解除されてプログラムを自由に一時停止できる場所）を許す

### 非確定性

- select文で記述できる
    - select文が現れると全てのガードが評価され、値が真である分岐の一つが選ばれて実行される
    - もし複数の分岐が真である場合にはどれかが適当に選ばれる

### オブジェクトモデル

### パス表現

- モニタ機構の概念に基づき、宣言的にプロセス同期を指定する方式
- パスPascalの基本命令
    - ; 順序指定、プロシージャの実行は指定された順番で行えわなければならないことを規定
    - n:() リソースの制限、最大n個の同時実行が許されることを規定する
    - [] リソースの同時アクセス、[]内のプロシージャをどれかのプロセスが実行している限り、他のプロセスは[]内のプロシージャを同時に実行できることを示す

### 優先度

### リモートプロセデュア・コール

- 他のプロセスで定義されているプロシージャをリモートプロシージャという

### DP

- distributed process
- プロセス間通信をプロシージャで行う

### CSP

- communicating sequential process
- 出力（入力）コマンドの実行完了を別のプロセスの入力（出力）コマンドが実行されるまで待たせることにより同期を行う

### Adaタスキング

- Adaは抽象データ型を本格的に支援する汎用プログラミング言語
- 並列処理を本格的に支援する初めての汎用言語でもある

### Adaのランデブ

- Adaのプロセス同期機構

### スケジュリング

- Adaではユーザーが制御できる待ち行列はエントリ待ち行列のみであり、それらはFCFS（到着順）方式に基づいて処理される
- したがって優先度はユーザがwhen条件を用いて記述しなければならない

### タイムアウト

- delay文で記述する

```markdown
select
	accept A(...) do
	...
	end;
or
	accept B(...) do 
	...
	end;
or
	delay 5*MINUTES --タイムアウト
	...end select;
```

### プロセス故障

- プロセス統合機構は、一つのプロセスの故障が他のプロセスに波及しないようにすべきである
- プロセスの故障に関しては以下が重要
    - プロセスの故障検出
    - 故障からの回復
- 故障検出は以下の2種類の例外処理を規定するのが現実的な方法
    - 応答を返さないプロセスを検出するためのタイムアウト機能
    - プロセス進行中に生じる演算や処理の例外
Docker Networkでコンテナ間通信を実現しよう！

# 君もDockerコンテナ間で通信する方法に悩んでいないかい？

以前、コンテナ内のhost.docker.internalはホストPCのlocalhostと読み換えられるよ！という話をしていました ↓

https://thredot.org/threads/FRMEDFRPCL1708B7

しかしあれから

**Dev Container上の開発環境から、別コンテナのSQLサーバーにアクセスできない！**

という問題が度々発生してしまい頭をかかえることに
<br>

公式ドキュメントや技術ブログを色々と漁った挙句、どうやら

**Dockerコンテナ内から別コンテナにアクセスする場合はDocker Networkを使用したほうがよろしい**

らしく、
実際にコンテナ間接続の再現性が高い方法だったのでざっくり解説します

https://docs.docker.com/network/

## Docker Networkとは何？

簡単に言うと

**複数のコンテナを同じネットワーク内で利用出来るようにする機能**
<br>

例えば

- コンテナA （クライアント用）
- コンテナB （サーバー用）

がある場合、

コンテナAからコンテナB内のポート3000番に接続する際には

```text
http://[コンテナBの名前]:3000
```

と指定するだけで接続ができるというもの
<br>

便利ですね。

## 設定方法

今回はbridgeドライバを用いたDockerネットワークの設定を解説します

公式ドキュメントでは

- docker-composeを用いる方法
- コンテナそのもののネットワークとホストを同一化する方法

など他にも様々な方法が紹介されていますが、単純に複数のコンテナを繋げる用途であればこの設定で十分です
<br>

bridgeドライバが何かというと、つまり

**コンテナAとコンテナBのネットワークの橋渡し**

をうまいことやってくれるドライバ（文字通り）
<br>

設定の手順としては

1. Docker Networkを作成

2. コンテナAをNetworkに追加

3. コンテナBをNetworkに追加

を順番に行います

<br>

1 の「ネットワークを作成する作業」については次のコマンド

```bash
docker network create ネットワーク名 -d ドライバの種類
```

https://docs.docker.com/reference/cli/docker/network/create/

<br>

2, 3 で行う「ネットワークにコンテナを接続する作業」は次のコマンドで実現できます

```bash
docker network connect 1で作成したネットワーク名 接続したいコンテナ名
```

https://docs.docker.com/reference/cli/docker/network/connect/

<br>

したがって最終的なコマンドは以下のとおり

```bash
$ docker network create my-net -d bridge
$ docker network connect my-net コンテナAの名前
$ docker network connect my-net コンテナBの名前
```

上手く設定できていれば、コンテナAから

```text
http://[コンテナBの名前]:[ポート番号]
```

へ接続できるようになっているはず
（ポート番号はホスト側ではなく、コンテナB内側なので注意）

## なぜhost.docker.internalが動かないケースがあったのか？

不明です なぜでしょう

別コンテナのサーバーに繋がるケースもあれば、その逆も然り。

再現性が無く調査を諦めました。

（原因がわかる方は是非ともコメントで教えていただけると大変助かります）
<br>

ひとまず

- Docker Networkでは安定して接続できていること

- 開発用途であればあまり困らないこと

から、これからはDocker Networkを優先しようかなと思った次第です。

Dev Containerで環境構築コストがだいぶ下がっているので、せっかくならDocker Networkも自動化しておきたいですね

## 参考資料

https://thredot.org/threads/FRMEDFRPCL1708B7

https://docs.docker.com/network/

https://docs.docker.com/reference/cli/docker/network/create/

https://docs.docker.com/reference/cli/docker/network/connect/
WindowsのChromeからUbuntu(WSL2)へファイルなどをダウンロードする方法

# WindowsのChromeからUbuntu(WSL2)へファイルなどをダウンロードする方法

# はじめに

<!-- 発端や概要を記載 -->

- ChromeからnvimをWSL2のUbuntuにダウンロードしたいけど、ファイル選択画面もでてこず、勝手にWindowsのダウンロードファイルにダウンロードされて困った

# 環境

- windows
- WSL2
- Ubuntu22.04.3
- Chrome

# ゴール

- WindowsのChromeからWSL2のUbuntuにダウンロードする

# 解決策

1. Chromeの設定をいじって、Chromeからファイルをダウンロードするときにダウンロード先のフォルダを選択できるようにする
2. フォルダ選択の際に、Ubuntuのフォルダを選択できるようにショートカットを作成する
3. ダウンロードできる！

## 詳細

### Chromeの設定をいじって、Chromeからファイルをダウンロードするときにダウンロード先のフォルダを選択できるようにする
-  Chromeの設定画面を開く
       ![スクリーンショット 2024-02-25 224751.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3721421/c7613da7-4054-f829-e025-989951d7e2e7.png)

- ダウンロード → 「ダウンロード前に各ファイルの保存場所を確認する」をONにする

### Ubuntuのショートカットを作成する

- Windowsのエクスプローラーを開く
- 左のバーの下の方を見る
- ペンギンのアイコンと、「Linux」という文字を見つける
       ![スクリーンショット 2024-02-25 225236.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3721421/f8740289-ebc5-1fb1-9c01-433821409333.png)

        
    - トグルマークを押す
    - ダウンロードしたい先の場所を探す
        
        今回なら、ひとまずルートディレクトリにダウンロードできればいいので、
        Ubuntu-22.04/home/<user name>   （ここがUbuntuのuserのルートディレクトリです）
        
    - ダウンロードしたいフォルダを右クリック→クイックアクセスにピン止めする

### ダウンロードできる
Chromeからダウンロードを試してみる
フォルダを選択する画面が出てきて、クイックアクセスからUbuntuのフォルダを選択できる。

おしまい
【雑記】Next.jsでバージョンを指定するには？

# やりたいこと

この本( https://book.mynavi.jp/ec/products/detail/id=130848 )で使われているNext.jsが12系のようだが、最新版(240225時点)が14系らしく。色々異なっている様子。
まず、12にあるらしいpagesがなく、appになっているがディレクトリ名が変わっただけでなく、どうも振る舞いもかわっている。

そのため、初期状態の14系ではなく12系でできるようにしたい。

# 困ってたこと

バージョン指定がわからない

# やったこと
https://twitter.com/_noid11/status/1562683692765483009

とりあえず、以下を試してみた。

```
npx create-next-app@^12 my-app  
```

package.jsonを確認する。

```
{
  "dependencies": {
    "next": "^12.3.4"
  }
}
```

ん、できてる…？

localhostの画面は確かに12系の画面になってる。
ただ、 npm run dev を実行したときに14.1.0と出てくるのが気になる。。。


```
sakana10@pc my-app % npm run dev 

> my-app@0.1.0 dev
> next dev

   ▲ Next.js 14.1.0
   - Local:        http://localhost:3000

warning ../package.json: No license field
 ✓ Ready in 2.5s
 ○ Compiling / ...
 ✓ Compiled / in 991ms (233 modules)
```

ひとまず様子見かなぁ。

# 雑感
書籍を使って勉強するときのあるあるだけど、初期の環境構築にかなり時間を取ってしまった。

環境構築後は理解できる話が多いので、この後はスムーズに進んで欲しい。
「独学エンジニア」レッスン1

# レッスン1
今回はレッスン1にて学習したことになります。
## 学習するにあたって目指すゴール
このサービスでの目指すべきゴールは<b>「エンジニアとして自走できるレベルで就職する」</b>ことです。
僕はありがいことに既に就職しており、現場にも参加させていただいているので今回は「エンジニアとして自走しスキルアップすること」をゴールにします。
### そもそも自走するとは
　①自己学習を継続できる
　②課題に対して自分なりに調査し解決できる
　③障害や問題が発生した際に最低限の対応ができる
これら3つのことが<b>自走できる</b>の定義らしいです。

このコラムの中で、一番共感したのは「プログラミングの文法を学んだもののそれをどのように使用していくか」のスキルがないということです。これを聞いてものすごく頷きました。
自社研修や就職前のプログラミング学習でも写経や文法の勉強ばかりでそれをどのように使っていくのかを全く学ぶことができませんでした。その為、参画しても自分にはなにもできないという現実が待っていました。

## 受講後になっていたい姿
このコラムでは目標を具体的に書き出すことでモチベーションUPや辛いときに立ち返る場所としてプログラミング学習が挫折しないように以下の3つを実施しました。


<b>①長期的になっていたい姿（定性目標）</b>

プログラミングを学ぶことで長期的になっていたい姿、目標を書き出します。期間はいつでも良いのですが、2~3年後あたりが設定しやすいかと思います。ここでは、「なんのためにプログラミングを習得したいのか？」という、プログラミング学習のモチベーションの根本にあたる部分を明確にします。
例えば「場所に縛られずに働けるようになる」「新規サービスを作れるようになる」「プログラミングで稼げるようになる」などです。

<b>②受講後になっていたい姿（定性目標）</b>

本コースを受講完了した時になっていたい姿を書き出します。ここでは、「中期的にどうなりたいのか？」という定性的な達成目標を明確にします。受講中はここに書いた目標を目指していくことになります。自分のモチベーションが一番上がり、達成した状態をイメージしやすいものにしましょう。
例えば「エンジニアとして転職する」などです。

<b>③受講後の具体的状態（定量目標）</b>

2の目標を今度は定量的な指標にして書き出します。2だけですと定性的に書いているため、具体性に欠け、行動に落としにくいです。2の達成状態を定量目標として明確化することで、行動に繋げやすくします。ポイントは、期間を設けること、具体的に記載すること、達成したか計測可能であること、現実的に達成可能であること、です。
例えば「6ヶ月後に内定をもらっている」「4ヶ月後にポートフォリオができあがっている」」などです。

### ◆僕の目標としては下記の通りです。
①
・服が好きなのでファッションに関係するWEBサービスの開発に携われるようになる（自分で開発出来たら直良し）
・技術力/ヒューマンスキル共に信頼されて稼げるエンジニアになる
②
・現場の上長（先輩）からスキルアップしたことを認めてもらう
・現在の現場使用ツールについて他社に説明できるほどには理解を深めている
③
・半年後にはポートフォリオが出来上がっている（来季の査定面談でアピールできるようにする）

## コースを通じて作るもの
今回の学習を通して作る3つのものを簡単に紹介します。
### ◆ブラックジャックのゲームを利用して開発
習得スキル：PHPの基礎・オブジェクト指向
### ◆Wikipediaのアクセスログ解析システムの開発
習得スキル：SELECTやWHERE構文・テーブルJOIN・PHPとDBの連携・解析結果の表示
### ◆オリジナルアプリをフルスクラッチで開発（フレームワークを自作して開発）
習得スキル：素のPHPでのフルスクラッチ開発（フレームワークを使わずゼロからの開発）・フレームワークを利用したシステム開発

# まとめ
今回のレッスン1は学習を通してのゴールと目標の確認でした。
期間を明確にした目標を書きだしたことで自分に鞭打って進めることができそうです。さらにサボりそうなときや挫折しそうなときに振り返ってモチベーションを上げていきます。
◆独学エンジニアウェブサイト
https://dokugaku-engineer.com/course/serverside
Rubyで開発していた際にRuboCopで怒られた内容を纏める

## はじめに
rubyの静的解析ツールで有名なRuboCopとvscodeに以下の拡張機能を導入し、
rubyのコードを書いているときに出現したメッセージと必要な対応についてまとめます。
[ruby-rubocop-revived](https://marketplace.visualstudio.com/items?itemName=LoranKloeze.ruby-rubocop-revived)
### 想定読者
RuboCopで発生したメッセージ内容と対処法を探している方

## メッセージ一覧
### Missing frozen string literal comment.(Style/FrozenStringLiteralComment)

文字列リテラルを最初からfreezeした状態で生成してくれる、以下のマジックコメントが記載されてないときに出現します。

文字列リテラルを非破壊的にするメリットはそんなにあるのか？
については以下の記事が詳しく説明されておりました。
https://qiita.com/universato/items/1dd8943df07f2445655e

### Do not prefix reader method names with `get_`(Naming/AccessorMethodName)
アクセサーで使用されるprefixのため関数名でget_やset_を使用するのは非推奨のようです。

### Use xxxxx.positive? instead of xxxxx > 0.(Style/NumericPredicate)
1以上、0未満などの表現は大小比較ではなく、negative?やpositive?メソッドを使うのが好まれるようです。

### Use `Kernel#loop` for infinite loops.(Style/InfiniteLoop)
他の言語ではよく使われる無限ループの書き方while trueよりもloop doの使用が推奨されます。
どちらも無限ループとして実行は可能ですが、
whileの場合はループ内で宣言された変数がループ外でも使い続けることができるという違いが在るため、そういった面でも非推奨のようです。

## 終わりに
rubocop使用時に同様のメッセージが出てきて、調べている人の一助になれば幸いです。
今後も新たなメッセージが出たら追加していこうと思います。
【React】GoogleMap上で自由にカスタマイズされたピンを配置する

# はじめに
今回は、react上に描画されたGoogelMapへ好きなピン(＝コンポーネント)を配置する方法を紹介します

#### この記事でできるようになること
- mapに自由なコンポーネントを配置する

## 前提

- apiキーを取得できていて、react上に表示できているものとします
![スクリーンショット 2024-02-25 22.18.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2778030/e31f8bbf-03af-f3a7-8138-a9b303d79d54.png)

使用するパッケージ
- [@react-google-maps/api](https://www.npmjs.com/package/@react-google-maps/api) v2.19.2

## 本題

一般的に、GoogleMap上にピンを描画する際には、`MarkerF`コンポーネントを使用するものと思います。
しかしこの`MarkerF`、使用したことがある方はおわかりかと思いますが非常に自由度が低いものとなります。

クリックアクションや見た目のカスタマイズ等でかなりすぐ限界が来ます。
そこで代わりの方法となるのが、`OverlayViewF`を使用したピンの描画です。

![スクリーンショット 2024-02-25 23.05.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2778030/9ce02a8c-db0e-2beb-1561-87d5c11fcd32.png)

簡易的なコードを以下に記します。
```tsx
const Map: React.FC = () => {
    const [center, setCenter] = useState({ lat: 35.6894, lng: 139.6917 });
    return (
        <GoogleMap
            center={{ lat: center.lat, lng: center.lng }}
            zoom={12}
        >
            {Object.keys(mapObject).map((key) => {
                return (
                    <OverlayViewF
                        key={key}
                        position={{
                            lat: lat,
                            lng: lng,
                        }}
                        mapPaneName={OverlayView.OVERLAY_MOUSE_TARGET}
                        getPixelPositionOffset={(x, y) => {
                            return {
                                x: -(x / 2),
                                y: -y,
                            };
                        }}
                    >
                        <CustumMapPin />
                    </OverlayViewF>
                );
            })}
        </GoogleMap>
    );
};
```
この時、`CustumMapPin`はどんなコンポーネントでも大丈夫です。
`onClick`なども問題なく発火します。

`position`で地図上での位置を決めます。

`mapPaneName`でレイヤーを指定します。([ドキュメント](https://developers.google.com/maps/documentation/javascript/reference/overlay-view?hl=ja#MapPanes))

`getPixelPositionOffset`で、このコードでは`CustumMapPin`の表示位置を調整しています。

以下に型情報をコピーしておきました。
```ts
declare function OverlayViewFunctional({ position, bounds, mapPaneName, zIndex, onLoad, onUnmount, getPixelPositionOffset, children, }: OverlayViewProps): ReactPortal;
declare const OverlayViewF: react.MemoExoticComponent<typeof OverlayViewFunctional>;
```
注意としては、`MarkerF`と違いクラスター表示は一手間必要なようです...
うまいことできたら、また記事にするかもしれません。

## おわりに
お読みいただきありがとうございました！
役に立てば幸いです。

### ドキュメントや参考にさせていただいた記事など
https://note.com/suzukyu1201/n/nf1dd7731a5be#4cda3f4f-d620-4779-a7d4-92df1e1dfa85

https://developers.google.com/maps/documentation/javascript/reference?hl=ja

https://stackoverflow.com/questions/75674933/markers-and-overlayviews-not-reliably-showing-in-google-map-using-react-google

https://zenn.dev/renshimosawa/articles/6d3a5fa5d90cbf
アクセスキーリストを作成する

CloudShellに　アクセスキーを持っているユーザ一覧をリストアップする。
# IAMユーザーのリストを取得
users=$(aws iam list-users --query "Users[].UserName" --output text)

# 各ユーザーについてアクセスキーの有無を確認

```
for user in $users; do    
    # アクセスキーのリストを取得
    keys=$(aws iam list-access-keys --user-name $user --query "AccessKeyMetadata[].AccessKeyId" --output text)
    # アクセスキーが存在する場合、ユーザー名を出力
    if [[ ! -z $keys ]]; then
        echo $user
    fi
done
```
マウスポインタをPythonで自動化する（２地点間の移動）

PythonとChatGPTを駆使してマウスポインタの移動を自動化したい。
手始めに2地点間の移動を自動化できるかGPTに聞いてみたら以下のコードが返ってきた。

```python
import pyautogui
import time

def move_mouse_between_coordinates(start_coordinates, end_coordinates, duration):
    start_x, start_y = start_coordinates
    end_x, end_y = end_coordinates

    # 座標間の差分を計算
    delta_x = end_x - start_x
    delta_y = end_y - start_y

    # 移動先の座標を5秒ごとに計算して移動
    steps = int(duration / 5)  # 5秒ごとのステップ数
    for step in range(1, steps + 1):
        # 5秒ごとの座標計算
        current_x = start_x + (delta_x * step / steps)
        current_y = start_y + (delta_y * step / steps)

        # マウスを移動
        pyautogui.moveTo(current_x, current_y)

        # 5秒待機
        time.sleep(5)

# 例として、(100, 100) から (500, 500) までを5秒ごとに移動する場合
start_coordinates = (100, 100)
end_coordinates = (500, 500)
duration = 10  # 移動にかかる総時間

move_mouse_between_coordinates(start_coordinates, end_coordinates, duration)
```

ただこれを使うには、pyautoguiライブラリをインストールしておく必要があるみたい。

```bash
pip install pyautogui
```
指定された文字列からHTMLテーブルを生成する

Python 2.7を使用して、指定された文字列からHTMLテーブルを生成するスクリプトを作成します。このスクリプトは、入力されたブランチとバージョン情報を解析し、各ブランチについての詳細情報をHTMLテーブル形式で出力します。

```python
# 入力文字列
input_string = "ブランチ1/V00.01/a:100,b:100,c:100 ブランチ2/V00.02/a:200,b:200,c:200"

# 入力文字列を処理してデータを抽出
branches = input_string.split()
branch_info = {}

for branch in branches:
    parts = branch.split('/', 2)  # 最初の2つのスラッシュで分割
    name = parts[0]
    version = parts[1]
    data = parts[2]
    data_items = data.split(',')
    data_dict = {}
    for item in data_items:
        key, value = item.split(':')
        data_dict[key] = value
    branch_info[name] = {'version': version, 'data': data_dict}

# HTMLテーブルの作成を開始
html_output = '<table border="1">\n'
html_output += '  <tr>\n    <th colspan="2">ブランチ</th>\n'
for name in branch_info:
    html_output += '    <td>{}</td>\n'.format(name)
html_output += '  </tr>\n  <tr>\n    <th colspan="2">バージョン</th>\n'
for info in branch_info.values():
    html_output += '    <td>{}</td>\n'.format(info['version'])
html_output += '  </tr>\n'

# データ行の処理
data_keys = list(branch_info.values())[0]['data'].keys()  # Python 2.7では直接リストになる
for key in data_keys:
    html_output += '  <tr>\n'
    if key == list(data_keys)[0]:  # 最初のキーであればrowspanを設定
        html_output += '    <th rowspan="{}">機種</th>\n'.format(len(data_keys))
    html_output += '    <th>{}</th>\n'.format(key)
    for info in branch_info.values():
        html_output += '    <td>{}</td>\n'.format(info['data'][key])
    html_output += '  </tr>\n'
html_output += '</table>'

print(html_output)
```

このスクリプトは、指定された形式の文字列を受け取り、解析してHTMLテーブル形式で出力します。スクリプトはPython 2.7の文法に基づいていますが、`print`関数の使用や辞書のイテレーションなど、Python 3との互換性に注意する必要があります。Python 2.7では、辞書の`values()`メソッドがリストを返すため、直接インデックスを使用してアクセスすることが可能ですが、Python 3ではこの部分を`list(branch_info.values())[0]['data'].keys()`のように変更する必要があります。
daskで重いCSVファイルを処理する

ここでは、daskを使って重いCSVファイルをPythonで処理した話を備忘録的に記録します。

# Pandasで重いCSVファイルを処理するときに、たまに起こること
Pandasを使って重いCSVファイルを処理する際に、以下のようなエラーが発生することがあります。
私は最近、1億8000万行のECサイトのログデータに対して、各ユーザの各商品に対する閲覧回数を集約する計算を行ったところ以下のエラーが発生しました。

```python
The Kernel crashed while executing code in the current cell or a previous cell. 
Please review the code in the cell(s) to identify a possible cause of the failure. 
Click here for more info. 
View Jupyter log for further details.
```


原因としてはPCのメモリ不足などが考えられるのですが、メモリが少なくても大きなデータを扱いたいときがあります。

# daskで大きなファイルを分割して処理する

### daskとは
daskは並列分散コンピューティングのためのPythonライブラリです。
pandasと似たAPIを持つので、個人的にはかなり使いやすいです。

### 具体的なコード例
ここでは、daskを用いて、データを分割し処理するという方法を紹介します。

私自身あまり大きなデータを処理した経験がなかったのですが、今回紹介する方法で上の様なエラーを出さずに処理を完了させることができました。

以下に具体的なPythonのコードと説明を記載します。

```python
# daskのインポート
import dask.dataframe as ddf

# データフレームの読み込み
df = ddf.read_csv('data.csv')

# パーティション数の設定と再パーティションの実施
npartitions = 10
df = df.repartition(npartitions=npartitions)

# データをパーティションごとに処理
for partition in df.to_delayed():
    # daskデータフレームをpandasデータフレームに変換
    df_current = partition.compute()
    
    -------------------
    --- 行いたい処理 ---
    -------------------

    # メモリの開放
    del df_current
```

上記のコードでは、読み込んだデータに対して再パーティションを行っています。
パーティションとは、データテーブルを内部的に分割することです。
メモリ不足を引き起こさない様に自分でパーティション数を決め、再パーティションを行っています（daskでは読み込み時に自動的にパーティションされています）。
そして、for文でパーティションごとに分割されたテーブルを処理しています。
また、for文の終わりでは処理を行ったデータをメモリから解放しています。

これにより、メモリ不足を起こさずに処理を行うことができます。



# おわりに
今回は、daskによるデータの分割と処理の方法を自分用のメモを兼ねて紹介しました。
もっと良い方法がありそうなので、引き続き調査を行いたいと思います。
この記事が参考になった方がいらっしゃれば幸いです。
Pythonで342ABCのAを解いた結果

# はじめに

https://atcoder.jp/contests/abc342/tasks に参加しました。今回でコンテスト参加５回目です（まだ灰色）。
毎回Pythonで書いています（Python以外の言語はほぼ無知です）。


# A - Yay!
> https://atcoder.jp/contests/abc342/tasks/abc342_a

### 問題詳細
英小文字からなる文字列が与えられる。
１文字を除いて、すべて同じ文字で構成されている。
他の文字と異なる文字は、前から何文字目？

### 私の考え
１文字目と他の文字を比較して別の文字のindexを保持しよう。例外として１文字目のときだけ別処理しよう。文字列は１００文字以下なので計算量は問題ない。

### コード
```Python
S = list(input())

count_1 = 0
count_2 = 0

for i in range(1,len(S)):
    if S[0] == S[i]:
        count_1 += 1
    else:
        count_2 += 1
        index = i

if count_2 == 1:
    print(index+1)
else:
    print("1")
```

### 考察
A問題は深く考えずに解いたので、１文字目が別の文字のときの場合を例外処理にしました。
今考えると１、２、３文字目を比較して多数派の文字が今回全体の多数派であるという処理から始めるのがよかった気と思います。
jsarticleクラスの表紙書式の変更方法

## 結論

maketitleをdefで再定義する。

## デフォルトの書式

まずはデフォルトの書式を確認する
```
\documentclass[12pt,a4j,uplatex]{jsarticle}
%upLaTeX+jsarticleを指定
%フォントサイズは12pt、用紙サイズはA4
%用紙サイズにjを付けると日本のサイズになるらしいけどISOとJISのサイズは確か一緒
%(upLaTeX的には違うものだったような気もするが要確認。)

%デフォルトを確認したいのでプリアンブルでは表示させたい内容だけを記載

\title{up\LaTeX +jsarticleの表紙書式}
\author{kazuki}
\date{2024/02/25}
%\todayを使えばコンパイルの日時になるが、YYYY年MM月DD日とかにしようと思うとプリアンブルで定義する

\begin{document}
\maketitle
%表紙生成

up\LaTeX の場合dviで出てくるのでpdfに変換するためにdvipdfmx等を使う必要がある。
%表紙だけでは味気ないので適当な文章を追加。

\end{document}
```

コンパイル結果は以下の通りである。![default.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3722880/d246de8d-86c2-ee02-9ef5-c65ee9ee9479.jpeg)

デフォルト状態でもタイトル、筆者、日付が表示された後に本文が表示される。
論文の場合タイトルページに主要項目と合わせて概要を同じページに書くことが基本であるためこれでも十分である。しかし、概要は次ページに書く場合はこの出力では問題がある。

## デフォルトを弄らない程度の変更

上記状況(表紙は表紙として独立した体裁)の場合、以下のような要件を満たす必要がある~~ということにする~~。

1.  表紙にはページ番号を表示しない
1.  タイトル、筆者、日付の順番で用紙中央に配置すること
1.  日付はYYYY年MM月DD日形式で作成日を挿入すること
1.  概要等表紙以外の内容は次ページ以降に挿入すること

という場合、
```
\maketiltle
\thispagestyle{empty}
\newpage
```
と記載してページ番号を消してページを切り離せば上記要求を満たすことはできる。
しかし例えば画像(校章等の画像)や筆者、査読者等を表にして記載すること(~~罫線大好きな人が多いのは別の問題~~)、などという意味不明な(~~過去に固執する~~)人の言い分を聞かなければいけない場合には上記のように数行書き足すだけでは対応しきれない。

## デフォルトを弄る程の変更

さて本題である。デフォルト体裁では物足りない場合には
```
\makeatletter
```
と
```
\makeatother
```
の間で\maketitleの書式を再定義する必要がある。
(\makeatletterと\makeatotherについては[こちらの記事](https://qiita.com/alphalia/items/22f63b42483b541f66f4)から)

```
\documentclass[12pt,a4j,uplatex]{jsarticle}

\newcommand{\reviewer}[1]{#1}
%査読者の追加
%[1]{#1}でこの行より下の任意個所で引数を設定し代入可能

\makeatletter
%この中でmaketitleを再定義することで書式(体裁)を変更

\def\@maketitle{

%変更後の書式を通常のTeXの書式で記載
%makeatletter以前でusepackageを使用していればそれらのパッケージも使用可能
%画像、表、等の挿入や右寄せ、左寄せ、中央配置等ほぼ全てが使用可能

%以下は例

\begin{center}
{\Large \@title}
\end{center}
%タイトルを中央に配置

\begin{flushright}
\@date
\end{flushright}
%日付を右寄せで配置

\begin{center}
\@author \\
\@reviewer
\end{center}
%筆者と査読者を中央に配置

\thispagestyle{empty}
%ページ番号削除

\newpage
%改ページ

}%defの閉じ括弧

\makeatother

%以下は変更前と同様
\title{up\LaTeX +jsarticleの表紙書式}
\author{kazuki}
\reviewer{名無しの権兵衛}%3行目で定義したコマンドに引数を設定
\date{\today}

\begin{document}
\maketitle
%表紙生成

up\LaTeX の場合dviで出てくるのでpdfに変換するためにdvipdfmx等を使う必要がある。
%表紙だけでは味気ないので適当な文章を追加。

\end{document}
```

出力結果は以下のとおりである。
![change-0.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3722880/14a6cf0b-36dc-d9b8-689b-af7d9b0c251a.jpeg)
![change-1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3722880/1d7d01ce-97e5-33ec-02e5-e686f6cb4c13.jpeg)


2ページ目でページ番号が"1"ではなく"2"になっているが、これは1ページ目をカウントしているためである。
これの改善方法としては目次の次のページで、\setcounterでページ番号のカウンターを-1をするか、目次のページ番号をアラビア数字ではなくローマ数字に変更して本文のページをアラビア文字に変更する。
一般的な書籍でも目次と本文ではページの数字をアラビア数字とローマ数字等使い分けており、それに倣う形である。LaTeXの場合ページ数カウンターは数字の書式を変更するたびにリセットされるため、切り替え個所毎に1から始まる。

## まとめ

表紙書式の変更はmaketitleをdefで再定義する。ページ番号の整理等表紙だけで完結しない体裁の設定については別途設定する必要がある(目次の設定などもそのうち書くかも)。
Error: Hydration failed because the initial UI does not match what was rendered on the server.

# error
```
Error: Hydration failed because the initial UI does not match what was rendered on the server.
Warning: Expected server HTML to contain a matching <ul> in <p>.

```
# 原因
* NextJSとMUIを併用したため
* pタグの中にulタグが存在するため

# 真因
MUIのTypographyは、pタグによる実装。

# 対応
Typographyのタグのスコープを調整し、ulタグを内包しないよう調整。
WindowsでEdgeをアンインストールする方法

## はじめに
ほとんどEdgeを使わないので、次を参考にアンインストールしました。

https://www.neowin.net/guides/here-is-a-simple-method-to-uninstall-edge-in-windows-10-and-11/

その経験をもとに、少し手順を簡単にしてみました。ご利用は自己責任で。

## 手順
- 次からvivetoolのzipファイルをダウンロードする。

https://github.com/thebookisclosed/ViVe/releases

- ダウンロードしたzipファイルを右クリック→「すべて展開」をクリック→展開先を「`C:\vive`」として展開する。
- 管理者としてコマンドプロンプトを開く。
- アンインストールできるか確認するために、「`dir *.json`」と入力し[Enter]を押す。
- `IntegratedServicesRegionPolicySet.json`があれば、次の処理へ。なければ、Windowsをアップデートする。
- 次のコマンドをコピーして、管理者として開いているコマンドプロンプトに貼り付ける。
```bat
cd C:\vive
vivetool /enable /id:44353396
cd C:\Windows\system32
set TargetFile=IntegratedServicesRegionPolicySet.json
takeown /f %TargetFile% /a
icacls %TargetFile% /grant Administrators:F
notepad %TargetFile%
```
- `IntegratedServicesRegionPolicySet.json`がメモ帳で開くので、８行目の「`disable`」を「`enable`」に変更し、11行目の「`"AT"`」の前に「`"JP", `」を追加して上書き保存する。
```diff_json
{
  "$schema": "schemas/IntegratedServicesRegionPolicySet.Schema.1.0.0.json",
  "version": "1.0",
  "policies": [
    {
      "$comment": "Edge is uninstallable.",
      "guid": "{1bca278a-5d11-4acf-ad2f-f9ab6d7f93a6}",
-     "defaultState": "disabled",
+     "defaultState": "enabled",
      "conditions": {
        "region": {
-         "enabled": ["AT", "BE", "BG", "CH", "CY", "CZ", "DE", "DK", "EE", "ES", "FI", "FR", "GF", "GP", "GR", "HR", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MT", "MQ", "NL", "NO", "PL", "PT", "RE", "RO", "SE", "SI", "SK", "YT"]
+         "enabled": ["JP", "AT", "BE", "BG", "CH", "CY", "CZ", "DE", "DK", "EE", "ES", "FI", "FR", "GF", "GP", "GR", "HR", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MT", "MQ", "NL", "NO", "PL", "PT", "RE", "RO", "SE", "SI", "SK", "YT"]
        }
      }
    },
以下略
```
- Windowsを再起動する。
- 「スタート」→「設定」→「アプリ」→「アプリと機能」または「インストールされているアプリ」→「Microsoft Edge」の順で開いて行き、「アンインストール」がクリックできるようであればクリックしアンインストールする。クリックできなければ、「変更」→「修復」として、修復が終了すれば、設定アプリを終了させ、この項目の手順を最初から行う。
- まだ、`Microsoft.MicrosoftEdge.Stable`パッケージが残っているので、管理者としてPowershellを開き、次をコピー・貼り付け、パッケージを削除する。

```powershell
Get-AppxPackage Microsoft.MicrosoftEdge.Stable | Remove-AppxPackage
```

これで、Edgeがアンインストールできた。現在のところ不具合は出ていないが、今後どうなるか分からないので、実行は自己責任で。
Swift 5.9 可変長汎型 Variadic Genericsを使ってみる。

# 要点

次の引数の数を変えたオーバーロードを
```swift
func query<Payload>(
    _ item: Request<Payload>
) -> Payload

func query<Payload1, Payload2>(
    _ item1: Request<Payload1>,
    _ item2: Request<Payload2>
) -> (Payload1, Payload2)

func query<Payload1, Payload2, Payload3>(
    _ item1: Request<Payload1>,
    _ item2: Request<Payload2>,
    _ item3: Request<Payload3>
) -> (Payload1, Payload2, Payload3)

func query<Payload1, Payload2, Payload3, Payload4>(
    _ item1: Request<Payload1>,
    _ item2: Request<Payload2>,
    _ item3: Request<Payload3>,
    _ item4: Request<Payload4>
) -> (Payload1, Payload2, Payload3, Payload4)
```
次のようにまとめられる。
```swift
func query<each Payload>(_ item: repeat Request<each Payload>) -> (repeat each Payload)
```
次のように使用すると上記の`each Payload`に`Int`, `String`, `Bool`が順繰りに入る。
```swift
let results = query(Request<Int>(), Request<String>(), Request<Bool>())
```


上記コードは[WWDC2023の動画](https://developer.apple.com/videos/play/wwdc2023/10168/)から拝借。

- `each Payload` は型引数パック (Type Parameter Pack)。英文法に照らしてeachの後は単数型が適切
- `item`は値引数パック (Value Parameter Pack)
- `repeat`は繰返パターン(repetition pattern)。`repeat each Payload` の表記は、一連の具象型をコンマで区切った`Int, String, Bool`のような表記に置き換わる。そのためTupleや関数宣言の括弧`(...)`の中でのみ使用ができる

# 実験
下記コードをplaygroundにコピペすると挙動を確認できます。
(Swift5.9, Xcode 15.2で動作確認済)

```swift
// MARK: Protocol

protocol MockProtocol {
    associatedtype Value
    var value: Value { get }
    var description: String { get }
}

extension MockProtocol {
    var description: String { "\(value)" }
}

// MARK: Basic Structs

struct MockString: MockProtocol {
    let value = "I am MockString"
}

struct MockInt: MockProtocol {
    let value = 1
}

struct MockBool: MockProtocol {
    let value = true
}

// MARK: Tuple Struct

struct MockTuple<each V: MockProtocol>: MockProtocol {
    let value: (repeat each V)

    init(_ value: repeat each V) {
        self.value = (repeat each value)
    }
}

extension MockTuple {
    var description: String {
        let descriptionTuple = (repeat (each value).description)
        return "\(descriptionTuple)"
    }
}

// Mark: Implementation

func returnMockTuple<each T: MockProtocol>(_ t: repeat each T) -> MockTuple<repeat each T> {
    return MockTuple(repeat each t) // MockTupleB<Pack{MockString, MockInt, MockBool}>
}

returnMockTuple(MockString(), MockInt(), MockBool()).description // "("I am MockString", "1", "true")"
```

# 参考資料
https://developer.apple.com/videos/play/wwdc2023/10168/

https://zenn.dev/en3_hcl/articles/fd653e12e3b063
pyannote.audio 3.1 使ってみる

# pyannote.audio　のバージョンを3.1にあげてみる

### pyannote.audioとは
pyannote.audioは音声から話者ダイアライゼーション（話者分離）を行うライブラリ

### pyannote.audio 2.1からのバージョンアップ
```2.1の使い方
from pyannote.audio import Pipeline
pipeline = Pipeline.from_pretrained("pyannote/speaker-diarization@2.1",
                                    use_auth_token="ACCESS_TOKEN_GOES_HERE")
diarization = pipeline("audio.wav")
```

``` 3.1の使い方
from pyannote.audio import Pipeline
pipeline = Pipeline.from_pretrained(
  "pyannote/speaker-diarization-3.1",use_auth_token="HUGGINGFACE_ACCESS_TOKEN_GOES_HERE")

diarization = pipeline("audio.wav")
```

基本的な使い方は変わってない　っが・・・
おかしい。2.1の時は約1時間の音声ファイルの話者分離が3分程度で終わっていたのに、20分立っても終わらない・・・
どうやらGPUがちゃんと使われていないみたい

``` 3.1の使い方(GPUバージョン)
from pyannote.audio import Pipeline
pipeline = Pipeline.from_pretrained(
  "pyannote/speaker-diarization-3.1",use_auth_token="HUGGINGFACE_ACCESS_TOKEN_GOES_HERE")

import torch
pipeline.to(torch.device("cuda"))

waveform, sample_rate = torchaudio.load("audio.wav")
diarization = pipeline({"waveform": waveform, "sample_rate": sample_rate})
```

これで2.1の時と同じ3分程度で完了した。
3.1 ではどうやらtorch.deviceを明示的に指定と、オーディオファイルを事前にロードする必要があるみたい？

### おまけ　３.１の必要なライブラリ
```
pip install pyannote.audio==3.1.1
pip install pydub==0.25.1
pip install speechbrain==0.5.14
pip install soundfile==0.12.1
pip install lightning==2.0.1
pip install --no-cache-dir \
torch==2.2.0+cu121 \
torchaudio==2.2.0+cu121 \
torchvision==0.17.0+cu121 \
torchtext==0.17.0+cpu \
torchdata==0.7.1 \
--index-url https://download.pytorch.org/whl/cu121
```

### 参考ページ
https://huggingface.co/pyannote/speaker-diarization
https://huggingface.co/pyannote/speaker-diarization-3.1
【GraphQL Ruby】値が空文字の場合に null が返るように

# 結論

```ruby
class NilIfEmpty < GraphQL::Schema::FieldExtension
  def after_resolve(value:, **_rest)
    value.presence
  end
end
```

```ruby
class Types::BaseField < GraphQL::Schema::Field
  def initialize(*args, **kwargs, &block)
    super
    # NOTE: unwrap を使うと、String! のような null: false のフィールドでも if の中を通せる
    if type.unwrap == GraphQL::Types::String
      extension(NilIfEmpty)
    end
  end
end
```



# 背景など

Rails × GraphQL Ruby で GraphQL サーバーを実装していて、非必須な String 型のデータのためにDBレベルでカラムに空文字のデフォルト設定がついている場合、GraphQL のレイヤーで `null: true` としていても、値がない場合でも空文字が返ってしまいます。

クライアント側としては、型のある言語を採用している場合などは特に、非必須な String フィールドの値は「null でも空文字でもない値 or null」の形になっていると扱いやすいため、値がない場合には必ず null が返るようにしたいと考えました。

これを実現するため、DBレベルでデフォルト値の設定をしない、という方法があると思いますが、非必須なカラムで nil(null)
と空文字の両方を考慮する必要が出てくる、などの理由で、安易に踏み込めないのかなと思います（管理画面などの実装も同じ Rails アプリケーションで実現している場合などは特に...）

GraphQL のレベルで解決するとして、フィールドと同名のメソッドを定義し、`object.xxxxx.presence` みたいな処理を書けば一応実現はできます。ただ、すべての String 型フィールドでこのメソッドを定義するのは苦しいです。

そこで、上記コードのように Field Extensions と GraphQL::Schema::FieldExtension#after_resolve を使い、GraphQL::Types::String の場合は必ず `.presence` を通った値が返されるようにするのがよさそうに思いました。



# 補足

もし、空文字と null を区別したいフィールドが一部存在する場合は、そのフィールドだけでこの Extension を適用しないオプションを設定するのかなと思います。こちらは未検証ですが、ドキュメントを読む限りは、以下のように書くことができそうです。

```ruby
# ドキュメントからそのまま引用しています↓

class Types::BaseField < GraphQL::Schema::Field
  # @param custom_extension [Boolean] if false, `MyCustomExtension` won't be added
  # @example skipping `MyCustomExtension`
  #   field :no_extension, String, custom_extension: false
  def initialize(*args, custom_extension: true, **kwargs, &block)
    super(*args, **kwargs, &block)
    # Don't apply this extension if the field is configured with `custom_extension: false`:
    if custom_extension
      extension(MyCustomExtensions)
    end
  end
end
```



# 参考

- [Field instrumentation no longer working · Issue #3299 · rmosolgo/graphql-ruby](https://github.com/rmosolgo/graphql-ruby/issues/3299)
- [GraphQL - Field Extensions](https://graphql-ruby.org/type_definitions/field_extensions.html)
【FortiGate】IPSec-VPNモニタリング設定について

## IPSec-VPNモニタリング機能
VPN接続をする際に冗長性を持たせるためにメイン/バックアップの2つのトンネルを用意することがしばしばあります。
接続先の障害で切り替わりしますが、ルーティングのメトリックのようなIPでの確認切り替わりだけでなく、トンネルのダウンがおきた時点で可能な限りすぐに切り替わってほしいのでモニタリング機能を整理しました。

## 設定方法

### 基本設定
モニタリング設定は「vpn ipsec phase1-interface」内のインタフェース設定で行います。

```:設定例
config vpn ipsec phase1-interface
    edit "VPN_main"
        set interface "port1"
        set peertype any
        set net-device disable
        set proposal aes128-sha256 aes256-sha256 aes128-sha1 aes256-sha1
        set dpd on-idle
        set remote-gw x.x.x.x                   <-- メインセンタのリモートIP(GIP)
        set psksecret XXX
    next
    edit "VPN_backup"
        set interface "port10"
        set peertype any
        set net-device disable
        set proposal aes128-sha256 aes256-sha256 aes128-sha1 aes256-sha1
        set dpd on-idle
        set remote-gw y.y.y.y                   <-- バックアップセンタのリモートIP(GIP)
        set monitor "VPN_main"                  <-- モニタ対象のインタフェース
        set psksecret ENC XXX
    next
end
```

基本的な設定としてはバックアップ側の設定にモニタ対象のインタフェース名を指定することで有効になります。

### 復旧時の動作
バックアップに切り替わった後、メイン側が復旧したときの動作を指定できます。
冗長機能などではよく自動/手動の切り戻し方式が選択できますが、本機能は自動切り戻しだけになります。
切り戻しタイミングのみ設定可能です。

|タイミング|内容|
|:---|:---|
|即時(immediate)|すぐにメインに切り戻す|
|遅延(delay)|一定時間(秒)待機後、メインに切り戻す|
|時間指定(time)|指定した曜日(or 毎日)/時間になったらメインに切り戻す|

時間指定は説明だけだとわかりにくいので具体例を挙げます。

#### 例1 月曜日の昼(12:00)にバックアップに切り倒し、20時に復旧した場合
|設定|動作|
|:---|:---|
|毎日 0:00 |火曜日の0時に切り戻し|
|毎週月曜日 23:00 |当日の23時に切り戻し|
|毎週日曜日 0:00 |6日後の日曜日0時に切り戻し|

#### 例2 月曜日の昼(12:00)にバックアップに切り倒し、23時1分に復旧した場合
|設定|動作|
|:---|:---|
|毎日 0:00 |火曜日の0時に切り戻し|
|毎週月曜日 23:00 |翌週月曜日の23時に切り戻し|
|毎週日曜日 0:00 |6日後の日曜日0時に切り戻し|

#### 例3 月曜日の昼(12:00)にバックアップに切り倒し、翌日(火曜日)5時に復旧した場合
|設定|動作|
|:---|:---|
|毎日 0:00 |水曜日の0時に切り戻し|
|毎週月曜日 23:00 |翌週月曜日の23時に切り戻し|
|毎週日曜日 0:00 |6日後の日曜日0時に切り戻し|

---

### モニタリング設定値

|設定値|設定内容|デフォルト値|設定範囲|備考|
|:---|:---|:---:|:---:|:---|
|set monitor|モニタ機能の有効化、モニタ対象の指定|無(未設定)|インタフェース名を指定||
|set monitor-hold-down-type|モニター対象のトンネルが再接続した場合の回復時間方式|immediate|immediate：復旧後即時<br/>delay：一定時間待機<br/>time：指定日時待機||
|set monitor-hold-down-delay|復旧から切り戻しまでの待機時間(秒)|0|0～31536000|hold-down-typeが「delay」の時のみ設定可|
|set monitor-hold-down-time|復旧している場合の切り戻し時間|00:00|hh:mm (24時間表記)|hold-down-typeが「time」の時のみ設定可|
|set monitor-hold-down-weekday|復旧している場合の切り戻し曜日|sunday|everyday(毎日)<br/>sunday(日曜)<br/>monday(月曜)<br/>tuesday(火曜)<br/>wednesday(水曜)<br/>thursday(木曜)<br/>friday(金曜)<br/>saturday(土曜)|hold-down-typeが「time」の時のみ設定可|

## 補足事項
モニタリング機能を有効化した場合、メイン/バックアップのどちらか一つしか「UP」状態にすることができません。
切り倒しが発生したタイミングでメインは「DOWN」、バックアップが「UP」になり、メイン復旧後も切り戻しが発生するまでメインは「DOWN」のままになります。
※トンネルインタフェースのUP/DOWNを管理している場合は注意が必要です

## 参考
[Technical Tip: IPsec VPN: Site-to-Site tunnel monitor](https://community.fortinet.com/t5/FortiGate/Technical-Tip-IPsec-VPN-Site-to-Site-tunnel-monitor/ta-p/190643)
[FortiGate v7.0 CLI Reference](https://docs.fortinet.com/document/fortigate/7.0.0/cli-reference/370620/config-vpn-ipsec-phase1-interface)
【Linuxでバックグラウンド実行】nohupと&とbgの挙動の違い

Linuxでバックグラウンド実行といえば、「nohup hogehoge &」が定番ですが、単に&をつけた場合や、nouhpのみの場合、またbgの場合の挙動の違いを知りたく、動作確認してみました。

検証に使うコマンドは以下です。
jarファイルはspring bootプロジェクトを固めたもので、実行することによりtomcatが起動します。
```shell
java -jar sample.jar
```

# 動作確認環境
OS:CentOS Linux release 7.9.2009 (Core)
（サクラインターネットのVPS）

ターミナルソフト:RLogin

# 検証パターン

以下を試しました。
* パターン1 : ctrl + cを実行
* パターン2 : ctrl + cを実行せずにexitでターミナル切断
* パターン3 : ctrl + cを実行後にexitでターミナル切断
* パターン4 : ctrl + cを実行後ターミナルソフトの×ボタン押下
* パターン5 : ctrl + cを実行せずにターミナルソフトの×ボタン押下

なお、ターミナルソフトのウィンドウの×ボタンをクリックするのは褒められたものではないですし、ソフトによって挙動が変わることも十分考えられるため、あくまで参考程度です。

# 検証結果
横長になってしまうので、2つの表に分けました。
「パターン1 : ctrl + cを実行」は二重記載になってしまっていますがご容赦ください...

## パターン1、2、3
| 実行コマンド | ctrl+cを実行 | ctrl+cを実行せずにexitで切断 | ctrl+cを実行後にexitで切断|
|:-----------|------------:|:------------:|:------------:|
| java -jar sample.jar &       | プロセスは終了しない        | プロセスは終了しない | プロセスは終了しない |
| nohup java -jar sample.jar     | プロセスが**終了する**      |    （※コマンド入力が利かない）    | プロセスが**終了する**|
| nohup java -jar sample.jar &       | プロセスは終了しない        | プロセスは終了しない   |プロセスは終了しない |
| bg（※下記参照）       | プロセスは終了しない        | プロセスは終了しない         | プロセスは終了しない|

## パターン1、4、5
| 実行コマンド | ctrl + cを実行 | ctrl + cを実行後ターミナルを切断 | ctrl + cを実行せずにターミナルを切断 |
|:-----------|------------:|:------------:|:------------:|
| java -jar sample.jar &       | プロセスは終了しない        | プロセスは終了しない |　プロセスが**終了する** |
| nohup java -jar sample.jar     | プロセスが**終了する**      | プロセスが**終了する**       |プロセスは終了しない |
| nohup java -jar sample.jar &       | プロセスは終了しない        | プロセスは終了しない   |プロセスは終了しない |
| bg（※下記参照）       | プロセスは終了しない        | プロセスが**終了する**         |プロセスが**終了する** |

#### bgコマンドについて

bgコマンドは、一度フォアグラウンドで起動したものを、途中からバックグラウンドに切り替えるコマンドです。最初からバックグラウンド実行するものではありません。

まず
```shell
java -jar sample.jar
```
とフォアグラウンド起動しておいてから、ctrl + zで一時停止させた後、bgコマンドを実行します。
上記の一覧表は、bgコマンド実行後に確認したものです。

# まとめ

やはり
```shell
nohup java -jar sample.jar &
```
が最強。
SwiftUIで画面遷移をViewから剥がして独立させる

# 単にNavigationStackを使いやすくカスタマイズしただけです

## 注意
NavigationStackを使用するためiOS16以上をターゲットにしたプロジェクトが対象です。

## 課題
Viewに画面遷移の責務を持たせたくない

## 理由
・Viewに画面遷移の役割を持たせるのが責務として肥大化してしまうから
・筆者はUIKitを使用しての画面遷移の際にRouterクラスを作成してそこに画面遷移の責務を持たせる形に慣れ親しんでいたため

## 対応
### 使い方
```
// Stackさせるベースのところ
var body: some View {
    CustomNavigationStack(.home) {
        Text("Aの画面ですよ")
    }
}

class ARouter {
    // 遷移の仕方
    func navigateToB() {
        RouterPath.shared.addToHome(path: .home2)
    }
}
```

### 中身

```
struct CustomNavigationStack<Content>: View where Content: View {
    let pathType: RouterPathType
    @ViewBuilder let root: () -> Content
    
    @ObservedObject private var sharedRouterPath = RouterPath.shared
    
    var body: some View {
        switch pathType {
        case .home:
            navigationStack(path: $sharedRouterPath.homeRouterPath)

        case .profile:
            navigationStack(path: $sharedRouterPath.profileRouterPath)
        }
    }
    
    @ViewBuilder private func navigationStack<Data>(
        path: Binding<Data>
    ) -> some View
    where Data : MutableCollection,
          Data : RandomAccessCollection,
          Data : RangeReplaceableCollection,
          Data.Element : RouterPathProtocol
    {
        NavigationStack(path: path) {
            root()
                .navigationDestination(for: Data.Element.self)
        }
    }
}
```
```
class RouterPath: ObservableObject {
    static var shared = RouterPath()

    // このプロパティと下のRouterPathTypeが1対1になる
    @Published var homeRouterPath = [HomeRouterPath]()
    @Published var profileRouterPath = [ProfileRouterPath]()
    
    func addToProfile(newView: ProfileRouterPath) {
        profileRouterPath.append(newView)
    }
    
    func addToProfile(path: ProfileRouterPath) {
        profileRouterPath.append(path)
    }
}
```
```
enum RouterPathType {
    // ホームタブ
    case home
    // プロフィールタブ
    case profile
}
```
```
protocol RouterPathProtocol: Hashable {
    associatedtype Content: View
    var destinationView: Content { get }
}

enum HomeRouterPath: RouterPathProtocol {
    case home2
    case home3
    
    var destinationView: some View {
        switch self {
        case .home2:
            Text("home2編集")
        case .home3:
            Text("home3作成")
        }
    }
}
```
```View+Extension
extension View {
    func navigationDestination<D>(
        for data: D.Type
    ) -> some View where D : RouterPathProtocol {
        return navigationDestination(for: data) { path in
            return path.destinationView
        }
    }
}
```