OmniAICreator/Qiita-1.07M huggingface dataset:
【初心者向け】SPRINGでCSVデータをDBに登録してみた


# はじめに
押忍！
今日は業務用アプリとかでよく見る
CSVデータをアップロードしてDBに登録する機能をSpringを使って作成してみました！

# そもそもCSVってなんぞ
私は業界に入るまで見たことも触ったこともなかったんで一応記載しておきます。
Comma Separated Valuesの略称で
```:CSVsample
従業員番号,氏名,部署
A123456789,総務太郎,総務部
B223456789,営業花子,営業部
```
こんな感じでカンマごとに値を区切ったデータの事です。
ファイル形式は .csv になります。

ちなみに１行目は項目名を記載したヘッダーレコードなのですが、
物によってあったりなかったりします。

今回はある想定で作成をしたので
DBに登録するのは２行目以降ってことですね。


# やりたいこと
画面からCSVを選択してアップロード
アップロードされたCSVの内容をDBに登録


# 作ってみた
まずは画面から
csvに下記のフォームを追加します。

```HTML
	<form th:action="@{/upload}" method="post" enctype="multipart/form-data">
		<input type="file" name="file"><br>
		<button type="submit">アップロード</button>
	</form>
```
・form 中の　enctype="multipart/form-data"ですが
　WEBアプリでファイル送信をする際に、
 　一般的に使用されるデータ送信フォーマットだそうです。
　細かいところまで調べるとそれだけで記事が書けそうなので今回はここまで！

・あとはinput type="file"
　にすることで勝手にそれっぽくしてくれます。
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2157384/270f4185-89ef-b6fe-c0c6-dda32791f7ea.png)

<br>
次にJava側で送信されたCSVを受け取り、DBに登録する処理を追記します。

```Java
@PostMapping(path = "/upload")
	public String upload(@RequestParam("file") MultipartFile file) {
		try (InputStream inputStream = file.getInputStream();
				BufferedReader br = new BufferedReader(new InputStreamReader(inputStream))) {
			
            //読み取ったCSVの行を入れるための変数を作成
            String line;
            //ヘッダーレコードを飛ばすためにあらかじめ１行だけ読み取っておく（ない場合は不要）
            line = br.readLine();
    		//行がNULL（CSVの値がなくなる）になるまで処理を繰り返す
            while ((line = br.readLine()) != null) {
            //Stringのsplitメソッドを使用してカンマごとに分割して配列にいれる
				String[] csvSplit = line.split(",");
            //分割したのをセットして登録
				Entity entity = new Entity();
				entity.setAAAA(csvSplit[0]);
				entity.setBBBB(csvSplit[1]);
				entity.setCCCC(csvSplit[2]);
				entity.setDDDD(csvSplit[3]);
				Repository.save(entity);
			}
			br.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return "view";
	}
``` 

 
今回はControlerの中に処理を記載しましたが
本来であればServiceとかで作成して呼び出すのが正しいかと思います！
あと例外処理（CSV以外のファイルが送信された、CSVの項目数が違う etc）については今回は放っておきます:money_mouth:

# まとめ
上記のコードで実行したところ一応CSVの内容をDBに登録する事が出来ました！
あとは状況に応じて例外処理とか実施すれば使えそうですね

とりあえずCSVを読みこむ時は
・１行ずつ読み込む
・カンマごとに分割する
のがポイントです！たぶん
Microsoft Power Automate DeskTopって何？ ～ここがすごいぞ！PAD～

# はじめに
この記事は、
RPAに興味のある方、業務効率の手段の一つとして、Microsoft Power Automate DeskTop(以下、PADと呼ぶ)を知りたい方向けになります。
また今回の紹介するサービスなどは、無償で使える範囲のものになります。
有償版に関しては、別記事を参照してください。

# PADとは？
PADは、Microsoftが提供しているRPAツールです。
PADは、ローカルアプリケーションの自動化や、Webアプリケーションの自動化を行うことができます。
またPADは、ローコードツールであるため、プログラミングができない方も簡単に使うことができます。
PADにはアクションと言われるパーツが数多くあるので、どのアクションを組み合わせるかで幅広いニーズに対応できます。

# ここがすごいぞ！PAD3選

私が、PADを使っていてここはすごいなと思ったポイントを3つ紹介したいと思います。

### その1　Microsoftアプリとの連携が充実している
PADは、Microsoftが提供しているサービスなだけあり、Microsoftアプリとの連携がかなり充実しています。
例えば、Outlookと連携して、任意の宛先に自動で送信ができたり、メールの文章から任意のメールボックスに入れるなどさまざまなことができます。
Outlook以外でもExcelの操作もスムーズにできるので、Excel業務の自動化を簡単に行うことができます。

### その2　Webアプリケーション(Chrome,edge,etc)の自動化
PADは、Webアプリケーションの自動化に関しても豊富なアクションがあります。
一番分かりやすいものはスクレイピングを簡単に行うことができます。
例えば、ブラウザの検索結果をExcelに格納して共有することができます。
ただスクレイピングができるだけですと、Pythonのライブラリ(seleniumなど)でもできるので、PADを使うメリットになりません。
PAD固有の良さとして、GUIの操作の自動化を簡単に行うことができます。
PADでは、UI要素を画像認識、絶対座標、htmlのclass名などに頼ることなく指定できます。
PADにUI要素ピッカーというものがあるので、それを利用するとできます。
そのため、seleniumなどに比べてもGUIの操作を簡単に行うことができるのです。

### その3　オリジナルアクションを作れる！
その1、その2でPADがもつ素晴らしいアクションたちを紹介しましたが、幅広いニーズに対応しようと思うと少しアクションが足りない印象があります。
例えば、今日の天気をお知らせしてくれるbotを作りたいと思ったときに、天気情報を取得できるアクションがないのでできません。（例えが悪すぎました泣）
このように、痒いところに手が届くようなツールかと言われたらそうではありません。
しかし、PADを少し工夫して使うとこの問題を解決できます。
PADのアクションに、「**PowerShellスクリプトの実行**」というものがあります。
これを使うことでPADアプリの外にあるソースコードを実行し、出力結果を取得することができます。
つまり外部コードで、天気情報を取得し、その情報をPADで整形することができます。
これは、新しく天気情報を取得できるアクションを生成したことになります。
このように少し工夫することで、PADの扱える範囲を自分なりに大きくすることができます。

