OmniAICreator/Qiita-1.07M huggingface dataset:
UE4.26でMagic Leap 1の開発は変わったのか検証


[Magic Leap Advent Calendar 2020](https://qiita.com/advent-calendar/2020/magicleap)の17日目です。

Magic Leap 1のUE4ネタがないようだったので、それ+先日アップデートされたUE4.26での更新に関する情報まとめます。
丁度タイミング的にUE4.26でMR関連の更新が色々とあったものの、Magic Leap 1は専用のAPIが用意されているところもあり、影響はあったのか気になったので、検証しました記事です。
(Magic Lecp 1のドキュメントにも、UE4.26アップデートに関することは特に何も書かれていない感もあったので。)

** ※今回はMagic Leap用のUE4(Magic Leap UE4 Editor)ではなく、通常のUE4を使用しています。 **

##### 参考
- [Magic Leap 1のUE4開発ドキュメント](https://developer.magicleap.com/en-us/learn/guides/unreal-engine-development-overview)
- [HoloLensのUE4向けドキュメント内のUE4.26更新の影響情報](https://docs.microsoft.com/ja-jp/windows/mixed-reality/develop/unreal/unreal-porting)
- [UE4.26のリリースノート](https://docs.unrealengine.com/ja/WhatsNew/Builds/ReleaseNotes/4_26/index.html)

## 各主要機能検証

#### アイトラッキング
Magic Leap独自APIになっていないものの、特に更新はないようなので、影響はないようです。

今まで通り、「GetGazeData」で情報取れます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214053/3c292a47-5d3e-b726-e621-63e5150a80db.png)


#### ハンドトラッキング
これはMagic Leap専用のAPIがあり、UE4.26の「GetMotionControllerData」からHand判定をして情報を取得してハンドトラッキング情報として利用することはできませんでした。
従来通りの、GetGestureKeypointTransformで行うようです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214053/d553513f-c78e-d332-fa3d-e66aec1a8bc3.png)


ちなみに、モーションコントローラーのトラッキングについては、MotionControllerコンポーネントを使うパターンでも、「GetMotionControllerData」でController判定するパターンでも動いているので、
メインの入力装置のトラッキングは「GetMotionControllerData」を経由して行うようにすると、簡単に共通化できそうな気もします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214053/03e01171-a20e-0e08-dc0d-eb28d8178867.png)


#### 空間マッピング
ARSessionConfigが引き続きLuminARSessionConfigで専用のものを使用していることもあってか、こちらも特に変わり内容でした。
そもそもHoloLensでやっているSpatialMappingベースだと、ARSessionConfigで設定するよりは、MRMeshとMagic Leap専用のMagic Leap Mesh Trackerを使用したものの方がイメージに近い的なところもありますが。
「Toggle ARCapture」でSpatial Mappingを指定して手動で有効化する必要はないようです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214053/87cb2939-4255-bbf0-74c3-4dbc53447eb9.png)


## その他アップデートの影響

#### Zero Iterationが落ちる問題が解決
UE4.25使用時に設定の組み合わせでUE4が落ちて使えない問題があったのが、解決したみたいです。
これは最初対処法が判らなくて、Zero Iterationが使えず困っていましたが、問題なく動くようになったみたいで、地味に嬉しいバグフィックスですね。

ちなみに試した時は以下メッセージが出たため、
```Engine is attempting to use the Magic Leap HMD since Zero Iteration is enabled but its required Vulkan extensions have not been enabled
Update the DefaultEngine.ini config of your project to set the [HMDPluginPriority] of MagicLeap higher than other HMDs
or launch the editor with the -hmd=MagicLeap command line arg.```
ひとまずDefaultEngine.iniに以下記載を追加しました。
```[HMDPluginPriority]
MagicLeap=40```

## まとめ
UE4.26では、一層OpenXRベースで、XR関連をまとめてきている感がありましたが、
Magic Leap的には、まだある程度専用API等で動かしていく部分は結構ありそうです。
逆に、専用APIになっているが故に、こういったアップデートの影響を受けないという考え方もありますが、
マルチプラットフォーム展開的な観点からは、あまりアプリ側は専用APIで管理はしたくないので、
今後の動向が気になりますね。
(専用のUE4エディタの提供もどこまでやっていくのか含め。)
アナログ回路 その9

# 概要

circuit sandboxをplunkerでホスティングした。
アナログ回路をシュミレーションで、説明してみる。

# トランジスタ・マルチバイブレータ回路

![無題.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/3a5b0229-9b4a-2dce-69b8-f9ea270c71b1.jpeg)


# 結果

![無題.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/d6ed3cbf-6fe9-c4e2-e12d-f503827a2899.jpeg)


# 説明

NPNトランジスタが交互に動作する。
その間隔は、コンデンサが決める。

# 成果物

https://embed.plnkr.co/plunk/jQn18RlGcwBE7e6S

以上。
計測自動制御学会SI2020講演会

#テクスタに使用しているプログラム

# モータ駆動用プログラム

- [走行用モータドライバ Sabertooth Dual 25A 6V〜24V](https://www.dimensionengineering.com/products/sabertooth2x25)
- [ソースコード等詳細ページ](https://qiita.com/tmdoi/private/fd4f11deb5544f232aad)

# モータドライバを駆動するマイクロビットのプログラム
- [BLEからの文字列コマンドを理解して、モータドライバに送信する](https://makecode.microbit.org/_Lfy62vbtFFa0)

# GAME ZIP64 コントローラを使って遠隔操縦するプログラム
- [マイクロビットのA/Bボタンで遠隔操縦と自律走行のモードを切り替え](https://makecode.microbit.org/_hsiDmC49Jbjr)

# コンパス用マイクロビットのプログラム
- [コンパス用プログラム](https://makecode.microbit.org/_FbHh8X3WFHCr)

# 関連動画
- [micro:Maqueeを操縦する](https://youtube.com/playlist?list=PLPKfPNY87vSiK69DwczRPVZVzouwKIlwg)
ActiveRecordで組み立てたRelationオブジェクトからサブクエリを抽出する

## 環境
- Ruby on Rails 6.1.0

## WhereClause.to_h()
`Hoge`と`Fuga`というふたつのActiveRecordモデルクラスがあるとして、`Fuga`の適当なIDで`Hoge`レコードを取ってくるようなメソッドがあるとします。

```ruby
def super_heavy_method()
  subquery = Fuga.first
  return Hoge.where(fuga: subquery)
end
```

このとき何らかの理由で`super_heavy_method()`の中身を触らずに、その返り値である`Hoge`のRelationオブジェクトから`subquery`内部にある`Fuga`のIDを取り出したいとします。

一度組み立てたActiveRecord Relationオブジェクトには、クエリの中身を取り扱うメソッドがいくつか用意されています。`where_clause()`というメソッドでWhereClauseオブジェクトが取得でき、その名の通りWhere句の条件をオブジェクトとして取得できます。`to_h()`でハッシュとして取り出すことができます。

```ruby
query = super_heavy_method()
query.where_clause.to_h() #=> {"fuga_id"=>1}
```

### 参考
- https://github.com/rails/rails/blob/v6.1.0/activerecord/lib/active_record/relation/where_clause.rb#L61
A2019 - ファイル/フォルダートリガー

#Automation360  - ファイル/フォルダートリガー

Attended Botでは、各種トリガーを使う事が出来ます。
トリガーは、PC上の何らかのイベントをきっかけにロボットを実行するための仕組みです。
ここでは、ファイル・フォルダトリガーを使ってみます。

##トリガーの追加
Automation360 開発画面の左下に「トリガー」という所があり、そこを展開します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/615564/0e82b547-0f1b-3aa4-a21c-bcb29fd784bf.png)

そうすると、このような各種トリガーが表示されます。
Google APIのVoice Triggerはカスタムパッケージとして追加したものですので、標準では出てこないと思います。
（SDKを使って開発すれば、独自のトリガーも実装できます。）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/615564/4b8995ca-de0f-a7d3-794b-a195779667c5.png)

そのトリガーを下記の赤く括った領域にドラッグ＆ドロップします。
尚、複数のトリガーを仕掛けることが出来ます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/615564/de612ed5-1171-3000-2751-d1dd73d1cf00.png)

ファイルトリガーは、特定のファイルの新規作成、削除、ファイル名の変更、更新が指定できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/615564/4d8dc491-7234-c3f9-2c0c-12f475c0f6fc.png)

フォルダートリガーは、指定したフォルダーが作成されたり名前が変更されたときや、新規ファイルが作成されたりといったイベントを指定することが出来ます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/615564/51d8a8f0-8077-7ba4-a718-d5dc23eec632.png)

##トリガーの内容を受け取る変数の指定
ファイルトリガー、フォルダートリガーでは、イベントの情報がレコード型変数としてBotに渡されます。
必要なレコード型の変数の詳細は、それぞれのアクションのプロパティから変数を新規作成すると確認することが出来ますが、下記の様なものです。

| ファイル・フォルダトリガーに指定する変数 |
|:-:|
| 入力として使用にチェック  |
| レコードタイプ  |
| （スキーマ）名前/型<BR> triggerType / 文字列<BR>eventType / 文字列<BR>timeStamp / 日時<BR>fromFolder / ファイル<BR>fileまたはfolder / ファイル  |

ここで、一つ問題になりがちなのが、最後の２つで、ファイル型になっている事です。
ロボットの中でファイルやフォルダを開いたりするのであれば問題ないのですが、そのフォルダのパスを利用した処理を行おうとした場合に、ファイル型変数を文字列型に変換できないのです。

なので、回避策として、手動で下記の様な変数を作り割り当てます。

| ファイル・フォルダトリガーに指定する変数 |
|:-:|
| 入力として使用にチェック  |
| レコードタイプ  |
| （スキーマ）名前/型<BR> triggerType / 文字列<BR>eventType / 文字列<BR>timeStamp / 日時<BR>fromFolder / **文字列**<BR>fileまたはfolder / **文字列**  |

こうすることで、文字列として値をとることが出来ます。

##トリガー付きのロボットを試す。
Bot Creatotrユーザーの場合は、実行->トリガーで実行で試すことが出来ます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/615564/ef006654-50c3-125c-e57f-999f94d3ccd8.png)

