OmniAICreator/Qiita-1.07M huggingface dataset:
YAGNI原則の誤解には注意

# YAGNI原則とは
YAGNIは「You Aren't Going to Need it」の略。
一言で言うと「機能は実際に必要となるまでは追加しないのがよい」という意味。

# YAGNIの読み方
YAGNI(ヤグニ)だと思います。
※けど、ヤゲニでも通じるはず

# 理解の仕方に注意
この原則は色々なサイトで色々な訳され方がされています。
例えばこちら、「必要なものは必要になったときに書きなさい」

ちょっと解釈の仕方を間違えると、以下のような理解にたどり着く可能性があり注意です。

「必要なものは必要になったときに書きなさい」 
	= 「必要なものは必要になったときに考えなさい」 
	= 「未来のことはその時に考えなさい」
	= 「未来のことは今考えなくていいよ」

**え、未来のこと考えなくていいの....😯？！**

# 本当にそうなのか？

YAGNIの本質は以下に羅列されています。
```
- きっと使う"だろう"という予測で作られた機能は、実際には10％程度しか使われない。
- 余分な機能があると、仕事に時間がかかり、リソースを浪費する。
- 余分な機能は設計を複雑化させ、予期しない変更が起こった時、より多くの変更コストを支払うことになる。
- 人生の時間は貴重である。ゆえに、コードを書くためではなく、現実の問題に集中するために費やすべきだ。
- コードをすばやく実装する最も良い方法は、余分なコードを書かないことだ。
- バグを減らすために最も良い方法も、余分なコードを書かないことだ。
```

使うかわからない余分な機能は、**デメリットが多いので実装する必要は無い**と説いています
未来のことを考えなくていいと言っているわけではありません。


# 結論

YAGNI原則はフレーズだけが1人歩きしてしまい、誤って理解してしまう可能性があります。
決して未来のことは考えなくていいというわけではありません🙅

確定している未来の事象や、現実化する可能性が非常に高い近未来のことは考慮して、ソフトウェアの構成要素（クラス、モジュール、関数）をコーディング・設計するべきです。
そうすれば、後々容易に追加や拡張をすることができるはずです。

# 参照

https://search-bank.net/article.php?id=596#1-0
チップマウンタソフトopenPnPのTRY

1.概要
最近仕事で実装を担当しチップマウンタを自作した。そのとき上手く結果が出せなかったず悔しい思いをしたためオープンソースのチップマウンタを趣味的に作ってみることにした。仕事のようにレポートでまとめれば良いのだが飽きないように日記形式で共有させて欲しい。
2.パーツ手配
パーツは0から作ることもできる（仕事でやったが工数大）がどうせ趣味なのでレーザーカッティングプロッタ組み立てキットを流用することにした。
![81cHLQ6LXwL._AC_SL1500_.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/243548/4007bcf1-566f-0ba4-e136-1649e0743dcf.jpeg)
https://amzn.asia/d/ea049Wc

次にopenPnPを動作させるPCを手配。CNCソフトのgrblのようにUSBシリアルだけのインターフェースならばメインPCで動かせば良いがカメラなどは別でUSBでつなぐはずなので結果PCとチップマウンタの配線が面倒になるのではと予想。最近？はミニPCなる便利なものがあると聞き試してみることにした。このミニPCをリモートデスクトップ接続でメインPCから操ればLAN経由なので配線0にできるはず。後述するがこれは購入ミス！
![61M9LzzfwpL._AC_SL1474_.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/243548/bacc7b34-5aac-707c-723a-f9a6f5dcbc7f.jpeg)
https://amzn.asia/d/07meN0k

あとはコントローラが必要。英語を頑張って読む（筆者はTOEIC300のクソバカ）とreprap系も表記があったが回路は互換が効かないことが多いのでケチらず本家おすすめのSmoothieboardというものを手配（￥18000!高かった）。
![51cPqCXWPBL.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/243548/f7822027-1d1c-0299-036f-1079cc91529c.jpeg)
https://amzn.asia/d/gDuinZd

手配から2日でまずはレーザーカッティングプロッタが届いた。組み立ては簡単。
その２日後くらいにミニPCが到着。しまった！win11 home editionだった。proでないとリモートデスクトップ機能が使えない。金の力でmicrosoftくんへ10k円ほど貢いでpro版へアップグレードした。トホホ...
他に手配するものは、、、なかなかまとまった情報がなくて困っていたがこのサイトを見つけた。
https://docs.opulo.io/
LumenPnPというもの。中身読むとopenpnpを制御ソフトとして使っているチップマウンタのキット。
読んでいくとヘッド用と下面用に２つカメラが必要みたい。配線、ワイヤリングに関する情報がなかったため調べるとこのサイトを見つけた。
https://github.com/openpnp/openpnp-openbuilds/wiki/Build-Instructions
これの最後らへんに丁寧に吸気系の配管まで書いてある。冒頭にはBOM(部品表)もあり良き良き。
いや、linkはほとんど切れてるし少し古いのかも。ヘッダツールもよく見る緑じゃないし。
この人のが新しい気がする。
https://hackaday.io/project/9319-diy-pick-and-place
左下にBOMへのlinkあり。カメラはUSB顕微鏡はクソなので買い替えたというようなことが書いてある。該当するカメラはこれ。
![d42ba4dc3eb0acffbfaa648ff05c579c.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/243548/73952962-06de-6bf5-9dfa-f0c0556df013.jpeg)
https://www.robotdigg.com/product/1140/OpenPnP-USB-Interface-1.0MP-720P-Vision-Camera

レンズは6mm　LED付きを手配しておくか。LEDは邪魔だったらはんだごてで取れば良いし。
あとはヘッダかなあ。うーむ、デュアルヘッダはどれも2万以上するなあ。なんなら自作したほうが安く済むのでは？というわけでリニアガイド100mmを手配。
![61JOrOwHM5L._SX522_.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/243548/c2a9c8bd-2755-4586-d027-cba94aa91bac.jpeg)
https://www.amazon.co.jp/gp/product/B07NCD7SMB/ref=ox_sc_act_image_1?smid=A1FILI8D7D93WU&th=1

次回はヘッダとリミットスイッチホルダーの設計をしよう

2023/1/22 記事投稿
【UserLAnd】AndroidでUbuntu環境構築

# はじめに
家にPCがないのでスマホ（Android）で開発環境を構築しようと考えました。

# 動作環境
* Sony Xperia 10 IV
* Android OS 12
* UserLAnd 3.1.4
* Ubuntu 20.04.5 LTS

# UserLAndをインストール
PlayストアでUserLAndを検索してインストールします。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3118198/a355083e-805f-e4be-e016-0a3e82e45769.png" width=50%>

# Ubuntuをインストール
UserLAndを起動してUbuntuをインストールします。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3118198/2070d28d-ee77-ccee-0017-1d94ae9e205a.png" width=50%>

# パッケージの更新
OSを最新の状態にするためパッケージを更新します。
```bash
$ sudo apt update
$ sudo apt upgrade
```

# Vimをインストール
初期状態ではエディタが入っていないのでVimをインストールします。
```bash
$ sudo apt install vim
```
Apacheを介して、NextJSプロジェクトにアクセスする

# Apacheを介して、NextJSプロジェクトにアクセスする。
NextJSのプロジェクト(next_app)をApacheを介して`/next/`として公開する。

|説明|パス|
|-----|---|
|NextJSのプロジェクトディレクトリ | /www/js/next_app/ |
|URL|http://xxx.local/next/

# 作業目的
1. クライアントとの通信プロトコルをHTTP/2にする試験(NextJSでHTTP/2カスタムサーバを作成した場合、処理の最適化がされないとの記事を読んだため)
1. 複数プロジェクトを同一サーバで動作させるときに、ディレクトリ名を変えて公開するための下調べ

# 作業内容
## Apacheにproxy設定を行う
:::note info
httpsで公開する場合はextra/httpd-ssl.confに追加する
:::
```httpd.conf
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so

ProxyRequests Off
<Location /next_test/>
    ProxyPass        http://localhost:3000/
    ProxyPassReverse http://localhost:3000/
</Location>
```
```
# systemctl restart httpd
```

## Nextのプロジェクトをビルドする
```
$ cd /www/html/next_app
$ vi next.config.js
```
```next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
    assetPrefix: "/next",
    basePath: "",
    reactStrictMode: true,
    images: {
        unoptimized: true
    },
}
module.exports = nextConfig
```
```
$ npm run build
$ npm start
```

## 備忘録
basePathはNextJSのプロジェクトディレクトリなので空白にする。
assetPrefixはbuildの生成結果が参照するディレクトリなので、`/next`を設定する。

これで、JS,画像ファイルのリンクは/next/で始まるので、Apacheから参照できる。
ミルクボーイのネタでGPT-3をファインチューニングしてみた (1) ~入門編~

ミルクボーイのネタをGPT-3に与えてファインチューニングし、漫才のような掛け合いができるか試してみます。

## 訓練データ作成
以下に訓練データの形式が書いてあります。
https://beta.openai.com/docs/guides/fine-tuning/prepare-training-data

```
{"prompt": "<prompt text>", "completion": "<ideal generated text>"}
{"prompt": "<prompt text>", "completion": "<ideal generated text>"}
{"prompt": "<prompt text>", "completion": "<ideal generated text>"}
...
```

という形式で準備する必要があります。

いい感じにprompt ➡︎ きっかけとなる文章、completion ➡︎ 続きの文章
のようなイメージです。