# ここが良くない...
ここまで、PADの素晴らしいポイントを紹介しましたが、ここ良くないなと思われるポイントが2つ存在します。
ただこの2ポイントは有償版を利用していただくと解消されます。ここから書く内容は、お金をケチらなければ考えなくいいんだという気持ちで読んでください。
無償版と有償版の違いや有償版の価格などは以下のサイトが分かりやすくまとめられているため、参考にしてください。
・[Power Automate Desktop無償版と有償版のちがい](https://digital-labor.nissho-ele.co.jp/blog/00040/)
・[Power Automate価格（Microsoft HP）](https://powerautomate.microsoft.com/ja-jp/pricing/)

ここから、PADのここが良くないなと思ったポイントを紹介します。
一つ目は、フローの共有がめんどくさいことです。
PADユーザー同士で直接フローを共有することができないため、一度フローをテキストファイルに変換して、そのテキストファイルを共有して、それをフローに変換するという手順を踏まないと共有できません。これはめんどくさいですし、かなりダサいです。
二つ目は、トリガー実行、定時実行ができません。
フローの実行方法が手動かショートカットを用いた実行しかないため、あるフォルダー内にファイルが生成されたら実行や、ある時刻になったら実行みたいなことができません。
特に定時実行は業務をしていても欲しいなと思える機能なので、とても残念に思いました。
以上がPADのここが良くないなと思ったポイントになります。

# おわりに
以上、PADについて書いてきましたが、この記事を見てPADを使ってみたいと思っていただければうれしいです。
今私は、無償版を使っていますが、将来的には有償版を使いたいなとは考えていません。
如何に無償の範囲で有償のサービスを再現できるかを模索しているので、突破口が見つかりましたら、記事にしたいと思います！
macOSにおけるジョブ管理ツール、launchd。

## あらまし。
- macOSを使う方で、自分のパソコンを自動で管理したいという方に向けて書きます。私の場合、外付けSSDに対してもTimeMachineと同様のファイル履歴管理がされる仕組みを作るために調べました。実際には「rsync_tmbackup」というCLIツールを呼び出しましたが、ここではシンプルにするためrsyncを題材にします。

## 前提。
- macOSXからは、crondからlaunchdへ移行されている。
- システムデーモン、エージェントの違いについては説明せず、エージェントを前提に説明する。
- 扱うコマンド、ファイルによって、パーミッションの問題が発生する。その点についての説明はしない。
- この説明では、rsyncの実行を想定している。ただし、プロパティファイルからはシェルスクリプトを埋め込んだAPPファイルを呼び出す。これは、「プライバーとセキュリティ」による、アプリケーションのアクセス許可に準じるためである。そのため、shファイルを指定した場合の考慮はしていない。
- rsyncの引数については説明を行わない。

## 必要なファイル作成から、ジョブ発動までの流れ。
APPファイルを作成する。（後述する各ファイルの説明を参照。）
　↓
プロパティリスト（plistファイル）を作成する。（後述する各ファイルの説明を参照。）
　↓
プロパティリスト（plistファイル）をlaunchdに登録する。（後述するlaunchdへの登録を参照。）
　↓
プロパティリスト（plistファイル）に記述されたジョブの条件や、プログラム（APP）をOSが読みこむ。
　↓
上記の条件に応じて、プログラム（APP）が発動される。
　↓
APPに含まれたシェルスクリプト、ここではrsyncが実行される。
　↓
 コマンドが実行される。また、後述する標準出力、エラー（StandardOutPath、StandardErrorPath）に結果が表示される。

 ## 各ファイルの説明。
- plistファイル。
今回のケースでは、以下のパスに配置する。
~/Library/LaunchAgents
追加の情報は以下を参照ください。
https://support.apple.com/ja-jp/guide/terminal/apdc6c1077b-5d5d-4d35-9c19-60f2397b2369/mac
また、私が確認した限りでは絶対パスを記述しないとAutomatorの段階でうまく実行できませんでした。そのため、仮のユーザー名として「mine」を記述しています。
LimitLoadToSessionTypeについて、公式なドキュメントでは定義を探せませんでした。今回はユーザーごとのファイル履歴というケースであるため、ネットで得た情報を暫定的に利用しています。
```xml:plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>Label</key>
	<!-- ファイル名と合わせること。 一意になる文字列であれば、以下の形式にこだわらない。-->
	<string>com.mine.rsync</string>

	<key>LimitLoadToSessionType</key>
	<!-- GUIセッションのみ。https://stackoverflow.com/questions/9576287参考。 -->
	<string>Aqua</string>

	<key>ProgramArguments</key>
	<array>
	  <string>open</string>
	  <string>/Users/mine/Documents/Scripts/ssd_backup.app</string>
	</array>

	<key>RunAtLoad</key>
	<true/>
	<key>StartInterval</key>
 	<!-- １時間おきに実行する。 -->
	<integer>3600</integer>

	<key>StandardErrorPath</key>
    <string>/Users/mine/rsync.error.log</string>
</dict>
</plist>
```

- appファイル。
Automaterで任意のシェルスクリプトを埋め込みます。
概要については以下を参照ください。
https://qiita.com/KurosawaTsuyoshi/items/425cd484e8d7759af460
APPファイルとして保存する前に、実行してエラーがないことを確認した方が後が楽です。

## launchdへの登録。
作成したプロパティリスト（plistファイル）をlaunchdに登録します。
以降、~/Library/LaunchAgents/　にプロパティリストが配置されていることを前提とします。
まず、プロパティリスト（plistファイル）が正しいかチェックします。
plutil -lint ~/Library/LaunchAgents/（ファイル名）.plist
OKと表示れたら、以下のコマンドでlaunchdへ登録します。
launchctl load ~/Library/LaunchAgents/（ファイル名）.plist

## あとがき。
もっと細かいことがいろいろあります。
しかし、細かすぎると取り掛かるのがおっくうになりますのでなるべく簡潔にしました。
個人的な観点としては、コンシューマ向けではありません。難しすぎる。
ここまで書いて気づきました。
開発者のためにあえてmacOSでは対応しないのか。（嫌味ではありません。）
私に作れるかな〜。そのうちに考えます。

引用させていただいた方には感謝いたします。
ご覧いただきありがとうございました。
BlenderのPython開発における仮想環境の構築方法

# 概要
BlenderのPython APIを使った開発において、Blender内臓のpipを用いてインストールを行うことで外部ライブラリも利用することができます。

https://www.kkaneko.jp/db/cg/bpypip.html

しかし、プロジェクトごとにパッケージを管理したい場合や、[fake-bpy-module](https://github.com/nutti/fake-bpy-module) をインストールしてコード補完を利用する場合などは仮想環境でパッケージの管理を行いたいところです。

ここではBlenderのPython API開発での仮想環境の使い方を紹介します。

# 動作環境
ここでは以下の環境で動作確認を行っています。

- Windows 11
- Blender 4.0.1

# 仮想環境の作成
Blenderのプロジェクトファイル `.blend` が保存されているディレクトリをプロジェクトディレクトリとして、以下のような構成で仮想環境を作成します。

```
📂 (project_directory)
 ├─📂 .venv
 ├─📄 hoge_project.blend
 └─📄 hoge_script.py
```

下記のコマンドによりBlender内臓のPythonから `venv` による仮想環境を作成します。

```powershell:PowerShell
& "C:\Program Files\Blender Foundation\Blender 4.0\4.0\python\bin\python.exe" -m venv .venv
.\.venv\Scripts\activate
```

ここでは外部ライブラリの一例として `numpy` をインストールしてみます。

```powershell:PowerShell
pip install numpy
```

# Pythonスクリプト
外部ライブラリを呼び出すPythonスクリプトは以下のように記述します。

```hoge_script.py
import pathlib
import sys

import bpy

# プロジェクトファイル(.blend)のディレクトリを取得
project_dir = pathlib.Path(bpy.path.abspath("//"))

# 仮想環境の site-packages ディレクトリを指定
site_packages_dir = project_dir.joinpath(".venv", "Lib", "site-packages")

# site-packages ディレクトリをPATHに追加し、外部ライブラリを検索対象に追加
sys.path.append(str(site_packages_dir.resolve()))

# PATH追加後に外部ライブラリのインポートが可能になる
import numpy as np

# 外部ライブラリの呼び出し確認
print("numpy version:", np.__version__)
```

Pythonスクリプトの実行方法は通常通りで、BlenderのGUI上や下記のコマンドで起動します。

```powershell:PowerShell
& "C:\Program Files\Blender Foundation\Blender 4.0\blender.exe" -b hoge_project.blend -P hoge_script.py
```

以下のように正常に `numpy` のインポートが通っていることが確認できます。

```:標準出力
Blender 4.0.1 (hash d0dd92834a08 built 2023-11-17 00:36:52)

~~~中略~~~

numpy version: 1.23.5

Blender quit
```

# 補足: `fake-bpy-module` の仮想環境へのインストール方法
VSCodeでPythonスクリプトをコーディングする際に、`bpy` モジュールのコード補完を有効にするために `fake-bpy-module` が利用できます。

https://github.com/nutti/fake-bpy-module

pipからインストール可能なので、上述と同様で下記のコマンドによりインストールします。

```powershell:PowerShell
.\.venv\Scripts\activate
pip install fake-bpy-module-4.0
```

仮想環境をアクティベートした状態で下記のコマンドにより、仮想環境を認識した状態のVSCodeが起動します。

```powershell:PowerShell
code .
```

`bpy` モジュールのコード補完が有効化されていることが確認できます。

![コード補完](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591150/3882f226-69b7-bf36-9ded-2725ace8a0cd.png)
【ISUCON】mysqldumpslowコマンドが使えない時の対処法

MySQLのスロークエリログをmysqldumpslowコマンドで集計しようとしたところ、以下のエラーで実行できなかった。
```
$ mysqldumpslow mysql-slow.log
zsh: command not found: mysqldumpslow
```

色々調べてみたところ、mysqldumpslowを提供するMySQLのクライアントツールが正しくインストールされていない可能性があるとのこと。

インストールされているか確認するため以下のコマンドを実行したところ、mysqlコマンドが見つからないというエラーが返ってきた。
```
$ mysql --version
zsh: command not found: mysql
```

やっぱりインストールされていないっぽいので以下のコマンドでインストール。
```
$ brew install mysql

# AppleシリコンMacの人はこちら
$ arch -arm64 brew install mysql
```

これでmysqldumpslowコマンドが使えるようになった。
```
$ mysqldumpslow mysql-slow.log

# 実行結果
Reading mysql slow query log from mysql-slow.log
Count: 1  Time=0.07s (0s)  Lock=0.00s (0s)  Rows=5.0 (5), root[root]@localhost
  show databases

Count: 462  Time=0.04s (18s)  Lock=0.00s (0s)  Rows=2.9 (1344), root[root]@webapp_app_1.webapp_default
  SELECT * FROM `comments` WHERE `post_id` = 'S' ORDER BY `created_at` DESC LIMIT N
...
```
ISUCON本だと当たり前にこのコマンドが使えるような書き振りだったので少々混乱しましたが、明示的にインストールしないと使えないパターンもあるのでご注意ください。
【Ruby Gold3.1詰まったシリーズ】tallyメソッド確認してみた

# はじめに
今回はtallyに関する内容です。Ruby3.1の新しい概念の一つにtallyメソッドがあるので簡単にまとめてみます。

# 確認してみた
環境はruby 3.1.4です。
[こちら](https://qiita.com/heysan/items/82bdfb7af4325f05e0e5)によると、tallyメソッドは要素ごとの個数を返すメソッドらしいです。
実際に配列に対してtallyメソッドを実行
~~~ruby
fruits = ["banana", "pineapple", "grape", "apple", "grape", "pineapple"]
fruits.tally 
~~~
すると、
~~~
irb(main):001> fruits = ["banana", "pineapple", "grape", "apple", "grape", "pineapple"]
irb(main):002> fruits.tally 
=> {"banana"=>1, "pineapple"=>2, "grape"=>2, "apple"=>1}
~~~
banana/pineapple/grape/appleの個数が返っている。
tallyメソッドを使用しないパターンで同じ結果を返す方法をchatgptに聞いてみると、
~~~ruby
fruits = ["banana", "pineapple", "grape", "apple", "grape", "pineapple"]

tally = fruits.each_with_object(Hash.new(0)) do |fruit, counts|
  counts[fruit] += 1
end

puts tally
~~~
が返ってきて、実際に試すと、
~~~
irb(main):003* tally = fruits.each_with_object(Hash.new(0)) do |fruit, counts|
irb(main):004*   counts[fruit] += 1
irb(main):005> end
=> {"banana"=>1, "pineapple"=>2, "grape"=>2, "apple"=>1}
irb(main):006> 
irb(main):007> puts tally
{"banana"=>1, "pineapple"=>2, "grape"=>2, "apple"=>1}
~~~
tallyメソッドを使用した結果と同じ結果となりました。

# おわりに
確認した結果、tallyメソッドは要素ごとの個数を返すことが分かりました。また、tallyメソッド以外の方法でtallyメソッドと同じ結果を出す方法も確認した結果、ブロック操作する必要がでてきたので、tallyメソッドを利用した方が簡単に要素ごとの個数を返すことができると感じました。もし誤っていたらご指摘いただけると助かります！

# 参考
https://qiita.com/heysan/items/82bdfb7af4325f05e0e5
webサイト開発で便利なサイト5選

## UI設計

### 原色大辞典

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1471588/ed3078d4-10ea-5964-84f9-2efbc16870cc.png)

https://www.colordic.org/w


- 和色や洋色の時点
- 選んだ色に近い色や色相環で反対の色、おすすめの配色パターンも教えてくれる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1471588/2cdef733-e4d5-96c7-a168-8c2a390346e1.png)

## UI実装

### バーンワークス UI ライブラリ


https://ui.burnworks.com/

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1471588/8c07ba0b-79de-50bb-d81c-f7dc65cc28b0.png)

- tailwindの日本語サイト向けUIライブラリ
- ほかのライブラリにないようなデザインも豊富

### daisyUI

https://daisyui.com

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1471588/ff104ef0-8ade-8ec0-a100-98b1f1038c83.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1471588/9b3a1b43-16d7-ad8f-3c53-2e2a96e188ba.png)