トリガーで実行を選択し、下記の様に待ち受け状態になったら指定したアクションをしてみてください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/615564/4e4e7a3d-1c1f-c49a-9311-372f99691a75.png)

例えば、特定のフォルダーに対する新規ファイル作成を指定することで、
こんな感じで、対象としているフォルダーとそのファイルのフルパスを得ることが出来ます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/615564/4864ef58-418e-5595-1f7a-ecbc5d793036.png)
Rails：データ型についてちょっとまとめてみた

# 最初に

**カレンダー企画2020の17日目**
プログラミングの勉強を始めて3ヵ月程経ったので学んだことのメモをアウトプットとして記事に残します。
これからプログラミングの世界に入る人の手助けになれたら嬉しい限りです。
間違っていたり、言葉が違っていたり、誤解されるような言葉があったら教えてください^^
言葉を長々と読みづらかったら申し訳ありません。少しずつなれてがんばります。

## Rails：データ型についてちょっとまとめてみる

[こちらで](https://qiita.com/yutas-8/items/5e039926793677be6fba)
データベースのテーブルについてまとめたのですが、
そこにカラムというのが登場しました。データ型はそのカラムに制限をかける（条件をつける）みたいな役割があります。

たとえば、
ネットショッピングサイトで金額のところに文字が入るようなことになるとちょっと困りませんか？
通常なら値段の「2980」だけを入れたいのに、制限をかけないでやってしまうと店舗側のミスなどで値段ではなく「大特価」だけが表示されて肝心の値段が分からないなんてことも考えられます。
それに、合計金額を出したいのに文字が入っていれば正常に動作せずお客様にも迷惑なサイトになります。

ちょっと分かりづらいですが本来欲しいデータではないものが入ってしまうということを事前に防ぐことができます。


## 代表的なデータ型を紹介

| データ型 | 制限される内容 |
|:-:|:-:|
| integer    | 数値（整数）  |
| decimal    | 数値（精度の高い小数）  |
| float      | 数値（浮動小数）  |
| string     | 文字（~255字までの短い文字列）  |
| text       | 文字（長い文字列） |
| date       | 日付  |
| datetime   | 日時  |
| time       | 時刻  |
| timestamp  | タイムスタンプ  |
| binary     | バイナリ  |
| boolean    | 真偽  |


## データ型以外にもカラムに設定できるものがあります

### AUTOINCREMENT

自動的に番号を連番で割り振る機能。
IDによく使われます。
アカウントや投稿の作成順に1から順に割り振られます。

### NOT NULL

空欄を禁止する機能。
保存する時にカラムの中身が空ではダメなものにはこれをつけると良いです！
たとえば、
アカウント作成のpasswordとかなしで登録されては困るのでつけたり、
ブログでタイトルは必ずつけてほしいと考えるのでしたらタイトル相当するカラムにつけるといいです。

### DEFAULT

初期値を設定する機能。
レコードが登録された時に自動でカラムの値をいれて登録します。

### UNIQUE

重複を禁止する機能です。
同じメールアドレスでの登録は禁止にしたい時やpasswordの重複などで使います。


他にもあると思いますので興味のある方は調べてみてください。


## 最後に

このようにカラムを作成する際は同時に制限をかけたり、ルールを設けることでアプリケーションを運用し始めた時に誤操作などを防ぎます。
最初のこの設計が結構大事になってきますね。
SharePointのビューで承認の状況でフィルターするとき


SharePointのリストで承認の状況でフィルターするときの自分用覚書です。

このようなフィルター条件を指定するとき、まぁいわゆる「承認済み」とか「Approve」みたいなものを入力しても認識されない

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317739/76ca57b0-1c89-07d5-c248-7a27d528950c.png)

画像のような、(おそらく内部的に状態を示す値の)半角数字を入力すると期待するフィルターが実施できる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317739/51039b2a-fdac-6b83-3b21-83d0138f5d4f.png)



0 : 承認済み
1 : 却下
2 : 承認待ち
3 : 下書き
schema.sqlの書き方の例

#schema.sqlの書き方を書いている記事がない
初心者です。実務に入るときに「実務では細かく定義する必要があるからschema.sqlは手動できちんと書きましょう」と言われましたが、書き方を探しても本当に何もないんですよね。ということで、サンプルコード（ここでは、飲食店での食材管理を想定したテーブル）を掲載します！
以下にサンプルコードがあり、その後に軽い解説も入れています。

```schema.sql
create table if not exists foodstuff (
    id              bigint       unsigned not null auto_increment comment 'ID',
    name            varchar(30)           not null unique key comment '食品名',
    delivery        date                  not null comment '納入日',
    expiration_date date                  not null comment '消費期限',
    stock_amount    int                   not null comment '在庫量',
    status          tinyint(1)            not null default 0 comment 'ステータス',
    create_time     datetime              not null default current_timestamp comment '作成日時',
    update_time     datetime              not null default current_timestamp on update current_timestamp comment '更新日時',
    primary key (id)
)
character set utf8mb4 engine innodb;
```

#解説

```
create table if not exists foodstuff
```
ここではテーブル名を定義しており、この部分の基本的な形は"create table foodstuff"です。しかし、基本的な形のままだと2回目以降の読み込みの際に再度同じテーブルが作られて同じ名前のテーブルが複数存在することになり、エラーの原因となります。その状況を回避するため、"if not exists"を挿入することで同じ名前のテーブルがすでに存在する場合は再度テーブルを作成しないようにしています。

```
id bigint unsigned not null auto_increment comment 'ID',
```
スペースをたくさん入れているのは見やすくするためで、実際の動作に関しては、必要な部分でスペースが１個あれば大丈夫です。
この１行（カンマまで）で１つのカラムを定義しています。左から順にカラム名、データ型（、オプション）です。
"unsigned"というのは符号なしという意味です。IDは1から始まって増えていくだけなので、マイナスは不要なのでこれを付けています。
"not null"は文字通りnullを許容しないというオプションです。
"auto_increment"を指定するとデータを入れたときにそのカラムにすでに入っているデータの中で最大のものよりも１大きい値が自動で入ります。
"comment 'ID'"というのはコメントで、ここに書いたことはデータベースには反映されません。日本語でカラムの説明をしたいときなどに付けます。

```
status tinyint(1) not null default 0 comment 'ステータス',
```
この行にあるように、"default 0"などとデフォルトの値を決めることもできます。

```
create_time datetime not null default current_timestamp comment '作成日時',
update_time datetime not null default current_timestamp on update current_timestamp comment '更新日時',
```
作成日時と更新日時はこのようになります。"current_timestamp"で現在時刻（データを作成した時刻）を指定できます。この２行に関しては他の書き方があまりないので、どのようなテーブルでも同じようになるのではないでしょうか。

```
primary key (id)
```
ここは文字通り、idカラムをprimary keyとして指定するという意味です。

```
character set utf8mb4 engine innodb;
```
テーブルの括弧の後でテーブル全体のオプションを指定しています。ここは必要に応じて指定してください。また、テーブルの定義はセミコロンまでなので、セミコロンを付けることをお忘れなく。

#まとめ
最後までお読みいただき、ありがとうございました。間違い等があればコメント欄へお願いします！
アナログ回路 その8

# 概要

circuit sandboxをplunkerでホスティングした。
アナログ回路をシュミレーションで、説明してみる。

# RLC並列回路

![無題.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/16a0ea69-61a6-e3d9-0fea-7d484e309f11.jpeg)


# 結果

![無題.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/bb646ccf-78a0-95b0-5331-784d5b2418f6.jpeg)

# 説明

1kHzのバンドパス・フィルターとして、作用する。

# 成果物

https://embed.plnkr.co/plunk/ET9tQqh96OebvMSh