今回は駒場さんのセリフを打ち込むと、GPT-3から内海さんのような答えが返ってくることを目標とします。

ミルクボーイのネタで言えば、
```
{"prompt": "うちのオカンがね　好きな朝ごはんがあるらしいんやけど　その名前をちょっと忘れたらしくてね"
"completion": "朝ごはんの名前忘れてもうて　どうなってんねんそれ"},
{"prompt": "色々聞くんやけどな　全然分からへんねんな"
"completion": "分からへんの？　いや　ほな俺がね　おかんの好きな朝ごはん　ちょっと一緒に考えてあげるから　どんな特徴ゆうてたかってのを教えてみてよ"}
```
的な感じでしょうか。

[ひまぷっち | Marvelous Macho Making](https://himapucchi.com/)  様が、芸人さんのネタを文字起こししてくださっているので、そこからデータを拝借しました。
その中から、ミルクボーイの「コーンフレーク」「最中」「サイゼ」のネタからデータセットを作成してみました。
[【M-1グランプリ2019】ミルクボーイ「コーンフレーク」漫才ネタ書き起こし | ひまぷっち](https://himapucchi.com/m2019first-milkboy/)
[【M-1グランプリ2019】ミルクボーイ「最中」漫才ネタ書き起こし | ひまぷっち](https://himapucchi.com/m2019final-milkboy/)
[ミルクボーイ 「サイゼ」漫才ネタ書き起こし | ひまぷっち](https://himapucchi.com/milkboy-02/)

prompt ➡︎ きっかけとなる文章、completion ➡︎ 続きの文章 となるようにデータの選別をしました。(力技)

## ファインチューニング
公式ガイドに沿って実行していきます。
https://beta.openai.com/docs/guides/fine-tuning

### CLIコマンドインストール
```
pip install --upgrade openai
```

### APIキー設定
```
export OPENAI_API_KEY=“<OPENAI_API_KEY>”
```

### データ検証
```
openai tools fine_tunes.prepare_data -f dataset.json -q
```

### ファインチューニング
```
openai api fine_tunes.create -t dataset_prepared.jsonl -m davinci
```
ベースモデルは一番高性能のdavinciを利用しました。
各ベースモデルのコストについては以下を参照ください。
[Pricing](https://openai.com/api/pricing/#faq-fine-tuning-pricing-calculation)
今回はデータ数が少ないこともあり、ファインチューニングのコストは$0.80でした

今回はファインチューニング中で中断されませんでしたが、もし中断されてしまった場合は、以下コマンドで再開できるそうです。
```
openai api fine_tunes.follow -i <YOUR_FINE_TUNE_JOB_ID>
```

無事に完了しました。
```
Job complete! Status: succeeded 🎉
Try out your fine-tuned model:

openai api completions.create -m davinci:ft-personal-2023-01-22-07-35-43 -p <YOUR_PROMPT>
```


## 試してみる
```
openai api completions.create -m davinci:ft-personal-2023-01-22-07-35-43 -p "オカンが好きな朝ご飯を忘れたらしい->" 
```
上記を実行すると以下が出力されました。
```
オカンが好きな朝ご飯を忘れたらしい->朝ご飯忘れたとかそんなんどうでもいーのよ！
```

その他には以下のような結果が得られました。
```
でもちょっとわからへんのよな->何がわからへんのよ
晩ご飯で出てきても全然いいらしい->どうなってんねん！なにがそんなにも信用出来ないのよ
食べたら皮が全部上顎に引っ付くらしい->え？ 本当にひっくりかえる？
そやねん-> ほな、もうちょっと詳しく言ってくれる？
オトンが鯖缶ちゃうかて->コノヤロー、もうええわほんで！詳しく教えてくれるか？
```

会話にはなっていませんが、内海さんっぽい口調にはなってると思います笑

データ量が非常に少なかったので正直あまり期待していなかったですが、なんとなく関西弁っぽくなっているので、驚きました。

今回は実験的な試みなので、データ量増やしたくなったら、スクレイピングや動画の文字起こしなどを駆使してデータ量を増やしたいと思います。
Django-PostGIS(Docker-Compose)

# Django-PostGIS(Docker-Compose)
## 自分用の勉強メモ
######
自分用 : Docker folder 12

## 実行環境構築
### フォルダ構成
######
```
C:.
│  docker-compose.yml
│  Dockerfile
└─ requirements.txt
```

### docker-compose.yml
######
```yaml:docker-compose.yml
version: "3"
services:
  db:
      image: postgis/postgis:15-3.3
      ports: 
          - "5432"
      environment:
        - POSTGRES_DB=db
        - POSTGRES_USER=postgres
        - POSTGRES_PASSWORD=postgres
  web:
    build: .
    command: python manage.py runserver 0.0.0.0:8000
    volumes:
      - .:/code
    ports:
      - "8000:8000"
    links:
      - db
```

```dockerfile:dockerfile
FROM python:2.7
ENV PYTHONUNBUFFERED 1
RUN mkdir /code
WORKDIR /code
ADD requirements.txt /code/
RUN pip install -r requirements.txt
ADD . /code/
```

```text:requirements.txt
Django
psycopg2
```


### 実行する
```powershell:powershell
docker-compose run web django-admin.py startproject composeexample .
```

### フォルダ構成
######
```
C:.
│  docker-compose.yml
│  Dockerfile
│  manage.py
│  requirements.txt
│  
└─composeexample
        settings.py
        settings.pyc
        urls.py
        urls.pyc
        wsgi.py
        wsgi.pyc
        __init__.py
        __init__.pyc
```

### 設定を修正する
```py:\composeexample\settings.py
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'postgres',
        'USER': 'postgres',
        'PASSWORD': 'postgres',
        'HOST': 'db',
        'PORT': 5432,
    }
}
```

### 実行する
```powershell:powershell
docker-compose up
```

### 確認する
```http:http
http://localhost:8000/
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/438214/25dbbd4e-f65b-e982-a667-a9a237afa400.png)


### PostGISを有効化する
Databaseのコンテナに接続する
```powershell:powershell
psql -h 127.0.0.1 -p 5432 -U postgres
```

```sql:sql
CREATE EXTENSION postgis;
```

### テスト用のデータ作成
```sql:sql
CREATE TABLE test_gis (id serial primary key, name varchar(20), geom geometry(LINESTRING));

INSERT INTO test_gis (id, name, geom)
VALUES (
  1,
  'name1',
  ST_GeomFromText('LINESTRING(2 3,4 5,6 5,7 8)')
);

SELECT id, name, geom AS geom FROM test_gis;
```
引用元（一部加工編集）：[[docker] postgreSQL12 + PostGIS3 環境を作成する](https://www.hinomaruc.com/create-postgres12-postgis3-envionment-using-docker/)

######
参考＆引用：
[クイックスタート・ガイド：Compose と Django](https://docs.docker.jp/v1.9/compose/django.html)
[[docker] postgreSQL12 + PostGIS3 環境を作成する](https://www.hinomaruc.com/create-postgres12-postgis3-envionment-using-docker/)
[postgreSQLへのshp fileのimport](https://avinton.com/academy/importing-shp-files-to-postgresql/)
【参加レポート】Amazon Personalize 入門ハンズオン

# はじめに
JAWS-UG DE&I（旧名：JAWS-UG 関西女子会)にて開催された[Amazon Personalize 入門ハンズオン](https://jawsugkgirls.doorkeeper.jp/events/147142)に参加してきました。
会場はグランフロント大阪にある[アールスリーインスティテュートさん](https://www.r3it.com/)のオフィスです！

https://twitter.com/k_suzuki_pnx/status/1617025138700214272?s=20&t=Gu8hBt5NkjO_U7bMBTtALw
# Amazon Personalize 入門ハンズオン
講師はアマゾンウェブサービスジャパンの小林さん。

## Amazon Personalizeの概要説明
Amazon.comやAmazon Prime Video,Amazon Musicでも使われているパーソナライゼーション。

以下の観点でビジネスに貢献している。
- エンゲージメント
- 商品の発掘
- コンバージョン
- 売上

ただ実際にパーソナライゼーションを実現するには、モデルの構築やリアルタイム性スケーラビリティなど様々な観点で課題が発生する。
それを解決する助けとなるのが[Amazon Personalize](https://aws.amazon.com/jp/personalize/)
以下のような機能がある。
- ユーザ個々に対するレコメンデーション
- ユーザの嗜好に合わせて特定アイテムの並び替え
- 特定のアイテムに対する類似アイテムリストの提供

**どのユーザが、いつ、どのアイテムを閲覧したかという情報だけあれば利用可能**

また、ハンズオン中の会話に、ECサイト以外の使い方として、サポートサイトで「このドキュメントを見た人は、次にこのドキュメントをおすすめする」みたいな使い方ができるよねといった会話もありました。
社内ブログを運用している企業だと刺さる部分もありそうですね。
（費用対効果がどれくらいあるのかは分からないですが...）

Amazonのサイトみたいな構成を作ることができるワークショップも用意されているみたいです。
一回テンプレートを流してみて、それぞれのサービスがどんな感じで使われているのかを分解してみるのも面白いと思います。
https://github.com/aws-samples/retail-demo-store

構成図を見る感じ、ハードルは高め？w
![スクリーンショット 2023-01-22 15.36.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2109911/99f5e854-951b-fd63-ac32-efc85caf530a.png)

## ハンズオン
[AWS 公式の Getting Started](https://docs.aws.amazon.com/ja_jp/personalize/latest/dg/getting-started.html)のハンズオンを本のちょっと変更した内容。
映画のレビューデータセットを使ってユーザにおすすめの映画をレコメンド。

終わってすぐに消せば200円程度で済むハンズオンとのこと。
概要は以下のような感じです。
![スクリーンショット 2023-01-22 15.16.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2109911/7ada7e72-2fa1-a324-9ff8-6a16f35edeaa.png)
事前に用意されていた、ユーザとアイテム(映画)の情報をインポートして、そのデータを元に機械学習におけるトレーニングを実行。

ハンズオン中のコメントにソリューションとかキャンペーンとか名前が直感的に分かりづらいというのがありましたが、普段機械学習とかやっていればスッと理解できるものなんですかね。

# おわりに
初めてのAmazon Personalize
何となく使い方が分かりました！

現状直近で使うイメージが湧いていないですが、実際にアプリケーションと連携させてみるともっと使い道が見えてくるかなと思いました。
本記事の中で紹介した「[retail-demo-store](https://github.com/aws-samples/retail-demo-store/tree/master/workshop)」のワークショップをやってみたり、AWS Workshops Studioにある「[Amazon Personalize with Glue DataBrew](https://workshops.aws/categories/Machine%20Learning?tag=Personalize)」とかをやると理解が深まりそうです！
Webアプリケーション開発環境構築（Docker+VSCode）

# Webアプリケーション開発環境構築（Docker+VSCode）
## 自分用の勉強メモ

## 1.前提条件
* Windows 11 Pro

## 2.追加機能
* WSL2
* Docker Desktop
* VS Code

## 3.WSLを有効にする
### WSLのインストール
PowerShellを管理者モードで起動する。
```PowerShell:PowerShell
wsl --install
```
PCを再起動する。

ディストリビューションを一覧表示する。
```PowerShell:PowerShell
wsl -l -v
```

接続する。
```PowerShell:PowerShell
wsl
```

OSの情報を確認する。
```Linux:Linux
$ cat /etc/os-release
```

アップデートを行う。（たまに手動で行う）
```Linux:Linux
$ sudo apt update && sudo apt upgrade
```

###### 参考サイト
* WSL2のインストールと分かりやすく解説【Windows10/11】
  https://chigusa-web.com/blog/wsl2-win11/
* Install Linux on Windows with WSL
  https://learn.microsoft.com/en-us/windows/wsl/install

## 4.Dockerをインストールする
「Use WSL 2 instead of Hyper-V (recommended)」にチェックを入れたままにする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/438214/54e22994-d7b9-62d5-4680-f68d1a46343b.png)

設定を変更する。
「Start Docker Desktop when you log in」のチェックを外す。（ログイン時に起動しないように）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/438214/bbc33a3c-9917-3201-8442-4174b1918cbc.png)

起動する。
```PowerShell:PowerShell
docker run -d -p 80:80 docker/getting-started
```
ブラウザでアクセスする。
```
http://localhost/
```

###### 参考サイト
* 【Docker Desktop】Windowsにインストール（WSL2）
https://chigusa-web.com/blog/windows%E3%81%ABdocker%E3%82%92%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E3%81%97%E3%81%A6python%E7%92%B0%E5%A2%83%E3%82%92%E6%A7%8B%E7%AF%89/

## 5.VS Codeをインストールする
以下を追加する。

* Japanese Language Pack for Visual Studio Code
* Prettier - Code formatter
* indent-rainbow
* Material Icon Theme
* zenkaku
* Dev Containers

###### 参考＆引用：
* 【VS Code】インストール手順を解説 【Windows/M1 Mac対応】
https://chigusa-web.com/blog/vs-code-install/
* Download Visual Studio Code
  https://code.visualstudio.com/download
* 【VS Code】オススメの設定・拡張機能・便利機能・ショートカット【Win/Mac対応】
https://chigusa-web.com/blog/vs-code%e3%81%ae%e3%82%aa%e3%82%b9%e3%82%b9%e3%83%a1%e3%81%ae%e8%a8%ad%e5%ae%9a%e3%83%bb%e6%8b%a1%e5%bc%b5%e6%a9%9f%e8%83%bd%e3%83%bb%e3%82%b7%e3%83%a7%e3%83%bc%e3%83%88%e3%82%ab%e3%83%83%e3%83%88/
* 【VS Code】Dockerコンテナの環境でリモート開発【Win/Mac】
https://chigusa-web.com/blog/vs-code%e3%81%a7docker%e3%81%aepython%e7%92%b0%e5%a2%83%e3%81%a7%e3%83%aa%e3%83%a2%e3%83%bc%e3%83%88%e9%96%8b%e7%99%ba/
* 【図解】VScodeのRemote Container拡張機能とは？わかりやすく
https://penpen-dev.com/blog/vscode-remote-container-toha/
wsl2でubuntu18.04LTSからubuntu20.04LTSにdo-release-upgradeする時の注意点

# 問題
wsl2でubuntuのOSのバージョンを上げたいので，以下のコマンドを実行するとエラーが表示されて進まなかった
```
$ sudo do-release-upgrade

...
...
...

===Command terminated with exit status 1===
```

# 解法
ubuntu18.04LTSにインストールされているsnapが原因で，エラーになることがあるみたい
以下のコマンドでsnapを削除してもう一度バージョンを上げてみる
```
$ sudo apt remove snapd
```
M1MacでFlutterのセットアップしているときにJavaが認識しなかった時の対応

<h1>FlutterのセットアップでJavaが認識しなかった時の対応

<h3>・はじめに

M1Macを入手した時にFlutter doctorでエラーが出た時に躓いたのでメモ代わりに投稿。

<h3>・環境

Mac OS 13.1
Flutter version 3.3.10
Android Studio (version 2022.1)
Platform android-33, build-tools 33.0.1
*Xcode類は省略

<h3>・発生したエラー

「✗ Unable to find bundled Java version.」
ググってみるとAndroid Studioで使いたいJavaがMac上の物と繋がっていないってエラーが出ているみたいでした。

<H3>対応

1./Applications/Android\ Studio.app/Contents にjreフォルダーを作成
2./Applications/Android\ Studio.app/Contents/jbrの中身をjreにコピー
3.flutter doctor コマンドで状態を再確認

自分の場合は上記対応でflutter セットアップが完了できました。

---
<h3>参考サイト

[Unable to find bundled Java version(github) ](https://github.com/flutter/flutter/issues/118502)
Hi5 2.0のいじり方

# はじめに
Hi5 2.0グローブを買いました。Unity SDKが提供されているので使用しましょう。

https://note.com/gpsnmeajp/n/ndf38083d5eda

# SDKのサンプルを動かす
動かすだけであれば

+ Hi5_2_Package_Vive_V1.1.0.23.unitypackage (アユート様サポートページで配布)
+ steamvr_2_7_3.unitypackage (SteamVR Plugin)

を入れます。

SteamVRのセットアップは普通にやります。

Assets\NoitomHi5\Scenes\Example_Inertia.unity を開きます。
起動するとSteamVRが起動しますが、Hi5 2.0さえ接続していれば、特にコントローラやVIVEトラッカーは無くても動きます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191114/dbb74e64-6098-9353-43c8-3b6f168afbc9.png)

Hi5_Left_Hand, Hi5_Right_Handが手のモデルです。

# 指の開き具合を有効にする
Hi5_Thread_MonoBehaviourのIs Enable Finger Fixedをオフにします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191114/86537e4d-e07b-9df6-f726-c8d5f8f414a4.png)

# 指の姿勢がおかしいとき
手を静止させた状態で再生を行い、認識したらキャリブレーションを実施します。
様子がおかしいときは、停止して少し待ってから、可能な限り手を静止させて再生を押すと良いです。認識するまで動かなさないようにします。

# 続く...

https://twitter.com/Seg_Faul/status/1618616759417995265?s=20&t=aedV5Llv-B1Tp_u-prLMYg
Googleプロジェクト管理：プレゼンテーションをアクセシブルにする

# はじめに

わたしが [Google プロジェクト管理:プロフェッショナル認定証で得られた素晴らしい体験][google]を、要点をまとめ小さく分割して、わかりやすく簡潔に紹介していきます。

興味があれば、ぜひ ***"Google プロジェクト管理:プロフェッショナル認定証"*** を受講してみてください。

[google]: https://qiita.com/mapami/items/317ae776a2268fd54c8f

https://jp.coursera.org/professional-certificates/google-project-management

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2358573/dc97f9d2-8c30-5310-a190-3fb484c9c091.png" width="800">


ここでは、アクセシビリティを成功させるためのヒントを、プレゼンテーションのデザインから紹介します。

# Create clear, simple slides

まず、***<font color="MediumVioletRed">明確でシンプルなスライド</font>*** を作成します。多すぎるグラフィック、多すぎるテキスト、多すぎるアニメーションを使用することは避けてください。視覚的な複雑さは、特に視覚障害者や認知障害者にとって、プレゼンテーション中の情報吸収を難しくします。スライドにアニメーションを使用する場合は、重要なコンテンツが消えてしまい、人々を置き去りにしないように注意してください。読むのが遅い人や通訳に頼っている人は、内容を吸収するのに少し時間がかかるかもしれません。点滅やフリッカーのような反復的なアニメーションは、気が散って発作を誘発する可能性があるため、使用しないようにしましょう。

しかし、シンプルだからといってつまらないというわけではありません。シンプルなスライドでも、美しく、有益なものになります。ただ、1枚のスライドに多くの情報やアクティビティを詰め込もうとしないことです。普段、講演でスライドを使わない人も、要点をまとめたスライドを1枚作るだけでも、試してみてください。音声だけ、つまり視覚的な補助がない場合、言葉の壁や聴覚・認知障害のために、理解するのが難しい人がいるかもしれません。

# Add alt text for images, drawings, or diagrams

画像や絵、図には ***<font color="MediumVioletRed">「altテキスト」</font>*** と呼ばれる代替テキストを入れるのもポイントです。そうすることで、スクリーンリーダーを使用している人々がアクセスできるように、グラフィックで伝えられている情報を説明します。

:::note info
GoogleスライドやPowerPointでaltテキストを追加するには、オブジェクトを選択して右クリックし、"altテキスト "を選択するだけです。同じ配慮が、チャートにも適用されます。
:::

特に、より多くのデータを収めるために小さなフォントを使用している場合、グラフを解読するのは難しいかもしれません。スライドにデータの多いチャートやグラフが含まれている場合は、スライド自体かスピーカーのノートに、必ずテイクアウェイを明記してください。

# Use text for critical information

次に、***<font color="MediumVioletRed">重要な情報には必ずテキスト</font>*** を使用することです。図表やスライドの重要な情報を伝えるのに、色やその他の視覚的なフォーマットだけに頼ってはいけません。視覚的なフォーマットに頼りすぎると、色盲の人や画面を見ることができない人を排除することになります。例えば、フローチャートの新しいセクションを強調するために、単に色を変えるだけではいけません。

色の変更と同時に、"new "のような文字による合図を追加します。画像に頼る部分が多い場合は、プレゼンテーションの最後に要約を書き、要点をまとめて簡単に読めるようにすることも検討しましょう。

# Provide captions for all audio or video recordings

もう一つのコツは、ビデオコンテンツやリアルタイムでキャプションを入れることです。プレゼンテーションで共有されるすべてのオーディオまたはビデオの録音にキャプションを提供します。

プレゼンテーションでリアルタイムキャプションが利用できる場合は、それを利用します。リアルタイムキャプションは、耳の不自由な聴衆を助けるだけでなく、会場内にさまざまなアクセントや言語がある場合、プレゼンターが早口で話す場合、マイクに問題がある場合、おしゃべりな聴衆がいて隣の人の気が散ってしまう場合にも有効です。

# For contract and text size, more is better

もうひとつ覚えておきたいのは、コントラストと文字サイズです。文字と背景色の差をコントラスト比といいます。コントラスト比が高いと、特に遠くに座っている人や弱視・色盲の人がテキストを読んだり画像を解読したりしやすくなります。理想的なコントラスト比は ***<font color="MediumVioletRed">7:1</font>*** です。コントラストチェックのツールもありますので、ぜひお試しください。

文字サイズの推奨値はさまざまですが、 ***<font color="MediumVioletRed">通常は大きいほうがよい</font>*** でしょう。プレゼンテーションが始まる前に、部屋の後方に行き、スライドが読めるかどうか確認しましょう。また、すべての大文字を使用すると、失読症の人など、一部の人にとってテキストを読むのが難しくなります。可能な限り、すべて大文字の使用は避けましょう。これは簡単な変更ですが、大きな効果があります。

# Share content in advance

可能であれば、プレゼンテーションの数日前にスライドを聴衆に送信してください。 これにより、聴衆は内容を確認し、必要であれば、各自のニーズや好みに合わせてアレンジすることができます。例えば、視覚に障害のある聴衆は、画面読み上げソフトを使って自分のデバイスでスライドを追いかけたいと思うかもしれません。

スライドを事前に共有できない場合は、プレゼンテーションのアウトラインを箇条書きにした文書を送信することを検討してください。頭字語や技術的な用語、わかりにくい用語を使用する場合は、定義を記載した用語集を同封してください。この情報は、特に手話通訳者やキャプション担当者に役立ちます。
Django-PostgreSQL（Docker-Compose）

# Django-PostgreSQL（Docker-Compose）
## 自分用の勉強メモ
######
自分用 : Docker folder 11

## 実行環境構築
### フォルダ構成
######
```
C:.
│  docker-compose.yml
│  Dockerfile
└─ requirements.txt
```

### docker-compose.yml
######
```yaml:docker-compose.yml
version: "3"
services:
  db:
      image: postgres
      ports: 
          - "5432"
      environment:
        - POSTGRES_DB=db
        - POSTGRES_USER=postgres
        - POSTGRES_PASSWORD=postgres
  web:
    build: .
    command: python manage.py runserver 0.0.0.0:8000
    volumes:
      - .:/code
    ports:
      - "8000:8000"
    links:
      - db
```

```dockerfile:dockerfile
FROM python:2.7
ENV PYTHONUNBUFFERED 1
RUN mkdir /code
WORKDIR /code
ADD requirements.txt /code/
RUN pip install -r requirements.txt
ADD . /code/
```

```text:requirements.txt
Django
psycopg2
```


### 実行する
```powershell:powershell
docker-compose run web django-admin.py startproject composeexample .
```

### フォルダ構成
######
```
C:.
│  docker-compose.yml
│  Dockerfile
│  manage.py
│  requirements.txt
│  
└─composeexample
        settings.py
        settings.pyc
        urls.py
        urls.pyc
        wsgi.py
        wsgi.pyc
        __init__.py
        __init__.pyc
```

### 設定を修正する
```py:\composeexample\settings.py
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'postgres',
        'USER': 'postgres',
        'PASSWORD': 'postgres',
        'HOST': 'db',
        'PORT': 5432,
    }
}
```

### 実行する
```powershell:powershell
docker-compose up
```

### 確認する
```http:http
http://localhost:8000/
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/438214/25dbbd4e-f65b-e982-a667-a9a237afa400.png)


######
参考＆引用：
[クイックスタート・ガイド：Compose と Django](https://docs.docker.jp/v1.9/compose/django.html)
Corrupt node-revision node-revにID情報がありません

SVNで下記のエラー
**Corrupt node-revision node-revにID情報がありません**
（Missing id field in node-rev）

**【原因】**
直近コミットのリビジョン情報が壊れていると思われる。
（※何度も不定期で発生したが、いずれも原因は不明。）

**【対応】**
サーバから対象のrev情報を削除する。

①下記にアクセス
サーバIPアドレス/foo **/repos/db**

②ファイル「current」を開き、最新リビジョンNoを確認

③repos/db/revsから最新リビジョンNoと一致する番号のファイルを削除
※対象コミット内容が削除されるので、事前に退避させておく

④currentを開き、数字を1引いた値に書き換えて保存

⑤reposに移動

⑦下記コマンドを実行（エクスプローラのアドレス欄に打ち込み）
svnadmin recover .

⑧下記コマンドを実行（エクスプローラのアドレス欄に打ち込み）
svnadmin verify

Verifyung metadata at revision .....
↓
Verified revision ...
と表示されていきます。
※リビジョン数が多いとその分時間がかかります。

エラーが出なければOK。

その後退避させておいたファイルをコミットして掲題のエラーメッセージは解決となります。
（ただし最終コミット者のローカルリポジトリが壊れている場合（たまにある）は、別途別フォルダにチェックアウトし直してコミットするか、または別のアカウントからコミットする必要がある）
Laravelでフォームの値を一時的に保持する方法（_old_inputが便利）

# はじめに
以前Laravlを使った時に、フォーム入力後の遷移したページに「入力をやり直す」ボタンを置いて、それを押したらフォーム入力欄に入力値が入力された状態で戻して欲しいと言われました。

何となく簡単そう・・・ではなかった。。。
意外と難しかったので、（ベストな方法ではないかもしれないですが）それについて書きます。
良い方法があれば知りたいのでコメントで教えて下さい！

# 実現したいこと
①ページAで、フォームを入力してそれをpostする
②ページB（確認画面）で「（入力を）やり直す」ボタンを押す
③入力値が保持された状態でページAへ遷移する
（バリデーションエラーの時のような挙動です！）

# 結論
下記の方法で、一時的に入力値を保持することができます。
①**セッションの_old_input**に入力値を保存する
```php
        $request->session()->flash('_old_input',[
            'hoge' => $hoge,
            'fuga' => $fuga,
        ]);

        return redirect()->route('pageA');
```
②ページAでoldヘルパーを使って取得する。
```php
<input name="hoge" type="text" value="{{ old('hoge') }}">
```

# 少し解説
どうやって実現しているかというと、Laravelのoldヘルパーとvalidationの仕組みを利用しました！
（oldヘルパーを利用するとバリデーションエラーになったときに、フォームの値を保持してくれます）

説明のために、oldヘルパーとバリデーションについて少し触れておきます。

## oldヘルパーとバリデーションの仕組み（簡易版）
まず、bladeファイル側で、バリデーションエラーになったときに、値を保持しておきたい項目のvalue属性に「**name属性の値**」と同じ引数を渡して設定します。
```php
<input type="text" name="hoge" value="{{ old('hoge') }}" >
<input type="text" name="fuga" value="{{ old('fuga') }}" >
```
上記のように書いて、Laravelのコントローラーにリクエストしてバリデーションエラーとなった場合、

セッションの”_old_input”という項目にリクエストした値が、「name属性の値」で入っています。そしてリクエストがあった画面へ戻されます。
その値をoldヘルパーの引数に「name属性の値」を設定することで取得することができます。

因みにblade側でこんな感じで_old_inputを取得出来ると思います。
```php
session()->get('_old_input')
```

## 今回どのように乗り切ったか
blade側で、フォームにoldヘルパーを書きます。
まずページAからpostされたタイミングで、コントローラー内で入力値をセッションに保存しておきます。
```php
        $request->session()->put([
            'hoge' => $request->hoge,
        ]);
```

もし、ページB内で「入力からやり直す」ボタンを押した時は、（コントローラー側で）_old_inputに先程セッションに保存した値を保存してページAに遷移させます。
```php
        $request->session()->flash('_old_input',[
            'hoge' => $request->session()->get('hoge')
        ]);

        return redirect()->route('pageA');
```

もし、ページB内で「確定して送信」ボタンを押したときは、（コントローラー側で）セッションに保存されているフォームの入力値を削除します。
```php
        $request->session()->forget('hoge');
        $request->session()->save();
```

# 最後に
Laravelの知見が浅く、ベストな方法ではないと思うので、より良い方法があれば是非コメントで教えて下さい。
TextMeshProUGUIで表示したTextの最後の位置を取得する方法

# 概要

Unityの`TextMeshProUGUI`コンポーネントで`Text`を表示する際に、最後の文字の位置を取得したいと思ったことはありませんか？（ノベルゲームの末尾に点滅するアイコンを表示したいなど…）

今回紹介する手法を用いることで、末尾に任意の`RectTransform`を追従させることが出来るようになります。

※今回は **左上詰め** のテキストに追従させていますが、
`Anchor`や`Pivot`位置、スクリプトを調整することで任意方向に詰めたテキストにも応用できると思います。


![test2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/701843/a6e34b04-a587-1002-d1f5-7b157ec3c860.gif)

# 動作環境
Unity 2021.3.6f1
TextMeshPro 3.0.6

# セットアップ

![スクリーンショット 2023-01-22 151612.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/701843/0253dd73-9a50-bb58-706f-54e45f94f869.png)
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/701843/d25de60e-7a61-4278-516e-3e1a3a318cb4.png)

### Back
背景用の`GameObject`です。
`Image`と共に、今回作成したスクリプトをアタッチしています。

### Text(TMP)
テキストを表示する`GameObject`です。
`RectTransform`の設定は、末尾に表示する画像等を考慮して右側を少し広めに取っています。
`TextMeshProUGUI`は **左揃え** かつ **上揃え** に設定しています。 

### Marker
末尾に追従させる`GameObject`です。
`RectTransform`は **左上を基準** に設定し、位置の微調整は **Pivot** で行います。
また、今回はアニメーションも指定しています。

# 惜しい実装例

よく紹介されている手法として、`PreferredWidth`、`PreferredHeight`を利用する手法があります。

```csharp
[SerializeField] private TextMeshProUGUI _text;
[SerializeField] private RectTranform _marker;

private void Update(){
    var x = _text.preferredWidth;
    var y = _text.preferredHeight;
    _marker.anchoredPosition = new Vector2(x,-y);
}
```

![test1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/701843/894b36c3-7607-7f8e-a01f-b16ec92f91b2.gif)

しかしこの方法では、テキストの **最大横幅** と **最大縦幅** を取得しているため、改行が入ると正しく動作しません。
（また、`Wrapping`の設定がONだと、自動改行時に`preferredWidth`だけがドンドン大きくなるなど…）

# 提案する実装例

```csharp
[SerializeField] private TextMeshProUGUI _text;
[SerializeField] private RectTranform _marker;

private void Update(){
    var texInfo = _text.textInfo;
    var x = texInfo.lineCount == 0 ? 0 : texInfo.lineInfo[texInfo.lineCount - 1].length;
    var y = _text.preferredHeight;
    _marker.anchoredPosition = new Vector2(x, -y);
}
```
![test2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/701843/a6e34b04-a587-1002-d1f5-7b157ec3c860.gif)

`TextMeshProUGUI`の`textInfo.lineInfo`より、各行の情報を配列で取得できます。
また、`textInfo.lineCount`より、現在表示中の行数を取得できます。
※`Wrapping`による自動改行でも、行数は加算されます。

`texInfo.lineInfo[texInfo.lineCount - 1].length` より、**最終行の横幅** を取得できます。
※**任意行の横幅** を取得可能なため、`Anchor`位置や`Pivot`、スクリプトを修正することで、
任意方向に詰めたテキストに対応できると思います。

```csharp
//提案した実装
var x = texInfo.lineCount == 0 ? 0 : texInfo.lineInfo[texInfo.lineCount - 1].length;

//間違った実装
var x = texInfo.lineCount == 0 ? 0 : texInfo.lineInfo[^1].length;
```
「わざわざ`lineCount`を用いなくても、`lineInfo`配列の最後のデータを取得すればいいのでは？」
と思う方もいるかもしれませんが、`lineInfo`配列はキャッシュされている情報です。
**配列の要素数は現在の表示行数とは不一致**で、消えてしまった以前の内容が残り続けます。
必ず`lineCount`を使用して下さい。

# まとめ

`TextMeshProUGUI`の`Text`の最後の位置を取得する方法についてご紹介しました。
是非、ご自身の制作活動に活用してみてください。
Unable to find an exact match for CDP version 109, so returning the closest version found: 108

SeleniumでChrome Driverを使って実行したところ下記のエラー。

**Unable to find an exact match for CDP version 109, so returning the closest version found: 108**

原因としてはWebブラウザのバージョンとドライバのバージョンが一致していないからという、ただそれだけのことなのだが、109のドライバをダウンロードしても動作しなかった...ので回避策。

【対応】

・Chromeをアンインストールし、バージョン108を再インストール。

・Chrome Driverのバージョンも108のものをダウンロード。

・Chromeの自動更新をさせないため、下記のファイル名をテキトーに変更。
C:\Program Files (x86)\Google\Update\GoogleUpdate.exe
.NET 7 Blazor Webassembry に SyncFusinを入れる備忘録

[無料で使える「Syncfusion」を導入する手順
](https://blazor-master.com/blazor-syncfusion/) を参考に進める。

- NuGetで `SyncFusion.Blazor.Buttons` `SyncFusion.Blazor.Themes` をインストール
- プロダクトキー登録とサービス追加
```programs.cs
:
// SyncFuion
Syncfusion.Licensing.SyncfusionLicenseProvider.RegisterLicense("xxxxx");
builder.Services.AddSyncfusionBlazor(options => {options.IgnoreScriptIsolation = true; });
:
```
- テーマ設定
```index.hml
<head>
:
    <!--SyncFusion Theme-->
    <link href="_content/Syncfusion.Blazor.Themes/bootstrap4.css" rel="stylesheet" />
</head>
```
- ボタン配置
```LoginDisplay.razor
    <Authorized>
        Hello, @context.User.Identity?.Name!
        <SfButton IsPrimary="true">ログアウト</SfButton>
    </Authorized>
```
インターフェースとは何か

TypeScriptのインターフェースを理解するために備忘録として残します。

# インターフェースとは何か
インターフェースとはオブジェクトがどんな形のものか定義するためのもの
JavaScriptには存在しない

## インターフェースを使用するには
* `interface`キーワードを使用する
* 名前の先頭は大文字にする
* メソッドも追加できる
```app.ts
interface Person {
    name: string;
    age: number;
    greet(phrase: string): void;
}
```

## インターフェースを使用するメリット
* オブジェクトの型チェックに使える
```app.ts
interface Person {
    name: string;
    age: number;
    greet(phrase: string): void;
}

let userOne: Person;
user1 = {
    name: 'Mary';
    age: 40;
    greet(phrase: string) {
        console.log(phrase);
    }
}

userOne.greet('Hello');
```
婚活戦闘力診断ツールをサクッと作ってみました

# はじめに

結婚は同じくらいのレベル感の者同士が結ばれるものだと思いますが、同じくらいのレベル感というのはなんとなくのフィーリングで感じ取っているものだと思うので、それを数値化する診断ツールを作成しました

それがこちらです

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2275128/59d94475-f70d-0216-5c3d-64cc66d05a29.png)

Vercelにあげているので、実際に診断したい方は以下のリンクからアクセスしてください

https://marriagescoring.vercel.app/


# 診断原理

診断に使用している各スペックの元ネタは「結婚・家族形成に関する意識調査(2010)」の結婚相手に求める条件を使っています
各条件に点数を割り振り加重平均を取って100点満点に規格化しています


# 使用技術

Vue.jsでちょこっと作りました
ビルドツールはViteで、CSSは整えるのがめんどくさかったので、デザインはイケてないです
余力があれば整えます


# 使い方

ツールの使い方ですが、診断したい人（例えば、自分とか）の各項目のスペックを入力していくと一番下で合計点数としての婚活戦闘力が算出されます
画像の例では「名無しの権兵衛」さんの婚活戦闘力が58点ですので、「名無しの権兵衛」さんは婚活戦闘力が58点相当の女性と釣り合いが取れることが分かります
たとえば、「名無しの権兵衛」さんが結婚相手の条件に20代と大卒に固執するのであれば釣り合う女性像は以下のようになります

・性格：普通
・経済力：年収300万
・体型：やや太っている
・親の同意：得られる
・容姿：中の下
・仕事への理解：「名無しの権兵衛」が行っている仕事への理解は乏しい
・年齢：20代後半
・職種：非正規雇用
・家事能力：人並みに出来る
・学歴：関関同立
こちらの女性が婚活戦闘力57点となります

自分と同じくらいのレベル感の結婚相手を見つける際に、自分は何にこだわりがあって何を犠牲に出来るのかを探すことにお使いいただけます
是非ご活用ください


# おわりに

一応Vue.jsで作っているので、今後はVue.jsでこのような簡単な診断ツールをどう作るのかについての作り方の解説とかをして行けたらいいかなと思っています
Vue.jsの簡単な開発方法の解説になると思いますが、意外とVue3.0系の情報って少ないので需要あるかなと思ってますが、どうなんでしょうね
VSCode デバッガーの使い方（python）

# 設定について

### コマンドパレットを開く（⇧⌘P）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137120/946d4dee-e66c-327b-febd-f0dab7c15101.png)

- 「Python：インタープリーターを選択」を選択すると、インストールされているpythonの選択画面になる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137120/5ee8a318-63f0-9fff-18f2-71225d231f36.png)


# デバッグ方法

## ブレークポイントの設定

設定したい行で「F9」か、行番号の左に出てくる薄い赤い丸をクリックするとブレークポイントを設定できる。

- 条件付きブレークポイント：設定したブレークポイントで止まるための条件を設定することができる。

## 実行

実行するメインファイルをアクティブにして（そのファイルにタブ移動して）「F5」でデバッグを開始する。

- ステップオーバー（F10)：1行を実行し次の行に移る。実行対象が関数であった場合、その関数を実行し終えて次の行に移る
- ステップイン（F11）：デバッグの最小単位で、1行を実行する。実行対象が関数であった場合その関数の中に移り、1行を十個すうる
- ステップアウト：現在実行している関数が終了するまでステップ実行を行う

