OmniAICreator/Qiita-1.07M huggingface dataset:
MDMってなんだろう

# MDMってなんだろう

## 初めに
MDMに関する知識は少しだけあるものの、その説明を求められると難しいことがあります
そんな私を脱却するためにまとめます

## 今回書くMDMは？
Mobile Device Managementについて説明します
Master Data Managementだと思って開いた方はごめんなさい:bow:

## MDMって？
- Mobile Device Managementといって企業などで使われるモバイルデバイス（スマホやタブレット、ノートパソコン）を管理、セキュリティツールのこと
- そんなデバイスを遠隔で監視、制御、セキュリティ確保を目的としたツールのことをMDMソリューションと呼んだりするよ（それも含めてMDMということが増えてきている気がするけど、、、）
- **こんなことができるよ！**
- 詳しいことは次の章で記載します:bow:
    - デバイスの登録と管理
        - 新しいPCなどを追加して設定を追加することができる
    - ポリシーの設定と適用
        - セキュリティポリシー、アクセスの制御、アプリケーションの制御…などを定義して適用できる
    - セキュリティの確保
        - パスワードの長さや文字の指定、暗号化やリモートワイプなどデバイスのセキュリティを保つことができる
    - アプリ管理
        - 企業などが承認（許可）したアプリを配布したり、インストールできるようにしたりできる
    - 遠隔監視やサポート
        - 遠隔で状況を確認したり、デバイスの操作を行うことができる

> ほかにも製品によってできることやできないことが少しずつ変わってきます。
> 導入の際には、製品の特長を吟味して導入しましょう

## MDMを入れるメリットをまとめよう
### デバイスのセキュリティ強化
- アンチウイルスソフトや社内で必須としているアプリケーションの強制インストール、パスワード要件のしていまで数多くのことをこなすことができます
    - また、制限の厳しさをデバイスによって分けたりなど容易に行うことができます
### トラブルシューティング
- 遠隔で、導入されているアプリケーションのバージョンを確認したり、デバイスを操作することでトラブルシューティングに役立てることができます
    - 昨今では、働き方の多様化によってオフィス外での仕事も増えてきましたね
### デバイス紛失時の対応
- リモートロック（対象のPCを操作できないようにロックする）やリモートワイプ（遠隔でのPCデータ削除）を行うことができます
    - 端末には個人情報が保存されていることがあるため、悪用される前にシャットアウトすることが重要になってきます
### キッティング工数の削減
#### そもそもキッティングってなんぞ？
jBS様のサイトより
https://www.jbsvc.co.jp/useful/management/what_is_kitting.html
> キッティングとは、PCやスマートフォンなどのデバイスに各種設定やソフトウェアのインストールなどを行う作業全般のことを言います。
>セットアップやインストールとの違いは、英語のkitに、「装備一式を準備する」という意味があるように、エンドユーザーがすぐに業務に使用できる状態にまで準備するということです。

そんなキッティングを自動で行うことで、手作業の工数削減や情報の入れ間違えなどを防ぐことができます

## まとめ
本記事では、MDMの基礎をまとめてみました
まだまだ勉強中の身なので間違いがあったら是非指摘していただけると嬉しいです…！
今後も身につけた知識をアウトプットしていきます！

## 参考文献
https://www.jbsvc.co.jp/useful/management/what_is_kitting.html

https://www.jamf.com/ja/blog/what-is-mdm/
AWS re:Invent 2023 レポート (IoTお絵描きロボットのワークショップ)

# 1. はじめに
- AWS re:Invent 2023 に参加した。特に楽しかった/勉強になった内容についてまとめておく。
- 本記事では、お絵描きロボットを動かすワークショップについて紹介する。「現地ではこんな楽しいのができるんだよ」ということで、来年以降行く人の参考になれば... 

# 2. ワークショップの概要
- ワークショップ名：「IOT205 | Using generative AI & AWS IoT to build a 2D robot that draws pictures」
- できること：
    - Amazon Bedrock 上の Stable Deffusion で、好きな画像を生成する。
    - 生成した画像を描画用のものに変換し、AWS IoTを経由して手元のお絵描きロボットに送信する。お絵描きロボットがアームを動かし、ボールペンで実際に物理的に絵を描いてくれる。（以下動画の感じ）

![動くところ2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189302/0b77cced-22ce-dfd2-cb6d-40dcb7243e7c.gif)

# 3. ワークショップの進め方

# 3.1 アーキテクチャの説明

- 最初にアーキテクチャの説明がある。概要としては以下の通り（ちゃんとは理解できていないが...）。
    - AWS Amplifyで、フロントエンドWEBを作成する。
    - Amazon Bedrock(Stable Diffusion)で、入力されたキーワードに基づく画像を生成し、S3に保存する。
    - Lambda(Image vectorization function)で、画像を描画用のデータに変換する。
    - ロボット(図中のXIAO Sense)を、AWS IoT CoreでMQTT接続する。描画データに基づき実際にお絵描きするように指示する。

![構成図.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189302/15838396-8d7d-2dff-f365-ab3f4f2d03fb.png)

# 3.2 作業手順

- AmplifyでフロントエンドWEBを作成する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189302/cfd78f82-bbbb-7529-d1d9-fcdd1b295a4d.png)

- プロンプト「A picture of an astronaut on moon, riding a horse, 8k, photorealistic, hd」を入力すると、右側に宇宙飛行士の画像が生成される。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189302/c48cb6eb-46c0-4e82-ef30-0655b0bc8ff6.png)

- 生成された画像をボールペンでの描画が可能な感じのデータに変換する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189302/a8fbc696-5589-5297-da14-63655dd33532.png)

- お絵描きロボットを組み立てる。（バラバラの状態で渡されるので、アームやモーターをマニュアルに従いねじ止めしたり）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189302/fb3af43c-cd49-ce95-605f-a1c235826892.png)


- AWS IoT Core 経由のtopic送信により、「テスト用の四角形を描画せよ」「S3に保存されたデータに基づき描画せよ」などの命令を行い、ロボットに描画させることができる。（記事冒頭の動画参照）
- 周りの人は実際にAI生成された絵の描画もできていたが、私はwifi接続が安定せず、四角形の描画までしかできなかった。


# 4. 所感
- 真剣にAWS上の設定したり、ロボット組み立てたりして、あっという間の2時間だった。
- 実際に物理的に動くものを作れることで、「うわー勝手に動いて絵描いてる！」みたいな驚きがあり、こういうのを自分でもやってみたいというモチベーションにつながった。
プログラマーのための調和の取り方: マージとリベース

Gitのトピックブランチでの作業において、mergeとrebaseの使い方

Gitを使って開発を行う際に、トピックブランチで作業しているとアップストリームの更新があった時にどのように取り込むか悩むことがあります。この記事では、mergeとrebaseの違いと、rebaseをオススメする理由について説明します。

## mergeの問題点

一番単純な方法として、mergeコマンドを使ってアップストリームの変更を取り込むことがあります。しかし、mergeコミットを作ると、後で変更を差し戻す場合に問題が生じることがあります。実際に経験したことがある人なら分かると思います。

また、mergeコミットが含まれると、merge-baseなどのGitコマンドが使い物にならなくなることもあります。

## オススメしたいこと

```shell
$ git fetch
$ git merge origin/main # ← これを使用せずに
$ git rebase origin/main # ← こっちをオススメしたい
```

## rebaseの利点

rebaseコマンドは、アップストリームの変更を自分のブランチに取り込む方法の一つです。rebaseを使うと、作業ブランチのコミットをアップストリームの直後に並べ替えることができます。

rebaseの利点は、コミットを個別に操作できるため、後で取り消すことが容易であることです。また、rebaseを行うことで、コミットの履歴がシンプルで理解しやすくなるというメリットもあります。

## 注意点と混乱しないために

rebaseやpull、mergeなどのコマンドを使う際には、それぞれのコマンドの動作に注意が必要です。特に、手動でコミットを取り消す際には、これらのコマンドの違いを理解しておかないと混乱します。

また、コンフリクトが発生した場合にはrebaseを使う方が解決しやすいです。そして稀に遭遇するrerereという機能もあります。rerereは、コンフリクトの解消方法を記録しておくデータベースです。初期設定では3つの解消方法を持っているはずです。間違った解消を行い、後でresetするとrerereでハマることも稀にあります。

それでは、Gitのトピックブランチでの作業において、mergeとrebaseの使い方について説明しました。皆さんも適切な方法を選んで作業を進めてください。
【micro:bit】3度おいしい100均LED

# LEDジュエリーライト

LEDジュエリーライト（調光機能付）を100均で購入しました。

1. LEDでL-チカの実験ができます。
1. 半固定抵抗がついていて、アナログ入力の実験ができます。
1. スイッチ付きの電池ボックスとして使えます。

<table><tr><td>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252891/1bc2fecb-f242-4e6c-8620-69f57afbaf3f.png)

</td><td>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252891/e55b7a40-ccf1-0c33-90db-231041b71bff.png)

</td></tr></table>

## 調光ツマミの端子

調光ツマミには、３つの端子が出ています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252891/fa9f8377-93b1-2e78-53f2-18b88ecf151b.png)

:::note warn
**LEDの向き**
LEDの配線を外す前に、配線のプラス側とマイナス側とがわかるようなしるしをつけておきましょう。
:::