以上。
Javascript(console上でモンスターを倒す)

# console上でモンスターを倒す

```javascript:monster.js

 'use strict';
  let enemy = 100;
  let count = 0;
  window.alert('戦闘スタート！');

  while(enemy > 0){
    const attack = Math.floor(Math.random() * 30) + 1; // Math.random() * 30 において 0~29までのランダムな数がえられるので、30まで取得するために+1
    console.log('モンスターに' + attack + 'ダメージを与えた！！');
    enemy -= attack;
    count++;
  }
  console.log(count + '回でモンスターを倒した！！');

```
<b>コンソール上でHP:100のモンスターを倒す！！</b>
<dl>
<dt>1、変数の用意</dt>
<dd>1、モンスターの体力を格納した変数 monster を定義。</dd>
<dd>2、モンスターにダメージを与えた回数を格納するための変数 countを定義。</dd>
</dl>

<dl>
<dt>2、アラートメッセージの表示</dt>
<dd>window.alertによりアラートメッセージを表示させる。</dd>
</dl>

<dl>
<dt>3、繰り返し文のwhileを用いてモンスターにダメージを与える処理を繰り返す</dt>
<dd>1、<b>Math.floor(Math.random() * 30) + 1; </b><br>

上記によって0~30のランダムな数字をattackに格納している。<br>
つまり、勇者の攻撃力をここで判定している。</dd>

<dd>2、<b>console.log('モンスターに' + attack + 'ダメージを与えた！！');</b><br>
上記によってコンソールにモンスターに与えたダメージについてのメッセージを表示させる。</dd>

<dd>3、<b>enemy -= attack;</b><br>
上記によってモンスターの体力である enemy から 勇者の攻撃力 attack を引く。</dd>

<dd>4、<b>count++;</b><br>1回ダメージを与えたことになるので、count　に1を足す。</dd>
</dl>

<dl>
<dt>4、何回目でモンスターを倒したかをコンソールに表示させる</dt>
<dd>console.log(count + '回でモンスターを倒した！！'); </dd>
<dd>上記により、何回目でモンスターを倒したかをコンソールに表示させている。</dd>
<dd>countにはダメージを与えた回数が格納されている。</dd>
</dl>

<b>参考文献

> 確かな力がつくJavaScript 超入門   著者: 狩野　祐東
CentOS6.7でMYSQL5.7⇒8.0にアップグレードする

# CentOS6.7でMYSQL5.7⇒8.0にアップグレードする話
はい皆さんこんにちは

この記事はCentOS6.7を頑なに使い続ける私やアナタのために書き残します。

# 詳細

参考にしたサイト
https://blog.offline-net.com/2018/04/22/upgrade_from_mysql_57_to_80/
https://qiita.com/imunew/items/3810a41960f40db85c94
https://ksm.bf1.jp/?p=216

環境：
CentOS6.7
MYSQL5.7
MYSQL8.0

注意事項：
CentOS6は2020-11-30 でサポート終了しています。
それでも使いたい人向けになります。

##まずyumが使えない
サポートが終了しているのでYUMのURLが接続できません。
そこで代替えのURLに変更する必要があります。
※詳細は参考にしたサイトをご覧ください。

```
# sed -i -e "s/^mirrorlist=http:\/\/mirrorlist.centos.org/#mirrorlist=http:\/\/mirrorlist.centos.org/g" /etc/yum.repos.d/CentOS-Base.repo
# sed -i -e "s/^#baseurl=http:\/\/mirror.centos.org/baseurl=http:\/\/vault.centos.org/g" /etc/yum.repos.d/CentOS-Base.repo
```
これによってyumが使えるようになりました。

##MYSQL5.7をアンインストール

```
# cat /etc/redhat-release
CentOS release 6.7 (Final)
# mysql --version
mysql  Ver 14.14 Distrib 5.7.32, for Linux (x86_64) using  EditLine wrapper
# cat /etc/my.cnf

# rpm -qa |grep community-release
mysql57-community-release-el6-7.noarch

# rpm -e mysql57-community-release
```

##MYSQL8.0をインストール

```
# wget https://dev.mysql.com/get/mysql80-community-release-el6-3.noarch.rpm
# rpm -ivh mysql80-community-release-el6-3.noarch.rpm
# yum --showduplicates search mysql-community-server
mysql-community-server-8.0.22-1.el6.x86_64
↑が最新版になっていると仮定します。

# /etc/init.d/mysqld stop
# grep datadir /etc/my.cnf
datadir=/var/lib/mysql
　と仮定する。
# cp -aR /var/lib/mysql/ /var/lib/mysql_bk/
※容量に空きがあればバックアップを取る。
# yum update mysql-server

# vi /etc/my.cnf
１．query_cache_* のパラメーターをコメントアウト
２．[mysqld]に次のオプションを入れる　default_authentication_plugin=mysql_native_password
# cat /etc/my.cnf

# cat /etc/init.d/mysqld|grep /mysqld | grep action
mysqldの場所を確認「/usr/sbin/mysqld」だったとします。

# /usr/sbin/mysqld --basedir=/usr --user=mysql --upgrade=FORCE
⇒処理中のままターミナルが帰ってきません。
```
別ターミナルを上げる

```
# tail -f /var/log/mysqld.log
このログが出たらOK
2020-12-16T03:02:18.203596Z 0 [System] [MY-010931] [Server] /usr/sbin/mysqld: ready for connections. Version: '8.0.22'  socket: '/var/lib/mysql/mysql.sock'  port: 3306  MySQL Community Server - GPL.
---
2020-12-16T03:05:35.865223Z 0 [ERROR] [MY-010901] [Server] Can't open shared library '/var/lib/mysql/lib64/mysql/plugin/validate_password.so' (errno: 0 /var/lib/mysql/lib64/mysql/plugin/validate_password.so: cannot open shared object file: No such file or directory).
⇒こういうエラーが出る場合は以下でファイルを探す
# find / -name "validate_password.so"
/usr/lib64/mysql/plugin/validate_password.so
/usr/lib64/mysql/plugin/debug/validate_password.so
※この場合lib64より手前の--basedir=/usrが正しいオプション。
　次の手順にあるkillコマンドで停止し、再実行する。
---
```


##アップグレード完了確認

```
# ps -ef |grep FORCE
# kill -9 ｛↑のPID｝
upgradeしているターミナルが強制終了と表示される

# service mysqld restart
# mysql -u root -p
mysql> select version();
+-----------+
| version() |
+-----------+
| 8.0.22    |
+-----------+
mysql> quit
---
ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (111)
このエラーが出る場合は
/etc/my.cnfに以下を入れてMYSQLDを再起動する
[client]
socket=/var/lib/mysql/mysql.sock
---

# mysql --version
mysql  Ver 8.0.22 for Linux on x86_64 (MySQL Community Server - GPL)

```


##感想
CentOS6系でまだまだ頑張る人の参考になれば幸いです。


**ありがとうございました。**
アナログ回路 その7

# 概要

circuit sandboxをplunkerでホスティングした。
アナログ回路をシュミレーションで、説明してみる。

# RLC直列回路

![無題.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/b68819d3-76cd-5396-f9a7-8c3e3a541f7c.jpeg)


# 結果

![無題.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/a36dee45-c1f1-84dc-f3da-8576391aab07.jpeg)

# 説明

1kHzのハイパス･フィルターとして作用する。


# 成果物

https://embed.plnkr.co/plunk/Jz6iskPK32QBfMCD

以上。
Jupyter環境とVenv環境を作る

## はじめに
本記事は筆者のPythonの環境構築を紹介したものになります。
筆者はjupyternotebookを用いた**データサイエンス用環境**と**Djangoを使うようの環境**の2つを作っています。

**jupyter環境内でも仮想環境をさらに分けて作れるし必要ないのでは？**と思われるかもしれませんが、jupyter(conda)環境には対応していなくて、venv(pip)環境に対応しているモジュール/APIなどが存在します。なので、両方あったほうがなにかと便利になると思います。

##なぜ環境を分けるのか
プログラムを作る際は**プログラムごとに環境を作り直すことが必須**といえます。なぜなら、**プログラムごとに必要な追加モジュールやバージョンが異なるから**です。

jupyter(conda)環境であればmaplotlibをインストールしますが、Webサイト構築用の環境にはこのモジュールはいりません。また、一方のプログラム内ではこのモジュールのver1.1を使わないと作動しないが、ほかのプログラムでは最新のverにアップデートしたいといった状況にも対応できます。以上のことから環境を分ける作業は必須です。

