OmniAICreator/Qiita-1.07M huggingface dataset:
33業種×エンジニア：化学

## はじめに
未経験からのエンジニア転職を模索中。33業種それぞれでエンジニアはどのような働き方をしているのかが気になったので調べたことをまとめてみます。実際に現場で働いている方から見たらぬけ等あるかと思いますが、あたたかい目で見守ってください

## 化学×エンジニアの働き方の例
![kagaku.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3777936/541e2006-793e-ba6b-c5a5-a698189e42fa.jpeg)

### 1. システムエンジニア（SE）
- 役割: 化学工場や研究所のITインフラの設計、開発、導入、運用管理を行う
化学プロセス管理システムの開発と保守。
研究データ管理システムの構築。
生産管理システムの最適化と自動化。

### 2. プログラマー
- 役割: 化学プロセスや研究データを効率的に管理するためのソフトウェアのコーディング
分析機器と連携するデータ処理ソフトウェアの開発。
分子モデリングソフトウェアのプログラミング。
ラボの自動化システムのスクリプト作成。

### 3. サーバーエンジニア
- 役割: 化学企業のサーバーの設計、設定、保守、管理を担当
大規模データの管理とバックアップシステムの構築。
クラウドベースの計算資源の管理。
リアルタイムデータ解析のためのサーバー設定。

### 4. ネットワークエンジニア
- 役割: 化学施設のネットワークインフラの設計、設定、運用、保守を行う
研究所と生産施設を繋ぐ安全なネットワークの構築。
リモートモニタリングシステムのネットワーク設定。
セキュリティ対策とトラフィック管理。

### 5. データサイエンティスト
- 役割: 化学データの解析、予測モデルの作成、結果のビジュアル化を行う
実験データの解析とパターン認識。
生産データからの品質予測モデルの作成。
市場データの解析による新製品開発の支援。


## 世界大手企業
### [BASF](https://www.basf.com/jp/ja.html)
概要: ドイツに本拠を置く世界最大の化学企業。化学、プラスチック、パフォーマンスプロダクツ、作物保護製品、オイル、ガスなど幅広い分野で事業を展開している。持続可能なソリューションを提供し、革新を推進することに注力している
### Dow Inc.
概要: アメリカ合衆国に本拠を置く世界有数の化学企業。化学製品、プラスチック、先端材料、農業製品などの製造と販売を行っている。高性能材料や化学ソリューションを提供し、さまざまな産業の発展に貢献している。
### [DuPont](https://www.dupont.com/)
概要: アメリカ合衆国の大手科学企業。先進的な材料、特殊化学製品、農業製品などの分野で広範な事業を展開している。イノベーションを通じて、持続可能なソリューションを提供し、社会の課題解決に貢献している。


## 日本企業
### [三菱ケミカルホールディングス](https://www.mcgc.com/)
概要: 日本を代表する化学メーカーであり、三菱グループの一員。化学、プラスチック、医薬品、機能材料、炭素製品など多岐にわたる事業を展開している。技術革新と環境保護に取り組み、持続可能な社会の実現を目指している。
### [住友化学](https://www.sumitomo-chem.co.jp/)
概要: 日本の総合化学メーカー。石油化学製品、エネルギー・機能材料、情報電子化学品、健康・農業関連製品などの事業を展開している。革新的な技術と製品を提供し、グローバルな課題解決に貢献している。
### [旭化成](https://www.asahi-kasei.com/)
概要: 日本の大手化学メーカー。繊維、ケミカルズ、エレクトロニクス、住宅、医療、環境ソリューションなど多岐にわたる事業を展開している。イノベーションと持続可能な成長を追求し、社会に貢献することを目指している。


## さいごに
化学×ITエンジニアの求人で検索をかけてみると「化学メーカー向け基幹システム保守」「python言語を用いたプログラム作成」「化学品マーケットプレイスおよび貿易に関わるシステムの設計・開発」なんかが見つかりました。
課題で学習した言語や環境があることを確認できました。もっと精進しないとな。
研究研究の化学だから、課題が尽きることはなさそうなイメージです。
TypeScript　typeof keyof valueofについて

自分用にTypeScriptでの`typeof,keyof,valueof`を整理します。
個別項目のリンクからサバイバルTypeScriptに飛べます。

## [typeof](https://typescriptbook.jp/reference/type-reuse/typeof-type-operator "サバイバルTypeScript　typeof型演算子")
変数やオブジェクトの型を取得する。
keyofやその他のユーティリティ型に関しても直接的にオブジェクトに使用することはできない。まずtypeofで型を取得し、取得した型に対して使用できる。

### 使用例
```
const person = {
  name: "Alice",
  age: 30,
};

type PersonType = typeof person;
// PersonTypeは { name: string; age: number } 型
```

## [keyof](https://typescriptbook.jp/reference/type-reuse/keyof-type-operator "サバイバルTypeScript　keyof型演算子")
オブジェクトの型のすべてのプロパティ名（キー）をユニオン型として取得する。

### 使用例
オブジェクトに対し直接使えないので、型を定義し使用。
```
interface Person {
  name: string;
  age: number;
}

type PersonKeys = keyof Person;
// PersonKeysは 'name' | 'age' 型
```

## ValueOf
オブジェクトの型のすべてのプロパティの値（バリュー）をユニオン型として取得する。
カスタムユーティリティ型(開発者が独自に定義した型)で、定義は下記の通り。
```
type ValueOf<T> = T[keyof T];
```
T[K]の形式で、まず[]内の処理としてTの型にアクセスしてプロパティ名（キー）を取得。
次にTに対してK（キー）を用いて[インデックスアクセス型](https://typescriptbook.jp/reference/type-reuse/indexed-access-types#%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E5%9E%8B%E3%81%AE%E6%A7%8B%E6%96%87 "サバイバルTypeScript　インデックスアクセス型")を使用。
K（キー）に対応したTのプロパティの値を取得できる。

### 使用例
オブジェクトに直接使えないのでtypefoで先に型を抽出してから使用。
```
const CounterActions = {
  DECREMENT: "DECREMENT",
  INCREMENT: "INCREMENT",
  ADD: "ADD",
} as const;

type ActionType = ValueOf<typeof CounterActions>;
// ActionTypeは 'DECREMENT' | 'INCREMENT' | 'ADD' 型
```
Xserver SNSについて思うところ

# はじめに
先日、Xserver SNSというサービスがリリースされました。
知識の無い方でも簡単にMisskeyやMastdonのサーバーを構築できることを謳い文句に、サーバーの構築と保守を代行してくれるサービスです。

この記事では、Xserver SNSについての思うところをあることないこと書いていこうかと思います。


# わるいところ
# スペックの割に割高
スタータープラン(3core, 2.9GB, 200GB)の価格は2,410円ですが、これだけの金額を払えばもう少し立派なスペックのVPSを借りることができます。

ちなみに、Xserver VPSではその半値で似たようなスペックのVMを借りることができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3283241/1275bfa3-d42b-de86-c4dd-7e9c4c87f4cd.png)

https://vps.xserver.ne.jp

サポート周りを丸投げできるとしてもどこか割高で勿体ない気がします。

ちなみにディスク容量は200GBしかなく(追加はできますが)、リレーに参加したり連合先が増えたりしてくると、すぐに足りなくなってしまいそうです。
50GB追加するごとに495円かかるようです。

# バックアップができない
バックアップ機能がありません。

> 自動バックアップ機能はありますか？
いいえ、自動バックアップ機能はありません。
万が一の障害に備えバックアップはしていますが、データを確実に保全し、保証するものではありません。

だそうです。

https://sns.xserver.ne.jp/support/faq/service_server_backup.php

別サーバーからの移管とその逆ができればまだよかったものの、それもできないようです。うーーーん。


## R18コンテンツが扱えない
悪い点であるかどうかは微妙ですが、R18コンテンツが扱えません。
国内の事業者だと概ねR18コンテンツは扱えないのでどこでも一緒な気がしますが、一応。


# コミュニティを苦しめるだけなのでは
結局のところ、知識のない管理者がのさばると苦しむのはコミュニティ全体ではないでしょうか。
知識のない管理者らは、技術的な問題やトラブルに適切に対処することができず、連合先にも迷惑をかけることがあるかもしれません。

スパム缶画像スパムの台頭は記憶に新しいですが、サーバーの立ち上げすらできない方々がまともに対応できるとは到底思えません。


# いいところ
悪いところばかりを言っても仕方がないのでいいところを。

## メンテナンスコスト低い
丸投げできるのでメンテナンスコストは低いです。
Node.jsのバージョンアップをミスって鯖落ち～みたいなことは起きません。
いいですね。

## 企業が運営している
結局、利用するメリットでこれが一番大きいのではないでしょうか。
個人でホスティングをやられてる方もいらっしゃいますが、結局個人によるものなので法人のそれと比べると見劣りします。


# おわりに
私自身、あまりこのサービスに対してあまり肯定的な意見を持っていません。

Fediverse自体、ある種の善意によって治安が保たれている側面もあり、サーバーを建てるためのハードルはよからぬ影響を与える物々へのいい障壁にもなっていたと考えています。

スタートアップスクリプトも然り、この手の「簡単に始められます！」系のサービスは、技術的なハードルを下げる一方で、責任感の無い管理者を増やす可能性があります。

短期的に見れば、多くの人が簡単にサーバーを立ち上げられることによって、Fediverseは一時的に活性化するかもしれません。
しかし、長期的には、管理者の知識不足やサポートの不足によって、Fediverse全体としてのコミュニティが苦しむ結末もあり得るのではないでしょうか。

それでは。

# 追記
追記です。

最近、xsnsでは一か月無料キャンペーンをやっていたようです。
それだけならいいんです。それだけなら。

無料キャンペーン後に次々と閉鎖されるサーバーを見ると、無責任な運用が浮き彫りになっているように感じます。
問題なのは、ただ閉鎖するだけでなく、410 Goneを返さない点です。これはFediverse全体にとって致命的なルール違反とも言えます。