アドカレ8日目の記事でも紹介させていただきました！

https://qiita.com/sasanqua/items/6a0c0650ec9dd9dd1ebd


- ドキュメントが充実している
- かゆいところに手が届くコンポーネント集


## アイコン

### SVGREPO


https://www.svgrepo.com/


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1471588/7b806639-b231-fac1-2dd6-1f5476e367c4.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1471588/d0dbb3d8-a690-57d3-0b5f-691f26978b0a.png)


- 種類が多くて自分のプロジェクトに合わせやすい
- 使うときにサイズの調整とかは必要


### MingCute Icon


https://www.mingcute.com/


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1471588/04c63912-f0b3-ab3f-4b66-d0f73acf9d00.png)


- アイコンも公式サイトもシンプルで使いやすい
- たいていのアイコンはそろってるからこのサイト１つでアイコンをまかなえる


## 終わりに

他にも便利なサイトがあれば教えてください！！
WindowsとMacのファイルシステムの違い

# 1. 背景
社会人になってからMacだけでなくWindowsも利用するようになりました。両者のファイルシステムの違いに興味を持ったため、調べた内容を記事にまとめます。

# 2. ファイルシステムとは
ファイルシステムとは、記憶装置に保存されたデータを管理し、操作するために必要な機能です。OSが提供します。

# 3. Macのファイルシステム
- APFS (Apple File System):
    - macOS High Sierra以降で導入。
    - APFSは高速なパフォーマンス、セキュリティ強化、スペース効率の向上などを提供。
    - クロスプラットフォームの利用も可能で、iOSデバイスとも互換性がある。
- HFS+ (Hierarchical File System Plus):
    - 過去のMac OS X（現在はmacOS）で使用。
    - HFS+はジャーナリング、ファイルメタデータの保持、ファイル名のUnicodeサポートなどが特徴。


# 4. Windowsのファイルシステム
- NTFS (New Technology File System):
    - 最も一般的。
    - NTFSはセキュリティ強化やパフォーマンス向上などの機能を提供。
    - 高度なアクセス制御、ファイル圧縮、トランザクションサポート、エンクリプションなどが含まれる。
- FAT32 (File Allocation Table 32):
    - 古いバージョンのWindowsやリムーバブルデバイス（USBフラッシュドライブなど）で使用。
    - シンプルな構造であり、大容量のファイルやパーティションには不向き。

# 5. 注意事項
- Windowsはドライブにアルファベットのラベル（Cドライブ、Dドライブなど）を使用するが、Macはデバイス名（Macintosh HDなど）を使用する。
- Windowsはセパレータとして「\」を使用し、Macは「/」を使用します。

# 6. おわりに
MacとWindowsのファイルシステムにはそれぞれ特徴があることがわかりました。
Nextjsでsql.jsのwasmを綺麗にプロジェクトに追加する方法

ブラウザ上でSQLite3を使用したい場合はsql.jsというライブラリを使う事ができます。

sql.jsはSQLite3をwasmでビルドすることでブラウザ上で動くようにしたプロジェクトです。
そのため、SQLiteに互換性があり、データベースファイルを読み込む事もできます。

## sql.jsを動かすにはwasmもロードする必要がある

sql.jsを動かすためにはwasmが必要になるため、フロントエンドエンドのプロジェクトをビルドする際にsql.jsのjsだけでなく、wasmの方もアクセスできるように追加してやる必要があります。

wasmファイルはインストールしたsql-jsのライブラリ内に存在します。

```
ls node_modules/sql.js/dist/sql-wasm.wasm                                               
```

React.jsではfile-loaderを使うことで下記のようにwasmをロードすることができます。

```typescript
import sqlWasm from "!!file-loader?name=sql-wasm-[contenthash].wasm!sql.js/dist/sql-wasm.wasm";

const SQL = await initSqlJs({ locateFile: () => sqlWasm });
```

https://github.com/sql-js/react-sqljs-demo/blob/master/src/App.js

## Next.jsでは難しい

NextjsはSSRやSSGなどビルドがReact.jsに比べて複雑なので、file-loaderでは上手くwasmを同梱させることができません。

一応、wasmファイルを手動でpublicディレクトリに移す事で動かす事もできますが、sql.jsのバージョンアップのたびに手動で管理するのは煩雑です。

## Webpack5のasset/resourceを使えば解決できる

Webpack5ではasset/resourceというバンドルのための機能が標準で搭載されるようになりました。
この機能を使う事でNextjsでもsql.jsのwasmファイルをプロジェクトに追加することができます。

next.config.js経由でwebpackのコンフィグを設定します。

```javascript
/** @type {import('next').NextConfig} */
const nextConfig = {
  webpack: (config, { isServer, webpack }) => {
    if (!isServer) {
      config.resolve.fallback.fs = false;
    }
    config.module.rules.push({
      test: /\.wasm$/,
      type: 'asset/resource',
    })
    return config;
  },
}

module.exports = nextConfig
```

Next.js内のクライアントコンポーネントで下記のようにします。

```typescript
const SQL = await initSqlJs({
    locateFile: () => (new URL("sql.js/dist/sql-wasm.wasm", import.meta.url)).toString(),
})
```

これでsql.jsをnext.jsのプロジェクトに追加して利用することができました。

今回の手法を使ったデモを用意してあります。

https://github.com/RASBORA/nextjs-sqljs-webpack5-demo
[VSCode][Python] 一括コメントアウト

## VSCodeにおける一括コメントアウトについて

### 環境
- MacOS Monterey
- Python3.11.1

### 手順
1. [command] + [/]
    (Windowsの場合、[CTRL] + [/])
    
 ~~~Python
# count = 0
# while True:
#     if count >= 5:
#         break
#     print(count)
#     count += 1

count = 0
while True:
    if count >= 5:
        break
    if count ==2:
        count += 1
        continue

    print(count)
    count += 1
 ~~~

 ### 他のプログラミング言語
|言語|1行コメント|ブロックコメント|
|:---|:---:|:--:|
|Python|#|"""　""" または '''　'''|
|HTML|なし|\<!--　-->|
|CSS|なし|/*　*/|
|JavaScript|//|/*　*/|
|Swift|//|/*　*/|

