OmniAICreator/Qiita-1.07M huggingface dataset:
Jestでテストを自動化する

# Jestとは？
meta(Facebook)製のテスト用のjavascriptフレームワーク。

# UIテストを自動化
### テストの目的
- DOMの出力が期待通りであるか
- コードの変更前後でDOMの出力に差分が発生していないか（スナップショットテスト）

# スナップショットテスト
##### パッケージをインストール
まず、react-test-rendererというパッケージをインストールする。
```
npm install --dev react-test-renderer
```
##### テストファイルを作成
test/example.test.js
```javascript:test/example.test.js
import React from "react";
import renderer from "react-test-renderer";
import App from "../App";

it("Page snapshot testing", () => {
  const component = renderer.create(<App />);
  expect(component).toMatchSnapshot();
});
```
##### テストを実行
```
npm test
```
# ユニットテスト
##### ユニットテスト用にLinkコンポーネントを作る。
```javascript:src/Link.js
import React from "react";

export const Link = (props) => {
  retrun (
    <a
     href="http://reactjs.org"
     target="_brank"
     rel="noopener noreferrer"
    >
      {props.text || "No contents"}
    </a>
  );
};

```
App.jsも変更
```javascript:src/App.js
import React from "react";
import logo from "./logo.svg";
import Link from "./Link";
import "./App.css";

export const App = () => {
  retrun (
    <div className="App">
      <header>
        <img src={logo} className="App-logo" alt="logo" />
        <Link text="Learn React" />
      < /header>
    </div>
  );
};
```
##### テストコードの作成
Linkコンポーネントがpropsが渡されたときと渡されてない時でUIが変わる。
このパターンが正常に機能するかをテストする。
```javascript:src/tests/Link.test.jsx
import React from "react";
import { render } from "react-dom";
import { act } from "react-dom/test-utils";
import Link from "./Link";

describe("Link component testing", () => {
  let container = null;
  container = document.createElement("div");
  document.body.appendChild(container);
  
  it("render", () => {
    // テストケース１
    act(() => {
      render(<Link />, container);
    });
    // propsが渡されない場合
    expect(container.textContent).toBe("No contents");

    // テストケース２
    act(() => {
      render(<Link />, container);
    });
    // propsが渡されない場合
    expect(container.textContent).toBe("this link");
  });
})
```
describe(name, fn)でテストのパッケージ化（ラップ）を行う。
act() Reactのテスト関数。render状態を表現する。

# 参考
https://jestjs.io/ja/docs/tutorial-react

https://dev.classmethod.jp/articles/snapshot-test-of-the-react-app-using-jest/

https://ajike.github.io/test-jest-javascript/
暗号化のトレイルヘッドが他にも影響している。


# Select Id,Name from Contact where LastName =:lastName and MailingPostalCode                                   ^ ERROR at Row:1:Column:35 field 'LastName' can not be filtered in a query call

このエラーの質問ががここ数日間目につきます。