Fediverseの基本的な理念は、連合型ネットワークにおける互助と調和にあります。しかし、410を返さず突然消えるサーバーは、他の多くのサーバー迷惑をかけることになります。

また、この問題の根本には、Xserver SNSが技術的責任を軽視している点があるのではないでしょうか。サービスが簡易的であるがゆえに、運用に必要な基本的な知識や責任感を持たない人々が安易に参加してしまいます。

結局その程度だったんですね。
~~AS単位でブロックしてやろうかとまで思いましたが、踏みとどまりました。~~
Pandas: テキストファイルを csv に変換

## 仕様

コラム名、データとなっている次のようなテキストファイルを csv に変換する方法

入力ファイル

```text:in01.txt
市区町村コード 		131016
宛名番号 		12345678912
個人履歴番号 		1
個人履歴番号_枝番号 	1
最新フラグ 		1
改製番号 		1
世帯番号 		234567890123456
```

出力ファイル

```text:out01.csv
"市区町村コード","宛名番号","個人履歴番号","個人履歴番号_枝番号","最新フラグ","改製番号","世帯番号"
"131016","12345678912","1","1","1","1","234567890123456"
```

## プログラム

```py:vertical_to_csv.py
#! /usr/bin/python
#
#	vertical_to_csv.py
#
#						Jul/15/2024
#
# --------------------------------------------------------------------
import	sys
import	csv
import	pandas as pd
#
# --------------------------------------------------------------------
sys.stderr.write("*** 開始 ***\n")
file_text = sys.argv[1]
file_csv = sys.argv[2]
#
fp_in = open(file_text,encoding='utf-8')
lines = fp_in.readlines()
fp_in.close()

keys=[]
data=[]
for line in lines:
	cols = line[:-1].split()
	keys.append(cols[0])
	data.append([cols[1]])
#	print(cols[0])
#	print(cols[1])
#
print(len(keys))
print(len(data))
#
df = pd.DataFrame({keys[i]: data[i] for i in range(len(keys))})
print(df.shape)
df.to_csv(file_csv,index=False,quoting=csv.QUOTE_ALL)
#
sys.stderr.write("*** 終了 ***\n")
# --------------------------------------------------------------------
```

## 実行結果

```text
$ ./vertical_to_csv.py in01.txt out01.csv
*** 開始 ***
7
7
(1, 7)
*** 終了 ***
```
PDFの圧縮についてのメモ書き

Ubuntu版
# GhostScript
```bash
gs -sDEVICE=pdfwrite \
   -dCompatibilityLevel=1.7 \
   -dPDFSETTINGS=/ebook \
   -dEmbedAllFonts=false \
   -dNOPAUSE \
   -dQUIET \
   -dBATCH \
   -sOutputFile="出力ファイル名" \
   "入力ファイル名"
```
# 画像化してもう一度pdfに戻す
しおりなどのリンク機能や文字データは完全に消えるため、論文や長い文章だと不便になる可能性が大きい。あくまで印刷やメールでの添付での用途がいいのかも
```bash
# popplerでpdfを画像化 -r がdipをコントロールしているので、ここを変えると変換後のサイズが変わる
pdftoppm -png $input_file ./tmp -r 300
# ImageMagicで画像をpdf化
convert ./tmp*.png $output_file
# tmp画像を削除
rm ./pdf2img2pdftmp*.png
```
:::note warn
メモリ不足としてこのコマンドはエラーを起こしやすいのでコンフィグファイルを最初に書き換える。
ImageMagickのコンフィグファイルはデフォルトだと
/etc/ImageMagick-6/policy.xml
にあり、そこにある```<policy domain="resource" name="memory" value="256MiB"/>```
の256MiBをもっとでかい値で書き換える
:::

### Windows版
Adobe AcrobatでPDFファイルを開き、印刷を選択→Microsoft Print to PDFでファイルを出力すると圧縮される。テキストデータやしおりなどは消えるので注意。
ぼっちこそ　スタッフ参加だ　カンファレンス

# はじめに
こんにちは、エンジニア友達がほとんどいないぼっちエンジニアのげんきと申します。

この記事ではぼっちが初オフラインカンファレンスに初スタッフ参加した感想や良かった点をお伝えしていこうと思います。

また、自分以外のぼっちエンジニアがこの記事を読んで「スタッフ参加してみようかな...！」と思っていただけると大変うれしいです！

# 自己紹介
改めましてげんきと申します。

元々バックオフィス向けソフトウェアの提案営業からキャリアをスタートしましたが、「売るより作れたほうが楽しそう」という理由で新卒の会社を辞めソフトウェアエンジニアにキャリアチェンジをしました。

キャリアチェンジして5年ほど経ちましたが、業務外で気軽に話せるエンジニアがほとんどいないというかなり重症なぼっちエンジニアです・・・

# 参加したイベント
今回私が参加させていただいたのは「大吉祥寺.pm」というイベントです！

「吉祥寺.pm」というテックイベントの10周年を記念した大規模オフラインイベントでした！

元々はPerlのイベントとして始まったようですが、現在はPerlに限らずさまざまなジャンルの発表を聞くことができる、他のテックカンファレンスとはちょっと異なるユニークなイベントになっています。

# 参加の経緯
こんなぼっちがスタッフ参加を志したのは、また別のオフラインイベントで拝聴したある講演で聞いたワードがきっかけです。