##仮想環境
環境を分ける方法はいくつか用意されています。通常1つのパソコンには１つのPython.exeしか導入できないので1つしか環境は作れません。しかし、実際には**仮想環境**といわれるものを構築し、一つのOSに複数のPython環境を作ることが可能になっています。主観ですが仮想環境とはフォルダごとにプログラムファイルを保存することとイメージするとわかりやすいです。
## 筆者のPython仮想環境への考え
筆者はvenv環境が好きです。理由はjupiter環境は問題が起きた時対応が難しいと感じたからです。
venv環境はとても単純でどこにどのファイルがあるかすぐ把握できるのが魅力です。**jupyterはあらかじめanacondanavigatorなどの便利ソフトが入ってるので、クリックで環境構築やインストールができてしまうのが魅力ですが、初心者は逆に何を行っているのか分かりづらい**と思います。筆者も初心者なのでvenvのほうがわかりやすくて好きということです。

## やってはいけないこと
jupyter環境はconda、venv環境はpipというツールを用いて動作します。問題はこのcondaとpipが競合してしまうことです。**同じ環境内で両方のツールをインストールしてしまえばバグが起きてしまいかなり面倒**です。

なので一般にこの両環境を合わせることはよくありません。**混ぜるな危険**。

##本題：仮想環境の構築
Pythonの場合大雑把に言うとjupyter環境、venv環境、virtualenv環境があります。（ほかにもあるとは思いますが）。virtualenv環境とvenv環境は似ているのですが、公式ではvenv環境が推奨されています。jupyter環境はデータサイエンス用の環境となります。venv環境はその他、といった感じです。
**結論を言いますと一つのユーザではこの2環境は両立できません**。筆者はいろいろトライしましたが、うまくいかず、断念しました。なので筆者は**ユーザを2つ作ってそこでそれぞれの環境を作りました**。

※ただし、jupyter環境の一つの醍醐味であるnotebookですがこれに関してはvenv環境でpip install notebookをすれば導入できますので、notebookだけを使いたいのであればjupyter環境はいらないかもしれません。
![仮想環境.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392111/ed925f8c-66b3-0cc9-fc36-edc0c0d65b57.png)
以下それぞれの環境を構築する方法を書きます。

## jupyter(conda)環境
まず、ユーザを新しく作ってそのユーザに切り替えましょう。
以降は2度手間ですので、以下のサイトを参照してください。
https://www.python.jp/install/anaconda/windows/install.html

## venv(pip)環境
同じく新たなユーザを作ってください。jupyter環境のあるユーザでなければ問題はないのでその場合は現ユーザで作ってもいいと思います。

Pythonの導入→venvモジュールのインストール→venvコマンドで仮想環境作成といった流れです。

Pythonの導入は
https://www.python.jp/install/windows/install.html
を参照してください。やっていることはアプリのダウンロードとPathへの追加です。

venvのインストール、仮想環境の作成
どうやらPythonの標準ライブラリにvenvモジュールはあらかじめ入ってるようなので別途インストールする必要はなさそうです。
https://qiita.com/fiftystorm36/items/b2fd47cf32c7694adc2e

## これら環境は何が違うの？
jupyter環境は**condaモジュール**を使ってパッケージの管理をします。

モジュールとは簡単に言うとpythonスクリプトです。pythonであらかじめあるdatetimeやos.pathなど使った経験があるかと思います。こういった機能が書かれたPYthonスクリプトがあらかじめPython.exeと一緒に同梱されています。これを標準ライブラリといいます。
https://docs.python.org/ja/3/library/index.html
これが標準ライブラリでvenvもありますね。

話を戻すとjupyterには**condaモジュール**があり、これの機能は**ファイルのインストール、削除、アップデート**などなどです。コマンド上では**conda install ~~**とうてば動作します。
一方venv環境はcondaではなく**pipモジュール**があります。**機能はcondaと同じ**で、**pip install ~~**とうてば動作します。

違いはこのパッケージ管理を行うモジュールです。実はこのモジュールごとに入れられるパッケージ（matplotlibやdjango、Celeniumなど）が違います。有名なライブラリはconda用、pip用で用意されていますが、**根本的な構造は違うので動作速度や容量、やれることなどに差が出ます**。

**conda環境はデータサイエンス系のモジュールが豊富で充実していますが、pip環境はそれ以外の用途ではcondaに勝るモジュールを導入できることがあります**。

以下URLでは筆者が実際に直面した問題になります。
https://teratail.com/questions/276416
#lesson 4 tableau public で100万行以上（エクセルでは無理）のオープンデータを公開 リレーション

# リレーション（テーブル間関連付け）
取り込んだテーブルの項目はコード化されていることがしばしばあります。
今回、使うテーブルは、国コードしかないので、国名を表示するために、国コード、国名のテーブルとリレーション（テーブル間関連づけ）を行います。