+ [How can I fix the errors in SOQL program?](https://trailhead.salesforce.com/en/trailblazer-community/feed/0D54S00000HkUis)
+ [Write SOQL Queries Error](https://trailhead.salesforce.com/ja/trailblazer-community/feed/0D54S00000HkagvSAB)


個人的には暗号化が怪しいと思っています。

2人ともこのトレイルヘッドを完了している。
[Shield Platform Encryption](https://trailhead.salesforce.com/en/content/learn/modules/spe_admins)

https://github.com/SalesforceFoundation/Volunteers-for-Salesforce/issues/487

誰も信じてくれないけど３人目を発見
+ [Error in Hunt Your Prospect Unit](https://trailhead.salesforce.com/en/trailblazer-community/feed/0D54S00000JdxIfSAJ)

# There was an unhandled exception. Please reference ID: MKNQAVZC. Error: Faraday::ClientError. Message: INVALID_FIELD: description from account where name = 'Blackbeards Grog Emporium' ^ ERROR at Row:1:Column:43 field 'name' can not be filtered in a query call

It looks like you are using an org that was used for another challenge where you encrypted the name field in accounts. You won't be able to pass this challenge with that org, you'll have to sign up for a new DE org and do the challenge in that one.

[Trailhead Challenge not working. Apex Rest API unit in tralead](https://developer.salesforce.com/forums/?id=9060G0000005VGLQA2)

4人目

+ [I am facing problem in Write SOQL Queries](https://trailhead.salesforce.com/trailblazer-community/feed?tab=questions)

+ [Getting error in Write SOQL Queries](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V0000798KOgSAM)
【Rails】【Ruby】form_with で入力された値（params）を取得したい！

## はじめに
未経験からエンジニアに転職しました。
まだまだわからないことだらけですが、毎日楽しく働いています！

業務や個人開発での発見やエラー解決などをアウトプットしています。
初学者向けの内容です。

## やること
Railsの form_with で入力された値を取得して色々操作したい。
今回はサンプルとして
「form_with で入力されたID（数値）を取得して、そのID（数値）を使ってデータを操作する」をやってみる。


# 手順
~~~ruby:view
<%= form_with url: huga_huga_path, method: :patch, local: true do |f| %>
 <div class="field">
                # :hoge_id がparams になる
  <%= f.text_area :hoge_id, class: 'textarea' %>
  <%= f.submit %>
 </div>
<% end %>
~~~

![スクリーンショット 2022-06-03 8.31.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/916052/463e7a05-4b65-c445-c918-0748b509525e.png)
↑のように、textarea に数値が複数入力されたと想定する。

form　に入力された値を取得するには、
~~~ruby
params[:hoge_id]
~~~
上記のように書く。

view で↓のように、「:hoge_id」と書いた部分がparamsになる
~~~ruby
<%= f.text_area :hoge_id, class: 'textarea' %>
~~~


## 使い方のサンプル
このサンプルでは、↓をやってみる。
「入力された数値を取得して、その数値と同じidのデータをupdate_all で一括更新する」



~~~ruby:controller
# fromに入力された数値を取得する
# .split(/\R/) をすることで、改行して入力された数値を区切ることができる
hoge_ids = params[:hoge_id].split(/\R/)

# DBから、数値が同じIDかつステータスがdraftのデータを検索してきて、
huga = Model.where(id: hoge_ids, status: :draft)

# update_all で、データを一括で更新する
huga.update_all(status: :published, published_at: Time.current)
~~~



# 参考
https://qiita.com/tarhashi/items/d8ce2ce650d24af875d6
20200603_第1回社内向勉強会_つまらなそうな情報科学は実は面白い?

これは株式会社ネッコス・やどかりさんにおいて行うゆるふわ社内朝活用のメモです。

# 2022/6/3<br />つまりなそうな情報科学は実は面白い?

---

# 今日のアジェンダ

- 自己紹介(5分)
- 勉強すると何が良いのか(5分)
- 情報科学をざっくり紹介

---

# 自己紹介

年表とともにここ13年くらいを振り返ります。
そのとき流行っていた言語なども紹介します。

----

# 情報科学とは?

- コンピュータの仕組み
- ネットワークの仕組み
- プログラミング理論
- データベースの仕組み

---

# つまり仕組みのお話!

+ それと歴史

---

# では逆に実務に役に立つネタとは?

---

# 実務ネタ

- AWSの使い方
- フレームワークの使い方
- プログラムの書き方

---

# つまりは使い方!

---

# では仕組み(情報科学)を勉強すると何が良いのか?

- つまらなそう?
- 実務には役に立たない?

---

# 面白いから!(建前)

---

# 仕組みを知るとできること

- 早くなる(できないことができる)
- エスパーできる(問題解決)

---

# 早くなる

ミッション : 72時間かかる移行処理わ15分以内に実施せよ!
実際にあったリプレイス案件のデータ移行の話

---

# 早くなる(事例)

- 72時間かかる移行処理を3分で!
- 15分かかる集計処理を3秒で!
- (初期)Paizaのランキング最上位ランク!

---

# エスパーできる

みんなお手上げのバグを3日かけて特定する

---

# キーワードは抽象化

---

# 抽象化とレイヤー

- なんでエンジニアが必要なのか
- どこに集中するのか
- サーバーレスの図(参考)

---

# 情報科学をざっくり紹介

- ネットワーク
- コンピュータ
- プログラミング
- データベース・トランザクション


# でも使い方の勉強会もしたいかも

- Linuxコマンド入門
- SQL入門
- 正規表現入門

---

# 情報の探し方

- AWSカンファレンス
- Googleカンファレンス

---

# 次回予告

- AWS Summit 2022の簡単なおさらい
クラウドエンジニアの自分が人生でやりたいことリスト100(プライベート編)

# なんでこの記事を書くの？

僕の友人が面白い記事を更新していたので、その影響を受けて。

https://note.com/turatura_toudai/n/n335a2768c4d7

整理のため自分も一度人生のやりたいことを書き起こしておくべきかなと思った。
他のエンジニアの方にも参考にして頂きたく、また意見交換をできたらなと。

キャリア編

https://qiita.com/cakofei/items/7a86404c4a3b8ab473fb

# リスト100(都度更新予定)
1. ハンターハンターを見届ける、富樫先生お願いします
2. 大好きな人と結婚したい
2. ディズニーシーのあのホテルに泊まる
2. 大好きな友人達とこれからも仲良くできますように
2. 鶏の唐揚げの極致に出会いたい(大分、北海道など巡る？海外にも有名なのあるのかな)
2. 北海道に半年ほど住みたい、札幌、函館など
2. 神戸、広島、福岡に3か月ずつ住みたい
2. 京都にもう一度生活したい(大学寮楽しかったなあ)
2. 仕事をこのまま楽しむ、なんだかんだ社会人(エンジニア)の方が圧倒的に楽しい
2. 何か面白い趣味を定期的に見つけたい
2. ポーカーを上手くなって、バーで誰かと仲良くなる
2. エンジニアとして少し有名になる(定期的なアウトプットが必要ですね～)
2. 勉強会やブログにて0→1フェーズを分かりやすく後輩などに教育する
2. 家族孝行、ヨーロッパ連れて行ってあげたい
2. もこう先生に会う、社会人1年目の時の心の支え
2. 10万円超える焼き肉を食べる
2. 洋楽を上手に歌えるようになる、avicil
2. サンリオピューロランドでシナモンに癒される
2. ダイエットして腹筋を割る
2. 1からプロダクトを作りたい、今友人たちと音楽レビューアプリ開発を始めた
2. 年収1000万を超えたい、というか将来子供が安心して暮らせるレベルを稼ぎたい
2. 東京の海の見えるタワマンでぐふふ、1か月だけ住ませてくれない？
2. ブロックチェーン関係のプロジェクトに関わりたい、defiは革命だ
2. PancakeSwapの行き先を見届けたい、天才集団の未来は？
2. 一人だけ当時好きだった人ともう一度話したい
2. 誰かに何かを与え続ける人になりたいし、その為の余裕が欲しい
2. ありがとうを定期的に言われたい、その一言で馬車馬のように働けます
2. 友達か恋人と2週間くらいオーストラリア行きたい
2. 全身脱毛
2. クラブで踊りたい、まっっっっったく踊れないけど
2. 本格的な釣り、船上で刺身やね
2. クッソ高い寿司食べる、同じネタを何個も
2. 水曜日のダウンタウンとかりそめ天国以上に面白い番組を見つける
2. 「大切なものは、欲しいものより先に来た」と言える人生を送る、ハンターハンターの名言ですね
2. 高校の友人たちと夜中にするくだらない議論がいつまでも続きますように
2. クルーズディナー
2. 夜の景色の良いところでBBQ!!!
2. ショーシャンクの空にを超える映画を見つける
2. ハンターハンターを超える漫画を見つける
2. 朝型人間になる(現在7:58)
2. スマブラにもう一回本気を出す(タミスマで配信台に立つ)

本日はここまで(2022/6/3)
unibody 2010midのMac miniでNvidia SDK Managerを使う

# 動作環境
8GBに拡張した2010midのMac miniにubuntu18LTSをインストール。ディスクは500GBのSSDに交換。`交換の際にはデバイスのコネクタを壊さないように。私は温度センサーのコネクタを壊しVintageから購入する羽目になった。センサがないとフルスピードで動作しない。`
メモリーはAppleの仕様では2010midは4GBが最大となっているが、

https://www.vintagecomp.com/shopdisplayproducts.asp?id=665&cat=メモリMac+mini%0D%0AMid+2010%0D%0A最大16GB

の情報で最大16GBとあり、こちらから入手した8GBキットで拡張し、SDK managerの動作条件を満たした。

# ubuntuのバージョン
`ubuntu20LTSの場合、SDK manager1.8にJetPack5以前はサポートしないと表示される(2022/6/1)`ため、ubuntu18LTSを使用した。

# USBディスク
Mac miniでUSBディスクにubuntuをインストールし、2013Lateの15'BookProで起動させたかったが、miniでは起動できても、BookProでは起動できなかった。BookProはBig Surにまでバージョンアップしたので、そのせいかもしれない。

# 最後に
SDK managerでJetsonへのインストールをFinishできれば、安心だが、動作環境を用意するのが大変。将来はNXやAGXで作業できるようにしてもらいたい。クロスコンパイルで無くなるし、何より動作条件を満たしたハードウェアがNvidiaから提供される。

Macの仮想環境上にUbuntuをインストールした場合は、Finishできなかったが、ネイティブ環境を用意することで、Finishできるようになった。Macの能力が不足するせいか、timeoutする場合もあるが。2013LateのMBP15で外部ディスクからの起動を成功させて、インストールできるようにしたい。外部ディスクから起動できれば、FPGA開発環境も使用できるようになる。
T2搭載Macも、M1Macも応用が効くようになれば良いが。とりあえず`VintageMac万歳`
GitHub Actions for Databricksを用いてデータとMLのワークフローを自動化する

[How to Implement CI/CD on Databricks With GitHub Actions \- The Databricks Blog](https://databricks.com/blog/2022/06/02/automate-your-data-and-ml-workflows-with-github-actions-for-databricks.html)の翻訳です。

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

データと機械学習(ML)の需要が高まるにつれて、ビジネスサイドは大規模に信頼性のあるデータとAIのワークフローをデプロイできるように、継続的インテグレーション、デプロイメントのプラクティスを導入しています。本日、お使いのCI/CDプロバイダーからMLワークフローのテストとデプロイメントの自動化を容易にする[GitHub Actions for Databricks](https://docs.databricks.com/dev-tools/ci-cd/ci-cd-github.html)の第一弾を発表します。例えば、プルリクエストにおいてインテグレーションテストを実行したり、mainへのプッシュでMLトレーニングパイプラインを実行することができます。ワークフローを自動化することで、開発者の生産性を改善し、デプロイメントを加速し、エンドユーザーや組織にさらなる価値を提供できるようになります。

# GitHub Actions for DatabricksはCI/CDワークフローをシンプルにします

現在、チームはデータとAIワークフローのためのCI/CDパイプラインをセットアップするのに膨大な時間を費やしています。これらCI/CDパイプラインを手組みすることは苦痛を伴うプロセスであり、複数のAPIを組み合わせたり、カスタムプラグインを開発し、それらのパイプラインを維持していく必要があります。GitHub Actions for Databricksは、GitHub ActionsからDatabricksノートブックを実行するシンプルかつ簡単な方法を提供するファーストパーティのアクションです。これらのアクションのリリースによって、Databricksの自動化ワークフローを容易に作成、管理できるようになります。

# GitHub Actions for Databricksで何ができるのでしょうか？

我々は、データエンジニアやデータサイエンティストがGitHubから直接ノートブックを実行できるようにする2つの新たなGitHub Actionsを[GitHub marketplace](https://github.com/marketplace?query=databricks+publisher%3Adatabricks+)でリリースしました。

さまざまな方法でリポジトリからノートブックを実行するためにこれらのアクションを使用することができます。例えば、以下のタスクを実行するためにこれらを活用することができます。

- 現在のリポジトリからDatabricksノートブックを実行し、完了を待つ。
- 現在のリポジトリとPyPIの依存ライブラリを使用してノートブックを実行する。
- Databricksワークスペースで既存のノートブックを実行する。
- 異なるワークスペースでノートブックを実行する。例えば、ステージング用ワークスペースでノートブックを実行し、プロダクション用ワークスペースでノートブックを実行する。
- あるノートブックの出力を別のノートブックの入力として、複数のノートブックを連続で実行する。

GitHub ActionsのワークフローからDatabricksノートブックを実行するために、どのようにこの新たなアクションを使用するのかを説明するサンプルを以下に示します。

```yaml:YAML
name: Run a notebook in databricks on PRs

on:
 pull_request:

jobs:
 run-databricks-notebook:
   runs-on: ubuntu-latest
   steps:
     - name: Checkout repo
       uses: actions/checkout@v2
     - name: Run a databricks notebook
       uses: databricks/run-notebook@v0
       with:
         local-notebook-path: path/to/my/databricks_notebook.py
         databricks-host: https://adb-XXXX.XX.dev.azuredatabricks.net
         databricks-token: ${{ secrets.DATABRICKS_TOKEN }}
         git-commit: ${{ github.event.pull_request.head.sha }}
         new-cluster-json: >
           {
             "num_workers": 1,
             "spark_version": "10.4.x-scala2.12",
             "node_type_id": "Standard_D3_v2"
           }
```

# GitHub Actions for Databricksを使ってみる

試す準備はできていますか？GitHub Actions for Databricksの詳細と使い方はドキュメント:[Continuous integration and delivery on Databricks using GitHub Actions](https://docs.databricks.com/dev-tools/ci-cd/ci-cd-github.html)をご覧ください。

### Databricks 無料トライアル

[Databricks 無料トライアル](https://databricks.com/jp/try-databricks)
STM32G031とMCP9701で温度をPA2ハードウェアシリアルに出力


x MCP9701-E/TO 販売コード 103199

x 動作確認済み2022/6/3 18:46

x あまり正確では、ない

目的
秋月で売っている安価なMCP9701(約25円)を使って温度を出力する。

構成
MCP9701-E/TO I-03199

説明
MCP9701は、
0℃の時、400mV
1℃あたり19.5mV
精度は、±4℃
電線が引き出しやすい位置のPA4をアナログ入力にする
計算には、容量削減の為に浮動小数点となるべく割り算は、使わない
MCP9700は、ファミリー、オフセット500mV、10mV/1℃ 今回は、使わない

19.5は、1℃あたりの電圧
3300は、ADCの電圧
400は、0℃

3300/19.5=169.2
400/19.5=20.5

(4096*1692)/4096=1692



![o_con516.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/4334d444-c0cf-b00c-3c14-f543389e5306.jpeg)



```c++


//S_SER_9701_V2_031_2


#include <Arduino.h>
#include <HardwareSerial.h>

//10の割り算 0から1028までは、正しい。主に0から999
#define DIV10(n) ((n*205)>>11)


//初期化
void setup()
{

  delay(3000); //not delete

  //シリアルの初期化
  Serial.setTx(PA2_ALT1);
  Serial.setHalfDuplex();
  Serial.begin(9600);

} //setup


//メインループ
void loop()
{

  //アナログ値の読み込み  
  analogReadResolution(12); //adc 12bit mode
  int s = analogRead(A3);   // PA11 PIN5 031

  //電圧を温度に変換 ex 20.0 -> 200 温度の十倍を出力
  s = ((s * 1692) >> 12) - 205;

  //温度の表示
  Serial.print( DIV10(s) );            // 小数点以上
  Serial.print(".");
  Serial.print( s - (DIV10(s) * 10) ); // 小数点以下
  Serial.println();

  //1秒の待ち
  delay(1000);

} //loop


```
100日後くらいに個人開発するぞ！day038

## 今日は変数を使ってみた！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2632394/3738f32e-d525-657e-f430-c37b7d41ccc6.png)



## 今日の学び

### 変数とは
* 変数とは：値を入れる箱のようなものを変数という。
* 変数の定義：変数を使うには定義する必要があり、「変数名＝値」で定義する。
* 代入とは：変数に値を入れることを代入という。
* 注意点
    * 変数をクオーテーションで囲むと変数ではなく文字列となる
    * プログラムは上から順に実行されるため変数を定義した後でしか使えない

### 変数を使うメリット
* 同じ要素を繰り返し使える
* 変更に対応しやすい
* 何の要素かわかりやすい


### 変数名のルール
＊ 英単語を用いる 
    * 頭文字に数字を用いるとエラーが出る
    * ローマ字や日本語は望ましくない
* 2後以上の場合はアンダーバーで区切る


### 変数の値を更新する
* 変数は一度代入した値を変更することができる
    * 代入後に再び代入すると変数の中身が更新される


### 変数を自分自身に代入する
* 変数にその変数を代入することができる
    * 例：2が代入されているnumberに3を足す
        * `number=number+3`
* 変数自身を代入する際に省略した書き方
    * `x=x+10` → `x+=10`
    * `x=x-10` → `x-=10`
    * `x=x*10` → `x*=10`
    * `x=x/10` → `x/=10`


### 変数展開
* 変数展開とは文字列の中に変数の値を含めることを指す
* 文字列の中に`#{変数名}`を入れることで代入している値に置き換えて文字列に含めることができる
    * 例：「19歳です」と出力したい場合
        * `age = 19`
        * `puts "#{age}歳です"`
* 変数展開の注意点
    * シングルクオーテーションの場合は変数展開が行われない
* 変数展開のメリット
    * 数字と文字列を連結させる場合に変数を使える
Apacheをインストールする

# yumコマンドでApacheをインストールする
以下のコマンドを実行してください。
```
# yum install httpd
```

Apacheがインストールされたか確かめます。
以下のコマンドを実行してください。
```
# httpd -v
```

# Apacheを起動する
以下のコマンドを実行してください。
```
# systemctl start httpd
```

Apacheが起動されたか確かめます。
以下のコマンドを実行してください。
```
# systemctl status httpd
```

正常に起動された場合、「Active:active(runnning)」と表示されます。
![スクリーンショット 2022-06-03 6.45.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14202/00ac6139-e895-f564-c396-270bc8bec2f4.png)

# 自動起動するように設定する
以下のコマンドを実行してください。
```
# systemctl enable httpd
```

自動起動の設定を確認します。
```
# systemctl is-enabled httpd
```
自動起動の設定の場合、「enabled」と表示されます。
![スクリーンショット 2022-06-03 6.48.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14202/9e82a074-2629-23ca-92c6-5a167985b710.png)

以上で、インストールは終わりです。
日輪刀を作ってみる　その1

過去に作ったものから継続して改善しているものを公開しようと思います。
鬼滅の刃が流行りまくってた頃、市販のオモチャをみて似たようなもの作れないかな・・・と思い立ち、
電子工作経験がてら日輪刀を作ってみようと思い立ちました。
今となっては若干遅れた間はありますが、まだおもちゃも発売されているので。。。

#目次
[1. はじめに](#1-はじめに)
[2. 構成検討](#2-構成検討)
[3. 作製](#3-作製)
[4. おわりに](#4-おわりに)

# 1. はじめに
バンダイより鬼滅の刃のオモチャが発売されてます。（本家日輪刀）
スイッチを押すと音声が出る刀です。
凝った形をしており、なかなか良いお値段します。

https://toy.bandai.co.jp/series/kimetsu/item/detail/11583/

一方、ダイソーではこんな刀があります。（光る忍者刀）
200円ととても安価で、光って音が出る刀です。

https://jp.daisonet.com/products/4549131577549

ダイソー品を改造して音声が出て光るように改造すれば、
それっぽくて面白そうだなと思い、改造することにしました。

# 2. 構成検討
まず忍者刀の構成はこんな感じです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1112433/3e407672-651f-5e07-0c85-89246a428377.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1112433/14218b7c-f067-1ede-3902-b58d4160eda6.png)

音声ではなく、振動検知するとｼﾞｬｷﾝと鳴るような構成です。
LEDは常時点滅点灯するような形。
電源は単3電池1.5V×3本=4.5V。
ここから改造する部分を下記のように検討しました。
音声を出すユニットとして、DFpalyerを使いました。
SDカードリーダとmp3デコーダ、アンプ内蔵しているので、
音声や音楽をmp3にしてをsdカードに入れて、スピーカに直付けして使えます。
今回は簡単にタクトスイッチを追加して、トラックを回すだけの構成にしました。
振動センサは使いません。

DFは単体で200円ちょっと。

https://www.amazon.co.jp/Aideepen-MP3%E3%83%97%E3%83%AC%E3%83%BC%E3%83%A4%E3%83%BCDFPlayer%E3%82%AA%E3%83%BC%E3%83%87%E3%82%A3%E3%82%AA%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB%E3%80%81MP3-WMA%E3%81%AE%E3%82%92%E7%B5%B1%E5%90%88%E3%83%87%E3%82%B3%E3%83%BC%E3%83%80%E3%83%BC%E3%80%81TF-U%E3%83%87%E3%82%A3%E3%82%B9%E3%82%AF%E3%82%92%E3%82%B5%E3%83%9D%E3%83%BC%E3%83%88-%E9%9F%B3%E5%A3%B0%E3%83%9C%E3%82%A4%E3%82%B9%E9%9F%B3%E6%A5%BD%E3%83%97%E3%83%AD%E3%82%BB%E3%83%83%E3%82%B5%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB/dp/B07M93GZVJ/ref=pd_lpo_2?pd_rd_i=B07M8TJ24Q&th=1

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1112433/4360ff48-38e6-05b8-dc9f-8a2c6cdaa2ac.png)

# 3. 作製
いきなりですが実装後です。
DFは5Vで駆動なので、もともとの1.5V×3本=4.5Vの電源ラインから線をひっぱってきて動かしました。
DFをスピーカ穴スペースにねじこみ、スピーカは手元にあった少し小さなものに変えて、すみっコに移動させました。
なんか適当にうってる小さめのスピーカでも入りさえすれば問題ないかと。
入るかどうかと音量の検討は必要ですが。

https://www.amazon.co.jp/uxcell-%E3%82%AA%E3%83%BC%E3%83%90%E3%83%AB-1-W-8%E3%82%AA%E3%83%BC%E3%83%A0-%E3%83%87%E3%83%A5%E3%82%A2%E3%83%AB-%E3%83%AF%E3%82%A4%E3%83%A4%E3%83%BC-%E3%83%9E%E3%82%B0%E3%83%8D%E3%83%83%E3%83%88-%E3%82%B9%E3%83%94%E3%83%BC%E3%82%AB%E3%83%BC-%E3%83%95%E3%82%A9%E3%83%B3-%E3%82%BF%E3%83%96%E3%83%AC%E3%83%83%E3%83%88-PC%E7%94%A8-4%E5%80%8B/dp/B017IIV8KM/ref=pd_lpo_1?pd_rd_i=B017IIV8KM&psc=1

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1112433/2f7dcf14-1c36-067e-4e18-775dd5c3ce5a.png)

DFPlayer用SDカードのディレクトリ構成などは解説先がたくさんあるのでここでは割愛します。
また配線接続はDFの公式とほぼ同じです。ADKEY1,2とIO2には今回接続なし。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1112433/d2ac3c49-65bb-8ee8-4f2a-c76b0fbb4614.png)

なお音声データは個人利用の範囲でなんやかんやします。
詳細は述べません。

# 4. おわりに
これで光って喋る刀ができました。
ボタンを押すと、ﾅﾝﾄｶの呼吸でﾅﾝｶの型を叫んでくれるので、ｷﾒﾂごっこが可能です。
SDカード内のデータを書き換えれば音声は任意に帰ることが可能ですので、キャラ変更も可能。
既存筐体使い回すので作業は少ないですが、LEDはそのままなのでちょっとさみしい。
キャラの呼吸に合わせて青くしたり、黄色くしたり、というのはまた別途。
access2000の作法 その16

# 概要
access2000の作法、調べてみた。
テーブルをcsvでアウトポートしてみた。

# アウトポートボタンを作る手順。
- menuフォームを右クリック。
- デザインビューを開く
- ボタンを設置
- ウィザードが開く  キャンセル
- プロパティシートを開く
- イベントを開く
- クリック時、コードビルダーを開く
```
Private Sub コマンド13_Click()
	DoCmd.TransferText acExportDelim, , "sisyutu", CurrentProject.Path & "\out.csv", True
	MsgBox "ok"
End Sub
```
- フォームを閉じる
- 保存する


以上。
深夜のインシデントの恐ろしさ

# 初めに
インシデントが深夜に発生した場合に備えて、権限の管理、インシデントの解消をする担当者、責任者を定めておきましょう。
そうしないと私の二の舞になります。

今回のインシデントはコミュニティで起ったことであり、
複数人で管理しているサイトで問題が起きました。

# インシデントレポート

深夜1時、ユーザーからこんな連絡が来た
「特定のブラウザでウェブサイトを見れない！！」

2時間後に連絡に気づき、「え？」と思いました。

## 何をしていたか

その前日の夜、DoSが来たため
Cloudflare の設定で「Under Attack!」にしていた。

Under Attack! モードにすると数秒待ってねと表示されます。

ここまでは普通なのですが、
ユーザーエージェントが普通と違うブラウザからアクセスするとループしてしまった...

つまり、数秒待ってねというのがループし、抜け出せなくなっていたのです。

ただ、Firefox、Chromeなどの有名なブラウザでは正常に動いたのが不幸中の幸いでした。

## 取れない連絡

さて、Cloudflareが原因だと分かったからそれを変更すればよかったのですが、
私には権限が無かったんです...あー、終わった。そう思いました。

ステータスページを更新したり、権限ある人を呼び出したり、Twitterにお知らせを投稿したりと、
一応やれることはやったのですが、それでも根本的な解決に至りませんでした。

権限がある人を今呼び出したところで、時計は午前3時を指しており、起きるはずもありませんでした...
深夜帯に起きている人なんてなかなかいないですからね...

## 3 hours later...

さぁ、朝になりました。私は寝てません。

さて、ようやく連絡が付いたため、Under Attack!モードを解除するとともに、WAFで対策し、
ここでインシデントは解消されました。

ここまで5時間ほどのインシデント。
1か月（30日）のうちの5時間となると稼働率は約99.3%になり、このような一部ダウンのインシデントもSLAの保証に入れてた場合は、
金銭的な損失も発生してしまうインシデントでした。

# あとがき

今回のインシデントにより分かったのは、

- CDNの仕様を理解する
- 様々な環境での動作を調べる
- 深夜にも対応できるよう権限を管理する

以上です。

インシデントはいつかは起きます。（GoogleもAtlassianも障害が起きるので）

起こさないように対策をねる必要もありますが、
起きたときの対処法を定めることは非常に重要だと痛感されました。
access2000の作法 その15

# 概要
access2000の作法、調べてみた。
csvをインポートしてみた。

# インポートcsvボタンを作る手順。
- menuフォームを右クリック。
- デザインビューを開く
- ボタンを設置
- ウィザードが開く  キャンセル
- プロパティシートを開く
- イベントを開く
- クリック時、コードビルダーを開く
```

Private Sub コマンド12_Click()
    Set db = CurrentDb
    Dim rs As Recordset
    Dim FileName As String
    Dim intRet As Integer
    Dim GetFileName As String
    With Application.FileDialog(msoFileDialogOpen)
        .Title = "ファイルを開くダイアログ"
        .AllowMultiSelect = False
        .InitialFileName = CurrentProject.Path
        intRet = .Show
        If intRet <> 0 Then
          GetFileName = Trim(.SelectedItems.Item(1))
        Else
          GetFileName = ""
        End If
    End With
    FileName = GetFileName
    If FileName <> "" Then
       Set rs = db.OpenRecordset("sisyutu")
        With CreateObject("ADODB.Stream")
            .Charset = "UTF-8"
            .Open
            .LoadFromFile FileName
            buf = .ReadText(-2)
            Do Until .EOS
                buf = .ReadText(-2)
                tmp = Split(buf, ",")
                rs.AddNew
                rs!年月日 = CDate(Mid(tmp(0), 1, 10))
                rs!項目 = tmp(1)
                rs!金額 = Int(tmp(2))
                rs!備考 = tmp(3)
                rs.Update
            Loop
            .Close
        End With
        rs.Close
    Else
        MsgBox "ファイルが指定できていません", vbExclamation + vbOKOnly, "ファイル未選択"
    End If
End Sub



```
- フォームを閉じる
- 保存する


以上。
access2000の作法 その14

# 概要
access2000の作法、調べてみた。
参照設定、表示してみた。

# 参考にしたページ。

https://qiita.com/Q11Q/items/91bc3eddabbc6b5060e6

# 写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/478270ae-567e-e806-0b4e-8b54689c1cbc.png)

# 参照設定ボタンを作る手順。
- menuフォームを右クリック。
- デザインビューを開く
- ボタンを設置
- ウィザードが開く  キャンセル
- プロパティシートを開く
- イベントを開く
- クリック時、コードビルダーを開く
```
Private Sub コマンド13_Click()
    DebugPrintWhatRefCurrentDb
End Sub
```
- フォームを閉じる
- 保存する


以上。
access2000の作法 その13

# 概要
access2000の作法、調べてみた。
バージョン表示してみた。

# 写真


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/ab4badb0-d18f-98c3-7f40-643647fc4ce3.png)

# バージョンボタンを作る手順。
- menuフォームを右クリック。
- デザインビューを開く
- ボタンを設置
- ウィザードが開く  キャンセル
- プロパティシートを開く
- イベントを開く
- クリック時、コードビルダーを開く
```
Private Sub コマンド8_Click()
   DoCmd.RunCommand acCmdAboutMicrosoftAccess
End Sub
```
- フォームを閉じる
- 保存する


以上。
GoProを無線でつないでオンライン会議で中継をしたい件

GoProを無線でつなぎ、Teamsやzoom等で中継する方法が欲しくなったんですが、
実例が見つからなかったのでやってみた件を備忘録として残します。


#目次
[1.はじめに](#1-はじめに)
[2.準備](#2-準備)
[3.ﾈｯﾄﾜｰｸ接続](#3-ﾈｯﾄﾜｰｸ接続)
[4.ffmpeg起動](#4-ffmpeg起動)
[5.おわりに](#5-おわりに)



# 1. はじめに
ﾍｯﾄﾞﾏｳﾝﾄ的なｶﾒﾗで、作業者の手元をｵﾝﾗｲﾝ会議で共有しつつ、議論をしたいﾆｰｽﾞがありました。
当初はGoProやﾃﾞｼﾞｶﾒ＋ｷｬﾌﾟﾁｬﾎﾞｰﾄﾞをUSBｹｰﾌﾞﾙで繋いでいましたが、ｹｰﾌﾞﾙがｼﾞｬﾏで作業しづらいし、ｶﾒﾗﾏﾝと作業者の二人が必要でこのご時世に密になってしまうのが問題になっていました。
下図のように、Win10環境で無線で構築するｼｽﾃﾑを作ることを目的とします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1112433/dccb42ae-04b7-9e01-09a1-5e5fd20d6fc5.png)


# 2. 準備
現在手持ちの機器類で構成します。
手持ちﾊﾟｿｺﾝは一般的なwifi 1回線分しか持たないので、USB wifiｱﾀﾞﾌﾟﾀを使ってwifiを2回線にします。


[ﾊｰﾄﾞｳｪｱ]
ｶﾒﾗ：GoPro Hero4
ﾊﾟｿｺﾝ：Win10 64bit
ﾙｰﾀ：ﾊﾞｯﾌｧﾛｰ WSR-1800AX4
wifiｱﾀﾞﾌﾟﾀ：型番無し 中華製の市販品（300円程度）

[ｿﾌﾄｳｪｱ]
Python：3.9.6
ffmpeg：N-103611-gdb2514a5dc-20210913

ffmpegの導入は下記を参考に導入します。
https://jp.videoproc.com/edit-convert/how-to-download-and-install-ffmpeg.htm
Cドライブ直下に保存してパスを通した後、win再起動。

こちらの動画で使用している、ViewGoPro.batとViewGoPro.pyをダウンロードします。

https://youtu.be/VDhk8vXckVY

https://youtube-sns.com/download/116/

これで準備は完了です。

# 3. ﾈｯﾄﾜｰｸ接続
GoProの横ﾎﾞﾀﾝを長押しして、ｱｸｾｽﾎﾟｲﾝﾄを立上げます。
usb wifiｱﾀﾞﾌﾟﾀを挿して、ﾄﾞﾗｲﾊﾞｲﾝｽﾄｰﾙ。（最近のものなら大体自動）
元から付随のwifiはﾙｰﾀなり、外部につながるNWにつないでおきます。
追加されたwifi2をGoProのｱｸｾｽﾎﾟｲﾝﾄに接続します。

![pic1.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1112433/2f0d7eaf-3be8-cf73-1c53-02e8bd38b208.jpeg)

これでGoproと外部NWに同時に接続された状態になりました。


# 4. ffmpeg起動
ViewGoPro.pyそのままでも使えますが、一部だけ画像設定を変更します。
下記にカメラ設定のhttpコマンドがあるので、参考にpyファイルに追記していきます。
https://github.com/KonradIT/goprowifihack/blob/master/HERO4/CameraStatus.md
Video Mode based parameters:のあたりで、ResolutionやFrameRateを環境や用途に合わせて設定します。
今回は4kまでは必要なかったので、1080, 60fpsくらいで設定しておきます。

pythonを何かしらで起動して、その後実行。
自動でwindowが立ち上がり、ストリーミングが開始します。
あとはTeamsなりZoomなりでweb会議をつなぎ、ﾃﾞｽｸﾄｯﾌﾟ共有でｽﾄﾘｰﾐﾝｸﾞを表示すれば目的達成です。



# 5. おわりに
やってみれば単純ですが、意外とwifiを2回線使いするようなこともないなと思ったので、書いてみました。
なお、今回は少し古いGoproﾊﾞｰｼﾞｮﾝですが、新しいGoproの場合はhttpｺﾏﾝﾄﾞやipｱﾄﾞﾚｽがかわるかもなので、下記から各ﾊﾞｰｼﾞｮﾝのｺﾏﾝﾄﾞ確認して、pythonのhttpｺﾏﾝﾄﾞ部分を修正すれば使えるかと思われます。
ﾊｰﾄﾞが無いので未検証ですが…

https://github.com/KonradIT/goprowifihack

使い勝手がよさそうなら、pythonﾌｧｲﾙをexe化して汎用化させてもいいかな。
【Colab】【Python】動画(mp4)をGIFファイルに変換する方法

# 結論
:::note
Google Colaboratoryサービスで、Pythonのライブラリ「MoviePy」を使用して、動画(mp4)をGIFファイルに変換する
* [Colaboratory へようこそ - Colaboratory - Google](https://colab.research.google.com/?hl=ja "Colaboratory")
* [MoviePy 1.0.2 documentation](https://zulko.github.io/moviepy/ "moviepy")
:::

# サンプルコード
```Python:sample.py
# ファイルアップロード
from google.colab import files
uploaded = files.upload()
# アップロードしたファイルの名前を取得
file_name = list(uploaded.keys())[0]

input_fileName = file_name
# 変換後のファイル名を設定
output_fileName = "processing_file.gif"

from moviepy.editor import VideoFileClip
# 動画取り込み
clip = VideoFileClip(input_fileName)
# サイズ変更
clip = clip.resize(width=700)
# GIFに変換
clip.write_gif(output_fileName, fps=6)
# ダウンロード
files.download(output_fileName)
# 終了
clip.close()
```

# 手順（参考資料：gifファイル有）
1. Google アカウントでログインする
2. Googleドライブを開き、Google Colaboratoryをインストールする。

![processing_file (5).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2441785/1ea33e1b-08e0-fe15-e88f-380ce6b224f0.gif)

:::note warn
※6.0MB,21秒のmp4ファイルを、サイズ:500,fps=6で約5MBのgifに変換
:::

3.　[新規]から[Google Colaboratory]をクリックする
![processing_file (1).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2441785/e06b99ec-95c6-4c8c-7fe6-75e31c8c4c04.gif)

:::note warn
※4.0MB,21秒のmp4ファイルを、サイズ:700,fps=6で約5MBのgifに変換
:::

4.　サンプルコードを入力、実行
5.　任意のMP4ファイルをアップロード
6.　自動でファイルダウンロードまで実行されます。
![processing_file (7).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2441785/c46a98bb-ed5b-846e-09a1-2afc53543fa0.gif)

:::note warn
※13MB,73秒のmp4ファイルを、サイズ:500,fps=3で約7MBのgifに変換
:::


---

### アップロードされたファイルを削除する方法
1.　「!ls」と入力し実行すると、ローカルにアップロードされているファイルが確認できる
2.　メニュー＞[ランタイム]＞[ランタイムを接続解除して削除]を押下
3.　再度「!ls」と入力し、実行結果が「sample_data」ならば、削除成功
![processing_file (8).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2441785/e3369e7c-4d29-e0d5-c737-6ce7a78ffbac.gif)

---

###### 参考資料

* ファイルのアップロード・ダウンロード

https://kino-3.github.io/tech-memo/colab/file/

* MoviePy紹介ブログ

https://self-development.info/moviepy%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6python%E3%81%A7%E5%8B%95%E7%94%BB%E3%82%92gif%E3%82%A2%E3%83%8B%E3%83%A1%E3%81%AB%E5%A4%89%E6%8F%9B%E3%81%99%E3%82%8B/

* ファイルの削除　
※ファイル削除するスマートなロジックが思いつかないため、今回はサンプルコードに含めず

https://lemon818.com/python-file-delete/

* importの理解に参考

https://pg-chain.com/python-from-import
FlutterでRealmデータベースを見る方法(realmの場所)

結論から書くとデータがあればdata/data/アプリ名/Filesにあります。※Android Studio

じゃあそのファイルはどこにあるのってとこなんですが、下記です。

![スクリーンショット 2022-06-03 3.37.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/494487/a0c99c1f-e347-f5ef-71aa-b15ab90e0e32.png)

下記をタップすると
![スクリーンショット 2022-06-03 3.39.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/494487/c9fdfa92-c8b8-bd97-784c-5b205117fcb3.png)

みたいな感じで出てきます。

その中にdataと書かれた部分があるので、最初に伝えた階層まで行きます。

data/dataの階層の後にcom.example.みたいなファイルが無数にあるので、その中から自分が作ったアプリ名のファイルを探します。今回で言えば、untitle5

![スクリーンショット 2022-06-03 3.41.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/494487/72b18528-a39a-e44f-0ca9-ebdc88c8189a.png)

その中にFilesというデータがあり、その中を見るとrealmファイルがある場合そこからローカルに落とすことが可能です。

![スクリーンショット 2022-06-03 3.43.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/494487/76fca1c7-dc7c-171c-b35e-49f4b3c30014.png)

ちなみにRealmデータが作られてなければそこにはもちろんrealmのデータはないので、Realmデータを作るところから始めることになります。

その内容はこちらの記事で解説したので、よければこちらもどうぞ。

https://qiita.com/celcior0913/items/99525e84201fac60c194

元々iOSの出身でrealmのパスなんてprintすればすぐ見れるやろくらいの感じで思っていたのに、全然場所がわからずかなり詰まったので、自分が忘れないように忘備録として残します。

どなたかの参考になれば幸いです。
データベースの中身をrails dbconsoleで確認する方法

# 記事の内容
ターミナルでデータベースの中身を確認する。


## dbのコンソールを起動する

まずはコンソールを起動する。
```
$ rails dbconsole
```

コンソールが起動。
```
sqlite>
```

## コンソールからデータベースの内容を確認

テーブル一覧を表示。
```
sqlite> .table
ar_internal_metadata  schema_migrations     users 
```


<br>指定したテーブルの構造を確認。
```
.schema users
CREATE TABLE IF NOT EXISTS "users" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "email" varchar NOT NULL, "crypted_password" varchar, "salt" varchar, "last_name" varchar NOT NULL, "first_name" varchar NOT NULL, "created_at" datetime NOT NULL, "updated_at" datetime NOT NULL);
CREATE UNIQUE INDEX "index_users_on_email" ON "users" ("email");
```

<br>ちなみに、テーブルを指定しないと全テーブルを確認できます。
```
.schema
CREATE TABLE IF NOT EXISTS "schema_migrations" ("version" varchar NOT NULL PRIMARY KEY);
CREATE TABLE IF NOT EXISTS "ar_internal_metadata" ("key" varchar NOT NULL PRIMARY KEY, "value" varchar, "created_at" datetime NOT NULL, "updated_at" datetime NOT NULL);
CREATE TABLE IF NOT EXISTS "users" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "email" varchar NOT NULL, "crypted_password" varchar, "salt" varchar, "last_name" varchar NOT NULL, "first_name" varchar NOT NULL, "created_at" datetime NOT NULL, "updated_at" datetime NOT NULL);
CREATE TABLE sqlite_sequence(name,seq);
CREATE UNIQUE INDEX "index_users_on_email" ON "users" ("email");
```

<br>個別のSQL文も打つことができる。
```
sqlite> select * from users;
1|e@e|||e|e|2022-05-13 18:03:09.993057|2022-05-13 18:03:09.993057
```

<br>コンソールを終了。
```
sqlite> .quit
```
lambda_runtimeのレスポンスオブジェクト作成に使えるクレートを作った話


ServerlessFramework のプラグインである [serverless-rust](https://www.serverless.com/plugins/serverless-rust) を使用して、API GatewayとAWS Lambdaを使ったAPIを作成しようとしていた。

Rustでラムダ関数を作成するのに便利なクレートはないだろうか？と調べたところ、[lambda_runtime](https://crates.io/crates/lambda_runtime) なるものを見つけた。
おおこれは便利だ、とサンプルコードをそのまま使用してみた。何かあれば修正してデプロイすれば良いし、無料枠を潰すほど実行することもないだろう。できればデプロイにかかる時間を有料枠で買えればよかったが...

[紆余曲折](https://qiita.com/mwataame/items/5247a1deb98e68561413)あったものの、serverlessコマンドで無事APIを作成することはできたようだ。
試しに実行してみよう。

```
$ curl https://xxxxx.execute-api.ap-northeast-1.amazonaws.com/dev/test
{"message": "Internal server error"}
```

あら、やっぱりだめか。エラー内容を確認するためにCloudWatch Logsで確認してみたところ、ラムダ関数内でエラーはなく無事に実行完了していた。

なるほど、APIGatewayに渡すならレスポンスの形はちゃんと整えなければならないようだ。[ドキュメント](https://docs.rs/lambda_runtime/0.5.1/lambda_runtime/fn.run.html)によると `Serialize` を実装していればよいらしい。

とりあえず `json!` マクロでそれっぽいものを作ってみよう。

```rust
async fn handler(
    _event: LambdaEvent<serde_json::Value>,
) -> Result<serde_json::Value, lambda_runtime::Error> {
    Ok(json!({
        "statusCode": 200,
        "body": "OK",
    })
}
```

デプロイして実行してみたところ

```
$ curl https://xxxxx.execute-api.ap-northeast-1.amazonaws.com/dev/test
{"message":"OK"}
```

うまくいったみたい。やったね。

ただせっかくレスポンスが「`Serialize` を実行している型」と定義されているなら、そんなレスポンスオブジェクトを作ってしまおう。
自分はこういう**何でもあり**なオブジェクトはタイポや名前忘れが防げなくてキライだ。Rustのコンパイラにちゃんとチェックしてもらいたい。

### 作りました

こいつです　→　[lambda-apigateway-response](https://crates.io/crates/lambda-apigateway-response)

実際の実装はこんな感じ。シンプルイズベスト

```rust
#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Response<T: Serialize> {
    #[serde(serialize_with = "serialize_status_code")]
    pub status_code: StatusCode,

    #[serde(serialize_with = "serialize_body")]
    pub body: T,

    #[serde(skip_serializing_if = "Headers::is_empty")]
    pub headers: Headers,

    #[serde(skip_serializing_if = "MultiValueHeaders::is_empty")]
    pub multi_value_headers: MultiValueHeaders,

    pub is_base64_encoded: bool,
}
```

まだできたてなのでいろいろと足りていないところがあるけれど、そこはご容赦を。

ビルダーパターンを取り入れても良いし、`Serialize` を実装していない `lambda_http::Response` から変換できるよう `From<lambda_http::Response>` を実装してもよいかもしれない？

頑張ろう💪
【Dokcer】bashの操作ログを永続化する【Remote-Containers】

## bashの操作ログを永続化する
### Docker
```Dockerfile:Dockerfile
FROM node:16.15.0

ENV TZ=Asia/Tokyo
ARG USERNAME=node

RUN corepack enable npm
RUN SNIPPET='\n if [ "$SHLVL" = "2" ] ; then \n \
            \t script -f /bashlog/script/`date "+%Y%m%d%H%M%S"`.log \n \
            fi \n \
            \n export PROMPT_COMMAND="history -a" && export HISTFILE=/bashlog/.bash_history \n' \
    && mkdir -p /bashlog/script\
    && touch /bashlog/.bash_history \
    && chown -R ${USERNAME} /bashlog \
    && echo ${SNIPPET} >> "/home/${USERNAME}/.bashrc"

USER ${USERNAME}
RUN mkdir -p /home/${USERNAME}/.vscode-server/extensions
WORKDIR /myapp-frontend

EXPOSE 3000

```
```/docker-compose.yml
version: '3.9'
services:
  frontend:
    build: .
    volumes:
      - sources:/myapp-frontend
      - bashlog:/bashlog
      - vscode-extensions:/home/node/.vscode-server/extensions
    environment:
      NODE_ENV: development
    ports:
      - 3000:3000
      - 9229:9229
    command: /bin/sh -c "while sleep 1000; do :; done"
volumes:
  sources:
  bashlog:
  vscode-extensions:
```

### Remote-Containers

```.devcontainer/devcontainer.json
{
  "name": "myapp-frontend",
  "dockerComposeFile": ["../docker-compose.yml"],
  "service": "frontend",
  "workspaceFolder": "/myapp-frontend",
  "customizations": {
    "vscode": {
      "extensions": [
        "EditorConfig.EditorConfig",
        "dbaeumer.vscode-eslint",
        "esbenp.prettier-vscode",
        "VisualStudioExptTeam.vscodeintellicode",
        "arcanis.vscode-zipfs",
        "bradlc.vscode-tailwindcss"
      ]
    }
  }
}
```
RAFTの環境をdocker-composeで作る。

https://qiita.com/fkeikaf/items/6922fa430f5a4207b4b7

https://github.com/princeton-vl/RAFT

これのdocker-composeで環境を作る時の設定
グラボが無いので、動作確認とかはできない。ごめんね。
docker立ち上げるまでは後で修正するかも。
以下を参考にした。

https://zenn.dev/miyatsuki/articles/db220deeb28900

```:tree
.
- build-env
  - Dockerfile
  - requirements_conda.txt
- project
  - pythonファイルなど
- docker-compose.yml
```

```docker-compose.yml
version: '3'

services:
  project_name:
    container_name: 'project_name'
    build: 
      context: ./build-env
      dockerfile: DockerFile
    image: image_name:tag_name
    tty: true
    volumes:
      - ./project:usr/src/project_name
    runtime: nvidia
    shm_size: '2gb'
```

```Dockerfile:Dockerfile
FROM pytorch/pytorch:1.6.0-cuda10.1-cudnn7-devel

# NVIDIA pubkey更新
RUN rm -f /etc/apt/sources.list.d/cuda.list \
 && apt-get update && apt-get install -y --no-install-recommends \
    wget \
 && distro=$(. /usr/lib/os-release; echo $ID$VERSION_ID | tr -d ".") \
 && arch=$(/usr/bin/arch) \
 && wget https://developer.download.nvidia.com/compute/cuda/repos/$distro/$arch/cuda-keyring_1.0-1_all.deb \
 && dpkg -i cuda-keyring_1.0-1_all.deb \
 && rm -f cuda-keyring_1.0-1_all.deb

RUN apt-get install -y vim less unzip
WORKDIR /usr/src/project_name

COPY . .
```

## apt-get updateのエラー(NVIDIA pubkey更新について)
https://tech-blog.optim.co.jp/entry/2022/05/18/100000

最近更新されたらしい。古いバージョンを使う場合は今後も世話になる。

## build-env
特にイメージを作り直すときにはまる。
https://stackoverflow.com/questions/26600769/build-context-for-docker-image-very-large

# おわりに
画像処理用のグラボ欲しいとか思ったが、Google Coraboratoryが優秀なので、そっちで頑張ろうかなと思う。
【React】React Router v6でNestがうまく動かなかった件

# 概要

`React Router v6`を利用してルーティングを行うとネストしたルーティングが動かなかった

この記事はその解決方法を残すものです

# 解決した方法


[index-routes](https://reactrouter.com/docs/en/v6/getting-started/overview#index-routes) の仕組みを利用して階層を設定する必要があったのがポイントです


```tsx
<Route path="/page1">
    <Route index={true} element={<Page1/>}/>
    <Route path="detailA" element={<Page1DetailA/>}/>
    <Route path="detailB" element={<Page1DetailB/>}/>
</Route>
```

## 全体像

```tsx:App.tsx
<BrowserRouter>
    <Routes>
        <Route index element={<Home/>}/>
        <Route path="/page1">
            <Route index={true} element={<Page1/>}/>
            <Route path="detailA" element={<Page1DetailA/>}/>
            <Route path="detailB" element={<Page1DetailB/>}/>
        </Route>
        <Route path="/page2" element={<Page2/>}/>
    </Routes>
</BrowserRouter>
```
【Git】自分的よく使うGitコマンド

# 初回プッシュ
## 既存のファイルをプッシュする
**ファイル追加してない場合**
```
cd ローカルリポジトリのパス
git init
git branch -m main
git remote add origin https://github.com/SNQ-2001/XXXXX.git
git add -A
git commit -m 'first commit'
git push origin main
```

**READMEやLICENSEを追加した場合**
```
cd ローカルリポジトリのパス
git init
git branch -m main
git remote add origin https://github.com/SNQ-2001/XXXXX.git
git pull origin main
git add -A
git commit -m 'first commit'
git push origin main
```

# 2回目以降プッシュ
```
cd ローカルリポジトリのパス
git add -A
git commit -m 'update: README'
git push origin main
```

# ブランチ関係
## ブランチの確認
```
cd ローカルリポジトリのパス
git branch -a
```

## ブランチ作成
```
cd ローカルリポジトリのパス
git checkout -b develop
git push -u origin develop
```

## ブランチの削除
**ローカルとリモートどちらも存在してる時？**
```
cd ローカルリポジトリのパス
git push --delete origin develop
```

**リモートにのみ存在してる時**
```
cd ローカルリポジトリのパス
git fetch -p
```

# コミットコメントを複数行
```
cd ローカルリポジトリのパス
git add -A
git commit -m '修正' -m 'バグを修正'
git push origin main
```
UE5で削除された r.TonemapperFilm 0 の代替手法（ToneCurveAmount）

アンリアルエンジンでトゥーン表現などを行う場合、
デフォルトで適用されているフィルム トーンマッパ **"r.TonemapperFilm 1"** によって
少し色がくすんでしまって困る、ということがありますよね。
![2022-06-03_00h16_18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463796/e371bd77-f699-e1fa-5ddf-90d2394a20fd.png)
フィルム トーンマッパの詳細に関しては、以下URLをご参照いただけたらと思うのですが、
https://docs.unrealengine.com/4.27/ja/RenderingAndGraphics/PostProcessEffects/ColorGrading/
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463796/31be76e5-77c1-dbed-5a44-edf6b47223ae.png)
フィルム調のリアルな絵作りを行いやすいというメリットがある一方、彩度が落ちてしまって元テクスチャの印象が少し変わってしまうというデメリットもあります。

そこで、アンリアルエンジン４までは、
多くのユーザー様が **"r.TonemapperFilm 0"** とし、
麦わらの一味の発色を取り戻していたかと思うのですが、
![2022-06-03_00h16_42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463796/4deefe4a-9196-9814-4c7f-e9f6ae07e6fa.png)
こいつが悲しいことに、アンリアルエンジン５では削除されてしまいました。
https://docs.unrealengine.com/5.0/ja/unreal-engine-5-migration-guide/
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463796/47e0aee2-f362-8b4e-dec7-a731fd8c5695.png)
そこで今回はその対応策の一つとして、
ポストプロセス設定の **ToneCurveAmount** をご紹介させていただけたらと思います。
![2022-06-03_00h17_06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463796/e6ef103b-0422-1427-b593-3fb0b096f245.png)
使い方は非常に簡単で、上記画像のようにポストプロセスの設定で、
**Tone Curve Amount** に **0** を設定するだけです。
（Expand Gamutも 0 にしておくとより良いと思います。）

この機能に関しましては、
UNREAL FEST EXTREME 2022 SUMMERの
**「アイドルマスター スターリットシーズン」におけるグラフィックス実装事例と最適化事例** の質疑応答でも触れられていた機能かと思うのですが、
https://youtu.be/re56DDIQRiM?t=4911

**ToneCurveAmount** の効果としては、
PostProcessCombineLUTs.usf　CombineLUTsCommon()の処理内にて
FilmToneMap() の影響をどの程度与えるかのパラメーターになっており
0にした場合は FilmicToneCurve の影響を除外することが可能となっております。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463796/4fc09982-469a-192f-e6de-d363b0eac60c.png)
**ToneCurveAmount** のパラメーターコメントにもある形で、
多くの場合は ExpandGamut（あと多分BlueCorrectionも？）合わせて0にして、
OCIOなどで任意の色変換を行う際や
MRQやシーンキャプチャーなどでレンダリングする際にニュートラルな状況を得たい　といった場合に使用されております。
**ShowFlag.ToneCurve** でも制御できます。

もちろん ToneCurveAmount を 0 にした場合でも、
削除されてしまった従来のトーンマップ FilmPostProcess() の処理などは行われないため、
講演動画でもご説明されているとおり、厳密に r.TonemapperFilm 0 と同じ結果にはならないのですが、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463796/fc386399-ff24-c6ff-bdfc-2a9eaece54f9.png)


ToneCurveAmount 0 は
**設定がとてもお手軽** ＆ **他のポストプロセス機能は問題なく使える** などのメリットから
様々な方が試されているトーゥン対応方法に連なる一つの選択肢になるのかなと思いました。

もし別の対応手法も気になる！という方は、ぜひ以下URLもご参照ください。
https://qiita.com/ruyo/items/28255f26725a6b6bd475
https://www.hakobuneworks.com/posts/settingsforpixelart/
https://twitter.com/kamipallet/status/1482012169084739592?s=20
https://forums.unrealengine.com/t/disable-tonemapper/242463/3

ユーザー様の情報共有によってアンリアルエンジンは支えられております。
いつもありがとうございます！
![ToneCurveAmount.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463796/76050450-e3d0-f325-b89e-613e758055c8.gif)
UnityのVisual Scripting上で楽に衝突判定する

# 概要

当たり判定をVisual Scripting上でやっていて、
1つ2つならともかく、これが多くなるとノードがごちゃつきそうだなと思ったのでC#でなんとかしてみる

# 方法

## どうやってるのか

Visual Scripting上ではOnCollisionEnterといったイベントノードから衝突したゲームオブジェクトを取得して、
何が衝突したのか、衝突したらどうするのかをノードを繋げて処理することになるんですが、
これが多くなったり他のオブジェクトで処理したいとなるとすごいことになりそうなのが容易に想像つきます。
調べた感じでは他のオブジェクトで処理したい場合はイベントを送るのが定石っぽい。

## どうしよう

### とりあえず

こんな感じにしようと考えた

- 必要なゲームオブジェクトに衝突判定用のイベントハンドラを設定しておき
- イベントハンドラは呼ばれるたびに衝突したオブジェクトを記憶
- 判定したい時はOnUpdate内で記録された情報を参照して衝突したかどうかを判定

こうすれば判定はシンプルに済みそう。
ただイベントハンドラの設定をVisual Scriptingでやると、設定だけでノードがそこそこ要りそうなのと、
必要なオブジェクト全部にそれするのかという話になるので却下。

### 動的にイベントハンドラ設定？

Visual Scriptingの仕組み上絶対できるとは思ってたんですけど、なんせドキュメントが…

https://docs.unity3d.com/ScriptReference/Events.UnityEvent.AddListener.html

って思ってたんですがUnityEvent.AddListenerでいけるっぽいです
とはいえそのためのノードを作って必要なオブジェクト内にペタペタ貼るのもどうかなと考えてしまいました。

### MonoBehaviourのサブクラス

衝突関係のイベントハンドラを設定したMonoBehaviourのサブクラスを作っておき、
衝突判定したいゲームオブジェクトにアタッチしてもらうのが最も簡単そう

## 実装

### イベントループ

最初は衝突したオブジェクトを1つだけ記録して衝突判定イベントが呼ばれるたびに書き換えるという
今思えば大間抜けなコーディングをしていたわけですが・・・

- 衝突関係のイベントは物理演算に絡んでおり、一度のOnUpdateの間に複数呼ばれたり呼ばれなかったりするらしい
- 複数当たってる時はその分だけ衝突イベントが発生するようだ

ということで当たってのに当たってないということになってしまうんですよね・・・これは論外なので、

- 衝突イベントがあれば対象のオブジェクトを記録する
- さらに衝突イベントがあれば対象のオブジェクトを書き換えではなく追記する
- 衝突中(OnCollisionStay～)イベントでも同様に対応
- LateUpdateで記録を消去

という形で処理することにした。

## コード

今のところこんな感じ

https://github.com/uniras/CollisionChecker/blob/main/CollisionChecker.cs
何もしてないのに prisma studio が壊れた

## 現象

```npx prisma studio``` すると、```Invalid string length``` エラーがでるようになった。
![Screen Shot 2022-06-02 at 22.24.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245908/9f0dd84c-c576-1a9c-f0f0-abb450269e4f.png)

non-recoverable error とか言われると、慌てふためく。

## エラーメッセージ詳細

> Fatal Error
A non-recoverable error has occurred and Studio has to be restarted. Please consider reporting this error to us by opening an issue on GitHub and attaching the error details. If this persists, please clear out your IndexedDB and try again.

>Invalid string length
RangeError: Invalid string length
    at JSON.stringify (<anonymous>)
    at _t.serialize (http://localhost:5555/assets/index.js:1:49091)
    at _t.update (http://localhost:5555/assets/index.js:1:12197)
    at Cc (http://localhost:5555/assets/vendor.js:50:6994)
    at _t.n (http://localhost:5555/assets/vendor.js:50:6688)
    at _t.update (http://localhost:5555/assets/index.js:1:48948)
    at Cc (http://localhost:5555/assets/vendor.js:50:6994)
    at _t.n (http://localhost:5555/assets/vendor.js:50:6688)
    at http://localhost:5555/assets/index.js:1:82272
    at Array.forEach (<anonymous>)

## 環境
next: 12.1.6
react: 18.1.0
@prisma/client: 3.14.0
prisma: 3.14.0

## 解消方法
Invalid string length？何か巨大なデータがうっかり入っちゃったりした？などと、慌てふためくけど、開発環境だとしても、DB のデータを削除してみるのは、やめましょう。DB 悪くない。

ちゃんと、解決方法書いてある。


> If this persists, please clear out your IndexedDB and try again.
(それでも解決しない場合は、IndexedDBをクリアし、再度試してみてください)

逆だろ。先にクリア。

## IndexedDB is 何？
Browser のキャッシュ的な。Chrome の場合、DevTools を開き、Application > IndexedDB からPrisma Studio を消す。
![Screen Shot 2022-06-02 at 22.40.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245908/4dc0a493-2716-fb25-ce88-00d4d7d913c9.png)

消したら、リロードして、元通り。

おしまい。
Hololens2をIntel Macbook Proで使うためのTips ①

Hololensは自分の認識している３次元空間に、視覚的に３Dオブジェクトを追加でき、それを手でつまんで移動したり、という未来の先駆けのようなことができます。今回、プロジェクトで関わることになり、自分のMacbook上で環境構築を試みました。

## MacBookでHololensを開発するのは異端？

Hololens 1/2の開発にはWindows環境が必要です。でも、それはMacOSのBootcampを使い、Windowsとデュアルブートすることで解決できます。前モデルのHololens 1についてはMacのBootcampでの構築事例が見られますが、情報が古くなっています。最新モデルのHololens 2に関しての、特にMacbook上での環境構築の情報は不足しているようなので、実際に試してみてMacBook Proでの環境構築のTipsを述べていきます。


**「Hololens使うのにWindowsマシンは持っていない」** という私のような異端の方々の助けになれば幸いです。

なお、基本的にはMicrosoftの一次情報を見れば構築できますが、この記事ではMacユーザーに特化した情報についてなるべく述べるつもりです。

https://docs.microsoft.com/en-us/learn/paths/beginner-hololens-2-tutorials/


# 検証環境

![スクリーンショット 2022-06-02 17.30.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614389/d713e85f-9668-8780-121a-20ff8a448221.png)

- Storage： 256GB (100GBをBootcampに割り当て)

# TL; DR

- Bootcampに100GB程度の**十分なパーティション**を割り当てる **（大事なことなので何度も言います）**
    - 事前にMacOS側のファイルを可能な限り削除/外部ストレージに退避（特に256GBしかストレージがない場合)
    - 初めに40GB割り当てたが、環境構築の過程で足りないことがわかった。
        - これに後で気づいたので、Bootcampをリセットしたので、環境構築に約二倍の時間をかけてしまった
    - **パーティション割当の時間がとにかく長い** ので、寝る前に開始して、寝てる間に動かすのがおすすめ
- Bootcampを使ってWindows 10をインストールする
- Unity Hubをインストールする
    - https://unity3d.com/jp/get-unity/download
- Unity Hubでデフォルトで求められるソフトウェアを入れていく（インストーラに従う）
    - 待ち時間が長いので、その間はコーヒーブレイクでもしましょう
    - ただしVisual Studio 2019はBuild Settingsで互換性の問題があるメッセージが出たので、これは一旦スキップ。理由はわからない。
        - 代わりにVisual Studio 2022を入れて、次のコンポーネントを入れたところ解決。
- Visual Studio 2022と、必要なコンポーネントを入れる
    - インストーラで出てくるオプションにWindows 10 SDK, C++を追加するのを忘れない

このあとは以下のチュートリアルの細かい部分を参照してください:

https://docs.microsoft.com/en-us/learn/modules/learn-mrtk-tutorials/1-3-exercise-configure-unity-for-windows-mixed-reality?tabs=openxr


## .NETのインストールのTips

上記の公式チュートリアルで.NET 5.0をMRTKのインストールの過程で入れることになります。
.NET 5.0のダウンロードサイトでは以下の3つのオプションがありました。

- 「コンソールアプリの実行」
- 「デスクトップアプリを実行する」
- 「サーバーアプリの実行」

このうち、必要なのは「デスクトップアプリを実行する」です。他を選んでインストールしても、MRTKのインストーラに「.NET5.0をインストールしてください」と怒られます。

## BootcampのTips

Windows/MacOSの切り替えを行うには、起動時にOptionキーを押しましょう。

## Optional: Paralells

https://www.parallels.com/jp/

好みによって、ParalellsをMacOSにインストールすると、MacOSを起動しているときにHololens開発ができるかもしれません。これは、ParalessがWindowsのあるBootcampのパーティションを参照して仮想マシンを建てられるからです。ただし、 **UnityやVisual Studioが重いと考えられるので、仮想マシン上で十分なパフォーマンスが出るのかは未検証** です。これについては、後日使ってみて記事を書くことがあるかもしれません。


公式チュートリアルをMacbookで引き続き試してみる予定です。その際の詰まったこと、分かったことなどを②、③などと記事を書いていくかもしれません。

それではみなさん、良い拡張現実ライフを！
【Angularアプリケーション開発 #6】複数データを表示させる

なんちゃってMockファイルを作成して、複数データをhtmlで扱う方法を学びます。

- Mockファイルを作成しましょう。
外部から参照できるようにexportの宣言を忘れずに！
```typescript:mock-member.ts
import { Member } from './member'

export const MEMBER:Member[] = [
  {id:'1',name:'daisuke'},
  {id:'2',name:'masato'},
  {id:'3',name:'takeshi'},
  {id:'4',name:'shiji'}
];
```
- コンポーネントからMockファイルのデータを参照できるようにします。
  - MEMBERをimportします。
  - `members`という変数にMEMBERの代入しています。
※onSelectメソッドは今回関係ありません。（気にしないでください）
```typescript:members.component.ts
import { Component, OnInit } from '@angular/core';
import { Member } from '../member';
import { MEMBER } from '../mock-member';

@Component({
  selector: 'app-members',
  templateUrl: './members.component.html',
  styleUrls: ['./members.component.css']
})
export class MembersComponent implements OnInit {

  members = MEMBER;

  member:Member = {
    id:'1',name:'huyuki'
  }
  constructor() { }

  ngOnInit(): void {
  }

  onSelect():void{

  }
}
```
- 次にhtmlを修正していきましょう。
  - `*ngFor="let member of members"`は配列のmembersをmemberプロパティに小分けしているイメージです。ngForで１つずつmemberに分解してmembersの要素数分のループをしています。
  - `(click)="onSelect(member)`はイベントバインディングというものです。
  clickするとtsファイルの`onSelect()`メソッドが呼ばれます。（次回実装します。）
```html:members.component.html
<h2>従業員一覧</h2>

<ul class="members">
  <!-- (click)はイベントバインディング -->
  <li *ngFor="let member of members" (click)="onSelect(member)">
    <span class="badge">{{member.id}}</span> {{member.name}}
  </li>
</ul>

<h2>{{member.name}}</h2>
<div>
  <label>id:</label>{{member.id}}
</div>
<div>
  <label>名前:
    <!-- 双方向データバインディング -->
    <input type="text" [(ngModel)]="member.name" placeholder="名前">
  </label>
</div>

```
- 最後にcssでデザインを整えます。
```css:members.component.css
/* MembersComponent's private CSS styles */
.members {
  margin: 0 0 2em 0;
  list-style-type: none;
  padding: 0;
  width: 15em;
}

.members li {
  position: relative;
  cursor: pointer;
  background-color: #EEE;
  margin: .5em;
  padding: .3em 0;
  height: 1.6em;
  border-radius: 4px;
}

.members li:hover {
  color: #377796;
  background-color: #DDD;
  left: .1em;
}

.members a {
  color: rgb(69, 100, 96);
  text-decoration: none;
  position: relative;
  display: block;
  width: 250px;
}

.members a:hover {
  color: #607D8B;
}

.members li.selected {
  background-color: #CFD8DC;
  color: white;
}

.members li.selected:hover {
  background-color: #BBD8DC;
  color: white;
}

.members .badge {
  display: inline-block;
  font-size: small;
  color: white;
  padding: 0.8em 0.7em 0 0.7em;
  background-color: #482697;
  line-height: 1em;
  position: relative;
  left: -1px;
  top: -4px;
  height: 1.8em;
  min-width: 16px;
  text-align: right;
  margin-right: .8em;
  border-radius: 4px 0 0 4px;
}
```
画面は以下のように表示されていると思います。
![スクリーンショット 2022-06-03 0.42.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2689436/7a16117c-4663-8333-e163-42170afe725c.png)
interface使用例 (composition api)

## 使用例
```vue
<script setup lang="ts">

enum Gender {
  GIRL = "Girl",
  BOY = "Boy",
}

enum Hobby {
  SPORT = "Sport",
  TVGAME = "TvGame",
}

enum Score {
  HIGH = "High",
  MIDDLE = "Middle",
  LOW = "Low",
}

interface Human {
  gender: Gender;
  hobby: Hobby;
  score: Score;
}

const options = reactive<Human>({
  gender: Gender.GIRL,
  hobby: Hobby.SPORT,
  score: Score.HIGH,
});
</script>
```

このようにinterfaceとenumを合わせて使用すれば、
指定した値以外の混入を防げる。

例えば、
```ts
const options = reactive<Human>({
  gender: 'girl',
  hobby: Hobby.SPORT,
  score: Score.HIGH,
});
```
のように書くことができない