OmniAICreator/Qiita-1.07M huggingface dataset:
LPC1114で温度,S-5851Aをソフトウェアシリアル出力 (ハードはichigojam)


目的
温度をシリアルに出力したい

工夫点は、書き込み用シリアルとデータ出力用シリアルを
分ける事によつて開発の効率を上げた。
データ出力用ソフトウェアシリアルの出力先は、dp9(9PIN)
標準シリアルに出力を出したい場合は、pc.printfに変えればよい
速度は9600bps



```c++


#include "mbed.h"

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

//#define S5851A 0x48
#define ADDR        ((0x48)<<1)   //  address

//Serial pc(USBTX, USBRX); // tx, rx
//Serial pc(SERIAL_TX, SERIAL_RX); //767
//Serial pc(PA_2, PA_3); //010
//Serial pc(PA_9, PA_10); //010
//Serial pc(dp16, dp15); // tx, rx 1114

//I2C i2c(I2C_SDA, I2C_SCL); //767
I2C i2c(dp5, dp27); //1114
//I2C i2c(PA_10, PA_9); //010

#define UART_DELAY (96) //  1/9600

//仮想シリアルの出力ポート
//DigitalOut TX(PA_9); //010
//DigitalOut TX(PA_2); //010
//DigitalOut TX(dp16); //1114  標準シリアルポートTX
DigitalOut TX(dp9); //1114 9PIN

//DigitalOut myled(D13);    //767
//DigitalOut myled(PA_4);   //010
//DigitalOut myled(dp14); //1114

//アナログ入力の設定
//AnalogIn adc_vbat(A3); //PA_4
//AnalogIn adc_vbat(A0); //767
//AnalogIn adc_vbat(dp4); //1114


//仮想シリアルへの一文字出力 9600bps
int pc_putc(char ch) {

    TX=1;

    TX=0;//START
    wait_us(UART_DELAY);

    for(int ii=0;ii<8;ii++){
        TX=(ch>>ii)&1;
        wait_us(UART_DELAY);
    }; //for

    TX=1;//Stop
    wait_us(UART_DELAY);

    return(0);

} //pc_putc

//文字列の表示
int pc_printf(char *str1) {

    //文字の中身がゼロか
    while(*str1){

        //一文字出力
        pc_putc(*str1 ++);

    } //while

    //戻り値
    return(0);
}//pc_printf



int     tempval;        //温度
char    data_read[6];   //i2cバッファー
int     n10;            //10の桁


int main() {

    //初期化
    TX=1;wait_ms(2);    //文字分のウエート
    pc_printf("\r\n");  //ゴミの吐き出し

    //無限ループ
    while(1) { 


        //初期化
        //set address 0
        i2c.write(ADDR, "\000", 1); //addres 0

        //温度の読み込み
        // Read temperature register
        i2c.read(ADDR, data_read,1,false);

        //温度の保存
        // Calculate temperature value in Celcius
        tempval =  data_read[0];



    
        //tempval = 12; //debug
    
        //計算
        // Calculation temp
        n10 = DVI10(tempval);             //10の桁
        tempval = tempval - ( n10 * 10 ); //1の桁

        //液晶に出力
        // Display result
        data_read[0] = '0' + n10;
        data_read[1] = '0' + tempval;
        data_read[2] = '\r';
        data_read[3] = '\n';
        data_read[4] = 0;

        //温度の出力
        //pc.printf(data_read); //1114
        pc_printf(data_read); //1114

        //1秒を待つ
        wait_ms(1000);
    } //while

} //main




```


![i2c_s5851a_1114_1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/69467678-64ea-c7f7-72da-d522665615e3.jpeg)
テレワーク(自宅勤務)で効率を上げる方法の経験談

## この文章を書いた理由

子育てをしながら自宅勤務をするといつも時間がたりない感じが強いです。

そこでどうしたら自宅勤務時の効率をアップして、子育て（家族との大事な時間）と仕事を両立させるか考えてみることになりました。

効果的だとは保証できないですが、自分が実施してよかった点をまとめておきますので、必要とする方に参考になればと望んでいます。

## スケジュールの調整

- 自分が一番集中できる時間帯は
- 自分が一番邪魔されない時間は

自己分析したところ、私には午前9時から12時が一番集中力が高く、誰にも邪魔されない時間は夜22時〜24時の間でした。

一般的なプロジェクトだと、午前9時から昼1時間挟んで午後6時までが通常勤務時間なので、一番生産性があるのは午前の3時間とのことになりますね。

午後は子供が学校から戻ってきて邪魔になったり、チームからの割り込み作業や会議が入ってきたりしてどうしても生産性が落ちる傾向ですね。

そこで自分がコントロールできる範囲で作業内容を下記の通り調整しました。

- 重要な作業は午前中に入れる
- 会議などは午後にする
- 技術調査などは一覧を作り、ちょっと暇があったら調査する
- 携帯を活用し、場所に囚われず（Slack内容確認や、資料調査など）携帯で行う
- 昼はちゃんと休む（できれば15分ぐらい仮寝する）

## コミュニケーション方法の調整

通常使っているコミュニケーション方法として電話、WeChat（Line）、Slack、メール、GoogleMeetなどだったので、これらの特徴を利用して使い分けをしました。

**電話：**即時性の高い内容は携帯で直電話で話をする。ただし通信料金が高いので、WeChatやLineの無料音声通話を利用する。

**WeChat（Line）：**今すぐでなくてもいい内容、記録を残すひつようのある会話はこれらのツールを利用します。ただし、ダイレクトで使うことが多いので、業務的にチーム内のみんなに共有する必要のあるないようはSlackを使うようにします。

**Slack：**無料のSlackを使っているため、重要な内容を書かない（もしくは書いたら必ず別の永久的な場所に同じ内容を保存しておく）、アップロード容量が制限されているので、ファイルの共有やアップロードはしない。チャンネルを作り、必要なメンバが必要な情報にアクセス（過去の会話履歴含め）できるようにする。

**メール：**ファイル添付や、正式な記録が必要な内容、カレンダーに記録するひつようのあるミーティングスケジュールはメールで連絡する（Google Meetを使っているので、Google Mailにベストでした）。

**GoogleMeet：**作りも簡単で、時間の制限もないし、インストールも要らずChromeで即時に動かせるので（画面共有なども簡単にできる）おすすめです。

## 効率化ツール