## デバッグコンソール（⇧⌘Y）

設定したブレークポイントで止まっている場合、変数の中身などを確認することができる。


## ウォッチ式

ブレークポイントで止めた後に、その止まっている行の中の変数や数式などをウォッチ対象とすることで、実行時にどのような値になっているかを適宜確認することができる。

1. ブレークポイントを設定して、デバッグを実行する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137120/34db62ed-bfef-5dd6-278b-f20b746ce102.png)

2. デバッガが止まったタイミングで、評価したい数式を選択して右クリック、「ウォッチに追加」を選択する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137120/ef347ece-ba43-2451-0448-8b2da4cf2093.png)

3. 左側のウォッチ式メニューに追加され、適宜ステップインすることでウォッチ対象にした変数の値が表示される。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137120/bffb2141-1895-ac7e-60b7-9335f24a2b6d.png)

## 　コールスタック

現在の実行されている関数がどういう呼び出し履歴をたどって現在のコードが表示されているかを市ｍせす。
SQLのかんたんな使い方

# SQLとは
+ データベース上の操作を行うのが目的な「データベース言語」
    + 例えば生徒名簿(データベース)から特定の生徒を抽出したり、生徒を増やしたりできる
+ 基本の抽出方法は5種類
    + SELECT
    + WHERE（AS,ORDER BY,GROUP BY)
    + INSERT
    + UPDATE
    + DELETE