## 調光ツマミの配線

調光ツマミの端子とmicro:bitの端子とを次のように配線します。

**調光ツマミ**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252891/a6fbd0b3-102e-93ce-a036-3485261a7450.png)

## LEDの配線

LEDの配線のプラス側をmicro:bitの3Vに、配線のマイナス側をmicro:bitのP1に接続します。
P1をデジタル出力にして、LEDを点灯・消灯させます。

**LEDの配線**
![IMG_20231212_220100x.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252891/b77771d9-5835-65af-4486-620bcf64de35.jpeg)

:::note warn
**micro:bitとLEDの配線**
より明るくLEDを点灯させるために、LEDの配線のプラス側をmicro:bitの3Vに、配線のマイナス側をmicro:bitのP1に接続しています。
その為、P1の出力を1にするとLEDが消灯し、P1の出力を0にするとLEDが点灯します
:::

# 点滅速度をボリュームで変更するコーディング例

次のコーディング例では、アナログ値（P2の入力）を読み取って、グラフに表示したり、そのアナログ値でLEDの点滅速度を変えたりしています（一時停止の時間）。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252891/e4769206-c702-e51f-98a2-f35fd2d66ed6.png)

https://makecode.microbit.org/_KXXhsu5bXCRg

# おわりに

100均で購入したLEDジュエリーライトをmicro:bitに接続しました。

1. スイッチ付き電池ボックスとして利用できました。
1. アナログ入力の値が変化することを確認しました。
1. L-チカの点滅速度を調光ツマミで変化させました。
ISUCON13参戦記