Notionがかなりお薦めです。( https://notion.so )

自分は有料版を使っているのですが、個人だと月４ドル（500円ぐらい）で容量無制限で使えるので、メモやプロジェクトの管理などに活用しています。携帯でも簡単にインストールして使えるし、機能の充実しているので、自分の経験まとめや情報記録管理などはこれ一つで十分な感じです。

## 生活との両立するには

難しい課題ですが、改善方法がないわけではございません。

自分の場合、家族用のカレンダーを作り、奥さんと共有しています。子供のピアノクラス、ダンスクラス、外国語クラスなどを全部カレンダーに登録し、自分の時間外作業時間も登録しておきます。

こうすることで、家族メンバー間でもお互いのスケジュールが分かり別の予定をする時、時間調整が容易になりました。会議やミーティング、飲み会などはなるべく家庭のスケジュールとタブラないようにすることで、チームのイベントも、家庭の予定もスムーズに進めることになりました。

あと、可能な限り、プロジェクトチームや会社の理解を得て、作業時間中にでも子供の面倒などを見れるようにある程度の自由を得て、仕事をするのが幸せにつながる感じがしました。その分夜22以降の邪魔されない時間で頑張って進捗を取り戻すなど工夫をすることで、影響を最低限に抑えることができたのです。

## 最後に

生き方改革をするには自由と自律が必要になります。自分のスケジュールを自分で調整できる自由がある分、自分が担当している作業はきちんと終わらせる自律性も求められるわけです。

なので、一番重要なのは、やはり自分が好きなことをやることですね。これがテレワークよりもっと難しい感じがするのですが、なるべく自分の好きなことに近い仕事やプロジェクトをすることで得るものは大きいです。

最後にテレワークをするみんなが幸せな仕事と生活を楽しめるようにお祈りします。
Laravel5.7のバリデーションでJPEG画像が画像として認識されない現象

# はじめに
古いLaravel（5.7）で画像のバリデーションを行った際に、何故かJPEG画像だけが画像として認識されない（エラーで弾かれてしまう）現象がありました。
バリデーションの内容は下記です。実にシンプル。

PNGやGifは問題無いのに、なぜ？

```php:MediaRequest.php
<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class MediaRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return true;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            'file' => 'required|image',
        ];
    }

    /**
     * @return array
     */
    public function attributes()
    {
        return [
            'file' => '画像ファイル',
        ];
    }
}
```

# 要因
composer update を行った後から発生したので、何かのパッケージが悪さしているのは明白です。
バージョンを戻した上で、改めてひとつずつパッケージを確認していきました。

すると、symfony/mime をアップデートした際に発生する事がわかりました。

```console
$ composer update symfony/mime --dry-run
- Updating symfony/mime (v5.1.2) to symfony/mime (v5.3.0)
```

どうやら、symfonyがv5.2以降で拡張子の順序を変更したため、
Laravelのバリデーション時にJPEG画像のmimetypeが一致しなくなり、エラーとして弾かれてしまうようになったとのこと。:joy:

```php:/vendor/symfony/mime/MimeTypes.php(v5.1.2)
'image/jpeg' => ['jpeg', 'jpg', 'jpe'],
```

```php:/vendor/symfony/mime/MimeTypes.php(v5.3.0)
'image/jpeg' => ['jpg', 'jpeg', 'jpe'],
```

# 解決方法
手動でパッチを当てる事で解決できるそうですが、私の場合は symfony/mime のバージョンを5.1に固定する事で難を逃れる事としました。

```composer.json
"require": {
    "symfony/mime": "5.1.*",
},
```

# おわりに
迂闊に composer update などしてはいけませんね。:sweat_smile:
古いLaravelをお使いの方はお気を付けください。

# 参考

https://github.com/laravel/framework/issues/35417
GatsbyJSにいれたnode16系で[DEP0148] DeprecationWarning: Use of deprecated folder mapping "./" in the "exports" field module resolution of the package at ...と怒られたのでその対応

結論から言うと node15系（15.14.0）にしぶしぶ変更してエラーが消えました。
※追記：gatsby-cloudを使ってビルドしている場合は現在node14までしか使えないためアプデするなら14系の方が良いかもしれません。

node12系からnode16系へバージョンアップさせる流れでぶち当たりました。（gatsbyのバージョンは3.7.2）

エラー内容ですが

```
[DEP0148] DeprecationWarning: Use of deprecated folder mapping "./" in the "exports" field module resolution of the package at
/Users/省略/package.json.
Update this package.json to use a subpath pattern like "./*".
```

ということで package.jsonで ./ となっているところを探したもののすでに ./* となっておりそこが問題ではありませんでした。

色々探してみると postCSS のバージョンが古いことが問題のようです。この記事を見ている頃には解決されているかもしれません。
しかしpostCSSの最新バージョンをインストールしましたがダメでした。

また、gatsbyプラグイン各種を最新アップさせたり、package.jsonにexportのJSONを追記してみたりしたものの解決できず。
node_modulesを再インストールも虚しく解決することができませんでした。

## Gatsbyライブラリの中のPostCSSのバージョンが古いことが原因らしい

https://twitter.com/PostCSS/status/1385261623171063811


PostCSS側ではこの問題は解決されているみたいですが、Gatsbyが使っているPostCSS自体が古いため？エラーを解決できないようです。


## nodeバージョン12系から15系に変更したついでに消えたエラー

```
[DEP0066] DeprecationWarning: OutgoingMessage.prototype._headers is deprecated
```

ちなみに上のエラーも一緒に消えてくれました。 got@latest で解消できたという記事も見かけましたが何もせずに消えてくれました。
Spotifyの新規サービスGreenroom

Spotifyが新規サービス<b>Greenroom</B>を提供しましたね。
ここからは私の意見と思うことについて書いていきたいと思います。

GreenroomはclubhouseのSpotifyバージョンみたいなものですね。
clubhouseは会話などをリアルタイムで公開することができるアプリとなっています。

日本でもclubhouseはかなり流行りましたね〜
YouTuberや芸能人なんかも使っていたのが記憶に新しいです。
しかし爆発的に伸びたせいか、今は少し人気が落ちているような印象です。

そのclubhouseを見て各社が似たようなサービスを提供していました。
Twitterのspacesが一番有名かなと思います。

そして今回サービスを提供したGreenroomですが、元となるアプリが存在しました。
それがロッカールームというアプリです。このアプリは日本には進出していないらしいので私も含め馴染みが全くないのですが、調べていると、clubhouseの対抗馬だったようです。
そのロッカールームをSpotifyは2021年3月に買収していました。
買収から約３ヶ月でGreenroomをリリースしたということなんですが、かなり過酷そうなスケジュールですね。笑
そんな技術者たちが存在していることに日々驚かされます。

しかし残念ながら現時点ではこのGreenroom、<b>日本は対象外</b>です。
そのうち日本にも来るとは思うのでニュースを日々チェックしようと思います。

##アーティストとの連携が爆発的に伸びる？
Spotifyは世界最大の音楽アプリで世界中のアーティストの方々がSpotifyで音楽を配信しているのですが、そのアーティストとSpotifyの連携がGreenroomの伸びに関係してくる気がします。
例えばですが自分の好きなアーティスト同士の対談などをGreenroom上で行っていたら、参加したくなりますよね。
Greenroomじゃなくてもできることですが、やはり世界最大の音楽アプリ上でできるということが最大のメリットかなと思います。アーティストは自分達の楽曲などをより早くファンに伝えることができたり、音楽を聴けるだけでなく、好きなアーティストの情報もいち早く入手できたりしたら、利用者にとってもかなりありがいサービスですよね。

早く日本でも使えるようになって欲しいですね〜
Gitの概要

#はじめに
この記事は初学者の学習内容の記録用です。
記載内容に間違いがありましたら、ご指摘いただけると幸いです。

#Gitとは
バージョン管理ツールの一つで
ソースコードのバージョン管理に使用される。

#Gitの特徴

* リモートとローカルでソースコードを管理する<br>分散型バージョン管理システム(Distributed Version Control System)
* ローカルでは更に「ワークツリー」「ステージ」「ローカルリポジトリ」に<br>
分かれてソースコードを管理する
* スナップショットを取って変更したファイルをまるごと記録する(差分管理ではない)
* コミット時に一つ前のバージョンを記録しているので過去にさかのぼっていける
 
#Gitのメリット・デメリット
###メリット
* ブランチを素早く作れるので、複数人で同じファイルを編集している際でも<br>並行して作業しやすい
* ローカルにステージがあることで記録したい単位でファイルを管理しやすい
* ローカルにリポジトリがあることでオフラインでもバージョン管理できる
* Github Flowに沿って開発するとコードレビューを<br>masterへのマージの都度できて品質向上につながる

###デメリット
* 機能がたくさんあり複雑である

#Git基本用語

|　用語 　|　解説　| 
|:-----------|:------------|
| リポジトリ |スナップショットを記録するデータの保管場所　| 
| ステージ |コミットする変更を準備する場所  | 
| ワークツリー |ファイルの変更の作業場所　| 
| コミット　|ファイルの変更を確定し記録すること| 
| ブランチ |プロジェクトの履歴を分岐させたもの　|
| フェッチ　|リモートリポジトリの内容をローカルリポジトリに取り込むこと| 
| マージ　|ブランチを統合すること| 
| プル　|ローカルで作業中のブランチにフェッチとマージを一度にすること| 
| コンフリクト |マージの際に変更したファイルの場所がかぶっていたときに起こる| 
| プッシュ |コミットした内容をリモートリポジトリに送ること| 
| プルリクエスト |プッシュした内容のレビューを依頼し、問題なければマージしてもらう| 

#Gitで最初にやること
1. Gitをインストール
1. Githubアカウントを登録し、リモートリポジトリを作成
1. .gitignoreファイルにGithubにアップロード・バージョン管理しないファイル<br>(パスワード、外部リソース接続情報などの設定ファイル・キャッシュファイル)<br>を定義する<br>
※Githubでリポジトリの新規作成時に各言語・FWごとにテンプレートがあるので<br>自動生成がおすすめ[【GitHub】.gitignoreのテンプレートを言語・FWごとに自動生成](https://qiita.com/axs-dev/items/6ca7fe195004ddb2cd2c)
1. ローカルでリモートリポジトリとの紐付けをする(git remote add)
1. 管理対象フォルダ・プロジェクトを初期化する(git init)

#Gitを使って個人的にバージョン管理するフロー
1. ファイルをワークツリーで変更する
1. 記録したいファイルをステージに登録してインデックスを作成する(git add)
1. 記録を確定させたいインデックスをコミットする(git commit)
1. 作業が一区切りついたらリモートにプッシュする(git push)

#Gitを使ってチーム開発するフロー(Github Flow)
1. masterブランチから作業用ブランチを作成
1. 作業用ブランチでファイルを変更してコミット<br>(上記:Gitを使って個人的にバージョン管理するフローと同じ)
1. 作業用ブランチをGitHubへプッシュ
1. プルリクエストを送ってコードレビューを依頼
1. コードレビューでOKが出ればmasterブランチにマージ
1. masterブランチをデプロイ

* masterはリリース用ブランチです。<br>
* 開発する機能・修正などの作業の単位で別にブランチを作成して作業します。

#参考・学習したサイト

https://www.udemy.com/course/unscared_git/

https://backlog.com/ja/git-tutorial/

https://www.ricksoft.jp/blog/archives/9483/
Linux cronでOS再起動を行う

##"shutdown -r now"ではなく、"/usr/sbin/shutdown -r now"とするのがポイント
再起動コマンドをシェルファイルに記載し、cronからシェルファイルを実行する場合。
パスの関係でshutdown -r nowと記述しても再起動されないので注意が必要
以下のように、/usr/sbin/shutdown -r nowと記述する必要がある

```shell
rebootDate=`date "+%d"`

if [ ${rebootDate} -eq "15" ]; then
  /usr/sbin/shutdown -r now
fi
```
Google Maps APIを使用して施設の写真を手にいれる方法

## 概要
GoogleのAPIを使用し、施設の写真を取得する方法を探していた時に、3つのやり方があったのでまとめました。
APIを使用するためにはキーが必要なのですが、以下の記事を参考にして取得しました。
https://qiita.com/Haruka-Ogawa/items/997401a2edcd20e61037

APIを叩く際にはcurlコマンドを使用しました。

## 方法
* [Place API](https://developers.google.com/maps/documentation/places/web-service/overview?hl=ja)を使用する方法
* [Street View Static API](https://developers.google.com/maps/documentation/streetview/overview?hl=ja)を使用する方法
* [Maps Embed API](https://developers.google.com/maps/documentation/embed/get-started?hl=ja)を使用する方法

## Place APIを使用する方法
施設名をパラメーターとして渡し、以下のAPIを叩いて、photo_referenceをレスポンスとして受け取ります。

```terminal
$ curl -G -d input=〇〇総合体育館 -d inputtype=textquery -d fields=photos -d key=APIキー https://maps.googleapis.com/maps/api/place/findplacefromtext/json

{
   "candidates" : [
      {
         "photos" : [
            {
               "height" : 2448,
               "html_attributions" : [],
               "photo_reference" : "abcdef...",
               "width" : 3264
            }
         ]
      }
   ],
   "status" : "OK"
}

```
取得したphoto_referenceの値を使用し、以下のAPIを叩き、画像のリンクを取得します。
画像自体はoutput.pngという名前で出力しています。

```terminal
$ curl -G -d photoreference=abcdef... -d key=APIキー -d maxwidth=400 https://maps.googleapis.com/maps/api/place/photo -L > output.png
```

## Street View Static APIを使用する方法
このAPIを使用するとGoogle Street Viewのパノラマ画像の中から、指定した部分の静止画を取得することができます。fovに視野角、pitchに縦方向の角度、headingに横方向の角度、sizeに画像サイズを指定します。

```terminal
$ curl -G -d location=〇〇総合体育館 -d fov=100 -d pitch=10 -d heading=0 -d size=600x600 -d key=APIキー https://maps.googleapis.com/maps/api/streetview > output.png
```

## Maps Embed APIを使用する方法
この方法は緯度、経度を指定して、そのストリートビューをWebサイトに埋め込んで使用します。
施設名をパラメーターとして指定できないため、事前に緯度と経度を取得しておく必要があります。

```html
<iframe
  width="450"
  height="250"
  frameborder="0" style="border:0"
  src="https://www.google.com/maps/embed/v1/streetview?key=APIキー&location=46.41...,10.01..." allowfullscreen>
</iframe>
```
指定フォルダ内のすべてのファイルを実行するバッチ

単体テストのHTMLなどをすべて開いて確認しなくてはいけないような時に便利

```bat:exec.bat
@echo off
echo "フォルダを指定してください。フォルダ内のすべてのファイルを実行します。"
set /p IN="input:"
for /r %IN% %%i in (*) do (
 echo %%i
 %%i
)
```

```
実行結果
c:¥//****/**.html
c:¥//****/**.html
c:¥//****/**.html
c:¥//****/**.html
c:¥//****/**.html
```
[Rails] MVCモデルを深ぼる~Model編~

##はじめに
今回はModelについて少し踏み込んだ内容をアウトプットしていきたいと思います。
よろしくお願いします。

##モデルの役割とActive Model
モデルはコントローラーから命令されてデータを保存したり、データベースからデータを引っ張り出してくれたりします。またデータの加工を行ってくれたり、保存する前にデータの検証も行ってくれる役割があります。

モデルの「データをデータベースへ保存する」という機能はActive Recordという仕組みによって実現されています。
「保存する前のデータの検証」Active Modelという仕組みによって実現されています。すなわちモデルはこの二つの仕組みによって構成されています。

もう少し細かく、それらActive ModelとActive Recordが持っているモジュールをいくつかみて、モデルの理解を深めていきます。


## Callbacksモジュール
Callbacksモジュールは必要なタイミングや、任意のタイミングでコールバックを定義することができます。
*※ここでいうコールバックとは任意のタイミングで実行できる処理のことを指します。*

コールバックはメソッドを定義するのと同じように登録します。下記に例を載せておきます。

```Ruby
class Tweet < ApplicationRecord
 validates :text, presence: true
 belongs_to :user
 has_many :comments

 # バリデーションの後で「puts_sample」を実行
 after_validation :puts_sample

 # 「puts_sample」というcallbackを登録
 private
   def puts_sample
     puts 'sample'
   end
end
```

after_validationという記述でバリデーションが行われた後に実行するように指定しています。

##Validationsモジュール
バリデーションはデータベースへデータを保存する際に、保存してもいいデータなのか（期待通りのデータの形なのか）判断するために用いられるフィルターのようなものです。
もし、誤ったデータであるなら、バリデーションが弾いてくれます。

例えば、validates :text, presence: true　と書いて、textが空なら保存しないようにするやつです。

##Serializationモジュール
Serializationモジュールは値を返す時に整えて返してあげることがモジュールです。
どういうことかというと、一つのレコードに5種類のデータ（カラム）が存在していたとして、しかし、必要なデータはその中の二つだけだったとしたら、残りの三つは不要なのでそのデータは含めないように整えてくれるのです。

例のコードをを下記に載せておきます。

コントローラーでこのようなindexアクションが定義されているとします。

```Ruby
class TweetsController < ApplicationController
  def index
    @tweets = Tweet.includes(:user).order("created_at DESC")
    render json: @tweets
  end
end
```

これはJSON形式で値を返しています。
中身は下記のようになっているとします。

```terminal
[
  {"id":2,"text":"太陽の写真","image":"data:image/sample","created_at":"2020-04-22T06:11:44.134Z","updated_at":"2020-04-22T06:11:44.134Z","user_id":1},
  {"id":1,"text":"綺麗な景色","image":"data:image/jpeg;base64,/9j","created_at":"2020-04-22T06:11:25.425Z","updated_at":"2020-04-22T06:11:25.425Z","user_id":1},
]
```

しかしながら必要なのはtextとimageだけだったら、モデルにattributesメソッドを用いて下記の記述をすると、textとimageだけの値を返却することができます。

```Ruby
  def attributes
    {'text' => nil, 'image' => nil}
  end
```

このようにすることで、余分な情報がないので扱いやすくなります。

##Formオブジェクト

Formオブジェクトは、例えば、一度の投稿作業で（投稿ボタンのクリック一回で）複数のテーブルへ情報を更新したりする時に役立ちます。フォームに関する処理を切り出す仕組みです。

フォームに入力されている情報が複数のモデルに関係するデータで、一回で複数モデルを操作し、データを更新したい時（投稿機能）や、フォームに入力された情報に対するモデルが存在しないがバリデーションをかけたい時（検索機能）などに使用します。

使用方法は別記事で書きたいと思います。

##終わりに
3回にわたって、MVCモデルを少し踏み込んでみました。自分自身、新しく知れたことや、いまだに理解が浅いところが浮き彫りになり、このように記事をまとめる機会を作れてよかったと感じています。特に理解し難い部分や詳細に説明できなかった部分に関しては、オブジェクト指向の概念がしっかりと理解しきれていないことに起因していると思います。

このような基礎的な部分はこれからもねちっこく付き合って理解していきたいと思っています。
Scalewayの最安VPSが安い気がする。

STARDUST1-Sってやつが€1.83(約250円)/月。

以下スペック、そこそこで安い。

- CPU: 1Core(X86 64Bit)
- SSD: 10GB(NVMe)
- メモリ: 1GB
- Bandwidth: 100Mbps

Scalewayは少し前にARMのVPSで話題になったが、もうARMのVPSはやってないらしい。
単価が安すぎて儲からなかったのかな。
iPad ProをWebサーバーにしてローカル開発環境を構築する

最初は、所有しているMBAがだいぶ古くなってきたし、満足できそうなスペックのM1 MacBook Airが発売されたので買い換えようかな〜と思っていたのですが、そう言えば最近Macを起動することがなくなってきたし、仕事でMac使っているのでプライベートでもMacを使うの億劫だなと思い、MBAの買い替えではなく思い切ってiPad Proを購入してみました。
今では子供のおもちゃになっている、第2世代iPad mini購入以来のiPadになるため、かなりウキウキで毎晩面白い事できないか考えていたところ、iSH Shellという面白いアプリを見つけたので、iSHを使ってのWebサーバー構築とローカル開発環境の構築手順をご紹介したいと思います。

# iSH Shellとは

iOSまたはiPadOS上で、Linuxシェル環境を可能にするアプリになります。

> iSH is a project to get a Linux shell environment running locally on your iOS device, using a usermode x86 emulator.
> iSHは、usermode x86エミュレータを使用して、iOSデバイス上でLinuxシェル環境を実行するプロジェクトです。

https://apps.apple.com/jp/app/ish-shell/id1436902243

Alpine Linuxがベースになっているようなので、必要なミドルウェアのインストールは**apk**コマンドでインストールすることができます。
では、次にWebサーバー構築に必要なミドルウェアをインストールする方法をご紹介いたします。

# ミドルウェアのインストール

ちょっとした編集に必要なvimは必須として、ひとまずgitとsshとunzipをインストールすることにしました。
後は、今回PHP7とLaravelで開発したかったので、PHP7とcomposerとLaravelをインストールします。

```
apk update
apk upgrade
apk add vim zsh git openssh
apk add php7 composer unzip
apk add php7-dom php7-xml php7-xmlwriter php7-fileinfo php7-tokenizer php7-session
```

# Laravelのインストールとサーバーの起動

Laravelプロジェクトを作成して、動作確認をしてみます。

```
composer self-update --2
composer create-project laravel/laravel sample
cd sample
php artisan serve
```

# ブラウザで確認

ブラウザで`http://127.0.0.1:8000`にアクセスして、以下の画面が表示されることを確認します。

![Laravel.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52331/3b01341d-7137-75a0-22e6-f4f82ac9536b.png)


# Textasticでコーディング

実はiSHで作成したファイルは、`Files`アプリで編集することが可能です。

![IMG_2259E6C08AA7-1.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52331/f8de71f2-307b-a05f-7e6b-1b136dcae7a1.jpeg)

iPadOSの開発ツールアプリで常にいる、Textasticでコーディングしていきます。

https://apps.apple.com/jp/app/textastic-code-editor-9/id1049254261

# 参考
【GAS：Directory API+Groups Settings API】組織内の全Googleグループの設定をスプレッドシートに出力

#概要

`groups.list`メソッドで一度に取得できる結果は200件までのため、200件を超える結果を取得するためdo-while文を使って記載している。
https://developers.google.com/admin-sdk/directory/reference/rest/v1/groups/list

Groups Settings APIで取得できるプロパティは以下の通り。
今回は例として`includeInGlobalAddressList`を使用。
https://developers.google.com/admin-sdk/groups-settings/v1/reference/groups

A列にメールアドレス、B列に設定値を記載する仕様にしている。

#コード

```
function listAllGroups() {
//出力先シート名をgetSheetByName()内に指定
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('データ');
var allGroupdata = [];
var pageToken;
var page;

//シートの内容を全消去
sheet.clearContents();

//組織内に存在するすべてのGoogleグループを取得
do {
page = AdminDirectory.Groups.list({
//ドメインを指定
domain: 'test.co.jp',
maxResults: 100,
pageToken: pageToken
});
var groups = page.groups;

for (var i = 0; i < groups.length; i++) {
  var group = groups[i];
  var groupdata = [];
  groupdata.push(group.email);
  var groupSettings = AdminGroupsSettings.Groups.get(group.email);
  groupdata.push(groupSettings.includeInGlobalAddressList);

  allGroupdata.push(groupdata);
}

pageToken = page.nextPageToken;

} while (pageToken);

sheet.getRange(1, 1, allGroupdata.length, 2).setValues(allGroupdata);

}
【C#】WPFでCalendar コントロールがフォーカスを握ったままになる問題の対策

WPFでCalendarコントロールと設定ボタンを配置して
選択した日を設定するような画面を作った時の話。

画面自体は他の人が作成していて、動作確認時に、
『日付を選択した後、設定ボタンを2回押さないと反応しない』という指摘が。

確かに確認してみたらその挙動になる。
他にも入力コントロール(テキストボックスやスピンボタン)があるが、
そちらは入力後にボタンを押下すると正しく反応するので
Calendarが悪いと判断。

個人的には日付選択はDatePickerを使うことが多かったので初体験だったけど
調べてみるとCalendarのバグらしく、ネット上でも議論が交わされていた。
https://social.msdn.microsoft.com/Forums/vstudio/en-US/b4413872-59d0-4a06-9d20-8d21de126dc6/calendar-not-losing-focus-wpf-40?forum=wpf

結論としてはCalendarコントロールがフォーカスを握ったままになってしまうので
それを開放してあげる必要がある、ということ。

具体的な対応方法は以下のようにCalendarコントロールを配置したウィンドウクラスの
OnPreviewMouseUp() をオーバーライドし、Calendar コントロールにフォーカスがある場合は開放する。

```c#
protected override void OnPreviewMouseUp(MouseButtonEventArgs e)
{
    base.OnPreviewMouseUp(e);
    if ( (Mouse.Captured is Calendar) || (Mouse.Captured is System.Windows.Controls.Primitives.CalendarItem) )
    {
        Mouse.Capture(null);
    }
}
```
私に Python を教えてくれた海外の人たち

もちろんこれまで日本語の書籍や開発者コミュニティ―に参加して多くの日本人の先輩に教えて貰いましたが、海外の方々についていつでも思い出せるように記録しておきます。

情報は 2021/06/18 時点のものです。

# Guido van Rossum
Pythonチュートリアル 第3版

https://www.oreilly.co.jp/books/9784873117539/

https://twitter.com/gvanrossum?lang=ja
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/bf499dca-132c-3568-fa1a-d184a13a3556.png)


https://www.youtube.com/watch?v=7kn7NtlV6g0

# Jake VanderPlas
Pythonデータサイエンスハンドブック

https://www.oreilly.co.jp/books/9784873118413/

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/4074269b-87b7-f449-ac78-b6a22b34925a.png)

https://www.youtube.com/watch?v=DifMYH3iuFw

#Matthew A. Russell
入門 ソーシャルデータ 第2版

https://www.oreilly.co.jp/books/9784873116792/

https://www.linkedin.com/in/ptwobrussell/
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/99f76459-e4bb-b47a-191b-dab6635a685e.png)

https://www.youtube.com/watch?v=3EYwWoT-EC8

#Jacqueline Kazil

Pythonではじめるデータラングリング

https://www.oreilly.co.jp/books/9784873117942/

https://www.linkedin.com/in/jackiekazil/
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/418585fb-4b6f-ffc3-e18b-135dc0c918ff.png)

https://www.youtube.com/watch?v=bjjoHji8KUQ

#Katharine Jarmul


Pythonではじめるデータラングリング

https://www.oreilly.co.jp/books/9784873117942/

https://www.linkedin.com/in/katharinejarmul/?originalSubdomain=de

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/0f332d39-8028-d1b0-17a0-adf593e4c68a.png)

https://www.youtube.com/watch?v=B3PtcF-6Dtc

#Cory Althoff
独学プログラマー Python言語の基本から仕事のやり方まで

https://www.nikkeibp.co.jp/atclpubmkt/book/18/C92270/

https://twitter.com/coryalthoff

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/a0c2ad87-076b-6e6c-fa79-fcb1f2ed65e6.png)



https://www.youtube.com/watch?v=1ZWGwc8Xd3Y
2進数 ⇄ 10進数【Ruby】

コーディングテストで出会った、rubyのオブジェクト変換メソッド（？、to_iやto_hなどの事を言いたい）の便利な仕様についてまとめる。

```ruby
# 引数がinteger型の場合 → to_sメソッド
p 255.to_s(2)
# => "11111111"

# 引数がstring型の場合 → to_iメソッド
p "11111111".to_i(2)
# => 255
```

これらのメソッドは2進数以外の、任意の単位への変換も可能。

ex. )16進数の場合

```ruby
p 255.to_s(16)
# => "ff"
```
XcodeでSVGを使うときにハマった話

![Xcode-12.4](https://img.shields.io/badge/Xcode-12.4-brightgreen) ![Swift-5.3](https://img.shields.io/badge/Swift-5.3-brightgreen)

## はじめに
Xcode 12 から SVG が使えるようになりましたね:tada: 
今やってる案件も Android とリソースが共有できるということで SVG を使おう！という話になったのですがなぜか下記のように iOS 側だけ画像が切れてしまうということがありました。

| iOS | Android |
| :---: | :---: |
|<img width="220" alt="ios" src="https://user-images.githubusercontent.com/34936885/122488215-f1885100-d017-11eb-915b-6f86b4d906e8.png">|<img width="240" alt="android" src="https://user-images.githubusercontent.com/34936885/122488199-ed5c3380-d017-11eb-8af6-a17698a76128.png">|

Android ではちゃんと表示されているので Xcode の設定の問題では？と思いわりとハマってしまいました:cry:

## 原因
原因は SVG のこれでした `transform="translate(.5 1)"`。おそらく `translate` で右に 5 下に 1 よってしまっている！

SVG はこんな感じ。

```xml
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="28" height="28" viewBox="0 0 28 28">
  <g fill="none" fill-rule="evenodd" transform="translate(.5 1)">
    <path d="M14,7 L28,14.5 14,22 14,7" fill="#34C759"/>
  </g>
</svg>
```

## SVGの導入
### Xcode
Xcode で SVG を使う場合は下記のようにします。

1. xcassets に Image 追加
1. Resizing の Preserve Vector Data にチェック
1. Scales を Single Scale に設定

<img width="264" alt="xcode" src="https://user-images.githubusercontent.com/34936885/122488832-44aed380-d019-11eb-8a91-776a9c930a0a.png">

### Android Studio
Android Studio で SVG を使う場合は drawable に Vector Asset を追加するだけです。

<img width="719" alt="studio" src="https://user-images.githubusercontent.com/34936885/122488838-4a0c1e00-d019-11eb-967f-1ef49ffb6a44.png">

このとき生成される XML は下記です。

```xml
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="28dp"
    android:height="28dp"
    android:viewportWidth="28"
    android:viewportHeight="28">
  <path
      android:pathData="M14.5,8L28.5,15.5 14.5,23 14.5,8"
      android:fillColor="#34C759"
      android:fillType="evenOdd"/>
</vector>
```

Android で切れずに表示されるのは `transform` 属性が削ぎ落とされているためだと思います:thinking:

## おわりに
はじめての SVG 導入ということもありわりとハマってしまいました:sob: 
そもそも SVG がなんなのかよくわかっておらず何をみればいいのかもわかりませんでした。。。

Xcode 側の設定でどうにかなるよなどあれば教えていただけると幸いです:bow:

## 参考
* [Xcode12／SwiftUIでSVGを使う](https://www.subthread.co.jp/blog/20210218/)
* [AndroidでSVGを画像としてImageViewに表示する(Support Library 26編)](https://qiita.com/wakwak/items/787306c92ef6c0a10a20)
Listの活用

```java
package List;

import java.util.ArrayList;


;
public class List {

	public static void main(String[] args) {
		//listの活用(要素の数）
	ArrayList<String> list = new ArrayList<>();
	
	System.out.println(list.size());  // 0
	list.add("まぐろ");   //0
	list.add("かつお");  //1
    list.add("サーモン");   //2
    
    System.out.println(list.size()); // 3
    
    //listの活用（get)
    System.out.println(list.get(0));  // "まぐろ"
    System.out.println(list.get(2));  // "サーモン"
	
    
    
	}

}
```


コレクションとは？
たくさんの要素をひとつのユニットに集めた単なるオブジェクトだ。入れ物を表すコンテナと呼ばれることもある。

インターフェースとは？
クラスに含まれるメソッドの具体的な処理内容を記述せず、変数とメソッドの型のみを定義したもの
リストとは？

リストとは？
複数データを順番通りに並べ替えて格納するときに利用します。

addとは？
メソッドで追加するもの


listは変数を０～表す箱のようなものを作る。
JavaScriptのDOM操作−読み込みタイミング


JavaScriptのDOM操作でつまづいた箇所があったので、
メモしておきます。


DOM操作をする際、JavaScriptを読み込むタイミングに
注意しなければなりません。


私の場合、最初は次のタイミングで読み込もうとして
エラーになりました。


```
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>test</title>
  <script>
  function setWords(){

    word = words;
    target.textContent = word;

  };

  window.onload = function start(){

    setWords();

  }

  const words = ["red","blue","green",'white'];
  const target = document.getElementById("target");


</script>
</head>

<body>
  <p id="target"></p>


</body>
</html>
```


こう書いてしまうと、
headで先にJavaScriptを読み込んでしまうため、
読み込み時に、DOMが作成されておらず、
エラーになります。


![F2A478E4-EA23-4AC1-86B6-BB644869DC19_4_5005_c.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1290117/c498907e-b373-e3da-0367-d8ece385073a.jpeg)

「Cannot set property ‘textContent’ of null」は、
DOMが構築されておらず、プロパティーが空ですよという
メッセージです。


なので、これを解決するのは、非常にシンプルで、
JavaScriptの読み込みタイミングをDOM構築のあとにすれば
いいというわけです。


```
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>test</title>

</head>
<body>
  <p id="target"></p>

<script>
  function setWords(){

    word = words;
    target.textContent = word;

  };

  window.onload = function start(){

    setWords();

  }

  const words = ["red","blue","green",'white'];
  const target = document.getElementById("target");


</script>
</body>
</html>
```


こうすれば、Javascriptを読み込む前に、DOM要素を作成するため、
DOM操作が可能になります。


また、headにJavaScriptを書くと、
JavaScriptを読み込んでから、bodyを読み込むので、
微妙に読み込み時間が長くなります。


そのため、JavaScriptの読み込みは、
基本的にbodyの閉じタグ直前にするのがいいようです。
RSpecのテスト中にMySQL client is not connected

テストコード記述中にエラーが発生。

```
Failure/Error: _query(sql, @query_options.merge(options))
     
     ActiveRecord::StatementInvalid:
       Mysql2::Error::ConnectionError: Lost connection to MySQL server during query
```

エラーの内容としてはクエリ中にMySQLとの接続が切れた、という内容ですね。
特に今回はAPIを使用したテストコードなので、高速でテストをしすぎているのが原因みたい。

https://qiita.com/shun915a/items/e18f538be6221f929876

https://qiita.com/NedzumiNeko/items/9dea39ee7dd957e7a2ef

ということで、sleepを導入する。

```spec/models/purchase_shipping_spec.rb
RSpec.describe PurchaseShipping, type: :model do
  describe '購入情報の作成' do
    before do
      item = FactoryBot.create(:item)
      user = FactoryBot.create(:user)
      @purchase_shipping = FactoryBot.build(:purchase_shipping, item_id: item.id, user_id: user.id) 
      sleep(1) #追記
    end
```

これでFactorybotで作成した情報ができたら、1秒待機することになり、MySQLも正常に読み込みます。
以前Pythonでスクレイピングするときにも似たようにSleepを入れて意図的に処理を遅らせていましたが、それと似てますね。
FPM（php）


#FPM-phpの挙動（備忘録）

PHPってかFPM
apacheみたいに１リクエスト毎にPHP立ち上げるわけじゃないから

FPMは親プロセスとして１個だけPHPが動いて（動きっぱなし。unixデーモンとして起動する）
リクエスト毎にPHP子プロセスを割り当てる。

だからFPMつかってると落ちてもPHPがリスタートしないっぽい。

豆知識として
FPMの場合はphp.ini書き換えても
FPMのデーモン再起動しないと反映しない
rails server が起動できない

# rails server が起動しない

`rails server`コマンドを実行したところ次のような警告が出て起動することができなくなりました。

```
Address already in use - bind(2) for "127.0.0.1" port 3000 (Errno::EADDRINUSE)
```

127.0.0.1:3000がすでに起動していると言われています。
よくよく考えてみたら「Ctrl + C」で終了せずにターミナルを閉じてしまっていたので、前回起動したserverがそのまま動いていました。

# 解決方法
1.プロセス番号を調べるために下記コマンドを実行。
`lsof`:オープンしているファイルを一覧表示
`-i`:ネットワークソケットを対象にする
`:3000`:今回はポート番号3000番を指定

```
$ lsof -i :3000
```

2.するとこのように一覧表示される

```
COMMAND     PID         USER   FD   TYPE             DEVICE SIZE/OFF NODE NAME
ruby      95177 hogehoge   11u  IPv4 0x9a79e2de85019e93      0t0  TCP localhost:hbci (LISTEN)
ruby      95177 hogehoge   12u  IPv6 0x9a79e2de81c7c90b      0t0  TCP localhost:hbci (LISTEN)
```

3.あとは`kill`コマンドでプロセスを終了すればOK

```
$ kill 95177
```

# 参考サイト

[rails server を停止させたい！](https://zenn.dev/nagan/articles/1599d9216cf858)
Elastic BeanstalkでのAWS WAFの設定方法

Elastic Beanstalkで作成されるApplication Load BalancerにAWS WAFを設定する方法です。

## 設定ファイル
*  .ebextensions ディレクトリで waf.config 作成します。ファイル名は***.configならなんでもOK
*  作成したACLとALBを紐付ける設定をします。ACLのARNはAWS WAFのコンソールから確認できます。

```./ebextensions/waf.config
Resources:
  WebACLAssociation:
    Type: AWS::WAFv2::WebACLAssociation
    Properties:
      ResourceArn: '`{ "Ref" : "AWSEBV2LoadBalancer" }`'
      WebACLArn: {ACLのARN}
```

### ACLのARNの確認方法
ACLの一覧から右上の歯車をクリックすると確認できます。

![100853420-16c5cf80-34cb-11eb-8d27-bcefb4f22698.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260824/f3aee10c-2d41-4b4a-ba79-b6d43846e2b8.png)


## デプロイする
* waf.configを追加した上で環境を作成すると、AWS WAFのコンソールでACLとリソースが紐づけられていることが確認できます。

![100853427-188f9300-34cb-11eb-9a9f-c01560fa6cab.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260824/0d5b3f79-0cbd-410e-6e03-3161242005dd.png)
【2021年6月版】JSのArray.reduceとMapで、Object Arrayを簡単にユニークにする

# JavaScript, TypeScriptで"オブジェクトの配列"を"簡単に"ユニークにしたい。

こちら↓

```js
const arr = [
   { id:"a0", propA: "A0-propA", propB: "A0-propB", ... },
   { id:"a1", propA: "A1-propA", propB: "A1-propB", ... },
   { id:"b0", propA: "B0-propA", propB: "B0-propB", ... },
   { id:"a0", propA: "A0-propA", propB: "A0@propB", ... },
...
];

// シンプルに要素をユニークにする
const uniq_arr_1 = [... arr.reduce((map, a) => map.set(a.id, a), new Map()).values()];
// 要素をユニークにし、変換もする
const uniq_arr_2 = [... arr.reduce((map, a) => map.set(a.id, { id: a.id, value : a.propA, desc: a.propB}), new Map()).values()];

```

## 解説

JSやTSで Object Array を distinct したい。オブジェクトの配列要素を特定のプロパティ、メンバで一意にしたい。。。単にArrayをUniqueにする方法でサクッと調べてみると`Set`を使う方法が出てきますが、`Set`では要素の等価性、同一性の評価がカスタマイズできないので文字列や数値のような"プリミティブ"な要素の配列にしか使えません。。forやforeachで頑張ればできるのですが、できるだけ"簡単に"やりたい、というわけです。

というわけで、`Array.reduce`と`Map`を使って、`Map`のキーに特定のメンバーを指定することで、配列の要素を一意にし、その後 `Map.values()`とスプレッド構文で`Array`に戻しております。
ミソは`Array.reduce`の第2引数で初期値に`new Map()`を渡すこと、そして`Map.set`で要素を追加している箇所、そして`Map.values`です。
`Map.set`は戻り値が`Map`なので、`Map.set`しただけでそのまま暗黙の`return map`が出来ております。
また、`Map.values()`とスプレッド構文で簡単にArrayに戻すことが出来ています。

というわけでなかなか悩ましいObject Arrayを一意にする方法ですが、`Array.reduce`と`Map`を駆使して簡単にできました。
多次元配列について

問題

```ruby
fruits_price = [["apple", [200, 250, 220]], ["orange", [100, 120, 80]], ["melon", [1200, 1500]]]

appleの合計金額は670円です
orangeの合計金額は300円です
melonの合計金額は2700円です
```

こういう出力結果を得たいと思います。

なんかfruits_priceを見ると配列の中に配列がありますね。
これを多次元配列というようです。

試しに

```ruby
puts fruits_price[0]
```
とすると

```ruby
apple
200
250
220
```

配列の中の1番目の配列を取り出してくれる。
ということはその配列の2番目の配列が金額の配列なのではないか、ということで試しに

```ruby
puts fruits_price[0][1]
```

とすると

```ruby
200
250
220
```
となってくれました。

ということで、希望の出力結果を生み出すには
①fruit_priceから順番に配列を取り出す。
②取り出した配列から金額の配列を取り出す。
③その金額を合計する。
という処理の順番になると思うので、

```ruby
fruits_price.each do |fruit| #fruit_priceから順番に配列を取り出す。
  sum = 0 #sumという計算結果を格納する変数を定義
  fruit[1].each do |price| #fruit_priceから取り出した配列がfruit。その2番目をpriceに格納。
    sum += price #sumにpriceを合計する結果を格納
  end
  puts "#{fruit[0]}の合計金額は#{sum}円です"
end
```

という処理になります。
Salesforceでコミュニティサイトの開発環境を作成する

## 概要

Experience Cloud（旧Community Cloud）の本番環境で既に稼働しているコミュニティサイトの開発環境をSandboxで作成する。

## 開発環境の作成

本番環境の**[設定][環境][Sandbox]**の**[新規Sandbox]**からSandboxを作成する。

Sandboxを作っただけだとまだサイトが見れないので、
**[設定] [環境] [すべてのサイト]**の対象のサイトの**[ビルダー]**をクリックして右上の**[公開]**をクリックしてサイトを有効化する。

## コミュニティユーザでのログイン

実際にサイトを使用するCommunityライセンスユーザーで開発する必要がある場合は以下の手順でユーザーを作る。（**[全てのサイト]**のURLから遷移すると自分でログインしてしまう）

※通常の**[ユーザ]**画面から**新規ユーザ**でユーザを作成するとCommunityライセンスユーザを設定することができない。

適当に取引先を作成し、適当に取引先責任者を作成し、取引先責任者の詳細レコード右上の▼メニューから**[カスタマーユーザーを有効化]**する。  
有効化した後にもう一度右上の▼メニューの**[ユーザーとしてエクスペリエンスにログイン]**を選択するとCommunityライセンスユーザーでログインできる。

## コミュニティユーザーでデバッグログを出力する

Visualforceページを開発している場合など、コミュニティユーザでログインしているとApexデバッグログが出ないので
**[環境] [ログ] [デバッグログ]**から**[新規]**で先程作成した取引先責任者を追加してあげる必要がある。

[デバッグログの設定](https://help.salesforce.com/articleView?id=code_add_users_debug_log.htm)
AWS Step Functions Workflow Studioがリリースされたので触ってみた

AWSのマネージドワークフローエンジンであるStep Funstions周りで、おもしろそうなツールが発表されてました。

[New – AWS Step Functions Workflow Studio – A Low-Code Visual Tool for Building State Machines](https://aws.amazon.com/jp/blogs/aws/new-aws-step-functions-workflow-studio-a-low-code-visual-tool-for-building-state-machines/?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed%3A+AmazonWebServicesBlog+%28Amazon+Web+Services+Blog%29)



Step FunctionsのState MachineをGUIで書こうってツールらしいです。
今まで、[draw.io](https://github.com/sakazuki/step-functions-draw.io) にも似たようなプラグインはありましたが、今回はAWS公式のツールなので使い勝手やアップデートに期待が持てるところです。

Step Funstions好きなので、早速触ってみました。


なんとなくそれっぽいワークフロー。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85375/cdbf741f-3048-c7c7-000e-555d07fdbcbf.png)


## よかったところ
### まずフロー構築が簡単

Stateの追加ですが、左欄から配置したいState Typeを選んでState Machine図にドロップするだけです。


<img width="50%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85375/3691ff62-595a-07e7-849c-b06fe5d58b44.png">

ぐりぐりワークフローが組み上がるので、妄想を形にしてる感があって楽しいですね。

### 各種Stateのオプションの登録が簡単

各種Stateの使い方はけっこうDSLだと複雑で、それなりに学習コストがあります。ひたすらドキュメントとの睨めっこが必要ですが、Workflow Studioでは画面に従ってSelectBoxなどから選ぶだけです。
Chice Stateの分岐条件記述もこの通り。
![choice.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85375/35f70a38-525f-31b6-a00d-0535916f7bab.png)

### AWS系リソースとの統合が簡単
AWS系リソースの呼び出しも左欄から選んでドラッグするだけです。

<img width="200px" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85375/c64c6695-70d9-e760-a803-aba9422650ec.png">

各統合サービスの呼び出しパラメータオプションなどの詳細もGUIに詳細に出るため、何ができるのか非常にわかりやすいです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85375/9aae0c6d-f1d0-f896-bc72-f5d5b1130bd2.png)

SQSやAWS Batchへの処理の移譲とコールバックパターンとかも、以上のようにボタン一つで設定できます。
DSLだと本来メンバーにも統合サービスごとにパラメータ特性の説明が必要だったのでありがたいです。

(呼び出しが```<arn>.sync ```なのか ```<arn>.waitForTaskToken ```なのかとか、正直開発知識として必要だったかというとかなり些末なとこだし、なにより公式ドキュメントが見づらかった)



### いざというときのjson修正も簡単
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85375/98b6f432-8580-9b68-0f19-9f52b6b11bb0.png)

Workflow Studioは要するに静的にState Machineの定義jsonを出力するだけのツールなので、相互変換が簡単です。実際に出力するjsonを見れるので、必要なら記法の学習もできるかと思います。

Workflow StudioはこのままState Machineのデプロイもできますが、基本的にはこのjsonをコピペしてリポジトリ管理することになるでしょう。

## まとめ
AWS Step Functions Workflow Studio、非常にいいツールでした。
今後 Step Functions使う時は、自分はまずここからフローを設計していくつもりです。
mglearn をインストールしたときの記録

### 出発地

Pythonではじめる機械学習

https://www.oreilly.co.jp/books/9784873117980/

用いられているライブラリ
mglearn
のインストールを行ったので記録しておきます。
環境によって対処方法が異なると思いますが、私の場合はこうでした。

### 最初の状態
OS: windows 10.0
python: 3.7.3

### 実施日
2021/06/7

### 利用ツール
Anaconda Prompt
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/58a833a5-7ab0-3733-fb75-c5166cf19508.png)


### 実施コマンド
```
pip install mglearn
```

### 到着地
python: 3.7.3
mglearn: 0.1.9

```
conda list
# packages in environment at C:\ProgramData\Anaconda3:
#
# Name                    Version                   Build  Channel
（中略）
mglearn                   0.1.9                    pypi_0    pypi
（後略）
```
Rubyで文字列を置換する方法

Rubyで文字列を置換する方法です。
今回はpaiza様の問題集に掲載されているプログラムを題材にしています。

「, maybe」を「!!」に文字を置換する方法です。
subメソッドを使って
sum("置換対象の文字列","置換後の文字列")
で表します。今回の場合は

```ruby
sub(", maybe.","!!")
```

になります。全体のプログラムは下記の通りになります。

```ruby
#作成日  2021/06/18
#作成者　乃木坂好きのITエンジニア
puts "何か文字列を「maybe」を使って」入力してください"
input_line = gets
puts input_line.sub(", maybe.","!!")
```

になります。
LetsEncrypt サーバ証明書を自動更新する

# これはなに

サーバ証明書を自動更新するようにした際のメモ。

# 1. certbot-auto 版
## 1-1. 更新バッチ

`/root/certbot/` に `certbot-auto` が置いてある前提。

``` /root/certbot/renew.sh
#!/bin/bash
/root/certbot/certbot-auto renew --post-hook "systemctl restart nginx"
mail -s "`hostname` executed certbot-auto renew, status: $?" <to-mail_address> < /dev/null
```

## 1-2. crontab

毎週月曜 5:01 に実行。

```.sh
1 5 * * 1 /root/certbot/renew.sh >/dev/null 2>&1
```

# 2. certbot 版
## 2-1. 更新バッチ

``` /root/letsencrypt/renew.sh
#!/bin/bash
certbot renew --post-hook "systemctl restart nginx"
mail -s "`hostname` executed certbot renew, status: $?" <to-mail_address> < /dev/null
```

## 2-2. crontab

```.sh
1 5 * * 1 /root/letsencrypt/renew.sh >/dev/null 2>&1
```
VSCode拡張機能のESLintで.eslintignoreが機能しないときの対処法

## 概要

表題のとおりですが、VSCodeで開発中にESLintの`.eslintignore`に除外したいものを記載しているのに、VSCode上では無視されないという状況にハマったので原因調べました。誰かが同じように嵌った時に役に立てたら幸いです。

## 状況

* `.eslintignore`に除外したいファイル・ディレクトリを記載している
* コマンドで`npx eslint`を実行すると`.eslintignore`の内容の通り適切に除外される
* VSCodeの拡張機能のESlintでは`.eslintignore`の内容が反映されずエラーがあればエラーになる

拡張機能はこれ

https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint

## 嵌った時のディレクトリ構成

以下のようにrootディレクトリにfrontとbackをそれぞれ用意し、Docker関連のファイルを置く構成です。
frontディレクトリにcreate-react-appで作成したReactアプリが入っています。（ESLint関連の設定ファイルも）

```
root/
  ├ back/
  ├ front/
  │　├...
  │　├.eslintrc.js
  │　└.eslintignore
  ├ .dockerignore
  ├ Dockerfile
  ├ docker-compose.yml
```

## なぜ機能しないのか

`.eslintignore`をおいている場所をVSCodeの作業ディレクトリにしないと機能しないらしいです。
`rootディレクトリ`を作業ディレクトリとしてVSCodeを開いても、適切にESlint（拡張機能）の設定が反映されないようです。

以下のようにfrontディレクトリ内でESlintのエラーが発生します。

![q1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/619552/db4bb57a-c67a-582d-00ab-77c462328290.png)

## 対処法

`frontディレクトリ`を作業ディレクトリとしてVSCodeを開きましょう。
`.eslintignore`の内容がが適切に反映されるはずです。

以下のようにESlintのエラーが発生しなくなります。

![q2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/619552/ffc6aa75-78ca-c15d-7312-a33b61f073ae.png)

## 参考

https://github.com/microsoft/vscode-eslint/issues/699
Pumaサーバーを導入して、RailsアプリをHerokuへデプロイする。

RailsアプリをHerokuにデプロイしている過程で、こんな警告を見つけた。

```
remote: ###### WARNING:
remote:
remote:        No Procfile detected, using the default web server.
remote:        We recommend explicitly declaring how to boot your server process via a Procfile.
remote:        https://devcenter.heroku.com/articles/ruby-default-web-server
```
翻訳してみると、
<font color="Red">
Procfileが見つからないから、デフォルトのwebサーバーを使ったよ。Procfileを介してサーバープロセスを起動する方法を明示的に宣言することを勧めるよ。
</font color>
サーバー周りの問題であることは明らかだが、やはりよくわからないので、記載してあるURLへ行ってみることに。

#原因
デプロイの段階で使用しているWEBrickというサーバーが、本番環境での実行には適していないというものだった。

#WEBrickとは
Railsに付属しているデフォルトのWEBサーバーのことで、RailsやRackのようなフレームワークの開発用に設計されている。

WEBrickは、あくまで開発目的での使用を想定しているため、本番環境で使用するとリクエストに時間を要するなど、充分なパフォーマンスを発揮できないらしい。

#Pumaの導入
Herokuが推奨する、本番環境用のwebサーバー「puma」を導入することにした。

まず、Gemfileにpumaのgemを追加する。
※基本的にrailsアプリ作成の段階でgem自体は入っているらしい。

```
# Gemfile

gem 'puma'
```

次に、config/puma.rbにサーバーの設定を書き込む。
(なんてこと言ってますが、コピペしてちょこっといじった程度です。。）

```
#config/puma.rb

workers Integer(ENV['WEB_CONCURRENCY'] || 2)
threads_count = Integer(ENV['RAILS_MAX_THREADS'] || 5)
threads threads_count, threads_count

preload_app!

rackup      DefaultRackup
port        ENV['PORT']     || 3000
environment ENV['RACK_ENV'] || 'development'

on_worker_boot do
  # Worker specific setup for Rails 4.1+
  # See: https://devcenter.heroku.com/articles/deploying-rails-applications-with-the-puma-web-server#on-worker-boot
  ActiveRecord::Base.establish_connection
end
```
次に、Procfileに設定を書き込む。私の場合、Procfileが無かったため作成しました。

※ここでひとつ注意！！
<font color="Red">Procfileは、アプリケーションの「ルートディレクトリ」に作成すること。</font color>
私は見事にここで事故りました...。

↓Procfileの設定

```
# Procfile

web: bundle exec puma -C config/puma.rb
```
これでpumaの導入&設定が完了!!

再度Herokuへプッシュ。

冒頭の警告文が消え、無事PumaサーバーでRailsアプリを動かせました!

#参考
・https://takagi.blog/changing-the-application-server-for-a-Rails-app-running-on-heroku-to-puma/
・https://devcenter.heroku.com/ja/articles/ruby-default-web-server
・https://devcenter.heroku.com/ja/articles/deploying-rails-applications-with-the-puma-web-server
・https://creepfablic.site/2019/06/15/heroku-procfile-matome/
Spring21 Experience Cloud ユーザ、パートナー、顧客のメールアドレス変更時に確認が必要 (更新、延期)　オンチェックボックスの位置

Experience Cloud ユーザ、パートナー、顧客のメールアドレス変更時に確認が必要 (更新、延期)についてチェックボックスの位置として

>>設定
⇒ID 検証
⇒メールアドレスの変更に対してメール確認が必要 (エクスペリエンスビルダーサイトのユーザに適用)
Docker DesktopでCompose V2を無効にする

## 背景

Docker Desktopを3.4.0にバージョンアップ後、コンテナ間で通信ができなくなったので調査。

docker network で独自のnetworkを作成し、

```
docker network create \
  --driver=bridge \
  --subnet=10.100.0.0/12 \
  --gateway=10.100.0.1 \
hogenetwork
```

docker-compose.ymlには以下のように記述して固定IPを付与している。

```
services:
  app:
    image: hogeimage:latest
    hostname: hoge
    networks:
      hogenetwork:
        ipv4_address: 10.100.6.11
```

普段はこれで10.100.6.11のIPアドレスでコンテナが動くのだが、なぜか
コンテナのIPが10.96.0.1になっていた。

```
$ docker exec -it hoge bash
bash-4.2# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
2: tunl0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN group default qlen 1000
    link/ipip 0.0.0.0 brd 0.0.0.0
3: ip6tnl0@NONE: <NOARP> mtu 1452 qdisc noop state DOWN group default qlen 1000
    link/tunnel6 :: brd ::
54: eth0@if55: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    link/ether 02:42:0a:60:00:01 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 10.96.0.1/12 brd 10.111.255.255 scope global eth0
       valid_lft forever preferred_lft forever
bash-4.2#
```

## 原因

Docker Desktop 3.4.0がリリースされ、Compose V2 betaが使えるようになった。

https://docs.docker.com/docker-for-mac/release-notes/#docker-desktop-340

https://matsuand.github.io/docs.docker.jp.onthefly/compose/compose-file/compose-file-v2/#networks

```
$ docker-compose --version
Docker Compose version 2.0.0-beta.3
```

ところが、Compose V2 で起動すると、defaultのネットワークが勝手に作成され、そのネットワークのIPが割り当てられてしまう様子。

```
$ docker-compose up -d
...
Network hoge_default  Creating
Network hoge_default  Created
...
```

## 対応


Compose V2の書式に対応すれば治りそうだが、まだbeta版なので今は対応しないことにした。

V2を無効にするコマンドがあったので、それで対応。

https://docs.docker.com/compose/cli-command/

```
$ docker-compose disable-v2
```

## 参考

https://matsuand.github.io/docs.docker.jp.onthefly/compose/compose-file/compose-versioning/#version-2

https://matsuand.github.io/docs.docker.jp.onthefly/compose/compose-file/
phpの自然順ソートは接頭辞があると0埋めを処理できない

#前提

PHP Version => 8.0.1

phpはnatsort関数で配列を自然順にソートすることができる。

[リファレンス](https://www.php.net/manual/ja/function.natsort.php)

##数字のみの場合✅

0埋めがされている場合は先頭の0埋めを考慮した(0を取り除いた)ソートになる。

```php
$zeros = array('09', '8', '10', '009', '011', '0'); 
natsort($zeros);
print_r($zeros);
```

```
Array
(
    [5] => 0
    [1] => 8
    [0] => 09
    [3] => 009
    [2] => 10
    [4] => 011
)
```

##接頭辞が含まれる場合❎

数字の前に文字列が含まれている場合は、0埋めを考慮した(0を取り除いた)ソートにならない。

```php
$zeros = array('IMG_09', 'IMG_8', 'IMG_10', 'IMG_009', 'IMG_011', 'IMG_0'); 
natsort($zeros);
print_r($zeros);
```

```
Array
(
    [5] => IMG_0
    [3] => IMG_009
    [4] => IMG_011
    [0] => IMG_09
    [1] => IMG_8
    [2] => IMG_10
)
```

##補足：接尾辞が含まれる場合✅

ちなみに接尾辞がある場合は数字のみと同じく0埋めを考慮した(0を取り除いた)ソートになる。

```php
$zeros = array('09.jpg', '8.jpg', '10.jpg', '009.jpg', '011.jpg', '0.jpg'); 
natsort($zeros);
print_r($zeros);
```

```
Array
(
    [5] => 0.jpg
    [1] => 8.jpg
    [0] => 09.jpg
    [3] => 009.jpg
    [2] => 10.jpg
    [4] => 011.jpg
)
```

##最後に

自作で関数を作成する以外に解決方法をご存知の方がいたらコメントください。
【Google Cloud Day'21】「Google Cloud エンタープライズ ユーザー会の魅力を大公開」を視聴して

https://cloudonair.withgoogle.com/events/google-cloud-day-digital-21/watch?talk=d2-jag-01
"概要：昨年 10 月に Google Cloud のユーザーとパートナーを結ぶ Google Cloud エンタープライズ ユーザー会 (通称 Jagu’e’r) を設立しました。既にいくつかの分科会で活動が始まっており、どのような活動を行っているかご紹介します。
6/2 (火) 17:00-18:00 にユーザ会に参加してみたい方向けの IT リーダーズ座談会も企画しておりますので是非そちらも合わせてご参加ください。

 IT リーダーズ座談会 参加登録はこちら
https://cloudonair.withgoogle.com/events/jaguer-special-event0602"

<table>
	<tr>
		<th>切り口</th>
		<th>内容</th>
	</tr>
	<tr>
		<th>ユーザー会について</th>
		<td>通称 Jagu’e’r。会長は株式会社 LIXIL 岩﨑 磨。HP　https://jaguer.jp/</td>
	</tr>
	<tr>
		<th>発足の背景</th>
		<td></td>
	</tr>
	<tr>
		<th>発起人・体制</th>
		<td>元々エンタープライズ企業にいたGoogle社員。コミュニティアンバサダーは参加企業のインタビューなど盛り上げる役割を担っている。</td>
	</tr>
	<tr>
		<th>活動内容</th>
		<td></td>
	</tr>
	<tr>
		<th>会のメリット</th>
		<td></td>
	</tr>
</table>

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556084/a41df16e-fb08-4d6f-d1f8-7592f6878fd6.png)
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556084/d473fb14-60f3-c0ee-7c1f-49c3d0152a22.png)
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556084/60c240b4-4574-af0e-0df0-9652935709e5.png)
![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556084/8b73df95-a644-c9aa-483b-c6ffd97f7050.png)
![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556084/f2dc43e9-b455-4dae-7ac2-360b99af6e3a.png)
GitHubでCommit者のリンクが張られない。または違うアカウントのリンクが張られる

# 症状
GitHubのコミットはアカウントと通常リンクが張られるが、SourceTreeを用いてcommit&pushしたときにgithub上でコミットがリンクが張られない問題
# 原因
[ここ](https://docs.github.com/ja/github/committing-changes-to-your-project/troubleshooting-commits/why-are-my-commits-linked-to-the-wrong-user)に書かれている通り、GitHubはGitHhubのアカウントのEmailアドレスとpush時のローカルのGitのEmailアドレスの照合を行って紐づけを行っている。
そのため、ローカルのGitの設定されたEmailアドレスとGitHub側のアカウントのEmailアドレスで照合が取れないときにリンクが張られない。
また、ローカルのGitの設定されたEmailアドレスが古いアカウントのままの場合、古いアカウントのアドレスのGitHubアカウントのリンクが張られる
# 解決策
ローカルのGitの設定を見直して、GitHubで設定されているEmailアドレスと揃える
インタープリタを作る その20

#概要

インタープリタを作ってみた。
avrインタープリター書いてみた。
インターフェースを変更する。

#インターフェース変更案

out命令を利用して、レジスタの値をテキストエリアに表示する。
out(0, 16)で、レジスタ16の値を数値表示する。
out(1, 16)で、レジスタ16の値を文字コードとして表示する。

#サンプルコード

```
	out: function(A, _Rr) {
		var Rr = this.dataspace[_Rr];
		var ev;
		if (A == 0)
		{
		  ev = kan(Rr);
		}
		else
		{
			ev = kan2(Rr);
		}
		out.value += ev;
		this.PC++;
	},


```

#成果物

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

以上。
【Google Cloud Day'21】「NTTドコモの Google Cloud 活用事例：Apigee を使ったサービス基盤の構築とマイマガジンサービスの開発」を視聴して

"概要：NTTドコモにおけるサービス開発の高速化を目指し、バックエンドの基盤システムが個別に提供している API を集約する中間基盤「RAFTEL」を実現すべく Apigee を採用しました。その理由や活用方法を紹介します。
また、RAFTEL を利用したサービス開発の事例であるマイマガジンでは、ニュースメディアとしての速報性の向上とパーソナライズ強化を実現すべく Google Cloud を全面的に採用して新たなシステムを構築しました。GCP の採用理由やその効果を紹介します。
https://cloudonair.withgoogle.com/events/google-cloud-day-digital-21/watch?talk=d1-appdev-07


<table>
	<tr>
		<th>切り口</th>
		<th>内容</th>
	</tr>
	<tr>
		<th>講演の内容</th>
		<td></td>
	</tr>
	<tr>
		<th>会社概要</th>
		<td></td>
	</tr>
	<tr>
		<th>チームについて</th>
		<td></td>
	</tr>
	<tr>
		<th>RAFTELについて</th>
		<td></td>
	</tr>
	<tr>
		<th>RAFTEのの導入効果</th>
		<td>ManagementAPIも便利</td>
	</tr>
	<tr>
		<th>マイマガジンについて</th>
		<td></td>
	</tr>
	<tr>
		<th>マイマガジンの課題</th>
		<td>data ware houseの導入が必要になった</td>
	</tr>
	<tr>
		<th>BQの採用</th>
		<td>他の課題もAthosなどを利用して解決していくことになった</td>
	</tr>
	<tr>
		<th>システム構成</th>
		<td></td>
	</tr>
	<tr>
		<th>よかったところ</th>
		<td></td>
	</tr>
</table>

![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556084/805826c7-6344-9701-f06b-75ee9fc3585b.png)
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556084/913442c6-26dc-eaf1-b0ae-dc4b4816bd3f.png)
![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556084/0c9daf2c-b3c4-89d6-cef6-1379f111647e.png)
![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556084/d4d9272c-f676-784b-fbe0-36419bb11ab8.png)
![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556084/914c291e-35b6-0647-e291-cd0d1f47c3f8.png)
![7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556084/c390919c-7953-45ac-3598-98060fb2e0e3.png)
![8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556084/f7e8cbc2-791c-033c-b30d-8e00d95afde0.png)
![9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556084/6e7aa521-413a-85da-8b65-d0576eac70d5.png)
![10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556084/d7bbec1b-464b-dca6-2c30-a7ff794903f6.png)
![11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556084/270bdf38-41c4-df7e-5c5f-56d1001b1e28.png)
![12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556084/a2e1dbf8-a491-3204-6d56-bc188bb72ce6.png)
![13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556084/36f8d4ca-fa0c-1217-903a-27b64a1a133c.png)