### 参考リンク
[コメントアウト一覧](https://baapuro.com/VScode/eleven/)
[Swiftのコメントアウト](https://blog.code-candy.com/xcode_comment_improvement/)
【Java】var変数とのうまい付き合い方

# var 変数とは
var 変数とはJava11以降で使用が可能となった、いろいろな型を代用する変数のことである。
例えば、

``` 
String str="test";
```

とJava10以前であれば、記載する必要があったが、Java11以降であれば、下記の書き方も出来るようになった。

```
var str="test";
```

# 問題点
上記のように明らかに右側の形式が明確な場合は問題ない。
ただし、他のメソッドからの戻り値の値をセットする場合などではちょっとややこしいことにもなる。

```

pubic static void main(){

var hogehoge=getStr();

}

pubic String getStr(){

   String str="";
  //doSomething

  return  str;
}

```
この時点でgetStrメソッドの戻り値ってどんな型がどうか分からない。
確かに右側のメソッドでは必ずString型で返しているが、記述的に問題はなく、コンパイルも通るわけではあるが。

# JavaDocコメントの推奨
これだけだと確かにメソッドの内容を探しに行く必要がある。クラスが別だったら、別のJavaファイルを見に行かないと行けない。面倒。
そんな時のためにJavaDocコメントを書くくせをつけよう。
```

pubic static void main(){

var hogehoge=getStr();

}

/**
 * return strの文字列
 *
 */
pubic String getStr(){

   String str="";
  //doSomething

  return  str;
}

```

return だけでも書いてあると少なくとも文字列を返してあるのが分かる。
これだけだと実際には改修するプログマー思いではないので、ある程度改修の事も考えてJavaDocコメントは考えよう。

# 変数の付け方
var変数に入れることができる値のうち、ListとかMapの場合には○○Listとか○○Mapとかがつけるなどの癖付けも有効になる。
```

pubic static void main(){

var hogeList=new ArrayList<String>();

}

```
ただし、命名規則がちゃんとしている場合にはそれに準ずる必要がある。

# var変数との付き合い方
varがJava11以降で使えるようになってしまったので、var変数を使うと型がよくわからなくなってしまった。ただ、解禁されてしまったのは仕方ないので、それはJavaの開発をするときに開発プログラマーとプロジェクト全体でvar変数の使用をどう考えるか、また、変数の命名規則はどうするかをちゃんと規定していくべきだと考える。

以上
MDN 翻訳コミュニティの2023 年度 OSC 活動紹介

# はじめに
この記事は 2023 年の [MDN 翻訳 Advent Calendar](https://qiita.com/advent-calendar/2023/mdn-translation-community-japan) 向けに作成したものです。

## イベント出展

2023 年は、下記イベントに出展しました。

### OSC Tokyo 2023 Spring

- [Open Source Conference 2023 Tokyo/Spring](https://event.ospn.jp/osc2023-spring/)
- 日程：2023年4月1日(土) 10:00～16:00
- 会場：東京都立産業貿易センター台東館 7階

https://www.google.com/maps/place/%E6%9D%B1%E4%BA%AC%E9%83%BD%E7%AB%8B%E7%94%A3%E6%A5%AD%E8%B2%BF%E6%98%93%E3%82%BB%E3%83%B3%E3%82%BF%E3%83%BC%E5%8F%B0%E6%9D%B1%E9%A4%A8/@35.714427,139.79875,17z/data=!3m1!4b1!4m2!3m1!1s0x60188ec3d981d0f5:0x82b2ec9f4699aec6?hl=ja

### OSC Tokyo 2023 Fall
- [Open Source Conference 2023 Tokyo/Fall](https://event.ospn.jp/osc2023-fall/)
- 日程：2023年10月21日(土) 10:00～16:00
- 会場：大田区産業プラザPiO 大展示ホール

https://www.google.com/maps/place/%E5%A4%A7%E7%94%B0%E5%8C%BA%E7%94%A3%E6%A5%AD%E3%83%97%E3%83%A9%E3%82%B6PiO/@35.558782,139.724067,14z/data=!4m6!3m5!1s0x601860f87f5da4e3:0x8a0493a2f4accfb0!8m2!3d35.5587817!4d139.7240667!16s%2Fg%2F122brw5n?hl=ja&entry=ttu

### 展示例
![IMG_6277.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28875/436e7a60-ef22-8130-55b7-63c4cafb3e18.jpeg)
![IMG_6275.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28875/e93414e9-5c47-c0a0-db4f-65eb06b4cc99.jpeg)

### 来訪者への接客

翻訳コミュニティに興味を持って頂いた方には、下記内容を案内しています。

- MDN Web Doc の紹介
- 翻訳の手順の紹介
- 翻訳についての不安解消
- ミートアップイベントの紹介

イベント用のスライドは、こちらになります。

https://www.docswell.com/s/ic_lifewood/KJLEGE-2023-09-10-215840

立ち寄って頂いた方には、ノベリティグッズなどを頒布しています。

今月 12/23（土）13:00～ 翻訳コミュニティ定例ミートアップがあります。
ご興味のある方、ぜひ参加して下さい！

https://mozilla.doorkeeper.jp/events/166059
【SwiftUI】StretchableなUIを作成する

# Stretchableとは
そもそもStretchableなUIとはなんでしょうか。
`Stretch` + `able` つまり「伸縮可能なUI」を指します。
ScrollViewの開始位置から上にスクロールしたときに、Headerがビヨーンと伸びるあれです。
ちなみに、Stretchableという言い方以外に「StretchyView」という呼び方もあるそうです。

その作り方を説明していきます！

# 動作環境
- MacOS Sonoma 14.1.2
- Xcode 15.0.1
- Swift 5.9

# 作り方
作り方としては、`ScrolView`の中に`GeometryReader`を入れて、画像の高さとHeaderのY軸のOffsetを計算すればできそうです。

まずは下記のような関数を作成します。
```Swift
  func stretchableHeaderImage(image: Image) -> some View {
     GeometryReader { proxy in
        image
          .resizable()
          .aspectRatio(contentMode: .fill)
          .frame(
             width: proxy.size.width,
             height: getHeightForHeaderImage(proxy),
             alignment: .center
          )
          .clipped()
          .offset(y: getOffsetForHeaderImage(proxy))
       }
       .scaledToFill()
    }

    func getHeightForHeaderImage(_ proxy: GeometryProxy) -> CGFloat {
        let offset = proxy.frame(in: .global).minY
        let imageHeight = proxy.size.height
        return offset > 0 ? imageHeight + offset : imageHeight
    }

    func getOffsetForHeaderImage(_ proxy: GeometryProxy) -> CGFloat {
        let offset = proxy.frame(in: .global).minY
        return offset > 0 ? -offset : 0
    }
```
そしてこれらを`ScrollView`に入れることで、stretchableなHeaderを持つScrollViewが完成です！

:::note info
・GeometryReaderの外側に`.scaledToFill()`
・ScrollViewの外側に`.ignoresSafeArea(edges: .top)`
が必要です！
:::

# コード全体

```Swift: StretchableHeaderView
import SwiftUI

struct StretchableHeaderView: View {
    var body: some View {
        ScrollView {
            stretchableHeaderImage(image: Image(systemname: "faceid"))

            // ここにListなどのviewを追加します
        }
        .ignoresSafeArea(edges: .top)
    }

    func stretchableHeaderImage(image: Image) -> some View {
       GeometryReader { proxy in
          image
             .resizable()
             .aspectRatio(contentMode: .fill)
             .frame(
                width: proxy.size.width,
                height: getHeightForHeaderImage(proxy),
                alignment: .center
              )
            .clipped()
            .offset(y: getOffsetForHeaderImage(proxy))
        }
        .scaledToFill()
    }

    func getHeightForHeaderImage(_ proxy: GeometryProxy) -> CGFloat {
        let offset = proxy.frame(in: .global).minY
        let imageHeight = proxy.size.height
        return offset > 0 ? imageHeight + offset : imageHeight
    }

    func getOffsetForHeaderImage(_ proxy: GeometryProxy) -> CGFloat {
        let offset = proxy.frame(in: .global).minY
        return offset > 0 ? -offset : 0
    }
}

#Preview {
    StretchableHeaderView()
}
```

# 終わりに
ここまでお読み頂き、ありがとうございます！
株式会社ゆめみの24卒アドベントカレンダー9日目の記事でした。
Mind+を使ってPythonビジュアルプログラミング。Microbit編

## はじめに
秋葉原ロボット部の有志で、milk-v duoを購入し、個々人が様々な実験を行って、勉強会内で報告しています。

Milk-v duoは9ドルのrisc-vコンピュータとして知られています。
ハードウェアは以下の通りです。

1. CPUはCVITEKのCV1800B (C906@1Ghz + C906@700MHz)
1. 最高1 GHzで動作するデュアルRV64コア
1. 64 MBのラム
1. オプションのアドオンボードを接続すると10/100Mbpsの速度でイーサーネットに接続可能

Mind+にはArduino Cでのビジュアルプログラミングの環境のほかに、Pythonでのビジュアルプログラミングの環境が存在します。
ここでは、Pythonでのビジュアルプログラミングの環境が対応しているmicrobitで、ビジュアルプログラミングを行います。

## Pythonビジュアルプログラミング環境の構築
「Python」のボタンをクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/693019/6e299d28-d968-b1f6-19be-d5386c4f4817.png)
右上の「Library Management」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/693019/b114d92b-f8f1-ccda-af5d-2201449eff5b.png)
pinpongライブラリがインストールされているか確認します。
枠内の右端に灰色地に白文字の「Installed」が表示されていると、pinpongライブラリがインストールされています。
もし、オレンジ地に白文字で「Install」と表示されていたら、ライブラリがインストールされていないので、クリックしてインストールします。

画面左下の、オレンジ色の「Extension」をクリックします。
「pinpong」をクリックして、オレンジ色の文字の状態にします。
この状態で、使用するブロックを選びます。
今回は「pinpong initialize」だけでプログラム可能です。
他のセンサ類を使用するときは、「読み込み失敗：」の必要なものをクリックします。
必要なものを選択し終わったら、「戻る」をクリックします。

下の図は、「pinpong initialize」が選ばれている状態を示しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/693019/c2bd6968-ba8c-a8be-97ed-6812056ea5bf.png)


左上の「コード」をクリックすると、ビジュアルプログラミング環境になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/693019/bc19f9f6-f8c3-4c3d-f5b5-2d8681ee3782.png)

## PythonビジュアルプログラミングでLチカ
microbitのマイクロUSB端子横の黄色LEDでLチカを行います。

「Run」ボタンを押すと、LEDが点滅します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/693019/7bd922cf-6a56-e3b0-2d70-ac72d008ab32.png)