## 使うデータ
[kaggle](https://www.kaggle.com/zanjibar/japantradestat) にあります。ダウンロードには、kaggle のアカウントが必要です。

- custom_y_hs2_from_1998.csv(93.49 MB)
- country_jpn.csv(9.17 KB)

## 説明動画は、[これ](https://youtu.be/KVU8pLgM5F4)

- データ間リレーション
- フィルターで、輸出入金額上位5位の国に限定する
アナログ回路 その6

# 概要

circuit sandboxをplunkerでホスティングした。
アナログ回路をシュミレーションで、説明してみる。

# RLC直列回路

![無題.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/8cd30f5e-97cd-449d-7d4e-56d11f80e260.jpeg)

# 結果

![無題.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/6b77dce1-79a0-9132-53a7-055d9815b5f7.jpeg)


# 説明

1kHzのローパス･フィルターとして、作用する。

# 成果物

https://embed.plnkr.co/plunk/CYduaHbfL0QBvoD6

以上。
CloudFunctionsを使って未認証状態のメールアドレスをAuthから削除する

## 前提
・Node.jsの環境構築が終わっている
・Cloud Functionsの設定が終わっている
・Blazeプランを使用している

##はじめに
普段はSwiftを扱っており、JavaScriptの扱いに苦労したので、まとめておきます。
作成した関数は毎日同じ時間に実行され、条件を満たすユーザーを削除するようにしました。
## スケジュールに従って実行される関数の作成

```JavaScript
//12時０分に実行
exports.deleteUnverifiedUser = functions.pubsub.schedule('0 12 * * *')
.timeZone('Asia/Tokyo')
.onRun((context) => {

  return null;
});
```
ここは公式ドキュメントに書いてあります
[公式ドキュメント](https://firebase.google.com/docs/functions/schedule-functions)
[cronの書き方](https://www.yoheim.net/blog.php?q=20190902)

## ユーザーを削除する処理
条件を満たすユーザーを削除する処理を追加します。

```JavaScript
exports.deleteUnverifiedUser = functions.pubsub.schedule('0 12 * * *')
.timeZone('Asia/Tokyo')
.onRun((context) => {

  const deleteUnverifiedUser = (nextPageToken) => {
    admin.auth()
    .listUsers(1000, nextPageToken)
    .then((listUsersResult) => {
      listUsersResult.users.forEach((userRecord) => {
        var now = new Date();
        var timeForComparison = now.setHours(now.getHours() - 24);
        var userCreationTime = new Date(userRecord.metadata.creationTime);
        
        if(!userRecord.emailVerified && userCreationTime < timeForComparison) {
          admin.auth().deleteUser(userRecord.uid)
        }
      });
      if(listUsersResult.pageToken) {
        deleteUnverifiedUser(listUsersResult.pageToken)
      }
    })
    .catch((err) => {
      console.log(err);
    })
  };

  deleteUnverifiedUser();
  return null;
});
```
ここでの条件は（未認証かつ作成から24時間が経過）です
[参考](https://firebase.google.com/docs/auth/admin/manage-users#list_all_users)

## 最後に
簡単な処理ですが、誰かの役に立てれば嬉しいです☺️
【python3】未定義な関数やメソッドを宣言するデコレータを作ってみた。

# 1. 準備
次のようなモジュール( = pyファイル)を作り、`import`しといてください。

```python3:未定義.py
class 未定義Error(Exception):
    def __init__(self, f): super().__init__(str(f)+"は未定義です。")
class 未定義:
    def __init__(self, f): raise 未定義Error(f)
class 未定義メソッド:
    def __init__(self, m): self.m = m
    def __call__(self, *_, **__): raise Error(self.m)
```

# 2. 使い方
## 2-1. 関数内関数などの場合(オブジェクト指向のメソッドでない場合)

まず、次のように未定義の関数の`def`の上にデコレータ`@未定義`をつけます。

```python3:
from 未定義 import *

def f_out():
    @未定義
    def f_in():pass
    return f_in
```

そして `f_out()`を評価すると、次のようになります。

```:未定義Error：f_inは未定義です
Traceback (most recent call last):
  File "<pyshell#301>", line 1, in <module>
    f_out()
  File "~~~~.py", line 104, in f_out
    def f_in():pass
  File "~~~~.py", line 100, in __init__
    raise 未定義Error(f)
未定義Error: <function f_out.<locals>.f_in at 0x0000023470EFADC0>は未定義です 
```

# 2-2. オブジェクト指向のメソッドの場合

まず、次のように未定義のメソッドの`def`の上にデコレータ`@未定義メソッド`をつけます。

```python3:

class Test:
    def __init__(self):pass

    @未定義メソッド
    def mtd(self):pass
```

そして`Test().mtd()`を評価すると、次のようになります。

```:未定義Error：Test.mtdは未定義です
Traceback (most recent call last):
  File "<pyshell#309>", line 1, in <module>
    Test().mtd()
  File "~~~~.py", line 101, in __call__
    def __call__(self, *args, **kwargs): raise 未定義Error(self.m)
未定義Error: <function Test.mtd at 0x0000021AD5D3AF70>は未定義です
```

補足: クラスではメソッドを作ると、明示的に`クラスあるいはそのオブジェクト.メソッド(*)`を呼ばずとも、処理系によって一度そのメソッドが実行されます。
そのため、`@未定義メソッド`のところを単に`@未定義`に置き換えると、未定義なメソッドが存在する時点で、例えクラスが一度も呼ばれたり、オブジェクトが生成されなくても`未定義Error`を返すようになります。
第五回



# hello\_worldを出力しよう

今回は

    
    Hello world

と出力するプログラムを作成したいと思います．


# hello\_world.rbの解説

rubyでstringを打ち出す方法は以下のようになる．

| method | effect          |
|:-------|:----------------|
| print  | 普通の出力(改行なし)|
| puts   | 普通の出力(改行あり)|
| printf | Cのprintfと同じ |
| p      | coding中にdebug出力|
| pp     | pのpprint       |

プログラムではhello worldをputs ,p ,pp ,printf ,printの順に出力していく．


# hello\_world.rbの実行

ソースコードの内容は以下のようになる．

```ruby:hello_world.rb

puts 'hello world '


p 'hello world by '


pp 'hello world by '


printf 'hello world  '

print 'hello world '

```

これを実行すると

     
     hello world
    "hello world by "
    "hello world by "
    hello world  hello world

と出力された．


# 派生問題


## Theme

    
    > ruby hello_name.rb Ruby

と打ち込まれたら

    
    hello Ruby

と出力するruby codeをかけ．


## 解説

```ruby

puts ARGV[0]

```

　ARGVとは，argument vector，すなわち「引数の配列」である．コマンドラインからスクリプトを実行するときに，スクリプトに引数を渡すために利用される．ARGV[0]には1番目の引数が設定されている．

　これを用いて"hello Ruby"を出力する方法は，以下が用意されている．

| puts| puts "hello"+ARGV[0]       |
|:----|:---------------------------|
| puts| puts "hello " #{ARGV[0]}   |
| print| print "hello  #{ARGV[0]}\n"|
| print| print "hello "+ARGV[0] +"\n"|

ここから，以下のコードを実行してみる．

```ruby:hello_name.rb

puts "hello #{ARGV[0]}"
puts "hello #{ARGV[0]}\n"
puts "hello " + ARGV[0] + "\n"

```

ターミナル上で

    
    > ruby hello_name.rb Ruby

と記入すると，実行結果は

    
    hello Ruby
    hello Ruby
    hello Ruby

となった．



------
 - **source** ~/grad_members_20f/members/NobuakiMori/L05_hello.org
アナログ回路 その5

# 概要

circuit sandboxをplunkerでホスティングした。
アナログ回路をシュミレーションで、説明してみる。

# RC直列回路

![無題.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/022be2b8-91a2-072b-37f5-071b90d887ff.jpeg)

# 結果

![無題.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/18916187-ffad-94a1-4b3c-e676167dca76.jpeg)


# 説明

100Hzの方形波を加えて見た。
コンデンサは、充電、放電を繰り返す。


# 成果物


https://embed.plnkr.co/plunk/CCjPIjaddvvrMwlU

以上。
Rspecを用いたテストにおけるfactory_botの利用

## はじめに
[OPENLOGI Advent Calender 2020](https://qiita.com/advent-calendar/2020/openlogi) の12月17日の記事です。

本日はオープンロジ歴4ヶ月の金井が担当します。
前職まではメーカー勤務で畑違いでしたが、ソフトウェアの品質管理に興味が湧きQAエンジニアとしてエンジニアのキャリアをスタートしました。

今年も終わりが近づき初心を振り返るために、入社前に 「QAエンジニアならテスト書かな！！」 と自作のアプリの単体テストを書いていたのでそれを振り返ってみようと思います。
（実際は開発者が単体テストを書いているので直接関与することはありませんでしたが、QAチームでテストの自動化に絶賛取り組んでいるので完全に無駄になることはないは、、ず。。。）

実装言語、環境は
- Ruby2.5
- Ruby on Rails5.2
（自分の初学言語であり、社内では使用していないです。）

## そもそもRspecとは
Ruby用のテスティングフレームワークです。
今回はRuby on RailsにRspecを導入します。

## factory_botとは
Rspecでテストを書いていて、
毎度対象のインスタンスを生成（User.newのところ）するのは面倒です。
例えばこんな感じで（Userモデルの単体テスト）

```ruby
require 'rails_helper'
describe User do
  describe '#create' do
    it "usernameがないと登録できない" do
      user = User.new(username: "", email: "test@example.com", password: "111111", password_confirmation: "111111")
      user.valid?
      expect(user.errors[:username]).to include("が入力されていません。")
    end

    it "emailがないと登録できない" do
      user = User.new(username: "テストさん", email: "", password: "111111", password_confirmation: "111111")
      user.valid?
      expect(user.errors[:email]).to include("が入力されていません。")
    end
  end
end
```

そこで使えるのが factory_botです。
予めインスタンスの情報を記述しておけば、User.newでいちいちインスタンスを生成せずに、
buildやcreateといったメソッドで簡単に呼び出すことができます。

## factory_botの導入
まずGemfileに以下を記述します。

```ruby:Gemfile
gem 'factory_bot_rails'
```

次にspecディレクトリ直下にfactoriesフォルダを作成し、
その配下にそれぞれのファイルを置いていくというのが慣例みたいです。
今回の例であればusers.rbファイルを新規作成します。

```ruby:users.rb
FactoryBot.define do
  factory :user do
    username              {"テストさん"}
    email                 {"test@example.com"}
    password              {"111111"}
    password_confirmation {"111111"}
  end
end
```

これであとは呼び出すだけです。

*** factory_botの呼び出し

```ruby
user = FactoryBot.build(:user)
```

作成したインスタンスは上記で生成されます。
今回はbuildメソッドですが、createメソッドでも生成されます。
createメソッドの場合は一時的にテスト用のDBにデータが保存されます。
例えば一意性の確認の時に、最初にcreateメソッドで1人目を登録しておくことで、
2人目が同じ内容を登録した時にバリデーションが働いているかを確認することができます。

そして、FactoryBotという記述を省略することができます。
そのためにはrails_helper.rbファイルに以下を記述しましょう。
このファイルはRspecをRailsにインストール後、
```rails g rspec:instal```で生成されるファイルの一つです。

```ruby:rails_helper.rb
RSpec.configure do |config|
# 下記を追記
  config.include FactoryBot::Syntax::Methods
```

最終的にはこうなります。

```ruby
# factory_bot導入前
user = User.new(username: "テストさん", email: "test@example.com", password: "111111", password_confirmation: "111111")

# factory_bot導入後
user = build(:user)
```

かなりスリムになりました！

ちなみに、特定の箇所を変更したい場合は以下の通りです。

```ruby
user = build(:user, username: "")
```

これでusernameが空のインスタンスが生成されることになります。

## 最後に
簡単な内容だったと思いますが、数ヶ月前の自分のような初学者の助けになれたら幸いです。
docker M1 macプレビュー版のダウンロード

## はじめに
タイトル通りです

## docker M1 macプレビュー版がブログで公開されました
今朝[ブログ](https://www.docker.com/blog/download-and-try-the-tech-preview-of-docker-desktop-for-m1/)でプレビュー版が一般公開されてましたね！

[Docker Developer Preview Program](https://www.docker.com/blog/expanding-dockers-developer-preview-program/)に参加せずとも、これでサクッと試すことが可能に🎉
※ ちなみにプログラムの参加にはフォーム提出 => メール受信 => slack登録 & フォーム提出 => slackの `#dev-preview-program` チャンネルに招待される というちょっと長い工程が必要です。
[参考](https://qiita.com/ao41/items/5feb96cd01c312407a2b)

プレビュー版を試してプルリクバンバン送りたい方はプログラムに参加することをおすすめします！

## 動かしてみた

docker 起動させるとチュートリアル始まりました

```bash

docker run --name repo alpine/git clone https://github.com/docker/getting-started.git
docker cp repo:/git/getting-started/ .
cd getting-started
docker run -d -p 80:80 --name docker-tutorial docker101tutorial
docker tag docker101tutorial [dockerID]/docker101tutorial
docker push [dockerID]/docker101tutorial
```

```bash

:~ $ docker ps -a
CONTAINER ID   IMAGE               COMMAND                  CREATED          STATUS                       PORTS                NAMES
5403e08b5bc1   docker101tutorial   "/docker-entrypoint.…"   15 minutes ago   Up 15 minutes                0.0.0.0:80->80/tcp   docker-tutorial
a124acdfa30f   alpine/git          "git clone https://g…"   19 minutes ago   Exited (0) 19 minutes ago                         repo
```

コンテナ起動してるし、dockerHubへのpushもできてるし、問題なさそう☺️
[Vue.js]ref属性を使って子コンポーネントインスタンスと子要素へのアクセスする

##はじめに
refを初めて使用したので、備忘録として残します

##ref属性とは
プロパティとイベントが存在するにも関わらず、ときどき JavaScript で直接子コンポーネントにアクセスする必要がある。
その場合に ref 属性を使うと、子コンポーネントにリファレンス ID を割り当てることができる

##実装方法
今回はインプットフォームにフォーカスさせる

①インプットフォームにref属性を付与する

```
<input ref="input">
```

②親によって使用されるメソッドを定義して親コンポーネントに <base-input> 内部の input 要素にフォーカスさせる

```
methods: {
  // 親からインプット要素をフォーカスするために使われる
  focus: function () {
    this.$refs.input.focus()
  }
}
```

これらの実装でfocusメソッドが動いた時にrefを付与したインプットフォームにフォーカスされる

##参考
https://jp.vuejs.org/v2/guide/components-edge-cases.html#%E5%AD%90%E3%82%B3%E3%83%B3%E3%83%9D%E3%83%BC%E3%83%8D%E3%83%B3%E3%83%88%E3%82%A4%E3%83%B3%E3%82%B9%E3%82%BF%E3%83%B3%E3%82%B9%E3%81%A8%E5%AD%90%E8%A6%81%E7%B4%A0%E3%81%B8%E3%81%AE%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9
【超簡単！】Three.jsでUIを作る(1)  

![text2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276138/0707e58c-5482-c346-7ffa-c04e9f2b39e1.gif)

僕の大好きな、「[Experiments with Google](https://experiments.withgoogle.com/)」が制作した「[Assisted Melody](https://experiments.withgoogle.com/assisted-melody)」のWebアプリケーションがUIがWebGLで制作されていました。こんなUI簡単に実装したいですよね..。

探しても、この辺りの情報をまとめてくれている人がいなかったので自分で作ることにしました。

# sample01. マウスの位置を取得する + ただのシンプル四角形を描く

UIを作る前にここから学びましょう。
マウスのy座標に合わせて回転スピードが変わる四角形を作りました。

コード内に解説は全て書いたので、読んでください。
![text3.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276138/a7dee0b6-0f40-dd63-a775-d6c3a172f1e7.gif)

<p class="codepen" data-height="641" data-theme-id="dark" data-default-tab="js,result" data-user="yamkaz" data-slug-hash="ExgmoxR" style="height: 441px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="ThreeJS: Plane Geometry + MousePosition">
  <span>See the Pen <a href="https://codepen.io/yamkaz/pen/ExgmoxR">
  ThreeJS: Plane Geometry + MousePosition</a> by やまかず / Kazuyuki Yamamoto (<a href="https://codepen.io/yamkaz">@yamkaz</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

<script async src="https://production-assets.codepen.io/assets/embed/ei.js"></script>

→[次：【超簡単！】Three.jsでUIを作る(2)](https://qiita.com/Yamkaz/items/93fd11ebe772f24f9594)
次回は複数並べた四角形と、それをスクロールに合わせて移動します。
[Rails]whenever(gem)を用いたバッチ処理の実装

# 目標

3分おきに投稿した本を一定数削除する。

# 開発環境
・Ruby: 2.5.7
・Rails: 5.2.4
・Vagrant: 2.2.7
・VirtualBox: 6.1
・OS: macOS Catalina

#実装

###1.`Gem`を追加

```ruby:Gemfile
gem 'whenever', require: false
```

```java:ターミナル
$ bundle　install
$ bundle exec wheneverize //config/schedule.rbファイルが生成 
```

###2.`「data_reset.rb」`を作成

```app/lib/batch/data_reset.rb
class Batch::DataReset
  def self.data_reset
    Book.delete_all  #データベース内の本を削除
  end
end
```
◎idを指定したい場合は以下を記載
`Book.where.not(id: 1..30).delete_all` :id1~30以外は削除

◎作成日以降(12月1日以降)のデータを消したい時は以下を記載
`Book.where("books.created_at < ?", "2020-12-1").delete_all`

###3.`「config/application.rb」`を編集
```config/application.rb
  class Application < Rails::Application
    # Initialize configuration defaults for originally generated Rails version.
    config.paths.add 'lib', eager_load: true #ここを追加
    # Settings in config/environments/* take precedence over those specified here.
    # Application configuration can go into files in config/initializers
    # -- all .rb files in that directory are automatically loaded after loading
    # the framework and any gems in your application.
  end
```
`「data_reset.rb」`を有効にするために上記ファイルを変更


###4.確認
```java:ターミナル
bundle exec rails runner Batch::DataReset.data_reset //data_resetが行われるか確認
```
```java:ターミナル
Running via Spring preloader in process [プロセスID] //このようにでたら成功です
```

###5.`「schedule.rb」`を編集

```ruby:config/schedule.rb
:
:
require File.expand_path(File.dirname(__FILE__) + "/environment")
rails_env = Rails.env.to_sym
set :environment, rails_env  # 絶対パスから相対パス指定
set :output, 'log/cron.log' # ログの出力先ファイルを設定
every 3.minute do
  begin
    runner "Batch::DataReset.data_reset"
  rescue => e
    Rails.logger.error("aborted rails runner")
    raise e
  end
```

###4.`「cron」`を反映
wheneverではconfig/schedule.rbに記述した内容がcrontabに反映される仕組みになっています。

```terminal:ターミナル
$ bundle exec whenever --update-crontab
```
以下がでていれば成功です

```terminal:ターミナル
[write] crontab file updated
```

#その他のバッチ処理コマンド

`crontab -l` ➡︎ 実際にcrontabに反映しているか確認
以下がでていれば動いてる

```java:ターミナル
# Begin Whenever generated tasks for: /home/vagrant/work/アプリ名/config/schedule.rb at: 2020-05-05 03:29:06 +0000
0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58 * * * * /bin/bash -l -c 'cd /home/vagrant/work/アプリ名 && bundle exec bin/rails runner -e [開発環境] '\''Batch::DataReset.data_reset'\'' >> log/cron.log 2>&1'
# End Whenever generated tasks for: /home/vagrant/work/アプリ名/config/schedule.rb at: 2020-05-05 03:29:06 +0000
```

`$ sudo systemctl start crond` ➡︎ cron起動

`$ sudo systemctl stop crond` ➡︎ cronをストップ

`$ bundle exec whenever --clear-crontab` ➡︎ cronを削除
非モテだからマッチングアプリの練習したい

#はじめに

クソアプリ2 Advent Calendarの17日目です！
今年の６月からプログラミングの学習を初めて今回が初参加となります！！（当たり前）

今回は一緒に学習している方と二人で制作しました　(@sawamonさん)
クソアプリということで面白さを重視してつくりました


##何を作ったか

非モテの為のマッチングアプリの練習アプリを作りました（といってもchatbot)
お粗末なコードですがソースコードはこちら(https://github.com/gumipo/matching)

『マッチングアプリを登録したけど何話してええかわかんねぇえ』
って時に備えて女性との会話練習しようって思いました
![68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f3636393739322f61323733316562332d366335342d343037632d646530322d3335343966623733626237322e706e67.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669792/0ad7509f-115d-4b9b-0e79-40ea10441b57.png)

自分の名前とバチバチにキマってる写真を登録して始めよう！
（Databaseへ保存されないので好きなの使ってね）

![スクリーンショット 2020-12-15 18.14.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669792/753493c1-803b-761d-615f-1bb9410025bc.png)

続きは実際にお試しいただければ幸いです
https://mtching-d4bad.web.app/

見事女の子を口説き落とせた方は自信持って本番のマッチングアプリやりましょう

##今回参加してみて
やはり技術の無駄遣いは楽しい
来年も参加したい！！

##まとめ
初参加で何を作ろうか悩みましたが、なにはともあれ完成できたので良かった

今回二人で作成したこともありチーム開発の観点でも学習できた


以降のクソアプリも楽しいですね！！
アナログ回路 その4

# 概要

circuit sandboxをplunkerでホスティングした。
アナログ回路をシュミレーションで、説明してみる。

# RL直列回路

![無題.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/f4f454a2-27c0-286f-76d5-4ba560f4d057.jpeg)


# 結果

![無題.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/651d5822-f402-78e5-84ab-78cac83fb7fe.jpeg)


# 説明

100Hzの方形波を加えて見た。
波形の立ち上がりと立ち下りで、スパイク状の電流が流れる。


#成果物

https://embed.plnkr.co/plunk/kGlCZwY6WKm1XMbT


以上。
Xplenty ジョブの高速化Tips

#1. 少量データの処理を高速化する
Xplentyはデータ処理プラットフォームとしてHadoopを利用しており、通常のジョブはMapReduceで実行されます。もともとMapReduceはビッグデータ処理基盤として設計されているため、データの処理量にかかわらず開始と終了後のクリーンナップにオーバーヘッド時間がかかります。

そこで、Xplentyでは**小さいデータ量を扱うジョブの場合**は、MapReduceを使用せずにマスターノード上で処理を実行するオプションが用意されています。パッケージの変数画面で以下のように変数を設定することでMapReduceを介さずにスクリプトベース（Pig）でジョブが実行され、ジョブ実行時間の高速化を図ることが可能です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65461/3c8142cf-e1c9-fc60-1607-b23d307fbda9.png)

#2. Salesforceからのデータ読み込み処理の高速化
Xplentyでは、Salesforceオブジェクトから大量のデータを抽出する場合、「PK Chunking」の設定を有効にすることでPrimary Keyに基づき指定したチャンクサイズに分割して並列で読み込み処理を行うことで、読み込みにかかる処理時間の高速化を図ることが可能です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65461/e0d0fa8f-ae12-578e-cc6e-c07bf64b5ae5.png)

#3. Rest APIでのデータ書込処理の並列化
ユースケースによっては、サードパーティのREST APIに膨大な量のデータをスピーディに書き込まなければならない場合があります。APIをシングルスレッドで実行するのは非常に時間がかかります。理想的には、データスループットを高速化するために、APIを並列で実行するのがベストです。

XplentyはHadoop MapReduceを使用してサーバーのクラスタ上にコンピューティングタスクを分散させるため、（メモリやディスクの制約により）単一のサーバーでは処理できない大規模なデータセットに理想的な製品です。これにより、**ペタバイト級**のデータの並列処理が可能になります。

MapReduceの処理は、4つの主要なフェーズに分けられます。

- **Map**　キーによってグループ化されたキー・バリューペアです。
- **Shuffle**　同じキーを持つすべての値が、Reducerによって一緒に束ねられます。
- **Sort**　すべてのレコードはReducerによりキーごとにソートされます。
- **Reduce**　Reducerによりデータ値が集計されます、

サードパーティAPIへのデータ書き込みを高速化するために、Curリクエストを並列で実行することができます。以下の図のようにCurl()を実行する**Selectコンポーネントの直前に<font color="orangered">Sortコンポーネント</font>を追加することで、タスクが複数のクラスタノードに渡り分散されるようになります**（タスクはMapperではなくReducerによって処理されるため）。 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65461/0f1e5961-50ce-8e7a-e5da-aa1290736732.png)

デフォルトでは、Xplentyは単一のHadoop Reducerを使用します(Xplentyのシステム変数「_DEFAULT_PARALLELISM」は0に設定されています)が、「_DEFAULT_PARALLELISM」はシングルノード（1 node）のHadoopクラスタあたり最大「5」まで設定することができ、5つの並列スレッドを処理できるようになります。
** <パッケージ変数画面> **
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65461/fa3772c4-3f80-d731-5ccd-4314798bc05e.png)

Xplentyの変数「_DEFAULT_PARALLELISM」を「6」以上に増やすには、Hadoopクラスタが複数のノードを持っている場合にのみ有効です。
例えば、15の並列スレッドであれば、「_DEFAULT_PARALLELISM」は3ノードのクラスタが必要となります。


#4. システム変数
システム変数の中には、「_MAX_COMBINED_SPLIT_SIZE」（1つのタスクで処理するデータ量をバイト単位で指定します。設定値より小さいファイルは、このサイズに達するまで結合されます。それより大きなファイル（圧縮されていない、またはBzip2 を使用して圧縮されている場合）は設定されたサイズに基づき分割されます。）のように特定のシナリオにおいて、ファイル処理にかかるオーバーヘッドを少なくし、パフォーマンスを最適化する変数があります。

[Xplentyシステム変数の一覧はこちら](https://qiita.com/Azabu10ban/items/ab7a054e1391eb1d1727)
M5StickV+TOPPERSデモ3種

# はじめに

TOPPERS BASE PLATFORMにもいくつかデモアプリが含まれていますが、M5StickV向けではないので、M5StickV+TOPPERS用のデモアプリを作成してみました。

# 使い方

[M5StickV で TOPPERS BASE PLATFORM を動かしてみる](https://qiita.com/fukuebiz/items/016f88bbd48aa89a7226) の流れに加えて、[こちら](https://github.com/fukuen/toppers-m5stickv-demo) のデモアプリを asp フォルダーに上書きして、asp/OBJ/K210_GCC/ 以下のデモアプリをビルドします。

# CAMERA

カメラの画像をLCDに表示するだけのシンプルなデモです。M5StickVの動作確認や、その他のアプリのベースに使います。

カメラはM5StickVで使われているOV7740とMaixシリーズで使われているGC0328が使えます。（OV2640はTOPPERS BASE PLATFORM(RV)標準でサポートされています）


# BOOTSELECT

M5StickVには16Mバイトのフラッシュメモリが搭載されていて一般的には使い切ることはありません。そこであらかじめ複数のデモアプリを入れておいて、切り替えて使えるようにしました。もちろん標準のMaixPyも一緒に入れることもできます。

仕組みや使い方などはこちらの記事を参考にしてください

- [M5StickVでマルチブートする](https://qiita.com/fukuebiz/items/3d37351b7a3b0086e7c2)
- [Maixduinoでマルチブートする①](https://qiita.com/fukuebiz/items/f5ee98dbd1ab5055a50b)
- [Maixduinoでマルチブートする②](https://qiita.com/fukuebiz/items/e1170a8e798c20ac1feb)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555397/8ed79800-74e9-5ec4-2f30-1f0dbd4b57b7.png)



# SPIFFS

SPIFFS (SPI Flash File System) はマイコンに搭載されたフラッシュメモリをファイルシステムとして利用する仕組みです。M5Stack/ESP32などでよく利用されています。

[GitHub SPIFFS](https://github.com/pellepl/spiffs)

M5StickVにはM5StickVには16Mバイトのフラッシュメモリが搭載されていて、出荷時に上位3MバイトがSPIFFS領域として使用されています。出荷時にはMaixPy起動時のロゴ画面、起動サウンド、構成ファイルなどが格納されています。

M5StickV+TOPPERSでこのSPIFFSに入っているロゴ画面を表示してみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555397/1f4d2fd9-3b5c-aa65-af93-050ea5346ae7.png)

（jpeg表示にゴミが入ってます。。。）

# おわりに

今のところI2Sを動かすことができていませんが、I2Sのスピーカー、マイクも使ってみたいです。
【Stereo Depth】SCV-Net : Sparse Cost Volume Network

<h1>Sparse Cost Volume for Efficient Stereo Matching</h1>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482094/1f80874d-402b-24f4-2fce-8fba5572c53e.png)
Cost Volumeを作る代表的なモデルとして[GC-Net](https://qiita.com/minh33/items/8f3ce0ad64035d994af6)があるが、計算速度が遅い。
この論文では計算速度向上の為Cost Volumeの作り方を少し工夫している。

<h1>新規性</h1>
<h2>Sparse Cost Volume Construction</h2>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482094/1ae1d237-3fb2-2f61-25e6-084cd867fbc3.png)

cost volumeを作る時通常は1pixelずつスライドさせて(Batch,Disparity,Channel,Height,Width)作るのだが、SCV-Netでは
3pixelずつスライドさせて(Batch,Disparity/3,Channel,Height,Width)のコストボリュームを作る

もちろん計算速度が大幅に上がる。

<h1>結論</h1>
・Cost Volumeを減らし、layerを増やすなどの他のoperationを足す事で、計算コストを削減しつつ、同等の精度が出る。

ずっと思ってたけど、Cost Volumeってかなり無駄が多い気がする。

<h1>参考文献</h1>
Sparse Cost Volume for Efficient Stereo Matching
https://www.researchgate.net/publication/329134120_Sparse_Cost_Volume_for_Efficient_Stereo_Matching
JS 符号学习

1.  ...表示可以将一个string或者array拆解成一个个元素进行操作
举例：
function sum(x, y, z) {
  return x + y + z;
}

const numbers = [1, 2, 3];

console.log(sum(...numbers));//这里为了使用sum的方法，传递的参数将从一个array变成元素。而且...只是拆解，和array或者string里的char的个数无关
DefxとDeniteを合わせて検索を快適に

この記事は[ZOZOテクノロジーズ #4 Advent Calendar 2020](https://qiita.com/advent-calendar/2020/zozo_tech4)の17日目の記事です。
昨日は @akitokさんの HTMLの[分散負荷試験という選択肢](https://qiita.com/akitok/items/c422a8067236707d48d5) でした。


## はじめに

Defxを利用中、カーソル上のディレクトリに対して、Deniteで検索できれば捗りそうだなと思ったので実装してみました。
2つのダークパワーにより、さらなる闇力を上げていこうかと思います！

## Defx

簡単に説明すると、ツリー型のようなファイラーです。

![スクリーンショット 2020-12-16 11.11.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218282/8794b285-3001-5f1a-cb1c-461cdac367f3.png)


## 実装

Defxは、defx-action-callにより、独自関数をアクションとして呼び出すことができます。
これを利用して、Defxのカーソル上のディレクトリ内検索できるよう実装します。
※最後に最小構成のvimrc載せてます！

### Defxから呼び出す関数

処理としては、

1. Defxのカーソル上のディレクトリパスを取得（`a:context.targets[0]`で取得可能）
1. それをもとに、Denite grepコマンドを実行

これだけでOKです！

```vim
function! DefxDeniteGrep(context) abort
  let dirpath = fnamemodify(a:context.targets[0], ':p:h')
  exec 'Denite grep -path=' . dirpath ' -start-filter'
endfunction
```

### Defxキーバインドに追加

```vim
autocmd FileType defx call s:defx_custom_settings()
function! s:defx_custom_settings() abort
  nnoremap <silent><buffer><expr> <SPACE>fg
    \ defx#do_action('call', 'DefxDeniteGrep')
endfunction
```

## 実践

1. `:Defx`
1. 検索したいディレクトリにカーソル合わせる
1. `<SPACE>fg`でDenite grep実行

ちなみに、インタラクティブでgrepしたい場合は、下記のように書き換えればOKですね！

```vim
function! DefxDeniteGrepInteractive(context) abort
  let dirpath = fnamemodify(a:context.targets[0], ':p:h')
  exec 'Denite grep:::! -path=' . dirpath ' -start-filter'
endfunction
```

## 最小構成のvimrc
https://gist.github.com/deresmos/32b54ebe418c935895505f41f4303358

サンプル実行

```bash
$ git clone https://gist.github.com/deresmos/32b54ebe418c935895505f41f4303358 sample
$ nvim -u sample/defx_sample.vim
```

## まとめ
簡単にDefxの独自アクションを実装できるので、他にも色々とできそうですね！例えば、２つのディレクトリの差分をチェックしたい場合も、Defxで２つのディレクトリ選択してアクション実行させれば実現できそうですね！
Shadertoyのスペシャルキーボードテクスチャーの謎

###Shadertoyのスペシャルキーボードテクスチャーの謎
Shadertoyでは、シェーダーにマウスの値やサウンドのFFTデータなどをテクスチャーで渡すのが特徴である。
以前の記事でもサウンドデータの渡し方に触れた。https://qiita.com/quittardis/items/57d06947bf0a8b9fb7d0
キーボードのデータをどのように渡すかは、こちらのサイト"Special Shadertoy features"のkeyboardの項で解説されている。　　
https://shadertoyunofficial.wordpress.com/2016/07/20/special-shadertoy-features/

```
special texture keyboard: size 256 x 3 ;   values in .x field.
(ascii+.5)/256, 0.5/3. : 1 if key #ascii is currently pressed (keydown) otherwise 0
(ascii+.5)/256, 1.5/3. : 1 at the moment key is pressed (keypressed) otherwise 0
(ascii+.5)/256, 2.5/3. : 1/0 toggle for key #ascii
```
ところが、openframeworksからアドオンofxshadertoyを使ってshadertoyのコードを表示する場合、
具体的にどうするのか謎であった。shadertoyのグルの方々にとっては、上の解説だけで、謎でもなんでもないのだが、　　
凡夫にはチンプンカンプンで、実装に苦労したが、とりあえず動作するところまでこぎつけたのでリポートする。
こちら↓のKeyboard input example のコードが同じようにopenframwworksで動作するかどうかをゴールとした。　　
https://www.shadertoy.com/view/XsBXDw　　

![スクリーンショット 2020-12-17 095420.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/430586/5c3014b9-6d44-e70e-c1ae-0a8320021094.jpeg)
(a-yのキーを押してテストする。）
###openframeworksのコード
　先ずは、こちらの記事「ShaderToy+openFrameworksでクリエイティヴ ヴィジュアルを＜その１＞」
 https://qiita.com/quittardis/items/8ba902ebceeef93d55c8　　
を参考にofxshadertoyのアドオンを導入する。  
ofApp.hに以下を追加する。 
 
```
 ofTexture ktx;
 unsigned char keypixel[255 * 3];
```
これらは、キーボードテクスチャーをストアするofTextureと、ピクセル値の保存場所である。　　
次に、void ofApp::setup() を下記のようにする。

```
　ofDisableArbTex(); // very important!!!!
　shadertoy.load("shaders/key.frag");	
　//アルファチャンネルあり設定(デフォルトはこれ)
　fbo.allocate(640, 480, GL_RGBA);
　//
　shadertoy.makeKeyboardTexture(ktx);
　for (int i = 0; i < 255*3; i++)  keypixel[i] = 0; // clear keybord texture
	
　ktx.loadData(keypixel, 256, 3, GL_RED);
　shadertoy.setTexture(0, ktx);
　shadertoy.setAdvanceTime(true);
```
　上記のshadertoy.load("shaders/key.frag"); で読み込むkey.fragは、フォルダdata/shadersに置く。  
 内容は、https://www.shadertoy.com/view/XsBXDw
のコードをコピペする。このsetup()でやっていることは、キーボードテクスチャーの初期化である。
shadertoy.makeKeyboardTexture(ktx); で256x1のテクスチャーをktxを用意する。  
上のスペシャルキーボードテクスチャー  の記事に256x3とあるので混乱するが、このテクスチャーはグレーのテクスチャーである。
draw()は以下のようにする。

```
void ofApp::draw(){
	shadertoy.draw(0, 0);
}
```
最後に:keyPressedと、keyReleasedを以下のようにする。
keypixel配列の 
0-255が、 　　今押されているキー
256－511　　トグル情報
512-767   　　　押されたキー 
ということになっているらしい。

```
void ofApp::keyPressed(int key){
	//cout << key << "\n";
	for (int i = 0; i < 255; i++) keypixel[i] = 0; // clear 0-255 line 1
	for (int i = 0; i < 255; i++) {
		if ((key - 34) == i) {
			keypixel[i] = 255;       // pressing
			keypixel[i + 512] = 255; // pressed
		}
	}
	ktx.loadData(keypixel, 256, 3, GL_RED);
	shadertoy.setTexture(0, ktx);
}

//--------------------------------------------------------------
void ofApp::keyReleased(int key){

	for (int i = 0; i < 255 * 3; i++) {
		if ((key - 34) == i) {
			keypixel[i] = 0;
			if (keypixel[i + 256] == 0) {
				keypixel[i + 256] = 255; // toggle
			}
			else {
				keypixel[i + 256] = 0;   // toggle
				keypixel[i + 512] = 0;   // clear pressed
			}
		}
	}
	ktx.loadData(keypixel, 256, 3, GL_RED);
	shadertoy.setTexture(0, ktx);

}

```

これで、上記のshadertoy本家のKeyboard input example →　https://www.shadertoy.com/view/XsBXDw　　
と同じ動作になる。
dayjsで日本時間タイムゾーンで時刻を表示する

```js
//事前設定
const dayjs = require('dayjs') // v1.9.7
dayjs.extend(require('dayjs/plugin/timezone'))
dayjs.extend(require('dayjs/plugin/utc'))
dayjs.tz.setDefault('Asia/Tokyo')

// 現在時刻
console.log(dayjs.tz().format())
// -> 2020-12-17T09:57:06+09:00

// from UTC
console.log(dayjs.utc('2020-12-17T00:00:00Z').local().format())
// -> 2020-12-17T09:00:00+09:00
```
横幅によってJavaScriptを一部無効化有効化にする方法

やりたいこと
横幅481pxより大きい場合はjavascript(stickUp)を有効させる
横幅481pxより小さい場合はjavascript(stickUp)を無効にさせる

```
jQuery(function($){
  $(function() {
  var w = jQuery(window).width();
  var x = 481;
  if (w >= x) {
    $(".nav-wrapper").stickUp();
  }
  });
});
```
  var w = jQuery(window).width();で横幅を取得する


```
jQuery(function($){
  $(function() {
  var w = jQuery(window).width();
  var x = 481;
  if (w >= x) {
    $(".クラス名").〇〇();
  }
  });
});
```
DEV - Trigger

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332907/19b09904-73e3-1a50-69a6-27ea38664d9f.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332907/98b47563-7f18-87cf-dc20-806ac7f9793f.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332907/f297fc95-0327-d74a-6fc4-40f2d26319cf.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332907/4d4b50bf-6639-1448-0ff7-caa8b46173b9.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332907/217d45bc-7a71-684b-121a-3f540a466dc9.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332907/870edd24-f6b4-2fb2-e696-95451ce55522.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332907/0720db30-9fb7-a76b-88df-2b7cfd6df0ad.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332907/5a5dadc7-7999-169f-30aa-7424abacbe72.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332907/82ab4a8a-7f8d-c66c-bf3a-303d68c63e17.png)