それはそーだいさん（[@soudai1025
](https://x.com/soudai1025)）という方の「コミュニティと共に生きる - キャリアの螺旋 / live with community」というタイトルのスライドに出てきた**計画的偶発性理論**というワードです。

「あなたの人生を変える瞬間は突然やってくる」
「その瞬間が来る可能性を上げる」
「自らの接触機会を増やす→チャンスの機会を増やす」
「チャンスは与えられるのではなく自分から勝ち取りに行くモノ」

**エンジニアの師もいなければ仲間もいない私**は上記のような説明と一緒に紹介された計画的偶発性理論というワードに大変な衝撃を受け、「行動に移すんだ！！」と気が付くとconnpassのカレンダー上の興味のあるオフラインイベントに片っ端から申し込みをしていました。

しかし、オフラインイベントにただ足を運ぶようになったものの、結局はコミュ障。。。
他のエンジニアとの交流はうまくいかず、どうしたもんか...を頭を働かせた結果「いっそのことイベントの主催側として参加してみよう」と思い立ちました。

そんなタイミングでたまたまオープンな場でボランティアスタッフを募集していた大吉祥寺.pmが目に留まり、これだ！！！と参加に至ります。

# スタッフ参加してみて
結論として、とても楽しく満足のいく経験ができたと感じています！
そんな今回のスタッフ参加を通して、気づいたことやスタッフ参加によるメリットを紹介できればと思います。

## 「ぼっち」は話のネタの1つ
今回の経験を通して気づいたことの1つが「ぼっちなんてただの属性、話のネタにすればいい」ということです。

スタッフの顔合わせ時に私が「ぼっちなんですけど○○な理由で参加しました」と自己紹介したところ、後からこれまでの経歴を聞きに来てくたりと会話が発生しました。

そう、「ぼっち」であることから交流がうまれたのです！

「ぼっち」なんてただの属性で、それを卑下して終わりじゃもったいない

「ぼっち」であることをネタに会話を生んでいきましょう！！

## 懇親会で「自分スタッフやってました！お疲れ様でした！」の一言で色々な卓に飛び込める！
これは主催者のmagnoliakさん（[@magnolia_k_](https://x.com/magnolia_k_)）に教えていただいたスタッフの特権です。（magnoliakさんありがとうございました！！）

当日スタッフの名札を引っ提げていたおかげで、席が空いている卓を探し回り「スタッフでした、感想きかせてください！」という感じで合計2,3卓へ乾杯しに回れたと思います！（とても楽しかった！！）

酒の入った状態 × 他の場所に飛び込める優先権を自分が持っている = もう無敵です！

## 当日になっての「やっぱ行ーかない」という逃げ道を最初から封鎖する
これがぼっちにとってのスタッフ参加することによる一番のメリットかもしれません。

個人的に、「一緒に参加する人がいない休日のオフラインイベント」って一番ハードルが高い条件だと感じてます...

なぜかというと、一人で一般参加で申込している時の当日キャンセルのしやすさが半端ないからです。

前日までどれだけモチベーションが高くても当日朝起きたタイミングで「あ、今日やっぱやめとこ」となった経験は皆さんにもあると思います。（ありますよね...？）

スタッフ参加にすることで当日キャンセルという選択肢をつぶせるのでこれはいい判断だったなと思います。

## イベントに対するモチベーションをMAXにする

またスタッフ参加は強制力をもたせるだけではありません。

スタッフ同士の事前顔合わせやオフラインでの事前準備などがあったおかげでイベントを絶対成功させたいという前向きな気持ちが強くなっていました。

最終的には強制力ではなくイベントに対するモチベーションが頭や体を動かしてくれていたと思います。

## おまけ：有名人と会って挨拶した気分に（一方的に）なれる
今回の大吉祥寺.pmが歴史あるイベントということもあり、読んだことのある技術本の著者の方が何名かご参加されていました！

有名人に弱い私は、「今すれ違ったのはあの本の○○さん！？あそこには△△さん！？！？」みたいな感じで一人で舞い上がり、心の中で「いつもお世話になっております。」と勝手に挨拶した気になっていました笑

また、懇親会では大変お世話になった本の著者の方と実際にご挨拶・お話することができとても貴重な経験をすることができました！

＃ 最後に
いかがでしたでしょうか？

今回スタッフ参加を経験したことで、これまでの一般参加と比べてチャンスの量が全然違うということに気づくことができました。

今後イベントに参加する場合はスタッフ枠があれば迷わずチャレンジしていきたいと考えています。

カンファレンスやテックイベントにスタッフで参加してみようと思うきっかけになれば幸いです。

チャンスが目の前にくるのを待つのではなく、チャンスがありそうな場所へどんどん向かっていきましょう！！

ご覧いただきありがとうございました。

# 参考
そーだいさんの講演資料：
https://speakerdeck.com/soudai/live-with-community?slide=40
EV3のOSと言語を完全に理解する

今回取り扱うのはEV3で使用できるOSと言語の話です。
| OS | 起動速度 | ベース | 言語 |
| - | - | - | - |
| LMS2012 | 30秒 | Linux? | ブロック,Scratch,JS,C,C++,Basic,Swift |
| ev3dev | 2分 | Linux | Python,Java,Go,C++,C,Prolog,Rust,その他 |
| leJOS | 1分 | Java | Java,その他JVM言語 |
| MonoBrick | 1分 | Mono | C#,F#,IronPython,その他.NET言語 |
| EV3RT | 5秒 | TOPPERS | C,C++,Ruby,Rust |
# LMS2012
![LMS2012](https://storage.googleapis.com/zenn-user-upload/fd21d05cfbee-20231028.jpg)
MicroSDを使用せずに起動するタイプのOSです。いわゆるデフォルトOSですが、十分に機能が備わっており追加ファームウェアなどを加えればMicroSDは必要ないレベルになります。
## EV3 Classroom
https://education.lego.com/ja-jp/downloads/retiredproducts/mindstorms-ev3-lab/software/
最新の最も使用されているアプリケーションです。Scratchがベースになっています。
## EV3 Lab
https://education.lego.com/ja-jp/downloads/retiredproducts/mindstorms-ev3-lab/software/
いわゆる教育版と呼ばれているものです。EV3 Classroomより前から存在したため、情報が多いです。
## LEGO MINDSTORMS Module for LabVIEW
https://www.ni.com/ja/support/downloads/software-products/download.lego-mindstorms-module-for-labview.html#351224
EV3 Labにプログラミングのスタイルが似ていますが、これを使用するといくつものEV3を同時に制御できます。
## MakeCode
https://ev3manager.education.lego.com
Microsoftが提供しているプログラミングツールです。ブロック言語に加え、JavaScriptでプログラミングできます。
## SwiftPlaygrounds
https://www.apple.com/jp/swift/playgrounds/
AppleがMacまたはiPadで使用できるアプリです。Swiftという言語でEV3を操作できます。GUIで動作テストができるのも魅力です。
## ROBOTC
https://www.robotc.net
有料(?)専用ソフトでC言語を使ったプログラムを書くことができます。他にこのページではEV3のシミュレーターも販売しています。
## Cpp4Robots
http://www.cpp4robots.cz
Visual Studio 2022の拡張機能として提供されています。CかC++でプログラムを書けます。プログラムの送信、実行もVisual Studioからできます。
## Robot JavaScript
https://robotjavascript.com
JavaScriptをEV3で実行するアプリです。アプリはMicrosoftStoreにもあります。常に左のツールバーにチートシートがありスムーズにコーディングできます。
## EV3 Basic
https://sites.google.com/site/ev3basic/
Small Basicの拡張機能です。Basic言語が動かせます。欠点としてPCとリアルタイムで通信しなければプログラムが動きません。
## BricxCC
https://sourceforge.net/projects/bricxcc/files/bricxcc/
C言語が動かせます。専用ソフトのツールが幅広く、ほとんどのEV3の管理が単体でできます。
# ev3dev
![ev3dev](https://storage.googleapis.com/zenn-user-upload/a2a7dd9aece7-20231028.jpg)
Linuxがベースになっていて、Linuxコマンドが使用できます。言語はライブラリさえあればどんな言語でも動かせるのが大きなメリットです。

使用可能言語は以下のサイトにまとめられています。各言語のメリットデメリットは個人で調べてください。
https://www.ev3dev.org/docs/programming-languages/
# leJOS
![leJOS](https://storage.googleapis.com/zenn-user-upload/1ff1e36ec8fe-20231028.jpg)
Javaをベースに作られており、JVM言語ならほとんど動かすことができます。JVM言語の中にはスクリプト言語の「Groovy」などもあり、幅広く選ぶ事ができます。
また機能面でも充実しており、例えば遠隔操作やPCからプログラムの実行なども可能です。
私のイチオシのOSです。本読んでください。
https://zenn.dev/sasnews/books/249f78f69b08d0
# MonoBrick
![MonoBrick](https://storage.googleapis.com/zenn-user-upload/ea7b5b4c8c06-20231028.jpg)
Linux上でexeを動かすMonoをベースとしていてC#、F#、IronPythonなどの.NET言語を動かすことができます。
おすすめポイントとして他のOSにはない圧倒的なフォントの美しさがあります。なぜかフォント作りを頑張っているんですよね。
# EV3RT
![EV3RT](https://storage.googleapis.com/zenn-user-upload/36b875fdfd2f-20231028.jpg)
言語はC、C++が使用できますが、実際に調べてみるとm-rubyやRustを動かしている人もいるOSです。高速な実行速度が必要な人には一択でしょう。
また起動速度も早いです。OSの起動は約5秒ですがそのほとんどがEV3のBIOSの起動時間なのでOS自体はほぼ0です。
# その他
## CoderZ
https://gocoderz.com
情報がほとんどないためわからないが、ブラウザ上でのシミュレーションを基本としている。どのような形でエクスポートできるのだろうか。
## Open Roberta Lab
https://www.open-roberta.org
ブロック言語を使用してプログラムを作成し、各OSで使用できるようにコンパイルする。
現在使えるOSは「ev3dev」「leJOS」「c4ev3(?)」の3つである。メモ機能やシミュレーションモードなど機能が充実しており、各OSの言語の書き方の勉強などにも使える。
Firestoreで特定の日時以降のデータを取得する

## 特定の日付より未来のデータを取得する
- 例）7月1日以降のデータを取得したい場合
```dart
DateTime startDate = DateTime(now.year, 7, 1, 0, 0);
final snapshot = await FirebaseFirestore.instance
  .collection('COLLECTION_NAME') // コレクション名
  .doc('DOCUMENT_ID') // ドキュメントID
  .orderBy('TIMESTAMP_FIELD') // 比較するコレクションのフィールド名
  .startAt([Timestamp.fromDate(startDate)]) // クエリの開始日
  .get();
```

## 特定の日付より過去のデータを取得する
- 例）7月1日以前のデータを取得したい場合
```dart
DateTime startDate = DateTime(now.year, 7, 1, 0, 0);
final snapshot = await FirebaseFirestore.instance
  .collection('COLLECTION_NAME') // コレクション名
  .doc('DOCUMENT_ID') // ドキュメントID
  .orderBy('TIMESTAMP_FIELD', descending: true) // // 比較するコレクションのフィールド名
  .startAfter([Timestamp.fromDate(startDate)]) // クエリの開始日
  .get();
```


## Converter
- FirestoreはTimeStamp型、FlutterはDateTime型なので変換する必要があるため以下のコンバーターを使用したような、しなかったような...
```dart
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:freezed_annotation/freezed_annotation.dart';

class TimestampConverter implements JsonConverter<DateTime, Timestamp> {
  const TimestampConverter();

  @override
  DateTime fromJson(Timestamp value) => value.toDate();

  @override
  Timestamp toJson(DateTime value) => Timestamp.fromDate(value);

  static DateTime? fromJsonNullable(Timestamp? value) => value?.toDate();
}
```

## 所感
多分他にもいい方法があるように思いますが、意外とFlutterでTimeStamp型のクエリをしてる記事が少なかったので書いてみました
endAt,endBeforeについても時間があればまとめておきたいですね

## 参考
https://firebase.google.com/docs/firestore/query-data/query-cursors?hl=ja
https://qiita.com/koffee0522/items/c025e3d7d888c4a9a6e3
https://zenn.dev/sukedon/scraps/94eb764fa021e8
Dockerでポスグレ(v.14)を立てるときのヘルスチェック

# 初めに

Docker(Docker Compose)でポスグレを構築したい時、別で立てているアプリケーションのコンテナなどからアクセスする場合にDocker Composeのhealthcheck機能で待機すると思います。

この際、ネットで調べて出てくるヘルスチェックの方法（コマンド）は恐らく以下の2種です。

- pg_isreadyを使う
- psqlを使う

複雑なことをするならpsqlを使用したシェルスクリプトを作りますが、今回は簡単に**pg_isready**を使用する方法で。

# 最終的な設定

```yaml
services:
  workspace:
    # 待機する側のコンテナ
    image: busybox
    tty: true
    stdin_open: true
    depends_on:
      # これで"local_db"のhealthcheckが成功するまで開始を待つ
      local_db:
        condition: service_healthy

  local_db:
    image: postgres:14
    environment:
      POSTGRES_DB: local_db
      POSTGRES_USER: local_user
      POSTGRES_PASSWORD: password
    ports:
      - "5432:5432"
    volumes:
      # データの永続化
      - db_volume:/var/lib/postgresql/data
    healthcheck:
      # 実行するコマンド。ここがすべて！
      test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB} || exit 1"]
      interval: 10s
      timeout: 10s
      retries: 5
      start_period: 5s

volumes:
  db_volume:

```

コメントで記載している通り、"local_db"のhealthcheckのtestに記載されたコマンドの内容がこの記事の主題です。

# ダメだったパターン集

ポスグレのコンテナにヘルスチェックを行うコマンドの例はネットで調べるといくつか出てくるんですが、うまくいかなかったり、うまくいったようでエラーっぽいログは出ていたりと微妙な感じでした。

## ただの"pg_isready"だけ

公式でまっさきに出てくるこの設定だと、

```yaml
test: ["CMD-SHELL", "pg_isready"]
```

以下のようにrootというロール？は無いですよとのことでエラーになります。

```tex
2024-07-15 09:13:09.621 UTC [39] FATAL:  role "root" does not exist
```

## ユーザー名も指定

また、よく出てくるこの設定ですと、

```yaml
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} || exit 1"]
```

以下のように接続先DBがなぜかユーザー名と同じになるらしく、エラーログが出てしまいます。

```tex
2024-07-15 09:11:08.364 UTC [39] FATAL:  database "local_user" does not exist
```

## "CMD"で実行

先に紹介した成功パターンのコマンドでも、"CMD"で実行するとうまくいきません。

```yaml
test: ["CMD", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB} || exit 1"]
```

結果。ヘルスチェックのログを確認。
以下のコマンドはjqを実行可能である必要があります。


```bash
docker inspect --format "{{json .State.Health }}" <container name> | jq
```

```json
{
      "Start": "2024-07-15T09:20:14.587660971Z",
      "End": "2024-07-15T09:20:14.618478886Z",
      "ExitCode": -1,
      "Output": "OCI runtime exec failed: exec failed: unable to start container process: exec: \"pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB} || exit 1\": executable file not found in $PATH: unknown"
    }
```

理由はよく調べてません…（CDMとCMD-SHELLの違いわかってない）

# おわりに

というわけで結論としては冒頭に書いたようなyamlとなります。

とにかくコマンドがこれじゃないと正しく動かないだけなので、ヘルスチェックの他の項目であるintervalとかretriesについては各自の都合いい感じで設定してください。

公式や他の記事がうまくいかないのは、ポスグレのバージョンが13以前だとうまくいくのかな…
type-challenges 中級編6: Append Argument, Permutation, Length Of String

# type-challenges 中級編6: Append Argument, Permutation, Length Of String

## はじめに

[GitHubのtype-challengesリポジトリ](https://github.com/type-challenges)は、TypeScript型システムの理解を深めるための型クイズ問題集です。高品質な型を作成することで、バグを減らし、プロジェクトの保守性を向上させることができます。今回も中級編から3つの問題に挑戦します。

### 1. Append Argument

与えられた関数型 `Fn` と任意の型 `A` に対して、関数型 `Fn` の引数リストの最後に型 `A` を追加した新しい関数型を生成します。

#### 例

```typescript
type Fn = (a: number, b: string) => number

type Result = AppendArgument<Fn, boolean>
// expected to be (a: number, b: string, x: boolean) => number
```

#### 私の回答

```typescript
type AppendArgument<Fn, A> = 
    Fn extends (...args: infer R) => infer V ? (...args: [...R, A]) => V : never
```

#### 解き方

- `Fn extends (...args: infer R) => infer V` で、関数型 `Fn` の引数リスト `R` と戻り値型 `V` を抽出します。
- 新しい関数型の引数リストとして、既存の引数リスト `R` の最後に型 `A` を追加すればOK。

:::note info
関数の引数リストは`...args: infer R`で型推測しちゃいましょう。
それさえできれば簡単。
:::

### 2. Permutation

Union 型を、その順列の配列に変換する型を実装します。

#### 例

```typescript
type perm = Permutation<'A' | 'B' | 'C'>; 
// expected to be ['A', 'B', 'C'] | ['A', 'C', 'B'] | ['B', 'A', 'C'] | ['B', 'C', 'A'] | ['C', 'A', 'B'] | ['C', 'B', 'A']
```

今回わからず、答えを見ました、
参考回答

```typescript
type Permutation<T, K = T> =
  [T] extends [never] ? [] :
  K extends K ? [K, ...Permutation<Exclude<T, K>>] : never
```

#### 解説

- Union 型 `K` の各要素について、その要素を先頭に持ち、残りの要素の順列を再帰的に計算するようになっているようです。
:::note warn
```ts
K extends K ? X<K> : never
```
(KはUnion型)
って書くとKのUnionの数評価されて各イテレーションごとに`X<K>`が出てくるらしい....
知らなかった...
:::


- 各ステップで、Union 型 `T` から現在の要素 `K` を除外して次の順列を計算します。
- その際に出た`never`型は
```ts
[T] extends [never] ? [] :
```
で空配列を返して対応しています。

:::note info
いや難しかった。解説読んでもちょっと理解に時間が掛かってしまった、、
:::

### 3. LengthOfString

文字列リテラルの長さを計算する型を実装します。

#### 例

```typescript
type length = LengthOfString<'reina'>; // expected to be 5
```

#### 私の回答

```typescript
type LengthOfString<S extends string, Arr extends string[] = []> = 
  S extends `${infer First}${infer Rest}` ?  
  LengthOfString<Rest, [...Arr, First]> :
  Arr['length']
```

#### 解き方

- ``S extends `${infer First}${infer Rest}` `` で、文字列 `S` の最初の文字 `First` と残りの文字列 `Rest` に分割します。
- `First` をカウント用の配列 `Arr` に追加し、再帰的に `Rest` を処理します。
- 文字列 `S` が空になるまで再帰し、最終的に配列 `Arr` の長さを返します。

:::note info
地道に文字列を配列にしているだけですね！
:::

### まとめ

このように、TypeScriptの型システムを理解し、実際に型を実装することで、より安全で保守性の高いコードを書くことができます。ぜひこれらの課題を解いて、型力UPしてみてください。

### 参考記事

- [TypeScript公式ドキュメント](https://www.typescriptlang.org/docs/)
- [type-challenges GitHubリポジトリ](https://github.com/type-challenges/type-challenges)
macのzshでtreeをつかう

個人的「質はともかく継続する」38日目です。

macでzshを利用中にtreeコマンドを使おうとしたら、インストールされていなかったのでメモ。

## brewでインストール

```sh
brew install tree
```

表示された。

```text
├── 第一章
│   ├── 1.はじめに.md
│   ├── 2.Markdownの概要.md
│   └── 3.見出し.md
└── 第二章
    ├── 4.文字装飾.md
    ├── 5.リスト.md
    └── 6.コードブロック.md
```
スプレッド構文について

スプレッド構文とは
- 配列の値を展開する
- 引数を配列として取得する

を行うことができる。

今回は展開するパターンの例

```js
const a = [1,2,3,4,5]
const max = Math.max(...a)
console.log(max)
```

Math.maxメソッドは複数の値から最大を返すメソッド。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Math/max
一つ一つ設定すると大変なので、配列を...で展開するのがスマート
【Angular】Angular CLI コマンド make-this-awesome を知っていますか

小ネタ

```bash
% ng make-this-awesome
Let's take a look... nope, it's all good!

% ng make-this-awesome
You're already doing great.

% ng make-this-awesome
Nothing to do; already awesome. Exiting.
```

ランダムに褒めてくれたりするだけのコマンド

https://github.com/angular/angular-cli/blob/6f521fbc91631961f7c8a4799bb2fb0cfc3f4cdb/packages/angular/cli/src/commands/make-this-awesome/cli.ts
[Power Automate]クラウドフローとデスクトップフローの接続ができない原因かも？「デスクトップマシンの登録に関するテナントの制限」

こんにちわ、 [のりじ](https://x.com/nori790822) です。

Powe Automateのクラウドフローからコネクタでデスクトップフローを呼び出すことが可能です。
この仕組みを作成する場合、「Power Automateコンピューターランタイム」で「コンピューターの設定」が必要ですが、「環境」が選択できず個人的にハマったのでメモ。

## 1. 「コンピューターの設定」で「環境」が選択できない！？

クラウドフローとデスクトップフローを連携して利用する場合、OSのバージョンとライセンスに問題がなければ利用可能です。

- [クラウド フローからデスクトップ フローをトリガーする](https://learn.microsoft.com/ja-jp/power-automate/desktop-flows/trigger-desktop-flows)

![PAD20240715-1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103396/adc3d51f-a66c-2fd1-24c4-9666e2ad103b.jpeg)

クラウドフロー側で「接続」を何度設定してもうまくいかなかったので、一応デスクトップフロー側（Power Automateコンピューターランタイム）も確認してみることに。
すると「環境」が選択できず、上図のような表示が出ました。

## 2. Power Automate デスクトップマシンの登録に関するテナントの制限

公式ドキュメントを確認してみると、以下の記載が。
- [Power Automate デスクトップマシンの登録に関するテナントの制限](https://support.microsoft.com/ja-jp/topic/power-automate-%E3%83%87%E3%82%B9%E3%82%AF%E3%83%88%E3%83%83%E3%83%97%E3%83%9E%E3%82%B7%E3%83%B3%E3%81%AE%E7%99%BB%E9%8C%B2%E3%81%AB%E9%96%A2%E3%81%99%E3%82%8B%E3%83%86%E3%83%8A%E3%83%B3%E3%83%88%E3%81%AE%E5%88%B6%E9%99%90-f0b44662-7a18-403d-989a-c1445c376768)

```
デスクトップ用 Power Automate バージョン 2.24 以降では、次の管理者特権が必要です。
- マシンが登録されているテナントを変更する。
- AAD 参加済みマシンを AAD 参加済みテナントとは異なるテナントに登録する。
```

・・・はい、個人PCを放置しすぎました🫠
というわけで、「管理者特権」を設定していきます。

## 3. 特定のテナントを許可する

公式ドキュメントには色々なパターンが記載されていますが、「登録テナント許可リスト」の対応で大丈夫かと思います。マシンは常に許可リスト内のテナントへの登録を許可し、他のテナントへの登録を拒否する、というものです。

### 3-1. レジストリ エディターを実行する

![PAD20240715-2-1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103396/7bee6188-214f-a377-dc85-7e1ca10c49ab.jpeg)

「検索」に「レジストリ」と入力し、レジストリエディターを開きます。

![PAD20240715-2-2a.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103396/2c6c2b90-ace8-a2a2-2ff7-bc6793a63a03.jpeg)

以下の内容をたどっていき、最終的に右側に「Registration」の中身が表示されている状態にします。

```
Computer\HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Power Automate Desktop\Registration
```
### 3-2. 新しい文字列を追加する

![PAD20240715-2-3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103396/29724577-56d3-1c8f-4271-a0e7849a8f6d.jpeg)

上部メニューの「編集」→「新規(N)」→「文字列値(S)」をクリックします。
名前は「AllowedRegistrationTenants」に変更します。

### 3-3. テナントIDを入力する

![PAD20240715-2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103396/e440e681-b8b6-3fa4-8baa-938a937bbfc9.jpeg)

「値のデータ化」の部分に、マシンが登録を許可する必要があるテナントIDを入力します。
テナントIDの確認方法は「3-4. テナントIDの確認方法」で。
なおテナントIDは、コンマ区切りで複数登録できるようです。

### 3-4. テナントIDの確認方法

テナントIDは、[Power Automate ポータル](https://make.powerautomate.com/)で確認できます。
Power Automate ポータルにサインインしたら「Ctrl + Alt + A キー」を押します。

![PAD20240715-2-4.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103396/e940a912-9d92-b0a9-31c2-ad281aa2a8d2.jpeg)

JSONが表示されるので「userInfo」でページ内検索し、「tenantId」の文字列（図中の赤枠内）がテナントIDになります。

以上の設定が完了したら、「Power Automateコンピューターランタイム」を表示します。
無事に「環境」が選択できるようになった！

## 最後に
私は「レジストリいじるん？怖ッ」となったんですが、単純に追加で済んだのでよかったです。
クラウドフロー⇒デスクトップフローの接続がうまくいかない場合、クラウドフローの接続情報だけでなくデスクトップフローも確認しようね、という話でした。
【Vercel】お名前.comで取得したドメインの設定方法

## はじめに
お名前.com で取得したドメインをVercelで設定する方法について紹介します。

https://vercel.com/

## 手順
1. ドメインの取得（本記事では省略）
2. Vercel側の新規ドメイン設定
3. お名前.com側で取得したドメインのDNS設定
4. Vercelで確認

## 設定します
### 001. ドメインの取得
本記事では省略します。

### 002. Vercel側の新規ドメイン設定
1. Vercelのプロジェクトページにアクセス。
2. Settingタブを押下。
3. Domainsメニューを押下。
4. 取得したドメインを入力し、Addする。
![スクリーンショット 2024-07-15 1.13.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3334980/dede78bd-85d0-aab1-b939-02b026f6a93d.png)
5. 一番上を選択し、Addする。
![スクリーンショット 2024-07-15 1.31.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3334980/47a6f239-ff9e-3933-964a-3c615eba96e0.png)

6. Aレコードの確認（お名前.com の設定画面で必要）
![スクリーンショット 2024-07-15 1.14.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3334980/ea5358f4-6171-c091-e34e-4502643ffef8.png)

7. CNAMEレコードの確認（お名前.com の設定画面で必要）
一番上の選択を行った場合は、こちらも確認が必要です。
![スクリーンショット 2024-07-15 1.37.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3334980/14c2c42c-f41e-6eee-941f-970d0aa5db5f.png)
**※ 一番最後の 「.」は不要**

### 003. お名前.com側で取得したドメインのDNS設定
1. 取得したドメインのDNS設定ページを開く。
![スクリーンショット 2024-07-15 1.17.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3334980/f1b23ead-1efb-97e6-7036-68822dac5ded.png)
2. Aレコード、CNAMEレコードの入力
![スクリーンショット 2024-07-15 1.19.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3334980/49fe906d-22c7-ede6-d77c-6c584ec51eb2.png)

3. 設定を保存

### 004. Vercelで確認
ちょっと反映に時間がかかるかも。私は10~15分かかりました。

Webアクセスできれば完了です。
お疲れ様でした 🤲

## まとめ
ちょっと調べてみましたが、Vercelでは本番環境、確認環境といった環境毎でのドメインの登録もできるようです。（便利 😳）

環境変数もGUIで簡単に設定できますので、かなり強いですよね。

## 参考
https://vercel.com/docs/projects/domains#domains-overview

https://vercel.com/docs/getting-started-with-vercel/domains#add-a-domain
【Azure CosmosDB】存在しないデータをSELECTするだけで例外になる

解決方法わかりません。

CosmosDBからID指定でデータを取得する際は、[Container.ReadItemAsync](https://learn.microsoft.com/ja-jp/dotnet/api/microsoft.azure.cosmos.container.readitemasync?view=azure-dotnet)を使うと楽です。

```cs
use Microsoft.Azure.Cosmos;

CosmosClient cosmosClient = new("エンドポイント");
Database database = cosmosClient.GetDatabase("DB名");
Container container = database.GetContainer("テーブル名");
ItemResponse<DummyModel> itemResponse = await container.ReadItemAsync<DummyModel>("ID", new PartitionKey("partitionKey"));
```

ところが最後の`ReadItemAsync()`で、存在しないIDを指定すると[CosmosException](https://learn.microsoft.com/ja-jp/dotnet/api/microsoft.azure.cosmos.cosmosexception?view=azure-dotnet)が発生します。
なんで。

さらにCosmosDB側にも404のステータスコードが発生します。
なんで。

普通に、存在しなかったらnullとか空配列を返してくれるだけでいいんだけど。
せめて[ItemRequestOptions](https://learn.microsoft.com/ja-jp/dotnet/api/microsoft.azure.cosmos.itemrequestoptions?view=azure-dotnet)とかで対応できないものでしょうか。
こんなクッソどうでもいいログがいちいちLog Analyticsとかにまで流れて無駄なんで止めたいんですが。


こんなおかしな挙動何も言われないわけがなく既に[Issue](https://github.com/Azure/azure-cosmos-dotnet-v3/issues/692)になっているのですが、しかしこれ対応なんてしねえよでFAです。
どうにかするには[Streaming API](https://github.com/Azure/azure-cosmos-dotnet-v3/blob/63f4799b5eb7192401159548e346cb383570e07b/Microsoft.Azure.Cosmos.Samples/Usage/ItemManagement/Program.cs#L222)を使え、っことらしいのですが、このStreaming API全然情報が出てこないのでよくわからない。
どうしてFromStreamとか[いちいち自力で実装しないといけない](https://github.com/Azure/azure-cosmos-dotnet-v3/blob/63f4799b5eb7192401159548e346cb383570e07b/Microsoft.Azure.Cosmos.Samples/Usage/ItemManagement/Program.cs#L431)んですか？
オブジェクトの分割代入について

配列を使って一気に変数を宣言する際に、`,`やスプレッド構文を使って
- 特定の値の取得
- いらない値の選別

ができる
```js
const a = [1,2,3,4,5]
const [ ,b,...rest] = a
console.log(b,rest) // 2 [ 3, 4, 5 ]
```
【Git】コミット時のコメントの付け方

# はじめに
Gitでコミットする場合はコミットメッセージが必須となります。
※コミットメッセージが空のままで実行するとコミットに失敗します。

このコミットメッセージですが、本当に適当に書いている人が多いです。。。
この記事ではコミットメッセージの重要性と記載方法について記載していきます。

# Gitコミットメッセージはなんで記載するの？
まず、コミットメッセージの記載する理由は以下の通りだと考えています。
・<font color="Red">一目でどんなコミット内容なのか判断するため</font>
・<font color="Red">何故この修正内容になったか理由や意図について簡易的に説明しやすいようにする為</font>
・revertしたい時にどのコミットを対象とするか判断しやすい
　→revert自体はあまり推奨されるコマンドでは無いですが、、
・ある時点でどのような修正が入ったか確認したい時に便利
　→例えば、
　　　大体この辺りのバージョンから特定のバグが発生するようになった、
　　　では具体的にどのコミットから発生するようになった？
　　とかの場合に役立つ
・コードレビュー時の差分確認の時に役立つ

不要な修正はコミットすべきで無いので、コミットするからには
必ず修正する理由や意図があるはずです（当然ですが無いならコミットすべきではありませんw）。

そのため、**修正する理由や意図を簡潔に一目で分かるような内容にすること**が重要です。



# 記載内容
コミットメッセージに記載する内容としては、以下が挙げられます。
・概要
・原因について記載する
・コミットの理由や意図について
・管理ツールのチケットなどがあるのであれば、チケットのURLを貼ってもOKだと思う
・コミット種別
　→コメントでわかるようであれば不要な気もする。
　　ただし、一目でわかるようにするためには有効だと思うので、シンプルな少ない種別ルールであれば良いと思う

次の項目から、具体的に悪い例/良い例について記載していきます。

# 悪い例
```
修正
```

まず、よく見かけるBadな例です。

何の修正か全く分からない内容となります。
修正と一言で言っても無数にありますよね？
・機能追加のための修正？
・リファクタリングのための修正？
・バグ修正？
・テストコードの修正？

私が過去に見たコミットメッセージで驚いたのは、
"修正"というコミットメッセージで一日に20回ほどコミットしている人がいたことです。

コミットの粒度という点においても不適切ですし、
コミットメッセージを何にも理解していないだろうなと。。
※この人のコードを私がレビューしましたが、チームのコーディングルールを200%無視したマイルールで実装している人でしたね。。

ちなみに、コミットの粒度というのも考えておく必要があります。
というかチームとして各メンバにこの辺りは認識を合わせておく必要があります。
特にレビューしてもらう必要があるのであれば、ある程度の単位（例えば細かくても良いから１機能実装したら１コミットとか）でコミットした方が良いです。


```
Fix bug

とか

レビュー指摘事項対応
```
次のBadな例です。

バグをどう直したのか？どういう意図で直したのか？
を知りたいのに、何の意味もないコミットメッセージになっていますよね？

# 良い例
良いと思われる例をいくつか記載する。

・機能追加
```
add: xxx画面を追加し、xxx画面から遷移出来るように修正
```

・バグ修正
```
fix: hogehoge画面でxxx操作したときに落ちるバグ修正。
　　　原因：xxxの場合にarray index out of bounds
   　修正内容：配列チェックを追加すると共に、配列範囲外にアクセスしないよう類似チェックをした結果を反映
　→バグチケット：https://xxx
```

・リファクタリング
```
refactor: hogehoge()メソッドのxxxの処理をxxxに修正
　→詳細内容を記載したチケット：https://xxx
```

あくまで例として記載しましたが、
長すぎるコミットメッセージも良くはありません。

そういった意味ではバグ修正時のメッセージは少々長いですが、、
原因や修正内容を記載しようとするとこれくらいになるんだよなー。


# 重要なこと
とどのつまり、
<font color="Red">自分以外の第三者がコミットメッセージを見て理解しやすい内容になっているか</font>どうか
が重要です。

そのため、第三者が母国語が英語の外人の担当者が見る人が大多数であれば、英語で書いた方が良いです。



# 余談
これは余談ですが、コミットメッセージに適切なコミットの理由や意図について記載したとしても、
コードやDocコメントなどを見ても修正の意図や理由が分からない場合はその修正内容は不適切なことになります。
当然ですが、この場合はコミットする前に修正内容を見直しましょう。

以上
日本市場向けのVue 3.0ベース管理システム「vue-jp-admin」を紹介します

# vue-jp-admin を紹介します

長年日本でソフトウェア開発を行っている私が、Vue 3.0を基盤としたバックエンド管理システム「vue-jp-admin」を開発しました。このプロジェクトは、日本市場向けに特化し、ウェブサイト管理、会員センター、CMS、CRM、OAなど、幅広いWebアプリケーションの迅速な開発をサポートします。

![pc01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3833523/d594fb92-17ca-750b-f6c8-d8fd53e65d95.png)
![pc02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3833523/86a833af-e1d9-0f5f-54af-5201db9200f1.png)
![mb01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3833523/795279a8-a80b-823b-8850-d8753eed7307.png)

## 特徴と利点

- **日本市場向け最適化**: 日本の開発者と市場のニーズを深く理解し、設計および最適化された機能セットを提供します
- **シンプルで使いやすい**: 精緻に封装されたフロントエンドコードは、使いやすく、エラーの発生確率が低いです
- **同時兼容移動端とPC端**: レスポンシブデザインにより、どんなデバイスでも快適にご利用いただけます

## 免費開源 & 本土化の建議

vue-jp-adminは完全に無料でオープンソースです。日本市場に最適化された開発のため、皆様の本土化の建議を歓迎します。

### 本土化の建議

- UI コンポーネントの追加や改善案
- 新しいプラグインの導入案
- 共通的な方法の改善案

例えば、以下のような提案をお待ちしています：

- 日本市場向けの特定のUIコンポーネントの要望
- データ処理やエラーハンドリングなどの共通メソッドの追加

建議は[GitHub Issues](https://github.com/yangrongwe/vue3-jp-admin)またはQiitaのコメントを通じて提供していただけます。皆様の貴重な建議に基づいて、vue-jp-adminをより良いフレームワークに進化させていきます。

## プロジェクトの詳細

vue-jp-adminは現在積極的に開発中であり、新機能や最適化のアップデートを定期的に行っています。日本市場で必要とされる優れた管理システムソリューションを提供するため、私たちの開発コミュニティにぜひご参加ください！

## 技術スタック

- **Vue 3**: プログレッシブJavaScriptフレームワーク
- **Vite**: 迅速なフロントエンドツールチェーン
- **Pinia**: 次世代の状態管理ライブラリ
- **TypeScript**: 静的タイプを提供するJavaScriptのスーパーセット
- **Vuetify 3**: Vue.js用のマテリアルデザインコンポーネントフレームワーク
- **VxeTable**: 豊富な機能を提供するテーブルコンポーネント

このプロジェクトに興味を持っていただけたら嬉しいです。質問やフィードバックがありましたら、お気軽にご連絡ください！また、jp-adminが役立つと感じていただけたら、ぜひ「いいね」してください。どうぞよろしくお願いします。

### お問い合わせ先

- Email: yangrongwei1996@gmail.com
- WeChat: 13196848849
- GitHub: [https://github.com/yangrongwe/vue3-jp-admin](https://github.com/yangrongwe/vue3-jp-admin)
「Composeの基本レイアウト」のメモ#7 ~Favorite collections のグリッド - 遅延グリッドの実装~ 

### 2つの固定行を持つグリッド
+ `LazyHorizontalGrid`で作成する
    + パラメータ
        + `rows`, `modifier`

#### 最小構成
```Kotlin
@Composable
fun FavoriteCollectionsGrid(
    modifier: Modifier = Modifier
) {
    LazyHorizontalGrid(
        rows = GridCells.Fixed(2),
        modifier = modifier,
        
    ) {
        items(favoriteCollectionsData){ item -> 
            FavoriteCollectionCard(item.drawable, item.text)
        }
    }
}
```

#### LazyHorizontalGridの微調整
+ Gridは親要素いっぱいまで広がるため、高さを決める
    + `modifier = modifier.height(168.dp)`
+ グリッドの水平方向の contentPadding は 16 dp である
    + `contentPadding = PaddingValues(horizontal = 16.dp)`
+ 横方向と縦方向の配置は、16 dp の間隔で行われる
    + `horizontalArrangement = Arrangement.spacedBy(16.dp)`
    + `verticalArrangement = Arrangement.spacedBy(16.dp)`
+ グリッドの高さは 168 dp である
    + `modifier = modifier.height(168.dp)`
+ FavoriteCollectionCard の修飾子は高さ 80 dp を指定する
モバイルアプリのアイデアを考えてみる。

実現したらワクワクするようなアイデアを書き起こしてみる。

## コンセプト

旅行を支援するアプリです。ユーザーがチャットで旅行に行きたいと話しかけるところからスタートしてAIが会話を通じて「ここに行ったら面白い体験ができます」などのおすすめをしていくアプリです。ユーザーは検索するのではなく会話を楽しみながら旅行計画をたてていく事がコンセプトです。

## ユーザーの何を叶える？

友達と旅行計画を立てる楽しみをAIといつでもできる。おもてなしをする。

## 機能

- AIと旅行の計画？話し合いをする。結論がでなくても良い
1. **会話型AIアシスタント**
    - **旅行先の提案**: ユーザーの興味や過去の旅行履歴に基づいて、AIが適切な旅行先を提案します。
    - **プランニング支援**: 旅行日程、観光スポット、食事場所、宿泊先などを提案し、ユーザーが計画を立てるのをサポートします。
2. **ユーザーの好みを学習**
    - **カスタマイズ**: ユーザーの好みや過去のフィードバックをDBにストックしより個別化された提案を行います。
3. **インタラクティブな会話体験**
    - **ユーモアとパーソナリティ**: AIにユーモアやパーソナリティを持たせ、会話が楽しいものになるように設計します。

## 考慮点

1. **データのプライバシーとセキュリティ**
    - ユーザーの旅行履歴や個人情報を適切に管理し、プライバシーを保護する仕組みを導入する。
2. **ユーザーエクスペリエンス**
    - 直感的で使いやすいインターフェースを設計し、会話の流れをスムーズにする。
    - 会話の途中で離脱しても再開しやすいようにする。
3. **多言語対応**
    - 国際的な旅行者を対象にするため、多言語対応を検討する。
4. **競合他社との差別化**
    - 他の旅行支援アプリとの違いを明確にし、ユニークな価値を提供する。
【Datadog】DogStatsD is 何

Datadog Fundamentals 受験に向けた個人的なアウトプットです。


## DogStatsDとは
DogStatsD は、Datadog が提供するメトリクス収集サービスで以下のような特徴がある。
- Datadog Agent に付属する軽量なメトリクス集計サービス
- StatsD プロトコルを拡張し、Datadog 固有の機能を追加
- アプリケーションからカスタムメトリクスを簡単に Datadog に取り込む為の手段

https://docs.datadoghq.com/ja/developers/dogstatsd/

## 主な機能
- カウンター、ゲージ、ヒストグラム、セットなど様々なメトリクスタイプに対応
- タグ付けによるメトリクスへのメタデータ付与
- UDP または UNIX ドメインソケットでのデータ受信
- データの収集と Datadog への転送

## メリット
- アプリケーション分離によるパフォーマンスへの影響の最小化
- 言語に依存しない実装が可能、豊富なクライアントライブラリ
- サンプリングによるネットワーク使用量の削減

## DogStatsD の使い方
- Datadog Agent のインストール
- アプリケーションへの DogStatsD クライアントライブラリの導入
- メトリクス送信コードの実装
- Datadog ダッシュボードでのメトリクス可視化

## まとめ
DogStatsD を使うことで、開発者は簡単にアプリケーション固有のメトリクスを収集・可視化でき、アプリケーションのパフォーマンスや動作をより詳細に把握することが出来る。
コールバック関数とアロー関数の省略記法について

以下のようなコードは有効である
```js
const a = [1,2,3]
const cb = (v => console.log(v)) // コールバック関数
a.forEach(v => console.log(v)) // アロー関数を使って、第一引数に反復している値を取得可能
a.forEach(cb) // forEachはコールバック関数を渡せる
```

forEachメソッドは反復可能オブジェクトで使えるメソッドであり、コールバック関数を渡してループを回すやり方と直接アロー関数を引数に渡すやり方がある。

そしてアロー関数は１行なら
- ()
- {}

の省略が可能。

よって、上記のような書き方が可能である

# 記事を書いた動機 & 書いた感想

色んな所で ()を省略したり、 {}を省略していて書いてる処理を見つけてモヤモヤしていた。
jsでも色んな省略記法があるので、たまには基礎の学習が有効に感じる
作成するドキュメントが多すぎ問題について立ち止まって考える

# 課題意識
作成するドキュメントが多すぎる。
本当にコレって必要なの？と思うことがある。


プロジェクトにおける成果物を文書化するケースとしないケースをもっと明確にしたい。
文書化する範囲としない範囲はどのように画定するのがよいだろうか？

文書化するかどうかを決めるにあたって考慮するとよい要因を記載した。このソースは、参考資料に記載する。

# 文書化するかどうかに影響する要因
**1. プロジェクトリスク**
例えば、文書化して合意をとらないと後で「言った言わない」論争になるリスクを考慮する、あるいは、文書化してはいけないものもある

**2. ドキュメントがプロジェクトに提供する「付加価値」**
本当に、「付加価値」はあるか？
あるならば、どれくらいの量か？
を明確にしよう。ないor少ない、なら文書化しない方が時間の損失が少ないかもしれない。

**3. 開発手法または使用するアプローチ**
開発手法とは、ウォーターフォール型か、アジャイル型か、など。アジャイルアプローチでは、必要最小限の文書化を目標にする。

**4. 成果物の間にトレーサビリティが必要か否か**
トレーサビリティとは、要素間が対応づけられており、遡及できること。例えば、どのテストケースが、どのシステムの要件や仕様と対応づいているかを遡及できるようになっているか、などが相当する。テストケースが適切に要件をカバーしているかを知りたいならば、トレーサビリティが必要であり、テストケースの文書化が望ましいだろう。

# さいごに
成果物を文書化するかは、上記の4点を考慮しつつ判断しましょう。プロジェクトに無駄なドキュメントが減り、本当に必要なタスクに時間を割けますように！


# 参考資料

ISTQB®テスト技術者資格制度
Advanced Level シラバス日本語版
テストアナリスト
Version 3.1.1.J03 
p.20

https://jstqb.jp/dl/jstqb.jpdlJSTQB-SyllabusALTA_V311.J03.pdf
Mac テキスト・エディタで最初から新規ドキュメントを開く方法

Mac のテキスト・エディタを立ち上げると、デフォルトでは新規ファイルを作成するか、既存のファイルを開くかを選択するウィンドウが現れます。
しかし、既存ファイルを開きたいならファイルをクリックすれば良いだけなので、わざわざテキストエディタを開く際には、最初から新規ファイルを作成したいというケースの方が多いのではないでしょうか。
ネット検索してもなかなか方法が見つからなかったのですが、ようやく発見しました。

Terminal で書きコマンドを実行すれば完了です。

defaults write com.apple.TextEdit NSShowAppCentricOpenPanelInsteadOfUntitledFile -bool false

参考ページ
https://discussions.apple.com/thread/253444981?sortBy=best
DynamoDBのパーティションキー設計

# はじめに
今回はAmazon DynamoDBのパーティションキーについて深掘りしていきます！
効率的なパーティションキー設計は、DynamoDBのパフォーマンスとスケーラビリティに直結する重要な要素です。

# 対象読者
- DynamoDBを初めて使う人
- パーティションキーの設計に悩んでいる人
- データベースの効率化を図りたい人

# 目次
1. パーティションキーの基本
2. パーティションキーの設計方法
3. 効率的なパーティションキーの使用例
4. パーティションキー設計のベストプラクティス
5. まとめ

# 1. パーティションキーの基本

### パーティションキーとは？
パーティションキーは、DynamoDBテーブル内の各アイテムがどのパーティションに配置されるかを決定するためのキーです。このキーに基づいてアイテムは異なるパーティションに分散され、テーブル全体の負荷を均等に分散することができます。

:::note info
例えば、ユーザーIDをパーティションキーにすると、各ユーザーのデータが異なるパーティションに保存され、アクセス負荷が分散されます。
:::

# 2. パーティションキーの設計方法

### パーティションキーの選び方
良いパーティションキーには以下の特性が求められます：
- **一意性**: 各アイテムが一意に識別できること
- **均等分散性**: データアクセスが均等に分散されること
- **変更不要**: 一度決定したら変更する必要がないこと

例えば、ブログ記事のデータベースであれば、投稿IDや作成日時などがパーティションキーに適しています。

# 3. 効率的なパーティションキーの使用例

### 使用例1: ユーザーIDをパーティションキーにした場合
ユーザーIDをパーティションキーとして使用することで、ユーザーごとのデータを効率的に分散することができます。例えば、SNSアプリケーションでは、各ユーザーの投稿やコメントが異なるパーティションに保存され、アクセス負荷が均等に分散されます。

:::note info
ユーザーが1日あたりの投稿数が多くても、パーティションキーをうまく設計することで性能ボトルネックを避けることができます。
:::

### 使用例2: 複合キーの活用
複合キーにより、さらに細かなデータの分散が可能になります。例えば、ユーザーIDと作成日時を組み合わせてパーティションキーとすることで、同一ユーザーの大量のデータアクセスをさらに均等にすることができます。

# 4. パーティションキー設計のベストプラクティス

### シャーディング (Sharding)
データが集中しがちなとき、シャーディングを行ってデータをさらに細かく分散する方法があります。例えば、パーティションキーバリューの最後に乱数を追加する方法があります。

:::note info
これにより、2014-07-09.1 や 2014-07-09.2 などのパーティションキーバリューが生成されます。
:::

### データアップロードの最適化
大量のデータを一度にアップロードする際もパーティションキー設計は重要です。パーティションキーが均等に分散されるように設計されていないと、一部のパーティションが過負荷になってしまいます。

:::note info
アップロード時にもシャーディング技術を使うことで、効率よくデータを分散させることが可能です。
:::

# まとめ
パーティションキーの設計はDynamoDBのパフォーマンスとスケーラビリティに直結する重要な要素です。これを適切に設計することで、大規模なデータ処理でも効率的に運用することができます。
参考になれば幸いです！

# 参考文献
- [DynamoDB パーティションキー設計のベストプラクティス](https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/bp-partition-key-design.html)
- [パーティションキーの均等分散](https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/bp-partition-key-uniform-load.html)
- [パーティションキーの分割（シャーディング）](https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/bp-partition-key-sharding.html)
- [データアップロードの最適化](https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/bp-partition-key-data-upload.html)
- [DynamoDBパーティションキーの選び方](https://aws.typepad.com/sajp/2017/02/choosing-the-right-dynamodb-partition-key.html)
[解決済み]insomniaでAPIエンドポイントがうまくいかない！(Laravel Sanctum)

**[解決しました](#解決20240716)**

```:環境
Laravel 11
Insomnia 9.3.2
```

# 目的
Laravel Sanctumを使ってinsomniaでAPIを取得する。

# 問題
404
![SCR-20240715-onjr.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3798584/c387b534-7efa-1566-c641-7b8259c711fc.png)

# コード
```:api.php
<?php

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\UserController;

Route::get('/user', function (Request $request) {
    return $request->user();
})->middleware('auth:sanctum');

Route::post('/login', [UserController::class, 'loginApi']);
```

```:UserController.php
public function loginApi(Request $request) {
    $incomingFields = $request->validate([
        'username' => 'required',
        'password' => 'required'
    ]);

    if (auth()->attempt($incomingFields)) {
        $user = User::where('username', $incomingFields['username'])->first();
        $token = $user->createToken('ourapptoken')->plainTextToken;
        return $token;
    }
    return 'sorry';
}
```

# 試み
- ルーティングの確認
- キャッシュ削除、再起動
- 誤字脱字確認
- `php artisan route:list`
`POST      login ... UserController@login`
- わざとusernameもしくはpasswordを間違える（変わらず404）
- `localhost:8000`ではなく`127.0.0.1:8000`も試す（変わらず404）
- 教材データと比較
- `/login`の競合を避けるため`/auth/login`へ（変わらず404）
- log確認（何も出ていない）

# 多分…
そもそも404なのでルーティングがうまく行っていないのではないかと思っているのだが、正しくルーティングできているはずだよな…？でも結果として404が出ているわけで…。
バージョンの違いで他にもファイルを構わなきゃならない可能性も大いにあるが、[リリースノート](https://readouble.com/laravel/11.x/ja/sanctum.html)を見ながら設定してもよくわからん！！！！

GPT、Perplexityに聞くも堂々巡り。
insomniaでなにか設定しなくちゃならない項目があるのかな？
GETからPOSTに変えたし、bodyの項目はJSONで書いている。構文ミスもない。

これまでで一番わからない。オワタ

# ブログ
**[Xはじめました](https://x.com/szkdog)**
IDがしっくりきていないので変わる可能性大

# 解決(2024/07/16)
`api.php`が読み込まれていなかったのが主な原因だった。
<br>
```:AppServiceProvider.php
Route::prefix('api')
    ->middleware('api')
    ->group(base_path('routes/api.php'));
```
上記を`AppServiceProvider.php`に記述しapi.phpを読み込み、
```:AppServiceProvider.php
RateLimiter::for('api', function (Request $request) {
    return Limit::perMinute(60)->by(optional($request->user())->id ?: $request->ip());
});
```
同じく`AppServiceProvider.php`にレートリミッターを設定して正しく動いた。
<br>

これらふたつのコードはGPTに考えてもらったものだが、`api.php`が読み込まれていないのは自分で突き止めた！
[これ](#コード)をどちらもコメントアウトしても404が変わらず、それどころか`api.php`に適当な文字を書いてもLogにすらエラーが出なかったことで特定できた。

これでわからなければ適当なところにLog出力して特定してみようと思っていたが、今回は運が良かった。
まあどこにLog出力コード書けばいいのかわからないんだけども…。

ひとまず一件落着。
順序を無視して全ての要素が含まれることをチェックしたい

Vecをテストするにあたって、順序を無視して全ての要素が含まれることをチェックする方法を紹介します。

まずはVecをソートする方法です。

```rust
let mut expected = vec![3,1,4,2,5];
let mut actual = do_something(5);

expected.sort();
actual.sort();

assert_eq!(expected, actual)
```

要素に重複がないことが明らかなら、HashSetを利用する方法もあります。

```rust
let expected = vec![3,1,4,2,5];
let actual = do_something(5);

let expected_set = expected.iter().collect::<HashSet<_>>();
let actual_set = actual.iter().collect::<HashSet<_>>();

assert_eq!(expected_set, actual_set)
```

**環境情報**

```
$ rustc -V
rustc 1.76.0 (07dca489a 2024-02-04)
$ cargo -V
cargo 1.76.0 (c84b36747 2024-01-18)
```
Qiitaに毎日投稿を続けるコツ

## はじめに

現在、Qiita投稿マラソンに参加しています。
この記事は36記事目です。毎日投稿を36日間継続しています。

この記事では、毎日投稿を続けたい方に向けて、この約1ヶ月間で得た毎日投稿のコツを共有します。

## 先に結論

- 習慣
    - 例外を作らない
    - 自分なりのやり方を早めに見つける
    - 「毎日投稿する」と宣言して逃げ場を無くす
- 書くときのマインド
    - その日に一番書きたいことを書く
    - ハードルを上げすぎない
- 日常
    - アウトプット前提にする
    - インプットを増やす
    - 日常の困りごとに積極的に取り組む

## 習慣

毎日続けるためには習慣が大事です。

**(1)例外を作らない**

投稿しない日を作らないようにします。

1日でも例外を作ってしまうと、2回目の例外が生まれやすくなるためです。

**(2)自分なりのやり方を早めに見つける**

序盤は「自分なりの方法を探る期間」とあらかじめ考えておきます。
試行錯誤しながら、継続しやすい形式やリズムを探っていきます。

例えば、私の場合は「その日に書いてその日に投稿する」というリズムがあっていました。

**(3)「毎日投稿する」と宣言して逃げ場を無くす**

相手は誰でも良いので「毎日投稿する」と宣言することで自分の逃げ場を無くします。

逃げ場を無くすことで、継続しやすくなります。

例えば、SNSに投稿したり、Discordでコミュニティに対して宣言したりします。


## 書くときのマインド

**(1)その日に一番書きたいことを書く**

私はその日に一番書きたいことを書くようにしています。

テーマ選びに時間をかけすぎないためです。

この記事も、今日書きたいと思ったテーマになります。

**(2)ハードルを上げすぎない**

毎日投稿に限りませんが、投稿のハードルを上げすぎないようにしています。

投稿のハードルを上げると、そもそも投稿できなくなるためです。

例えば、自分にとっては当たり前のような内容でも、誰かにとっては新しい学びになることがあります。


## 日常

**(1)アウトプットを前提にする**

アウトプットを前提に行動します。

その結果、気づきが増えます。そして、投稿のネタが増えていきます。

**(2)インプットを増やす**

アウトプットを増やすために、インプットも増やします。

私の場合、技術書を読む冊数を増やしました。

例えば、次の記事は技術書のアウトプットの記事です。

https://qiita.com/mkt_hanada/items/eb70657fd7c4a7c78907

**(3)日常の困りごとに積極的に取り組む**

日常で困ったことがあれば、積極的に関わって、課題に取り組むようにします。
個人やチームの困りごとに積極的に取り組みます。

困りごとは記事のネタになりやすいためです。

例えば、次の記事は困りごとをきっかけに書きました。

https://qiita.com/mkt_hanada/items/d62c3380181d87f8a2a5


## おわりに

この記事では、毎日投稿を続けるコツについて、私の経験を共有しました。

参考になれば幸いです。
PM2でNuxt3をデプロイする

## ローカルの設定
pm2をグローバルにインストールします。

https://pm2.keymetrics.io/docs/usage/quick-start/
```
yarn global add pm2
```

ecosystem.config.jsという設定ファイルを作る。
これは、本番サーバーの設定情報を書くので、
基本、.gitignoreするべきかと思ったが、
そうすると、後のコマンドでecosystem.config.jsファイルがないって
怒られるので、環境変数化したい

```:ecosystem.config.js
module.exports = {
  apps : [
    {
      name: 'my-nuxt-app',
      exec_mode: 'cluster',
      instances: 'max', // またはアプリケーションを実行したいインスタンスの数
      script: './src/.output/server/index.mjs',
      args: 'start'
    }
  ],
  deploy : {
    production : {
      user : 'EC2インスタンスのユーザー名',
      host : 'EC2インスタンスのIPアドレス',
      key  : 'あなたのSSHキーへのパス',
      ref  : 'origin/main',
      repo : 'あなたのGitリポジトリURL',
      path : 'EC2インスタンス上のアプリケーションのパス',
      'post-deploy' : 'npm install && npm run build && pm2 reload ecosystem.config.js --env production'
    }
  }
};

```

環境変数は、
```:ecosystem.config.js
deploy : {
    production : {
      user : process.env.SERVER_USER,
      host : process.env.SERVER_IP,
    }
}
```

みたいにすれば良い。

ローカルの.zshrcとかに、
`export SERVER_IP="ec2のパブリックIP"`みたいに記載しておけばOK

## 本番(EC2)の設定

まずEC2インスタンスを作成します。
ここではAmazon Linux2023の
t2.nanoにします。

作成して、実行したら、サーバーに入ります

```
 ssh -i 作成したキーペアのパス ec2-user@パブリックipアドレス    
```

サーバーに入ったら、
node.jsをインストールします
```
[ec2-user@パブリックipアドレス ~]$ sudo yum update
[ec2-user@パブリックipアドレス ~]$ sudo yum install -y nodejs git
```
とかでインストールしてもいいですし、nvmとかでインストールしても良い。
私はnvmでやりました

ちなみに、
```
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
```
みたいなやり方もあるようですが、
これを実行すると、
非推奨的な警告が出て、
アップデートされたやり方でやってくださいと出るので、
現在ではそちらでやる必要はありそうです。

node.jsをインストールしたら、
本番にも

```
npm install pm2 -g
```
をしておきます。

## デプロイ

まずは、
```
pm2 deploy ecosystem.config.js production setup
```
を実行します。

私はこれで死ぬほどハマりました。
先程の、ecosystem.config.jsは、

```
deploy : {
    production : {
      user : 'ec2-user',
      host : 'EC2インスタンスのパブリックIPアドレス',
      key  : 'EC2インスタンスに接続するためのkey-pair',
      ref  : 'origin/main',
      repo : 'git@github.com:user/sample.git',
      path : '/home/ec2-user/デプロイしたいディレクトリ', //絶対パス
      'post-deploy' : 'npm install && npm run build && pm2 reload ecosystem.config.js --env production'
    }
  }
```

ここのkeyですが、
ec2に接続するためのkey-pairです。
git cloneするときに使う、
githubに登録されているkeyではありません。

~/.ssh/id_rsaとかではないです。

でも、これだとどうやってgit cloneするのか疑問で、
これだけだと、
```
git@github.com: Permission denied (publickey).
fatal: Could not read from remote repository.
```

的なエラーに悩まされました。

これはローカルで、ssh-agentの設定をしなければならず、
どうもPM2のデプロイがそのような設定になっているっぽいです。

ec2では、ssh -T git@github.comを実行しても、
上手く行くし、git cloneも通るのに、
pm2 deployコマンド経由でcloneすると、
毎回引っかかるのはおそらくここが絡んでいるかと。

ローカルのsshファイルで
```:~/.ssh/config
Host ec2のパブリックIPアドレス
  ForwardAgent yes
```
と設定し、
```
ssh-add ローカルの秘密鍵の場所(.ssh/id_rsaみたいな)
```
これをやってからもう一度やると、
通りました。

ssh-agentの確認は、
```
ssh-add -L
```
でできます。

いやー、この辺ドキュメントに全く書かれていないので、
半ばあきらめていたのですが、よかったです。

最後に、
```
pm2 deploy ecosystem.config.js production
```

を実行します。

http:ec2のパブリックIP:3000で画面が見られればOKです。
「Composeの基本レイアウト」のメモ#6 ~7. Align your body の行の実装~ 

### [7. Align your body の行 - 配置](https://developer.android.com/codelabs/jetpack-compose-layouts?hl=ja#6)
+ スクロール可能な行の作成は、`LazyRow`を使用する
+ リストの要素は先ほど実装した AlignYourBodyElement コンポーザブルとする

#### 最小構成
```Kotlin
@Composable
fun AlignYourBodyRow(
    modifier
){
    LazyLow(
        modifier = modifier
    ){
        items(alignYourBodyData){ item -> 
            AlignYourBodyElement(item.drawable, item.text)
        }
    }
}
```

#### LazyRowコンポーザブルの微調整
+ 各子コンポーザブル間に固定スペースを追加する
    + `horizontalArrangement`に`Arrangement.spacedBy(8.dp)`を渡す
+ LazyRow の両側にもパディングを追加する
    + `modifier.padding`で設定するのではなく、`contentPadding`パラメータに`PaddingValues(horizontal = 16.dp)`を渡す
格安 8ch SSR モジュールを Hack

￥1000〜￥2000ぐらいで購入できる SSR (ソリッドステートリレー)ボード。
これをRaspberryPi につなげてみます。

![IMG_20240715_121533.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/30775190-fc5f-4253-bcc4-47c1035299d2.jpeg)

これは SSR を取り外し、4ch分を DC タイプに載せ替えたHack途中の写真です。


# 購入時のTips

High Level Trigger と Low Level Trigger があります。
Amazonで購入してみたら 高レベルトリガーと書いてありましたが来たものは Low Level Trigger だったりしました。

# 回路図
High Level Trigger のもの。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/64954e1d-3942-1651-46bf-e7d7f5939c59.png)

各CHごとにこの回路が入っています。

# SSR の交換

DCタイプに交換してみました。それに伴い、DC電源の供給もリレーボードからできるように変更しています。


![IMG_20240715_133012.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/f0a7d855-02af-c6b6-ce26-2921b33a8c6f.jpeg)


写真でパターンカットしてますが、この箇所は表裏同じパターンが乗っているので意味がありません。代わりにインダクタを外しました。

# INPUT 対応

5ch, 6ch を INPUT ポート用に改造。

![IMG_20240715_140444.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/06e2dc8a-969a-5fb0-c6ab-57a12543c26f.jpeg)
![IMG_20240715_140434.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/20efea2c-6143-74e0-4166-c56db3d8de00.jpeg)

RaspberryPi の GPIO はプルアップしておき、Lo になると検出です。

:::note
Raspberry Pi の 内部プルアップを使った場合、ボード上の合成20kΩプルダウン抵抗に負けてしまいました。
その場合は、ボード上のプルダウン抵抗を削除します。

:::

# 高容量のSSRに入れ替え

もともとのSSRは2A品なので、8A容量のSHARP S108T02 に入れ替えています。

![IMG_20240715_141926.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/461db914-c681-94b7-0690-cdd6c2ac8bd2.jpeg)

# 完成品

以上の改良で、以下のボードが完成しました。
- Ch1〜Ch4： DC 24V 1A 出力
- Ch5〜Ch6： DIGITAL IN
- Ch7：NC (絶縁距離確保のためアキ)
- Ch8：AC 100V 3A 制御出力

![IMG_20240715_152243.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/2eaeb1f7-8645-0a41-ba58-b3fc0b0f9023.jpeg)