OmniAICreator/Qiita-1.07M huggingface dataset:
GitLab CIでDockerイメージをビルドする

GitLabでDockerイメージをビルドする際の基本的な設定を考えることにする。なお、今回、RunnerはDocker Runnerで作成しているものとする。

# 簡単に書くと

* dindでは特権モードを使うように設定、doodではdocker.sockをマウントするように設定
* dindとdoodでは使用するコンテナイメージが違う
* コンテナレジストリへのログインにはそのための環境変数を使う

# Docker in DockerかDocker outside of Dockerか

Docker in Dockerは、Dockerコンテナ内にDockerコンテナを立てるやり方、Docker outside of Dockerは、Dockerコンテナからホスト側のDockerを呼び出し、ホスト側にDockerコンテナを立てるやり方である。Docker in Dockerはdind、Docker outside of Dockerはdoodと略すのが通例である。

dindはあたかも普通の仮想マシンのようにDockerを扱うことができるというのが大きい。一方、dindは特権モードで動かす必要があることから、ひとたびトラブルが起きたら、ホストごと巻き込んでトラブルが起きる。

一方、doodは特権モードである必要はないため、影響があるのはホストとのマウントの範囲に限られる。一方、取り扱いには少し面倒な作業が必要になること、dood固有のトラブルが起きやすいことなどの問題がある。

今回は双方の取り扱いを書くことにするが、基本はdoodを推奨する。

また、事前にDockerベースのRunner設定が完了しているものとする。

# 設定作業

GitLab Runnerの設定は、config.tomlファイルを用いる。dindとdoodで設定箇所が異なる。

## dindでのconfig.tomlの修正箇所

runners.dockerセクションにprivilegedという項目がある。ここがデフォルトではfalseになっているが、ここをtrueに変更し、特権モードを有効にしたうえでGitLab Runnerを再起動する

## doodでのconfig.tomlの修正箇所

runners.dockerセクションにvolumesという項目がある。この配列に`"/var/run/docker.sock:/var/run/docker.sock"`という項目を追加する。これによりホストのDockerのUNIXソケットをコンテナ側にマウントする。設定ファイル変更後はGitLab Runnerを再起動する

# 使用するイメージ

