OmniAICreator/Qiita-1.07M huggingface dataset:
Azure SQL Databaseに接続するWebアプリをデプロイする際はODBCの設定を忘れずに

# 背景
作成したアプリが追加実装でDBと接続することになったが、デプロイしたところエラーが発生。
Dockerfileに追加で設定が必要とのこと。

App Serviceにデプロイするところまでは以下の記事の方法でできます。

https://qiita.com/flutter_daisuki/items/a9996a11eae00b6b2ddf

# Dockerfileを修正

https://learn.microsoft.com/ja-jp/sql/linux/sql-server-linux-setup-tools?view=sql-server-ver16&tabs=ubuntu-install

こちらに記載されてる内容をDockerfileに追記する必要がある。
確かにローカルで実装する時に導入したodbcドライバーをApp Serviceの環境にも入れなければいけないのに、どこにも記載してなかった...

```Dockerfile
FROM python:3.9

WORKDIR /code

COPY requirements.txt .

RUN apt-get update && apt-get -y upgrade

# 以下を追記
RUN curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add -
RUN curl https://packages.microsoft.com/config/ubuntu/22.04/prod.list > /etc/apt/sources.list.d/mssql-release.list

RUN apt-get update

RUN ACCEPT_EULA=Y apt-get install -y msodbcsql18 && \
    ACCEPT_EULA=Y apt-get install -y mssql-tools18 unixodbc-dev

RUN echo 'export PATH="$PATH:/opt/mssql-tools18/bin"' >> ~/.bashrc && \
    . ~/.bashrc

RUN pip install --no-cache-dir --upgrade -r requirements.txt

COPY . .

EXPOSE 3100

CMD ["gunicorn", "main:app"]
```

# 最後に
Pipelineではデプロイが成功してるのに、Webアプリを立ち上げると503エラーが発生してたので気づくまで時間がかかりました。
ログストリームには「odbcがありません」と記載されてるので、ログストリームをちゃんと確認しよう。
Ubuntu: /etc/rc?.d の状況を確認する

/etc/rc **N** .d の状況を表示するだけの簡単なスクリプトです。

```python:list-rc.d
#!/usr/bin/env python3

import argparse
import os
import sys


def is_ixusr(path):
    fst = os.stat(path)
    return bool(os.path.stat.S_ISREG(fst.st_mode) and
                fst.st_mode & os.path.stat.S_IXUSR)


def listdirex(path):
    return list(filter(is_ixusr, (f'{path}/{e}' for e in os.listdir(path))))


def list_init_d(init_level, etcdir):
    service = {f: [] for f in listdirex(f'{etcdir}/init.d')}
    flist = ([os.path.realpath(f), [l, f]]
             for l in init_level for f in listdirex(f'{etcdir}/rc{l}.d'))
    for real, (level, link) in filter(lambda d: d[0] in service, flist):
        service[real].append([level, os.path.basename(link)])
    return tuple(sorted((os.path.basename(name), tuple(sorted(mode)))
                        for name, mode in service.items()))


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('-v', '--verbose', action='store_true', default=False)
    parser.add_argument('-e', '--etc', metavar='DIR', dest='etc_dir', default='/etc')
    parser.add_argument('-l', '--level', metavar='INIT', default='0123456S')
    parser.add_argument('services', metavar='service', nargs='*')
    args = parser.parse_args()

    verbose = args.verbose
    init_level = args.level
    etc_dir = args.etc_dir
    services = args.services

    init_list = list_init_d(init_level, etc_dir)
    initd = init_list if not services else tuple(
        d for d in init_list if d[0] in services)
    wname = max([0, *[len(n) for n, _ in initd]])
    padding = ' ' * wname
    for name, mode in initd:
        mon = {l: 'off' for l in init_level}
        mon |= {l[0]: 'on ' for l in filter(
            lambda s: s[1][0] == 'S', mode)}
        mon = '  '.join(f'{k}:{mon[k]}' for k in init_level)
        print(f'{(name+padding)[:wname]}  {mon}')
        if verbose:
            msg = '\n'.join(f'{padding}    rc{l}.d/{f}'
                            for l, f in mode if l in init_level)
            print(msg + '\n' if msg else '')


main()
```

```console:実行結果
$ list-rc.d postfix kmod
kmod     0:off  1:off  2:off  3:off  4:off  5:off  6:off  S:on 
postfix  0:off  1:off  2:on   3:on   4:on   5:on   6:off  S:off
$ list-rc.d postfix kmod -v
kmod     0:off  1:off  2:off  3:off  4:off  5:off  6:off  S:on 
           rcS.d/S01kmod

postfix  0:off  1:off  2:on   3:on   4:on   5:on   6:off  S:off
           rc0.d/K01postfix
           rc1.d/K01postfix
           rc2.d/S01postfix
           rc3.d/S01postfix
           rc4.d/S01postfix
           rc5.d/S01postfix
           rc6.d/K01postfix
```
Okta - Access Testing Tool

# はじめに

今回は Access Testing Tool について記載していきます。

このツールは以下のようなケースで利用すると便利です。
- 新しいサインオンポリシーを作成した後の動作確認
- ユーザーからOktaにサインオンできないと問い合わせがあったときの設定確認


# Access Testing Tool

Access Testing Tool では、以下の要素を指定してサインオンの認証フローをテストすることが可能です。

- アクセス先のApplication
- サインオンユーザー
- 利用デバイスのOkta登録状態
- デバイスのOS種別
- 接続元IPアドレス
- リスク

# 使い方

ダッシュボードに拠点外のIP（適当に設定）からサインインできるかどうかを確認してみます。

Application に Okta Dashboard を指定し、Username と IP address を入力したら Run test から実行します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/350435/f7194a48-255c-4111-b9ff-6491038b0bde.png)

サインオンに成功する場合、以下のような結果が表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/350435/98e20e33-a578-289f-45b4-0fe8c7f6cd1a.png)

また、どのGlobal Session Policy、Authentication Policy で評価されたかを確認することができます。

以下のスクショでは、
- Global Session Policy
    - 黒塗りになっているポリシー
    - [許可]通常というルール
- Authentication Policy
    - Okta Dashboardというポリシー
    - [許可]MFAありというルール
にマッチしてサインオンできることがわかります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/350435/c40475ae-42aa-8a25-0949-da2538e96eea.png)


# 捕捉

## サインオンに失敗する場合の結果表示

こんな感じで表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/350435/e9f2b351-08ea-cb6c-3604-ae84d9827f74.png)

## 指定要素の変更

ユーザーやIPアドレスの指定は、それぞれ Specify group instead や Specify network zone instead を選択することでグループやネットワークゾーンの指定に変更することができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/350435/45304d38-841d-a7dc-314e-551048c47da5.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/350435/639a0814-56fb-7713-10d5-17f56fe5980c.png)


# さいごに

Access Testing Tool は簡単に使えますが結構便利なので是非使ってみてください。
今回はここまで。ありがとうございました。
EC-CUBE 4.3 の開発状況について

先日EC-CUBEの4.2.3がリリースされたばかりですが、EC-CUBEの次のメジャーバージョンである4.3についても、今後のリリースに備えて各種ミドルウェアやフレームワークのサポート状況を調査していってます。ざっくり現状把握している情報を共有できればと思います。

## システム要件について

PHPについては、Symfony6が8.1〜となる関係上、8.1以上がシステム要件となります。
リリース時点では8.1~8.3がカバー範囲となるかと思われます。

DBについてはMySQLが8〜、PostgresSQLが12〜となる見込みです。

## フレームワークやライブラリのバージョンについて

### Symfony

Symfonyは次のLTSである6.4が採用されます。
マイナーバージョンが上がる関係上、互換性のない変更がある程度発生します。Securityコンポーネント周りが比較的影響が大きい変更になるかと思われます。
https://github.com/symfony/symfony/blob/6.4/UPGRADE-6.0.md

### Doctrine

Doctrin/ORMは、v3が開発中ということで動向をウォッチしていましたが、v2が継続して保守されるということになります。v2を継続して採用する見込みで、大きな変更はなさそうです。
https://www.doctrine-project.org/2023/10/11/orm3-beta1-dbal4-rc1-future-plans.html

### Twig

現行ではv2を利用していますが、2023年末で保守が終了されるということで、v3への移行を予定しています。

https://github.com/twigphp/Twig/tree/2.x
> Twig version 2 end of maintainance is scheduled for end of December 2023. Please, upgrade at your earliest convenience.

### JS/CSS

BootstarpやjQueryなどのJavascriptライブラリについては、マイナーバージョンアップの範囲でアップデートされます。JS/CSSに関しては大きな変更はなさそうです。

## プラグインの互換性について

Symfonyが5から6にバージョンアップする関係上、ある程度互換性のない変更が発生しますが、可能な限り互換性を維持できるように対応を進める予定です。EC-CUBE上でどれだけ互換性を担保できるかは、実際にSymfony6へのバージョンアップを行いながら、これから調査していくことになります。

情報については、GitHubのIssueで随時公開していきますので、こちらをウォッチしていただければと思います。

https://github.com/EC-CUBE/ec-cube/issues/6069
youtube-dlを利用した動画ダウンローダーを作成したので紹介

# はじめに