点滅のタイミングに合わせて、右下の「Terminal」のウィンドウに「1」、「0」と表示されます。
MicrobitをPythonのビジュアルプログラミングで制御できました。
AWS 作ってみたをまとめてみた

習うより慣れよ、ということでAWSで○○作ってみたという記事を集めてみた。記事通りに進めていけば完成させられるものばかりなので、チュートリアルにどうぞ。

# いろいろ

#### AWSを用いてWeb初心者がサーバーレスアプリケーションを作ってみた

https://zenn.dev/bizyu/articles/067eb3b92ca0f9

#### API GatewayとLambdaで簡易Webアプリを作ってみる

https://qiita.com/moufuyu/items/340048eef98d98f11187

#### 【個人開発】AWSでサーバーレスなWebスクレイピングアプリを作ってみた

https://qiita.com/ozzy3/items/b2ef8f5329484de5095f

#### 【多分初心者向け】AWS Amplify Studio に触ってみて、とりあえず1からwebページを作ってみた

https://dev.classmethod.jp/articles/aws-amplify-studio-maybe-beginner/

#### AWS Lambdaを使ってSlack通知ツールを作ってみた

https://www.softbank.jp/biz/blog/cloud-technology/articles/202301/deploy-a-slack-using-lambda/

#### AWSの無料枠でBitCoinの自動売買プログラム組んでみた

https://wooolwoool.hatenablog.com/entry/2023/11/25/161925

#### AWSを活用してLINEチャットボットを作ってみた！①

https://www.ryucom.co.jp/blog/aws/4713

# EC2

#### 【AWS】EC2を使って、WEBサイトを公開する流れ

https://zenn.dev/grazie/articles/20c05aa22738b5

#### 【超絶初心者向け】これだけでEC2を無料で建てられるブログ。前編

https://blog.denet.co.jp/wakaba_ec2/

# API Gateway

#### API Gatewayを試してみた

https://qiita.com/zumax/items/1625106991a680cd41a3

#### ゼロから作りながら覚えるAPI Gateway環境構築

https://dev.classmethod.jp/articles/getting-start-api-gateway/

# S3

#### 5分で非IT業務者にS3を使ってAWSを体験してもらった

https://dev.classmethod.jp/articles/have-a-non-it-worker-experience-aws-using-s3-in-5-minutes/

# DynamoDB

#### DynamoDBを試してみた

https://qiita.com/zumax/items/ef8a5c855161f9e4ba92

# IoT Core

#### AWS IoTサービスを使ってみた

https://www.ryucom.co.jp/blog/iot/2408

#### AWS Greengrassを動かしてみた

https://research.sakura.ad.jp/2017/06/26/aws-greengrass%E3%82%92%E5%8B%95%E3%81%8B%E3%81%97%E3%81%A6%E3%81%BF%E3%81%9F/
EC2にDockerでOpenVPNを構築してVPN接続をする

## さいしょに

通常のVPN接続ではなくて、特定のタイミングでパケットロスを擬似的に発生させたり、ネットワーク遅延を意図的に起こすための環境を構築していきます。

最後の項目をやらなければ、普通のVPNです。

## 準備

なるべく簡単に構築したいので、ec2インスタンスにdockerの環境を構築しておきます。
ちなみに以下はAmazonLinux2なので、AmazonLinux2023だと少し導入が違うかも。

docker
```bash
$ sudo yum update
$ sudo amazon-linux-extras install docker
$ sudo service docker start
$ sudo systemctl enable docker
$ sudo usermod -a -G docker ec2-user
```

compose
```bash
$ sudo curl -L https://github.com/docker/compose/releases/download/v2.17.3/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/lib/docker/cli-plugins/docker-compose
$ sudo chmod +x /usr/local/lib/docker/cli-plugins/docker-compose
```

## 起動
```bash
sudo docker run --rm -d --privileged -p 500:500/udp -p 4500:4500/udp -p 1701:1701/tcp \
  -e PSK='共有シークレットキー' \
  -e USERS='ユーザ名:パスワード' \
  siomiz/softethervpn
```

共有シークレットキーは適当な文字列にしてください。（pwgen 32　とか）

```
UDP 500
UDP 4500
TCP 1701
```
上記をFWで許可しておきます。


## 接続
Macの場合、L2TP over IPSecでec2インスタンスのパブリックIPへ上記共有シークレットキー・ユーザ名・パスワードで接続します。

## 擬似的なパケロスとネットワーク遅延
ec2で以下をインストール

```bash
$ sudo yum install dstat iproute-tc
```

3%パケットロス、100msの遅延をランダムに発生させる。
```bash
$ sudo tc qdisc add dev docker0 root netem delay 100ms 10ms loss 3%
```

遅延とパケロスを削除
```bash
$ sudo tc q
```

極稀にこういった環境が必要になるケースがありますが、参考までに。
店舗のネットワークアラートをGoogle Chatに通知する

**この投稿は、2023年JINSのアドベントカレンダー9日目の記事です。**

## 自己紹介
JINSのITデジタル部所属の内田(@j-uchi)と申します。
メインはアプリケーションを(TypeScriptなWebアプリが多い)書く人ですが、色々やってます。

## あらすじ
JINSでは国内店舗のネットワーク機器にCiscoのMerakiシリーズを採用しています。
500店舗近くあると、毎日日本のどこかで通信障害が発生します。
私が入社した直後は、これらのアラートは私の先輩社員がメールアラートを見て確認していたのですが、瞬断等のすでに復旧したものもメールが届くので、その確認に毎日膨大な時間を割いていました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3632669/fe26b752-c2d5-8bcb-aea7-32df45798025.png)

この確認の負担を少しでも減らすのが、私のJINS生活最初のお仕事でした。

## 目的
- 店舗でのネットワーク異常を検出する
    - 瞬断に関してはノイズになるので通知しない
    - 一定時間異常が継続した場合に通知する
    - 異常とは
        - NW機器(ルーター, スイッチ, 無線AP)の電源断
        - 上流回線の通信不能
        - AWSやデータセンターに設置されているVPNサーバーとの接続断
- 社内コミュニケーションツールである、Google Chatに通知する

これらをTypeScriptで書かれたスクリプトを定期実行することで実現しました。

## どうやって？
↓こんな感じでGoogle Chatに通知が来るようになりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3632669/e1fcfa81-7909-66f6-143f-6141149de52a.png)

Google ChatのWebhookの設定は非常に簡単で、チャットスペースの`アプリと統合`>`Webhook`の画面からWebhookを追加し、そこに表示される専用のURLにテキストをPOSTするだけです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3632669/e488e0bc-6564-1187-713e-feb9eb36b8dc.png)

```typescript:Google Chatに投稿
import axios from 'axios';

const WEBHOOK_URL =
  'https://chat.googleapis.com/v1/spaces/xxxxxxxxxx';

const postMessage = async (message:string) => {
  await axios.post(WEBHOOK_URL, { text: message });
}

postMessage("ほげほげ");
```

Google Chatのテキストフォーマット

https://developers.google.com/chat/format-messages?hl=ja