使用するイメージは、dindとdoodで異なる。どちらも[docker](https://hub.docker.com/_/docker)というイメージを用いるが、dindではdindとついたタグのイメージを使う。例えばdocker:dindといったようなイメージを指定する。一方doodでは普通のタグを使う(例えばdocker:stableなど)。

# コンテナレジストリへのログイン

コンテナレジストリへログインするには、`docker login`コマンドを使う。外部のDockerレポジトリを使う場合はそのクレデンシャルを使えばよいが、GitLabに付属したコンテナレジストリを使う場合、そのログインは`echo "$CI_REGISTRY_PASSWORD" | docker login $CI_REGISTRY --username $CI_REGISTRY_USER --password-stdin`というものになる。簡単に言えば、標準出力にパスワードを出力し、それをパイプでログインコマンドの標準入力に渡す形でログインする、ということである。

# buildxを使いたい

buildxを使うには、イメージを作るのが手っ取り早いが、簡易にやると、以下のようなコードになる。

```bash
mkdir -p /usr/local/libexec/docker/cli-plugins
apk add git
apk add curl
export DL_ARCH_SUFFIX=${CI_RUNNER_EXECUTABLE_ARCH//\//-}
export BUILDX_URL="https://github.com/docker/buildx/releases/download/v0.10.0/buildx-v0.10.0.$DL_ARCH_SUFFIX"
curl -Lo /usr/local/libexec/docker/cli-plugins/docker-buildx $BUILDX_URL
chmod a+x /usr/local/libexec/docker/cli-plugins/docker-buildx
docker buildx install
docker buildx create --use --name multiarch --platform linux/amd64,linux/arm64
```

ここでバージョンは0.10.0と指定しているが、これは当然値が変わることがある。また、multiarchと指定しているが、ここの名前は自分で決めて構わない。ただし、この名前は後で使うので注意。

イメージのビルドは、例えば`docker buildx build --pull --platform linux/amd64,linux/arm64 -t $CI_REGISTRY_IMAGE:latest --push .`のようなコマンドになる。

最後の後始末は、このコマンドのあとに入れるわけだが、`docker buildx rm multiarch`と、ここで先ほど決めた名前を使う。なお、after_scriptに入れてはならない。というのも、after_scriptの実行コンテキストは他の2つのコンテキストとは別なためである。

なお、現在、複数アーキテクチャのイメージをコンテナレポジトリにpushすると、正しく表示されない不具合があるが、これはGitLabのIssueにも[登録されている](https://gitlab.com/gitlab-org/gitlab/-/issues/232815)バグである。
【DRF】データごとの件数をカウントして返すやり方

タイトルの通りなんですけどこれがなかなかできなくて4時間くらいずっとハマってしまったのでメモしておきます。


## やりたきこと

タイトルの通りなんですけど、例えば記事モデルと、タグのモデルがあるとします。
そして、タグごとに、「そのタグをつけて投稿してるユーザ数」みたいなデータがほしいとします。


```models.py

class Tag(models.Model):
    name = models.CharField(max_length=40)

class Article(models.Model):
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    title = models.CharField(max_length=100)
    content = models.TextField()
    tags = models.ManyToManyField(Tag, blank=False)

```

※実際であれば、Userモデルもあるのですが、上記サンプルコードからは割愛してます。

色々としないといけない気がするんですよね。

- 逆参照だ！
- ジョイン的な？
- SQLでいうgroup by的なこと
- なんとなくわかるけど、Serializerどうかけばいいんだろう

とかとか。
単純なdjangoなら「こうやればいけるよ」っていうの諸賢方が書いてくださってるのですが、DRFでこういうのが書かれている記事がなかなかなかったんです。Serializerがやはり曲者・・・。

## こう書いたらいけた

まず先に、views.pyのほうから説明します。

```view.py
class TagRankingListView(generics.ListAPIView):
    queryset = Tag.objects.annotate(Count('article'))
    serializer_class = TagRankingSerializer

```

`queryset = Tag.objects.annotate(Count('article'))`

で、そのタグがついたarticleのカウントをannotateして、それをquerysetに入れます。
そして、serializer_classを設定してますね。

そしたらserializer.pyです。

```serializer.py
class TagRankingSerializer(serializers.ModelSerializer):

    user_count = serializers.SerializerMethodField()

    class Meta:
        model = Tag
        fields = ('name', 'user_count')

    def get_user_count(self, instance):
        return instance.article__count

```

`user_count = serializers.SerializerMethodField()`

で出力する値を一個定義してます。
そして、 `class Meta:` でモデルと出力するfieldsを定義します。

そして、
```python
    def get_user_count(self, instance):
        return instance.article__count
```

で、viewsでannotateしたarticle__countを返すような感じで書きます。
※instanceには、Tagが入ります。

これで、 `http://127.0.0.1:8000/api/tagranking/`  にアクセスすると、

```
[
    {
        "name": "ビートマニア",
        "user_count": 0
    },
    {
        "name": "オンゲキ",
        "user_count": 0
    },
    {
        "name": "チュウニズム",
        "user_count": 0
    },
    {
        "name": "バイオハザード",
        "user_count": 1
    },
    {
        "name": "プリンセスコネクト Re:Dive",
        "user_count": 0
    },
    {
        "name": "ウマ娘 プリティーダービー",
        "user_count": 3
    },
    {
        "name": "オーバーウォッチ",
        "user_count": 1
    },
    {
        "name": "NIKKE",
        "user_count": 1
    }
]
```


という値が返ってきます。


`serializers.SerializerMethodField()`

多分こいつがかなり便利なものでDRFでAPIを書くときに重宝しそうな気がしてます。

これで一応やりたきことは達成できたのですが、
ひとつ難点があって、これめっちゃわかりづらいんですよね。

慣れの問題かもしれませんが、なんかわかりづらい・・・。
viewsとserializerの両方をみてようやくなにを返すAPIかがわかる。みたいな感じなのかな。

きっと、もっとスマートでいい書き方があると思いつつも、それを模索してたら一向に先に進めないのでいったんはこのまま進めるのです。

でも、本当にこれができてすごく感動したんですよ。
なんてったって4時間かかりましたからね。
普通にSQLとかで書けば一瞬なんですけど、いやぁほんとに苦労しました。

最終的に、Kindleで書籍を買ってそれをみてようやく突破した感じです笑。

[現場で使える Django REST Framework の教科書［3.2 LTS 対応版］ （Django の教科書シリーズ）](https://amzn.to/3ITDIx5)

普段ならこういう書籍は実物を買うのですが、あまりにも悔しくて今すぐなんとかしたくてこちらをポチりました。
そしたら、Mac版のKindleがまあ相変わらず使いづらいこと・・・笑

でも、これを買って無事解決できたので本当に嬉しかったです。
DRFについての書籍っておそらくこれしかないんじゃないかなって思ったので、時間あるときに一通り目を通しておきたいです。著者の方、本当にありがとうございました。


最後の方はすごく関係ない話ししてしまいましたがそんな感じです。
Django頑張って勉強します。
【Xcode】$PRODUCT_NAMEなどは何を表しているのか

# はじめに
Run Scriptをいじっていると`$PRODUCT_NAME`や`$TARGET_NAME`など意味不明な暗号が出てきます。
これが何なのか気になったので調べてみました。

# 正体
サンプルというプロジェクトを作成して解説を行います。
![スクリーンショット 2023-01-18 21.19.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/88314962-f48a-a663-2686-8a85e48851c4.png)

$PRODUCT_NAMEなどの正体はパスなのです。

先ほど作成した「sample」プロジェクトの場合は以下のようになっています。
```
PRODUCT_NAME=sample

TARGET_NAME=sample

SRCROOT=/Users/miyamototaishin/Desktop/sample
```

# 調べ方
① プロジェクトを選択します
② ターゲットを選択します
③ 「Build Phases」を選択します
④ 「＋」を選択します
![スクリーンショット 2023-01-18 21.24.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/246d1ee8-bacc-b871-fe85-6c9f267bf3c1.png)

⑤ 「New Run Script Phase」を選択します
![スクリーンショット 2023-01-18 21.27.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/a71661a7-c9e4-1651-8573-2b4ac95cefd7.png)

追加されたRun Scriptに以下のスクリプトをコピペします。
```sh
env > env.txt
```
![スクリーンショット 2023-01-18 21.29.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/f9fd55ff-68c2-c511-87e0-5b6d735750de.png)

実行します
![スクリーンショット 2023-01-18 21.29.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/415876db-8f57-9494-9cfd-fc90b9a187f3.png)

ビルドできたら`env.txt`が生成されているので開きます。
![スクリーンショット 2023-01-18 21.30.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/91c8b0da-1a83-29eb-4737-677dc845459d.png)

こんな感じでいっぱい載っているので必要なものを探して使いましょう
![スクリーンショット 2023-01-18 21.31.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/0235aad6-c425-3563-2957-273ff60cb97b.png)

# おわり
意外と使うのでやり方を覚えておいて損はなさそうです。

# 参考記事
https://shu223.hatenablog.com/entry/20120804/1344155002
[Python] Fletとは

## Fletとは
- フロントエンド開発の経験がなくても、好みの言語で開発可能なフレームワーク
    - インタラクティブなマルチユーザWeb
    - デスクトップ
    - モバイルアプリケーション
- Flutter by Google に基づくFlet Controls を用いてプログラムのUIを構築
    - Flutterウィジェットをラップするだけでなく独自の意見を追加
        - 小さなウィジェットを組み合わせる
        - 複雑さを隠す
        - UIのベストプラクティスを実装
        - 合理的なデフォルトを適用

## Flet app example
- 現在はPythonでFletアプリを書くことが可能
    - 他の言語も近々追加予定

### ライブラリ追加
```sh
# pipの場合
$ pip install flet
# poetryの場合
$ poetry add flet
```

### 実装例

```python
#!/usr/bin/env python3
# -*- coding: utf_8 -*-
"""flet実装例
"""

import flet as ft


def main(page: ft.Page):
    """実行ターゲット

    Args:
        page (ft.Page): ページのインスタンス
    """
    page.title = "Flet counter example"
    page.vertical_alignment = ft.MainAxisAlignment.CENTER

    txt_number: ft.TextField = ft.TextField(
        value="0", text_align=ft.TextAlign.RIGHT, width=100
    )

    minus_click = get_minus_click(page, txt_number)
    plus_click = get_plus_click(page, txt_number)

    page.add(
        ft.Row(
            [
                ft.IconButton(ft.icons.REMOVE, on_click=minus_click),
                txt_number,
                ft.IconButton(ft.icons.ADD, on_click=plus_click),
            ],
            alignment=ft.MainAxisAlignment.CENTER,
        )
    )


def get_minus_click(page: ft.Page, txt_number: ft.TextField):
    """テキストの値を-1するボタンの処理を返す

    Args:
        page (ft.Page): ページのインスタンス
        txt_number (ft.TextField): 数字のテキストインスタンス
    Returns:
        テキストの値を-1してページを更新する処理
    """

    def minus_click(e):
        txt_number.value = str(int(txt_number.value) - 1)
        page.update()

    return minus_click


def get_plus_click(page: ft.Page, txt_number: ft.TextField):
    """テキストの値を+1するボタンの処理を返す

    Args:
        page (ft.Page): ページのインスタンス
        txt_number (ft.TextField): 数字のテキストインスタンス
    Returns:
        テキストの値を+1してページを更新する処理
    """

    def plus_click(e):
        txt_number.value = str(int(txt_number.value) + 1)
        page.update()

    return plus_click


if __name__ == "__main__":

    # OSのネイティブウィンドウで起動
    ft.app(target=main)

    # Webブラウザで起動
    # ft.app(target=main, view=ft.WEB_BROWSER)

```

## 参考
- [Flutter](https://flutter.dev/)
- [Flet](https://flet.dev/docs/)
草莽Erlang ── 30. lists:any

口で言うより行うことがErlang習得への近道と信じています。

https://qiita.com/mnishiguchi/items/9237780e849d80a85e11

## lists:any/2

 リストの要素に対して適用する真偽値を返す関数を渡します。 少なくとも1つの要素が `true`と評価されれば`true`、そうでなければ `false`が返されます。

https://www.erlang.org/doc/man/lists.html#any-2 

```erlang
> Words = ["foo", "bar", "hello"].

> lists:any(fun(S) -> string:length(S) == 5 end, Words).
true

> lists:all(fun(S) -> string:length(S) < 5 end, Words).
false
```

[listsモジュール](https://www.erlang.org/doc/man/lists.html)には他にもリスト処理のための関数がたくさんあります。

## Elixirにも挑戦したい

闘魂ElixirシリーズとElixir Schoolがオススメです。

https://qiita.com/torifukukaiou/items/3b65e5c04fa8c55f526e

https://elixirschool.com/ja

https://qiita.com/piacerex/items/09876caa1e17169ec5e1
IoTプラットフォームの種類

# はじめに
毎週1本様々な技術に関する記事を投稿しています。
もし興味のある方は下のリンクから他の記事も見ていただければ幸いです。
 [@7_inai_](https://qiixta.com/7_inai_)

# IoTプラットフォームとは
IoTプラットフォームとは、`IoTを構成するための要素である、IoTデバイス・アプリケーション・センサー・ネットワーク等をクラウドを介して繋ぐための土台(プラットフォーム)`となるものです。
この記事では、各企業がリリースしている __IoTプラットフォームの詳細__ について記述します。IoTプラットフォームの概要について知りたい方は、[こちら](https://qiita.com/7_inai_/items/ee541c9ab58cdcab768b)からご確認ください。


# IoTプラットフォームの種類
以下のIoTプラットフォームの概要や特徴についてこれから説明していきます。
- ①Predix(GE)
- ②Mindsphere(シーメンス)
- ③SORACOM(ソラコム)


## ①Predix(GE)
GEが提供しているIoTプラットフォームで、__産業用機械からのデータを収集・解析する__ ためのソフトウェアプラットフォームです。
GAFAMの台頭により業績が低迷していたGEは、これらソフトウェア企業に対応するために __「製造業におけるマイクロソフト」__ を目指しました。そこで打ち出されたのが、インダストリーインターネットプラットフォーム __「Predix」__ です。PredixはクラウドベースのSaaS(Software as a Service)であり、オープンプラットフォームであるため、GE以外の企業も活用することができる

## ②Mindsphere(シーメンス)
シーメンスは電力・ガス・鉄道のようなインフラから電子機器やヘルスケアまで幅広い事業を手掛ける、ドイツ創業の総合電気メーカーです。
シーメンスがリリースしているIoTプラットフォームである __Mindsphere__ はGEのPredixを意識したものであると公言されています。Mindsphereは工場内の設備から情報を収集し、クラウドで管理することができます。また製造現場等のエンドユーザーのみならず、産業機器メーカーも同プラットフォームからデータ収集ができるという特徴があります。

## ③SORACOM(ソラコム)
IoTプラットフォームであるSORACOMは、IoTを実現するために必要となる、IoTデバイス、通信、アプリケーション等をワンストップで提供します。
SORACOMは、__自身がクラウド上に実装されているため、他のクラウドサービスとの親和性が非常に高い__ です。そのため、従来IoT化で必要だった、システムの計画や構築といった労力を必要とせずに、迅速にIoT化することができます。

## その他
他にも、AmazonのAWSやMicrosoftのAzureといったクラウドコンピューティングサービスも、IoTプラットフォームとして使用することができます。

# 終わりに
それぞれの企業が開発しているIoTプラットフォームに関して、調査しまとめましたが、データの見える化やIoTデバイスの接続といった主な機能は同じでありながらも、得意分野や目的に違いがあることが分かりました。また機会があれば、それぞれのプラットフォームについてもっと深掘りした記事を作成したいと思います。


最後までお付き合いくださりありがとうございました。
【技術書まとめ】HTML&CSS コーディング・プラクティスブック 6 実践シリーズ

引き続き現在のCSSを整理するために本書を手に取った。

- demo
    - https://candid-tapioca-70a7df.netlify.app/

- グリッドは直下の子要素にしか適用できない
    - 階層が深くなると複雑かつ拡張性もなくなる
- 設定を一元管理して、必要なところで使うようにする
    - `partsGrid`で左右の余白を揃える
    - `grid12`でPCとモバイルでレスポンシブにする


## 10pxギャップのグリッドで4列に横並びにする

```css
/* 12分割グリッド　*/
.grid12 {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  column-gap: 10px;
}
```


## h2と隣接pをグリッド8列目まで伸ばす（PC）

```css
@media (min-width: 768px) {
  .list h2,
  .list h2 + p {
    grid-column: span 8;
  }
}
```


## 3列グリッドでpcの最大幅1088pxにしつつ、レスポンシブ対応する

```css
.partsGrid {
  display: grid;
   /* 画面幅375pxでは余白30px(8vw = 375px x 0.08 = 30px) */
  grid-template-columns: minmax(8vw, 1fr) minmax(auto, 1088px) minmax(8vw, 1fr);
}

.partsGrid > * {
  grid-column: 2;
}
```


## 6グリッド使ったテキストで、折り返さずに8文字表示する

```css
.catch h1 {
  grid-column: span 6;
  min-width: 8em; /* 「ボタニカルライフ」を折り返さずに表示する */
}
```
AWS EC2 既に起動しているルートデバイスタイプがEBSのインスタンスのタイプを変更する方法

# 概要

- EBSボリュームを使っているEC2インスタンスのインスタンスタイプを変更する方法をまとめる。

# 情報

- 筆者のEC2のルートデバイスタイプがEBSかどうかの確認は下記の方法で行った。

https://qiita.com/miriwo/items/d6b98fb6416e61ea6d0e

# 方法

1. AWSにログイン
1. EC2のトップに移動
1. 左サイドバーの「インスタンス」をクリック
1. インスタンス一覧の中のタイプを変更したいインスタンスを選択
1. 「インスタンスの状態」をクリックし「インスタンスを停止」をクリック
1. インスタンス一覧の当該インスタンスのインスタンスの状態が「停止済み」になったことを確認
1. インスタンス一覧の当該インスタンスを選択し「アクション」の「インスタンスの設定」の「インスタンスタイプを変更」をクリック
1. 遷移先ページで変更したいインスタンスタイプを選んで「適用」をクリック（大きいインスタンスに誤って変更しないように注意する）
1. インスタンスタイプが変更される
1. 後はインスタンスを復活させれば完了

# 参考文献

https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/ec2-instance-resize.html
草莽Erlang ── 29. lists:all

口で言うより行うことがErlang習得への近道と信じています。

https://qiita.com/mnishiguchi/items/9237780e849d80a85e11

## lists:all/2

 リストの要素に対して適用する真偽値を返す関数を渡します。 リストの全体が`true`と評価されれば`true`、そうでなければ`false`が返されます。

https://www.erlang.org/doc/man/lists.html#all-2 

```erlang
> Words = ["foo", "bar", "hello"].

> lists:all(fun(S) -> string:length(S) == 3 end, Words).
false

> lists:all(fun(S) -> string:length(S) > 1 end, Words).
true
```

[listsモジュール](https://www.erlang.org/doc/man/lists.html)には他にもリスト処理のための関数がたくさんあります。

## Elixirにも挑戦したい

闘魂ElixirシリーズとElixir Schoolがオススメです。

https://qiita.com/torifukukaiou/items/3b65e5c04fa8c55f526e

https://elixirschool.com/ja

https://qiita.com/piacerex/items/09876caa1e17169ec5e1
FastAPIのエラーハンドリング

## 概要
- FastAPIのエラーハンドリングについて
- エントリーポイントと同じファイルに定義するかどうかで処理が変化
    - 同じ場合はハンドラーを使用
    - 違う場合はミドルウェアを使用

## エントリーポイントと同じファイルで定義

### ディレクトリ構造
```sh
fastapi_example
├── __init__.py
└── main.py         # FastAPIのエントリーポイント
```

### 実装例
```python:fastapi_example/main.py
#!/usr/bin/env python3
# -*- coding: utf_8 -*-
"""FastAPIのエントリーポイント
"""

from fastapi import FastAPI, status
from fastapi.responses import JSONResponse

app = FastAPI()


@app.exception_handler(Exception)
async def exception_handler(request, exc):
    return JSONResponse(
        status_code=status.HTTP_401_UNAUTHORIZED,
        content={"message": f"{type(exc)}"},
    )


@app.get("/exception")
async def exception():
    raise Exception

```

### 参考
- [Handling Errors](https://fastapi.tiangolo.com/ja/tutorial/handling-errors/?h=error)

## エントリーポイントと別ファイルで定義

### ディレクトリ構造
```sh
fastapi_example
├── __init__.py
├── error.py        # エラー関連のモジュール
├── main.py         # FastAPIのエントリーポイント
└── middleware.py   # ミドルウェア関連のモジュール
```

### 実装例
```python: fastapi_example/main.py
#!/usr/bin/env python3
# -*- coding: utf_8 -*-
"""FastAPIのエントリーポイント
"""

from fastapi import FastAPI

from fastapi_example.error import MyError
from fastapi_example.middleware import HttpRequestMiddleware

app = FastAPI()
app.add_middleware(HttpRequestMiddleware)


@app.get("/my")
async def my_error():
    try:
        int("hoge")
    except Exception as exc:
        raise MyError from exc

@app.get("/value")
async def value_error():
    int("hoge")

@app.get("/exception")
async def exception():
    raise Exception

```

```python:fastapi_example/error
#!/usr/bin/env python3
# -*- coding: utf_8 -*-
"""エラー関連のモジュール
"""


class MyError(Exception):
    pass

```

```python:fastapi_example/middleware
#!/usr/bin/env python3
# -*- coding: utf_8 -*-
"""ミドルウェア関連のモジュール
"""

from fastapi import Request, Response, status
from fastapi.responses import JSONResponse
from starlette.middleware.base import BaseHTTPMiddleware

from fastapi_example.error import MyError
import traceback

class HttpRequestMiddleware(BaseHTTPMiddleware):
    async def dispatch(self, request: Request, call_next) -> Response:
        try:
            response: Response = await call_next(request)
        except MyError as exc:
            print(traceback.format_exc())
            response = JSONResponse(
                status_code=status.HTTP_401_UNAUTHORIZED,
                content={"message": f"{type(exc)}"},
            )
        except ValueError as exc:
            print(traceback.format_exc())
            response = JSONResponse(
                status_code=status.HTTP_402_PAYMENT_REQUIRED,
                content={"message": f"{type(exc)}"},
            )
        except Exception as exc:
            print(traceback.format_exc())
            response = JSONResponse(
                status_code=status.HTTP_400_BAD_REQUEST,
                content={"message": f"{type(exc)}"},
            )
        return response

```

## 参考
- [Advanced Middleware](https://fastapi.tiangolo.com/ja/advanced/middleware/?h=middle)
- [独自定義したExceptionを利用](https://labs.snaq.me/entry/2022/07/19/143409)
github actionsのrunner-osのアップデートの際サービスコンテナを使ってmysqlのバージョン対応した話

github actionsのrunner-osを今まで`ubuntu-18.0.4`を使ってたが、今更ながら
アップデートしました。
https://github.com/actions/runner-images/issues/6002

### 変更後
```yml:workflow.yml
jobs:
   runs-on: ubuntu-latest
```

### 困ったこと
これで再プッシュして一件落着かと思ったが、プッシュ後データベースのマイグレーションjobでテストが落ち、調べていると`ubuntu-latest`のラベルを指定すると`ubuntu-22.0.4`のイメージを使うことになるらしい。
https://github.com/actions/runner-images#available-images
んでこちらのイメージだとプリインストールされているmysqlは8系だよとのこと。
https://github.com/actions/runner-images/blob/main/images/linux/Ubuntu2204-Readme.md

CI回してるサービスはmysql5.7系なのでここで詰まった。

### 解決法
github actionでは[サービスコンテナ](https://docs.github.com/ja/actions/using-containerized-services/about-service-containers)というものがあった。
これは私の中での解釈はローカルでdocker-composeにサービス名とイメージ指定すればコンテナ立ち上がって、別コンテナからアクセスできるのと同じでgithub action上でもジョブ内からコンテナにアクセスできるという理解。

```yml:workflow.yml
test:
    runs-on: ubuntu-latest
    services:
      mysql:
        # 使いたいイメージを指定
        image: mysql:5.7
        ports:
          - 3306:3306
        env:
          MYSQL_ROOT_PASSWORD: root
        # ヘルスチェック
        options: >-
          --health-cmd "mysqladmin ping"
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
    - name: Database migration
        env:
          RAILS_ENV: test
        # mysqlのバージョン確認とマイグレージョン実行
        # mysql -vを実行するとプリインストールされている8系が出るので立ち上げたサービスコンテナに接続
        run: |
          echo 'select version();' | mysql -h 127.0.0.1 --port 3306 -u root -proot
          cp -v config/database.test.yml config/database.yml
          bin/rails db:prepare    
```

[公式](https://docs.github.com/ja/actions/using-containerized-services/about-service-containers#running-jobs-on-the-runner-machine)にはサービスコンテナへのアクセスの方法として`localhost:<port>` または `127.0.0.1:<port>`でいけるよと書いてましたが、`localhost`指定だとConnection Errorになったので
`127.0.0.1`に変更して解決しました。原因わかる方教えてください。

```ruby:config/database.test.yml
test:
  adapter: mysql2
  encoding: utf8mb4
  charset: utf8mb4
  collation: utf8mb4_general_ci
  host: 127.0.0.1　  #localhostだと接続できず
  port: 3306
  username: root
  password: root
  database: test
```
06.グローバル属性解答コード


```index.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="utf8">
    <meta name="description" content="初めてのHTML文書です">
    <meta name="author" content="スタートプログラミング">
    <meta name="keyword" content="html,css,勉強,初心者,初めて,Web,ホームページ">
    <link rel="shortcut icon" href="favicon.ico">
    <link rel="stylesheet" href="style.css">
    <title>はじめてのHTML</title>
</head>

<body>
    <p class="profile">わたしのプロフィール</p>
    <p class="name">名前：下野純</p>
    <p class="age">学年:中学3年生</p>
    <p class="school">学校：スタートプログラミング</p>
</body>
</html>
```



```style.css
body {
  background-color: skyblue;
}
.profile {
  font-size: 24px;
}
.name {
  color: green;
}
.age {
  color: blue;
}
.school {
  color: red;
}
```
AWS EC2 起動中インスタンスのルートボリュームデバイスタイプを確認する方法

# 概要

- 既に起動しているEC2インスタンスのルートボリュームデバイスタイプを確認する方法を簡単にまとめる。

# 方法　

1. AWSにログイン
1. EC2のトップに移動
1. 左サイドバーの「インスタンス」をクリック
1. インスタンス一覧の中の確認したいインスタンスの「インスタンスID」をクリック
1. 「ストレージ」のタブを開き「ルートデバイスタイプ」を確認

    ![インスタンス___EC2_Management_Console_🔊.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/e4348c30-e68b-60d0-a6bf-f7cd8fd7a919.png)
M1 MacBook トリプルディスプレイを作る際のトラブル と 解決案

# この記事を書いた理由
トリプルディスプレイのセットアップに関する記事は多くのサイトで見られました。
しかし、その後の細かな設定については、答えが載っているサイトが少なく
時間を要しました。
自身の備忘録として、そして同じ様な悩みを抱えている人がいたら、解決の一助になれば良いと思い記事を書くことにしました。

# 自身の環境
- 使用しているPC：MacBook Air M1チップ
- 使用しているhub
→https://www.amazon.co.jp/gp/product/B07KJWYQJW/ref=ppx_yo_dt_b_asin_title_o03_s00?ie=UTF8&psc=1

- 今回使用したdisplaylink対応のHDMI変換ケーブル
→https://www.amazon.co.jp/gp/product/B015XESLTO/ref=ppx_yo_dt_b_asin_title_o00_s00?ie=UTF8&psc=1

・改善前の環境：MacBook Air + 別のディスプレイ1つ　の計2つのディスプレイが存在している状態。
　今回、新たに使用していなかったディスプレイを更に一台を繋ごうとしている。

# 行動したこと
ディスプレイを3つに刷るに辺り、こちらの記事が非常にわかりやすかったです。
→https://osuke-new-life.com/m1macbookair-3monitor-6711

上記の記事に書いてある通りに、displaylink対応のHDMI変換ケーブルを購入し
以下の画像のようにセットしました。

<img src = "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2130746/e2ebe683-9200-2b97-23db-2d3c8774e0cc.png" width="50%">

第三のディスプレイは無事に映り、終わったかのように思いました。

# トラブル1 : アマプラなど有料コンテンツが映らない!
正直戸惑いました。ディスプレイを映している方法的に、問題に引っかかるのだとか...。
ではどうすれば良いのかと言うと、こちらの記事が解決法を示していました。
→https://calmtempo.com/2022/08/displaylink_primevideo/

本当にありがたいですね。
これで問題は全て解決したかのように思われました...。

# トラブル2 : なんか画面明るくね？
これは輝度とかの話ではなく、いわゆる「night shift」が機能していないという話です。
他のディスプレイは問題無いのですが、DisplayLinkで映している画面だけ反映されませんでした。

これの解決策として、「BetterDisplay」 を使用することで、night shift調節を試みます。

## 使用するまでの手順
**①BetterDisplay をダウンロードする** 

ダウンロードサイト のURL→https://github.com/waydabber/BetterDisplay

<img src = "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2130746/dbd7072f-cbdd-c69b-3ae4-16e2a9dd9677.png" width="80%">

**②ダウンロードが完了した .dmgのファイルを開き、ドラッグする**

<img src = "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2130746/13a13c0a-7885-3cf1-3aae-c3fac956f065.png" width="80%">

**③BetterDisplay のアプリを起動する**
アプリケーションの中にあるBetterDisplayをクリックする。
すると、メニューバーの右側にアイコンが追加されるので、それをクリックすることで機能が使えます。

<img src = "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2130746/310164bc-442e-9bb2-ea2e-785f6dc3f84e.png" width="80%">

## 実際にnight shift を調節する
実際にクリックすると、各ディスプレイ毎に調整項目が出てくるので、night shift を調節したいディスプレイ のところまで
スクロールして下さい。以下の様な画像の項目があるはずです。
![スクリーンショット 2023-01-18 20.13.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2130746/0a97df8c-77e8-1309-ef1c-0cd9d6d1c36d.png)

これらの内、「Image Adjustments」 → 上から4つ目の項目
をいじることで、night shift の度合い（に相当するパラメータ）を調節することが出来ます。
（私は既に調節済みのため61%とありますが、初めは0% となっているはず）
![スクリーンショット 2023-01-18 20.17.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2130746/d77f41be-9b3c-8a90-69c6-6254987be706.png)

以上です。

# 最後に
BetterDisplayを活用すれば、画質を向上させることができそうな気がします。
ただ、HDMI変換ケーブルがボトルネックな可能性がありそうです。

これに関して何か分かった人がいましたら、コメントなどで教えていただけると幸いです。

最後まで御覧いただき、ありがとうございました。

# 参考文献

【2022】M1MacBook Airを9千円以下でトリプルモニターにする方法:
https://osuke-new-life.com/m1macbookair-3monitor-6711

DisplayLinkで外部出力しているMacBook AirでPrimeVideoを再生する方法:
https://calmtempo.com/2022/08/displaylink_primevideo/

テレビやDisplayLinkディスプレイをサポートし、True Tone、Dark ModeのOn/Offが可能になった
Mac用ディスプレイユーティリティ「BetterDisplay v1.2.8」がリリース。:
https://applech2.com/archives/20220727-betterdisplay-for-mac-support-tv.html

GitHub - waydabber/BetterDisplay:
https://github.com/waydabber/BetterDisplay
【ネットワーク】NATとは



## NATとは


NATは、IPアドレスを変換する装置です。

NATは２つのネットワークインターフェースをもっており、一方はパブリックIPが設定され、もう一方はプライベートIPが設定されている。


## NATの機能

NATは、パケットの送信元IPアドレスを自身のパブリックIPに変換します。これによって、パブリックIPを持たないホストからもNATを経由することでインターネットに接続できるようになります。

家庭で使われているルーターでも内部でNATが機能しています。





## まとめ


NATとは、IPアドレスを変換する装置であり、パケットの送信元IPを自身のパブリックIPに変換することで、パブリックIPを持たないホストでもインターネットに接続できるようにできます。
0.5 スタイルとCSS解答コード



``` index.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="utf8">
    <meta name="description" content="初めてのHTML文書です">
    <link rel="shortcut icon" href="favicon.ico">
    <link rel="stylesheet" href="style.css">
    <title>はじめてのHTML</title>

    <!-- <style>
        body {background-color: skyblue; }
    </style> -->
</head>

<body>
    <p>こんにちは！</p>
</body>
</html>

````

```style.css
/* 1.背景色をライムグリーン（limegreen）にしてみよう */
body {
  background-color: limegreen;
}

/* 2.本文「こんにちは！」の部分だけ、背景色をオレンジ（orange）にしてみよう */
body p {
  background-color: orange;
}
```
マイクラチュートリアル5-2 自動討伐

```lua

-- レバーがONの時に攻撃

while true do
  if redstone.getInput('top') == true then
    turtle.attack()
    turtle.dropDown()
  end
  os.sleep(0.5)
end

-- レバーがOFFの時に攻撃

while true do
  if redstone.getInput('top') == false then
    turtle.attack()
    turtle.dropDown()
  end
  os.sleep(0.5)
end

-- アイテムを同時にチェストに入れるプログラム

while true do
  if redstone.getInput('top') == true then
    turtle.attack()
    for i = 1, 16 do
      turtle.select(i) 
      turtle.dropDown()
    end
  end
  os.sleep(0.5)
end

```
docker-composeで運用しているMisskeyインスタンスをv13にアップグレードする


## 事前準備
DBのバックアップを取り`docker compose down`でサーバーを落とします。[リリースノート](https://misskey-hub.net/docs/releases.html#_13-0-0)を読んで予め変更内容を確認しておきましょう。

## DBのアップグレード
PostgreSQL15が必須なのでDBをアップグレードします。

### DBをダンプ
`sudo docker compose up -d db`でDBだけを起こします。  
以下のコマンドでDBをダンプします。

:::note warn
この方法でダンプしないとDBが破損することがあります。  
（`docker-compose exec db pg_dump -Fc -U misskey -d misskey > misskey.dump`などを使うと[非ASCIIのバイトが破損する](https://stackoverflow.com/questions/63934856/why-is-pg-restore-segfaulting-in-docker/63934857#63934857)ことがある）
:::

```
#DBをダンプ
docker compose -f /var/servers/docker/misskey/docker-compose.yml exec -T db bash -c "pg_dump -Fc -U misskey -d misskey > /var/lib/postgresql/data/misskey_db.dump"

# ダンプデータ取り出し
sudo mv ./db/misskey_db.dump ./

# DBバックアップ
sudo mv db db.old
```

ここでdocker-compose.ymlのDBのバージョンを変更します。  
変更したら次に進みましょう。

```
# DBを起動して初期化
docker compose up -d db

# PostgreSQLのコンテナID取得
docker ps

# ダンプファイルをコンテナにコピー
docker cp misskey_db.dump [先程調べたコンテナID]:/db.dump

# DBインポート
docker compose exec -T db pg_restore -U misskey -d misskey /db.dump

# DB落とす
docker compose down
```

## パーミッションの修正
v13からはrootlessで動くようになったので権限を修正します。
```
sudo chown -hR 991:991 ./files
sudo chmod u+x ./files
```

## 完了
`docker compose up -d`で起動させ動くかチェックします。これで完了です。
【Angular】ng-deepについて視覚的にまとめておくやつ

# ※ng-deep は非推奨です！！！
最初に念を押しておくがng-deepは非推奨である。どんどん使おうという記事ではないのでご留意を。
~~Angular 公式ドキュメントより：[(非推奨) /deep/ 、 >>> と ::ng-deep](https://angular.jp/guide/component-styles#%E9%9D%9E%E6%8E%A8%E5%A5%A8-deep---%E3%81%A8-ng-deep-)~~
2024/09/17 new! → Angular 公式ドキュメントより：[::ng-deep](https://angular.dev/guide/components/styling#ng-deep)

何がどう非推奨とか、どうすればよいとかはまた別のお話なのでここでは触れません。

# 本題
非推奨とはいえ、使わざるを得ない場面で致し方なく…というものにはng-deepをくっつけて実装してある。なので、一応その仕様について一発で分かるようにまとめておく備忘録を残す。

## 通常の状態
これは適当に作ったシンプルなAngular プロジェクトで、とりあえず各種コンポーネントにあるCSSでlabelのcolor指定をしたもの。まだng-deepは使用していない状態。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132584/637c308a-6454-4463-f8fa-c3933a1ee8b1.png)

## 孫コンポーネント Yに「::ng-deep」を適用してみる
最下層までさかのぼってlabelの色が全て緑になった。公式に書いてある通りの挙動を確認できた。
> 擬似クラス ::ng-deep を任意の CSS ルールに適用すると、そのルールに対するビューのカプセル化が 完全に無効になります。また、::ng-deep が適用されたすべてのスタイルは、グローバルなスタイルになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132584/f7a1146c-88a1-9747-8afd-df7c530260f9.png)

## 孫コンポーネント Yに「:host ::ng-deep」を適用してみる
公式の文章の続き。:host を追加するとそのコンポーネントにしか適用されないようになった。
> 指定されたスタイルを 現在のコンポーネントとそのすべての子孫に適用するには、必ず ::ng-deep の前に :host セレクターを含めるように してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132584/16d93b5f-0fff-e5a1-b85b-641449bf28a2.png)

## 子コンポーネント Aに「:host ::ng-deep」を適用してみる
`すべての子孫に適用する`とある。どういうことか確認するため、今度は子コンポーネントAに適用すると…
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132584/fc697f3b-b398-daa0-635b-c97e0e5025be.png)

このように孫コンポーネントXにも波及する。

## 孫に波及されると困る場合
と、このように「:host ::ng-deep」を使えば子孫までCSSを反映できる。Angular Materialなどのモジュールで生成されるUIに対してCSSを適用したい場合などに使うものと思う。

ただ、子コンポーネント内の子孫には反映してほしいけど、孫コンポーネントまで波及されると困る…という場合もあると思う。その場合は指定条件を増やせばよい。まぁこれはAngular のっていうか普通にCSS の基本だけど…普段意識してないと案外忘れがち。

例えば、`<label class="my-label">`というようにclass指定をすることで、孫には反映させない(※正確には、孫に"my-label"クラス指定を使わないことで適用外にする)ようにできる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132584/98e6709f-e097-9b81-6805-eb25c17dcef1.png)

## まとめ
* ::ng-deep はカプセル化を無視してグローバルなスタイルとして適用される
* :host ::ng-deep にすることで自分とその子孫へのスタイルとして適用される
* 子孫への影響を抑えたい場合は指定条件を厳しくしておく

## 2024/09/17 追記：ng-deep の代替について
リンクが死んでたので新しいドキュメントのリンク先に更新しました。ついでにng-deep の正式な代替案みたいなものが出てるか軽く調べたんですが、まだ活発に議論されてました。まぁAngular の`!important`みたいなもんだし、使わないのが一番だけど、じゃあこれが無くなったらどうすんねん！についてはまだ答えが出てない模様…
https://github.com/angular/angular/issues/25160
reazonspeech 日本語音声認識のメモ(v1.1 で良くなった!)

https://research.reazon.jp/projects/ReazonSpeech/index.html

Whisper large と同精度とあります.
v1.1 から長時間音声対応 + 認識精度よりよくなりました!

https://github.com/reazon-research/ReazonSpeech/releases/tag/v1.1.0

`$ reazonspeech input.mp3`

でかんたん認識できるようになりました!

恋する女子のときめきゅんあるあるテスト音声で試します!

```
{"start_seconds": 0.48, "end_seconds": 11.319, "text": "恋する女子のときめきゅんあるあるこっちかなこっちかなもう違う"} 
```

正解は 恋する女子のときめキュン、あるある　です. Whisper large での結果と合っています!

![Screenshot from 2023-01-18 20-08-10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36275/0ef97ecd-b21a-51c2-cb68-bb926839e03b.png)

```
...
{"start_seconds": 426.522, "end_seconds": 430.454, "text": "男性の方々にも女性が待ち合わせの前に"}
{"start_seconds": 430.454, "end_seconds": 437.313, "text": "入念に準備をしているところだったりとかあとデート中は実はすごくドキドキしていることが"}
{"start_seconds": 439.28, "end_seconds": 445.377, "text": "あったりもするのでそういったところもぜひ見ていただいて日頃女性がこういうふうにして"}
{"start_seconds": 445.377, "end_seconds": 451.714, "text": "自分たちの前で頑張ってくれているんだなみたいなことが伝わる内容になっていると思います"}
{"start_seconds": 451.714, "end_seconds": 454.546, "text": "ぜひ見ていただきたいと思います有村架純でした"}
```

470 秒最後までうまく認識してくれました.
最後きちんと「有村架純」になりました
(Whisper large だと有村香澄とかになったりする)

## model weight ダウンロード先

(reazonspeech のベースになっている) espnet では, モデルデータは huggingface の形式(?)に準拠しているようですが, モデルデータのダウンロード先は `~/.cache/huggingface` ではなく,

デフォルトだと

`<python folder>/lib/python3.10/site-packages/espnet_model_zoo/models--reazon-research--reazonspeech-espnet-next`

に保存されます.
miniconda を使っている場合は,

```
~/miniconda3/envs/<envname>/lib/python3.10/site-packages/espnet_model_zoo/models--reazon-research--reazonspeech-espnet-next`
```

になります.
weight サイズは v1 の 600MB くらいからは増えて, next では 800MB くらいでした.

## 改善必要点

おおむね whisper large と同じくらいの認識率でしたが,

```{"start_seconds": 33.333, "end_seconds": 38.993, "text": "おなかすいたなおおおなかすいたまだかなまだかな"}``` 

など多少文字が複製されたりがありました. 15 秒単位で処理しているようなので, その切れ目あたりに音声がかぶっているとうまくいかないのかもしれません. それでも whisper medium よりは認識はよいでした.

## CUDA 最適化はまだまだ...?

CUDA 12.1 なマシンで動かしたら torch tensor が CPU or device に無いよとか言われて実行エラーになりました.

reazonspeech の git+https で入るのだと espnet が古く,

https://github.com/espnet/espnet/blob/14701384c0e927356fc808e044fa71003e75778f/espnet/nets/batch_beam_search.py#L352

の `.cpu()` が抜けていていたためです.

ただ, espnet 側で `.cpu()` 付けて動かせるようにして処理速度はいまいちでした(3090 で 470 秒音声が認識 150 秒くらい). `nvidia-smi` で見ても稼働率は低いため, beam searh など, CPU で処理する部分に引っ張られて遅くなっているようです.
(ちなみに消費メモリは 4.4 GB でした)

そのうち改善されるかもはしれませんが, ESPNet 側でいろいろ対応しないといけないようなきもするので, とりあえずは CPU 実行でしょうかね.
whisper.cpp で reazonspeech モデル実行部分だけすり替えできるようになるとよりよいかもです.


## まとめ

CommonVoice などの人の声だけのテストデータに対してはそこそこいい感じで判定してくれる感じではありました.
モデルサイズは 800 MB くらいですので, Siri みたいなユースケースでスマホに組み込んで数秒単位の音声認識するのにも使えそう(whisper large も頑張ればいけるがちょっとつらい). お料理中に声で応答「お料理で豚こまが 50g 余った! 豚こま 50g でええ感じの明日のお弁当のおすすめ教えて!」と ChatGPT に問い合わせるとか!

より精度ほしいような, 議事録や, 映画とかなどのいろいろ雑音の入った音声データの文字起こしなどのユースケースでは, もうしばらくは Whisper large を使うのがよいでしょう.
そのうち ReazonSpeech が改善されて Whisper 置き換えもできるようになるでしょう
 
## TODO

* [ ]  rnnoise とかでの雑音除去をプリプロセスで入れてみる https://github.com/werman/noise-suppression-for-voice
* [ ] スマホに組み込んで使えるようにする(Whisper.cpp あたり使いモデル部分だけ改変でいけんかのう)
* [ ] wav2vec あたりと組み合わせ phoneme, 単語単位でのアラインメントにチャレンジ
マイクラチュートリアル5-1 コマンドブロック


コマンドブロック生成
```give @p command_block```


スポナー生成
```/give @p minecraft:mob_spawner 1 0 {BlockEntityTag: {SpawnCount:4,SpawnRange:4,MaxNearbyEntities:16,Delay:-20,MaxSpawnDelay:600, MinSpawnDelay:300,RequiredPlayerRange:16,EntityId:Zombie,SpawnData: {id:Zombie},SpawnPotentials:[{Type:Zombie,Weight:1,Properties:{}}]}}```
Github assistant で	[github assistant] Failed to push: [object Object] が出てしまう問題について

# 前提：GASとGithubを自動連携
Github assistantという拡張機能を使って、
GASのコードをGithubと連携させています

# 起きていたこと
Github assistantを用いてGithubへコードをプルしようと思ったができない
```
	[github assistant] Failed to push: [object Object]
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/968569/061ebaa2-59ae-bff9-c37c-cc12be27f3fa.png)

# 解決策：”//”のせいだった
ファイル名にコメントアウト（スラッシュ２本）を入れていたためダメだった模様
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/968569/4ee4e34e-6584-6cc7-9c6c-2bd294c41e49.png)
【GitHub】GitHub CodeSpacesについて調べてみた

# 出会い
ある日GitHubを歩いていたら。。。
私「なんか新着あるじゃん」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/173970/40b94728-dec3-956b-9ff5-ea86cf9065c4.png)

私「なんだこりわ・・・」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/173970/5030b606-5814-2b89-677c-17e0d28f5e6b.png)

気になったので調べてみました

:::note warn
いろいろ間違ったこと書いてるかもだけど許してニャン
:::

# Codespacesとは
公式を見たら書いてありますが、Githubが提供するWebIDEってイメージです。
高性能のVMに常に自分のリポジトリのコードとそれを使った環境が構築されているイメージ

# なにがいいの？
- リポジトリのCodeSpacesの対象にしたブランチに更新が入るたびに最新の環境構築済みのソースコードを触れる環境が用意されている
- 環境の準備や更新作業の手間を大幅に削減できる
※githubではクローンだけで45分かかっていたが5秒で構築済みの環境を触れるようになったみたい
- VSCodeなどと連携している
もともと使っているエディタから乗り換えたりしなくてよさそう
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/173970/9acaeab0-14dc-8b71-d9a3-6c09a399a7a9.png)

# 結論
現状は小規模開発なので、導入しなくてもいいかなと思いました。
より規模感が大きくなり開発環境構築のコストが増えたときに検討しようと思います。
個人でも利用できるっぽいので個人開発で試しに使ってみようかな

# 参考リンク
https://docs.github.com/ja/codespaces/overview
https://github.blog/jp/2021-08-30-githubs-engineering-team-moved-codespaces/
Xojo でデータベース接続パラメータを JSON 化してロードする

# 環境

- Xojo 2019 Ver3.2  (Web1.0 ベースの 旧Xojo)
- Webアプリ(スタンドアローン ないし デバッグ実行)
- Windows10 Pro 上でIDEを使用


# 方法

以下の2つの方法を試してみました。

- Xojo アプリのリソースに json ファイルを含める方法
- ファイル読み込みでメモリにロードする方法

# テストの json ファイル

dbaccess.json ファイル

```
{"host":"localhost","database":"test","user":"oreore","password":"hogehoge"}

```
# Xojo アプリのリソースに json ファイルを含める方法

dbaccess.json ファイルをContentsにドラッグ&ドロップします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/7f0f3fb1-22fb-e129-20af-ec241ed03581.png)

この状態で、以下のようにするとアクセスできます。

```
MessageBox dbaccess
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/233e3417-b73b-d542-af72-ec22c33c253d.png)



場所は WebPage1 の配下に置いても、あるいは Insert-Folder で、フォルダの中に含めても同様にアクセスできるようです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/31dde2a4-e5cb-c896-441a-a885e736dc19.png)

要素にアクセスするには以下のようにします。
```
dim j as new JSONItem(dbaccess)
dim host1 as string = j.value("host")
TextField1.Text=host1.ToText
```
コンパイル時、dbaccess.json ファイルは以下に含まれていました。

```
$ tree test
test
├── config.cfg
├── output.log
├── test
├── test Libs
│   ├── XojoConsoleFramework64.so
│   ├── libGZip64.so
│   ├── libRBCrypto64.so
│   ├── libRBInternetEncodings64.so
│   ├── libRBRegEx64.so
│   ├── libSSLSocket64.so
│   └── libc++.so.1
├── test Resources
│   ├── appicon128.png
│   ├── appicon256.png
│   ├── dbaccess.json
│   ├── favicon.ico
│   ├── favicon@2x.ico
│   ├── homescreen120.png
│   ├── homescreen152.png
│   ├── homescreen60.png
│   ├── homescreen76.png
│   └── ja.UTF-8
│       └── LC_MESSAGES
│           └── localizable.mo
└── test.cgi

4 directories, 21 files

```
# ファイル読み込みでメモリにロードする方法

デバッグなどにも共通して使える場所として、CurrentWorkingDirectory に置いた json ファイルを読み込むようにしました。

cf.,「Xojo Web アプリで CurrentWorkingDirectory を調べる」
https://qiita.com/nanbuwks/items/0d0aa59b8d555899deb6
```

Var jsonFile As TextInputStream
Var jsoncontents As String
var f,dir as Folderitem
dir = SpecialFolder.CurrentWorkingDirectory
f = dir.Child("dbaccess.json")
If Not( f.Exists ) Then
  MessageBox "dbaccess.json"+" が見つかりません。 "+dir.NativePath()+" にデータベースパラメータファイルを配置してください。"
else
  jsonFile = TextInputStream.Open(f)
  jsonFile.Encoding = Encodings.UTF8
  jsoncontents = jsonFile.ReadAll
  jsonFile.Close
  
  dim j as new JSONItem(jsoncontents)
  dim host as string = j.value("host")
  TextField1.Text=host.ToText
  
  MessageBox dbaccess
  dim j2 as new JSONItem(dbaccess)
  dim host2 as string = j.value("host")
  TextField1.Text=host2.ToText
End If
```
Databricks資格試験であなたのゴールを達成しましょう

[Achieve Your Goals With Databricks Certifications \- The Databricks Blog](https://www.databricks.com/blog/2023/01/05/achieve-your-goals-databricks-certifications.html)の翻訳です。

:::note warn
本書は抄訳であり内容の正確性を保証するものではありません。正確な内容に関しては原文を参照ください。
:::

**新年にキャリアアップしましょう！2023年にDatabricksの資格を取得して次のレベルに到達するためにDatabricksのイネーブルメントを活用して新年をスタートしましょう！**

技術的ロールへの需要は高まるばかりであり、[次の五年間で1.5億もの職が追加されるであろうことが予測](https://business.linkedin.com/talent-solutions/resources/talent-acquisition/jobs-on-the-rise-us)されています。業界や国に関係なく、これはデータや分析、AI関連のロールへの需要の増加と捉えることができます。実際、企業のお客様と会話する際、多くの方はデータやAIの導入において「スタッフのスキル」がトップの懸念事項であると述べています。

このスキルギャップを埋めるお手伝いをするために、Databricksではキーとなるデータ、分析、AIロールにおけるロールベースの様々な学習パスを提供しています。それぞれの学習パスは、学習者がレイクハウスプラットフォームの基礎を学ぶことができるLakehouse Fundamentalsからスタートします。データ、分析、AIの学習パスのそれぞれでは、学習者の知識をテストするための認定試験(簡単なクイズ、試験監督なし)や資格試験(試験、試験監督あり)があります。

![](https://cms.databricks.com/sites/default/files/inline-images/db-467-blog-img-1.png)
*Databricksのロールベースの学習パス*

# Databricksレイクハウス基礎

レイクハウスアーキテクチャは、急速にデータ、分析、AIにおける新たな業界標準になっています。以下のトピックを紹介するチュートリアル動画を含むDatabricks Lakehouse Fundamentalsでそのスピードに追従することができます:

- データレイクハウス
- Databricksのレイクハウスプラットフォーム
- Databricksレイクハウスプラットフォームのアーキテクチャとセキュリティ
- Databricksレイクハウスプラットフォームでサポートされるワークロード

クイズにパスすると、LinkedInやご自身のレジュメで共有できるLakehouse Fundamentals認定を獲得することができます。

![](https://cms.databricks.com/sites/default/files/inline-images/db-467-blog-img-2.jpg)
*LinkedInにおけるLakehouse Fundamentalsのバッジ*

# 限定オファー

新年にゴールを達成し、新たなスキルセットを学ぶお手伝いをするために、Databrikcsでは2023/1/31までに適正な**Lakehouse Fundamentals Accreditation**を取得した**すべての**Databricksユーザーの皆様に、以下の主要なDatabricks資格試験を受験するための **Databricks資格試験バウチャー($150相当)** を75%オフで提供できることを嬉しく思っています。

- Data Engineer Associate
- Data Engineer Professional
- Data Analyst Associate
- Machine Learning Associate
- Machine Learning Professional
- Associate Developer for Apache Spark 3.0 - Python
- Associate Developer for Apache Spark 3.0 - Scala

:::note
**注意**
認定試験にパスした際に使用した氏名、メールアドレス、認定の証明を用いて[こちらのサーベイ](https://databricks.sjc1.qualtrics.com/jfe/form/SV_dcEWYq4jzzuw9GC)を提出してください。
:::

# 何をすべきですか？

Databricksアカデミーで **Lakehouse Fundamentals Accreditation (V2)** を終了してください。

# 誰が登録できますか？

適正かつ期限が切れていないLakehouse Fundamentals認定を持つすべてのユーザーは$150のDatabricks資格試験バウチャー(75%のディスカウント)のリワードを申請することができます。[こちらのサーベイ](https://databricks.sjc1.qualtrics.com/jfe/form/SV_dcEWYq4jzzuw9GC)で証明を提出してください。

# デッドラインはいつですか？

2023/1/31までにサーベイに認定の証明を提出しなくてはなりません。

# いつバウチャーが送付されますか？

2月にバウチャーが送付されます。

# バウチャーの期限切れはいつですか？

バウチャーの期限は2023/7/1に切れます。この日より前に試験を予約して取得しなくてはなりません。


[Databricks Academy](https://www.databricks.com/learn/training/login)で **Lakehouse Fundamentals Accreditation (V2)** を修了し、[こちらのサーベイ](https://databricks.sjc1.qualtrics.com/jfe/form/SV_dcEWYq4jzzuw9GC)で証明を提出してください。すぐにキャリアアップしましょう！

### Databricks 無料トライアル

[Databricks 無料トライアル](https://databricks.com/jp/try-databricks)
エンジニアインターン4日目

今日はlpのテンプレート作成の続きを行った。テスト環境でデータベースから特定の情報を読み込み、その値を表示するという作業だった。そこで、データベースにもwordpressにもない値だった場合、データベースにはないが、wordpressにある場合、両方にある場合この３つの条件を設けてそれぞれに適切な値を入れる作業をした。まず、functionを作り、issetを使って値があるかを調べた。引数が多くなり、他の場所に引用することがめんどうになってしまった。そこで、先輩エンジニアからjsonを使ったら便利と言われた。jsonで配列をつくり、functionの引数にした。jsonを使えば容量も軽いし、別の場所に引用するのも簡単にできるとのことだった。自分はjsonを詳しく知らなかった。先輩エンジニアはweb開発の時はjsonをとても多く使うとのことだった。直接コードも見せていただき利便性を確かめることができた。今日隣で業務委託のエンジニアさんとのミーティングが聞こえてきた。社員のエンジニアさんは業務委託のエンジニアに難しそうなことを要求していた。レベルの高い話で、いずれかは自分もそのような話し合いができるようになりたいと思った。その反面今自分はまだ大学1年でできないことばかりである。自分をインターンとして採用していただけた理由は大学1年ということもあり、将来性に期待していただいたと思う。だから、今現在の自分にはあまり期待はしていないだろう。この[あまり期待されてない]ことをうまく利用する必要がある。たくさん失敗してたくさん学習しよ。それがインターンの特権でもあるし、学生の特権である。この環境に感謝しながら努力し続けよ。それがいま自分ができること。
ブラウザのみでDot言語をSVGや画像に変換する【Javascript】

# 概要
有向や無向グラフを書くのに優れた`Dot言語`。しかし、これを視覚化するには`Graphviz`というソフトをインストールしなければなりません。それって、面倒くさいですよね？

ということで、JavaScriptで`Graphviz`と同じ動きができる`Viz.js`を使って、ブラウザのみで`Dot言語`を視覚化する関数を作りました。

**余談**
すぐにでも`Dot言語`を図に起こしたい人は、次の`Viz.js`公式サイトへ。マークダウンエディタで、視覚化できます。便利！

http://viz-js.com/

# ソースコード
大まかには、Dot言語をSVGに→SVGをcanvasに→canvasをimg画像に、という流れで変換します。
```HTML
<body>
<img id="graph">
<script type="text/javascript" src="https://unpkg.com/viz.js@1.8.0"></script>
</body>
```

```JavaScript
// dot言語をSVGに変換する関数
function dotToSVGElement(dot) {
	const container = document.createElement("div");
	container.innerHTML = Viz(dot, {format: "svg"});
	return container.querySelector("svg");
}

// SVGをpng画像に変換する関数
function SVGElementToPng(output, svg) {
	const image = new Image();
	image.addEventListener("load", () => {
		const width = svg.getAttribute("width");
		const height = svg.getAttribute("height");
		const canvas = document.createElement("canvas");
		
		canvas.width = image.naturalWidth;
		canvas.height = image.naturalHeight;
		
		const context = canvas.getContext("2d");
		context.drawImage(image, 0, 0, image.naturalWidth, image.naturalHeight);
		const dataUrl = canvas.toDataURL("image/png");
		output.src = dataUrl;
	});
	
	const svgData = new XMLSerializer().serializeToString(svg);
	const svgDataBase64 = btoa(unescape(encodeURIComponent(svgData)));
	const svgDataUrl = `data:image/svg+xml;charset=utf-8;base64,${svgDataBase64}`;
	image.src = svgDataUrl;
}

// dot言語をpng画像に変換する関数
function dotToPng(dot) {
	const output = document.getElementById("graph");// img
	const svg = dotToSVGElement(dot);
	SVGElementToPng(output, svg);
}

const graph = `graph G {A--B;B--C}`;
dotToPng(graph);
```

### 参考資料

https://qiita.com/basho/items/431af27b2fc6e90c9469

https://zenn.dev/tatsuyasusukida/articles/javascript-svg-png
DateOnlyをJsonSerializer.Serializeするとエラーになる

# .Net6から導入されたDateOnlyはそのままではJsonSerializer.Serialize出来ない
## 対処法
対応は２点
* Serialize時にDateOnlyを出力するコンバーターを用意

```DateOnlyConverter.cs
public class DateOnlyConverter : JsonConverter<DateOnly>
{
    private readonly string serializationFormat;

    public DateOnlyConverter() : this(null)
    {
    }

    public DateOnlyConverter(string? serializationFormat)
    {
        this.serializationFormat = serializationFormat ?? "yyyy-MM-dd";
    }

    public override DateOnly Read(ref Utf8JsonReader reader, 
                            Type typeToConvert, JsonSerializerOptions options)
    {
        var value = reader.GetString();
        return DateOnly.Parse(value!);
    }

    public override void Write(Utf8JsonWriter writer, DateOnly value, 
                                        JsonSerializerOptions options)
        => writer.WriteStringValue(value.ToString(serializationFormat));
}
```

* JsonSerializer.Serializeにオプションを指定する

```
    var options = new JsonSerializerOptions(JsonSerializerDefaults.Web);
    options.Converters.Add(new DateOnlyConverter());//<-ここでコンバータをセットする

    var json = JsonSerializer.Serialize( {オブジェクト}, options);
```


# TimeOnlyは
このようなコンバータを作るといいそうです（未確認）

```TimeOnlyConverter.cs
public class TimeOnlyConverter : JsonConverter<TimeOnly>
{
    private readonly string serializationFormat;

    public TimeOnlyConverter() : this(null)
    {
    }

    public TimeOnlyConverter(string? serializationFormat)
    {
        this.serializationFormat = serializationFormat ?? "HH:mm:ss.fff";
    }

    public override TimeOnly Read(ref Utf8JsonReader reader, 
                            Type typeToConvert, JsonSerializerOptions options)
    {
        var value = reader.GetString();
        return TimeOnly.Parse(value!);
    }

    public override void Write(Utf8JsonWriter writer, TimeOnly value, 
                                        JsonSerializerOptions options)
        => writer.WriteStringValue(value.ToString(serializationFormat));
}
```

参考ページ[こちら](https://marcominerva.wordpress.com/2021/11/22/dateonly-and-timeonly-support-with-system-text-json/)

.Net6にDateOnlyが入ったんならシリアライザーもちゃんと出力してほしいものです。

ちなみに、WebAPIの引数でDateOnlyを使う場合は[こちら](https://qiita.com/nacopon/items/10977d516e2a79b8dcc3)を参照ください
Unityの当たり判定がすり抜ける時の対処方法！

Unityでゲームを作る時に、
RigidbodyやColliderは付いてるのに
衝突してほしいオブジェクトがなぜかすり抜けてしまうことってありませんか？




今回はそんな時の対処方法について紹介していきます！


# Unityでコライダーがすり抜ける原因

RigidbodyやColliderは付いてるのに
オブジェクトが他のオブジェクトに当たらずに、
すり抜けてしまう原因は

オブジェクトの移動速度が速い可能性が高いです。

## Unityでコライダーがすり抜ける対処方法

ではどのように対処すればいいのか、
2つほど解説していきます。

### 1:オブジェクトの移動速度を落とす

最も簡単な対処方法の一つです。

ただしゲームの表現や、
やりたいことが再現できなくなるため、
この手段はとれることが少ないと思います。

### 2:RigidbodyのCollision Detectionの設定を変更する

次の対処方法としてRigidbodyのCollision Detectionの設定を変える方法があります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/541829/440ac8f4-f83e-4478-3d10-3091147d8759.png)

設定を変えるだけですり抜ける現象を防ぐことができますが、一つ注意が必要です。
下記の順番で処理が重くなっていきます。

Discrete：一番処理が軽い。オブジェクトの移動速度が遅い場合に用いる。
Continuous：ぶつかる相手がRigidbodyコンポーネントを持っていない。尚且つ動かないオブジェクトの時に用いる
Continuous Speculative：お互いが動くオブジェクトで、移動速度が速いときに用いる。※誤検知がある
Continuous Dynamic：お互いが動くオブジェクトで、移動速度が速いときに用いる。

なので自分が作るゲームに合わせて
設定を変更して行ってください。


## YouTubeチャンネル

ゲーム雑学や、具体的なゲーム開発方法まで紹介しているチャンネルを運営しています！

https://www.youtube.com/channel/UCVMfSecoP77yIh1a1O-7Wjg

## 参照記事
Collision Detectionについて
もっと詳しく知りたい方は下記記事をご覧ください。

https://virtualcast.jp/blog/2020/05/collisiondetectionchart/
CustomMessage内でCustomMessageを呼び出す

# CustomMessageとは
http://wiki.ros.org/ja/ROS/Tutorials/DefiningCustomMessages

# ディレクトリ構成
```
- ws
  - src
    - package
      - msg
        - A.msg
        - B.msg
```
# message
- B.msg内でA.msgを呼び出す
```php:A.msg
string route
float32 velocity
```
```php:B.msg
package/A a
time time
```

## 補足
- std_msgs等に定義を追加する必要があるのかと悩んだのがきっかけ
- 一般的なプログラムと同様に指定すれば呼び出しできる
【PHPUnit】assertSameとassertEqualsを正しく使い分ける

## はじめに
今回の記事はassertSameとassertEqualsの使い分けについてです。何気なくassertSameを使用していて、意図しないエラーに遭遇したので、忘れないよう記事にします

## 状況と発生したエラー内容
今回のエラーは下記テストを実行した際に出力されました。ユーザーリポジトリのfindById（ユーザーIDを指定すると対象のユーザーを取得できるメソッド）のテストです。存在するユーザーIDを渡すとユーザーを1件取得できることを確認しています

また、`assertUser`メソッドでは、オブジェクトの属性値が期待するオブジェクトと、実際のオブジェクトで等しいかどうかを評価しています
```php
    public function test_存在するユーザーIDを渡すとユーザーを1件取得できること(): void
    {
        // given
        $expectedUser = $this->user;

        // when
        $actualUser = $this->userRepository->findById($expectedUser->getUserId());

        // then
        $this->assertUser($expectedUser, $actualUser);
    }

    private function assertUser(Uesr $expectedUser, Uesr $actualUser): void
    {
        $this->assertSame($expectedUser->getUserId(), $actualUser->getUserId());
        $this->assertSame($expectedUser->getName(), $actualUser->getName());
        $this->assertSame($expectedUser->getEmail(), $actualUser->getEmail());
    }
```
実行すると、以下のようなエラーが出力されました

**実行結果：**

```
Failed asserting that two variables reference the same object.

Time: 00:01.875, Memory: 22.00 MB

FAILURES!
ERROR: 1
```
なぜこのようなエラーが起こったのでしょうか？

## assertSame は「オブジェクトの属性値が同じ」という意味ではない
assertSameは **「オブジェクト同士を比較する場合、その2つのオブジェクトが同じオブジェクトを参照しているかどうか」** ということを評価します

なので、上記のコードは同じオブジェクトを参照しているわけではないので、エラーが表示されているのです

詳しくはこちらに記載してあります
https://phpunit.de/manual/3.6/ja/writing-tests-for-phpunit.html

では、オブジェクトの属性値を比較する際はどのメソッドを使用すればいいのか？

## オブジェクトの属性値を比較する際は assertEquals を使う
オブジェクトの属性値を比較する際は **assertEquals** を使用します。このメソッドは2 つのオブジェクト `$expected` と `$actual` が同じ属性値を持たない場合にエラーを出力します

なので、下記コードのようにassertSameをasssertEqualsに変更すると正しく評価されるようになります

```diff_php
    public function test_存在するユーザーIDを渡すとユーザーを1件取得できること(): void
    {
        // given
        $expectedUser = $this->user;

        // when
        $actualUser = $this->userRepository->findById($expectedUser->getUserId());

        // then
        $this->assertUser($expectedUser, $actualUser);
    }

    private function assertUser(Uesr $expectedUser, Uesr $actualUser): void
    {
-       $this->assertSame($expectedUser->getUserId(), $actualUser->getUserId());
-       $this->assertSame($expectedUser->getName(), $actualUser->getName());
-       $this->assertSame($expectedUser->getEmail(), $actualUser->getEmail());
+       $this->assertEquals($expectedUser->getUserId(), $actualUser->getUserId());
+       $this->assertEquals($expectedUser->getName(), $actualUser->getName());
+       $this->assertEquals($expectedUser->getEmail(), $actualUser->getEmail());
    }
```
一応実行結果としては、以下の通りです

**実行結果：**
```
Testing started at 18:33 ...

Time: 00:01.734, Memory: 22.00 MB

OK (1 test, 1 assertion)
```

## おわりに
「assertSameとassertEqualsの使い分け」についての説明は以上です。何かご指摘等あればコメント等で教えていただけると大変嬉しいです