Pythonの`youtube-dl`というライブラリを使用して、簡単にYoutubeなどの動画や音声をダウンロードおよび変換できるツールを作成したので紹介します。

https://github.com/MURAMASA2470/youtube_downloads

# youtube-dlとは

youtube-dlは、Python製のコマンドラインツールで、様々な動画共有サイトから動画や音声をダウンロードするためのツールです。YouTubeだけでなく、多くのサポートされているサイトからメディアをダウンロードすることができます。

### 公式リポジトリ
https://github.com/ytdl-org/youtube-dl

### サポートされている世界中のメディアサイト
https://ytdl-org.github.io/youtube-dl/supportedsites.html


# 使い方

## 環境

- Python 3.x

Python3以上で動作します。2系では動作しない為、バージョンアップしてください。

## インストール

当ツールでは以下のライブラリを使用します。

- youtube_dl
- ffmpeg
- ffmpeg-python

```bash
python -m pip install youtube_dl ffmpeg ffmpeg-python
```

## 実行

```bash
python ./ydl.py
> フォーマット(mp3またはmp4): "ここに変換したいフォーマットを入力"
> URL: "ここにダウンロードしたいURLを入力"
```

## オプション

```bash
usage: ydl.py [-h] [-f FORMAT] [-u URI] [-l LIST]

  -h, --help           : ヘルプメッセージを表示して終了

  -f, --format Format  : ダウンロードするファイルフォーマットを選択 (mp3またはmp4)。

  -u, --uri URI        : ダウンロードするメディアのURIを指定。

  -l, --list LIST      : URLリストのためのテキストファイルを指定。
                         リスト内のURLから一括でリソースをダウンロード。
```

# ダウンロード速度が遅い場合の対処法

Youtube側のアップデートにより、ダウンロード速度が著しく低下するときがあります。
youtube-dlのリポジトリのリリースされたものでは、更新が追い付かない為、`master`ブランチの最新を取得し、インストールすることで、速度を改善できることがあります。
※それでも改善されない場合は、対応するまで待ちましょう。

## MacおよびLinuxの場合

```bash
# gitから最新のコミットのSHAハッシュを取得

hash=$(git ls-remote https://github.com/ytdl-org/youtube-dl.git | head -n 1 | cut -c 1-40)

wget https://github.com/ytdl-org/youtube-dl/archive/$hash.zip

unzip -n $hash.zip && cd youtube-dl-$hash

python -m pip uninstall -y youtube_dl && python -m pip install .

cd .. && rm -r youtube-dl-$hash

```

## Windowsの場合

```bash
# gitから最新のコミットのSHAハッシュを取得

$hash=$(git ls-remote https://github.com/ytdl-org/youtube-dl.git | Select-Object -First 1).Substring(0, 40)

Invoke-WebRequest -Uri https://github.com/ytdl-org/youtube-dl/archive/$hash.zip -outfile ./youtube-dl-$hash.zip

Expand-Archive -Path .\youtube-dl-$hash.zip -DestinationPath ./ ; cd youtube-dl-$hash

python -m pip uninstall -y youtube_dl ; python -m pip install .

cd .. ; rm -r youtube-dl-$hash


```
Python環境のテンプレを作った話

株式会社ブレインパッドで機械学習エンジニアをしている新卒のえーちゃんです。

この記事は[BrainPad Advent Calender 2023](https://qiita.com/advent-calendar/2023/brainpad) 10日目の記事です。

# はじめに
環境構築ってめんどくさいですよね。
はい、ということでテンプレ作りました。
完成品は[こちら](https://github.com/YutaEiki-BP/python-template)になります。

# 全体像の説明
DevContainerと呼ばれるVSCodeの機能をベースに
- poetry (ライブラリ管理)
- ruff (リンタ&フォーマッタ)
- pytest, pre-commit

などを導入した環境です。

テンプレを使うとこのような感じですぐに開発を始めることができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627810/4e6b7876-e661-efee-d74b-7ab06dd843aa.png)


## どんな人向け?
- 環境構築分からんデータサイエンティスト
- 爆速でPoCを開始したい機械学習エンジニア

## 何ができる?
- プロジェクトごとに環境を分けることができる
- メンバーと環境を共有することができる
- コードの品質を保つことができる

# 使い方
## 1. 環境の導入
```console
git clone https://github.com/YutaEiki-BP/python-template.git [フォルダ名]
```
フォルダ名を適宜置き換えて上記のコマンドを実行すると、テンプレを含んだフォルダができます。
このままだとテンプレのgitが残っているので一旦以下のコマンドで削除します。
```console
cd [フォルダ名]
rm -rf .git
```
gitを使いたい場合は上記のコマンドに続けて以下のコマンドを実行してください。
```console
git init
```

## 2. 環境の起動
先ほど作成したフォルダをVSCodeで開きます。
すると画像のように「コンテナで再度開く」と表示されるのでクリックしてください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627810/b846de73-bad8-4c87-d31f-610bff11239f.png)

しばらく待って左下が開発コンテナーとなったら起動成功です！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627810/c50df0aa-2862-0b4c-8350-0cc88f5a6e80.png)

# 機能の説明
各ツールの詳細な説明はいずれ別記事で書きたいと思います。
ここでは簡単な説明だけ行います。

