OmniAICreator/Qiita-1.07M huggingface dataset:
C言語で木構造を実装をするときのテクニック



## はじめに

どうも。aqualengthです。[^1]

この記事は、[「木 Advent Calendar 2023」](https://adventar.org/calendars/9821)の21日目です。
昨日の記事は[箱](https://adventar.org/users/41410)さんの[木に関する数学の論文の紹介](https://koboshi-kyopro.hatenablog.com/entry/2023/12/20/000259)でした。
明日の記事はNullPointerExceptionです。

今日はC言語で木の実装をするときに使える(主に高速化の)テクニックを紹介していきます。
想定はC言語ですが、[一部のテクニック](#配列の構造体ではなく、構造体の配列で持つ)を除きC言語以外の言語でも使えるテクニックになっています。
あくまでテクニックの紹介なので、具体的な実装については省略します。

## 目次

- [はじめに](#はじめに)
- [目次](#目次)
- [ポインタではなくインデックスを持つ](#ポインタではなくインデックスを持つ)
- [配列の構造体ではなく、構造体の配列で持つ](#配列の構造体ではなく、構造体の配列で持つ)
- [1-indexedで持つ](#1-indexedで持つ)
- [二重連鎖木](#二重連鎖木)
- [子だけでなく親の情報も持つ](#子だけでなく親の情報も持つ)



## ポインタではなくインデックスを持つ

### 適用範囲:グラフ全般

メモリ確保のコストやキャッシュヒット率を考えれば、ノード毎にメモリを確保するより必要な分まとめて確保する方が高速に動作します。

メモリ領域もヒープ領域以外にスタック領域を使うことが出来るため、高速化としてはかなり有効なはずです(未検証)

言語によってはポインタやオブジェクトを扱えないこともあるため、そのような言語を使う場合や移植性を高めたい場合にも有効です。

## 配列の構造体ではなく、構造体の配列で持つ

### 適用範囲:グラフ全般

参考:[ダブル配列の豆知識](https://www.slideshare.net/s5yata/dsirnlp-04s5yata)

木を含むグラフ全般を実装するとき

``` c
struct tree{
	int node[N+1];
	unsigned left[N+1];
	unsigned right[N+1];
};
```

と実装するより

``` c
struct tree_node{
	int node;
	unsigned left;
	unsigned right;
}
struct tree{
	struct tree_node node[N+1];
};
```
のように実装した方がキャッシュヒット率が上がって高速になりやすい(らしい)です。

とはいえ、実装の手間が増えるわりには効果も大きくないため、別に前者で実装しても何ら問題はないです。

## 1-indexedで持つ

### 適用範囲:グラフ全般,完全二分木

いくつかのメリットがあります。

- 0番目の要素にデータ数やルートのインデックス,参照カウンタなどの情報を詰め込むことが出来る。
- 0という値を「値が存在しない」ことを示す特別な値として扱うことができる(ヌルポインタみたいなもの)
- [木を構造体の配列で持つ実装](#配列の構造体ではなく、構造体の配列で持つ)と相性が良い

## 二重連鎖木

### 適用範囲:多分木

テクニックと言えるかは微妙ですが、子の個数が不定の多分木を実装するときは
- 子の代表
- 兄弟
を持つのがセオリーです。
子の集合を配列ではなく連結リストで持つイメージです。

``` c
struct tree_node{
	int node;
	unsigned child;
	unsigned brother;
};

struct tree{
	struct tree_node node[N+1];
};

```
実装を見ると分かると思いますが、構造としては二分木と酷似しており、多分木を二分木として表現する方法と捉えることが出来ます。
このような実装を[二重連鎖木](https://ja.wikipedia.org/wiki/%E4%BA%8C%E9%87%8D%E9%80%A3%E9%8E%96%E6%9C%A8)と言います。


このテクニックはTrie(恐らくB木も)などの特定の子に定数時間でアクセスする必要がある場合には使えません。

<!---
## 完全木を配列で表現する

### 適用範囲:完全木


完全二分木以外の完全木では0-indexedである必要があります。
--->


## 子だけでなく親の情報も持つ

### 適用範囲:平衡木など

主に平衡二分探索木の実装で使うテクニックです。
言語によってはこのテクニックによって文字通り桁違いの速度差が出てきます。

本来、(平衡)二分探索木は親へのアクセスを必要としないデータ構造ですが、回転の操作では先祖の情報を遡る必要が出てきます。

遡るだけなら再帰呼び出しで実現可能ですが、再帰呼び出しには時間がかかります。

AVL木や赤黒木などの代表的な平衡二分探索木[^3]は回転の計算量が定数であるため、対数時間の計算量がかかる検索の部分がネックになります。

再帰呼び出しを使う場合、参照のみだった検索にスタックへの書き込みが加わるため、平衡でない二分探索木より遥かに遅くなります。(ただし、merge/splitをサポートする一般的な平衡二分探索木[^2]は左の子の要素数を持つ必要があるため、検索時に書き込みが発生します。とは言え、書き込みの回数を減らすのは重要です)

親の情報を持つ場合、検索自体にかかる追加の計算量はほぼ0なので、平衡でない二分探索木に匹敵するパフォーマンスを得ることが出来ます。


[^1]: bloodという名前で活動する場合もあります
[^2]: merge/splitが不要な場合は平衡二分探索木を使うまでもなくskiplistで十分です。まぁskiplistの実装は鬼難しいんですけど
[^3]: 乱択な平衡二分探索木やスプレー木がどうなのかは分かりません。
Databricks推論テーブルとレイクハウスモニタリングによる大規模言語モデルの監視

こちらのウォークスルーです。

https://docs.databricks.com/ja/machine-learning/model-serving/inference-tables.html

以前書いたこちらの記事の続編でもあります。

https://qiita.com/taka_yayoi/items/6ef148d2c4286b51b947

https://qiita.com/taka_yayoi/items/b481502fad773f475e23

OpenAI APIを使うチャットbotをDatabricksで動作させる際に、推論テーブル(inference table)を有効化すると、モデルがデプロイされているモデルサービングエンドポイントの入出力を追跡することができます。

モデルサービングエンドポイントを編集して推論テーブルを有効化し、保存先テーブルを指定します。
![Screenshot 2023-12-20 at 18.25.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/3ea25525-6ccd-b10d-9347-503b6244f345.png)

Databricksで稼働するチャットbotに問い合わせすると、モデルサービングエンドポイントを呼び出す形となり、その際に推論テーブルにリクエスト、レスポンスが記録されます。
![Screenshot 2023-12-20 at 18.26.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/c854cfce-559f-0d4b-6f5a-cc84137def61.png)

カタログエクスプローラでデータを確認できます。
![Screenshot 2023-12-20 at 18.29.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/2c3f80fb-8114-01d8-ded0-7c1e65a9f88b.png)

これは生データですので加工します。こちらにサンプルノートブックがあります。アプリケーションの入出力に応じて微調整する必要があるかもしれません。

https://docs.databricks.com/ja/machine-learning/model-serving/inference-tables.html#starter-notebook-for-monitoring-text-quality-from-endpoints-serving-llms

ノートブックを実行することで、チャットボットへの入出力にアクセスできるようになります。
![Screenshot 2023-12-20 at 18.32.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/bf38ed3c-6ac3-3377-dad9-a0675acd1a0f.png)

上記ノートブックにはレイクハウスモニタリングのコードも入っていますので、実行すると上記テーブルに対するモニターが設定されます。

自動生成されるダッシュボードでは、問い合わせ数や内容、レスポンス、レスポンスのtoxicity、perplexityなどを確認することができます。
![Screenshot 2023-12-20 at 18.21.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/177e2efb-6d18-ddf3-e14a-7ac11335313d.png)
![Screenshot 2023-12-20 at 18.34.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/5d7c64bd-e5d9-f95b-4a6b-c98f8a55e8e0.png)

企業で運用するチャットbotにおいては、LLMに対する入力とレスポンスのモニタリング、それに基づく対策、改善が重要となります。(まだ日本リージョンでは利用できませんが)リリースされたらぜひお試しください！

### Databricksクイックスタートガイド

[Databricksクイックスタートガイド](https://www.amazon.co.jp/dp/B09V1YXFVQ/)


### Databricks無料トライアル

[Databricks無料トライアル](https://databricks.com/jp/try-databricks)
Bunで生成したバイナリがdistrolessコンテナ上で動かない【解決】

# 結論

`gcr.io/distroless/static-debian12`ではなく`gcr.io/distroless/base-debian12`を使え！

# はじめに

Bun、速くて身軽で快適ですよね。

もはやyarnやpnpmなどのパッケージマネージャは不要だし、ランタイム同梱のバイナリまで生成してくれるのでDockerfile職人にも優しいです。

しかし今回、一部のdistrolessイメージではBunが生成するバイナリを動かせないという事象に遭遇したため、解決方法と共にこちらに残しておきます。

# 使用したDockerfile

```Dockerfile
FROM oven/bun:1 as install
WORKDIR /temp/build
COPY package.json bun.lockb /temp/build/
RUN bun install --frozen-lockfile

FROM install as build
COPY . .
RUN bun run compile

FROM gcr.io/distroless/static-debian12:nonroot
COPY --from=build /temp/build/app /
ENTRYPOINT [ "/app" ]
```

`bun run compile`は`bun build --compile src/index.ts --outfile ./app`と読み替えてください。

これを以下のdockerコマンドで実行すると、

```
$ docker build --no-cache -t myapp .
$ docker run --init -t myapp
exec /app: no such file or directory
```

エラーが出てしまいました。

# 原因

`/app`は確かに存在するし、実行ファイルであることには間違いないのに`no such file or directory`と言われてしまいます。

結論から言うと、エラーの原因は「[distrolessのstaticイメージにはglibcが含まれていない](https://github.com/GoogleContainerTools/distroless/blob/main/base/README.md#:~:text=distroless/base%2C-,which%20contains%20all%20of%20the%20packages%20in%20gcr.io/distroless/static,glibc,-libssl)」ことだったようです。

なので、先ほどのDockerfileの最終ベースイメージの`gcr.io/distroless/static-debian12`を`gcr.io/distroless/base-debian12`に置き換えると動くようになります。

# 補足

> `/app`は確かに存在するし、実行ファイルであることには間違いないのに`no such file or directory`と言われてしまいます。

と述べましたが、何も説明せずに言い切ってしまうのは無責任だと思うので実施した調査方法を共有しておきます。

実は、各distrolessイメージにはdebugタグが用意されており([参照](https://github.com/GoogleContainerTools/distroless#debian-12))、通常のイメージには含まれていないシェルなどが同梱されています。こちらのタグを利用すれば`docker run -it`でコンテナ内に潜り込んで調査できるというわけです。
yum updateには気をつけよう

この記事は、RHEL（RedHat Enterprise Linux）をEC2インスタンスで利用する際に「yum update」を行ったら、OSまでアップデートされてしまったので、それを回避する方法をまとめました。

## そもそも、yumってなんだ？
インストールやアップデート、アンインストールを行うことができる、パッケージ管理システムのこと。

yum以外にも、Debian系ではaptやyumの後継版としてdnfが使われていたりします。

## yum updateって何してる？
バージョン管理を主に行っているようです。
yum update実行後は、インストールされているパッケージが全て最新のものに更新されます。

## OSのバージョンアップを行わずに、yum updateを行う方法
yum updateを行わないという選択肢もありますが、脆弱性が改善されていたり仕様が変更されていたりするため、なにかと行っていた方が良いのかと思います。

### 使用したAMI(OS)
RHEL-8.6.0_HVM-20231114-x86_64-59-Hourly2-GP3

## 一時的にOSのバージョンアップを行わない方法
```
$ sudo yum update --exclude=redhat-release*
```
yum updateをする際に、オプションでOSのバージョンアップを行わないように指定します。

あくまで一時的にバージョンアップを行わない方法なので、常にバージョンアップを行わない方法は次を参考にしてください。

## 常にOSのバージョンアップを行わない方法
一時的にrootユーザへ切り替えます。
```
$ sudo su -
```

その後、yum.confを編集します。
```
# vi /etc/yum.conf
```
※ここではviを使用していますが、お好きなエディタをお使いください。

yum.confが開けたら、
```
exclude=redhat-release*
```
を追記します。

実際に変更したyum.confはこんな感じ↓
![8660213f-7e2c-4994-b609-25428aa71326.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3626263/0da6212f-19c3-8c6a-604a-cbc077463996.png)

準備ができたので、yum updateをしてみます。
```
# yum update
```

最後に、OSの確認をします。
```
# cat /etc/system-release
```
![無題の画像.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3626263/2f99cfc1-f8d4-efd5-7007-23ed07e35718.png)
指定したバージョンと異なっていなければ大丈夫です！


## 最後に
今回は、RHELでOSのバージョンアップが行われないようにyum updateを行う方法を記事にしました。
Amazon Linuxや他のOSでは方法が異なるようなので、また検証をしていきたいと思います。

不慣れて分かりにくい点もあったかと思いますが、お役に立てたら幸いです！
読んでいただき、ありがとうございました。
形式言語を用いた強化学習について

こんにちわ！NAISTでマルチタスク強化学習を研究しているものです。

ここでは、形式言語を用いて強化学習を行う手法を紹介します！

現在執筆中です。遅れてすみません

形式言語と強化学習は、コンピュータ科学と人工知能の分野で重要な役割を果たします。形式言語はコミュニケーションのための厳密なルールを提供するのに対し、強化学習はエージェントが最適な行動を学習するプロセスを示します。この記事では、これら二つの概念がどのように相互作用し、複雑な環境の理解と操作に寄与するかを探ります。

形式言語の基本
形式言語は、特定の規則や文法に基づいて構築される言語です。これには、プログラミング言語や数学的表現が含まれます。形式言語の明確な規則性は、情報の処理と解釈において非常に重要です。

強化学習の基本
強化学習は、エージェントが環境との相互作用を通じて行動を学習するプロセスです。エージェントは報酬を最大化することを目指し、試行錯誤を通じて最適な戦略を獲得します。

形式言語と強化学習の統合
意思決定プロセスの効率化： 形式言語に基づいて設計された環境では、強化学習エージェントはより迅速かつ効率的に学習することができます。形式言語は、エージェントが解釈すべき環境の構造を明確にし、学習プロセスを加速します。

複雑なタスクの単純化： 形式言語を使用することで、強化学習のタスクをより単純なサブタスクに分解できます。これにより、エージェントは複雑なタスクを小さな、より管理しやすい部分に分けて学習することができます。
電気学科がReact、flutterを学んで思ったこと

## これらを学ぶに至った経緯
### flutter
10月に行われた大学祭で行われたコンクールに同じサークルのメンバーで出場した。私が所属するサークルは大学祭内で模擬店を出店することになっていた。昨年も大学祭で模擬店を出店したが、売れた商品の個数や売り上げの記録が取られていなかったため、POSSシステムを自作することで模擬店運営のシステム化を図ろうと思った。その際の開発ツールとしてflutterを用いた。
### React
私はサークル内で同じ役職を担っている先輩、後輩とともに12月の初旬に行われたハッカソンに出場した。その際の開発ツールとしてReactを用いた。

### これらを学んで思ったこと
私は普段は電気学科で電気回路やアナログ回路、デジタル回路などの電気系を学んでいる。そのため、これらのような開発ツールを自主学習する機会は今までなかった。勉強をしていても情報学部の皆が当たり前に知ってるIT用語も知らなかったため、本やUdemyで勉強していると聞いたこともないような言葉ばかりでとても苦労した。しかし、わからないことがあれば優しく教えてくれる後輩や友達のおかげで、途中で挫折することなくどちらとも作品を完成させることができた。
(リンクだけです)材料力学「(力の3要素)」を調べた。

# wikipedia 
力を構成する要素は、力の大きさ (magnitude)、力の向き (direction)、作用線の方向、作用線の位置である。力が及ぼされる点を作用点(point of action) と呼ぶ。
静力学＜

https://ja.wikipedia.org/wiki/力_(物理学)#静力学

https://en.wikipedia.org/wiki/Force

# google検索
「**学力の三要素**」も、ヒットします。ステキ。

https://www.google.com/search?q=%E5%8A%9B%E3%81%AE3%E8%A6%81%E7%B4%A0%E3%80%80%E4%BD%95%E5%B9%B4%E7%94%9F&sca_esv=592900765&rlz=1CAUHAM_enJP1089&sxsrf=AM9HkKmtV4hF1Ey0eY86JVfLIwwEEGQDzg%3A1703188077559&ei=bZaEZZvhIfak2roPy4C4wAE

力には必ず、**力の大きさ、力の向き、力の作用点**の三つの要素があり、これを力の三要素という。

https://www.google.com/search?q=%E5%8A%9B%E3%81%AE3%E8%A6%81%E7%B4%A0&rlz=1CAUHAM_enJP1089&oq=%E5%8A%9B%E3%81%AE3&gs_lcrp=EgZjaHJvbWUqBwgBEAAYgAQyBggAEEUYOTIHCAEQABiABDIHCAIQABiABDIHCAMQABiABDIHCAQQABiABDIHCAUQABiABDIHCAYQABiABNIBCTExNjMyajBqN6gCALACAA&sourceid=chrome&ie=UTF-8

# 過去問
望星塾 様

https://www.google.com/search?q=site%3A%2F%2Fbouseijuku.sakura.ne.jp+%22%E5%8A%9B%E3%81%AE3%E8%A6%81%E7%B4%A0%22&sca_esv=592476218&rlz=1CAUHAM_enJP1089&sxsrf=AM9HkKnPBVASK0QB21_Pz2rIMU2YzftwqA%3A1703068052311&ei=lMGCZce6EqWZ0-kPgr4X&ved=0ahUKEwjH1KTy5p2DAxWlzDQHHQLfBQAQ4dUDCBA&uact=5&oq=site%3A%2F%2Fbouseijuku.sakura.ne.jp+%22%E5%8A%9B%E3%81%AE3%E8%A6%81%E7%B4%A0%22&gs_lp=Egxnd3Mtd2l6LXNlcnAiLnNpdGU6Ly9ib3VzZWlqdWt1LnNha3VyYS5uZS5qcCAi5Yqb44GuM-imgee0oCIyBBAjGCdIpS5QqxVYoCNwAXgAkAEAmAFroAHTAaoBAzAuMrgBA8gBAPgBAeIDBBgBIEGIBgE&sclient=gws-wiz-serp

https://www.google.com/search?q=site%3A%2F%2Fbouseijuku.sakura.ne.jp+%22%E5%8A%9B%E3%81%AE%E4%B8%89%E8%A6%81%E7%B4%A0%22&sca_esv=592476218&rlz=1CAUHAM_enJP1089&sxsrf=AM9HkKnvfx9q8-VZxCdsez3drqtt55V8Xg%3A1703189145383&ei=mZqEZfT-FqXS1e8Pga-DyAs

"力の3要素"との一致はありません。

# 参考

https://ja.m.wikipedia.org/wiki/%E3%83%99%E3%82%AF%E3%83%88%E3%83%AB

他言語版はまだありません。
0.0.0.0 と 127.0.0.1 と localhost の違い


<!--

たぶん作図したほうがわかりやすい
    172...
<-> 192.0.2.2 <-> 0.0.0.0 <-> 127.0.0.1
    172..
  -->

## 違い
### ◯ 127.0.0.1 と localhost

同じものになります。

あるいは localhost は 127.0.0.1 の別名と言ってもいいかもしれません。`nslookup` コマンドで対応付を見てみます。

```
$ nslookup localhost
...

Name:	localhost
Address: 127.0.0.1
Name:	localhost
Address: ::1
$
```

`/etc/hosts` を削除してもこの挙動は変化しませんでした。もしかしたら対応付を消す方法があるのかもしれません。


### ◯ 127.0.0.1 と 0.0.0.0

* 127.0.0.1 ... PC の中だけで通信を行う場合に使います。
* 0.0.0.0 ... PC の外と通信を行う場合に使います。



## 例えば

127.0.0.1 と 0.0.0.0 について説明します。

### ◯ 前提

* PC には 192.0.2.2 が割り当てたとします。
* ウェブサーバ Uvicorn をポート番号 80 で立ち上げたとします。
* データベースサーバ PostgreSQL ポート番号 5432 で立ち上げたとします。
* ウェブサーバとデータベースサーバを１つの PC の中で立ち上げたとします。


### ◯ 前提 ウェブサーバ

ウェブサーバは外部と通信が必要になるので 0.0.0.0 を設定します。

```
$ # Uvicorn を起動
$ uvicorn app:app --host 0.0.0.0
```

* Uvicorn の --host のデフォルト値は 127.0.0.1



### ◯ 前提 データベースサーバ

データベースサーバはウェブサーバとだけ通信をすればよいので 127.0.0.1 を設定します。

```conf:postgresql.conf
listen_addresses = '127.0.0.1'
```
```
$ # PostgreSQL を起動
$ postgres -D /etc/postgresql/10/main
```

* PostgreSQL の listen_addresses デフォルト値は localhost



### ◯ 結果

外部からウェブサーバには 192.0.2.2:80 でアクセスすることができますが、データベースサーバには外部から 192.0.2.2:5432 でアクセスすることはできません。

データベースサーバにはウェブサーバから 127.0.0.1:5432 でアクセスすることができます。


## ネットワークインターフェイス

１つの PC は複数のネットワークインターフェイスを持つことができます。ネットワークインターフェイスはそれぞれが IP アドレスを持つことができます。Windows なら ipconfig コマンド, macOS, Ubuntu なら ifconfig コマンドで確認することができます。

以下は Ubuntu での実行結果です。１台の PC が複数のネットワークインターフェイス, IP アドレスを持っていることがわかります。

```
$ ifconfig | grep "inet "
        inet 172.19.0.1  netmask 255.255.0.0  broadcast 172.19.255.255
        inet 172.20.0.1  netmask 255.255.0.0  broadcast 172.20.255.255
        inet 172.17.0.1  netmask 255.255.0.0  broadcast 172.17.255.255
        inet 127.0.0.1  netmask 255.0.0.0
        inet 192.168.11.2  netmask 255.255.255.0  broadcast 192.168.11.255
$
```

ウェブサーバを起動する際に 192.0.2.2 を指定せず 0.0.0.0 を指定すると、外部からすべてのネットワークインターフェイス、複数のIPアドレスを経由してアクセスしてもらうことができます。ウェブサーバに対しては 127.0.0.1 でも 192.168.11.2 でも 172.17.0.1 でも... 通信が可能になります。

一方でデータベースサーバはウェブサーバとだけ通信が可能です。

:::note warn
ただし 0.0.0.0 を指定することは一般的に開発環境でのみ推奨され、本番環境では適切なセキュリティ対策を講じる必要があります（ChatGPT からの引用です、不要なネットワークインターフェイスを閉じろ、ということを言っているのでしょうか？ https://bit.ly/48swjhx ）。
:::

## 参考

すいません、別のタイトルが思いつきませんでした... orz

https://qiita.com/1ain2/items/194a9372798eaef6c5ab
コマンドでSACLOS方式のミサイルを作る

この記事は [Minecraft Command Advent Calendar 2023](https://qiita.com/advent-calendar/2023/mccmd) 20 日目の記事です。

# はじめに
この記事ではマインクラフトのコマンドでSACLOS方式の誘導ミサイルを作ってみたことについて話していきます。
アルゴリズムおよび簡単なデモを紹介していきます。

# SACLOSとは
半自動指令照準線一致（Semi-Automatic Command to Line of Sight, SACLOS）とはミサイルの誘導方式の一種です。
射手が照準器で示した方向に向かってミサイルが自動で方向修正をしていくという仕組みになります。
主に1970年ごろの対戦車ミサイルに使われていました。
参考：[半自動指令照準線一致誘導方式(wikipedia)](https://ja.wikipedia.org/wiki/%E5%8D%8A%E8%87%AA%E5%8B%95%E6%8C%87%E4%BB%A4%E7%85%A7%E6%BA%96%E7%B7%9A%E4%B8%80%E8%87%B4%E8%AA%98%E5%B0%8E%E6%96%B9%E5%BC%8F)

# アルゴリズム
上記説明だと難しそうに聞こえますが以下のように単純化して考えることができます。
* プレイヤーの視線方向より上(下)にミサイルがあったらミサイルを下(上)に曲げる
* プレイヤーの視線方向より右(左)にミサイルがあったらミサイルを左(右)に曲げる

この判定をマインクラフト内で行う場合以下のようなやり方で実現できます。
```text:プレイヤーの視線より左にエンティティがいるかの判定
execute as @e[tag=missile] at @s facing entity @p[tag=sight] eyes positioned ^ ^ ^3 rotated as @p[tag=sight] positioned ^4 ^ ^ if entity @s[distance=..5] run tag @s add left
```
上記コマンドを使うと下図のような判定を行うことになり、対象エンティティが左にいるときだけtrueとなるようにできます。

###### ミサイルが自分より左にいる場合
![hantei1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3589337/566b4171-72f8-2e94-3487-8e429fcb5b93.png)

###### ミサイルが自分より右にいる場合
![hantei2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3589337/06ed0993-9354-4c15-b482-7e4f689e7ab0.png)

右、上、下にいる場合を判定したい場合は同じ要領でpositioned ^4 ^ ^の部分を^-4 ^ ^、^ ^4 ^、^ ^-4 ^としていけば実現できます。
あとは判定結果に応じてTPコマンドでミサイルの進行方向を変えてあげれば完成となります。

# デモ
実装してみた結果が以下になります。プレイヤーの見ている方向に向かってミサイルが飛んでいることが分かります。
https://twitter.com/uran2471/status/1723587254613123314
今のところ誘導するとプレイヤーの視線周辺を螺旋状に動いてしまっています。これはミサイルの旋回速度が状況によらず一定であることが原因ですので、その部分を修正していくことが今後の課題になるかと思います。

# まとめ
マインクラフトでSACLOS方式の誘導ミサイルを作ってみました。課題はいくつかあるものの単純なアルゴリズムで誘導兵器なようなものを作ることができることが分かりました。
【Flutter】ダイアログの背景色が設定通りにならない

備忘録として残します。

## ダイアログの背景色が真っ白に出来ない・・・
真っ白なダイアログを出したい場面があったので、
下記のようなコードで`backgroundColor`に`Colors.white`を設定しました。
```dart
Dialog(
      backgroundColor: Colors.white,
      shape: const RoundedRectangleBorder(
        borderRadius: BorderRadius.all(
          Radius.circular(16.0),
        ),
      ),
      insetPadding: const EdgeInsets.symmetric(
        horizontal: 26,
      ),
      child: // 省略
);
```

すると、下記のようになりました。
ちょっと紫がかっています。

<img width="240" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3628889/f76839f1-6bab-245a-7288-14f4f2c59585.png">


## 原因
Dialogの引数`surfaceTintColor`が影響しています。

https://api.flutter.dev/flutter/material/Dialog/surfaceTintColor.html

ドキュメントを読むと、下記の記載があります。
> If null and ThemeData.useMaterial3 is true
> then ThemeData's ColorScheme.surfaceTint will be used.

つまり下記の2つの条件が満たされる場合、
`ThemeData.surfaceTint`が利用されるようになっているようです。

- Dialogの引数である`surfaceTintColor`が設定されていない。
- `ThemeData.useMaterial3`が`true`になっている。

### 余談: ThemeDataはどこで定義されている？
 MyApp内で定義されていることが多いかと思います！
```dart
class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), <- これ
        useMaterial3: true,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}
```

ここで`deepPurple`が指定されていた影響で
ダイアログが紫がかっていたんですねぇ。

## 結論
`surfaceTintColor`に`Colors.transparent`を設定すると、
意図した背景色を反映させることが出来ます。

```dart
Dialog(
      backgroundColor: Colors.white,
+     surfaceTintColor: Colors.transparent,
      shape: const RoundedRectangleBorder(
        borderRadius: BorderRadius.all(
          Radius.circular(16.0),
        ),
      ),
      insetPadding: const EdgeInsets.symmetric(
        horizontal: 26,
      ),
      child: // 省略
);
```

← `surfaceTintColor`あり
→ `surfaceTintColor`なし

<img width="240" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3628889/b1c8b30d-c867-e909-78de-0ef0283cc6de.png"><img width="240" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3628889/f76839f1-6bab-245a-7288-14f4f2c59585.png">

## 最後に
新しいWidgetを使うときは、ドキュメントを読みましょう。(自戒)
rex0220 計算式プラグイン 文字列にある月を1～12月の複数選択項目にセット

[計算式プラグイン](https://qiita.com/rex0220/items/ae83c6d5ce50ff7a9a73)で、文字列にある月を1～12月の複数選択項目にセットする例です。

# 概要

文字列に、1～12月が含まれている場合に、複数選択項目の対象月を選択します。

![2023-12-20_18h06_59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/19cf3862-bf59-d46d-59a0-8ac22effa405.png)

# 計算式プラグイン設定

![2023-12-20_22h29_45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/808b0010-8f3c-a2ed-8050-2002b9f9ec01.png)

文字列から、正規表現で、数字+"月"を取得して、1～12月だけを取得

```.js
// 対象月 MULTI_SELECT
LET(
  文字列, ASC(参照文字列, "n"),
  選択肢, ARRAY_FOR(12, x, x+1 & "月"), 
  w, MATCH(文字列, "\d+月", "g"),
  INTERSECT(選択肢, w)
)
```

# 計算式プラグイン設定(NGあり)

「１１２月、２３月」などの1～12月以外で、数字と月の組合せでNG

![2023-12-20_18h08_06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/09f17b65-da70-3a87-e31e-d9a2397d5eb9.png)

12月から順番に、文字列をチェックしていきます。
※1月から始めると、11月も 1月にカウントされてしまいます。

```.js
// 対象月
LET(
    文字列, ASC(参照文字列,"n"),
    選択肢, ARRAY(12,11,10,9,8,7,6,5,4,3,2,1), 
    a1, ARRAY_SORT(ARRAY_FIL(選択肢, x,
      LET(
         w, 文字列,
         x1, x & "月",
         y, REPLACEALL(文字列, x1, ""),
         z, FSET(文字列, y),
         w != 文字列
      )
   )),
   ARRAY_MAP(a1, x, x & "月")
)
```
【Unity】図形を描くプログラムを紹介してみる

本日の最低気温は6°Cらしいです、寒すぎます
今暖かいところで書いているので、この記事を読んでくださっている方も暖かいところで読んでください
寒いところにいる人は**ストック**と**いいね**をして暖かいところに行ってから！
- - -

と、いうわけで暖かいところにいるクライアント新卒2年目のMです

[@maphy](https://qiita.com/maphy)からパスをもらい、[Cocone Advent Calendar 2023](https://qiita.com/advent-calendar/2023/cocone)の21日目の記事になります
昨日も明日も同期の記事なので、しっかりトラップして明日にパスしたいと思います

さっそくですが、ゲームをプレイしているとハート型や星型の技のエフェクトだったり出てきますよね
あれやりたいなと思ってやってみたので、すこし紹介します
少しでも参考になればいいなと思ってます!

# 紹介
> ※ 以降コード内に出てくるTWO_PIはMathf.PI * 2(2π)となります

## 星型
星、というよりダイヤ？な図形です

![image1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2988350/9889fa52-9e81-bd67-fb37-6afdf4a6e16d.gif)

```c#:星型
float step = 0.1f;  // 角度のステップ幅
float scale = 1; // サイズ

for (float angle = 0; angle < TWO_PI; angle += step)
{
	float x = scale * Mathf.Pow(Mathf.Cos(angle), 3);
	float y = scale * Mathf.Pow(Mathf.Sin(angle), 3);

	Instantiate(object, new Vector2(x, y), Quaternion.identity);
}
```

## クローバー型

![image2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2988350/43e37cc9-3024-9894-0be9-505bff34f922.gif)

```c#:クローバー型
float step = 0.1f;  // 角度のステップ幅
float scale = 1; // サイズ
int num = 3; // クローバーの数

for (float theta = 0; theta <= TWO_PI; theta += step)
{
	float r = 1 + Mathf.Cos(num * theta);
	float x = r * scale * Mathf.Cos(theta);
	float y = r * scale * Mathf.Sin(theta);
	Instantiate(object, new Vector2(x, y), Quaternion.identity);
}
```

三つ葉もいいけど、クローバーはやっぱり四つ葉ですよね
クローバーの数を変えるだけで簡単に葉の枚数も変えられます

![image4.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2988350/1bdbae0b-217a-4909-a06f-29537d90f3ce.gif)


## ハート型
ちょっぴりぽっちゃりなハート型

![image2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2988350/4b6f8d35-d1a6-8afd-078c-d5b6c9e19cf8.gif)

```c#:ハート型
float step = 0.1f;  // 角度のステップ幅
int scale = 1; // サイズ

for (float theta = 0; theta <= TWO_PI; theta += step)
{
	float r = 1 - Mathf.Sin(theta);
	float x = r * Mathf.Cos(theta);
	float y = r * Mathf.Sin(theta);
	Instantiate(object, new Vector2(x*scale, y*scale), Quaternion.identity);
}
```

# 終わりに
ハート型、他にも色々書き方があって形も変えられたりできるので試してみてください
下記に今回参考にしたサイトのURLを貼っておくので、よければそちらも目を通してみてください！

明日は[@takokurage](https://qiita.com/takokurage)の記事になります
タコなのかクラゲなのか、真実が明らかになるかもしれません
引き続き[Cocone Advent Calendar 2023](https://qiita.com/advent-calendar/2023/cocone)をよろしくお願いいたします！

### 参考
・[naze数gaku](https://nazesuugaku.com/math_graph_conclude/)
・[WolframMathworld](https://mathworld.wolfram.com/HeartCurve.html)
簡単にデジタルフィルタを設計できるPythonのSciPy

remez法を使ったデジタルフィルタをfreeのpython scipyを使って設計しました。

備忘録に残します。
<br>



１．remez法

　　よく比較される窓関数法と比べて、所望のフィルタ特性を、より少ないタップ数

　　で設計できます。

　　その分計算が複雑であるため、有償ツールであるmatlabやMathematicaを使って

　　設計していました。

　　今回フリーであるpythonとライブラリのSciPy,NumPyを使用して設計できること

　　がわかり、やってみました。
<br>

２．環境構築

 　下記のサイトを参考に、numpy, matplotlib, scipy, pandasをインストールします。

　 下記サイトがわかりやすかったです。

   https://qiita.com/koKekkoh/items/e5c8ff85379fbac8bea4

　フィルタ特性のグラフを表示させるため「matplotlib」も必要になります。
<br>

３．サンプルコード

　SciPyの公式サイトに使い方が載っています。　

https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.remez.html
<br>

引数は以下のように記載されています


　■numtaps・・・フィルタ長(タップ数)

　■band・・・帯域で配列で指定します。全て周波数Hzで指定します。

　　[通過帯域の開始、通過帯域の終了、遮断帯域の開始、遮断帯域の修了]

　■desired・・・理想ゲインを指定します。配列で指定します。

　　[通過帯域の理想ゲイン、遮断帯域の理想ゲイン]

　■weight・・・各帯域の重みづけを配列で指定します。

　■Hz・・・・・サンプリング周波数　int型。

　（注　不使用が推奨され、代わりにfsの使用が推奨されています）

　■type・・・フィルタタイプを選択します。デフォルトはbandpass

　■maxiter・・・アルゴリズムの最大反復回数。デフォルトは25回

　■grid_density・・アルゴリズムで使用されるグリッド密度。デフォルトは16

　■fs・・・・・サンプリング周波数。Hzよりこちらを推奨。float型。
<br>

実際の使用例は、以下のような形で使用します。

```python

fs = 500     # サンプリングレート
cutoff = 2   # カットオフ周波数
trans_width = 20 # 通過領域から遮断領域までの周波数　
numtaps = 64
desired = [1.0, 0.00]  # 通過領域ゲイン１、遮断領域ゲイン0

remez_impres = sp.signal.remez(
    numtaps, [0, cutoff, cutoff + trans_width, 0.5 * fs], desired, fs=fs
 )  
```

Hz、weight、maxiter、grid_density に関しては特に指定しません。
<br>


４．フィルタ設計ツール
　上記の使用方法で、簡単にフィルタ設計できるツールを作成しました。
　GitHubにコードをアップします。
<br>

https://github.com/ShigeoYakuno/REMEZ_FIR_FILTER/tree/master

4つの値を入れるだけでローパスフィルタを作成するツールになります。
UIはpython標準のUIアプリであるtkinterを使っています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3657924/128b851a-a0d6-9a91-564d-8aaa518a24b5.png)


4つの値を入れるだけでローパスフィルタを作成するツールになります。
UIはpython標準のUIアプリであるtkinterを使っています。

<br>
各値を入力し、calcボタンを押すとフィルタの周波数特性グラフが出力されます。
正規表現を比較するガードを付けていますが、英数字以外を入れたり、空白のまま
だとエラーになります。

<br>
ターミナル上には、フィルタ係数を表示するようにしています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3657924/fdfbe1b0-c668-8224-d697-2628f2e8453c.png)


<br>
得られたフィルタ特性です。グラフはmatplotlibで描いています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3657924/4a7c089a-da83-0997-d097-866c1a381109.png)
<br>

５．設計したフィルタが正しいのか


実際に設計したフィルタですが、他のツールを使用しても同等のフィルタ特性
となるかを確認しました。

digitalfilter.com社様のdsplinksというすばらしいツールと比較させていただきました。
http://digitalfilter.com/products/dsplinks/jpdsplinks.html

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3657924/85bcaf44-1fc4-564c-d802-ae48ad03b1c6.png)


若干の違いはあるのですが、同等のフィルタ係数と周波数特性を得ることが出来ました。
<br>

最後にエクセルにて、フィルタの多項式に係数を代入して作成したグラフを載せます。
当たり前ですが同様の周波数特性が得られました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3657924/de499450-5f73-4458-f965-285f631f6dcc.png)

<br>

PythonやSciPyといった無料のツールで複雑なデジタルフィルタ設計が簡単に出来ました。
今後もSciPyやNumpyを使用したツールを作成していきたいです。
【iOS】リリースしたアプリに高評価なレビューが来た時だけ通知する

# はじめに
アプリを開発してApp Storeにリリースした後、ユーザーからのレビューってめっちゃ気になりますよね。

良い評価をもらえた時はもちろん嬉しいです。
しかし、悪い評価をもらう事もあります。
悪い評価のレビューは暴言みたいなのも含まれていることがあります。

そんな悪い評価は見たくないですよね。

でも、良い評価をされた際は真っ先に確認したい。

そんな時にAppStoCeconnect設定です。

# 準備
- AppStoCeconnectのアプリをインストールしている
- 自分のアカウントにログインできている

# やりかた
設定したいアプリのページに行きます
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/bfc37ff4-7bb8-b848-9616-4294d4a43932.png" width="50%">

1番下にスクロールすると「Notification」という項目があるので選択します。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/708ce022-874d-634d-04b6-7a5c0dfa6995.jpeg" width="50%">

「Reviews」で通知して欲しい星の数のトグルをオンにします。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/73af982f-0e74-e96c-1e5e-7b6ed51f1e79.png" width="50%">

これで高評価のレビューだけ
通知が来るようになりました！

# おわり
これで良い気分になれます。
ユーザーからの良いレビューも貰えると開発のモチベも上がるので、良いことばっかりですね
Slackのtimes（個人チャンネル）の活用法

弊社Slackでは各メンバーに専用のtimesチャンネルがあり、Twitter感覚で好きに使っていいことになっています。人数が20~30人と少ないこともあり、全員が全員のtimesチャンネルに参加しています。リモート比率高めなので、コミュニケーションの場としてある程度重要なチャンネル...のはず。
ですが、いつでもできることはいつまでもやらないのと同じように、好きに使っていいものはなかなか使われません。
実際弊社でも、積極的にtimesチャンネルを活用しているメンバーは半分未満です（この記事がきっかけで増えてほしい）。
この記事では、私や弊社のメンバーがどのようにtimesチャンネルを活用しているのかをご紹介します。

## 分からないことをつぶやく
![スクリーンショット 2023-12-20 16.24.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/361302/f7a67d78-b863-76e2-7d97-b45f881f7e03.png)

作業でつまづいたとき、つまづきポイントをつぶやくと詳しい人が助けてくれます。逆に助ける側に回ることもあります。
つまづいていなくても、「こういう進め方で合ってるかな？」と不安なときは「こうやって進めてる」とつぶやくと、間違いを指摘してもらえたりします。こまめにつぶやくことで、ミスを早期に発見できます。
同じプロジェクト内に訊ける人がいればその人に訊けばいいのですが、
- 入ったばかりで誰に訊けばいいか分からない
- プロジェクト内に答えられそうな人がいない

ようなときにはtimesの出番です。
プロジェクトの枠を越えて会社全体にゆるく質問できるのがtimesのいいところです。

## 他のメンバーに話しかける
![mosaic_20231220171319.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/361302/d5ca1e49-ffd8-35bb-9231-e7113a609605.png)

他のメンバーのtimesで業務内外の相談などをすることもあります。そのメンバーのデスクに行って話しかけるようなイメージ。
誰が何に詳しいかが分かってくるとこのパターンが増えてきます。

## 知見を共有する
![スクリーンショット 2023-12-20 15.55.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/361302/45972be6-8658-fa30-8a94-3c2700483a51.png)

プロジェクトで得た知見を会社全体にゆるく共有するときにも使います。
知見共有用のチャンネルも別で用意されているのですが、timesの方が投稿のハードルが低く感じるので気軽に投稿できます。


## AIとおしゃべり
![スクリーンショット 2023-12-20 16.01.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/361302/2466d78c-1ada-c960-f460-c6cdb45c0029.png)

弊社Slackには、OpenAI API（GPT-4）を利用したbotがいて、timesでたまに質問したりおしゃべりしたりしています。
技術的な質問のほとんどはこいつに質問することで解決してしまったりするので、社内のコミュニケーションが減っているのはちょっとした課題かもしれません。

このbotについては以下の記事が詳しいです。（弊社メンバーの記事です）

https://qiita.com/noritsune/items/17c20dccb0eb00f2622e

## 提言
![スクリーンショット 2023-12-20 17.02.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/361302/23a6fd63-3722-77cf-f704-787d033e1dd6.png)
弊社は割と若い会社なので、改善案をつぶやくと柔軟に対応してくれることがあります。（リプライしているのは社長です）

## Twitter
![スクリーンショット 2023-12-20 16.54.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/361302/5e39c6e2-3b7d-1a13-ebee-eb2ecd2f2dde.png)

正直は私の使い方はこれが7割を占めています...
まあ雑談も組織作りには重要ということで。

## 注意していること
基本的に決まったルールがないので自由に投稿していますが、以下のことには気をつけています。

### ネガティブな投稿ばかりにしない
人間ネガティブなことも考えてしまうものですが、人に読ませるものなので、表に出すのは最低限にしています。
「暴言を吐かない」などと同じで、times以前にコミュニケーション全般で必要なことですね。

### 業務外のことを投稿しすぎない
やりすぎるとサボっていると思われます。

## おわりに
timesでの発言が業務改善に繋がったり、話しかけ（話しかけられ）やすくなったりした経験があるので、今後も活用していこうと思います。

弊社ではエンジニアを募集しています。ご興味ございましたら以下からどうぞ。

https://www.wantedly.com/companies/company_1847744/projects
paiza.ioでelixir その268

# 概要
paiza.ioでelixirやってみた。
Agentでstack書いてみた。

# サンプルコード

```

defmodule Stack do
	def start_link do
		Agent.start_link(fn ->
			[]
		end, name: __MODULE__)
	end
	def drop do
		Agent.update(__MODULE__, fn stack ->
			po = length(stack) - 1
			List.delete_at(stack, po)
		end)
	end
	def pop do
		v =	Agent.get(__MODULE__, fn stack ->
			stack
			|> List.last()
		end)
		Agent.update(__MODULE__, fn stack ->
			po = length(stack) - 1
			List.delete_at(stack, po)
		end)
		v
	end
	def get do
		Agent.get(__MODULE__, fn stack ->
			stack
		end)
	end
	def rev do
		Agent.get(__MODULE__, fn stack ->
			Enum.reverse(stack)
		end)
	end
	def push(v) do
		Agent.update(__MODULE__, fn stack ->
			stack ++ [v]
		end)
	end
end

Stack.start_link

defmodule Main do
    Stack.push(1)
    Stack.push(2)
    Stack.push(3)
    Stack.pop()
    |>IO.inspect
    Stack.get()
    |>IO.inspect
end



```

# 実行結果

```
3
[1, 2]
```

# 成果物

https://paiza.io/projects/hFp9Xgck_mC851X627c8jQ


以上。
Colab Enterpriseを使ってLoRA学習

Colab Enterpriseを使ってStable DiffusionのLoRA学習を行なってみたいと思います。


Colab Enterpriseは、ひとことで言うと「GCP上のColabratory」に相当するサービスです。ColabratoryやJupyter Notebookと同じように、ブラウザ上でPythonのコードを実行できます。課金は、使用量に応じて課金される従量課金です。有料のColab環境という点ではColabratory Proに似ていますが、個人のクレジットカード登録などが必要ないため、企業内で使用しやすいサービスになっています。

今回はこちらをAI画像生成の実験環境として使用します。Colab Enterpriseを使うメリットは、開発者だけではなく、デザイナーやイラストレーターの方々にも気軽に試してもらいやすいことです。

ただし、今回は画像の**生成**ではなく、気軽にGPU環境を用意できるクラウドのメリットを活かし、LoRAの学習について紹介してみたいと思います。

LoRAは少ない計算コストでモデルの追加学習を行なう手法です。画像生成の場合、絵柄やキャラクターを学習するために使用されることが多いようです。LoRA学習用途でよく使用されるKohya's GUIをColab Enterprise上で動かしてみます。

## 1. 環境準備
Colab Enterpriseでは、ランタイムテンプレートを設定することで、ノートブックの実行環境をきめ細かく設定することができます。今回は、次のようなランタイムテンプレートを作成しました。

- インスタンスタイプ: n1-standard-4
- GPU: T4
- ディスクサイズ: 100GB
- アイドル状態でのシャットダウン: 20分

今回実行したノートブックはこちらに公開しました。
https://gist.github.com/takada-at/545214ed2ddb68b2c526e25bb0f22e0c

基本的にはこちらを順番に実行していくだけです。コードの中身はリポジトリをチェックアウトし、依存ライブラリをインストールしているだけのシンプルなものです。サービスはgradioを通じて公開されるので、パスワード認証を設定しています。

### 2. 実行
ノートブックを順番に実行していくと、Kohya's GUIが起動します。以下のようにURLが表示されるのでこちらをブラウザで開きます。

![kohya.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/81883/bf4a3786-c629-b798-3e56-16d5c8a53e6a.png)

表示されたURLにアクセスし、パスワードを入力すると以下のような画面が表示され、LoRAの学習を実行することができます。

![スクリーンショット 2023-12-20 12.50.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/81883/83b97c93-66d7-3760-a43a-7dff0890fac3.png)


### 3. SDXLの学習
Stable Diffusion XL1.0(SDXL1.0)はStable Diffusionの最新版のモデルです。モデル自体が巨大なため、LoRAの学習にもかなりの性能が要求され、実行のハードルが高いです。今回は、Colab Enterprise上でもSDXLでの実行が確認できたので、実行時の設定を共有したいと思います。

**ランタイムテンプレート**

- インスタンスタイプ: n1-highmem-4
- GPU: T4
- ディスクサイズ: 100GB
- アイドル状態でのシャットダウン: 20分

メモリ16GBではSDXLの学習に不足するようだったので、メモリ32GBのn1-highmem-4インスタンスを使用します。

**学習時の設定**

以下のKohya's GUIの公式リポジトリに従って、SDXL用の設定を適用していきます。わかりにくいところのみ以下に解説します。

https://github.com/bmaltais/kohya_ss?tab=readme-ov-file#tips-for-sdxl-training-1

LR Scheduler / Optimizerの設定

- **LR Scheduler**: constant_with_warmupが推奨されているようです。
- **Optimizer**: Adafactorに設定し、Optimizer extra argumentに"scale_parameter=False", "relative_step=False", "warmup_init=False"を設定(下記スクリーンショットを参照)。

![スクリーンショット 2023-12-20 12.52.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/81883/4034350d-d7e0-7602-7398-8e71b576a1c3.png)

- **Cache text encoder outputs**: 「Parameters」「Basic」の「Cache text encoder outputs」をオンにする。

- **UNETのみ学習**: 「Parameters」「Advanced」「Additional parameters」に"--network_train_unet_only"を設定し、UNETのみ学習するように設定します。

![スクリーンショット 2023-12-20 12.51.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/81883/54b10821-785c-413b-8392-a4d99625e65d.png)

- **Gradient checkpointing**: 「Parameters」「Advanced」の「Gradient checkpointing」をオンにする。

以上ひととおりの設定をすれば、T4環境でもLoRA学習が実行できました。
24/365物語 ある日のアラート対応を通して

Journeyman( @beajourneyman )と申します。"ジャーニーマン"だと長いので"ジャニ"と呼ばれています。

こちらは新橋とITと運用にゆかりのある老舗「ssmjp Advent Calendar 2023」の20日目に参加しています。

https://adventar.org/calendars/3948

今回は24/365のアラート対応について、ある実体験を紐解いて学びを残します(24時間と言いつつシステム特性で深夜・早朝は鳴りません)。

# それはいつも突然に

昼休み後半で軽く食事を取ろうと思っていたら、担当システムからアラートが鳴りました。社内のSlackにも通知されています。程なくして、アラートコールが鳴りました。メイン担当なので、1年前からファーストコール(システムアラートが発生した時に24時間/365日で1番最初に電話を受ける担当)です。その後、もう1本かかってきました。

「○○(システム名)で致命的なアラートが発生しました。」

「知っている」と思いながら受付済のダイヤルトーンを押しました。メイン担当になって1年と少し、見たことがないパターンで複数の通知が来ていました。メインの監視サービスは Datadog です。担当している期間中に1度、Datadog 自体が大規模障害で通知が止まり、自動化されるコトのありがたみを実感しました。いつもお世話になっています。

「タイミングが悪かった。」

数年前から担当してくれているベテランメンバーが、丁度午後休みで退勤した後でした。今まで何度も見たコトがあるアラートも含まれていたので、順を追ってデータの正常性と業務影響を確認しようと思いました。

チームでは、確認者が着手する時にSlack上でリアクションする運用ルールにしています。PM兼SEではありますが、システム詳細の奥の奥まで把握しているのは、チーム内で1番経験があるベテランメンバーです。自分の知っている・覚えている範囲で判断するのは、危険だと直感しました。アラート通知にひと言、書きました。

"いつもと出方が違うようです。調べてみます。"


# 切り分けと優先順位付け

実際はもっと複雑ですが、平たく言えば優先順位は以下ように整理できます。

1. 業務が止まるような大きな影響
2. データ不整合がおきる影響
3. 軽微な業務影響

アラートは複数クライアントのひとつから特定時間に立て続けに発生している状況でした。以降は発生していません。その時点で1.は除外できました。

2.は、タイムウィンドウ内にデータのリカバリーが必要になります。つまり、急ぎリカバリーが必要なデータ不整合が発生していないか、確認が必要になります。アラートを切り分けると、複数種類の事象が確認できました。

ここでポイントになるのが、調査の優先順位付けです。これまで自分の経験や積み上げてきた手順からは、短い時間で判断できませんでした。Slackでサポート可能だったベテンランメンバーにアドバイスを仰ぎました。チャット内での議論を通して、普段あまり異常終了しないプロセスを優先的に調べた方がリカバリーが必要な場合は初動が早められる、と結論が得られました。

Datadog で通知された AWS Lambda の第1優先対象アラートからリクエストID(キー情報)で Cloud Watch の実行ログを解析しました。リトライ状況、終了状況を確認、影響がないコトが判断できました。ただ、いくつかあるアラートひとつ目なので継続調査です。

# 限られた時間の中で

続いて、良く発生しており、2.3.のケースも含まれるアラートの解析です。1,2分の間に立て続けに十数件発生してました。レアケースです。コレは Cloud Watch, DynamoDB, 内部DBを業務的なキー情報を元に横断的に調査する必要があります。つまり、時間を要するコトが判断できました。

調査・エビデンス取得・整形のプロセスがありますが、時間を要するのは整形のプロセスです。こちらを簡略化し、一覧にまとめる形で調査サイクルのスピードを上げる方針としました。一覧に落とし込んだ項目は以下の通りです。

| 対象 | 説明 |
| :-- | :-- |
| LambdaリクエストID | ログからの取得 |
| 業務キー | システム内のキー情報 |
| DynamoDB値 | 一次処理結果 |
| 内部DB値 | 最終処理結果 |
| リカバリ要否 | 調査結果 |

十数件全て調査を終え、ひと目で確認できる一覧にし、Slackでも連携しました。時間はかかりましたが、タイムウィンドウ内で余裕をもって対処できました。数をこなすうちにスピードアップした実感もありました。

# まとめ

簡単ですが、アラートを通して得られた気付きを残しておきます。

### サポートを求める場合は早めが大事
なんとかひとりで対応しようとして、手を動かす時間が止まるコトは、対処が間に合わないリスクを増大させます。チームで取り組む意識で取り組むと良いと思います。

### 伝達は「客観性」と「正確さ」

テキストでの伝達は「客観性」と「正確さ」な伝達に特に注意が必要です。情報の受け手は、調査者が見えてるAWSマネージドコンソールは見えていません。調査者が気付いていないポイントに気付く場合があります。必要に応じて、スクリーンショットの共有も大変有効です。

### 切り分けと優先順位

物事には適切な優先順位があります。対処する時はつねに念頭に置いて、時間経過を踏まえて判断して行きましょう。今回はチーム内で完結できるケースでしたが、エスカレーションが必要なケースは特に初動が重要です。責任のレイヤーによっても方針が変わるケースも少なくありません。

### タイムウィンドウに向き合う

決まった手順があり、確かに後から見る場合は分かりやすいなどの緊急の場合には必ずしも必須ではないケースはあります(無論必要な調査は全てします)。なぜ、その手順になっているのか、本来の目的を理解して簡素化できる部分、つまりスピードアップできる部分がないか意識して調査にあたりましょう。



今回、ベテランメンバーにアドバイスを求めて、自分自身で検知・調査・結果報告をやり切って、今後のためにログを残しておくコトにしました。何かの気付きになれば、幸いです。

以上です。
PHP: Symfony Mailer の使い方

こちらと同じことを、Symfony Mailer で行いました。
[PHP: Swift Mailer の使い方](https://qiita.com/ekzemplaro/items/16d3bc53fbf57f352b72)

## ライブラリーのインストール

```bash
composer require symfony/mailer
```

## プログラム

ツリー構造

```text
$ tree -L 2
.
├── composer.json
├── composer.lock
├── symfonymailer.php
└── vendor
    ├── autoload.php
    ├── composer
    ├── doctrine
    ├── egulias
    ├── psr
    └── symfony
```

```php:symfonymailer.php
<?php

require_once 'vendor/autoload.php';
use Symfony\Component\Mailer\Transport;
use Symfony\Component\Mailer\Mailer;
use Symfony\Component\Mime\Email;

// 送信設定
$from='user@hi-ho.ne.jp';
$to='user@example.com';
$mailer_dsn = 'smtp://user@hi-ho.ne.jp:password@hi-ho.mose-mail.jp:587';
$transport = Transport::fromDsn($mailer_dsn);
$mailer = new Mailer($transport);
$email = new Email();

$str_out = 'Hello,Everybody' . PHP_EOL;
$str_out .= 'Test' . PHP_EOL;
$str_out .= 'Dec/20/2023' . PHP_EOL;
$str_out .= 'Dec/20/2023' . PHP_EOL;
$str_out .= 'Dec/20/2023' . PHP_EOL;

$email
	->from($from)
	->to($to)
 	->subject('Time for Symfony Mailer!')
	->text($str_out)
       	;

// メール送信
$mailer->send($email);
```

## 送信

```bash
php symfonymailer.php
```

## 送信結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/6ee3ba61-1c7f-9754-fda1-eb00c94f1054.png)
初心者TerraFormer

今回は私が勉強中のTerraFormについて基本的なコードと共にご紹介します。

# Terraformって何ぞや？
Terraformとは、HashiCorp社により開発されているオープンソースのインフラ自動構築ツールです。TerraformではAWSやAzure、GCPなどのクラウドサービス上のインフラリソース（サーバなど）をコードで定義することが出来ます。

Terraformを利用することで作成したコードに基づいて自動でリソースを構築することが出来ます。Terraformでは、複数システムでコードを再利用することで効率化を図ることが出来ます。また、一度に大量のリソースを定義することで手動よりも早く構築することが可能になります。

このようにインフラリソースをコードで定義することをInfrastructure as Code（IaC）と呼びます。他のIaCツールとしてはサーバ内の設定変更を得意とするAnsibleなどが有名ですが、Terraformはクラウド上のリソースを構築することに長けています。クラウドリソースはTerraformで構築し、サーバ内の設定変更はAnsible、といった使い分けが可能です。将来的には、Ansibleを使い倒していけるようになりたいので頑張ってます(汗

AWSではTerraFormに似たサービスでAWS CloudFormationが存在しますが、こちらはAWS専用のIaCツールです。前述したとおり、TerraFormはAWSやAzure、GCPなどのクラウドプロバイダーに対応しているためマルチクラウド環境においても構築手段を統一することが出来ます。（かっこいい）

# コードがわかりやすい（と思う）
どんなコードなのか見てみましょう

```
provider "aws" {
  region = "ap-northeast-1"
}
```
上記ではAWSプロバイダの設定を行っていて、作業を行うAWSのリージョンを指定しています。

```
resource "aws_vpc" "example" {
  cidr_block = "10.0.0.0/16"
}
```
上記はVPCの作成を行っています。ここで指定するcidr_blockは、VPC内で使用したいIPアドレス範囲を指定します。

```
resource "aws_subnet" "example" {
  vpc_id     = "${aws_vpc.example.id}"
  cidr_block = "10.0.1.0/24"
}
```
上記VPC内にサブネットを作成します。そしてここでもcidr_blockを指定して、サブネット内で利用したいIPアドレス範囲を設定します。

```
resource "aws_security_group" "example" {
  name        = "example"
  description = "Example security group"
  vpc_id      = "${aws_vpc.example.id}"
  ingress {
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

```
このセクションではセキュリティグループを作成し、VPC内への入出力トラフィックを制御しています。"ingress"は受信トラフィックに対するルール、"egress"は送信トラフィックに対するルールを定義しています。

```
resource "aws_instance" "example" {
  ami                    = "ami-0c94855ba95c574c8"
  instance_type          = "t2.micro"
  key_name               = "${aws_key_pair.example.id}"
  vpc_security_group_ids = ["${aws_security_group.example.id}"]
  subnet_id              = "${aws_subnet.example.id}"
  tags = {
    Name = "terraform-example"
  }
}
```
遂にEC2インスタンスを作成します。AMI、インスタンスタイプ、SSHキーペア、セキュリティグループID、サブネットIDなどのパラメータを指定しています。

```
resource "aws_key_pair" "example" {
  key_name   = "example-key"
  public_key = "Your Public Key"
}
```
最後に、SSHキーペアを作成します。キーペア名と公開鍵を指定します。この公開鍵は、EC2インスタンスへSSH接続する際に使用します。

# 
いかがだったでしょうか。私が初めてインプットした時は「わかりやすい！」と感じました。
まだまだ勉強中ですので、この記事について間違った記載ありましたらご指摘の程宜しくお願いいたします。

↓詳しくは、TerraForm（公式）のドキュメントをご覧ください。
### [TerraForm](https://registry.terraform.io/providers/hashicorp/aws/5.26.0/docs/resources/ami)
#クリスマスなので、勉強会運営委員会の1年を振り返る 2023

## この記事は?
メリークリスマス！[@cosme](https://www.cosme.net/)メディアの開発を担当しています、アイスタイル・エンジニアの村田です。アイスタイルには、勉強会やLT運営など、さまざまなエンジニア向けイベントを行う**勉強会運営委員会**という組織があり、村田も所属しています。個人的にも、社内外の折衝など多岐に動いてきました。今日は委員会が1年間で行ったことを振り返ってみます。

 ※毎年振り返りにアドベントカレンダーを書く文化があります

https://techblog.istyle.co.jp/archives/9360

https://qiita.com/sakaguchii/items/a7250df7c741e3bd289d


## 勉強会運営委員会とは
勉強会運営委員会とは、2021年から本格的に始動したアイスタイル内で様々な勉強会を企画・運営し、最終的にはアイスタイルのエンジニアの市場価値を上げまくろうという組織です。社員、業務委託含め10人近いメンバーがおり、それぞれが目標達成に向かって日々尽力しています！

委員会の今期の活動方針は、
・インプットからアウトプットへの循環を形成する
・社外へのアウトプットも試みる、でした。



## 2023年の振り返り(本題)

### 🍇TMモデリング勉強会
外部コミュニティ「TMの会」の勉強会会場にアイスタイルの会議室を提供して、社員にも参加してもらった。
データモデリング勉強会、SQLインデックスチューニング勉強会、SQL入門勉強会などを開催した。
勉強会後の懇親会の開催が上手く行かず、これに関しては現在も模索中との事。


https://tm-study.connpass.com/event/269080/

https://tm-study.connpass.com/event/278407/

https://tm-study.connpass.com/event/300485/

### 🍍テク子の部屋
テク子の部屋という名前のSlackハドルミーティングを使ったラジオ番組を運営した。

元アイスタイルCTOの[竹澤さん](https://note.com/solmu/n/nd106e8619ce8)と、社内で各所に散らばっているエンジニアを毎回ゲストとして呼んで、月1のランチタイムにテーマトークをし、その様子をSlackのハドルミーティングで放送した。基本的にはアイスタイル所属歴が長いエンジニアの方をゲストに招き、アイスタイルでの出来事や、これまでのエンジニア歴でのお話をしていただいた。過去のお話を聞くこと大変役立つ内容が多く、またリモートで見えづらくなってしまった人と成りを改めて知る機会となった。

また、ラジオ参加者からフレッシュなエンジニアの方の話も聞きたいという声をいただき、第5回は新卒エンジニアの方をゲストに招いた。新卒の方からは配属部署の選び方など、新卒の方を迎える側として無かった観点を聞くことが出来た。


### 🥝勉強会紹介タイム
社内で勉強会の機運を醸成することは勉強会運営委員会の大事な機能の一つである。connpassなどで開催されている各勉強会をメンバーで見合い意見を出すことで、どういった勉強会を開催できそうか知見を貯めた。同時に社内のメンバーへの近々開催されるホットなイベントの共有も行なっていたが、実際に参加したことの計測が難しいため、委員会側のモチベーションが続きにくいという課題が判明した。

### 🍑テックブログReborn

今まではWordPress製のサイトが公式テックブログと位置付けられていたところを、QiitaおよびZennにも組織アカウントを作り、それぞれの自由意志で好きなプラットフォームに投稿できるようにした。

また、記事を書くガイドラインがないことが皆が記事を書く障壁になっているのではないか、という意見があり、コンプライアンスのチェック事項を設けるとともに、記事を公開する前に、技術レビュー1人、勉強会運営委員会1人それぞれの承認を得てから記事を出せるようなフローにした。レビュー効率化の一環として、Backlogで記事レビューをタスク化することで管理しやすくなり、効率がとても高まった。

Rebornしたてのタイミングは投稿者側も最初に投稿する躊躇いがあると考え、週2の間隔で記事を投稿する「スタートダッシュキャンペーン（社内名称）」を企画。有志を募り10月に開催し、無事完走することが出来た。

https://zenn.dev/p/istyle

https://qiita.com/organizations/istyle


### 🍐OBを招いての技術勉強会
Lambigさん、というかつてアイスタイルでリードエンジニアをしていたOBエンジニアをお呼びして、DI(Dependency Injection)に関する勉強会を行った。Javaを扱う内容が多く、普段Javaに触れていないメンバーは苦戦していたことから、勉強会運営目線としてテーマ選定の難しさを感じた。内容は非常に充実していたので、運営目線でより参加者に優しい形での開催を目指したい。

### 🍒セキュリティWAF勉強会
アイスタイルにセキュリティ的な支援をしてくれているベンダーにご協力いただき、２回にわたって開催された。セキュリティの基礎知識だけでなく、WAFの挙動まで、深掘りするような内容であった。

### 🥥毎回のエンジニア月次会主催
アイスタイルでは、部門を横断した情報共有やナレッジシェアの場としてエンジニア全員が参加するエンジニア月次会を開催している。今年から勉強会運営委員会が企画運営を行なっている。

毎回、部門ごとに発表者を募り、業務上の成果や、チームでの取り組みなど様々なテーマで発信がされている。AWSの資格支援情報など、そういった情報発信と勉強会運営委員として勉強会開催の情報まで多岐にわたって発信した。大勢のエンジニアの前で、進行や発表をするのは少々緊張したものの、普段関わりのないメンバーに顔を覚えてもらうなど、意外な面でのプラスもあったことは収穫であった。


### 🍏アドベントカレンダー2023の実施
アドベントカレンダーを実施した。1ヶ月に30本近い記事を各メンバーで書き上げ、色とりどりの記事が発表された。前述の通り、レビューのタスクをBacklogに集約し、フローを整備したことで効率よく実施できた。


### 🍌社外とのイベント共催の推進
アイスタイルでは、エンジニアの外部勉強会、交流会の参加をサポートする支援があるなど、社内だけでない外部との交流も推奨されている。そうすることによって、エンジニアが知見を得るだけでなく、社外にも繋がりを作りつつ、イベントの共催なども各メンバーで積極的に進めている。

(LTなど、istyle社とのテック系イベント共催などをやりたい会社さまがいらっしゃいましたら、ご気軽にお声がけください！)

アイスタイルの勉強会運営委員連絡窓口、
suzukitoのXアカウントは[こちら](https://twitter.com/toshifusa)。


## 終わりに(2024年に向けて
勉強会運営委員会は2023年、数多くの施策を実施してきました。来年も、アイスタイルの良い将来に向かって数多くの施策をやっていきたいと思います。皆様におかれましては、良い年の瀬をお過ごしください。
APIGatawayで指定のヘッダーを含まないリクエストを許可する方法

APIGatawayで、指定のヘッダーが無いとリクエストを拒否する設定

APIGatawayのリソースポリシーに以下を設定
```
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Deny",
      "Principal": "*",
      "Action": "execute-api:Invoke",
      "Resource": "arn:aws:execute-api:ap-northeast-1:{アカウントID}:{APIリソースの識別英数字}/*",
      "Condition": {
        "StringNotEquals": {
          "aws:Referer": "{適当な文字列}"
        }
      }
    },
    {
      "Effect": "Allow",
      "Principal": "*",
      "Action": "execute-api:Invoke",
      "Resource": "arn:aws:execute-api:ap-northeast-1{アカウントID}:{APIリソースの識別英数字}/*"
    }
  ]
}
```

Cloudfrontのオリジンで以下を設定
![スクリーンショット 2023-12-20 16.18.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72734/c120fc89-ffb3-fc82-d0ce-ee3254b7dae6.png)
スライドして実行するUIとそのアクセシビリティ

# スライドして実行するUI

旧iOSのスライドしてロック解除やチケット系アプリのスライドして入場など、わざわざスライドして実行させることで誤動作を防ぐUIがあります。ツイキャスにもイベントのチケットを販売できる機能があり、この機能の実装時に以下のようなスライドして入場するUIを実装しました。この記事ではその実装とアクセシビリティ対応を紹介します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/188172/f3e4e10e-b590-6861-07f5-21f55b007d3c.png" width="300" >

# 実装

以下に簡略化したサンプルコードを示します。特に難しいことはしていないのですが、ポイントとしては

- スワイプを始めたところところからの差分でスライダーを移動させる
- スマホ対応のためにスワイプ時はtouchmoveをキャンセルする

あたりだと思います。

<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="zYbOZmW" data-user="Takuto-Yoshikawa" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/Takuto-Yoshikawa/pen/zYbOZmW">
  Swipe UI</a> by Takuto Yoshikawa (<a href="https://codepen.io/Takuto-Yoshikawa">@Takuto-Yoshikawa</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>


# アクセシビリティ対応

さて実装時にWeb上にこういったUIのアクセシビリティに関して情報を見つけることができませんでした。そこでどうアクセシビリティ対応するのか検討する必要がありました。

結論から言うと

- 非読み上げ環境ではスライドして実行するUIを表示する
- 読み上げ環境ではスライドして実行するUIをを隠して代わりに普通のボタンを表示する

という対応になりました。つまり、読み上げ環境やキーボード環境の場合はスライドさせることはせず、タップだけで実行できるようにします。

そもそもスライドという小さいボタンを押して指をなぞる操作は身体能力が衰えると難しくなっていく操作に思えるので、使い所はよく考える必要がありそうです。その点を考えても代替の方法としてスライド操作以外を提供するのは妥当に思えます。

## VoiceOverでの仕様

なお実装後にiOSのスライドしてロック解除はVoiceOverではどのような仕様になっているか気になり調べてみました。その結果、

- 古いiOSでは、スライドしてロック解除をVoiceOverでタップ
- 最近のiOSでは、画面の一番下から指をスライド

という仕様になっていることが分かりました。今回の検討結果は古いiOSの仕様に近そうです。最近のiOSはそもそもヒットテストを巨大にすることで細かい操作なしにスライドして実行が行えるようにするアプローチのようでした。画面全体がスライド対象の場合はこのアプローチの方が良さそうです。
複数の devcontainer を使い分ける

# はじめに

VSCode の devcontainer、とっても便利ですよね。  
今回は、devcontainer をより便利に使う為のテクニックをご紹介します。

# devcontainer の使い分け

とあるアプリを、フロントエンドとバックエンドそれぞれ１つの github リポジトリにまるっとまとめて開発しちゃいたい、といったことはありませんか？  
このような場合に、リポジトリ内にフロントエンド用とバックエンド用でそれぞれ devcontainer を作成できると便利だと考えたので、出来ないか調査・検証してみました。  
結論、できましたのでその方法を共有できればと思います。

## ディレクトリ構造

下記のような形になります。
```bash
root@nimowagukari:/srv/work/multiple-devcontainer-test# tree -a -I .git
.
└── .devcontainer
    ├── backend
    │   └── devcontainer.json
    └── frontend
        └── devcontainer.json

3 directories, 2 files
root@nimowagukari:/srv/work/multiple-devcontainer-test# 

root@nimowagukari:/srv/work/multiple-devcontainer-test# git diff
diff --git a/.devcontainer/backend/devcontainer.json b/.devcontainer/backend/devcontainer.json
index efef13e..042b0f7 100644
--- a/.devcontainer/backend/devcontainer.json
+++ b/.devcontainer/backend/devcontainer.json
@@ -1,12 +1,16 @@
 // For format details, see https://aka.ms/devcontainer.json. For config options, see the
 // README at: https://github.com/devcontainers/templates/tree/main/src/javascript-node
 {
-       "name": "Node.js",
+       "name": "backend",
        // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
        "image": "mcr.microsoft.com/devcontainers/javascript-node:1-20-bullseye",
        "features": {
                "ghcr.io/devcontainers/features/git:1": {}
-       }
+       },
+       "runArgs": [
+               "--name",
+               "${localWorkspaceFolderBasename}-backend"
+       ]
 
        // Features to add to the dev container. More info: https://containers.dev/features.
        // "features": {},
diff --git a/.devcontainer/frontend/devcontainer.json b/.devcontainer/frontend/devcontainer.json
index efef13e..d380a74 100644
--- a/.devcontainer/frontend/devcontainer.json
+++ b/.devcontainer/frontend/devcontainer.json
@@ -1,12 +1,16 @@
 // For format details, see https://aka.ms/devcontainer.json. For config options, see the
 // README at: https://github.com/devcontainers/templates/tree/main/src/javascript-node
 {
-       "name": "Node.js",
+       "name": "frontend",
        // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
        "image": "mcr.microsoft.com/devcontainers/javascript-node:1-20-bullseye",
        "features": {
                "ghcr.io/devcontainers/features/git:1": {}
-       }
+       },
+       "runArgs": [
+               "--name",
+               "${localWorkspaceFolderBasename}-frontend"
+       ]
 
        // Features to add to the dev container. More info: https://containers.dev/features.
        // "features": {},
root@nimowagukari:/srv/work/multiple-devcontainer-test# 

```

.devcontainer 直下にディレクトリを作成し、その中に devcontainer.json を配置する形になります。  

コンテナを起動する際の操作にも注意が必要です。
- 開くフォルダは、.devcontainer フォルダの直上のフォルダ
- その後、対象の devcontainer 名を選択する

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2531097/a9ac3695-45ca-148b-aeb0-483c86fdb91f.gif)

# おわりに

いかがでしたでしょうか。  
devcontainer を利用して新たに monorepo で開発を進めようと考えている場合には、是非活用してみて下さい。
エンジニアへの転身：30歳、二児の母が外国で歩む新たなキャリアの道

# **序文**
株式会社エアークローゼットに今秋入社したばかりの藤崎です。この記事はエアークローゼット Advent Calendar 2023の20番目の記事です。外国人であり、しかも二児の母であることから、いい年（30歳）にもかかわらず新しい職に転職したことで、「どうやって！？」とLinkedInなどでよく尋ねられることがあります。そこで、今回はエンジニアになるまでの経緯について書いていこうと思います。

# **まずは決断**

28歳のとき、「ウェブ開発者になりたい！」と思い切って決断しました。経験は？ありませんでした。パソコンが得意？別に得意ではありませんでした。でも、まあ、「やる」と決めたのでやり切るしかなかったです！

# **どうやって勉強した？**

​​最初は、Eloquent Javascriptのような本やUdemyのオンラインコースなどを使って独学で勉強しました。しかし、数カ月経ったら、独学で勢いを維持するのはとても難しいことに気づき、コーディングスクールに通うことにしました。コーディングスクールでは、オブジェクト指向プログラミング、Javascript、Ruby、Ruby on Rails、HTML、CSSの基礎を学びました。

# **2児の母としてどのように勉強をこなしたか**

コーディングスクールを始めて間もなく、第2子を妊娠し、勢いを保つのに本当に苦労しました。毎日は気持ちが悪く、嘔吐し、へとへとでした。しかし、スケジュールを立て、仲間同士でプログラミングをすることで、勉強を続けることができました（他の人が私を頼りにしていると、先延ばしにしにくくなるもの！)。プログラム卒業後すぐに出産し、勉強を続けながら、「自由な」時間を使ってフリーランスで仕事をしました。締め切りがあることは、コーディングを止めないための十分なプレッシャーになりました。また就職活動と乳児の世話をしながら独学で新しい言語とフレームワークの勉強を続けました。何かしらの[コミットメント装置](https://en.wikipedia.org/wiki/Commitment_device)を持つことは、本当に軌道に乗せるのに役立ちました！

# **日本での就職活動は？日本語は必要ですか？**

プログラミングの勉強と並行して日本語能力試験N2にも挑戦し、合格することができました。airClosetには外国人エンジニアが多く、英語やベトナム語を話せる人がたくさんいますが、私は主に日本語を使って仕事をしています。しかし、airClosetで働くために日本語が完璧である必要はありません。日本語でのコミュニケーションを積極的に行い、コミュニケーション能力を向上させる努力を続ければOKです！

# **就職活動で苦労したことはありますか？**

就職活動中、少し自分を疑うこともありましたね。「エンジニアの経験もほとんどなく、小学生のような日本語を話す30歳の2児の母を誰が雇いたいというのか？」

幸運なことに、airClosetはそうしてくれました！私が単なる母親以上の存在であることを見抜いてくれました。私は開発者であり、仕事で実現できる可能性を秘めた人であることを認めてくれました。同様に、私はairClosetに、従業員を大切にし、挑戦させ、投資し、働く女性を支援することを大切にしている会社であることを感じました。迷わずに入社させていただきました。

# **エンジニアになった後の人生は？**

**楽しいです！** 私は自分にとって意味のあることをしていて、自分をチャレンジさせ、目標を達成しているわけですから！もちろん、入社後、大変なこともありました。外国で2児の母として新しいキャリアを積むことは非常に厳しいことなんです！勉強しないといけないこと（日本語を含む様々な言語）は尽きることがなく、いつも追いつき追い越せモードですね。でも、子供たちは、母親が一生懸命働き、楽しんでいる姿を見て、良い影響を受けて欲しいです！将来、子供たちも停滞することなく、難しいこと（楽しいこと！）に挑戦することができたらなと思ってます！

# **おわりに**
最後までご覧いただきありがとうございました！

エアークローゼット Advent Calendar 2023はまだまだ続きますので、ぜひ他のエンジニア, デザイナー, PMの記事もご覧いただければと思います

また、エアークローゼットはエンジニア採用活動も行っておりますので、興味のある方はぜひご覧ください！

https://corp.air-closet.com/recruiting/developers/

https://www.wantedly.com/companies/airCloset/projects