+ データベース同士を結合してデータを取り出せたりもする
    + INNER JOIN
    + LEFT OUTER JOIN(RIGHT OUTER JOIN)

# SELECT
+ 列(表の縦列)から抽出する
+ SELECT 列名 FROM テーブル名
+ 列名は複数選択できる。その際は「,」で区切る
+ SELECT 名前 FROM 生徒名簿;

# WHERE
+ SELECTからさらに条件を付けて絞り込みができる
+ WHERE 列名 条件式 値
+ SELECT * FROM 生徒名簿 WHERE 生徒No <= 13;
+ 様々な演算子が使える
    + AND → 左辺かつ右辺
    + OR → 左辺または右辺
    + BETWEEN a AND b → a以上b以下
    + IN → いずれかを含む
    + LIKE → 文字列の一部を含む
    + IS NULL → NULL値のフィールド
    + IS NOT NULL → 値のあるフィールド

# AS
+ 列に別の名前を付けて抽出できる
+ SELECT 商品名,税抜き価格*1.10 AS 税込み価格 FROM 商品;

# ORDER BY
+ 抽出結果を並び替えられる
+ 「ASC」が昇順(1...10)、「DESC」が降順(10...1)
+ SELECT * FROM 生徒名簿 ORDER BY ASC;

# GROUP BY
+ データをグループ化(一括に)できる
    + 日付が10/1に集金した学費の合計を出したいなど(日付をグループ化している)