## Pythonライブラリの管理
Pythonライブラリの管理には[poetry](https://python-poetry.org/)を使用しています。
ライブラリを追加したい場合はCmd + Shift + \` (Windowsの場合はCtrl + Shift + \`)でターミナルを開き
```
poetry add [ライブラリ名]
```
とすることでライブラリを追加することができます。

## コードの自動フォーマット
リンター&フォーマッターには[ruff](https://docs.astral.sh/ruff/)を使用しています。
ファイル保存時に自動でコード検査&フォーマットを走らせることでコードの品質を保ちます。

## コミット時のチェック
コミットの際には[pre-commit](https://pre-commit.com/)による自動チェックが行われます。
これによってリポジトリ全体の品質を保ちます。
- コードのチェック (ruff)
- 型のチェック (mypy)

などが行われますが、このほかにもチェックを追加することが可能です。

## テスト
テスト用ツールとして[pytest](https://docs.pytest.org/en/7.4.x/)を導入しています。
設定済みのためすぐにテストを開始することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627810/4246609d-cc3b-9fdc-5a34-0553fcc28bdb.png)

## Git履歴の可視化
VSCodeの拡張機能の[GitGraph](https://marketplace.visualstudio.com/items?itemName=mhutchie.git-graph)を導入しています。
開発の際にはすごく便利です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627810/c2f1d1cd-f34e-b6ca-9ad3-27abf07330e8.png)

# さいごに
今回はPython環境のテンプレを作った話でした。
短い経験ではありますが役に立ったプラクティスを盛り込んでますのでぜひ一度お試しください。
この記事では触れていませんが環境構築の思考プロセスなど追々話していければなと思います。
また、需要があればカスタマイズの方法なども今後記事化するつもりです。

[テンプレ](https://github.com/YutaEiki-BP/python-template)の改善要求・提案等もお待ちしております。

お問い合わせについてはyuta.eiki@brainpad.co.jpまでお願いします。
Unity無料アセット URP Stylized Water Shaderの使い方

## まえがき

無料で使える水のシェーダーを見つけたのですが、説明が英語だったので、メモを残しておきます。

https://assetstore.unity.com/packages/vfx/shaders/urp-stylized-water-shader-proto-series-187485

### GameObjectの作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3638306/115d0d89-2b46-1c7e-df53-455f2408d081.png)

新しいゲームオブジェクトを作る。ここでは公式の動画に則り、WaterVolumeとする。他の設定のテストに使ったのでピアノが置いてあるけど、そこは気にしないで... 

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3638306/a457b313-3112-4f83-9adc-456339c0d821.png)

作成したオブジェクトにMesh RendererとWater Volume(Transform)を追加。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3638306/8d298125-6cc4-fc31-18a5-a2167ad2d197.png)

Materialsにexample-water-01を追加。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3638306/81c349c9-1c0e-2065-a6d6-a5afae71ab16.png)

更に、Watrer Volume(transform)のTize Sizeを変更。小さくするとメッシュのサイズが小さくなり、綺麗になるが、処理は重たくなる。ここでは公式の解説と同じ0.5に設定。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3638306/cd3bcce8-04c3-5f11-a7ec-ddddd49a8f34.png)

WaterVolumeの子オブジェクトとしてGameObjectを作成すると、画面に水の塊が現れた！！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3638306/9b0d570d-8557-36c5-b567-b074412053f9.png)

ここで子オブジェクトの拡大率を変えると広が... らないね。
初期状態ではリアルタイムで描画されてないみたい。親オブジェクトの大きさを変更すれば変わるけど、これは崩れるのでやってはいけない。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3638306/2635dc71-f893-a7b0-fccb-fff4a4069373.png)

Realtime Updatesにチェックを入れると、以下のように大きくすることができた。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3638306/f18bc1fc-d796-a72f-802d-a8a64645b7b9.png)

## 浮くオブジェクト

https://youtu.be/fHuN7WkrmsI?si=46-0Lg3lY8L1in3s&t=102

この動画の1:40で浮いているオブジェクトに便利だよ～って話をしてると思うけど、私は使わないのでざっくりと。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3638306/8ff0a730-612f-f432-b508-5f13f306a744.png)

ヒエラルキーからSphere（球）を作成し、Water Volume Floaterを追加。Water Volumeの子オブジェクトではない。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3638306/44c4f8d5-87f4-4601-a475-43104540d007.png)

Water Volume（オブジェクト）にWater Volume Helperを追加して、Water Volumeの欄にWater Volume（上のコンポーネント）を放り込む。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3638306/f14ae801-0e8d-5693-c994-d7d6b4c549fe.png)

実行したら、確かに球がゆらゆらと揺れている。でも沈んじゃった... 
よく分からないので放置。今のところ使わないので

## 水のスタイル

入っているマテリアルは以下の3つ。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3638306/03c5207f-8987-2b33-7b60-e19155b2d7c4.png)
exalmple-water-01

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3638306/98550b74-bcac-edd4-861b-dab0951c224e.png)
exalmple-water-02

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3638306/6d752bca-2c67-8d24-2b46-09d001cba20a.png)
exalmple-water-03

新規のマテリアルを作成して、パラメータを変更すればより自由に水を作ることができる。

ここで、私の用途では使えないことに気付いた。
Pythonでコンプガチャの期待値を求める

# 概要

マクドナルドでとあるキャンペーンを行うようです。

**マクドナルドのハッピーセット「ハローキティ50周年」**
- 第1弾 12月15日(金)～12月21日(木)　キティのぬいぐるみ**25種**
- 第2弾 12月22日(金)～12月28日(木)　キティのぬいぐるみ**25種**
- 第3弾 12月29日(金)～　　　　　　　第1弾・第2弾で登場した全**50種**

https://www.mcdonalds.co.jp/company/news/2023/1207a/


50種全部ほしいのですが、どうやらランダムっぽいです。
そこで、コンプできる回数の期待値はどうなるか、気になってしまったので、コンプガチャと見立てて、Pythonでプログラムを作成していこうと思います。



# コンプガチャの期待値を計算

まず前提として、確率は全部均等とします。また、順番も完全ランダムとします。


コンプガチャの期待値を求める式は以下の通りです。

```math
コンプガチャ期待値=n\sum_{k=1}^{n} \frac{1}{k}
```

$\sum$（シグマ）に抵抗がある方もいると思いますが、分かりやすい式に書き換えると以下の通りです。



```math
コンプガチャ期待値=n×(1 + \frac{1}{2} + \frac{1}{3} +⋯+ \frac{1}{n})
```

Pythonで書くとこんな感じです。

```python3
def comp_gacha(n: int) -> float:
    '''
    ガチャをコンプするまでの期待値を求める
    Args:
      n (int): ガチャで当たる商品の種類数
    Returns:
      float: コンプまでの期待値
    '''
    sum = 0.0
    for i in range(1, n + 1):
        sum += 1 / i
    return n * sum
```

さらに、内包表記を使って書くと1行で済みます。($\sum$もたいしたことないですね)

 ```python3
def comp_gacha(n: int) -> float:
    '''
    ガチャをコンプするまでの期待値を求める
    Args:
      n (int): ガチャで当たる商品の種類数
    Returns:
      float: コンプまでの期待値
    '''
    return  n * sum(1 / (i + 1) for i in range(n))
```

実行結果は以下の通りです。
25個の期待値が95.4回なので、第1弾と第2弾を合計すると**190.8回**。
第3弾だけでは、**224.96回** 必要なので、全部集めるなら第1弾と第2弾で集めきったほうが良さそうです。

|ガチャで当たる商品の種類数|コンプまでの期待値|
|-:|-:|
|1個|1回|
|2個|3回|
|3個|5.5回|
|4個|6.33回|
|5個|11.42回|
|10個|29.29回|
|25個|95.4回|
|50個|224.96回|

# matplotlibを使ってグラフを表示

`matplotlib`を使って、ガチャの個数毎の期待値をグラフで表示します。

```python3
import matplotlib.pyplot as plt

def comp_gacha(n: int) -> float:
    '''
    ガチャをコンプするまでの期待値を求める
    Args:
      n (int): ガチャで当たる商品の種類数
    Returns:
      float: コンプまでの期待値
    '''
    return  n * sum(1 / (i + 1) for i in range(n))

def plot_comp_gacha(n: int):
    '''
    ガチャをコンプするまでの期待値をグラフで表示
    Args:
      n (int): ガチャで当たる商品の種類数
    '''
    x = list(range(1, n + 1))
    y = [comp_gacha(i) for i in range(1, n + 1)]

    plt.plot(x, y, 'ro', color='forestgreen')
    plt.plot(x, y, color='forestgreen')
    plt.xlabel("ガチャで当たる商品の種類数", fontsize=18, fontname='MS Gothic')
    plt.ylabel("コンプまでの期待値", fontsize=18, fontname='MS Gothic')
    plt.grid()
    plt.show()

n = 50
plot_comp_gacha(n)
```

出力したグラフです。なめらかな二次曲線になりました。

![Figure_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/473097/40f74501-dee5-a094-2bfd-199cf58cd481.png)

# 終わりに

今回はコンプガチャの期待値を計算するプログラムを書きました。
基礎的なコード紹介となったので、Python入門者の参考になればと思います。

あと、キティちゃん50種類すべて集めるのは、金銭面やカロリー面で厳しいので諦めますが、皆さんも、キャンペーン期間中にマクドナルドへ足を運んでみてください。（※マクドナルドの回し者ではありません。）

ここまで読んでいただきありがとうございました。
filament v3の新機能　パネルビルダーをチラ見

## 概要
filament バージョン3からパネルビルダーと言う機能が追加されました。
どのような機能なのか紹介します。

## 内容

名前の通り管理パネルを複数用意できる機能です。
パネルAにはResourceAとResourceB、パネルBにはResourceCとResourceDとカスタムページA
と言った具合に切り分けできる機能です。
イメージ的にはこんな感じ

```mermaid
flowchart TB;

subgraph パネルA
direction LR

ResourceA
ResourceB
end


subgraph パネルB
direction LR

ResourceC
ResourceD
CustomPageA

end

```

スクショを貼り付けてみます。URLに注目。
`/admin/`と`/app/`で表示されてるサイドメニューが異なります。
このようにルートによって使用するResourceクラスやカスタムページを調整できます。



![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282328/8d6cbcc3-1cb1-3b4f-3434-96763425aad9.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282328/ae2166aa-19b0-74fb-1794-4877393f1a71.png)


どのように管理しているかと言うと、各パネルごとにパネルプロバイダークラスを作成し、そこで何のクラスを使うのかを定義します。
以下は`/app`のパネルプロバイダークラスです。

- discoverResources
    - どのディレクトリ配下のResourceクラスを使用するかを定義する
- discoverPages
    - どのディレクトリ配下のPageクラスを使用するかを定義する
- discoverWidgets
    - どのディレクトリ配下のwidgetクラスを使用するかを定義する

こんな感じで、各パネルで何を利用するかを定義できます。詳しくはドキュメントへ

https://filamentphp.com/docs/3.x/panels/getting-started

```php
class AppPanelProvider extends PanelProvider
{
    public function panel(Panel $panel): Panel
    {
        return $panel
            ->id('app')
            ->path('app')
            ->colors([
                'primary' => Color::Amber,
            ])
            ->discoverResources(in: app_path('Filament/App/Resources'), for: 'App\\Filament\\App\\Resources')
            ->discoverPages(in: app_path('Filament/App/Pages'), for: 'App\\Filament\\App\\Pages')
            ->pages([
                Pages\Dashboard::class,
            ])
            ->discoverWidgets(in: app_path('Filament/App/Widgets'), for: 'App\\Filament\\App\\Widgets')
            ->widgets([
                Widgets\AccountWidget::class,
                Widgets\FilamentInfoWidget::class,
                PatientTypeOverview::class,
                TreatmentsChart::class
            ])
....
```
trコマンドを使うものに物申す、カッコつけんな！

## はじめに

`tr` コマンドの書き方で未だにカッコを付けている書き方をしばしば見ます。

```sh:昔の書き方（1990年頃までの一部の環境用）
tr '[a-z]' '[A-Z]'

# 補足: 別件の話だがカレントディレクトリに「a」などのファイルがあると
# [a-z] は「a」に展開されるのでクォートは省略してはいけない
```

このカッコは不要です。

```sh:今の書き方（1990年代以降に統一された）
tr a-z A-Z
```

POSIX.2-1992 でカッコがいらない形に標準化されました。

カッコを付けていると `-d` オプションを指定したときに問題が発生します。

```console:カッコを付けるとカッコまで削除される
$ echo "foo [BAR]" | tr -d '[a-z]'
 BAR
```

無制限にすべての環境にも対応しようと考えると開発コストは増大してしまいます。POSIX に準拠した使い方をしなければ、より多くの環境を考慮しなければいけなくなるので移植性を高めるのがより大変になってしまいます。移植性を重視する場合でも、対応しなくて良い環境（古いバージョンの OS など）は切り捨てて、対応すべき環境を減らすのが開発コストを抑える基本です。「POSIX に準拠した環境にしか対応しない」という方針は現実的な方針の一つです。

## 旧System Vコマンドから新System Vコマンドへ

カッコが必要だったのは**昔の** System V 環境です。昔のというのは POSIX に準拠していない環境のことです。POSIX では `tr` コマンドを標準化する時、引数の書式については BSD Unix の仕様に統一しました。**POSIX は仕様を統一しなければ移植性を高めることが不可能だと考えた**からです。

System V 系の Unix、例えば Solaris には複数の `tr` コマンドがインストールされています。旧 System V コマンドの `tr` コマンドはカッコが必要ですが、新 System V コマンドの `tr` コマンドはカッコは不要です。

## System V系Unixはデフォルトを互換環境にしていただけ

商用 Unix は POSIX に準拠しています。しかし OS のデフォルト状態（例えばコンピュータを買ってきて起動した状態）で POSIX に準拠しなければならないという要件はありません。なにかの設定を行うことで POSIX に準拠する場合でも POSIX 準拠していると認められます。

POSIX ではコマンド名は標準化されていますが、**コマンドをインストールするパスは規定されていません**。例えばシェルは POSIX に準拠したシェルは `/bin/sh` に配置する必要はなく、`/usr/xpg4/bin/sh` に配置しても良いということです。実際に Solaris 10 の `/bin/sh` は POSIX に準拠しておらず、POSIX 準拠のシェルは `/usr/xpg4/bin/sh` です。そこに配置しても環境変数 `PATH` に `/usr/xpg4/bin` を加えれば `sh` でコマンドが呼び出せるので POSIX 準拠となります。ちなみに **POSIX ではシバンはインストール時に適切なパスに書き換えることが想定**されています。詳細は [sh](https://pubs.opengroup.org/onlinepubs/9699919799/utilities/sh.html) の APPLICATION USAGE を参照してください。

Solaris では POSIX に準拠した `tr` コマンドは `/usr/xpg4/bin` と `/usr/xpg6/bin` 以下にインストールされています。`/usr/xpg6/bin` 以下にある `tr` コマンドのほうがより新しい POSIX 規格に準拠したバージョンです。Solars 11 では `/usr/xpg7/bin` ディレクトリもありますが、こちらには `tr` コマンドは含まれていません。移植性が重要な場合はユーザーが POSIX 準拠環境に設定して使うことが想定されています。

環境変数 `PATH` を POSIX に準拠したものに変更しなければ awk なども古いコマンドが使われます。これは機能が大幅に少ない awk なので移植性を考えるのであれば事実上使い物にならないでしょう。POSIX に準拠したものに変更すれば、旧 System V コマンドを使う必要はありません。

ちなみに Solaris で POSIX 準拠の `PATH` を取得する方法として `getconf PATH` を使う方法が有名ですが、デフォルトの `/usr/bin/getconf` では `/usr/xpg7/bin` のパスが取得できません。

```console
$ getconf PATH
/usr/xpg6/bin:/usr/xpg4/bin:/usr/bin:/opt/developerstudio12.5/bin:/opt/solarisstudio12.4/bin

$ /usr/xpg4/bin/getconf PATH
/usr/xpg4/bin:/usr/bin:/opt/developerstudio12.5/bin:/opt/solarisstudio12.4/bin

$ /usr/xpg6/bin/getconf PATH
/usr/xpg6/bin:/usr/xpg4/bin:/usr/bin:/opt/developerstudio12.5/bin:/opt/solarisstudio12.4/bin

$ /usr/xpg7/bin/getconf PATH
/usr/xpg7/bin:/usr/xpg6/bin:/usr/xpg4/bin:/usr/bin:/opt/developerstudio12.5/bin:/opt/solarisstudio12.4/bin
```

より新しい POSIX のバージョンに準拠する場合は、`getconf` を使わずに手動で `PATH` を設定する必要があるでしょう。なおこれらは Solaris の場合なので HP-UX や AIX など他の Unix ではドキュメントを参照して正しい方法を使う必要があります。

## GNU tr の日本語ドキュメントは古い

GNU tr の日本語ドキュメントにはこのように書かれています。

```
書式
       tr [OPTION]... SET1 [SET2]

中略

      CHAR1-CHAR2
             CHAR1 から CHAR2 までを昇順に展開した文字列

       [CHAR1-CHAR2]
              SET1 と SET2 の両方で指定した場合には CHAR1-CHAR2 と同じ
```

これをもって、GNU tr が認めてるのだからカッコつけてもいいじゃんと思うかもしれませんが、それは日本語版が古いだけで英語版からはこの記述は削除されています。日本語版はどうやら 2016 年頃のもののようです。

## さいごに

カッコつけんな！
rsyslogでログが欠落する時の対応

# はじめに
業務にて、rsyslogの一部ログが欠落していることがわかった。
/var/log/messagesにて「⚪️⚪️ messages lost due to rate-limiting」のメッセージが表示されていた。（⚪️⚪️の部分が何件かを表す）
ログが全て表示されるよう設定変更したので対応内容を記載します。

# rsyslogの設定変更
rsyslogとは、Linuxシステムでのログの生成、収集、処理、および転送を管理するためのシステムです。
rsyslogの設定ファイルは通常 /etc/rsyslog.conf または /etc/rsyslog.d/*.conf にあります。

下記の設定を見直すことにしました。

##### $MaxMessageSize
syslogが処理できるメッセージの最大サイズを設定するための変数です。
これにより、ログメッセージのサイズが一定以上の場合、そのメッセージが切り捨てられます。

```terminal
既存の設定
$MaxMessageSize 8k
```
この場合、メッセージの最大サイズが8キロバイト（8k）に制限されています。
もし8キロバイトを超えるメッセージが到着した場合、rsyslogはそのメッセージを切り捨てます。

##### Ratelimit.Interval:
ログメッセージの制限が適用される時間の間隔を設定します。
例えば、この値を60に設定すると、60秒間に指定された数のログメッセージしか受け入れません。

##### Ratelimit.Burst:
Ratelimit.Interval 内で許容されるログメッセージの最大数を設定します。
これは、一度に受け入れることができる最大メッセージ数を表します。

デフォルト設定は600秒あたり20000メッセージ。
rsyslogは、この指定された時間制限枠内で最大バースト後に届いたメッセージを破棄する。

設定を見直し下記のように変更します。

```terminal
$MaxMessageSize 16k

Ratelimit.Interval="60"
Ratelimit.Burst="20000"
```
メッセージの最大サイズが16キロバイト。
60秒あたり20000メッセージまで許容される。

# rsyslogの設定反映

設定変更を行ったので、反映します。

##### /etc/rsyslog.confの文法チェック
```terminal
sudo rsyslogd -N1
```

##### rsyslogの再起動
```terminal
sudo systemctl status rsyslog
sudo systemctl restart rsyslog
sudo systemctl status rsyslog
```

# ログの確認
対象サーバで、/var/log/messagesにて、「⚪️⚪️ messages lost due to rate-limiting」が出なくなったのでOK。

##### ログの確認
```terminal
sudo fgrep "rsyslog" /var/log/messages | tail
```
※全て出力するように変更した場合、ログのサイズが大きいとディスクの圧迫につながるので注意。

# 参考
https://qiita.com/11ohina017/items/087b1b7c4411c3b3195a
https://tech-lab.sios.jp/archives/36082
【ROS2/Python】ROS2のCLIをPythonから使う

# はじめに
本記事は、ROS2アドベントカレンダー10日目の記事です。

https://qiita.com/advent-calendar/2023/ros2

ROS2では起動しているノードの確認、サービスの実行などなどのためにCLIツールが用意されています。
`ros2 node/topic list`などですね。

それらをPythonからも使うことができるので紹介します。

# 仕組み
仕組みは単純で、そもそもROS2のCLIのソースコードは以下のGitHubで公開されておりPythonで書かれています。ROS2がインストールされた環境であれば、適切にimportして自分のPythonコードからも呼び出すことができます。

https://github.com/ros2/ros2cli/tree/humble

それぞれコマンドごとにディレクトリが分かれていて、その中の`api/__init__.py`に関数が定義されているようです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/426354/1cc91e0a-f7ce-0231-f7a8-283849df0ab8.png)


# 例
## ROS2のノード一覧を取得
以下の__init__.pyにある`get_node_names()`を使用すればよさそうです。

https://github.com/ros2/ros2cli/tree/humble/ros2node/ros2node/api

```python
import rclpy
from ros2node.api import get_node_names
rclpy.init()
node = rclpy.create_node("test_node")
print(get_node_names(node=node))
rclpy.shutdown()
```

## ROS2のトピック一覧を取得
以下の`get_topic_names()`を使用すればよさそうです。

https://github.com/ros2/ros2cli/blob/humble/ros2topic/ros2topic/api/__init__.py

```python
import rclpy
from ros2topic.api import get_topic_names
rclpy.init()
node = rclpy.create_node("test_node")
print(get_topic_names(node=node))
rclpy.shutdown()
```

# おわりに
ソースコードが公開されているので使えるものは使っていきたいですね。
チーム開発で学んだこと

今回私たちはcorreteというサービスを開発しました。

![チーム１スライド.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3563096/e09fe436-ed97-cefa-1d72-eb3323e69212.jpeg)

<div style="position: relative; width: 100%; height: 0; padding-top: 56.2500%;
 padding-bottom: 0; box-shadow: 0 2px 8px 0 rgba(63,69,81,0.16); margin-top: 1.6em; margin-bottom: 0.9em; overflow: hidden;
 border-radius: 8px; will-change: transform;">
  <iframe loading="lazy" style="position: absolute; width: 100%; height: 100%; top: 0; left: 0; border: none; padding: 0;margin: 0;"
    src="https:&#x2F;&#x2F;www.canva.com&#x2F;design&#x2F;DAF1-i64gYM&#x2F;view?embed" allowfullscreen="allowfullscreen" allow="fullscreen">
  </iframe>
</div>
<a href="https:&#x2F;&#x2F;www.canva.com&#x2F;design&#x2F;DAF1-i64gYM&#x2F;view?utm_content=DAF1-i64gYM&amp;utm_campaign=designshare&amp;utm_medium=embeds&amp;utm_source=link" target="_blank" rel="noopener">Coretteスライド</a>
<br>


![スクリーンショット 2023-12-10 13.47.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3563096/5880c853-28e0-56d0-702b-e4ec310b5b4b.png)
まずはこのように必要な機能を定義しました。
今回は好みを記録するアプリを作っていきます。

![スクリーンショット 2023-12-10 13.50.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3563096/d6f6798a-c3d8-12de-1bf0-a1dbba506215.png)
続いてはガントチャートでプロジェクト全体のスケジュールを計画します。


![スクリーンショット 2023-12-10 13.56.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3563096/28f029f2-8eaa-64e0-d126-0abb6300ee61.png)
そしてワイヤーフレームを作成しました。

その後
![スクリーンショット 2023-12-10 20.45.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3563096/275fc92f-cf21-99f5-7ea9-9d8546de88cc.png)
テーブル定義を行った後、タスクを個人ごとに分担して制作しました。
Google Cloud Certified Professional Cloud Developer 合格体験記

# はじめに

Google Cloudの高度資格では2つ目となる、Professional Cloud Developerを取得したのでその記録を残します。

# Google Cloud Certified Professional Cloud Developerとは
https://cloud.google.com/learn/certification/cloud-developer?hl=ja

GKEやCloud Run、またCloud SQLなどマネージドサービスを利用したアプリケーションを構築に関する知識を問う試験となっています。

# 学習方法
- [Udemyの問題集](https://www.udemy.com/course/google-professional-cloud-developer-2023/)
  - PCAのときに引き続き、試験対策のメインとして利用。こちらを完璧に試験に不安はないでしょう。
- Kubernetes、GKE、Cloud Runなどの知識
  - こちらは実務を中心に事前に知識があったので個人的には不要でしたが、関連する問題が多く出るため、身につけておくことは必須です。

# 結果&所感
2時間120分のところ、1時間弱で終了。その場で合格の表示が出ました。
こちらは、問題集で知識をまんべんなくつけることも重要ですが、ベースとなる理解を深め、じっくり問題文を読むことで消去法により回答できるような力をつけることが大切だと感じました。
RactorでGenServerっぽいものを作ってみた記録

## この記事は何
Rubyには3.0からRactorという機能がexperimentalで入っています。
これは文字通りRubyでActorモデルを実装することを可能にしたものです。
この記事では、このRactorを用いて、ElixirやErlangのOTPの一つであるGenServerを作ってみた記録記事です。

## Ractorとは
Ractorとは、Ruby 3.0から導入された新しい並行抽象化の機能です。
今までのThreadなどの仕組みとは異なり、GVLの制限を受けずに文字通り並列の処理をRubyで実現することが可能になります。

詳しくは以下の記事をご覧ください。

https://qiita.com/tsukasa_oishi/items/beda7e7ddcf92c8e634d

https://techlife.cookpad.com/entry/2020/12/26/131858

## OTPとは
OTP (Open Telegraph Protocol)とは、分散システムや並列処理をErlangやElixirで実現するためのフレームワークです。このOTPではいわゆるアクターモデルを用いた実装がされています。

OTPの一つとして、GenServerがあります。
GenServerとは、関数型言語であるErlangやElixirで状態を保持するために用いるパターンです。
GenServerでは、状態を変数ではなく、プロセスベースで保持します。

詳しくはこちらをご覧ください。

https://hexdocs.pm/elixir/1.15.7/GenServer.html

https://qiita.com/HirofumiTamori/items/b72ad232dc3b26e87a03

## 実装例
今回はこのErlangやElixirで用いられるGenServerを、同じくアクターモデルを実現するRactorを用いて実装していきたいと思います。

今回は以下のように実装を行なってみました。

```rb
class RactorGenServer
  def call(command, data = nil)
    ractor.send([command, data])
    ractor.take
  end

  def cast(command, data = nil)
    ractor.send([command, data])
  end

  private

  def ractor
    @ractor ||= Ractor.new do
      handle_message = ->(message, current_state) do
        case message
        in [:enqueue, data]
          {
            status: :ok,
            state: [*current_state, data],
            value: nil
          }
        in [:dequeue, nil]
          if current_state.empty?
            { status: :error,
              state: current_state,
              value: nil
            }
          else
            {
              status: :ok,
              state: current_state[1..-1],
              value: current_state.first
            }
          end
        end
      end

      state = []

      loop do
        message = Ractor.receive

        handle_message.call(message, state) => { status:, state:, value: }

        raise StandardError, "error" if status == :error

        Ractor.yield(value) if value
      end
    end
  end
end

# 使用例
gen_server = RactorGenServer.new
gen_server.cast(:enqueue, "item1")
gen_server.cast(:enqueue, "item2")
puts gen_server.call(:dequeue) # => "item1"
puts gen_server.call(:dequeue) # => "item2"
```

このような実装をすることで、Ractorのプロセス単位で状態を保持することが可能になります。
OTPでは、分散システムで扱われる想定のための実装も含まれていますが、今回はそこまで実装はしておらず、あくまでプロセス単位で状態を保持できるところまで実装してみました。

今回はRactorの使い方の模索の一環として、OTPのGenServerっぽいものを作ってみました。

まだだいぶ荒削りな実装なので、
よりOTPの挙動に近い実装のアイディアなどある方はぜひシェアいただけると嬉しいです。
Nuxt.js + EmailJS でコンタクトフォームを実装してVercelにデプロイしたら404エラーが発生したこと

初歩的な事とは承知の上で自分の備忘録として記事にします！

Nuxt.js、EmailJSでコンタクトフォームを実装し、Vercelにデプロイした際に404エラーが出てメールが送信できませんでした。

## 原因
Nuxt.jsのpagesフォルダ内でEmailJSのアカウント情報を設定していた点でした。

```ruby:index.vue
const emailjs = {
    userId: process.env.EMAILJS_USER_ID,
    serviceId: process.env.EMAILJS_SERVICE_ID,
    templateId: process.env.EMAILJS_TEMPLATE_ID
};
```

## 対処法
以下のようにruntimeConfigを使用して、アカウント情報を取得することで解決できました。
```ruby:nuxt.config.ts
runtimeConfig: {
    public: {
        userId: process.env.EMAILJS_USERID,
        serviceId: process.env.EMAILJS_SERVICE_ID,
        templateId: process.env.EMAILJS_TEMPLATE_ID,
    }
},
```

```ruby:index.vue
const config = useRuntimeConfig();
const emailjsConfig = {
    userId: config.public.userId,
    serviceId: config.public.serviceId,
    templateId: config.public.templateId
};
```

runtimeConfigを適切に設定することで、Vercelデプロイ時に環境変数が正しく読み込まれ、404エラーが解消され、メールの送信が可能となりました。
認識が間違っている箇所、足りていない箇所があればご教授お願いします！
【３分クッキング】ReactでVSCodeを作ろう！【React_Ace】

## はじめに
Ace Editorという、ブラウザで使えるJS製のテキストエディタがある。
↓参考
https://qiita.com/naga3/items/1bc268243f2e8a6514e5

以前、WEBアプリ開発の中で「テキストエディタほしいな～」という場面に遭遇したのだが、０からコンポーネント云々を作るのは大変なのでこのAceというのを導入した経験がある。

それもありがたいことに、
- 数十種類のテーマ（ライトモード、ダークモード対応）
- 言語を設定できる
- ↑　設定した言語で自動補完が使える

と、ほしい機能が満載で至れり尽くせりなのである。
特に自動補完なんかは個人で作ってられないので神機能だと思う。

さて、インターネットにはバニラなAceの解説記事しかないため、ここではReactでAceを使える「react_ace」についてまとめてみようと思う。

ちなみにタイトルは釣りです。

## インストールしよう

**ちなみにこの記事よりドキュメント一読したほうが早い。**\
https://github.com/securingsincity/react-ace

    npm install react-ace ace-builds

もしくは

    yarn add react-ace ace-builds

## サンプルコード

```tsx
'use client';

import AceEditor from "react-ace";
import "ace-builds/src-noconflict/mode-python";
import "ace-builds/src-noconflict/theme-crimson_editor";
import "ace-builds/src-noconflict/ext-language_tools";

export const Editor = () => {
    function onChange(newValue: any) {
        console.log("change", newValue);
    }
    return (
        <AceEditor
        mode="python"
        theme="crimson_editor"
        onChange={onChange}
        enableLiveAutocompletion={true}
        name="editor"
        width="100%"
      />
    )
}

```

- useclient使わないとだめだよ！！
- ace-builds/src-noconflict/を見るとテーマ一覧があるよ！！
https://ace.c9.io/build/kitchen-sink.html
↑　ここにも

- onChangeが便利だよ！！

### 最後に

ちなみに今確認したら、atcoderのエディタもAce使ってました！
第一世代　USBジャック取り付け（調査中）

「aibo ers-11x/210で遊ぶ Advent Calendar 2023」の13日目です。

ERS-111を分解していたところ、背中にUSBジャックを取り付けられそうな端子を見つけました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103446/15e77372-9821-64ee-ad99-e2a19d55841d.png)


この機種は通信機能が見つけられなかったので、ワンチャン、COMポートでつながるかもしれないと思い、改造してみました。

残念ながら作業中ですが、メモを残します。

:::note alert
警告
この記事について作者はいかなる責任も負いません。
:::

:::note
業務外の個人的な検討活動です。
:::

#### 本体を分解する
手足を取り外し、外装を外しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103446/3d33f093-e84d-1e88-d4f3-904bff0cdf4d.png)

基板の上の隙間の寸法を測ったところジャックが入る大きさでしたので、部品を発注しました。
https://ja.aliexpress.com/item/32849569894.html

#### 動作確認
ジャックを半田付けし、WindowsPCとUSB接続しました。
接続音はしましたが、適切なドライバを見つけられず、作業を保留しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103446/ef99d326-b964-d91b-508e-8b859db6dab1.png)

#### PulseViewで波形を解析
25日目の記事で使ったPulseViewによる波形解析をおこないました。
https://qiita.com/nakmura/private/559fda6b93d67b986b21

試行錯誤の結果、UARTで115200にすると何となく意味がありそうな内容が出てきました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103446/e81fa2f3-a2dd-33be-3eae-2e54ce2a8643.png)
【SwiftUI】Viewをズームインしたり、ズームアウトしたりする（iOS17）

# はじめに
今回のサンプルは`@GestureState`という機能を使います。
初めて見たよって方は`@GestureState`の記事から見てください

https://qiita.com/SNQ-2001/items/df8c61ff82ffc7bdad33

# サンプルアプリ
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/5ee71164-d8e4-b775-3328-756ace5d05b0.gif" width=50%>

# 実装
公式ドキュメントのコードです。
```swift
import SwiftUI

struct ContentView: View {
    @GestureState private var magnifyBy = 1.0
    
    var magnification: some Gesture {
        MagnifyGesture()
            .updating($magnifyBy) { value, gestureState, transaction in
                gestureState = value.magnification
            }
    }

    var body: some View {
        Circle()
            .frame(width: 100, height: 100)
            .scaleEffect(magnifyBy)
            .gesture(magnification)
    }
}
```

# シュミレーターでズームイン or ズームアウトする
今まで知らなかったんですけど、今回発見しました

`control` + `option` + 画面をドラッグ

これで出来ます。

# おわり
画像のズーム機能などを簡単に実装できそうですね。
さらに`@GestureState`を使うと指を離した時点で勝手に初期値に戻るのでより便利になります。

# 公式ドキュメント
https://developer.apple.com/documentation/SwiftUI/MagnifyGesture#overview
Amazon Managed Grafanaでデータソースの設定の自動化はCFnでは難しいけどAPIならできる

こんにちは。Kaneyasuです。

本記事はAmazon Managed GrafanaのAPIによる操作を書いています。
本記事のゴールは、ユーザー認証にAWS IAM Identity Centerを用いたAmazon Managed Grafanaに対し、Amazon Timestreamを指定したデータソースを設定するのを自動化するところまでです。

なお、本記事ではCloudFormationテンプレートのことをCFnと略しています。

# データソースの設定の自動化はCFnでは難しい

Amazon Managed Grafanaは[Amazon Timestream](https://aws.amazon.com/jp/timestream/)など、さまざまなDBをデータソースとして、可視化が可能です。

https://aws.amazon.com/jp/grafana/

Amazon Managed Grafanaの起動＝ワークスペースの作成まではCloudFormationテンプレートで行えます。

https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-grafana-workspace.html

ですが、できるのはワークスペースの作成までで、データソースの設定はまではできないようです。
よくよく見ると`DataSources`というプロパティがありますが、サンプルの記述がとても少ないので、正解がわかりません。
CFnでできるのはワークスペースの作成までと考えた方がよさそうです。

Grafanaは、ワークスペースを作った後、本格的な利用までに、データソースやダッシュボードの作成をしなければなりません。
これらを全て手動で行うのは少々手間なので、自動化を目指して別の手段を考えます。

# Grafana HTTP APIならできる！

Amazon Managed Grafanaというより、GrafanaそのものにHTTP API機能があります。

https://grafana.com/docs/grafana/latest/developers/http_api/

データソースに関するAPIもあるので、このAPIに対してPOSTリクエストを発生させれば、一発でデータソースを作成することができます。

試したところ、これがAmazon Managed Grafanaでも使えることがわかりました。

https://grafana.com/docs/grafana/latest/developers/http_api/data_source/#create-a-data-source

Amazon Managed Grafanaも、ワークスペースを作成するとURLが発行されます。
このURLをベースにして、Grafana HTTP APIを叩けば、APIの利用が可能です。
ワークスペースの作成まではCFnでできるので、その後の作業をGrafana HTTP APIでやればよいと考えることができます。

APIを利用するには認証を通す必要があります。
認証をそのまま突破するのではなくて、APIトークンを利用する方が楽です。
APIトークンはGrafanaにログイン後、画面から取得することができます。

https://docs.aws.amazon.com/ja_jp/grafana/latest/userguide/using-api-keys.html

>Grafana コンソールのサイドメニューで、設定 (歯車) アイコンを一時停止し、API キーを選択します。

問題はこれはGrafanaのAPIなので、このAPIドキュメントには、データソースにTimestreamを指定する方法が見当たらないことです。

# Timestreamをデータソースに指定するシェル

当然ですが、Grafana HTTP APIにはGETもあります。
データソースであれば、GETでAPIを叩けば、その設定内容がJSONで返ってきます。
これを利用して、一度手動でTimestreamを指定したデータソースを作り、その内容をGETで取得。
それをベースに、データソースのPOSTリクエスト用のJSONを作れば、自動化を実現することができます。

完成させたシェルがこちらです。
ワークスペースのURLとAPIトークンはハードコーディングを避けるため外だしファイルにしています。

https://gist.github.com/satoshi256kbyte/9fc989fd65955174ba690b9d252713ee

# 他の設定にも応用はできるか？

手動で作ってからGETのAPIを叩いてJSONを得て、それをベースに新規作成目的のPOST用JSONを作るやり方は他にも転用が効くと思います。

しかし、ダッシュボードに限っては、HTTP APIでは細かいところまでフォローされてないので、エクスポート・インポートを活用した方がよさそうです。

ダッシュボードのエクスポート・インポートは、別記事で書いたのでこちらをご覧ください。

https://qiita.com/satoshi256kbyte/items/f0a37f7c208c148aaf97
Python×DynamoDB:初心者向け簡単チュートリアル

## はじめに
AWS DynamoDBは、スケーラブルで柔軟性が高く、パフォーマンスに優れたNoSQLデータベースサービスです。Pythonと組み合わせることで、開発者は効率的かつパワフルなデータハンドリングを実現できます。

しかし、PythonとDynamoDBの組み合わせに関する解説記事は少なく、ハードルが高いかもしれません。

よって本記事では**Pythonを使ったAWS DynamoDBの基本的な利用方法**をわかりやすく紹介します。

また「Python×AWSのDB」の解説記事は全3つを予定しており、いずれもARISE analyticsアドベントカレンダーに登録予定です。内容はPython×DAX（DynamoDB Accelerator）とPython×Elasticache Redisを予定しています。

## 内容
### 事前準備
まずDynamoDBにアクセスするために、AWSのアカウントのアクセスキーとシークレットキーを環境変数に設定します。

```bash
$ export AWS_ACCESS_KEY_ID={アクセスキー}
$ export AWS_SECRET_ACCESS_KEY={シークレットキー}
```

:::note warn 
環境変数を設定しない場合は、プログラムにAWSのアクセスキーとシークレットキーを記載する必要があるので危険ですし、プログラム記述量が増えるので手間が増えてしまいます。
:::

### DynamoDBとの接続
`boto3`というライブラリを用いてDynamoDBと接続を行います。

まず`boto3`をインストールします。

```python 
(仮想環境)% pip install boto3
```

次に`boto3`を用いてDynamoDBのテーブルに接続します。

```python
import boto3

table_name = 'テーブル名' 
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table(table_name)
```

ちなみにEC2からの作業だと、VPCエンドポイントが設定されていない場合はインターネットゲートウェイを用いてDynamoDBに接続されます。

https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/vpc-endpoints-dynamodb.html


### DynamoDBへの書き込み
DynamoDBに書き込みを行います。

プログラムは以下です。

```python
from decimal import Decimal

def convert_floats_to_decimals(obj):
    """
    float->Decimalに変換する関数
    """
    if isinstance(obj, list):
        return [convert_floats_to_decimals(x) for x in obj]
    elif isinstance(obj, dict):
        return {k: convert_floats_to_decimals(v) for k, v in obj.items()}
    elif isinstance(obj, float):
        return Decimal(str(obj))
    else:
        return obj

data = {'Id':1, 'value': 3.5} #保存したいデータ
data = convert_floats_to_decimals(data) #float->Decimalに変換
table.put_item(Item=value) #DynamoDBへ書き込み
```

DynamoDBの書き込みでの注意点は以下２つです。

**プライマリーキーを必ずセットする**

**`float`型のデータは`Decimal`に型変換して保存する**

これでデータの書き込みができたので、次は読み込みの方法に移ります。

### DynamoDBの読み込み
DynamoDBのデータの読み込みを行います。

プライマリーキーを用いてデータを取得します。(今回はプライマリーキーを`Id`とします。)

プログラムは以下です。

```python
from decimal import Decimal

def convert_decimals_to_floats(obj):
    """
    Decimal->floatに変換する関数
    """
    if isinstance(obj, list):
        return [convert_decimals_to_floats(x) for x in obj]
    elif isinstance(obj, dict):
        return {k: convert_decimals_to_floats(v) for k, v in obj.items()}
    elif isinstance(obj, Decimal):
        return float(obj)
    else:
        return obj

key ={'Id': '1'} #プライマリーキーはId
response = table.get_item(Key=key) #DynamoDBの読み込み
response = convert_decimals_to_floats(response) #Decimal->float変換
```

## おわりに
いかがだったでしょうか。
上記のようにDynamoDBはPythonで簡単に扱うことができます！

参考になれば幸いです。

次回はDynamoDBより高速であるDAX(DynamoDB Accelerator)の使い方について解説します。
統計検定学習備忘録　※条件付き確率は問題文の書き方で定義等の解釈が度々混乱する件（特に連続型）

<h4>以下の資料の計算はあくまで過去に個人的に確認したもので、公的に査読されていないため、間違っている箇所があれば、遠慮なくご連絡いただけるとありがたいです。

※この記事は途中です
___
全体の問題のリンクも載せますが、例えば **統計検定2022　統計数理　問３（３）** の問題文は以下のようになっていました。

____
**上問〔１〕におけるパラメータ $\lambda$ が上問〔２〕のガンマ分布 $G(\alpha,\beta)$ に従うとき、確率変数 $X$ に関する確率 $P(X=k)$ を求めよ。（※ここで以下のことに注意）**

___
**注１： $\lambda$ はポアソン分布のパラメータで〔１〕では「離散型」確率変数 $X$ は従うとしています。すなわち、**
```math
f(k)=P(X=k)=\frac{{\lambda}^k}{k!}e^{-\lambda}　　（k=0,1,2,・・・）
```
**という式の中で$\lambda$ を使っている。**
___
**注２： ガンマ分布 $G(\alpha,\beta)$ は以下の非負の「連続型」確率密度関数に従う確率分布である。**
```math
g(\lambda) = \frac{{\beta}^{\alpha}}{\Gamma(\alpha)}{\lambda}^{\alpha-1}e^{-\beta\lambda}　   　　　なお、\lambda \geq 0
```
ただし、 $\alpha、\beta　は、\alpha > 0 、\beta > 0$　**を満たす実数**であり、ここの$\Gamma(\alpha)$ は
```math
\Gamma(\alpha) = \int_{0}^\infty t^{\alpha-1}e^{-t}dt = \lim_{s\to\infty}\int_0^s t^{\alpha-1}e^{-t}dt 
```
と定義される **関数（※階乗を一般化した関数、ガンマ関数（$\Gamma$関数）といいます。なお、$\Gamma$ もギリシャ文字）である。**
___

**注３：問題文に書かれていない部分では、$f(k) 、 g(\lambda)$　は定義されていない部分では、恒等的に（べったりずっと）0 である**として計算を進める必要がある。

※原本
chrome-extension://efaidnbmnnnibpcajpcglclefindmkaj/https://static.toukei-kentei.jp/wp-content/uploads/20230112122939/202211grade1suri-20230112122939-20230112122939.pdf
____

https://qiita.com/thinking-weed/items/8099d221865afd6db3c6
上記Qiitaのように〔１〕〔２〕までは分かったのですが、〔３〕から以下の問題が出てきて
(-_-;)？？何これ日本語？？(>｡<)ｺﾞﾎｯｺﾞﾎｯみたいな感じです。このQiitaもまだ気持ち悪い。
____

**上問〔１〕におけるパラメータ $\lambda$ が上問〔２〕のガンマ分布 $G(\alpha,\beta)$ に従うとき、確率変数 $X$ に関する確率 $P(X=k)$ を求めよ。（※ここで以下のことに注意）**

これ、初見何言ってるかよく分かんなかった（´д｀）ので、散々調べた結果、こうではないかという解釈をしました。

**（連続型）確率変数 $\Lambda = \lambda$ がガンマ分布 $G(\alpha,\beta)$ に従うという条件を満たしながら
（離散型）確率変数 $X$ が $X=k$ となるときの確率（密度関数）を求めよ。**

要は、
**「〔１〕では、$\lambda$ は定数として扱って計算進めたところを、変数として扱って、
確率 $f(X=k　かつ　\Lambda=\lambda)$ を計算せよ。」**
みたいなかんじです。

<h2>で、結局これ何計算してるん？？？（´д｀）

たぶん「ここでは」、このように定義して計算を進めているのではないかと思われます。
次の記事と参考資料⑥に載っている定義を参考にしました。
https://wiis.info/math/probability/continuous-probability-distribution/continuous-conditional-random-distribution/#elementor-toc__heading-anchor-0

```math
\displaylines{
    P(X=k　かつ　\Lambda=\lambda)=P(\Lambda=\lambda)P(X \ni k|\Lambda=\lambda)\\
    =\int_{-\infty}^{\infty}g(\lambda)d\lambda × P(X \ni k|\Lambda=\lambda)　　???
}
```
なお、要はいわゆる「乗法の定理」で、
$P(X \ni k|\Lambda=\lambda)$ は「確率変数$\Lambda$に$\Lambda=\lambda$ を与えたときの確率変数$X$ の条件付き確率（密度関数）」



____
長かった…(´д｀)ここからようやく答えの計算です。

※すみません。まだ検証途中ですm(_ _)m

<h3>統計でよく使うギリシャ文字（＝ローマ文字）早見表

以下の高知工科大学のサイトがまとまっていたため、リンクを貼っておきます
http://www.ele.kochi-tech.ac.jp/tacibana/etc/analog-intro/greek-alpha.html

<h1>参考資料一覧（※全部の内容を自分も理解できているわけではないです。）

①統計検定1級公式問題集　実務教育出版　
　※過去問のページ　https://www.toukei-kentei.jp/prepare/kakomon/
②青チャートI＋A、Ⅱ＋B　数研出版
③理工系の微分積分学　吹田信之、新保経彦　共著　学術図書出版書
④線形代数入門　齋藤正彦　著　東京大学出版会
⑤定本　解析概論　高木貞治　著　岩波書店　
⑥数学シリーズ　数理統計学　改訂版　稲垣萱生　著　裳華房
⑦数学シリーズ　集合と位相　内田伏一　著　裳華房
⑧one point 推定と検定　鷲尾泰俊　著　共立出版
⑨電磁場とベクトル解析　深谷賢治　著　岩波書店
 **⑩基礎数学８〔新版〕複素解析　高橋礼司　著　東京大学出版会（$\Gamma関数$に関する記述がたぶん解析概論の次に詳しく載っている？自分が知っているそこそこメジャーな数学書）**
 **⑪岩波　数学入門辞典**　
 **青本和彦・上野健爾・加藤和也・神保道夫・砂田利一・高橋陽一郎・深谷賢治・俣野　博・室田一雄　共著（日本数学界の重鎮たちによる数学用語の辞書。大概何でも載ってるが、あくまでヒントしかくれない(-_-;)）**
JP1について理解を深めたい。【自分用】

### はじめに
　仕事でJP1を使用した作業を任されることが増えたため、簡単にJP１についてまとめてみました。
 
### JP1ってなに？
　JP1は、1994年に発売された日立製作所が開発した、企業のITシステムの稼働監視、業務自動化、IT資産管理、およびインフラ管理などを統合的に行うITシステム運用管理ソフトウェアです。
　サーバーやネットワーク機器を複数台利用しているとそれぞれ運用・メンテナンスをするためには、各機器の状況確認やログの参照を行わなければなりません。
　しかし、JP1を使用すれば1台のモニターで全ての機器を管理することができるようになります。

### JP1の機能
 　JP1は、システムの全体を動かす「**オートメーション**」、システムを止めない「**モニタリング**」、IT資産管理とセキュリティリスクに対応する「**コンプライアンス**」の３つの分野でサービスを提供していて、それぞれの機能ごとに組み合わせて利用し効率的な運用を実現することが可能です。
  
### JP1/Automatic Job Management System（AJS）について
　JP1/Automatic Job Management System（AJS）はJP1の製品の中でもっとも有名なサービスの１つであり、同業他社製品（Zabbix、Hinemos等）が数多くおりますが、その中でも国内シェア率約26％とトップクラスのシェア率となっているジョブスケジューラーでもあります。AJSはジョブを視覚的に確認することが可能で、カレンダーを確認しながら実行の登録を行うことが可能です。
　![jp1_03s.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2629112/3d568b59-7a89-8864-8a4a-0c362ecc967a.png)

 
　AJSの特徴は様々な業務を自動化することができる点です。日次・週次・月次などをカレンダー上で登録することや複数の拠点のサーバーを接続し業務フローを自動化 することが可能となります。また、ユーザーの環境によって様々なシステムとの連携が可能であることも特徴です。
　たとえ複雑なジョブから構成されているジョブネットであっても、当日実行分のジョブのみジョブネットモニタ画面で表示させることが 可能でジョブの進行状況を把握でき、ジョブの実行保留・再実行・強制終了などの操作も実行することができる点も特徴のひとつです。

### JP1技術者資格認定について
　JP1にも、JP1技術者資格認定という株式会社日立製作所が認定する資格制度があります。「**JP1認定エンジニア**」「**JP1認定プロフェッショナル**」「**JP1認定コンサルタント**」 の3つがあり、それぞれで難易度が異なります。
　自分が近々受けようと思っているJP１認定エンジニアはJP1の全般を理解しており、運用に必要なテクニカルスキルを習得したエンジニアを認定しているものとなっています。

### まとめ
　今回は、JP1について簡単にまとめました。まだまだJP1の機能を完璧に使いこなせてはいないので、今後も業務・自己学習を通して学んでいけたらと思います。

#### 参考
[統合システム運用管理 JP1とは](https://www.hitachi-systems.com/ind/jp1/about_jp1/)
[JP1ジョブ管理](https://www.ashisuto.co.jp/product/category/system-management/jp1/#tab)
WSLのインストールエラーの時に確認すること


# はじめに

WSLでubuntuなどのディストリビューションをインストールしようとすると、以下のようなエラーが出ることがあります。
このエラーの原因は多岐にわたり、なかなか状況を改善できないことが多いです。
そういう時に、以下の内容を確認してみてください。

```
Installing, this may take a few minutes...
WslRegisterDistribution failed with error: 0xXXXXXXXX
Error: 0xXXXXXXXX ??????????????????????????????????????
```

# 確認すること

## 管理者権限のPowerShellで実行しているか？

そもそもですが、WSLをインストールする際は、管理者権限を持つPowerShellで実行する必要があります。

## Windows Updateが溜まっていないか？

Windowsのバージョンが古い場合、WSLが正常に動作しないことがあります。
更新プログラムを確認して、適応していないパッチがある場合はWindows Updateをインストールしてください。

## BIOS/UEFIのバージョンが古くないか？

古いBIOS/UEFIバージョンでは、仮想化機能や関連する機能が正しくサポートされていないことがあります。
自身のPCメーカーのサポートページから最新のBIOS/UEFIアップデートを確認し、アップデートを行ってください。

## CPUの仮想化機能が有効になっているか？

BIOS/UEFI設定画面で、仮想化機能（Intel VT-xまたはAMD-V）が有効になっていることを確認してください。
Intel製CPUの場合は「Virtualization Technology」、AMD製CPUの場合は「SVM Mode」といった名前で表示されます。

マザーボードのメーカーによってBIOS内の項目の場所は異なりますが、大体以下のようになっているはずです。

Intel製：
*「System Configuration」->「Virtualization Technology」->「Enabled」*

AMD製：
*「Advanced」 -> 「CPU Configuration」 -> 「SVM Mode」->「Enabled」*

## Hyper-Vは有効になっているか？

WSL 2を利用するためには、Hyper-Vが有効になっている必要があります。コントロールパネルの「プログラムと機能」から「Windowsの機能の有効化または無効化」に移動し、Hyper-Vを有効にしてください。

以下のコマンドでHyper-Vを有効化できます。

```bash
dism.exe /online /enable-feature /featurename:HypervisorPlatform /all /norestart
```
※PCの再起動が必要です。

## WSLのバージョンが2になっているか？

WSL 2を利用するには、適切なバージョンにアップグレードする必要があります。以下のコマンドを使用してWSL 2にアップグレードできます。

```bash
# インストールされている各ディストリビューションのバージョンを確認
wsl --list --verbose

# 上記でバージョンが1となっているものがあれば、バージョンを2に変更する
wsl --shutdown
wsl --set-version <ディストリビューションの名前> 2
```

## WSLのバージョンが古くないか？

以下のコマンドで、WSLを最新化できます。
```bash
wsl --update
```

## PC本体のメモリは足りているか？

WSLはメモリを多く消費します。タスクマネージャーなどで確認して、十分なメモリ量が使用可能であることを確認してください。
PC本体のメモリ上限にもよりますが、大体2GB～4GB程度消費されます。

## PC本体のストレージは足りているか？

WSLはかなりのストレージ容量を占有します。十分な空き容量を確保してください。
WSL本体は約1GB程度で、ubuntuなどのディストリビューションは5, 6GBほど占有します。
ディストリビューション内でDockerを使用している場合は、いつの間にか100GBを超えているなんてこともあるので注意しましょう。

以下のコマンドで、指定したディストリビューションの容量を確認することが出来ます。
※`Used`が占有している容量です。

```bash
wsl --system -d <ディストリビューションの名前> df -h /mnt/wslg/distro

# Filesystem      Size  Used Avail Use% Mounted on
# /dev/sdc        251G   42G  197G  18% /mnt/wslg/distro
```

# それでも解決しない場合

以上のことすべてを確認しても状況が改善しない場合は、WSLの再インストールをしてみるのも1つの手です。

以下の3機能を1度無効化した後に、再度有効化します。
- 仮想マシンプラットフォーム
- Linux 用 Windows サブシステム
- Windows ハイパーバイザー プラットフォーム


```bash
# 機能を無効化
dism.exe /online /disable-feature /featurename:VirtualMachinePlatform /norestart
dism.exe /online /disable-feature /featurename:Microsoft-Windows-Subsystem-Linux /norestart
dism.exe /online /disable-feature /featurename:HypervisorPlatform /norestart
# PCを再起動
Restart-Computer -Force

# 機能を有効化
dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart
dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart
dism.exe /online /enable-feature /featurename:HypervisorPlatform /all /norestart
# PCを再起動
Restart-Computer -Force
```

# 参考

https://zenn.dev/h4m4chi/articles/8627893de9cdc5
WASM書いてみた（Go vs Rust）

# はじめに
本記事では、Go言語とRustで同じ機能を持つWASMを書き、３つの観点で比較した

# つくったもの
https://github.com/exit8goodgame/WasmCompare

複数のファイルをZipアーカイブに変換しダウンロードする機能を持つWASMを、Go言語とRustで作成した

## 環境等
Mac Mini (M1)
```
Darwin root.local 23.1.0 Darwin Kernel Version 23.1.0: Mon Oct  9 21:28:12 PDT 2023; root:xnu-10002.41.9~6/RELEASE_ARM64_T8103 arm64
```

Go言語
```
go version go1.21.5 darwin/arm64
```

Rust
```
stable-aarch64-apple-darwin unchanged - rustc 1.74.1 (a28077b28 2023-12-04)
```


# すうじをみる
## コードサイズ
|  | 言語 | ファイル名 | サイズ(Byte) |
| ---- | ---- | ---- | ---- |
| 1 | Go言語 | main.go | 1662 |
| 2 | Rust | lib.rs | 2169 |

Go言語がより小さいファイルサイズ。ただし差は 500Byte程度。
コードサイズ（または文字数）は書き方にも影響され、IDEの機能で長いコードを書くのも苦しくないという意見は存在すると思う。
しかし、改修や機能追加の際にはコードを読み・理解する必要があり、コードの長さは無視できない為、今回比較対象とした。

## WASMサイズ
|  | 言語 | ファイル名 | サイズ(Byte) |
| ---- | ---- | ---- | ---- |
| 1 | Rust | zip_archive_rust_wasm_bg.wasm | 149554 |
| 2 | Go言語 | main.wasm | 2618952 |

Rustがより小さいファイルサイズ。桁が違う。ただしTinyGo未使用。
ビルドされたwasmファイルは、処理実行前にダウンロードされる。回線状況によってはユーザビリティに影響するため比較対象とした。

## 実行時間
|  | 言語 | 平均実行時間（msec） |
| ---- | ---- | ---- |
| 1 | Go言語 | 166.5 |
| 2 | Rust | 1846 |

Go言語がより短い実行時間。桁が違う。
計測方法は、１MByteのファイルを10個 入力として渡しZipアーカイブ完了までの時間を２回測り平均した。
処理開始と完了時に```Date.now()```でmsecを出力した。（リポジトリのindex.html参照）
ブラウザはChromeを使用した。

これは予想外で、同程度かRustが短い実行時間かと思っていた。
コードの書き方や計測方法にも影響されるが、今回はこの結果。

処理完了までの待ち時間として、ユーザビリティに影響するため比較対象とした。

# おわりに

今回比較した観点以外にも、WASMを書く言語として以下の点を気にしていきたい

- 求める機能を実現できるライブラリが存在するか・そしてWASMで利用可能か
- 新規メンバーの習熟コストが高いか
- 改修や機能追加が容易か

### 謝辞
今回の記事を書くきっかけを与えられた
[実践入門WebAssembly](https://www.amazon.co.jp/dp/B0CLG7DWPR/)