この記事は、[大阪工業大学 Advent Calendar 2023](https://adventar.org/calendars/9108)の13日目の記事です 

二個目の参戦記はisuconについてである  

# ISUCONとは
そもそもとして、isuconとは何なのかというと  
「いい感じにスピードアップコンテスト」  
の略称である  
webサービスをチューニングしていき、より高速化できたチームが優勝できる  

# 前準備
前準備としてisucon11,12あたりをawsやさくらのクラウドを使って素振りをした。  
KOBA789さんの[ISUNARABE](https://isunarabe.org/)はAWSとgithubアカウントさえあればできるのでおすすめ  
なぜか立てたインスタンスが悪さしてるのかインスタンスを落として起動させたらスコアが0になるとかいう事態になったりしましたけど、レアケースだったと思いたい。  
さくらでたてた時もなぜか変な挙動をするときがあったのでなぜなんだろうと言ってた気がする  

# 本番
何もできませんでした...  
は、ある意味正解だがマジで何もしてないわけではないので箇条書きにしておく。  
- インスタンスを立てる  
ここで一やらかしとして1時間インスタンスを立てていた  
[AWS Cloudformation で　ROLLBACK_COMPLETE　となってしまう場合の対応](https://qiita.com/officefutaro/items/b597ec137bce7b9c6ad5)とかを見ていたがregionとかで怒られていたりしたのでどうしようもなかった  
本当にごめんなさい  
- nginxやmysqlへlogの設定を入れたり  
logが出力されない事態が発生したがただの記述ミスだった  
- DNS  
powerDNSってなに...?というところから調べていた  
結局よくわからんまま[さくらの記事](https://knowledge.sakura.ad.jp/34340/)を見つけたので一部実装してみるか！となった  
pdnsとdnsdistがどちらかをrestartすればどちらかが動かなくなったがpdns->dnsdistの順は分かったが、dnsdist->pdnsがなぜ動かなくなるのかが分からないまま時間が来た  
両方ともportがすでに使われてるよ！と怒られていた  
まあでしょうねという感想しかない

# 感想
今回のisuconではうちのチームの得点が6,495(再起動試験に失敗して最終スコアは0)なのに対し、優勝チームの得点が468,006であった。  

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">ISUCON13 競技終わり間近の私「40万点超えるってどういうかんじなんですか？」<br>fujiwaraさん「コードの中身を全て知っているけど8時間で出せないスコア、意味がわからない」<br>私「いわゆる秘孔を突かれてます？」<br>fujiwaraさん「なにもわからん」<br>私「わからんてことがわかりました」…</p>&mdash; 941 (@941) <a href="https://twitter.com/941/status/1730537761365758413?ref_src=twsrc%5Etfw">December 1, 2023</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>  

上記は運営の一人である941さんのX(元Twitter)  
運営ですら何もわからんことをしでかしている優勝チームはどんなことをしているのだろうと思う人は以下のリンクを見てみるといいと思う。  

[ISUCON13で優勝しました(チーム NaruseJun)](https://zenn.dev/tohutohu/articles/923bdf5dcd73af)  

再起動試験に失敗する理由が思いつかなかったので、感想戦を時間があるときにやりたい
Python×ElastiCache for Redis:初心者向け簡単チュートリアル1-文字列型-

## はじめに
AWS Elasticache for Redisは、スケールアウトと高速なキャッシングを提供するマネージド型のインメモリデータストアサービスです。このサービスは、データの読み込みと書き込みのレイテンシーを大幅に削減し、アプリケーションのパフォーマンスを向上させることができます。

しかし、PythonとElasticache for Redisを組み合わせた実装に関する情報は多くなく、特に初心者にとっては取り組みにくいかもしれません。

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

Redisの型は文字列型、ハッシュ型などがあります。

https://redis-documentasion-japanese.readthedocs.io/ja/latest/topics/data-types-intro.html

https://marunouchi-tech.i-studio.co.jp/3366/

今回は**文字列型**をPythonで扱う方法について解説します。明日(12/14)はハッシュ型を解説予定です。



:::note warn
以降のプログラムは、Redisのエンジンバージョンは`7.0`でテストをしています。
:::

## 内容
### 事前準備
ElastiCache for Redisを扱うためのライブラリ`redis-py`をインストールします。

```bash
(仮想環境)% pip install redis
```


### Redisとの接続

```python 
redis_host = 'エンドポイント'
redis_port = 6379
client = redis.Redis(host=redis_host, port=redis_port,decode_responses=True, ssl=True)
```

`decode_responses=True`とすると、バイト型の返り値がデコードされて返ってきます。
`ssl=True`は転送の暗号化を行っている場合に必須となります。。

### 文字列型:Redisへの書き込み
書き込みは以下のように`set`を使います。
```python 
key = 'id1'
value = 1
client.set(key, value)
```

:::note warn 
Redisのキーは必ず一意にしなければなりません。
:::

以下のように入れ子になっているjsonファイルをRedisに保存する場合は、以下のように記述すると良いです。

```json 
{
    "id1": {
        "a":1,
        "b":2
    },
    "id2": {
        "a":1,
        "b":2
    },
}
```

```python 
import json 

file_path = 'ファイル名'
with open(file_path, 'r') as file:
    data = json.load(file)
    for key, value in data.items():
        client.set(key, json.dumps(value))
```

:::note
入れ子の値を`json.dumps()`で**文字列にするのがポイント**です。
:::

### 文字列型:Redisへの読み込み

単一のデータを取得する場合のプログラムは以下です。
```python 
import json

key = 'id1'
res = client.get(key)
#書き込みでjson.dumps()していた場合に必要
if res:
    res = json.loads(res)
```

次に条件に該当する値を複数取得する場合のプログラムとして、２通りの書き方を紹介します。

```python 
import json

keys_condition = 'id*'

#パターン1:keysを用いる
matching_keys = client.keys(keys_condition) 

#パターン2:scanを用いる
cursor = 0
matching_keys = []
while True:
    cursor, keys = client.scan(cursor, match=keys_condition) 
    matching_keys.extend(keys)
    if cursor == 0:
        break
        
#パターン1&2共通
res = client.mget(matching_keys)
#書き込みでjson.dumps()していた場合に必要
res = [json.loads(r) for r in res if r is not None]
```

:::note warn 
パターン1&2はデータのサイズなどによって、どちらが速いかが異なります。実験して確かめることをオススメします。
:::

## おわりに
Python×ElastiCache for Redisの文字列型の使い方の解説は以上となります。

- ハッシュ型での実装はこちら

https://qiita.com/sergicalsix/items/381ac7c0e4b37a374936

- 前回までの類似記事はこちら

https://qiita.com/sergicalsix/items/74ac10a50aeb2cbc2bdf

https://qiita.com/sergicalsix/items/38bfed6e5fca7ac8e82e
【Next.js】クライアントコンポーネントにインポートされた際にエラーを発生させる方法

`server-only`をimportすることでコンポーネントがクライアントコンポーネントにインポートされた際にエラーが発生するようになります。

`server-only`をインストールします。

```terminal
npm i server-only
```

`server-only`をインポートします。

```
import "server-only"
```

また、以下のように`import "client-only"`を記述することでコンポーネントがサーバーサイドで実行された際にエラーが発生するようにできます。

```
import "client-only"
```
M12マウントのカメラモジュールを調査中

画像認識のシステムを作る際に、カメラモジュールを選ぶことがある。
そのための情報を探すヒントをM12マウントのカメラモジュールについてメモしようと思う。

## M12マウント（Sマウント）
M12マウントは、小型のレンズを取り付けるためのマウントです。
M12マウントのカメラモジュールとM12マウントのレンズとの組み合わせでは、視野角の異なるカメラを組み上げることができます。
#### 取り付け上の注意点
- レンズの焦点距離によって、レンズのホルダーの適度な長さが変わってくる。そのため、ホルダーをカットしたり、ホルダーを取り替える必要があることがある。
- M12マウントのカメラモジュールの場合、固定焦点であることが多い。
- レンズのピント調整の手順を標準化すること。
- ピント合わせができたら、レンズが動かないように接着剤で固定する。

## 調査方法
M12 camera などのキーワードで検索すると、M12のカメラモジュールやレンズのサイトが多数出てくるので、それをヒントにサイトにたどり着いてほしい。

## M12のカメラモジュールの着目ポイント
- 使用しているイメージセンサ
    - イメージセンサの大きさ
    - イメージセンサの画素数
    - イメージセンサのpixelの大きさ
    - イメージセンサの感度
- 固定焦点かオートフォーカス可能かどうか
    - 圧倒的に多数は固定焦点。
- イメージセンサの大きさとレンズのイメージサークル
    - レンズを通過した光は、像面にイメージサークルを作る。
    - そのイメージサークルの範囲だけが、意味のある画像範囲を作る。
    - 通常のカメラでは、イメージサークルが、センサ面をカバーするように作る。
    - 魚眼カメラ・全方位カメラなどの超広角のカメラでは、イメージサークルがセンサー面をカバーしきらなくなったり、イメージサークルがセンサ面の範囲に収まるようになったりする。
    - イメージセンサとレンズの組み合わせの選択は、必要な解像度が出るかどうかの性能の見極めの重要なポイントとなる。
- カメラの照度特性
    - 利用環境のなかで十分な輝度値・SN比が得られるかを確認すること。
    - イメージセンサの感度特性が重要になる
- 低照度環境ではどう考えるか
    - SN比が不足する場合には、 画素数を減らして、１つのpixelサイズの大きなイメージセンサを使うという方法がある。

## カメラモジュールのインタフェース
#### MIPI-CSI2
- カメラのモジュールの下位のインターフェースであることが多い。
- カメラモジュールのISP(image signal processor) のインタフェースを使ってカメラの制御・データの取得をすることとなる。
- [CSI-2 - MIPI規格編](https://www.macnica.co.jp/business/semiconductor/articles/lattice/142604/)

#### MIPI-CSI2インタフェースの動作確認
参考記事を示します。
- [マイコンでカメラモジュールから直接画像を取り込む方法](https://edn.itmedia.co.jp/edn/articles/2304/14/news026.html)
- [Ultra96 Linux で MIPI カメラから画像を取得する (解説編)](https://proc-cpuinfo.fixstars.com/2019/01/ultra96-linux-mipi-camera-explain/)
- [Raspberry Piとカメラモジュールを接続する](https://www.pc-koubou.jp/magazine/17276)
- [Jetson NanoにCSI-2カメラを繋いでみたー(1)](https://mirai-tec.hatenablog.com/entry/2021/08/09/175835)

#### USB インタフェース
さらにUSBというキーワードを追加して検索してみてください。

#### GMSL2 インタフェース
さらにGMSL2というキーワードを追加して検索してみてください。


## 解説記事
[組み込みカメラ用 M12 レンズを選ぶための究極の方法を教えます！](https://www.e-consystems.com/blog/camera/ja/technologies/ultimate-step-by-step-guide-to-choosing-an-m12-lens-for-your-embedded-camera-application/)

## 参考記事
- [M12(Sマウント)のレンズについて調査中](https://qiita.com/nonbiri15/items/635ba96cf2c8f82f5040)
- [Camera Serial Interface(CSI-2)のカメラを使う](https://qiita.com/nonbiri15/items/a60bcb6ba6acef4ba685)
M1 macでintelイメージなDockerコンテナを動かすときの備忘録

備忘録


# Dockerfileでintelイメージで作成するときのおまじない
（Rosetta 2は各自導入しておきましょう）

Dockerfile
```Dockerfile
FROM --platform=linux/x86_64 ubuntu:22.04

FROM --platform=linux/x86_64 php:8.1-apache-bullseye
```


# Apacheが起動しない
```
# /usr/sbin/service httpd start
Starting  
[Tue Dec 12 23:38:11.970835 2023] [core:emerg] [pid 2410] (95)Operation not supported: AH00023: Couldn't create the mpm-accept mutex 
(95)Operation not supported: could not create accept mutex
AH00015: Unable to open logs
httpd is started.
```

/etc/apache2/apache2.conf や /usr/local/httpd/conf/httpd.conf などの
confにMutex posixsemを追加する
```
#M1 MAC時追記
Mutex posixsem
```
Goのクロスコンパイルのありがたみを知る

# クロスコンパイル
Goはクロスコンパイルをサポートしています。
つまり、MacOS上でWindows上、Linux上それぞれで動作するバイナリを生成することができます。CPUアーキテクチャも複数サポートしています。

## クロスコンパイルできると
実行環境用のバイナリを生成できるということは、わざわざGoが動作する環境を用意する必要がありません。(Goの環境構築は比較的容易ですが)
もっというと、リポジトリをcloneする必要がなかったり、コンテナにはバイナリ一つ載せればよいということになります。

## クロスコンパイルできる環境
クロスコンパイルできる環境一覧です。
`OS/CPUアーキテクチャ`で表示されています。
```bash
$ go tool dist list
aix/ppc64
android/386
android/amd64
android/arm
android/arm64
darwin/amd64
darwin/arm64
dragonfly/amd64
freebsd/386
freebsd/amd64
freebsd/arm
freebsd/arm64
freebsd/riscv64
illumos/amd64
ios/amd64
ios/arm64
js/wasm
linux/386
linux/amd64
linux/arm
linux/arm64
linux/loong64
linux/mips
linux/mips64
linux/mips64le
linux/mipsle
linux/ppc64
linux/ppc64le
linux/riscv64
linux/s390x
netbsd/386
netbsd/amd64
netbsd/arm
netbsd/arm64
openbsd/386
openbsd/amd64
openbsd/arm
openbsd/arm64
plan9/386
plan9/amd64
plan9/arm
solaris/amd64
wasip1/wasm
windows/386
windows/amd64
windows/arm
windows/arm64
```

ビルドする際、`GOOS`, `GOARCH`で環境を指定します。
M1以降のMacOSの場合以下のようになります。
```bash
GOOS=darwin GOARCH=arm64 go build .
```

環境変数を指定してビルドを実行してみます。
実行環境はM1 Macです。

```golang:main.go
package main

import "fmt"

func main() {
	fmt.Println("Hello, World!")
}
```

```bash
$ GOOS=darwin GOARCH=arm64 go build .
$ ./main
Hello, World!
```

次に、linux用のビルドし、MacOSでの実行を試してみます。
```bash
$ GOOS=linux GOARCH=amd64 go build .
$ ./main
-bash: ./main: cannot execute binary file
```

## Docker上のLinux環境で試してみる
ubuntu環境に先程ビルドしたバイナリをコピーして実行してみます。
```Dockerfile
FROM ubuntu:latest

WORKDIR /app

COPY ./main .

ENTRYPOINT [ "./main" ]

```

実行します。
```
$ docker build -t go_exec_on_ubuntu .
$ docker run -it go_exec_on_ubuntu
Hello, World!
```
良さそうです。
【Rails】文字リテラルの活用法について考えてみた

## はじめに
Ruby技術者認定試験Goldの対策時に存在を知ったものの、~~一体何に使うんだろうこれ~~中々活用法を見出だせずにいた文字リテラルに関して、何か使い道が無いか考えてみたという~~ネタ記事~~雑記となります

## 今回見出だした用途
以下のような挙動を示すために、pメソッド等を埋め込んでの軽い動作確認時などにもしかしたら若干便利かもしれません
~~~
[1] pry(main)> ?A*100
=> "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
~~~

```ruby:pメソッドと組み合わせてみる
p ?🐌*10
```

~~~text:ターミナル出力
"🐌🐌🐌🐌🐌🐌🐌🐌🐌🐌"
~~~

## 文字リテラルの大まかな挙動
?a → "a"、?あ→"あ"というように、?マークの直後に何か1文字を置くと、その文字を返すという挙動を示す。2文字以上置くと構文エラーとなります

~~~
Running via Spring preloader in process 150
Loading development environment (Rails 7.0.7.2)
[1] pry(main)> ?A
=> "A"
[2] pry(main)> ?あ
=> "あ"
[3] pry(main)> ?🐌
=> "🐌"
[4] pry(main)> ?AA
SyntaxError: unexpected '?'
[4] pry(main)>
~~~

返り値は文字列(string)となるため、String#+や*が適用できます。~~そのため🐌を大量発生させてターミナル上でとても目立たせたり出来る(開発チーム内で流行)~~
~~~
[1] pry(main)> ?A*100
=> "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
[2] pry(main)> ?A + ?B
=> "AB"
[3] pry(main)>
~~~

```ruby
p ?🐌*1000
```

文字リテラルは現在非推奨となっているため、使用しているとRubocopに指摘されてしまうのですが、これによって万が一の消し忘れのリスクなどを軽減出来るかも(？)
~~~text:文字リテラル　〜*周りのスペース不足を添えて〜
Offenses:

app/controllers/test_controller.rb:9:5: C: [Correctable] Style/CharacterLiteral: Do not use the character literal - use string literal instead.
  p ?A*100
    ^^
app/controllers/test_controller.rb:9:7: C: [Correctable] Layout/SpaceAroundOperators: Surrounding space missing for operator *.
  p ?A*100
      ^
      
27 files inspected, 2 offenses detected, 2 offenses autocorrectable
~~~
## 何故非推奨なのか？
それには主に以下のような理由があるそうです
### 挙動が直感的で無いと感じる人も多いため
例えば、もし以下のようなコードを突然提示されたとしたら、(私を含めて)暫く困惑する方もいらっしゃるのではないでしょうか？
```text:文字なのか？変数なのか？
[1] pry(main)> x = 5
=> 5
[2] pry(main)> ?x
=> "x"
[3] pry(main)>
```

### Ruby 1.9を境に動作が大きく変化しているため
Ruby1.8以前の往時の文字リテラルは、「文字に対応するUTF-8/ASCIIコードを返す」という、現在のString#ordに近い挙動をしていたという過去を持つため、見る人によって想像する処理の内容が異なる可能性があります
~~~text:String#ord
[1] pry(main)> "a".ord
=> 97
~~~

## まとめ
個人的に活用法を見出だせずにいた文字リテラルでしたが、軽微な動作確認やデバッグ時に~~🐌をより簡便に量産できるため~~意外と役立つかもしれないと感じました。
他のメソッドに関しても便利な使い道がないか日常的に探っていければと思います😊

## 参考にさせて頂いた記事
https://docs.ruby-lang.org/ja/3.2/doc/spec=2fliteral.html#char

https://docs.ruby-lang.org/ja/latest/method/String/i/=2a.html

https://docs.ruby-lang.org/ja/latest/method/String/i/ord.html

https://zenn.dev/universato/articles/20230409-z-ruby-char-literal
月間降水日数を計算してみる

# 概要
**月間**降水日数（日降水量が1mm以上の日数）を計算したいと思い，気象庁からデータを収集してプログラムを組んだという話です．

短いですが，記事にしてみました．

# データ収集
地道な作業ですが，「気象庁｜過去の気象データ・ダウンロード」から，各都道府県庁所在地を47つ選択し「日降水量」としてダウンロードしました．

今回は2018～2022年の5年間分のデータを集めました．

https://www.data.jma.go.jp/gmd/risk/obsdl/index.php

残念ながら，1回あたり半年ぶんくらいしかダウンロードできなかったので，2×5年分＝10回にデータが分かれてしまいました．

# データ処理

データを処理して集計します．

まず，1年分のデータが半年ずつになっているので1つにまとめて`2018.csv`などとしました．
ついでに不要な行などは削除しておきました．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1900599/1f7d2b39-4116-5afe-5fa6-6127bde54cb6.png)

そうしましたら，降水日数の集計に取り掛かります．
集計処理全体のコードは以下のようになります．

```python
import pandas as pd

rainy_days = dict()

for year in range(2018,2023):
    df = pd.read_csv(f'{year}.csv', encoding='shift-jis')
    df['date'] = pd.to_datetime(df['date'], format='%Y/%m/%d')
    df.set_index('date', inplace=True)

    # '.1'がついていない列を抽出
    df = df[df.columns[df.columns.str.contains('\.1') == False]]

    # 1.0以上なら1、1.0未満なら0に変換
    is_rain = df >= 1.0
    is_rain = is_rain.astype(int)

    # 月毎の降水日数
    rainy_days_ = is_rain.resample('M').sum()
    rainy_days_.index = rainy_days_.index.month
    rainy_days_.index.name = 'month'
    rainy_days[year] = rainy_days_.copy()

rainy_days['mean'] = sum([rainy_days[year] for year in range(2018,2023)]) / (2023-2018)
```

辞書型の`rainy_days`に各年の降水日数が入ったDataFrameを格納していきます．

各年`year`に対して，

1. csv読み込み
1. date列をdatetime型へ変換
1. 余分な列を削除
1. 日降水量1mm以上ならそのセルを1へ，1mm未満なら0へ置換
1. `.resample('M')`を使って月毎に合計値を出す
1. `rainy_days`へ格納

という処理を行います．最後に，5年間分の降水日数平均をとったDataFrameも追加しておきます．

**日降水量1mm以上**は，気象庁の下記サイトに基づいています．

https://www.data.jma.go.jp/cpd/longfcst/kaisetsu/tenkinissuu/tenkinissuu.html

そして，結果を可視化したのがこちら．

**京都府の2022年の各月の降水日数**
![京都_2022.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1900599/f2222299-d8e3-d473-b302-b0dea4b86f39.png)

**各月の降水日数平均の，全都市に関する中央値**
![median_mean.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1900599/d803c66a-cfe0-bf3d-506c-5edf4152b7f6.png)

やはり季節の変わり目にあたる3月,7月,9月とかは降水日数がやや多めですね．

ソースコードの`YEAR`や`REGION`をいじればいろいろ試せるようになっています．

```python:可視化部分
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.family'] = 'Meiryo'

REGION = '京都'
YEAR = 2022

if REGION in ['mean','median','max','min']:
    result = rainy_days[YEAR].agg(REGION, axis=1)
else:
    result = rainy_days[YEAR][REGION]
plt.bar(rainy_days[YEAR].index, result, zorder=2)
for i, v in enumerate(result):
    plt.text(i+1, 0, f'{v:.1f}', ha='center', va='bottom', color='white')

plt.title(f'REGION={REGION}, YEAR={YEAR}')
plt.xlabel('月')
plt.ylabel('降水日数')
plt.xticks(np.arange(1,13))
plt.grid()
plt.show()

```

# ソースコード

Qiitaアドベントカレンダーで使ったコードはこちらのレポジトリにまとめています．

本記事のコードは`10-rainfall`の中に入っています．

https://github.com/matsuda-tkm/qiita-calender-2023
オブジェクト指向UIデザインと向き合ってみた

# はじめに
本記事は[All About Group（株式会社オールアバウト） Advent Calendar 2023](https://qiita.com/advent-calendar/2023/allabout)の15日目の投稿です。

今回は [オブジェクト指向UIデザイン──使いやすいソフトウェアの原理 (WEB+DB PRESS plusシリーズ)](https://amzn.asia/d/h8TeyxD) を読み、ワークを実践してみて学んだことや感想をまとめた記事になります。
私は現在、弊社が運営するBtoBコンテンツマーケティングプラットフォームである[PrimeAd](https://www.primead.jp/)の開発に携わっています。その際、機能の実装だけではなく、ユーザーの課題を解決するためのHowを画面に落とし込むプロトタイピングから担当することがあります。約1年ほど担当し感覚的には慣れてきましたが、ユーザーが増えつつある現在、より快適なUIを提供できるようになりたいと思い、改めて勉強しようと本書を手に取りました。

# オブジェクト指向UIだとなにが嬉しいか
オブジェクト指向のUIは、対象となる物事（オブジェクト）と、それに何をできるかということがユーザーに見えている状態です。対立する概念として紹介されるタスク指向UIは、設計者や管理者がユーザーに行わせたいタスクが前提にあり、それを思い通りに実行させるためだけの動線が用意されている状態です。両者の特徴的な違いとして、オブジェクト指向UIは名詞が先行し、まずオブジェクトを選んでから行動を選ぶこと、タスク指向UIは動詞が先行し、まず行動を選んでからそのパラメータとしてオブジェクトを選ぶことが紹介されています。
タスク指向UIでは、特定のタスクを実現するために、ユーザーの行動の自由度を下げたり、ユーザーにとって複雑な手順になったりする場合があります。オブジェクト指向UIであればユーザーは最初から対象そのものやその性質、状態、できることなどを把握した上で行動できるため、迷ったり無駄な動作をすることが少なくなります。また、タスク指向の場合画面遷移や内部処理が増え保守が困難になるなど、開発者にとってもデメリットがありますが、これらもオブジェクト指向に沿えば改善するとされています。

# 持ち帰りたいところ
知らなかったことや考えを改める必要があると感じたのはこのようなところです。
## 良いデザインにはユーザーが自ら合わせられる
ユーザーがそれぞれ抱く具体的な要求に応えようとすると他のユーザーには使いにくくなっていくので、ある程度ユーザーが共通して持っている心理や性質にあわせてデザインをしようということが説明されています。それ自体はなんとなく知っていたのですが、ある程度ユーザーのニーズを切り捨てるようなネガティブな感覚がありました。そうではなく、ユーザーが与えられた道具（UI）に対して適応して望む行動を実践できるのなら、それが良いデザインであるというのが意外なところでした。まずオブジェクトがあり、それに何ができるかをあらかじめ示しておけるオブジェクト指向のUIは、ユーザーに見通しを与えてある程度自由に目的を達成させられるためこのようなデザインに合っているということです。

## タスクは変わっていく
これは私自身も担当サービスの使われ方を見て感じるところですが、タスクは進行するうちに増えたり変わったり、実行前の想像とは異なる形になることがあるとされています。タスク指向で作っていけば対応にきりが無いのは明らかですが、オブジェクト指向の場合通常オブジェクトとアクションの組み合わせで表されるタスクが、ときにそれだけでは実現できないところも出てきます。その場合、タスクを反映する方法として次のような方法が紹介されています。
- 表示形式に反映する
  - 同じオブジェクトでも、強調するプロパティを変えるとそれにフォーカスして行うタスクを実行しやすくなる
  - たとえば、店のリストとして名前の文字列を羅列するか、外観の写真を強調するか、地図にマッピングするかで想像する使い方が変わる
- 初期値に反映する
  - 入力フォームの初期値を設定することで、入力してほしい内容をある程度限定したり入力を省略させたりする
- フィルタリンググループに反映する
  - 同じオブジェクトのコレクションでも、フィルタリングされたグループによってタスクが異なる場合があるので、予めフィルタリングされたグループを意識させる
  - たとえば、注文のリストは「未完了」「発送済み」「完了」に最初から分かれていれば、発送したいときどのグループを見ればよいかわかる

# ワークをやってみて
いくつかの課題を解決するアプリケーションのUIを設計してみるワークが紹介されています。こちらを実践してみて最も感じた課題は以下のとおりです。
## オブジェクトの汎化
実現したいタスクに登場する言葉からオブジェクトを抽象化するのはある程度できているようですが、さらに一段汎化するということがなかなかできませんでした。たとえば、会議室を予約するアプリケーションの例で、オブジェクトを「会議室」ではなく「スペース」と考える、会議室のディスプレイの有無を確認したいというタスクから「ディスプレイ」を「設備」として汎化する、といったことに思い至りませんでした。逆に言えば、会議室の他にホール、ディスプレイの他にホワイトボードなどの例が出せれば気づけたのではないかと思います。
本書にも記述のあるとおり、最初から作るものの理想形を直接イメージすることはできず、目についた問題箇所を直すことでしか理想に到達することはできません。一番最初のプロトタイプの時点から、このオブジェクトを元にしたUIが実装されている世界で、課題を抱えたユーザーなら何をするか、特に課題と思っていないユーザーなら何をするか、というのをある程度具体的にシミュレーションしていくことが解決につながるのではないかと考えます。

# 最後に
感覚でやっていたところを再確認する部分が多いのかなと考えていましたが、想像以上に新たな発見がありました。この記事を読むエンジニアの方の中でも実務で似たようなことをしている方はそう多くはないかもしれませんが、何かの役に立てば幸いです。

# 参考文献
ソシオメディア株式会社 (著), 上野 学 (著, 監修), 藤井 幸多 (著). オブジェクト指向UIデザイン──使いやすいソフトウェアの原理 (WEB+DB PRESS plusシリーズ. 技術評論社. 2020年
AWS JavaScript SDK v3のテストでMockを使う

# 背景

Lambdaで実行する関数で使っているAWS-SDKをv2からv3に移行するに伴って、単体テストコードも修正が必要になった。
この記事は、v3における単体テストでAWSの各サービスへのアクセスをMockにする方法と、テストの実施方法についての記事になります。

# 準備

v2の時にはaws-sdk-mockを使っていたが、v3ではaws-sdk-client-mockを使う。
また、jestでのテストを便利にするためにaws-sdk-client-mock-jestも使用する。

```
npm i aws-sdk-client-mock aws-sdk-client-mock-jest
```

# テストコード

## Mockの作成

```javascript
require("aws-sdk-client-mock-jest");
const { mockClient } = require('aws-sdk-client-mock');

const { DynamoDBDocument } = require('@aws-sdk/lib-dynamodb');
const { CognitoIdentityProvider } = require('@aws-sdk/client-cognito-identity-provider');
const { SES } = require('@aws-sdk/client-ses');

// 省略

beforeAll(() => {
  DynamoDBMock = mockClient(DynamoDBDocument);
  CognitoIdentityProviderMock = mockClient(CognitoIdentityProvider);
  SESMock = mockClient(SES);
});
```

mockClientに各サービスを渡してあげればよい。

## 結果を編集する

テストに応じてAWSの各サービスから返ってくる値を変更したい場合は下記のようにする

```javascript
// DynamoDBは使うコマンドも読み込んでおく
const { QueryCommand,PutCommand,DeleteCommand } = require('@aws-sdk/lib-dynamodb');

// 省略

beforeEach(() => {
  DynamoDBMock.reset();
  CognitoIdentityProviderMock.reset();
  SESMock.reset();

  DynamoDBMock.on(QueryCommand).resolves({ Items: [] });
  DynamoDBMock.on(PutCommand).resolves({});

  CognitoIdentityProviderMock.onAnyCommand().resolves({});

  SESMock.onAnyCommand().resolves({});
});

```
作成したモックに対してonでコマンドを指定し、resolvesに返したい値を設定すればよい。
全てのコマンドを一括で設定する場合はonAnyCommandを使う。

## 結果を呼び出した順番に応じて変える

```javascript
DynamoDBMock.on(QueryCommand)
  .resolvesOnce({
      Item: [],
    })
  .resolvesOnce({ Items: [{
    ID:XXX,
    Name:XXXXXX
  }] })
  .resolves({ Items: [] });
```
resolvesOnceを使うと最初の１回だけ返したい値を変更できる。
また、resolvesOnceを続けて記述することで２回目の呼び出し、３回目の呼び出し・・・と返したい値を設定できる。
最後にresolvesをつけておけばそれ以降の呼び出し全ての返したい値を設定できる。

## 例外をスローさせる

```javascript
CognitoIdentityProviderMock.onAnyCommand().rejects({ code: 'UserNotFoundException' });

CognitoIdentityProviderMock.onAnyCommand()
      .rejectsOnce({ code: 'UserNotFoundException' })
      .resolves({});
```
rejectsを使うと例外をスローさせることができる。
また、rejectsOnceを使えば呼び出し回数に対応して例外を出すこともできる。

# 課題

- ヘイロードに応じて返す値を変えることもできるようだが、v2の時のテストでonCall(n)を使っていたものを移行したので今回は使用せず、ここに説明を挙げることができなかった
- Cognitoでコマンドを限定して返す値を設定する方法がわからかった。

上記、特に２つ目の件で何か情報をお持ちの方いましたらぜひコメントください。
ssh接続を最速で再接続する

/darallium/です！ご覧いただきありがとうございます。 😊


本日は「ssh接続を最速で再接続する」方法を紹介します:relaxed:

# introduction

僕はメインで用いる開発環境を自鯖に置いてオンライン化している。
小さな開発ではいまだに手元のエディタを使うことは当然ある。しかし、多くの時間ではやはりリモート接続先で開発しているのだ。

そこで、ある問題が発生する。Windows OSの環境でターミナルを開いているとき、リロードがめんどくさいのである。

この記事では、開発環境をオンライン化するにあたって起きた問題の一つを解決する方法を提示する。

# 問題

Windows OS環境では多くの人が`Windows Terminal`を使用しているだろう。筆者も利用している。

`Windows Terminal`を使用しているとき、あるプラクティスとして「sshコマンドを直接プロファイルに置くことで、よくアクセスするサーバーに簡単にアクセスできるようになる」というライフハックがある。`~/.ssh/conf.d/`以下に十分に設定していることを前提とすれば、`ssh <user>@<Host>`を記述すればよい。

しかし、ここである問題が発生する。開発をするとき、設定をいじった影響で環境を再読み込みしたい場合がある。`vscode`ならば、`ctrl + shift + p  + reload window`であろう。これを、ssh環境下で行う、すなわち接続を絶った場合には、一番親のプロセスが死んでしまいタブが閉じてしまうのだ。タブが閉じてしまった場合、専用のショートカットキーを割り当てていない限り**マウス操作が必要になってしまうのだ。**

# 解決法
1. 以下を.bashrcに記述する。
    ```shell
    if [ -n "$SSH_CONNECTION" ] ; then
      reload ()
      {
        exit 1
      }
    fi
    ```

2. Windows Terminalの対称のプロファイルの「プロファイルの終了時の動作」を自動またはプロセスが正常に終了したときのみ閉じるに設定する。
3. relaodコマンドでターミナルを終了する


man sshを眺めていたところ、SSH接続中にセットされる環境変数があることに気が付いた。`SSH_CONNECTION`である。これは、SSH接続元とそのポートを記述している環境変数らしい。

実際にssh接続先でやってみたところ、以下のようになった。
確かに、手元の環境が記述されている。
```shell
$ env | grep SSH
SSH_CONNECTION=<localip 1> <localport 1> <localip 2> <localport 2>
SSH_CLIENT=<localip 1> <localport 1> <localport 2>
SSH_TTY=/dev/pts/0
```


そして、Windows Terminalには以下のようなオプションがある。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/196553/f60bd07b-c25a-9141-8ed2-d4e9ca7aacef.png)

プロセスが正常に終了したときのみ閉じる
⇔プロセスが**異常終了したら閉じない**

ここで、linuxのexitコマンドは、引数に終了時の値＝エラーレベルを記述できる。異常終了は0以外をセットしてやればよい。


# referencing

https://nxmnpg.lemoda.net/ja/1/ssh
pytestでパラメータ化する3つの方法を端的に with サンプル

今日は、pytestのパラメータ化について書いておく。

# 要約

|方法|メリット|デメリット|
|---|---|---|
|@pytest.mark.parametrizeを利用する|直感的にかける|前処理、後処理が出来ない|
|@pytest.fixtureを利用する|前処理、後処理ができる|テストが冗長になる。|
|pytest_generate_tests(フック関数)を利用する。|複雑なデータセットで検証できる|直感的でない|

個人的には、

>前処理、後処理が不必要な場合：@pytest.mark.parametrize
>前処理、後処理が必要な場合：@pytest.fixture

で使い分けている。
※ まだ、pytestを書き始めたばかりなので、pytest_generate_testsの強みが・・・・

## 対象ソースコード

```python
def add(a: int, b: int):
    return a + b
```

## @pytest.mark.parametrize

```python
@pytest.mark.parametrize("x,y,result", [(1, 2, 3), (-1, 2, 1), (-1, -4, -5), (0, 0, 0)])
def test_add(x, y, result):
    assert result == add(x, y)
```

「x,y,result」がそれぞれの引数に入るので直感的でわかりやすい。

## @pytest.fixture

```python
@pytest.fixture(params=[(1, 2, 3), (-1, 2, 1), (-1, -4, -5), (0, 0, 0)])
def start_state(request):
    print("前処理")
    yield request.param
    print("後処理")

def test_add_pytest_fixture(start_state):
    x, y, result = start_state
    assert result == add(x, y)
```

1. start_stateの中で、前処理、及び 後処理が記載できる。(yieldを使うことで、各行で呼び出し元に行く)
1. request.paramの中に@pytest.fixtureのparamが入っている。
1. テストの引数で@pytest.fixtureがついているメソッド名を記載する。(pytestが自動で読み込んでくれる)

やはり、「前処理」と「後処理」がかけるのが強みであろう。
一方で、メソッドを追加しないといけないので多少冗長である。
また、引数のstart_stateがvscodeとかで紐づかないので多少厄介でもある。

ちなみに、
```bash
pytest -s
```
で、「print」の結果が表示されるので試されたい。

## pytest_generate_tests(フック関数)

```python
def pytest_generate_tests(metafunc):
    if "gen_param" in metafunc.fixturenames:
        metafunc.parametrize("gen_param", [(1, 2, 3), (-1, 2, 1), (-1, -4, -5), (0, 0, 0)])


def test_add_pytest_generate_tests(gen_param):
    x, y, result = gen_param
    assert result == add(x, y)

```

上だけだと、あまりこのフック関数を使うメリットは少ないように見える。
ただ、「metafunc」というものがとてつもなく強力らしい。

https://docs.pytest.org/en/7.1.x/reference/reference.html#metafunc

例えば、
```python
def pytest_generate_tests(metafunc):
    if "stringinput" in metafunc.fixturenames:
        metafunc.parametrize("stringinput", metafunc.config.getoption("stringinput"))
```

上記みたいに書くと、下記で、「hello」と「world」の2回のテストが実施できる。
```python
pytest -q --stringinput="hello" --stringinput="world" ファイル名.py
```

引数で制御できるのはたまには強みになる可能性もある。

以上
p5.js と Tween24.js を組み合わせたお試し：イージングのブレンド【完走賞ゲット-13】

:::note info
※ [Qiita の完走賞をゲットするための条件は「単一／複数のカレンダーに投稿した記事が合計25」です](https://twitter.com/Qiita/status/1593441648796524545)
:::

この記事は、「[完走賞ゲットのため小ネタ 25記事を投稿しようとチャレンジ v2 Advent Calendar 2023](https://qiita.com/advent-calendar/2023/youtoy)」の 13日目の記事です。

## 今回の内容
今回の内容は、以下の記事の続きにあたるものです。

●p5.js と Tween24.js を組み合わせたアニメーション・イージングのお試し 【完走賞ゲット-12】 - Qiita
　https://qiita.com/youtoy/items/ad2ade71d73fa2298723

前回の記事では、まずは p5.js と組み合わせる方法を探して、簡単なサンプルで試してみました。今回はその続きで、連続したアニメーションなど前回よりは少し複雑なアニメーションを扱えそうな内容を試します。

## Tween24.js とは
[前回に引き続き、描画ライブラリの p5.js と組み合わせる「Tween24.js」は、メソッドチェーンでアニメーションが書けるライブラリ](https://qiita.com/youtoy/items/ad2ade71d73fa2298723#tween24js-%E3%81%A8%E3%81%AF
)です。

 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/e639daa0-5c08-ff9f-e1c3-6a0383ef9821.png)

## Tween24.js を使ったお試し
### Tween24.js で試す機能を選定する
前回は軽いお試しだったので、今回は「Tween24.js」の特長的な部分を試せればと思います。

イージングの機能はよく使いそうなところかな、と思ってそのあたりを見ていくと、「カスタマイズ」「ブレンド」といった便利そうな仕組みがありました。

![イージングの種類](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/d1137128-bf38-10e7-4dff-d274c6a1f0e8.png)

それらの中でもブレンドは、自分にとっては活用しどころがたくさんありそうでした。
そこで、このイージングのブレンドを実際に試してみようと思います。

#### イージングのブレンドの処理
イージングのブレンドについて、公式の記事内の記載を見てみます。

```javascript
// Ease24._Blend(イージングA, イージングB, AからBへの変化量)
const blendEasing = Ease24._Blend(Ease24._6_ExpoIn, Ease24._BounceOut, Ease24._6_ExpoInOut);
Tween24.tween("#box1", 1, blendEasing)...
```

`Ease24._Blend()` で、ブレンドしたい複数のイージングを指定するようです。
さらに、そのブレンドした内容を、Tween24.tween() の第三引数（イージングの種類を指定する部分）で使ってやれば良いようです。

#### イージングのブレンドを p5.js と組み合わせる
公式のサンプルを、p5.js と組み合わせて試してみました。

まず実行結果を掲載してみます。

<iframe width="560" height="315" src="https://www.youtube.com/embed/IKZCXRymkCg?si=KbB7tpxnL1uKrfPw" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>

見た感じ、異なる複数のイージングが適用されているように見えます。

具体的な実装内容は、以下のとおりです。

```javascript
let tweenData, tween;

function setup() {
  createCanvas(500, 400);

  tweenData = { progress: 0 };

  const blendEasing = Ease24._Blend(
    Ease24._6_ExpoIn,
    Ease24._BounceOut,
    Ease24._6_ExpoInOut
  );

  tween = Tween24.tween(tweenData, 1, blendEasing, { progress: 1 });
}

function draw() {
  background(220);

  const x = tweenData.progress * width;
  circle(x, height / 2, 100);
}

function mouseClicked() {
  tween.play();
}
```

## おわりに
今回、Tween24.js を使ったイージングを p5.js と組み合わせて使ってみました。
単純なイージングは前回の記事を書いた時に試していたのですが、今回はイージングをブレンドする機能を試してみました。

動きの中に複数のイージングを簡単に含められる処理は、使いどころがいろいろありそうです。
【Rails】permit!メソッドで詰まった話

# はじめに
あるシステムの開発中にBrakemanで「Specify exact keys allowed for mass assignment instead of using permit! which allows any keys」という警告が表示され詰まった時のお話です。

# 問題
Brakemanで警告が表示されたコードは下記です。
~~~
params.permit![:hoges].to_h
~~~
原因を調査したところ、permit!メソッドを使用するとすべてのキーが許可されてしまうことや後から追加したキーも許可されてしまうため、Brakemanは警告を表示してそうでした。

# 解決策
permit!メソッドではなくpermitメソッドで許可するキーを指定するように変更しました。
下記は変更後のコードです。
~~~
params[:hoges].permit(key).to_h
~~~

# おわりに
permit!メソッドはセキュリティリスクを高めるため、可能な限りpermitメソッドを使用した方がよさそうです。誤り等ありましたらご指摘いただけると助かります！

# 参考

https://pikawaka.com/rails/permit
【Lua】lua-cjson で空配列を扱う

Lua では「配列」「オブジェクト」どちらも `table` として実装されており、空テーブル `{}` はどちらなのかわかりません。

`lua-cjson` を使ってテーブルを JSON にするとき、これをなんとか区別したくなります。

https://github.com/openresty/lua-cjson

# 空テーブルは空配列だったことにする
```lua
cjson.encode_empty_table_as_object(true)
```

この設定を使うと空テーブルが空配列として扱えます。簡単ですが、空オブジェクトであってほしいときも空配列になります。

# `encode` 時、空なら空配列にエンコードされるようにする
```lua
local arr = {}
setmetatable(arr, cjson.empty_array_mt)
```

配列とわかっているものにメタテーブルをセットしてあげるようにすると、空のときに空配列になってくれます。

# おわり
動かしていないのであとで動かします。
【Docker】GLIBCのバージョンが見つからない【WSL2】

## 課題
Ubuntu 20.04.6 LTS（WSL2）でDockerコマンドを実行しようとしたところ下記メッセージが表示され、実行できなかった。

## メッセージ内容
```
/mnt/wsl/docker-desktop/cli-tools/usr/bin/com.docker.cli: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.32' not found (required by /mnt/wsl/docker-desktop/cli-tools/usr/bin/com.docker.cli)

/mnt/wsl/docker-desktop/cli-tools/usr/bin/com.docker.cli: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.34' not found (required by /mnt/wsl/docker-desktop/cli-tools/usr/bin/com.docker.cli)
```
必要なGLIBCのバージョンが見つからないらしい。

## 実行失敗時のUbuntu バージョン
[Ubuntu 20.04.6 LTS](https://apps.microsoft.com/detail/9MTTCL66CPXJ?hl=ja-jp&gl=JP)

## 解決策
Ubuntuのバージョンを変える
[Ubuntu 22.04.3 LTS](https://apps.microsoft.com/detail/9PN20MSR04DW?hl=ja-jp&gl=JP)

## できた！
docker --versionコマンドが通るようになった。
```
Docker version 24.0.7, build afdd53b
```
個人開発者が使っているSnykの利用方法

私は本業の傍ら個人開発をしており、脆弱性診断ツールとして[Snyk](https://snyk.io/jp)を利用しています。
個人開発者としては、
- なるべく自分でやることを最小限にしたい
- フリープランでもかなりの機能が使える

という点がありがたいなと思っていて、プロジェクトを作ったらいつもすぐに導入しています。

今回は、 **Snykでできること** と **普段私がどのようにりようしているか** を記します。
（導入方法などは、割愛します。）

# Snykでできること

### ライブラリの脆弱性検知とその対応

「+Add Project」からGithubのリポジトリを選択すると、自動でそのプロジェクトを解析しライブラリの脆弱性チェックを行ってくれます。

脆弱性対応が必要な場合は、そのライブラリとバージョンを何に上げればよい（Fixed in）か、脆弱性識別子などを示してくれます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256444/a145d60b-9bc2-10a4-44f7-794440601046.png)

### コードの脆弱性診断

たとえば、httpモジュールを利用してサーバーを立ててリクエストを受けたら`Hello World`を返す実装があったとします。

```javascript
const http = require('http');

const server = http.createServer((req, res) => {
  res.writeHead(200, { 'Content-Type': 'text/plain' });
  res.end('Hello World');
});

const PORT = 3000;
server.listen(PORT, () => {
  console.log(`Server running at http://localhost:${PORT}/`);
});
```

`http.createServer` の場合平文で通信することになるので `https` モジュールを利用するように提案してくれます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256444/407f6ba4-d6fe-0eab-682b-ddfbefbaa27c.png)


# 普段どのように利用しているか

### Pull Requestでの脆弱性検査

Pull Requestを作成したり、コミットを積んだ際に、CIとしてライブラリの脆弱性検査を走らせるようにしています。
`package.json`に変更を積んでいないときでも検査してくれるので、すぐに検知することができ、大変便利です。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256444/4d9317c4-fb1a-7c6b-5c0b-3e461730f822.png" width="680" />

### Slack通知

Integration設定からSlackと連携し、脆弱性が出た際にSlack通知をすることも可能です。

![スクリーンショット 2023-12-12 23.06.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256444/e6365e70-8c51-af33-e6f2-cdd090884294.png)

### VSCodeとの連携

私は、エディタとしてVSCodeを利用していますが、SnykのExtensionとして下記のものがあります。

https://marketplace.visualstudio.com/items?itemName=snyk-security.snyk-vulnerability-scanner

これを導入すると、

- ライブラリ脆弱性検査
- ソースコードの脆弱性診断

をやってくれます。

例えば、 プロジェクトでpackage.jsonが存在する場合、ライブラリにいくつの脆弱性が出ているかを判断しているかを表示してくれます。

<!-- ここしゅうせい -->
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256444/a223b3dd-d31c-0953-85a2-5b267e5ec15c.png)

ソースコードの脆弱性診断についても、以下のように脆弱性についてのモーダルを出してくれます。
Githubから実際の例を参照する を押すと脆弱性を回避する方法も場合によっては提案してくれるので大変助かります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256444/6459037e-180c-cca1-1a34-d56e544d00c9.png)

# まとめ

脆弱性については、プロジェクトを運用していて必ず対応しなければならない問題なので、Snykを活用してなるべく自動化することをおすすめします。
java 8のLocalDateTimeクラスのisAfterとisBeforeが分かりにくかったため表にしてみた

# LocalDateTimeクラス
LocalDateTimeクラスの日時を比較するのにisAfterとisBeforeを使用するが、毎回どっちがどっちなのかが分からなくなるため表にしてみました。

https://docs.oracle.com/javase/jp/8/docs/api/java/time/LocalDateTime.html



|  | <font color="red">**a**</font> |  <font color="green">**b**</font>  | <font color="red">**a**</font>は <font color="green">**b**</font>より<font color="orange">**前**</font><br><font color="red">**a**</font>.is<font color="orange">**After**</font> <font color="green">**b**</font> | <font color="red">**a**</font>は <font color="green">**b**</font>より<font color="yellowgreen">**後**</font><br><font color="red">**a**</font>.is<font color="yellowgreen">**Before**</font> <font color="green">**b**</font> | <font color="green">**b**</font>は <font color="red">**a**</font>より<font color="orange">**前**</font><br><font color="green">**b**</font>.is<font color="orange">**After**</font> <font color="red">**a**</font> | <font color="green">**b**</font>は <font color="red">**a**</font>より<font color="yellowgreen">**後**</font><br><font color="green">**b**</font>.is<font color="yellowgreen">**Before**</font> <font color="red">**a**</font> |
|---|---|---|---|---|---|---|
|a：新しい<br>b：古い|2023/12/12  00:00:00  |2023/12/11  23:59:59  |<font color="lightblue">**false**</font>  |<font color="pink">**true**</font>  |<font color="pink">**true**</font>  |<font color="lightblue">**false**</font>  |
| 同日同時刻 |2023/12/12  00:00:00  |2023/12/12  00:00:00  |<font color="lightblue">**false**</font>  |<font color="lightblue">**false**</font>  |<font color="lightblue">**false**</font>  |<font color="lightblue">**false**</font>  |
| a：古い<br>b：新しい |2023/12/12  00:00:00  |2023/12/12  00:00:01  |<font color="pink">**true**</font>  |<font color="lightblue">**false**</font>  |<font color="lightblue">**false**</font>  |<font color="pink">**true**</font>  |<font color="pink">**true**</font>  |


## isAfter
>この日付/時間が、指定された日付/時間より後にあるかどうかをチェックします。
   LocalDate a = LocalDateTime.of(2012, 6, 30, 12, 00);
   LocalDate b = LocalDateTime.of(2012, 7, 1, 12, 00);
   a.isAfter(b) == false
   a.isAfter(a) == false
   b.isAfter(a) == true

https://docs.oracle.com/javase/jp/8/docs/api/java/time/LocalDateTime.html#isAfter-java.time.chrono.ChronoLocalDateTime-

## isBefore
>この日付/時間が、指定された日付/時間より前にあるかどうかをチェックします。
   LocalDate a = LocalDateTime.of(2012, 6, 30, 12, 00);
   LocalDate b = LocalDateTime.of(2012, 7, 1, 12, 00);
   a.isBefore(b) == true
   a.isBefore(a) == false
   b.isBefore(a) == false

https://docs.oracle.com/javase/jp/8/docs/api/java/time/LocalDateTime.html#isBefore-java.time.chrono.ChronoLocalDateTime-
[Go]パート4

# はじめに
訳あってGo言語を勉強することになりました。
完全に自分のメモ用です。
馴染みのない書き方を中心にメモしていきます。

## func
```go:main.go
package main

import "fmt"

func main() {
	var a int
	var b int

	a, b = test(5, 7)

	fmt.Println(a)
	fmt.Println(b)
}

func test(x int, y int) (int, int) {
	return x * y, x + y
}
```
結果
```
35
12
```
戻り値を複数返すことが可能です。

## ポインタ
```
package main

import "fmt"

func main() {
	var val1 int

	fmt.Println(val1)
	change(&val1)
	fmt.Println(val1)

}

func change(hoge *int) {
	fmt.Println(hoge)
	*hoge = 4
}
```
結果
```
0
0xc00009c018
4
```

参照渡しはポインタを使用します。

## 構造体
```go:main.go
package main

import "fmt"

type Person struct {
	name string
	age  int
}

func (p *Person) SetPerson(name string, age int) {
	p.name = name
	p.age = age
}

func (p *Person) GetPerson() (string, int) {
	return p.name, p.age
}

func main() {
	var person Person
	person.SetPerson("太郎", 23)

	name, age := person.GetPerson()

	fmt.Println(name)
	fmt.Println(age)
}

```
結果
```
太郎
23
```

以上。

https://qiita.com/mojapico/items/4f2ce6829d3bcaf2011f

https://qiita.com/mojapico/items/2cc87cf8eca6a804866a

https://qiita.com/mojapico/items/45ef9206d5a0778062ec
Pybricks Codeについて

[前回記事](https://qiita.com/inachi/items/4ab52ff28ce9806bf6c0)からの続きで、Pybricks Codeの紹介と、それを使ったファームウェアインストール方法について書きます。

# Pybricks Code とは

EV3以外の Pybricks では開発環境として [Pybricks Code](https://code.pybricks.com/)というWebブラウザで動くIDEを使います。

※ EV3用のPybricks環境の構築については @Sunrise98 さんの[記事](https://qiita.com/Sunrise98/items/732ddb179994dc83406c)を参照してください。

ハブとの接続には Web Bluetooth が使われるので、Web ブラウザは Chrome 系を使うのがよいでしょう。

# 外観

[Pybricks Code](https://code.pybricks.com/)にアクセスすると、次の画面が現れます。

![スクリーンショット 2023-12-12 21.44.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106817/a0b0fce4-cd08-1215-f026-d20bacd6a6c6.png)

# ハブへのファームウェア転送

ハブに MicroPython ファームウェアをインストールするには、左ペインの歯車アイコンをクリックして設定を表示して、「Install Pybricks Firmware」をクリックします。

![スクリーンショット 2023-12-12 22.03.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106817/872537a7-675e-769a-38f5-a222c7578913.png)

インストール対象のハブを選んで「Next」をクリックします。

![スクリーンショット 2023-12-12 21.54.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106817/dd69e905-dbd3-ed1a-d48c-ec1b0084c081.png)

ライセンスに同意のチェックを入れて「Next」をクリックします。

![スクリーンショット 2023-12-12 21.55.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106817/f6cbc38d-aafe-fb0a-fd24-9389c05056c1.png)

ハブにつけるBluetoothデバイス名を入力して「Next」をクリックします。

![スクリーンショット 2023-12-12 21.57.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106817/81de6679-5e92-3c1b-ee44-7c89808ee07c.png)

表示される手順にしたがって、ハブをDFUモード(いわゆるファームウェアをインストールするモード)にして、「Install」をクリックします。ハブのBluetoothに接続してファームウェアのインストールが行われます。

![スクリーンショット 2023-12-12 22.02.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106817/7cdc2130-0999-3c5f-9507-618f2a20faee.png)

例としてして示している Technic Hub の場合だと、DFUモードに入るのに次のようにします。

* ハブの電源が入っていれば、一度電源を切ります
* ハブの電源ボタンを押したままにします
* ハブのLEDがパープル色に点滅したら「Install」をクリックします
* Bluetooth接続するハブを選択します
* 電源ボタンの押下をやめます
* ファームウェアのインストールが行われます

# ハブとの接続

ハブと接続するには Pybricks Codeの上にある Blurtooth アイコンをクリックします。

![スクリーンショット 2023-12-12 22.53.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106817/9f26c625-c8cc-4d97-3411-94b6762c2893.png)

ハブのスキャンが行われ、表示されるデバイスを選らんで「ペア設定」をクリックします。

![スクリーンショット 2023-12-12 22.54.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106817/c7d0942b-3255-cc94-0f99-72ff416ff2fa.png)

Bluetoothアイコンが次に変わったら接続完了です。

![スクリーンショット 2023-12-12 22.54.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106817/8a8e587d-bc43-9c05-892c-2644aa4fca7e.png)


# REPL表示

ハブに接続したら、Pybricks Codeの上にある REPL　アイコンをクリックすることによって、コンソール領域に REPL が表示され、ここで入力も可能です。

![スクリーンショット 2023-12-12 22.52.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106817/96fdc145-6b7a-051b-6bbe-56b58ce24655.png)

モジュール一覧を表示してみた例を示します。

![スクリーンショット 2023-12-12 22.51.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106817/c721a920-d19a-25e2-510d-396e5421168c.png)

# プログラミングはまた次回で

[次の記事](https://qiita.com/inachi/items/02a92cb369df6444b0f0)ではモータやセンサーを使ったプログラミングについて書きます。
「機械学習ソフトウェアにおけるテスト手法」を読んだ感想

## 今回読んだ記事

https://speakerdeck.com/hitsuji1991/ml-software-test-metamorphic?slide=16

## key takeaway message

- メタモルフィックテスティング面白い！
- 大変実践的で説明可能性も高い
- 例えば画像認識系のMLモデルなら、DAをそれぞれ個別分解して少しずつ入力を変えてみて出力がどれくらい変わるのか検証したいところ。


## もっと知りたかったところ
- 他のテスト手法、ニューロンカバレッジや最大安全半径についても知りたいところ。
-
【Flutter】今年触れた技術について〜go_router〜

今回はFlutterで画面遷移する際に使用できるgo_routerを紹介します:writing_hand:

### 環境
Mac OS:Sonoma14.1.2
Android:33
Android Studio:Android Studio Giraffe | 2022.3.1 Patch 4

## go_router
公式はこちら↓

https://pub.dev/packages/go_router

Flutterで用意されている純粋な画面遷移方法は少し複雑なところがあります。
それを本ライブラリを使用することで、簡単に実現することができます。
また、pub.defでも現在(2023/12/12) Likeが3726ととても人気なライブラリであることがわかります。

以下に一例として画面遷移のコードを紹介します。
```Dart
/// The route configuration.
final GoRouter _router = GoRouter(
  routes: <RouteBase>[
    GoRoute(
      path: '/',
      builder: (BuildContext context, GoRouterState state) {
        return const HomeScreen();
      },
      routes: <RouteBase>[
        GoRoute(
          path: 'details',
          builder: (BuildContext context, GoRouterState state) {
            return const DetailsScreen();
          },
        ),
      ],
    ),
  ],
);

// ボタンを押された際に詳細(details)画面に遷移する例
child: ElevatedButton(
    onPressed: () => context.go('/details'),
    child: const Text('Go to the Details screen'),
),
```

とても簡単ですね！
これに類似したauto_routerというのもあります。こちらに関してはまた触ってみた時に紹介したいと思います！

https://pub.dev/packages/auto_route

では、また明日〜〜
【JointJS】セルが多いときのパフォーマンスに影響がありそうな設定を検証してみた

JointJSでは多くの図形を描画する場合にパフォーマンスへの影響が懸念されます。大量の図形を描画しようとした際に、コード側で対策をすることができるのかがきになるところです。
今回はいくつかの設定値をピックアップし、実際に計測を行うと設定の有無でパフォーマンスの改善の余地があるのかどうかを調査していきます。

## 【検証1】Graphに追加するときのSortの有無

### 概要

Graphの`addCell()`/`addCells()`メソッドではオプションで`{sort: false}`を指定することで追加したCellの順序を整理するかどうかを指定できます。この設定がどれくらいパフォーマンスに影響するかを確認します。

### 検証方法

100個 / 1,000個 / 10,000個のRectangleをそれぞれ生成し、`addCells()`メソッドで同時に追加したときの時間を`{sort: false}`/`{sort: true}`をつけてそれぞれ計測した

### 検証結果

Sortを行わない方が速い
ただし1,000個未満くらいの個数であればあまり差は出ない

```実行結果ログ.txt
100個のときの結果(ms)
ソートあり 15.600000001490116
ソートなし 20.200000002980232

1000個のときの結果(ms)
ソートあり 156
ソートなし 119.90000000596046

10000個のときの結果(ms)
ソートあり 12101.60000000149
ソートなし 948.2999999970198
```

### 計測に使用したコード

https://codepen.io/acnaman/pen/rNPbPaN

## 【検証2】paper.freeze()の指定有無

### 概要

Graphの要素を変更する際にPaperをfreezeしていると要素の描画が即時反映されなくなります。
即時反映されない分、速くなるのではないかと思い検証してみました。

### 検証方法

100個 / 1,000個 / 10,000個のRectangleをそれぞれ生成し、`addCells()`メソッドで同時に追加したときの時間を`paper.freeze()`している状態、`paper.unfreeze()`している状態でそれぞれ計測した

### 検証結果

変化なし。Paperのfreezeの有無はパフォーマンスには影響がなかった。

```実行結果ログ.txt
100個のときの結果(ms)
freezeあり 15.100000001490116
freezeなし 20

1000個のときの結果(ms)
freezeあり 149.5
freezeなし 161.70000000298023

10000個のときの結果(ms)
freezeあり 10767.79999999702
freezeなし 8292.5
```

### 計測に使用したコード

https://codepen.io/acnaman/pen/VwgNgNd

## 【検証3】markupに`joint.util.svg`を使用するかどうか

### 概要

カスタム要素のmarkupはJSONで書く方法と`util.svg`でSVGタグを書く方法と2通りあります。内部的な変換などによるパフォーマンス影響が無いかどうかを確認します。

### 検証方法

`util.svg`を使用したカスタム要素と使用しないカスタム要素(結果のSVGは同じになるもの)を 100個 / 1,000個 / 10,000個 それぞれ生成＋グラフ追加したときにかかる時間を計測した

### 検証結果

変化なし。`util.svg`を使用しているかどうかはパフォーマンスには影響が無いことがわかった。

```実行結果ログ.txt
100個のときの結果(ms)
joint.util.svg使用あり 18.899999998509884
joint.util.svg使用なし 22.19999999552965

1000個のときの結果(ms)
joint.util.svg使用あり 140.89999999850988
joint.util.svg使用なし 171.30000000447035

10000個のときの結果(ms)
joint.util.svg使用あり 6166.9000000059605
joint.util.svg使用なし 6026.69999999553
```

### 計測に使用したコード

https://codepen.io/acnaman/pen/vYbMPLv

## まとめ

今回計測を行った中ではSortの有無のみがパフォーマンスに影響があることがわかりました。実行速度が遅いときにSortを無効化することでパフォーマンス向上を期待できますが、以前の記事で紹介した通り、Sortを無効にすると`z`による重ね合わせ指定が無効となってしまいます。Sortが無効にできる状況かをよく確認してから適用するべきでしょう。

また、有料版のJointJS+では[仮想レンダリングを使用することでパフォーマンスに強みがある](https://www.jointjs.com/faq#what-is-the-performance-of-jointjs)という情報もあります。どうしてもパフォーマンスに課題が出てしまうという状況であれば、JointJS+の導入も検討してみてください。

※この記事は [JointJS Advent Calendar 2023](https://qiita.com/advent-calendar/2023/jointjs) の記事です。他の記事を読む場合はカレンダーのページを参照してください。

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