+ SELECT SUM(学費),日付 FROM 学費の集金 GROUP BY 日付;

# INSERT
+ データを追加できる
+ 1行だけでなく複数行も可
+ INSERT INTO テーブル名（列名A,列名B,…） VALUE（値A,値B,…）;

# UPDATE
+ 既存のデータを更新できる
+ UPDATE テーブル名 SET 更新内容
+ UPDATE 生徒名簿 SET 年齢 = 10 WHERE 生徒名='佐藤’;

# DELETE
+ データを削除できる
+ 複数、全てのデータの削除が可
+ リスクが高く注意が必要
+ DELETE FROM テーブル名; でテーブル自体を削除
+ DELETE FROM 生徒名簿 WHERE 出席番号 = NULL;

# INNER JOIN
+ 内部結合できる
+ 内部結合は、それぞれのテーブルの指定した列の値が一致するものだけを結合すること
+ 内部結合は、ベースとなるテーブルから、条件にマッチするレコードがないものは削除される
+ SELECT 列名1, 列名2, ... FROM テーブル名1 INNER JOIN テーブル名2 ON 結合の条件;
+ SELECT * FROM students INNER JOIN parents ON students.parent_id = parent.id;

#  LEFT OUTER JOIN(RIGHT OUTER JOIN)
+ 外部結合できる
+ 内部結合のようにそれぞれのテーブルの指定したカラムの値が一致するものを結合するのに加え、どちらかのテーブルにしか存在しないものに関しても取得する
+ LEFT OUTER JOINは左側のテーブルを軸にする、RIGHT OUTER JOINは右側のテーブルを軸にする
+ SELECT 列名1, 列名2, ...,FROM テーブル名1 LEFT(RIGHT) OUTER JOIN テーブル名2 ON 結合の条件;
+ SELECT * FROM students LEFT OUTER JOIN parents ON students.parent_id = parent.id;
Mac(M1)にpip3 install pyqt5でpyqt5をインストールしようしようとするとエラーになる（Preparing metadata (pyproject.toml) ... error）