MerakiのAPIを叩くサンプルコードは[前回の記事](https://qiita.com/j-uchi/items/ca45a443e63f82a37854)に貼ったので今回は割愛します。


## 最後に
この機構を運用するようになってから、店舗のネットワーク障害発生に素早く気づくようになり、障害発生を見落とす事故も減りました。
結果的にネットワーク障害を原因としてお客様や店舗の従業員にに不便をおかけする頻度も減りました。

明日は @tskoma さんの DatadogをTerraformし始めたはなし です！お楽しみに！
Pythonの仮想環境作成方法

# Pythonの仮想環境作成方法
## 仮想環境を作成する目的
複数のバージョンのPythonを使用する場合には、仮想環境を作成する。

## 仮想環境作成
venvの後ろにディレクトリパスを指定すると、仮想環境の作成ができる。

~~~
python -m venv 
~~~

`--upgrade-deps`をつけて実行すると、仮想環境専用のpipが最新版に更新される。

## 仮想環境の有効化
pathの部分は、仮想環境を作成したディレクトリパス

~~~
{path}\Scripts\activate.bat
~~~

## 仮想環境の無効化

~~~
deactivate
~~~

## pipの最新化コマンド

~~~
pip install --upgrade pip
~~~
nestjs+fastifyとかdistributed tracingについてなにかかきます。

すいません。アドベントカレンダーに書こうと思っていたのですが投稿が遅れてしまいました。
これから書こうと思いますので書き終りましたら記事を更新します。

# 予告
私はMicoWorks株式会社でMico Cloudというサービスを開発運用しています。
MicoCloudではNestjs+fastifyを使ったマイクロサービスがあります。そちらでnewrelicをAPMを導入しようとしたら嵌ってしまいました。
NestjsのデフォルトのWebサーバーはexpressです。オプショナルでfastifyを使うことができます。
Nestjsでnewrelicを使うサンプルがnewrelicのブログにあったので試してみましたが、fastifyを使っている場合に上手く動きませんでした。
Nestjs+fastifyで動かすために試行錯誤した結果どのように解決したかを記事にしたいと思います。
[Python] pyenvのインストール時のエラー対処法

## pyenvを用いて、Pythonのver.の切替時にエラーが発生したため、備忘録としてここに記す。

### 環境
- MacOS Monterey
- Python2.7.18
- (Python3へ変更を試みていた)

### 手順
1. HomebrewがMac OSにインストールされているかの確認
 ~~~Bash
$ brew --version
 ~~~
2. Homebrewのインストール
 ~~~Bash
$ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
 ~~~
3. pynenvのインストール
  ~~~
$ git clone git://github.com/yyuu/pyenv.git ~/.pyenv
$ echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bash_profile
$ echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bash_profile
$ echo 'eval "$(pyenv init -)"' >> ~/.bash_profile
  ~~~
 上記~~~$ git clone git://github.com/yyuu/pyenv.git ~/.pyenv~~~でエラーが発生
4. このエラーはgitポートが制限されているために発生したと考えられる。したがって、次のコマンドで修正できます。
 ~~~
$ git config --global url.https://github.com/.insteadOf git://github.com/
~~~

### 参考リンク
[ポートの制限解除](https://stackoverflow.com/questions/72486457/fatal-unable-to-connect-to-github-com-github-com0-140-82-121-4-errno-unkno)
[pyenvのインストール](https://magazine.techacademy.jp/magazine/24451)
HomebrewのFormulaを作成して公開する

# はじめに

自作したコマンドをhomebrewでインストールして利用できるようにするまでの流れです。

結論こうなります。
```bash
$ brew install foobar-cli
$ foobar -v
```

## コマンドを作成する
インストールするコマンドを作成します。
これはどの言語でもいいのですが、インストール時にbuildしたりするよりもbinにしておいたほうがすんなり導入できると思います。

前回作成したgoのreplをコマンドとしてインストールするためgithubに置きます。
適当なタグをつけ、Releasesを作成してbinファイルをアップロードしておきます。

https://github.com/runeleaf/go-repl/releases/tag/v0.1.0

コマンド側の準備はこれで終わりです。

## Formulaを作成する

brewコマンドからあたらしいFormulaを作成します。
上記のReleaseにあるappファイルのURLを控えておきます。

```bash
$ brew create --set-name=go-repl https://github.com/runeleaf/go-repl/releases/download/v0.1.0/app

```

私の環境だと`/usr/local/Homebrew/Library/Taps/homebrew/homebrew-core/Formula/go-repl.rb`こちらにファイルが作成され、vscodeで開かれました。

このファイルをいったん適当な場所に移動させます。

```bash
$ mkdir -p go-brew/Formula
$ mv /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core/Formula/go-repl.rb go-brew/Formula
```

移動させたファイルを編集します。
最終的なファイルの内容は以下。
appコマンドをbin.installするという内容です。

```ruby
# Documentation: https://docs.brew.sh/Formula-Cookbook
#                https://rubydoc.brew.sh/Formula
# PLEASE REMOVE ALL GENERATED COMMENTS BEFORE SUBMITTING YOUR PULL REQUEST!
class GoRepl < Formula
  desc "A simple REPL for Go"
  homepage "https://github.com/runeleaf"
  url "https://github.com/runeleaf/go-repl/releases/download/v0.1.0/app"
  sha256 "0784f7ab8163a0ff2ddaf3cbc5ce7e2930287c1c75617614ba79d2a3d65314f7"
  license "MIT"

  def install
    bin.install "app"
  end

  test do
    system "true"
  end
end
```

ファイルの構成はこのような感じ。
```bash
$ cd go-repl
$ ls -T
.
├── Formula
│  └── go-repl.rb
└── README.md
```

上記のファイルをgithubにpushしておきます。
その際のリポジトリ名ですが、
`homebrew-go-repl`
というように先頭に`homebrew-`をつけておきます。

## brewコマンドでインストールする

まずtapし、そのあとinstallをします。

```bash
$ brew tap runeleaf/go-repl # homebrew-go-replのこと
$ brew install go-repl
```

これでgoで作成したコマンドの`app`が利用できるようになりました。

```bash
$ which app
/usr/local/bin/app
$ app
go> foobar
foobar
go> exit
Bye!
```

コマンドがアップデートされたら上記のhomebrew-go-replを更新しておけば、brewコマンドで更新をすることができます。

削除するときは以下のコマンドで削除できます。
```bash
$ brew remove go-repl
$ brew untap runeleaf/go-repl
```

作成したサンプルコード

https://github.com/runeleaf/go-repl

https://github.com/runeleaf/homebrew-go-repl
材料力学「The Myosotis Method(ミオソテスの方法)」を調べた。


# オリジナル (途中へ)　【例題：はりの途中の点の変形量が知りたい】
ぽるこ 様
・[ミオソテス基本例題：はりの途中の点の変形量](https://secondinspire.com/vol6-8_myosotis-1/#i-6)
・ここで重要なのは『はりOAがどんな負荷を受けているか』ということだが、...
・【Aが片持ちばりの先端になるように問題をおきかえる。】
・ミオソテス基本：知りたい点が先端になるように切る
ver0.1
```python
from sympy import *

var('P,a,b,EI',real=True)
var('δA,θA'   ,real=True)
δA=((P*b)*a**2/(2*EI)+P*a**3/(3*EI)).simplify()
θA=((P*b)*a   /   EI +P*a**2/(2*EI)).simplify()
print("#δA=",δA)
print("#θA=",θA)
#δA= P*a**2*(2*a + 3*b)/(6*EI)
#θA= P*a*(a + 2*b)/(2*EI)
```

# (参考)sympyで　SimpleBeam_C_Myosotis_Method 

＞Center-loaded simple beams

https://en.m.wikipedia.org/wiki/Deflection_(engineering)#Center-loaded%20simple%20beams

ver0.2
・ユーザー定義関数にしました。
・l=a+b
```python
from sympy import *

var('P,a,b'      ,real=True)
var('δc,θc,RA,EI',real=True)
var('l'          ,real=True)
def mySimpleBeam_C_Myosotis_Method(P,a,b,EI):
    ans=solve([Eq(δc+θc*a, b/(a+b)*P *a**3/(3*EI)),
               Eq(δc-θc*b, a/(a+b)*P *b**3/(3*EI))],[δc,θc])
    return {δc:ans[δc].simplify(),θc:ans[θc].simplify()}
def myCantilever_l(P,l,EI):
    return {δc:P*l**3/(3*EI).simplify(),θc:P*l**2/(2*EI).simplify()}
δc=mySimpleBeam_C_Myosotis_Method(P,a,l-a,EI)[δc]
print("#",δc)
print()
# 点Cのたわみ(a=l/2の時)　Center-loaded simple beams
print("#",δc.subs({a:l/2,b:l/2}))
print("#",myCantilever_l(P/2,l/2,EI)[δc])
# P*a**3/(6*EI)
# P*a**3/(6*EI)
```

ver0.1
・上と同じです。
```python
# ver0.1
from sympy import *

var('P,a,b'      ,real=True)
var('δc,θc,RA,EI',real=True)
RA=b/(a+b)*P
RB=a/(a+b)*P
eq1=Eq(δc+θc*a,RA*a**3/(3*EI))
eq2=Eq(δc-θc*b,RB*b**3/(3*EI))
ans=solve([eq1,eq2],[δc,θc])
print("#",ans[δc].simplify())
# P*a**2*b**2/(3*EI*(a + b))
print()
print("#",ans[δc].simplify().subs({b:a}))
print("#",(P/2)*a**3/(3*EI))
# P*a**3/(6*EI)
# P*a**3/(6*EI)
```
# google検索

https://www.google.com/search?q=%E3%83%9F%E3%82%AA%E3%82%BD%E3%83%86%E3%82%B9%E3%81%AE%E6%96%B9%E6%B3%95&sca_esv=589336079&rlz=1CAUHAM_enJP1038JP1038&biw=1366&bih=644&sxsrf=AM9HkKmVAmcWBYBYUqy1h8vvLz0VU0V31A%3A1702110802120&ei=UiZ0ZcXzBvre2roPgc2SiA0&oq=%E3%83%9F%E3%82%AA%E3%82%BD%E3%80%80%E6%96%B9%E6%B3%95%E3%80%80&gs_lp=Egxnd3Mtd2l6LXNlcnAiFeODn-OCquOCveOAgOaWueazleOAgCoCCAAyCBAAGIAEGKIEMggQABiABBiiBDIIEAAYgAQYogQyCBAAGIAEGKIESPRXUKY3WKY3cAF4AZABAJgB0gGgAdIBqgEDMi0xuAEByAEA-AEBwgIKEAAYRxjWBBiwA-IDBBgAIEGIBgGQBgo&sclient=gws-wiz-serp

# 参考

~~＞材料⼒学2021 シーズン2
http://www.md.ams.eng.osaka-u.ac.jp/~nakatani/Lectures/Strength_of_Materials/PDFs/2021zairikislides04.pdf~~
~~以下は「この接続ではプライバシーが保護されません」がでます。~~
~~https://www.md.ams.eng.osaka-u.ac.jp/~nakatani/Lectures/Strength_of_Materials/PDFs/2021zairikislides04.pdf#page=18==

https://qiita.com/mrrclb48z/items/e23e11b77d3f04bbd700
ransackをクエリパラメータで指定する方法

# この記事について
この記事は [SUPER STUDIO Advent Calendar 2023](https://qiita.com/advent-calendar/2023/superstudio) の9日目の記事になります。

# この記事を書こうと思った理由
仕事でRestAPIを使ってGETリクエストする際に、ransackをクエリパラメータで指定して検索条件を指定することがあるのですが、改めて使い方などを整理したいと思い、また、自分の知らなかった機能も最近知る機会が合ったので、改めてまとめてみようと思いました。

# そもそもransackとは
ransackをそのまま日本語訳するとあまり印象の良くない翻訳になりますが、簡単に言うとRailsのActiveRecordにおける検索機能を実装するgemになります。

# 使い方
基本的には[こちらのドキュメント](https://github.com/activerecord-hackery/ransack/blob/main/docs/docs/getting-started/search-matches.md)通り指定することで利用できますが、簡単に解説していきます。
```
# ex) user情報のnameカラムを検索条件に指定する場合(完全一致)
https://hoge.sample.com/api/users?q[name_eq]=hoge

# ex) user情報のnameカラムを検索条件に指定する場合(部分一致)
https://hoge.sample.com/api/users?q[name_cont]=hoge

# ex) user情報のidカラムを検索条件に指定する場合(複数指定)
https://hoge.sample.com/api/users?q[id_in][]=10&q[id_in][]=20

# ex) 日付カラムを範囲指定する場合の一例
https://hoge.sample.com/api/users?q[created_at_gt]=2023/12/01%2000:00:00&q[created_at_lteq]=2023/12/02%2000:00:00
```

booleanのカラムやtrue,falseで指定するパラメータは下記のように指定します
```
# ex) 論理削除済みのレコードを含めて検索する場合
https://hoge.sample.com/api/users?q[with_deleted]=1

# ex) activeカラムがtrueのデータを取得する場合
https://hoge.sample.com/api/users?q[active_true]=1

# ex) optionカラムがnullでないデータを取得する場合(presentなども使えます)
https://hoge.sample.com/api/users?q[option_not_null]=1
```


また、下記のようにソート条件を指定することもできます。
```
# created_atで昇順でソートする場合
https://hoge.sample.com/api/users?q[s]=created_at%20asc

# 第一ソートにupdated_atの降順、第二ソートにpositionの昇順でソートする場合
https://hoge.sample.com/api/users?q[s]=updated_at%20desc&q[s]=position%20asc
```


# まとめ
全てではないですが、ransackをクエリパラメータで指定して検索するやり方をまとめてみました。少しでも誰かの参考になれば幸いです。
CS8909の対処法

## 概要

関数ポインタを比較しようとすると警告が生成される。

> CS8909: 同じ関数へのポインターがそれぞれ異なっている可能性があるため、関数ポインターの比較によって予期しない結果が生成される恐れがあります。

> Taking address of the same method twice is not guaranteed to produce same pointer.
(https://github.com/dotnet/roslyn/issues/48919#issuecomment-717391699)

なぜだかは不明だが同一の関数を指すポインタは複数あるらしい。
アドレスが飛んでしまうことのパフォーマンスへの悪影響によるものかもしれないが、不詳。

## 対処法

とりあえずそういう性質があるという事実を受け止めて、なんとか対処しよう。

複数回取得した場合のポインタが同一であることが保証されないのだから、一回取得してそれを使い回せばいいだろう。

```CSharp
static Dictionary<MethodInfo, nint> _cache = new();
public static nint GetAddress(MethodInfo mI)
{
    if (!_cache.TryGetValue(mI, out var v))
        _cache.Add(mI, v = mI.MethodHandle.GetFunctionPointer());
    return v;
}
```

どのような経緯で関数ポインタの値が異なるのかわからない以上、一度異なってしまったアドレスが同一の関数を指すのかどうかを調べるのは困難である。

リフレクション経由になるのでパフォーマンス面で劣るが、良い解決策は講じれなかった。

## 最後に

なぜ同一の関数に対するポインターが異なってしまうのかについて情報を持っている方がいたら教えていただきたい。

## 参考

https://stackoverflow.com/questions/66630082/what-are-alternatives-to-comparing-unmanaged-function-pointers-in-c-sharp-how-t
AtherosのSPI

AtherosのMIPS SOCにはSPIサポートがあります。

初期のAR5の時代のものとAR7以降のものとAR934xで拡張された仕様があるようです。

AR7系が多いので、これを見ると非常に原始的なSPIサポートで、クロックビットを操作してバイトの8ビットを送信して、その時の受信データがレジスタに入るという仕様でした。

さすがにこれではパフォーマンスがでません。

よくよくデーターシートを見るとSerial Flashの内容が0x1f000000からのメモリアドレスにマップされる機構があって、これを使うと高速にアクセスできるようです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/94377726-5604-ab95-a4c4-d8c20a89b6dd.png)

以前書いたflashの記事でもfreescaleのimxで同じ機能があるって教えてもらいました。

実はAR5をやってたときに、なんとなくきがついていたのですが、あまりまじめに調べていませんでした。

Ralinkの同じくらいのクロックのSOCが早いと感じたのはこのためかもしれません。

結局AR934Xで拡張された32Bit単位での処理を実装してみました。
GASとVueを使った開発でChatGPT初心者が活用したお話

## 重い腰を上げて
AI活用しようという流れがありました。「乗るしかない、このビッグウェーブに」。食わず嫌いなところもあったけど、置いていかれるのも問題だと感じました。

## 使い始め
最初のプロンプトはこんな感じでした：
> GoogleサイトでHTML形式の登録フォームを作成する方法を教えてください。
> 入力項目は以下の内容です。
> ・休暇の取得日を日付カレンダー形式の入力
> ・休暇の取得数をセレクトボックスの入力 

```
GoogleサイトはHTMLコードの直接埋め込みが制約があり、
Gmailアドレスの自動入力などの高度な機能はサポートしていません。
しかし、以下は、Google Formsを使用して簡単にフォームを作成し、、、(略)
```
あー、、、すごい。けどもうちょっとカスタマイズしたいから。

## コードが具体的になってきた
その後、色々やってきて作りたいのはGoogleサイトじゃ制限あって実現できないなとなり：
> GoogleAppScriptでHTML形式の登録フォームを作成する方法を具体的なソースコードを添えて教えてください。
入力項目は以下の内容です。
> (内容は同上のため割愛)

返ってきたのはGoogle Formsでフォームを作成する・・・

うーんそうじゃなくて、もっとHTML使いたい。
入力元をスプレッドシートに変更したい。
そこで以下のプロンプトを：
> そうじゃなくて、GoogleAppScriptでHTML形式の登録フォームを作成する方法を具体的なソースコードを添えて教えてください。
> 休暇の取得数をセレクトボックス形式の入力で選択項目をスプレッドシートから取得する。``
> 取得理由をラジオボタン形式の入力で、選択項目をスプレッドシートから取得する。``
> その他を選択した場合はテキストボックスを表示する``

すると。。。
```javascript
function doGet() {
  var htmlOutput = HtmlService.createHtmlOutputFromFile('Form')
    .setTitle('休暇申請フォーム')
    .setWidth(400);
  return htmlOutput;
}

function getOptions(column) {
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Options');
  var values = sheet.getRange(column + '2:' + column + sheet.getLastRow()).getValues();
  return values.flat();
}

function submitForm(form) {
  var userEmail = Session.getActiveUser().getEmail();
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
  var data = [userEmail, form.startDate, form.endDate, form.duration, form.reason, form.otherReason, form.notes];
  sheet.appendRow(data);
  return 'フォームが送信されました！';
}
```
HTMLソースは割愛しますがちゃんとGAS側のソースができた！

感想：**なんかこれはまるで、攻略本見ながらゲームしている感覚**

## 想定と違う時の軌道修正
「そうじゃなくて、(修正内容)」というフレーズをよく使います。

## やはり元の言語の知識は必要（あたりまえか）
Vueは自学で勉強していたり、実務でも少し使っていました。しかし、最近触っておらず、Vue3は未経験でした。
ただ、ChatGPTさんに分からないことを
> vue3のrefの概念がわからないのでおしえて 

とかお願いしてみたり。
むしろ、積極的に質問しました。

もちろん公式ドキュメントや他のサイトもググって裏取ったり、知識の補完はしていましたし
個人的にはまだまだ必要かなと感じています。

ただ、今更人に聞きにくい事とかをストレートに聞けるのは精神衛生的にも非常に良く
**もっと早く活用しておけばよかった**
と感じています。

ちなみに先月よりお布施(課金)始めました。
Milk-v duo用ビジュアルプログラミング環境を妄想してMind+を使ってみる。Raspberry pi pico編

## はじめに
秋葉原ロボット部の有志で、milk-v duoを購入し、個々人が様々な実験を行って、勉強会内で報告しています。

Milk-v duoは9ドルのrisc-vコンピュータとして知られています。
ハードウェアは以下の通りです。

1. CPUはCVITEKのCV1800B (C906@1Ghz + C906@700MHz)
1. 最高1 GHzで動作するデュアルRV64コア
1. 64 MBのラム
1. オプションのアドオンボードを接続すると10/100Mbpsの速度でイーサーネットに接続可能

pinpongドライバ対応のボードのプログラミングにMind+を使うことができます。
https://mindplus.cc/en.html
今回は、Raspberry pi picoのMicroPythonプログラミングをMind＋を使って、行います。

## Raspberry pi picoにUF2ファイルをドラッグ＆ドロップ
Raspberry pi picoでMicroPythonを使用するには、事前に「rp2-pico-latest.uf2」を導入する必要があります。
「rp2-pico-latest.uf2」は以下のurlにあります。
https://www.raspberrypi.com/documentation/microcontrollers/micropython.html
WifiとBTに対応したRaspberry pi pico WとRaspberry pi pico用のUF2ファイルがあります。
今回は、Raspberry pi pico用 MicroPython UF2ファイル「rp2-pico-latest.uf2」をダウンロードします。
https://micropython.org/download/rp2-pico/rp2-pico-latest.uf2
Raspberry pi picoの「BootSel」ボタンを押しながら、WindowsマシンにUSBケーブルを接続します。
「RPI-RP2」というドライブのフォルダーが開かれるので、「rp2-pico-latest.uf2」をドラッグ＆ドロップします。
コピーが完了すると、フォルダーが見えなくなります。

## Mind+からMicroPythonプログラム
ボードの選択までは、「Milk-v duo用ビジュアルプログラミング環境を妄想してMind+を使ってみる。Arduino uno編」に従って行います。
次に、「デバイスを接続」から、Raspberry pi picoのCOMポート、「pico」を選択します。
さらに、右上の歯車の下の部分に「MicroPython」が選択されていることを確認します。
プログラムの作成は「制御」のウィンドウから部品を選んでLチカのプログラムを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/693019/bea8edf1-2fec-b49e-dff4-f662c4749e9c.png)
プログラムが完成したら、「実行」をクリックしてファイルを転送します。
プログラムにエラーが無く、転送が無事終了したら、ボード上のLEDが点滅します。
美しい！！Elixirの関数定義

Elixirの利用者の一人の意見です

Elixirの関数の定義は、関数型言語らしい特徴があります。

数学での関数の定義は、xの範囲に応じて定義する表記ができます。

```math
f(x) = \left\{ \begin{array}{l}
\displaystyle x ( x >= 0 ) \\
0  ( x < 0 )
\end{array} \right.
```

Pythonでこの関数を書いてみると

```Python
def f(x) do
    if x >= 0:
        return x
    else:
        return 0
```

一つの関数の中で場合分けする記述でしか書けません。

Elixirの場合

```Elixir
def f(x) when x >= 0, do: x
def f(x) when x < 0, do: 0
```

美しい！
実に美しい！
稼働中のVM止めちゃってあたふたした話

BeeX Advent Calendar 2023 10日目 の記事です

# ご報告
12/8（金） JSUG Conference 2023 に行ってきました！（初参加）
弊社ブースに足を運んでくださった方、セッション事例を聞いてくださった方ありがとうございました。
午後ブースに立ち、会社紹介やパンフレット配布を担当しておりましたが、笑顔で受け取ってくれたり熱心に話を聞いてくれた方が多かったのがとても印象的です。いろいろな方とお話をして「どんなことに悩んでいるのか？」、「何が課題になっているのか」など聞けて私自身とても勉強になりました。

弊社の経営理念として、「With Customer」を掲げており、お客様と共に悩みや課題を解決していけるように努力を続けておりますので、もしご縁がございましたら弊社をどうぞよろしくお願いいたします。

# 本題
SAP環境構築Prjに携わっており、Azure環境でのインフラ担当として日々活動しております。

環境構築自体は落ち着いてきましたが、構築後の仮想マシンの非機能要件を設計/実装が終わり、一時的な設定変更をしているところで、起きてしまった出来事を共有できればと思います！

# とある日に仕事依頼
お客様へ環境をリリースする前の総合テストが始まるため、以下のように稼働スケジュールを変更してほしいとの依頼をいただきました。
※ テスト初日での依頼で、急いで設定してもらえると嬉しいとのことで優先度が高い仕事の依頼でした。

|  | 変更前の設定 | 変更後の設定 |
|:-:|:-:|:-:|
| 起動  | 9:00  | 7:30  |
| 停止  | 22:00  | 23:00  |

仮想マシンの起動停止は、自動化しており『Start/Stop VMs v2』を利用しています。

# 私が対応したこと
総合テスト期間中稼働スケジュール変更だったため、設定していた起動ジョブと停止ジョブを「無効化」して臨時ジョブを作成して有効化する対応をとることにしました。

# 事件発生
設定作業は日中帯に実施しており、おやつの時間が過ぎた16:00くらいにチャットで連絡があり、「サーバが停止してしまったため調査と起動をお願いします」との連絡がありました。

Azure側の障害で仮想マシンが落ちたのかしら？とのんきなことを思いながらアクティビティログを確認すると臨時で作成した停止ジョブが動いていることが判明しました。

# どんな設定をしたの？
以下設定でジョブを保存して有効化をしました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3521211/7bb35b38-4d30-8758-452d-adf7a1c322ef.png)

『開始時刻』の設定値が「2023-12-10T22:59:00」と未来日時に設定したので、ジョブが有効化されて即時実行されたとしても、動かないだろうと思っておりましたがどうもそれが違うみたいです・・・

新規でジョブを作成した際の最初の有効化は『開始時間』が未来日時であっても動いてしまうということが分かりました。

今まで設定していたスケジュールの時間変更であれば、開始時間を未来日時にしておけば実行はされませんでしたが、初回でジョブを作成したことによって発生してしまった事件になります。。

# まとめ
以下、今回の事故により分かったことです。

・ジョブ作成時の初回実行は、どんな条件であれ即時実行される
・一度作成済みのジョブを無効化 -> 有効化した際は即時実行はされないが、開始時刻が未来時刻でないといけない（過去時刻だと即時時刻されちゃいます）

https://learn.microsoft.com/ja-jp/azure/logic-apps/concepts-schedule-automated-recurring-tasks-workflows#patterns-for-start-date-and-time

起動している仮想マシンに対して、起動ジョブを作成/変更しているのであれば状態遷移はないですが、停止ジョブを変更する際は上記意識したうえで変更が必要になります。

# 最後に
稼働しているサーバを停止する事故は新人の時以来経験したことがなく、
今回久しぶりだったため、とても心臓に悪かったです。
※ お客様へ環境をリリースした後じゃなくてよかった・・・

Start/Stop VMs v2で仮想マシンの自動起動停止を制御している方も多いと思いますが、事故が起きないように今一度仕様を再度理解してもらえるようなブログになっていると幸いです。
app.record.detail.process.proceedのイベントハンドラーのベストプラクティス

## はじめに
みなさん、`app.record.detail.process.proceed`使ってますか？
その名も「プロセス管理でアクションを実行するときのイベント」です。

このイベント、詳細画面ながらフィールドの書き換えにも対応していてかつPromise対応もしている結構便利なイベントなので重宝している方もいらっしゃるのではないでしょうか。

私も最近よくこのイベントを使うのですが、一つのイベントに対して紐づけたい関数が複数になることが多いイベントなんですよね。
というのも、プロセスが申請中になったらXXX、プロセスが完了になったらYYYのようにプロセスの状態に応じて関数を使い分けることが多いからなんです。

今回はこの複数の関数の紐付けのベストプラクティスを考えてみました。

## ド定番
やはりパッと思いつくのはイベントオブジェクトのにある`event.action`や`event.status`を用いてIF文で分岐する方法でしょうか。

```javascript
  const showConsolle = () => {
    console.log('申請中に移行します');
  };

  const showAlert = () => {
    alert('完了します');
  };

  kintone.events.on('app.record.detail.process.proceed', (event) => {
    if (event.nextStatus.value === '申請中') {
      showConsolle();
    }

    if (event.nextStatus.value === '完了') {
      showAlert();
    }

    return event;
  });

```

まあこの形でも十分なんですが、紐づける関数が多くなってくるとやや冗長な気がしてきます。

## ベストプラクティスを目指して
というわけでこの`kintone.events.on`以降のコードを最適化していきたいと思います。
手をつけられそうなのはこのIF文です。
```javascript
if (event.nextStatus.value === '申請中')
```

`event.nextStatus.value`が特定の値だったら、特定の関数を実行すればいいわけです。
今回のケースであれば`申請中`だったら`showConsole`、`完了`だったら`showAlert`ですね。
このAとB、CとDのような紐付けはJSをやっている人ならパッと浮かぶでしょう。
そう、オブジェクトですね。オブジェクトには関数を入れ込むこともできました。

```javascript
const nextStatus = {
    申請中: showConsole,
    完了: showAlert,
};
```

この時点で()をつけてしまうと即時関数になってしまうので注意が必要です。

さて、ここまできたら`nextStatus`のキーが`event.nextStatus.value`と一致したバリューを取り出せば良いので…

```javascript
nextStatus[event.nextStatus.value]

// event.nextStatus.value　が 申請中 の場合は nextStatus['申請中']と置き換わり showConsole が取り出せる
```

このように表現できますね。
あとはこの値がFalsyでなければ関数を実行するようにしてあげればいいわけです。

```javascript
const nextStatusFunc = actions[event.action.value];
if (nextStatusFunc) {
    await actionFunc(event);
}
```

これで紐付けたい関数が増えても`nextStatus`に足していくだけですね。

## まとめ
kintoneカスタマイズをしていると、何も考えずいつものやり方で…となってしまうことも少なくありません。
たまにはこうしてより良い書き方を考えていけると良いですね。