Mac(M1)にpip3 install pyqt5でpyqt5をインストールしようしようとするとエラーになる（Preparing metadata (pyproject.toml) ... error）

以下のようなエラーがネット上でも報告されている

> https://github.com/Homebrew/discussions/discussions/1690

```
% pip3 install PyQt5
Collecting PyQt5
  Using cached PyQt5-5.15.7.tar.gz (3.2 MB)
  Installing build dependencies ... done
  Getting requirements to build wheel ... done
  Preparing metadata (pyproject.toml) ... error
  error: subprocess-exited-with-error
  
  × Preparing metadata (pyproject.toml) did not run successfully.
  │ exit code: 1
  ╰─> [24 lines of output]
      Querying qmake about your Qt installation...
```

homebrew(Macでよく使うパッケージマネージャ)からインストールすると成功する
それだけだと使えないと思うので環境変数を設定してパスを通す。

> [MacBook Pro (Apple Silicon, M1 PRO, 2021) でPython開発環境を整える](https://zenn.dev/eisukeito/articles/530313bdb4d42a)

```
brew install pyqt5
```

シンボリックリンクを貼ることでも解決できそう（以下は例、実際のパスに合わせて適宜要修正）
具体的にはhomebrewでインストールした先のディレクトリ(`/opt/homebrew/Cellar/pyqt@5/${pyqt_version}/lib/python${python_version}/site-packages/*`..)
から、現在使用しているpythonのディレクトリの`site-packages`(`$(dirname $(which python))/../lib/python${python_version}/site-packages/`)にリンクを貼るとよさそう。

```
python_version=3.10    ## 適宜要修正
pyqt_version=5.15.7_2  ## 適宜要修正 
ln -s /opt/homebrew/Cellar/pyqt@5/${pyqt_version}/lib/python${python_version}/site-packages/*  $(dirname $(which python))/../lib/python${python_version}/site-packages/
```

これで成功したと思うので一旦ここに記事を残して解決とする。
（本当はpip3 install時のエラーが解決されたら楽なのにな、など思いつつ）

# 参考

https://github.com/Homebrew/discussions/discussions/1690

https://zenn.dev/eisukeito/articles/530313bdb4d42a
AWS CDK - Identifiers

## Identifiers(識別子)

識別子は、作成されたスコープ内で一意である必要があります。
使用される識別子の種類について理解しておきます。
CloudFormation を利用したことのある方であれば、さらっと読んでおく程度で良いかと思います。

Construct IDs(コンストラクト ID) のみ理解しておれば良さそうである。

## Construct IDs(コンストラクト ID)

コンストラクトをインスタンス化するときに 2 番目の引数として渡されます。

以下の例では、アプリに `MyBucket` という識別子を持つ 2 つのコンストラクトがある例です。
1 つ目は、識別子 `Stack1` を持つスタックのスコープで定義されています。 
2 つ目は、識別子 `Stack2` を持つスタックのスコープで定義されています。 
これらは異なるスコープで定義されているため、競合は発生せず、同じアプリ内で問題なく共存できます。

```python
from aws_cdk import App, Construct, Stack, StackProps
from constructs import Construct
from aws_cdk import aws_s3 as s3

class MyStack(Stack):
    def __init__(self, scope: Construct, id: str, **kwargs):
        super().__init__(scope, id, **kwargs)

        s3.Bucket(self, "MyBucket")

app = App()
MyStack(app, 'Stack1')
MyStack(app, 'Stack2')
```

## Paths（パス）

CDK アプリケーションのコンストラクトは、App クラスをルートとする階層を形成します。この階層がパスです。

たとえば、前のコード例の 2 つの S3 バケットのリソースのパスは、
Stack1/MyBucket と 
Stack2/MyBucket です。

![スクリーンショット 2023-01-22 15.06.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/dfbe6a15-ba38-4b7f-9b4b-abb1ee969b9f.png)

## Unique IDs(一意の ID)

CDK では、CloudFormation テンプレート内のすべての識別子が一意である必要がある。

![スクリーンショット 2023-01-22 15.07.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/a650d081-754c-b588-1b1e-a08104fd920a.png)

## Logical IDs(論理 ID)

CloudFormation テンプレートで、AWS リソースを表すコンストラクトのリソースの論理識別子として機能します。

前の例で作成された VPC は、CloudFormation テンプレートで、論理 ID が MyVpcF9F0CA6F である AWS::EC2::VPC リソースになります。
[Android] NFCタッチからアプリ起動と同時にタグを読み込む

# やりたいこと

以下の記事で NFC タグをタッチしてアプリを起動するところまでできました。
[[iOS][Android] NFCタグを使ってスマホアプリを起動する](https://qiita.com/sunskysoft/items/405acd92609c0e5772e0)
次に、起動時にそのままタグを読み込みたいと思います。

# 事前準備

[[iOS][Android] NFCタグを使ってスマホアプリを起動する](https://qiita.com/sunskysoft/items/405acd92609c0e5772e0)を参照してください。
ホーム画面でNFCタッチすると、アプリが起動するまでの動作を行います。

# 起動時にタグ情報を読み込む対応

起動する ActivityのonCreate()で Intent を受け取り処理します。
NFC に書かれている Data(MIME) と AndroidManifest.xml の　intent-filter が一致することで、アプリ起動時に ACTION_NDEF_DISCOVERED アクションを伴いActivityが起動されます。

```Kotlin:MainActivity.kt
    private var nfcAdapter: NfcAdapter? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // NFC に書かれている Data(MIME) と AndroidManifest.xml の　intent-filter が
        // 一致することで、アプリ起動時に ACTION_NDEF_DISCOVERED アクションとなる
        if (NfcAdapter.ACTION_NDEF_DISCOVERED == intent.action) {
            // NDEF タグメッセージを取得する
            intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES)?.also { rawMessages ->
                val messages: List<NdefMessage> = rawMessages.map { it as NdefMessage }
                // メッセージから各レコードの情報を取得する
                for (num in 0..(rawMessages.size-1)) {
                    (rawMessages[num] as NdefMessage).apply {
                        // 例として、Payload を読み込んでみる
                        records.forEach { ndefRecord ->
                            println( String(ndefRecord.payload))
                        }
                    }
                }
            }
        }
    }
```
Activityの launchMode が singleTop でない場合は　onCreate() が呼ばれないこともあるので、その場合は　onNewIntent（）あたりでIntentを受け取ると良いようです。

# 実現できたこと

対象のアプリが前面にない場合に、NFCタグにAndroid端末をタッチすることで、アプリを起動。
その際にAndroidシステムが読み込んだタグの情報を、アプリが読み込む。
（起動後にNFCタグから離して、再タッチする必要がない）

# 後記
上記では、MIMEタイプのNDEFレコードを対象にしていましたが、[NFCの基本](https://developer.android.com/guide/topics/connectivity/nfc/nfc?hl=ja) に書かれているように、他のタイプのレコードも対象とでき、その時にフォールバックされるアクションも３種類あります。
正直なところ、いくつかのパターンを試してみましたが、intent-filterの書き方が悪いのか、うまくいきませんでした。。。そのうち、気が向いたらまたチャレンジしてみたいと思います。
４０代おっさんFastAPI、MongoDB連携メモ③

## 本記事について

この記事はプログラミング初学者の私が学んでいく中でわからない単語や概要を分かりやすくまとめたものです。
などありましたらコメントにてお知らせいただければ幸いです。

## update

```python
async def db_update_todo(id:str, data: dict) -> Union[dict, bool]:
    todo = await collection_todo.find_one({"_id": ObjectId(id)}) # find_oneでObjectId(id)が存在するか検証無ければnone
    if todo:
        updated_todo = await collection_todo.update_one( # update_oneを使ってMongo DBにアクセス
            {"_id": ObjectId(id)}, {"$set": data}
        )
        if (updated_todo.modified_count > 0): # modified_countが０より大きければ更新が成功したと判定できる
            new_todo = await collection_todo.find_one({"_id": ObjectId(id)})
            return todo_serializer(new_todo)
    return False
```

- find_oneでObjectId(id)が存在するか検証無ければnoneが返ってくる
- update_oneの返り値はUpdateResultと言うクラスから作られたインスタンスmodified_countと言う属性にアクセスできる
  - modified_countが0より大きければ更新が成功したと判定できる

## delete

```python
async def db_delete_todo(id: str) -> bool:
    todo = await collection_todo.find_one({"_id": ObjectId(id)})
    if todo:
        deleted_todo = await collection_todo.delete_one({"_id": ObjectId(id)}) # delete_oneを使用する
        if (deleted_todo.deleted_count > 0):
            return True
        return False
```

- delete_oneの返り値はDeleteResult
  - deleted_count属性で実際に成功したdeleteの数が返ってくる

## route_todo.py

```python
@router.put("/api/todo/{id}", response_model=Todo) # update
async def update_todo(id: str, data: TodoBody):
    todo = jsonable_encoder(data)
    res = await db_update_todo(id, todo)
    if res:
        return res
    raise HTTPException(
        status_code=404, datail="Update task failed"
    )

@router.delete("/api/todo/{id}", response_model=SuccessMsg)
async def delete_todo(id: str):
    res = await db_delete_todo(id)
    if res:                                        # returnはTrue
        return {'message': 'Successfully deleted'}
    raise HTTPException(
        status_code=404, datail="Delete task failed"
    )
```

- from database import に`db_update_todo, db_delete_todo`
- from schemas import に`SuccessMsg`

## 参考

https://www.udemy.com/course/farm-stack-react-fastapi
ジェネリック型とは何か

TypeScriptのジェネリック型を理解するために備忘録として残します。

# ジェネリック型とは
型が明確に決まっていない関数を宣言する際に使う
型は関数に引数を渡すタイミングで決まる

# ジェネリック型を使わない場合
```App.ts
const merge = (objA: object, objB: object) => {
    return Object.assign(objA, objB);
};

const mergedObj = merge({name: 'Lily'}, {age: 30});

//const mergedObjをオブジェクトとしてしか認識しておらず出力できない
console.log(mergedObj.age);
console.log(mergedObj.name);

// error
```

# ジェネリック型を使う場合
* 関数に`<>`を追加する
* `<>`の引数とは慣習的に`T` `U` が使われる

```App.ts
const merge = <T, U>(objA: T, objB: U) => {
    return Object.assign(objA, objB);
};

const mergedObj = merge({name: 'Lily'}, {age: 30});


console.log(mergedObj.age);
console.log(mergedObj.name);
// 30
// Lily
```
HTML5で廃止になった要素

HTML4.01からHTML5に移行する過程で、同じ機能を持つ別の要素や、
CSSの機能への統合などによって削除された要素。

## acronym
* title属性と組み合わせることで、略語の正式名称を指定する要素。
* abbr要素に統合されたため廃止。

## applet
* 文書にJavaアプレットを埋め込むための要素。
* Javaアプレット自体がJava 11で廃止されたため、こちらも廃止に。

## basefont
* この要素以降のテキストのフォント（サイズ、色等）を指定する。
* CSSで実現可能な内容だったため廃止。

## bgsound
* headタグ内に記述することで、Webページを開いた時にBGMや効果音を再生することができる。
* Internet Explorer(IE)独自の要素であり、IEが2022年6月に廃止された今では無用の長物。
* audio要素を使えば、IE以外のブラウザでも同様の事が可能。

## big
* タグで囲った部分の文字サイズが周囲より一回り大きくなる。
* CSSで実現可能な内容だったため廃止。

## blink
* タグで囲った部分を点滅させる。
* CSSのanimationプロパティで実現可能。

## center
* グで囲った部分を水平方向中央に表示する。
* CSSのalignプロパティで実現可能。

## dir
* 複数の段を持つディレクトリリストを表示するための要素。
* ul要素とほぼ同じ役割な上、殆どのブラウザが非対応。そのためか、HTML4.01の時点で非推奨となっていた。

## font
* タグで囲った部分のフォントと文字サイズを変える。
* CSSで実現可能な内容だったため廃止。

## frame
* 画面を複数に区切って、タイトルやサイドメニューを同一リソースで管理する「フレームページ」を作るのに使う要素。古いサイトでは今でも割と見かける。
* HTML5以降は「グローバルメニュー」を使うのが一般的。
* 一応、iframe要素を使えば昔のフレームページを再現することも可能、らしい。

## isindex
* 検索キーワードを入力するための「1行テキストボックス」を作るための要素。
* input要素で実現可能。

## listing
* 文中に「<」「>」等の特殊文字を含むソースコードをそのまま表示するのに使われていた要素。
* pre要素で実現可能。

## marquee
* 電光掲示板のように、文字を上下左右にスクロールさせるアニメーションを表示する要素。古いサイトでは今でもたまに見かける。
* CSSのmarquee-styleプロパティで実現可能。

## nobr
* タグで囲った部分の改行を禁止する。nobrは"No Break"の略。
* 文章や英単語、固有名詞など、切れるとわかりづらくなる部分に対して使うことを想定していた。
* wbr要素に取って代わられる形で廃止に。

## noembed
* HTML以外の外部アプリケーションやインタラクティブコンテンツを文書内に埋め込むembed要素に対応していないブラウザのために、代替となる内容を提供するための要素。
* object要素で実現可能。

## noframes
* フレーム未対応のブラウザや、ユーザがフレームの非表示設定をしている場合に、その代替の内容を表示するための要素。frameset要素内で使う。
* frameset関連が廃止されたので、当然これも廃止に。

## plaintext
* このタグ以降を全て生のテキストとして表示する。
* HTML2の時点で非推奨扱いになっており、HTML5で正式に廃止となった。

## spacer
* 水平方向や垂直方向にスペースを挿入する。
* CSSのmarginプロパティやpaddingプロパティで実現可能。

## strike
* タグで囲った部分に打消し線が引かれる。
* 同じ効果を持つs要素が意義を変えて続投したのに対し、こちらは削除されている。名前が長かったからか？

## tt
* タグで囲った部分を等幅フォントで表示する。
* CSSのfont-familyプロパティで実現可能。

## xmp
* listing要素と同じ、特殊文字を含むソースコードを表示するための要素。
* pre要素で実現可能。

* * *

# Living Standardで廃止された要素

## rb
* ルビを振る対象となる文字を指定する要素。
* 漢字を一文字ずつタグで囲い、それぞれにルビを振るという使い方もできた。
* rt要素に取って代わられる形で廃止に。

## rtc
* 対象に複数のルビを振るための要素。
* 読み方が複数ある場合、駅名標のように異なる言語をルビとして振りたい場合を想定していたと思われる。
* 主要なブラウザの多くが未対応な上、HTML5で実装されたもののすぐ廃止となった。殆ど使われなかったのだろうか。
(Amplify/Cognito)ログイン画面を実装の際に'./aws-exports'を使うと後々ハマるのでベタ書きが良い。

# はじめに
IoTデバイス用のログイン画面を実装したく、Amplify+Cognito+Reactを使用した。
様々な記事を参考にして進めてみたがハマったポイントが多く、私のようにフロントに精通していない人の参考になれば幸いです。

# よく紹介される方法と問題点

チュートリアルの流れとして、

```
$ sudo npm install -g @aws-amplify/cli
$ amplify configure
```
上記コマンドを使用して、

```
./aws-exports
.aws/credentials
```

を作成することが多いだろう。

しかし、その方法では```./aws-exports```が原因で後々ハマってしまう。

* GithubからAmplifyでデプロイする際に、ビルドエラーになってしまう。
* ローカルにファイルが残るので、開発環境の共有しにくい。
* どのプールと連携しているか、わかりにくい

既にビルドエラーになってしまった人は下記記事を参考にしてください。

https://engineers.weddingpark.co.jp/aws-amplify/


# 結論: ```./aws-exports``` を使用しない
ローカルから直接```amplify push```して手動デプロイを都度行いたい人意外は、```./aws-exports```は不要と考える。

## 必要ライブラリをインストール
```
$ npm install aws-amplify
# もしくは
$ npm install -g @aws-amplify/cli

$ amplify -v
10.6.1

```
```
# Amplifyライブラリインストール
$ npm install aws-amplify @aws-amplify/ui-react
```

## ソースコードを編集する
```javascript
import { withAuthenticator, AmplifySignOut } from '@aws-amplify/ui-react'
import { Amplify } from 'aws-amplify';

//ここに認証情報を書き込む
Amplify.configure({
  Auth: {
    identityPoolId: process.env.REACT_APP_IDENTITY_POOL_ID,
    region: process.env.REACT_APP_REGION,
    userPoolId: process.env.REACT_APP_USER_POOL_ID,
    userPoolWebClientId: process.env.REACT_APP_USER_CLIENT_ID,
  }
})

function App() {
  return (
    <div className="App">
      <header>
        <img src={logo} className="App-logo" alt="logo" />
        <h1>We now have Auth!</h1>
      </header>
      <AmplifySignOut />
    </div>
  );
}
 
export default withAuthenticator(App);
```

```.env```ファイルを作成して、認証情報を書き込む。

```Name:.env

REACT_APP_IDENTITY_POOL_ID=ap-northeast-1:XXXXXXX
REACT_APP_REGION=ap-northeast-1
REACT_APP_USER_POOL_ID=ap-northeast-1_XXXXXXXXX
REACT_APP_USER_CLIENT_ID=XXXXXXXXXXXXXXXX

```
sqlxでPostgresql(Docker)に接続するとerror communicating with database: Connection refusedとなる

# はじめに

以下の書籍をRustのコンテナ上で実行したところDatabase接続につまづいたのでまとめます

https://www.amazon.co.jp/Web%E3%82%A2%E3%83%97%E3%83%AA%E9%96%8B%E7%99%BA%E3%81%A7%E5%AD%A6%E3%81%B6-Rust%E8%A8%80%E8%AA%9E%E5%85%A5%E9%96%80-%E4%BD%90%E8%97%A4%E6%98%AD%E6%96%87/dp/4798067318/ref=sr_1_1_sspa?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=1EZPQYF2A7M8H&keywords=rust&qid=1674365618&sprefix=rus%2Caps%2C220&sr=8-1-spons&psc=1&spLa=ZW5jcnlwdGVkUXVhbGlmaWVyPUEzOUNaRVVFRzVMUVI4JmVuY3J5cHRlZElkPUEwMjA2OTE5M0Y0SlpKUlZSWVJJUiZlbmNyeXB0ZWRBZElkPUEyMk9DUUwzVFU1WjFLJndpZGdldE5hbWU9c3BfYXRmJmFjdGlvbj1jbGlja1JlZGlyZWN0JmRvTm90TG9nQ2xpY2s9dHJ1ZQ==

# 問題

書籍の設定をしたところRustコンテナから`postgresql`に接続ができませんでした

```
$ make dev

error: error communicating with database: Connection refused (os error 111)
make: *** [Makefile:6: dev] Error 1
```

`sqlx create db`で落ちていました

# 設定方法

まずは`docker-compose.yml`でコンテナ間で通信ができるようにします

```yml:docker-compose.yml
version: '3'
services:
  rust:
    build: .
    container_name: rust
    tty: true
    ports:
      - "3000:3000"
    volumes:
      - .:/app
    env_file:
      - .env
    networks:
      - app-net
  database:
    build:
      context: ./database
      dockerfile: Dockerfile
      target: 'database'
    ports:
      - "5432:5432"
    volumes:
      - pgdata:/var/lib/postgresql/data
    environment:
      POSTGRES_PASSWORD: admin
      POSTGRES_USER: admin
      POSTGRES_DB: todosnetworkName
      TZ: Asia/Tokyo
    restart: always
    networks:
      - app-net
  
volumes:
  pgdata:

networks:
  app-net:
    driver: bridge
```

ポイントは`brige`を行うことです
これをすることでRustから`database`という名前でアクセスしていきます(localhostのような感じで)

次に`.env`のURLも変更していきます

```.env:.env
DATABASE_URL="postgres://admin:admin@database:5432/todos"
```

次に`Makefile`も修正します

```Makefile:Makefile
dev:
	sqlx db create
	sqlx migrate run
	cd my-todo && cargo watch -x run
```

`make dev`を実行したときに`migrate`までしたら`my-todo`に移動して`cargo run`を実行します。これは`Cargo.toml`が`/my-todo`にあるので、実行場所を変えています

次に`cargo watch`を利用するためにrustの`Dockerfile`を変更します

```Dockerfile:Dockerfile
FROM rust:alpine3.17

RUN apk update && apk add git alpine-sdk make libffi-dev openssl-dev pkgconfig
RUN rustup component add rls rust-analysis rustfmt clippy
RUN cargo install sqlx-cli cargo-watch

WORKDIR /app/my-todo
```

`cargo-watch`をインストールしました

最終的には以下のディレクトリ構成になりました

```
├ database
    └ Dockerfile (DB用のDockerfile)
├ migrations
    └ timestamp_init.sql
├ my-todo
    └ src
    └ Cargo.toml
    └ Cargo.lock
├ .env
├ docker-compose.yml
├ Dockerfile (Rust用のDockerfile)
├ Makefile
```

# おわりに

コンテナ間で通信を行うのを久しぶりにやったので備忘録を兼ねてまとめてみました

# 参考

https://qiita.com/YuitoSato/items/4a4b46f5670b45739a37

https://nainaistar.hatenablog.com/entry/2021/06/14/120000

https://qiita.com/kyamamoto9120/items/c391f0ce5050c5ddcc87