OmniAICreator/Qiita-1.07M huggingface dataset:
Professional Cloud DevOps Engineer 合格体験記

GoogleCloudのDevOps認定を取得したので試験までに学習した内容や試験後に振り返って学習が足りなかったところを記事にさせていただきます。

### 1.バックグラウンド
- 業務ではGoogleCloudはじめクラウドほぼ未経験。
- DevOpsというほどではありませんが、CI/CDなどプロセス自動化を過去に業務にて担当.
- GCPの認定はACE,PCA,PDE,PCDを保持。
- GCP、コンテナが好き。

### 2.事前対策内容
 - [認定公式サイトを確認＆模擬を受験](https://cloud.google.com/certification/cloud-devops-engineer?hl=ja)
 - Qwicklabsで関連しそうなコースを実施。 ※記事の最後に記載
 - [SRE](https://sre.google/sre-book/table-of-contents/)のドキュメントを一通り読む。
 - [O'RellyのSREワークブック](https://www.oreilly.co.jp/books/9784873119137/)をそこそこ読む。
 - Spinnaker,Cloudbuild,GCRを利用したGKEへのデプロイプロセスの構築。

### 3.試験内容
 - 問題の傾向としてSREに関する問題が多かった気がします。SLOのモニタリング、SLOと新機能リリース頻度をバランシングするための振る舞いやエラーバジェットに基づいた判断、インシデント発生時の振る舞いと事後分析で何を振り返り誰に伝えるべきかというようなことを理解していないと回答が難しい問題でした。AWSとAzureのDevOps認定も持っていますが、これらは各社のサービスを使っていかに開発、運用作業を自動化するかということが問われましたが本試験だけ問題の雰囲気が異なっている印象を受けました。
 - 上記以外ではGKEやモニタリングに関する問題が多かったです。GCPのサービスを利用してSLOやエラーのモニタリングをどのようにやるべきか、仮に分担した場合に必要な権限はどれかということを理解していないと回答が難しい問題でした。
 - これら以外ではビルドやデプロイ時のセキュリティを効率的に確保する方法を問われる問題がありました。

### 4.試験を振り返ってみて
 - SREに関するインシデント発生時の振る舞いや事後分析においてやるべき内容に関する問題は自信がないものが多く学習が足りなかったと感じました。問題の割合も多かったのでもっとSREのドキュメントを読み込むべきでした。SREのドキュメントの読み込みは必須だと思います。
 - GCE,GKE上のアプリケーションをモニタリングするための方法やこれらを実行するための権限に関する問題の粒度が他の問題と比較して細かく回答内容に自信が持てず学習が足りなかったと感じました。モニタリングに関するラボや自身での構築をもっとやっておくべきでした。
 - 模擬でSpinnakerに関する問題がでたので色々と触ってみましたが、試験対策としては微妙でした。
 - これまでに取得していた他のGoogleCloudの認定と比較して最も難しかった気がします。記事記載時点では受験可能な言語は英語だけですが、私が英語得意でないというのもあると思います。

※ 事前に実施したQwicklabsは以下です。完了している中でも関連しているコースのみ記載しています。

| ラボ | Link |
| :--- | :--- |
| DevOps Essentials | https://www.qwiklabs.com/quests/96?catalog_rank=%7B%22rank%22%3A1%2C%22num_filters%22%3A0%2C%22has_search%22%3Atrue%7D&search_id=10665968 |
| Kubernetes in Google Cloud | https://www.qwiklabs.com/quests/29?catalog_rank=%7B%22rank%22%3A1%2C%22num_filters%22%3A0%2C%22has_search%22%3Atrue%7D&search_id=10666026 |
| Cloud Architecture | https://www.qwiklabs.com/quests/24?catalog_rank=%7B%22rank%22%3A1%2C%22num_filters%22%3A0%2C%22has_search%22%3Atrue%7D&search_id=10666042 |
| Google Cloud's Operations Suite on GKE | https://www.qwiklabs.com/quests/133?catalog_rank=%7B%22rank%22%3A1%2C%22num_filters%22%3A0%2C%22has_search%22%3Atrue%7D&search_id=10667212 |

### 5. 合格後の特典
GoogleCloudのProfessinalレベルの認定に合格するとリュックやパーカーなどの特典がもらえます。
本認定ではノート&タンブラー、パタゴニアのベストのいずれかがもらえるようでした。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/727512/d8b78b69-dfca-f7a5-78c8-a1e53ddc00b4.jpeg" width="300"><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/727512/48bf1558-f457-1d6a-a939-8f9faae52f68.jpeg" width="350">


以上、合格体験記でした。
２種類のparameter

 パラメータ
=

コントローラのアクションでは、ユーザーから送信されたデータやその他のパラメータにアクセスして何か作業を行なうのが普通です。Railsに限らず、一般にWebアプリケーションでは2種類のパラメータを扱うことができます。

|「クエリ文字列パラメータ」|URLの一部として送信されるパラメータで、クエリ文字列は、常にURLの"?"の後に置かれます。|
|:--|:--|
|「POSTデータ」|POSTデータは通常、ユーザーが記入したHTMLフォームから受け取ります。これがPOSTデータと呼ばれているのは、HTTP POSTリクエストの一部として送信されるからです。|

###どちらもコントローラ内ではparamsという名前のハッシュでアクセスできます。
VCのまとめ

def~~~endの間にかけるアクションは１つだけ

|index|@model複数形=モデル名.all|@model複数形.each do Iモデル単数形Iで１個づつ取り出す|GET|
|:--|:--|:--|:--|
|newアクション|フォームを表示(new.html.erb)|フォームからデータ送信|GET|
|createアクション|フォーム内に保存データ入力(form_for/form_with @モデルインスタンス変数）|データ保存|POST|
|editアクション|edit（new）のフォームを表示(new.html.erb)|フォームからデータ送信|GET|
|updateアクション|newフォーム内に保存データ入力(form_for/form_with @モデルインスタンス変数）|データ保存|PATCH|
|destroyアクション|editフォーム内に削除ボタン(@モデルインスタンス変数）|データ保存|delete|

|メソッド|役割|
|:--|:--|
|GET|サーバーからブラウザに情報を返す。単にウェブサイトを閲覧する際など、情報を取得するために利用される。
|POST|ブラウザからサーバーに情報を送信し、サーバーに情報を保存する。情報を登録する際など、サーバーに情報を送信するために利用される。
|DELETE|ブラウザからサーバーに情報を送信し、サーバーの情報を削除する。アカウントを削除する際など、サーバー内のデータを削除するために利用される。
|PATCH|ブラウザからサーバーに情報を送信し、サーバー内の情報を置き換える。登録情報を更新する際など、サーバー内のデータを更新するために利用される。

>railsガイド
>https://railsguides.jp/action_controller_overview.html

newメソッドの内容が空であるにもかかわらず正常に動作するという点です。これは、Railsではnewアクションで特に指定のない場合にはnew.html.erbビューをレンダリングするようになっているからです。コントローラが使用できるビューのパスからアクション名.html.erbというビューテンプレートを探し、それを使用して自動的に出力する」というものです。
WordPressのメインループ

#メインループ
WordPressではパラメーターからのリクエストに応じてデータベースの検索が行われて、該当する投稿データが返される。この時、データベースを検索する条件を「メインクエリ」といい、返ってきた投稿データをページに出力するための処理を「メインループ」と呼びます。

##メインループの制御方法：アクションフック：pre_get_posts
pre_get_postsは、メインクエリを解析後、データベースから投稿データを検索する前に実行されるアクションフックです。 WordPressの規定の処理中のイベントに任意の処理を追加する仕組みであり、追加する処理の内容はfunctions.phpに記述します。

```php
function custom_loop_rules ( $query ) {
    // 管理画面や、メインクエリ以外の処理に影響を及ぼさないように。pre_get_postsの設定は管理画面上の処理やメインクエリ以外の処理にも影響するので、特段の事情がない限りは、以下のように操作対象から除外しておきます。
    if ( is_admin() || ! $query->is_main_query() ){
        return;
    }
//フロントページの投稿数は、3にする。
if ( is_front_page() ) {
    $query->set( 'posts_per_page', 3 );
	  }
// カスタム投稿タイプ「movie」のみの場合
if(is_post_type_archive( 'movie' )){
$query->set('posts_per_page',12);
$query->set('order','DESC')
//配列は使えない。
}
}
add_action('pre_get_posts','custom_loop_rules');
```
上記のif分のところに、追加をしていく。 条件分岐は [WordPressCodex](https://wpdocs.osdn.jp/%E6%9D%A1%E4%BB%B6%E5%88%86%E5%B2%90%E3%82%BF%E3%82%B0) を確認する。

##pre _get_postsの使い方
https://qiita.com/_ruka_/items/e14280d34eddf49efad1
flutter webでfirestoreの画像が表示できない件

#出てきたエラー

```
======== Exception caught by image resource service ================================================
The following ImageCodecException was thrown resolving an image codec:
Failed to load network image.
Image URL: https://firebasestorage.googleapis.....(略)
Trying to load an image from another domain? Find answers at:
https://flutter.dev/docs/development/platform-integration/web-images
```


#解決策
以下で走らせる

```
flutter run -d chrome --web-renderer html
```

##参考サイト
https://stackoverflow.com/questions/65653801/flutter-web-cant-load-network-image-from-another-domain
Macで画面を分割して作業したいとき

Macを使用していて、画面を分割して作業したいときありますよね。
例えば、左半分にはChromeを。右半分にはVScodeをみたいなとき。
そんなときにどう画面を分割するか。

## 簡単に分割する方法
![スクリーンショット 2021-04-30 0.19.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/628093/99a77a44-f624-d615-14ca-d0dac37aa63c.png)
画面左上の緑の部分を長押しする。
そうすると、``ウインドウを画面左側にタイル表示``というのが出るのでこれをクリックする。
これで画面が分割できる。

![スクリーンショット 2021-04-30 0.22.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/628093/e99e53f1-edca-1fa6-23d6-b4cdda141a10.png)
こんな感じ
【Unity】軽量ブルームエフェクト作ってみた

# 概要
本記事はモバイル向けな高速なブルームエフェクトを自作してみた記事になります。

# 環境
- Unity2019.4.13f1
- BuiltIn RenderPipeline

を使用しております。

# 自作ブルーム
今回作成したポストプロセスのブルームエフェクト。
![MyPostProcessCandyRockStar.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148284/b2ccc986-5042-72e7-d135-00cf6da24f1d.gif)

# 工夫点

## 白飛び防止
ブルームをかけると強度によっては画面が白っぽくなりますが、
シェーダー側で色空間を調整することで白飛び防止できます。

```
ガンマからリニアへ
#if UNITY_COLORSPACE_GAMMA
    col.rgb = GammaToLinearSpace(col.rgb);
#endif

リニアからガンマへ
#if UNITY_COLORSPACE_GAMMA
    col.rgb = LinearToGamma(col.rgb);
#endif

```

## なるべくドローコールを落とす。
アップサンプルの過程を省略してしまいました。これによってドローコールがダウンサンプルの回数分減らせます。
![FrameDebugger.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148284/fe4f0bab-43ff-5508-d4af-f513e18413cb.gif)

# 処理負荷比較
５年くらい前のAndroid galaxy端末での処理負荷の比較です。
![2021-04-29_23h47_13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148284/73f4ed9e-ac20-21e1-eff8-d40995a59ade.png)
平均10MSほど早くなっています。
それでいて見た目も本家と引けをとらないです!

# プロジェクトデータ
[Github](https://github.com/t-macnaga/PostProcessing)にサンプルをアップしました。


# まとめ
白飛びしにくく、ドローコールも抑えめなブルームエフェクトを自作してみました。

# ライセンス表記
本記事ではUnityChanのCandyRockStarを使用させていただいております。
© Unity Technologies Japan/UCL
AWS CDK で他人が作った環境を自分の環境のスタックにデプロイする

## はじめに
* もはやCFn(CloudFormation)に環境設定を直書きしてる方は絶滅危惧種のようです...（知りませんでした）
* CFnのような面倒な記述なく、Pythonなどでゴリゴリ書けるCDKがトレンドみたいです。
* CI/CDで自動デプロイできるかの検証はまだできてないです（ｺﾞﾒﾝﾅｻｲ）
* 【注意】あくまで他人が作ったAWS環境を自分のAWS環境に移行するための手順です。
* 【注意】あらかじめ他人のAWS環境のCDK構築ファイル群をもらっておく必要があります。
* Macユーザー向けです。
* AWSを熟知している方、普段からCLIを触っている方、CloudFormationを書いたことある方向けです。
* 環境に合わせた任意の変数は`{}`で表現しています。

## 動作確認済みの環境
|         |バージョン                |
| ------- | ---------------------- |
| OS      | MacOS Catalina 10.15.6 |
| Python  | 3.9.1                  |
| pip     | 20.1.1                 |
| Node.js | 12.16.1                |
| npm     | 6.14.8                 |
| aws-cdk | 1.16.0                 |
| aws-cli | 2.0.44                 |


## 事前準備

* Homebrewをインストール　👉https://brew.sh/index_ja

* pyenvをインストール

    ```q
  $ brew install pyenv
    ```

* PATHを通す

    ```q
  $ vim ~/.bash_profile
  //bashではなくzshを使っている場合は~/.zprofile
  // 下記の3行を追記する
  export PYENV_ROOT="$HOME/.pyenv"
  export PATH="$PYENV_ROOT/bin:$PATH"
  eval "$(pyenv init -)"
  // 3行追記して保存(:wq)したら下記コマンドで変更内容を反映する
  $ source ~/.bash_profile
    ```

* python 3.8.5 をインストール

    ```d
  $ pyenv install 3.8.5
  $ pyenv global 3.8.5
  $ python3 -V  //3.8.5であることを確認
    ```

* aws-cliをインストール 👉https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/install-cliv2.html

* aws-cliとAWSアカウントを紐付ける

    ```q
  $ aws configure
  AWS Access Key ID : {自分のアカウントのアクセスキー}
  AWS Secret Access Key : {自分のアカウントのシークレットキー}
  Default region name : ap-northeast-1
  Default output format : json
    ```

## CDKによるリソースデプロイ
* CDKの準備を行う

```q
$ mkdir {hoge}
$ cd {hoge}   //.envがある環境
// 他人が作った環境のCDK資源をhogeフォルダにコピペする
$ python3 -m venv .env //初回のみ実行
$ source .env/bin/activate //仮想環境を展開
// 仮想環境から出たい場合は、`$ deactivate`
// 仮想環境に入ると、$マークの前に(.env)が表示されます。
(.env)$ pip install -r requirements.txt //（初回実行のみ）ライブラリをインストール
// 下記のWARNINGは無視してOK。
// WARNING: You are using pip version xx.x.x; however, version xx.x is available.
(.env)$ cdk ls
```

* 対象環境にCDK Appを作成する

```q
(.env)$ cdk synth //CFnフォーマットに変換されてテンプレートが出力される
(.env)$ cdk diff //diffチェックをする
```
* 対象環境にCDKでリソースをデプロイする

```q
(.env)$ cdk deploy
// deployコマンドを流すと、実行するかどうか聞かれるのでyを入力する。
// failed creationエラーが出た場合はwebコンソールから対象スタックを一度削除して再度デプロイする。
```
* デプロイ完了！！

```q
Stack ARN: arn:aws:cloudformation:ap-northeast-1:{アカウント番号}:stack/{スタック名}/{スタックID}
//上記が出力されればデプロイ完了！
//CLIで全てデプロイできたら、webマネジメントコンソールからスタックが出来上がっていることを確認できます。
```

## おわりに
* CFnの面倒な作業から解放されるCDKなるものがあるとは知りませんでした。
* IaCがこんなに簡単に実現できるとは、さすがAWSです👏
Android Studio 4.2 / Arctic Fox 2020 3.1 に更新したら起動しなくなったときの対処法

# はじめに

Android Studioを更新したら、起動しなくなった。
何回も調べて修正をしているのでメモ書きしておく

4.2にアップした時も起動しませんでしたが、Arctic Foxにアップデートしても起動しなくなりました；；
根本的な対応がないのかな？

# TL;DR

Android Studioのインストール先にある`studio64.exe.vmoptions`を以下のように修正する

```studio64.exe.vmoptions
-Xms256m
-Xmx1280m
-Xverify:none <= これを追加
-XX:ReservedCodeCacheSize=240m
-XX:+UseG1GC
-XX:SoftRefLRUPolicyMSPerMB=50
-XX:CICompilerCount=2
-Dsun.io.useCanonPrefixCache=false
-Djdk.http.auth.tunneling.disabledSchemes=""
-Djdk.attach.allowAttachSelf=true
-Dkotlinx.coroutines.debug=off
-Djdk.module.illegalAccess.silent=true
-Djna.nosys=true
-Djna.boot.library.path=
-Didea.vendor.name=Google

```

# ファイルはどこに？

## Windows10で通常にインストールした場合

下記になる。

`C:\Program Files\Android\Android Studio\bin\studio64.exe.vmoptions`

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/133291/77148d6c-c2c2-010b-9fdd-337406550059.png)
Formオブジェクト

Formオブジェクト

1つのフォーム送信で複数のモデルを操作したい場合や、テーブルに保存しない情報にバリデーションを設定したい場合に使います。
モデルに近しい機能を持ったクラスを新たに作成し、そのクラスに複数のテーブルへ保存させる処理やバリデーションを記述する、という方法です。
newアクションで生成したインスタンスをform_withのmodelオプションに指定することや、インスタンスに対してバリデーションを実行することができます。

今回、購入機能を実装するにあたり、複数のモデルのインスタンスをまとめる為
実装しました。中身に関しては編集中で今後追記していく予定です。

```〇〇.html.erb
’’’class "クラス名"
  include ActiveModel::Model

end’’’
gem 'simple_calendar', '~> 2.0'

# Railsでカレンダーを導入するgem

````
gem 'simple_calendar', '~> 2.0'
````

上記gemをgemfileの1番下に記述し、bundleinstallを行います。

# simple_calendar
簡単にカレンダー機能を付け加えれるgemです。
月間カレンダー、週間カレンダーなど日付指定をしてカレンダーを作成することができます。
AWS App Runner がすごそう。 Fargate や Heroku の代替になりそう

ついに AWS から Heroku っぽいサービスが登場した模様。その名も "App Runner" 。

既に東京リージョンでも使えるっぽい。

https://aws.amazon.com/about-aws/whats-new/2021/05/aws-announces-aws-app-runner

※まだ自分で試したわけではないので、リリースを見て感じたことです。

[追記]

実際に利用してみたところ、ほぼこの記事の認識で問題なかったが、**Security Group や VPC の概念が無く、 VPC 内部のアクセスに制限されたリソース（例えば RDS や ElastiCache ）には現状 App Runner でアクセスできない**。

よって、現在 Fargate + RDS などのインフラで動いている場合は、下記のような対策が必要になる。どれも微妙だが...

- セキュリティの低下を許容した上で Public Access を許可する（Heroku もそうなってる）
- Port Forwarding などの工夫を入れる
- Dynamo DB などに移行

よって、今すぐ Fargate の代替にできるかというと、 VPC 内のリソースにアクセスしたい場合はできないだろう。 RDS や ElastiCache にアクセスしなくて良いサービス、例えば画像加工 API とかにはすぐ投入できる。

ロードマップにはあるっぽいので、そのうち対応されることを祈る。

https://github.com/aws/apprunner-roadmap/issues/1

[/追記]

# 特徴

スクショを見ていると、 Heroku の WebApp 機能だけを切り取ったようなサービス。ランタイムには予め用意された実行環境か、コンテナから選べるのも Heroku っぽい。（個人的にはコンテナ一択だが）

WebApp を複雑なロードバランサーやデプロイの設定が要らず、 HTTPS の設定も Route53 と連携して自動的に行ってくれるみたい。

https://aws.amazon.com/blogs/aws/app-runner-from-code-to-scalable-secure-web-apps/

上記によると、特徴は下記のよう。

- 簡単にデプロイできる
- ロードバランサーの設定が不要
- KMS との連携も簡単にできるっぽい
- オートスケーリングはほぼ自動、同時リクエスト数を指定するだけっぽい
- コンテナのデプロイは、 ECR にプッシュするだけ

個人的には ECR へのプッシュで自動的にデプロイする仕組みがあるのが良いなと思った。どうせ新しいイメージをプッシュしたらそのままデプロイもしたいだろうし、自動的にデプロイしてくれて良いんじゃないかと思っていた。
Fargate の場合、CI 上で新しい Task Definition を作成して Update Service するのが地味にが面倒だった記憶がある。

# AWS の他サービスとの比較

### ECS Fargate

追記: そもそも App Runner は内部的に Fargate を使っているらしい。

Fargate より簡単っぽい。デプロイが簡単というのと、Fargate の場合は Task Definition とか Cluster とか Service とか、その辺の概念の学習コストが若干あるが、 App Runner はその辺すっ飛ばしてる感じがする。
逆に Fargate はコンテナやオートスケーリング、あとログの設定が細かくできるけど、別にそこまで必要ない場合の方が多そう。Fargate から App Runner に乗り換える、というのが一番ありそうな気がする。

気になるお値段は、これ見る限り、 Fargate と同じか、やや高いくらい？ あとでちゃんと計算しよう

https://aws.amazon.com/apprunner/pricing/

### Elastic Kubernates Service (EKS)

Kubernates 使ったことが無いので実際は分からないが、学習コストが非常に高い技術だとは聞く。大規模なインフラ構築する場合には良いかもだが、大抵はそこまで必要ない（って AWS の人が言ってた）。

あと AWS の場合は Google Cloud とは違って Controller の料金が高いから、 WebApp を動かしたいだけなら Fargate で良い（って AWS の人が言ってた）。

App Runner が普及したら、 EKS じゃなくて App Runner で良いよって言われるのだろうか。

### ECS on EC2

昔からある AWS のコンテナサービスだが、 EC2 を自前で管理しないといけないので、 ただ WebApp を動かしたいだけならあんま旨味は無いのではないかと思われる。コンテナのホストに SSH したい場合や、ストレージを細かく管理したい場合に向いているので、 App Runner とは競合しないかと思われる。

Fargate より安くすることができる（必ず安くなるわけではない）。

### Elastic Beanstalk (EB)

実現したいことは App Runner と同様だが、見えないところで色んなリソースが作成され、管理しにくいので個人的にはあんま好きじゃないサービス。 RDS とか EC2 がまとめて作られるけど、なぜか EB 経由で作成すると制約があった気がする。

# まとめ

Fargate の場合、ちょっとした WebApi を作るだけでも、様々なリソースを作成しないと環境構築できず、 Terraform で管理する場合はそこそこの HCL を書かないといけなかったから、それがさくっとできるようになるのはかなり嬉しい気がする。

Terraform とも既に連携できるっぽいので、次のプロジェクトで試してみたい。

# 追記

Terraform もブログ出してた。これによると、そもそも App Runner は Fargate をラップしたものらしい。それで Pricing にも vCPU など Fargate でお馴染みの概念が登場していたのか。

https://www.hashicorp.com/blog/announcing-launch-day-support-for-aws-app-runner-in-the-terraform-aws-provider
conda install tensorflow-gpuではCUDA11が入らず、RTX30シリーズが使えない（2021/05/19）

タイトル通り。Anacondaのバージョンは`anaconda3-2021.05`である。

#やったこと
TensorFlowでGPUを使いたい。Anacondaから使うことにして、何も考えず

```shell
conda install tensorflow-gpu
```

と、現時点（2021/05/19）で入るのは`2.4.1-h30adc30_0`。この際CUDAも`conda`で同時に入るため、自分でセットアップしなくても良い（というかondaで入れた方を優先する）。

しかし一緒に落としてくるcudatoolkitは`10.1.243-h6bb024c_0`である。
GeForce RTX20XXシリーズならばこれで普通に動くはずだが、最新のRTX30XXシリーズを使う場合はCUDA 11以上を必要とするので動かない。

TensorFlowはバージョン2以降からCPU版とGPU版とが統合したのだが、Anacondaのmklビルド版（`conda install tensorflow`だとこっちが入る）を使う限りはバージョン2であってもGPUが使えない。しかしGPU版をインストールしようとすると上記の問題が発生する。

つまり、Anaconda環境下でRTX30シリーズを使ってTensorFlowを回すことができない。

#対処法
`conda install`を使わず、`pip`で入れる。CUDA周りは自分で入れる必要があるが、一応動いた。
child_processでデータ転送する時、進捗を取得する

## 概要
ローカルマシンからリモートマシンにデータ転送する時、進捗を取得する方法で少し手こずったのでメモ。
scpを使った方法ではうまくいかず、rsyncを使っています。   


## サンプルコード  

```js
const childprocess = require("child_process");

const sourcePath = "転送するデータのパス";
const destPath = "転送先ユーザー名@転送先ホスト名(IPアドレス):保存先パス";

const spawn = childprocess.spawn("rsync", [
  "-avzP",
  "-e", // ホスト名だけで接続できる場合は不要
  "ssh -i ローカルマシンの秘密鍵ファイルパス(~/.ssh/xxx.pemなど)", // ホスト名だけで接続できる場合は不要
  sourcePath,
  destPath,
]);

spawn.stdout.on("data", (data) => {
  var per = data.toString().match(/\d{1,3}%/g);
  console.log(per);
});

spawn.stderr.on("data", (data) => {
  console.log(data.toString());
});
```  
  
## 出力  
最初にいくつかnullでますが、とりあえず取得できました。

```
null
null
null
[ '0%' ]
[ '18%' ]
[ '36%' ]
[ '41%' ]
[ '43%' ]
[ '45%' ]
[ '47%' ]
```
Postされたjson文字列を ASP.NET Web API側で取得する方法

## Postされたjson文字列を ASP.NET Web API側で取得する方法

ASP.NET Web APIでは、jsonデータが自動的にマッピングされとても便利なのですが、
Postされた値(Request.Content.Bodyのような)を読むプロパティーが見つからず、ロギングがデバッグ時に不便でなりませんでした。

Stack Overflowも漁ってみましたが、やり方が見つからないためデバッグで原因を探して取得する方法を調査しまいｓた


## サンプルソース
```csharp
    public class ProductsController : ApiController
    {
        public OutputValue Post(InputValue input)
        {
            // ★ Postされたデータを文字列で取得したい
            var output = new OutputValue();
            return output;
        }
    }
```

## 取得する方法

* Requestからstreamを取得しても、読み取り終わっているため先頭にSeekする必要があります。

```csharp
public OutputValue Post(InputValue input)
{
    // RequestからStreamを取得(streamがプロパティーとして公開されていため下記手順で取得する)
    var requestStream = this.Request.Content.ReadAsStreamAsync().Result;
    // streamはフレームワーク側の処理で最後まで読み込み終わっている。再度読み込むため先頭へSeekする
    requestStream.Seek(0, System.IO.SeekOrigin.Begin);
    // 文字列として取得したいのでStreamReader経由で読み取る
    var sr = new System.IO.StreamReader(requestStream);
    // 文字列を最後まで取得する
    var jsonString = sr.ReadToEnd();
}
```

*
HTTPリクエストメソッドの用途

# HTTPリクエストメソッドとは？

HTTP通信で使う方法(メソッド)のこと。

リクエストメソッドやHTTPメソッドと省略して言うことが多い。

# HTTPリクエストメソッドの種類と用途
**※以下で全てではないし用途もこれだけじゃない**

| メソッド | 用途 | CRUD |
| ---- | ---- | ---- |
| GET | 情報(HTML/APIなど)を取得 | READ |
| POST | 情報を取得/情報を登録 | CREATE |
| PUT | 情報を更新 | UPDATE |
| DELETE | 情報を削除 | DELETE |
| OPTION | [プリフライトリクエスト](https://qiita.com/rngs/items/629e10249911d7d6815f#%E3%83%97%E3%83%AA%E3%83%95%E3%83%A9%E3%82%A4%E3%83%88%E3%83%AA%E3%82%AF%E3%82%A8%E3%82%B9%E3%83%88)を送信 | |
| HEAD | HTTPリクエストのヘッド情報だけ取得 | |

# プリフライトリクエスト

[CROS](https://qiita.com/rngs/items/629e10249911d7d6815f#croscross-origin-resource-sharing)のリクエストの一つで、ブラウザが自発的にリクエストを発行する。
別ドメインのリクエストを送信する前に、利用許可されているかを確認するために発行される。
※許可されていないドメインからリクエストされた時はエラーとなる

# CROS(Cross-Origin Resource Sharing)

ドメインを跨いだアクセスを許可するか決めるもの

# 参考
- https://developer.mozilla.org/ja/docs/Web/HTTP/Methods
- https://developer.mozilla.org/ja/docs/Glossary/Preflight_request
- https://developer.mozilla.org/ja/docs/Glossary/CORS
【Rails】save!を実行したとき、ActiveRecord::RecordInvalid (Validation failed: User must exist):と表示されたときの対処法

<h2>症状</h2>
以下のsaveメソッドを実行した際に、以下のエラーメッセージが表示されました。

```terminal:ターミナル
ActiveRecord::RecordInvalid (Validation failed: User must exist):
```

翻訳すると「（検証に失敗しました：ユーザーが存在する必要があります）」になりました。
推察するに、1対nの関係性のあるHogeとUserを設定しており、Hogeを登録するためのuser_idを外部キーとして注入できていなかったようです。

<h2>解決策</h2>
user.idをHogeに注入することで解決しました。

```
#若干強引ですが、user.idをそのまま代入します
Hoge.user_id = user.id

if Hoge.save!
  logger.debug(SUCCESS)
else
  logger.debug(FAIL)
end

```
Oculusの開発者登録　備忘録

# Oculusの開発者登録

Oculusの開発を開始するには、スマートフォンで、コンパニオンアプリのOculusデバイス用の開発者モードを有効にする必要があります。デバイスを開発者モードにするには、Oculusダッシュボードで開発者組織に所属する(または組織を作成する)必要があります。Windowsで開発する場合は、Android Device Bridge (ADB)を使用するためのドライバーをインストールする必要もあります。

## 必要なもの

* [Oculus Quest 2](https://amzn.to/3GSDSBl)
* [Oculus Linkケーブル](https://amzn.to/3zLuxHQ)

## 参考にした本

* [VRコンテンツ開発ガイド 2018](https://amzn.to/3j2XGZ8)
* [作って学べる Unity VR アプリ開発入門](https://amzn.to/3xBlcAG)
* [VRエンジニア養成読本](https://amzn.to/2SW6pBS)


## 組織への参加または組織の作成

既存の組織に参加するには、次の手順に従います。

1. 管理者から既存の組織へのアクセスをリクエストする必要があります。
2. 招待メールが届きます。招待を受け入れると、組織のメンバーになります。

新しい組織を作成するには、次の手順に従います。

1. https://developer.oculus.com/manage/organizations/create/ にアクセスします。
2. 適切な情報を入力します。

![20190613-Oculus-quest-bluetooth024-1024x471.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/229633/75edaeb3-962e-a3b2-bcdb-26b73ecfaf18.jpeg)

開発者機密保持同意書を再確認し、[同意する]を選択して[送信]します。[マイアプリ]ページが読み込まれます。このページを利用して、企業・組織の最初のアプリを作成します。

# Oculus Questの開発者モードを有効にする方法

次の手順に従ってデバイスを開発者モードにします。

１. 開発用に使用するデバイスをオンにします。
2. スマートフォンでOculusアプリを開き、[Settings (設定)]に移動します。

![oculus-app3-768x549.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/229633/ad0c5f9a-d17c-392c-e779-421a6bf22590.png)

3. デバイスをタップして、[More Settings (詳細設定)] > [Developer Mode (開発者モード)]に移動します。
4. [Developer Mode (開発者モード)]のトグルをオンに切り替えます。

![Oculus-app1-946x2048.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/229633/ccc62c11-71ae-8bd0-8476-2916a6dd662c.png)

5. USB-Cケーブルを使用してデバイスをコンピューターに接続し、デバイスを装着します。
6. デバイスに表示される[Allow USB Debugging (USBデバッグを許可)]、および[Always allow from this computer (このコンピューターからは常に許可)]のプロンプトを承認します。

![123501957_688453455418503_2729454915805133542_n.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/229633/9b93f7d9-cc32-49ae-a02d-6b6744dc5c7d.png)

https://developer.oculus.com/

# Oculusブログ日本語版
新作リリースや製品のアップデート情報など、Oculusの最新ニュースをチェックしよう。

https://www.oculus.com/blog/?utm_source=web&utm_medium=oculus_JP_web&utm_campaign=blog&utm_term=Latest_News
[AtCoder] ABC 174 D - Alter Altar

https://atcoder.jp/contests/abc174/tasks/abc174_d

さらっと読んだところ、左側に白い石を全部寄せて、右側に赤い石を寄せればよいはずです。
あとはどういう条件で2つの操作をするかです。
自分はまずひとつ目の操作、

> 石を2個選び (隣り合っていなくてもよい)、それらを入れ替える。

だけを考えることにしました。
左端から石の色を調べていって白い石を探します。
同様に右端から調べていって赤い石を探します。
両方見つけたら上記の入れ替え操作をします。
そうやって左右の探索インデックスが交差するまで調べて入れ替えを繰り返します。
もう片方の操作である、

> 石を1個選び、その石の色を変える (赤なら白に、白なら赤に)。

をどう使えばいいのかわからなかったので、とりあえずこれで提出して試してみました。
そしたらACとなってしまいました。
操作が2種類ある意味は。。。
解説を見ようとしたらないし、わからないままです。
解けたからよしとしましょう。
言語はC++(GCC 9.2.1)でAtCoderのコードテストで確認しています。

```c++
#include <bits/stdc++.h>
using namespace std;

int main() {
  int N, L, R, answer = 0, white = -1, red = -1;
  string C;
  cin >> N;
  cin >> C;
  L = 0;
  R = C.size() - 1;
  while (L < R) {
    if (C[L] == 'W') white = L;
    if (C[R] == 'R') red = R;
    if (white >= 0) {
      if (red >= 0) {
        swap(C[white], C[red]);
        white = -1;
        red = -1;
        answer++;
      } else {
        R--;
      }
    } else {
      L++;
      if (red == -1) R--;
    }
  }
  cout << answer << endl;
}
```
Railsで作成したアプリをHEROKUにデプロイするまでに必要な手順

まずgemファイルに

```
group :production do
  gem 'pg', '1.1.4'
end
```
を group testの下あたりに記述します

そして

```
$ bundle install --without production
```
とします。--without productionというのは、今追加したgemは本番環境でしか使いませんよーという意味になります、ここでbundle installだけで行うと、開発環境にpg(postgres)がないぞ。となってエラーになるのでもう一度オプションをつけてやり直して下さい

次にgit commitしてherokuにデプロイする内容を保存します

```
$ git add -A
$ git commit -m ""
```

Herokuのアカウントを作成します
この時、二段階認証のMFAを有効にする設定を行いましたが、後々解除します。（登録時は有効にしておかないといけない？）

まず自分のシステムにHerokuコマンドラインクライアントがインストールされているか確認します

```
$ heroku --version
```

インストールされていなければこちらを実行してHeroku CLIをインストールします

```
$ source <(curl -sL https://cdn.learnenough.com/heroku_install)
```

確認します

```
$ heroku --version
heroku/7.27.1 linux-x64 node-v11.14.0
```

確認できればHerokuにログインします

```
$ heroku login --interactive
```
ここでメールアドレスと、パスワードを入力します。が、先程の二段階認証を有効にしていると、APIが対応してないか何かのエラーが発生するのでログインできません。https://dashboard.heroku.com/account こちらのアカウントページで無効にしてから、再度上記のコマンドを実行して下さい

そして

```
$ heroku create
```
を実行すると、urlが作成されデータベースが完成します。

commitしておいたRailsアプリをデプロイします。

```
$ git push heroku main
```

デプロイされたアプリの表示は、heroku createコマンド実行時に作成された、urlでブラウザを開けば確認できます
.ppk形式への変換は、WinSCPならCUIでできる

# 概要
秘密鍵をputty用の.ppk形式に変換するのは、puttygen.exeのGUIを使うのが普通（独断と偏見）ですが、
WinSCPを使うとCUIで済ませられます。
なので(半)自動化もできます。

# 本文

## WinSCPのヘルプ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282159/b2e9df33-da22-c9c5-5bca-088703cb5c7c.png)

## 実際のコマンド例
`winscp /keygen id_rsa /output=id_rsa.ppk`

## 結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282159/c15ffcc3-e3a1-fcb2-fdad-e485c377fb4d.png)

## 副次的効果
CUIで済むなら、設定スクリプトによる半自動化もできることになります。(パスフレーズだけは入力してねという)

## それでなにがうれしいのか
**手順書書くのが楽になるんですよ。** 
これに尽きます。
自分でやるときは、コマンド調べなおすくらいならputtygen使います。
でも手順書だと、キャプチャ付きで、

- puttygenを起動する
- loadボタンを押す
- 右下の `PuTTY Private Key Files (*.ppk)` をクリックし、 `All Files(*.*)` に変更する
- 元のキーを選択する
- 「読み込みに成功しました」っていうダイアログが出るのでOKする
- `Save private key` を押す
- 保存する

だいたいこんなもんですかね。
これがコマンド数発に置き換えられるのはかなり楽です。
手順書の手数は減らせれば減らすに越したことはないです。
~~手順書通りにやらないで「できない」って文句いう人も一定割合でいますし。~~ 
それに、手順書通りにぽちぽち作業・・・というのは、それが自動化できるなら無駄の極致です。
簡単なスクリプトを書くだけで、「これを実行すればOpenSSHキーをppkに変換できます」で済みます。

# ポエムな背景
- puttyとWinSCPを使う環境の構築手順を作成していた
- .ppkをputtygenのGUIなしでできないかと思った(めんどいもん)
- puttygen.exeではできないらしく諦めた
- WinSCPの設定インポートをGUIなしでできないかと思ってwinscp.exeを調べた
- 設定インポートの手段は見当たらなかった
- が、なぜかppkファイルを作るオプションがあった
- よくわからないけど手間がひとつ解消した
- 軽くぐぐった限りではGUIでやる方法しか出てこなかったので、投稿しておこうと思った

# ポエムな感想
WinSCPとputtyの親和性が妙に高いのはずっと感じていましたが、これは完全にputty側の機能やん・・・ありがたいけど。

# 予防線
もしありふれTipsだったらごめんなさい
STM32L010と内蔵ADCで電圧をシリアルに出力 3.300Vまで (RawSerial)


目的
主にNJL7502Lの微小な電圧を測る。

説明
adcの値(4096)に6600掛けて8192で割ると3300にピッタリなる。

忙しい人よう

https://os.mbed.com/users/caa45040/code/serial_raw_adc_010_1/


```c++

//電圧

#include "mbed.h"

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

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

//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
RawSerial pc(PA_2, PA_3); //010

char ch_hex_a_b[5];
char *ch_hex_a(int l_num)
{
    int a,b,c;

    b=DVI10(l_num);
    c=l_num-(b*10);
    a=DVI10(b);
    b=b-(a*10);

    ch_hex_a_b[0] = '0' + a;
    ch_hex_a_b[1] = '0' + b;
    ch_hex_a_b[2] = '0' + c;
    ch_hex_a_b[3] = 0;

    return(ch_hex_a_b);
} //ch_hex_a

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

    //文字の中身がゼロか
    while(*str1){
            
        //一文字出力
        pc.putc(*str1 ++);
                        
    } //while

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

int main() {

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

        //adcの読み込み 0から4096
        int s = (adc_vbat.read_u16()>>4);

//        pc.printf("\r\n -S=%d",s); //767

        //電圧に変換 ex 3.300 -> 3300 mVを出力
        s=(s*6600)>>13;

//        //s = 3300;
//        pc.printf("\t c=%d",s); //767

//小数点以上と小数点以下を分ける iiは1の桁 sは小数点以上の桁
int ii = s;
if     ( ii >= 3000 ) { ii = (ii - 3000); s = 3;}
else if( ii >= 2000 ) { ii = (ii - 2000); s = 2;}
else if( ii >= 1000 ) { ii = (ii - 1000); s = 1;}
else                  {                 ; s = 0;}

//        pc.printf("\t t=%d %d",s,ii); //767
//        pc.printf("\r\n"); //767 リターン


        //電圧の小数点以上の表示
        ch_hex_a( s*10 );
        ch_hex_a_b[0] = '+';
      //ch_hex_a_b[1] = '0' + s;
        ch_hex_a_b[2] = '.';      
        pc_printf(  ch_hex_a_b  );

        //電圧の小数点以下の表示
        pc_printf(  ch_hex_a(ii)  );

        //リターン
        pc_printf(  "\r\n"  );

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

    } //while

} //main

//容量削減
void error(const char* format, ...){}




```
meta要素を使って画面遷移させる

# 調べた経緯
「ページにアクセスされた時点から5分経過したらログイン画面へリダイレクトさせたい」という要望があったので、実装方法を調べてみました。  
当初、javascriptで`setTimeout`を使うかと思っていたのですが、`meta`要素を使って簡単にできたので、備忘録として残しておきます。

# 書き方
```html
<meta http-equiv="Refresh" content="{時間を秒で指定}; url={urlを指定}">
```

これに当てはめてみると、

- 5分後にリダイレクト
- リダイレクト先： http://www.example.com/

としたいとき、

```html
<meta http-equiv="Refresh" content="300; url='http://www.example.com/'">
```

このようになります！

これで5分経過後、`http://www.example.com/`にリダイレクトされます。


# 注意点
Googleはmeta refreshによるリダイレクトをサポートしているものの推奨してはいません。
（301リダイレクトが推奨されています。）
SEO的にも良くないようです。  

今回はSEO対策も不要で、且つサーバーサイドで処理することもできなかったので。
rails  serverが立ち上がらない時の対処

#はじめに
railsチュートリアル第8章
ターミナル上でrails serverと入力しました。
その後、Errno::EADDRINUSEと表示されて、サーバーが立ち上がりませんでした。
#開発環境
MacBook Pro 
プロセッサ2 GHz クアッドコアIntel Core i5
メモリ16GB
cloud9 
rails 6.0.3

#作業

```
$ rails server
```

ローカルサーバーが立ち上がらず、下記のエラーメッセージが表示される。

```
=> Booting Puma
=> Rails 6.0.3 application starting in development
=> Run `rails server --help` for more startup options
[11359] Puma starting in cluster mode...
[11359] * Version 4.3.6 (ruby 2.6.3-p62), codename: Mysterious Traveller
[11359] * Min threads: 5, max threads: 5
[11359] * Environment: development
[11359] * Process workers: 2
[11359] * Preloading application
Exiting

一部省略

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

ポート8080がすでに使用されているとのこと。

```
$ lsof -i -P | grep 8080
```
ポート8080の使用状況を確認する。
lsofコマンド→オープンしているファイルを一覧表示するコマンド。
-i→ネットワークソケット（接続口）を対象にする。
-P→ポート名のかわりにポート番号を表示する。

grepコマンド→ファイル中の文字列を検索する。

```
ruby    4849 ubuntu   13u  IPv4  39704      0t0  TCP localhost:8080 (LISTEN)
ruby    4849 ubuntu   14u  IPv6  39705      0t0  TCP ip6-localhost:8080 (LISTEN)
ruby    4850 ubuntu   13u  IPv4  39704      0t0  TCP localhost:8080 (LISTEN)
ruby    4850 ubuntu   14u  IPv6  39705      0t0  TCP ip6-localhost:8080 (LISTEN)
```

4849と4850のプロセスが動いていました。


#解決方法

```
$ kill -9 4849
$ kill -9 4850
```
動いているプロセスを終了させる。
killコマンド→指定したプロセスIDのプロセスを終了させる。
−9→強制終了。

#原因
過去にローカルサーバーをcontrol+Cコマンドで終了させることを失念した可能性が高い。

その後、無事にサーバーが立ち上がりました。
ご覧いただきありがとうございました。
【nuxt, rails, heroku】学習開始から6ヶ月でアプリを作ってデプロイしてみた

#はじめに
学習開始から半年で、学習した技術を用いてアプリを作ってみましので内容を記しておきます。
作成したアプリのリンクを共有しますので、プログラミン学習を始めたばかりの方の半年後のスキルのベンチマークになれば幸いです。

アプリのURL
https://amaimon-decision.herokuapp.com/

#記事内容
0. 筆者について
1. アプリのコンセプト
2. アプリ機能概要
3. 活用技術
4. まとめ

#筆者について
2020年8月からプログラミング学習を開始しました。
当時は営業職でwebプログラミング未経験からの挑戦です。
2021年1月からエンジニアとしての職を得ました。

####学習技術
バックエンド  ：Ruby, Ruby on Rails
フロントエンド ：Nuxt.js, Vue.js, vuetify
インフラ   　：AWS, heroku
その他　 　 ：docker, GitHub

#アプリのコンセプト
「達成する価値のある目標は多くない」をコンセプトに、達成したいと思ったことをからたった一つの目標を見つけ出すためのアプリを作成しました。

####利用者に提供する価値
自分にとって最も価値が高い目標を見つけ出すことができます。
これにより、下記3つのメリットを提供することを目指します。

・色々なことに気が散ってしまう状態を抜け出す
・継続できる目標設定ができる
・やらないことを決めることで自分自身の判断軸を見つめる

挑戦する方の役に立つことを目的にしています。

####利用方法
①興味のあることや達成したいと思ったことを書き出す
②ドラッグ＆ドロップ機能で①で書き出した項目の分類・並び替える（分類基準はその項目は他人が期待するものか否かと優先順位）
③完了ボタンかページ更新、ページ遷移で②で分類し優先順位付けたものの最上位を目標に設定する
④マイページにて③で設定した目標に達成したい理由などを追記する

↓作成したアプリのURL
https://amaimon-decision.herokuapp.com/

#アプリ機能概要
コンセプトを達成するために必要最小限の機能の実装を目指しました。
バックエンドエンドはRailsのAPIモード、フロントエンドはNuxtでVuetifyを活用してSPAを作成しました。それぞれをherokuにデプロイしています。
最も価値の高い目標を見つけ出すために必要だと感じた機能は下記です。

・ユーザー登録、ログイン、ログアウト機能
・目標書き出し、分類(ドラッグ＆ドロップ)、目標一つを決定する機能
・決定した1つの目標を別ページにて追記する機能

#活用技術
####ユーザー登録、ログイン、ログアウト機能
目標設定、目標分類が各ユーザーごとに発生するのでユーザーを識別するために実装しました。
本機能はgem"devise_token_auth", "devise"の二つを活用して実現しました。
また、ログイン状態を保持するためにRailsではcookie, NuxtではVuexを使っています。

####目標書き出し、分類(D&D)、目標を一つに決定する機能
このアプリの最重要部分です。
アプリコンセプトの利用方法部分の実装です。
イメージとしてはToDoアプリをドラッグ＆ドロップで移動できるものです。

ドラッグ＆ドロップを実装するにあたりvue-draggbleの活用を検討しましたが、カテゴリ間の項目の移動が実装できなかったので、見送りました。
文末記事を参考に実装しました。

目標を一つに決定する機能は、設定項目の特定カテゴリの最上位に設定されたものを目標に設定するように実装しました。

この際に気をつけたのが、項目の優先順位を変更した際の一斉更新機能です。
実装はRailsでは、ルーティングとメソッドを新しく定義して、繰り返し文mapで引数を全て更新するよう実装しました。
更新タイミングですが、vueライフサイクルのbeforeUpdate, beforeDestroyのタイミングと完了ボタンを押されたタイミングです。

余談ですが、ここの実装を通してjavascriptはタイミングがとても重要だと学びました

####決定した1つの目標を別ページにて追記する機能
使っているのはupdateメソッドですが、目的設定・選択機能とは別ページに実装しました。

意図としては、ユーザーにとって最も大事なのが、決定したたった一つの目標だからです。
目標設定・選択ページでの経験を最大化するために特別感を演出しようと考えています。


#まとめ
今後もこのアプリをアップデートしていく予定です。

まずは開発のためにダークモードにしたデザインを作成していく予定です。
次はユーザーのアプリ内での導線をデザインする予定です。

もしよかったら、使った感想などをいただけると幸いです。
https://amaimon-decision.herokuapp.com/


####参考記事
Vue.jsを使ってスクラッチから作るTrello風タスク管理アプリ
https://reffect.co.jp/vue/vue-js-trello
kintone plugin-uploader でタイムアウトの暫定対策メモ

kintone プラグイン開発環境を新しいPC に構築したところ、plugin-uploader でタイムアウトするエラーが発生。とりあえず、暫定対策したのでメモしておきます。
※ 2021/05/19 時点

# PC 環境

新しく出た Surface Laptop 4 の出来がよさそうだったので購入。
US キーボードが日本版だと選べないので、Amazon US から購入したが、日本に送れる PC がi5の１台のみ。

- Surface Laptop 4 13.5 Core i5-1135G7 8GB memory
    - \$1,299.00 + \$130.39 Shipping (Amazon 発注から約5日でUSから納品)
- Windows 10 PRO
    - Microsoft Store で購入 ¥12,568

# kintone プラグイン開発環境

[create-pluginを使ってプラグインの雛形を作成しよう！](https://developer.cybozu.io/hc/ja/articles/360000877946) からの一式を順番にインストール
※ 2021/05/18 時点の最新版

- create-plugin 4.0.1
- plugin-packer 5.0.1
- plugin-uploader 5.0.1
    - puppeteer 9.1.1

# plugin-uploader でタイムアウト

前のPCでも、plugin-uploader でタイムアウトすることがあったが、新環境ではほとんどタイムアウトする。
デバッグすると、プラグインファイルをアップロードするボタンをクリックする処理がうまく動いていないようだ。
plugin-uploader　を調べると、これまで使っていたバージョンとかなり異なる。
puppeteer は、ブラウザーを制御するライブラリ。

※ これまで動作していたplugin-uploaderのバージョン

- plugin-uploader 4.2.0
    - puppeteer 5.5.0

# plugin-uploader でタイムアウトの暫定対策

どうもボタンをクリックするタイミングがうまくいっていないようなので、ボタンクリックを2重にしてみたところ、アップロードされるようになった。
本対策としては、yield file.uploadFile(pluginPath) の処理完了を待ってボタンクリックするといいかもしれないが、暫定対策なのでこれでOK。

```plugin-uploader/dist/index.js
        yield file.uploadFile(pluginPath);
        yield page.click('button[name="ok"]');
        yield page.click('button[name="ok"]');
```

# GitHub の Issue , pull request

後で気が付いたのだが、GitHub に、Issue と暫定対策の Pull request が上がっている。
こちらの暫定対策では、puppeteer を V8 に戻すと動作するようです。

- [plugin-uploader: failes to upload plugin #886](https://github.com/kintone/js-sdk/issues/886)
- [fix(plugin-uploader): pin puppeteer version to v8 #889](https://github.com/kintone/js-sdk/pull/889)
【OCI】NATインスタンスを構築してみた

###概要

OCI(Oracle Cloud Infrastructure)のPrivate Subnet上に作成した仮想サーバから
インターネット宛の通信を行う場合は一般的にNAT Gatewayを利用します。

NAT Gatewayは設定項目も少なく、名前とNATに使うパブリックIPさえ指定すれば
すぐに使えるので非常に便利ですが、NATするトラフィックを制御することはできず
基本的にNAT Gatewayをターゲットとして指定している送信元IPからの全てのトラフィックを
対象にNAT変換を行います。

NAT(NAPT)するトラフィックを制御したいという要件があった場合の対策として
NAT Instanceを利用する方法がありますが、今回はそちらについて検証を行いましたので
検証方法と結果について共有させていただきます。

###検証構成
・VCN上にPublic SubnetとPrivate Subnetをそれぞれ作成、
NAT Instance(OS: Oracle Linux)をPublic Subnet上に配置します
・NAT InstanceのNAT変換の動作確認を行うためにNAT Client(OS: Windows Server)を作成、
Private Subnet上に配置します
・今回、検証を実施するユーザがインターネット上にいるためPrivate Subnetに配置している
NAT ClientにアクセスするためにはPublic IPを持った踏み台サーバが必要ですので
そのサーバとしてMGT Instance(OS: Windows Server)を作成、Public Subnet上に配置します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411653/da2a177a-89aa-452e-b835-50f7b58b8ee3.png)



###検証方法

・NAT ClientからNAT Instanceを経由してインターネット上にある
Google Public DNS(8.8.8.8)宛にpingによる疎通が取れるか試します


###設定方法
※VCN、Subnet、ルート・ルール、セキュリティ・リスト、
Internet Gatewayの作成方法は割愛します。
作成方法について詳しく知りたい方は以下のチュートリアルをご参照ください
https://oracle-japan.github.io/ocitutorials/beginners/creating-vcn/


■NAT Instance
①インスタンス作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411653/3618b476-dd1c-913e-63f6-9db59eec6e9d.png)
・名前: 任意の名前を入力(検証ではNAT Instance)
・イメージとシェイプ
  - イメージ: 任意のLinux OS(検証ではOracle Linux 7.9を使用)
  - シェイプ: 任意のシェイプ(検証ではVM.Standard.E4.Flexを使用)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411653/ab78926a-0a1a-9251-e5fb-d73e61d00a0e.png)
・サブネット: 事前に作成したPublic Subnetを選択
・パブリックIPアドレス: パブリックIPv4アドレスを割当て
・プライベートIPアドレス: 固定IPを入力(検証では10.0.1.11)

②VNIC設定変更
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411653/66f1cb7e-ed69-3a34-2fe9-afd49cefa819.png)
・VNICの編集メニューに移動
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411653/4a139217-c954-339a-c848-c1e2549a98c7.png)
・ソース/宛先チェックのスキップにチェック

③NAT関連設定
NAT InstanceにSSHにてログイン、NAT関連設定投入
![nat_instance_nw_parameter.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411653/ac1debae-a225-689e-e30b-d8b214526e47.png)

■NAT Client/MGT Instance
Windows Server 2019 Standard Editionで作成
※作成方法について詳しく知りたい方は以下のチュートリアルをご参照ください
https://oracle-japan.github.io/ocitutorials/beginners/creating-compute-instance/


###動作確認・結果
MGT Instance経由でNAT ClientにRemote Desktopでログイン
コマンドプロンプトでGoogle Public DNS(8.8.8.8)宛にpingを実施したところ
応答が返ってくることを確認しました。
またtracertの実施結果からはNAT Instance(10.0.1.11)を経由して通信が
行われていることが確認できました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411653/5775c861-0b0a-d28c-87ff-fd6ec77ebd3a.png)

###おわりに
・今回の検証ではNATの基本動作のみを試しましたが
次回は条件付き(例: 特定の送信元IPからの通信のみNAT対象にする)の
設定、動作も試してみたいと思います。
・本記事は個人で検証した内容の記録であり、検証方法及び結果を
保証するものではないことをあらかじめご了承・ご理解いただけますようお願い致します。
【Java】Fisher-Yatesのシャッフルで配列をシャッフルする

# はじめに

久しくプログラミング業務から離れているため、ちょっとしたアルゴリズムに触れて頭の体操をしようと思い立ち、Fisher-YatesのシャッフルをJavaで実装してみました。
アルゴリズムそのものは、[Wikipediaに記載されているもの](https://ja.wikipedia.org/wiki/%E3%83%95%E3%82%A3%E3%83%83%E3%82%B7%E3%83%A3%E3%83%BC%E2%80%93%E3%82%A4%E3%82%A7%E3%83%BC%E3%83%84%E3%81%AE%E3%82%B7%E3%83%A3%E3%83%83%E3%83%95%E3%83%AB)を利用しています。

# 作成したコード

* 以下のコードは、[Wikipediaの改良されたアルゴリズム](https://ja.wikipedia.org/wiki/%E3%83%95%E3%82%A3%E3%83%83%E3%82%B7%E3%83%A3%E3%83%BC%E2%80%93%E3%82%A4%E3%82%A7%E3%83%BC%E3%83%84%E3%81%AE%E3%82%B7%E3%83%A3%E3%83%83%E3%83%95%E3%83%AB#%E6%94%B9%E8%89%AF%E3%81%95%E3%82%8C%E3%81%9F%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0)をJavaのコードとして書き起こしたものになります。
  * コード中のコメントは、Wikipediaに記載されているアルゴリズムと対応（一致）しています。
* int型の配列をStreamにした後、そのままmapメソッドでStringにしようとするとエラーになりました。
  * [こちらのサイト](https://zenn.dev/someone7140/articles/6356ccf88d7b89)によると、int型配列をStreamにするとIntStreamになるものの、IntStreamではint型しか扱えないため、mapオブジェクトでString型に変換するとエラーが出てしまう...というのがエラーの理由だそうです。
  * そのため、mapToObjメソッドで各要素をString型にしています。


```java:FisherYatesRefined.java
import java.util.Arrays;
import java.util.Random;
import java.util.stream.Collectors;

/**
 * フィッシャー・イェーツのシャッフルの改良版
 * @author NKOJIMA
 *
 */
public class FisherYatesRefined {

	/**
	 * 要素数がnの配列aryをシャッフルする(添字は0からn-1):
	 * @param args
	 */
	public static void main(String[] args) {

		int[] ary = {0,1,2,3,4,5,6,7,8,9};
		System.out.println("シャッフル前");

		System.out.println(Arrays.stream(ary).mapToObj(elem -> String.valueOf(elem)).collect(Collectors.joining(",")));

		int n = ary.length;
		Random rnd = new Random();

		// iをn-1から1まで減少させながら、以下を実行する
		for (int i=n-1; i>=1; i--) {
			// jに0以上i以下のランダムな整数を代入する
			int j = rnd.nextInt(i);

			// a[j]とa[i]を交換する
			int tmp = ary[i];
			ary[i] = ary[j];
			ary[j] = tmp;
		}

		System.out.println("シャッフル後");
		System.out.println(Arrays.stream(ary).mapToObj(elem -> String.valueOf(elem)).collect(Collectors.joining(",")));
	}

}
```

# 実行結果

* 「シャッフル前」の結果は常に同じですが、「シャッフル後」の結果の並び順はシャッフルされていることが分かります。

```text:実行結果
シャッフル前
0,1,2,3,4,5,6,7,8,9
シャッフル後
8,7,3,0,2,4,9,5,6,1
```


# 参考URL

* [フィッシャー–イェーツのシャッフル - Wikipedia](https://ja.wikipedia.org/wiki/%E3%83%95%E3%82%A3%E3%83%83%E3%82%B7%E3%83%A3%E3%83%BC%E2%80%93%E3%82%A4%E3%82%A7%E3%83%BC%E3%83%84%E3%81%AE%E3%82%B7%E3%83%A3%E3%83%83%E3%83%95%E3%83%AB)
* [【Java】プリミティブのint型配列からmap関数でString型に変換](https://zenn.dev/someone7140/articles/6356ccf88d7b89)
雨が降る日の朝にメッセージを送ってくれるLINE botを作るうえでつまづいたこと

つまづいた点

◆Userモデルを作成時に起きたエラー

![スクリーンショット 2021-05-14 18.09.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1519908/fddf795f-b5f4-1c28-2bb0-aabfb1f8223b.png)


```
uninitialized constant URI::Generic(NameError)
```

rubyのバージョンが古いために出たエラーのようだ。

バージョンを上げると解消された。

```
#バージョン2.7.2のRubyをインストール
$ rbenv install 2.7.2
#省略

#使用する全体のrubyのバージョンを指定
$rbenv global 2.7.2

#Rubyのバージョンを確認
$ruby -v
ruby 2.7.2p137 (2020-10-01 revision 5445e04352) [x86_64-darwin17]
```


◆データベース・テーブル作成時のエラー

```
PG::ConnectionBad: could not connect to server: No such file or directory

Is the server running locally and accepting

connections on Unix domain socket "/var/pgsql_socket/.s.PGSQL.5432"?
```

ログを見てみるとpostgresqlのデータディレクトリがバージョン10なのに、バージョン11のpostgresqlも入ってしまっていたせいで上手くいかないようだ。

・データディレクトリ削除＆brew uninstall

```
$ rm  -rf /usr/local/var/postgres
```

homebrewの方も削除

```
$ brew uninstall --force postgresql
```

・再インストール＆データディレクトリ作成

```
$ brew install postgresql
$ initdb /usr/local/var/postgresql -E utf8
```

・PostgreSQLサーバー起動

```
$ brew services start postgresql
```


db作成成功

ここまで行い、データベースをpostgresqlで作成することができた。
githubで過去にコミットした時点に戻す

【GitHub】特定のコミットに戻す
-

brunchをmasterに戻す

戻したいコミットのハッシュ値を調べます。
-

|コマンド|% git log --oneline|
|--|--|

```rb:
f77a863 (HEAD -> master, origin/master) Merge pull request #16 from takuo-maeda/購入カード登録分岐
ee7e4a5 (origin/購入カード登録分岐, 購入カード登録分岐) カード情報表示OK
3b2d5d6 完成２
0e25399 Merge pull request #15 from takuo-maeda/カード登録
65ba5d2 (origin/カード登録, カード登録) card登録・購入終了
5af3dc0 アロー関数完成前
b6fc426 Merge pull request #14 from takuo-maeda/写真複数枚アップロード
bf9aa7e (origin/写真複数枚アップロード, 写真複数枚アップロード) 完成写真複数アップロード
cd19eb1 preview完成
27c53ae 写真プレビュー
471b488 AWS完成５
e9e98dc Listen変更
756c671 AWS起動３
d435db0 AWS公開準備１
2516991 (heroku/master) Merge pull request #13 from takuo-maeda/AWS
b44c966 (origin/AWS, AWS) AWS
af220e1 空のcommit
e35df7b Merge pull request #12 from takuo-maeda/AppStoreバッジ処理
e50ed66 (origin/AppStoreバッジ処理, AppStoreバッジ処理) 空のcommit
9ae4225 app-imgmending
78c4696 商品出品完成５月１日
611dfc8 空のcommit
4d09a69 basic認証
c065f55 空のコミット
b01eafb Merge pull request #10 from takuo-maeda/商品購入２
e73dfda (origin/商品購入２, 商品購入２) 空のコミット
1ecab9f 商品購入機能実装４月３０日１７：１８
61dcc60 商品購入ページ４月３０日１６：５１
3e52894 商品購入画面４月３０日０：０４
773d94f 完成２０：０３
487cc1c 購入完成５：３６
```





git reset --hard ハッシュ値
-

これで特定のコミットに戻すことができます。 masterではなくブランチの場合は切り替えを忘れずに。

Qを打って終了
-
saveとcreateについて

１点目
-

saveはインスタンスメソッドでnewを記述してからでないと使えない。
createはクラスメソッドでnewの記述はいらない

2点目：保存の判定
-

```rb:saveの場合
[1] pry(main)> @item = Item.new #newを作って
   (0.7ms)  SET NAMES utf8,  @@SESSION.sql_mode = CONCAT(CONCAT(@@sql_mode, ',STRICT_ALL_TABLES'), ',NO_AUTO_VALUE_ON_ZERO'),  @@SESSION.sql_auto_is_null = 0, @@SESSION.wait_timeout = 2147483
=> #<Item:0x00007feeacdcfe68
 id: nil,
 item_name: nil,
 description: nil,
 category_id: nil,
 status_id: nil,
 delivery_fee_payment_id: nil,
 prefecture_id: nil,
 delivery_prepare_id: nil,
 price: nil,
 user_id: nil,
 created_at: nil,
 updated_at: nil>
[2] pry(main)> @item.save　≈
   (13.5ms)  BEGIN
   (12.5ms)  ROLLBACK
=> false
#true/falseを返す
```

```rb:createの場合
[3] pry(main)> Item.create
=> #<Item:0x00007feead0fed28
 id: nil,
 item_name: nil,
 description: nil,
 category_id: nil,
 status_id: nil,
 delivery_fee_payment_id: nil,
 prefecture_id: nil,
 delivery_prepare_id: nil,
 price: nil,
 user_id: nil,
 created_at: nil,
 updated_at: nil>
インスタンスで返ってくるのでデータの中身
```
Python の `+=` は in-place だったりそうじゃなかったりする

# これは何？

https://qiita.com/cielavenir/items/579997ca2005ae329a16

を読んで面白かったので色々試した。

# 前提

[前述の記事からリンクされている文書](https://docs.python.org/ja/3/library/operator.html#in-place-operators) にある通り、

> 文字列、数、タプルのようなイミュータブルなターゲットでは、更新された値が計算されますが、入力変数に代入し返されはしません。
> 【略】
> リストや辞書のようなミュータブルなターゲットでは、インプレースメソッドは更新を行うので、その後に代入をする必要はありません。

となっている。なので前述の記事のとおり、mutable なオブジェクトの場合

```python:Python3
b=a;a+=x;print(b)
```

```python:Python3
b=a;a=a+x;print(b)
```

では異なる結果が得られる。`a+=x` って `a=a+x` と同じだよね、と思い込んでいる人はこの仕様に足をすくわれて苦しむことがあるだろう。

足をすくわれる前に気づいてよかった。

# 色々試した

## list, set, dic

```python:Python3
a=[1];b=a;a+=[2];print(a,b)
#=> [1, 2] [1, 2]
```

```python:Python3
a={1:2};b=a;a|={3:4};print(a,b)
#=> {1: 2, 3: 4} {1: 2, 3: 4}
```

```python:Python3
a={1,2};b=a;a|={3,4};print(a,b)
#=> {1, 2, 3, 4} {1, 2, 3, 4}
```

このとおり、 `+=` は in-place になる。

## string, tuple

```python:Python3
a="xy";b=a;a+="z";print(a,b)
#=> xyz xy
```

```python:Python3
a=(1,2);b=a;a+=(5,6);print(a,b)
#=> (1, 2, 5, 6) (1, 2)
```

`string` と `tuple` は immutable なので in-place にならない。

ちなみに関係ないけど `string` の `%` は、`%=` としても使える（今知った）。

```python:Python3
a="[%s]";b=a;a%="hoge";print(a,b)
#=>[hoge] [%s]
```

こちらも当然 in-place にはならない。

## pathlib.Path

```python:Python3
from pathlib import Path
a=Path("x");b=a;a/="y";print(a,b)
#=> x/y x
```

`pathlib.Path` も immutable なのか。メソッド見るとなるほど自分を変更する手段はなさそうだ。

## np.array

```python:Python3
a=np.array([1]);b=a;a+=[10];print(a,b)
#=> [11] [11]
```

ちなみに `[:]` の動作が組み込み配列と `np.array` で異なるので

```python:Python3
x=[1];y=x[:];x+=[10];print(x,y)
#=> [1, 10] [1]
x=np.array([1]);y=x[:];x+=[10];print(x,y)
#=> [11] [11]
```

と、動作が違うので要注意。

## byte と bytearray

```python:Python3
x=b'p';y=x;x+=b'q';print(x,y)
#=> b'pq' b'p'
x=bytearray(b'p');y=x;x+=b'q';print(x,y)
#=> bytearray(b'pq') bytearray(b'pq')
```
`byte` と `bytearray` で動作が異なる。まあ immutable かどうかで変わると言っているんだからそうだろう。

## frozenset

`frozenset` というものがあるのか。
`frozendict` と `frozenlist` はないのかな。

```python:Python3
a=frozenset({1,2});b=a;a|={4};print(a,b)
#=> frozenset({1, 2, 4}) frozenset({1, 2})
```

`set` と異なり、immutable なので in-place にはならない。まあそうだよね。

## collections の人たち

もっと色々あるかと思ったら、 `deque` ぐらいしかないのかな。

```python:Python3
a=deque([1,2]);b=a;a+=[3];print(a,b)
#=> deque([1, 2, 3]) deque([1, 2, 3])
```

## date, timedelta

```python:Python3
a=date(2021,2,3);b=a;a+=timedelta(99);print(a,b)
#=> 2021-05-13 2021-02-03

p=timedelta(11);q=p;p+=timedelta(9);print(p,q)
#=> 20 days, 0:00:00 11 days, 0:00:00
```
`date` も `timedelta` も immutable らしい。


# まとめ

というわけで、組み込みライブラリ周辺ではちゃんと

* immutable なら 非 in-place
* mutable なら in-place

となっていて、このルールからの逸脱は見つけられなかった。

もっと他に `+=` 、 `|=` 、 `/=` 、 `^=` の類を試したら良さげなものがあったらお知らせください。
pipコマンドの使い方　pip21.1.1のドキュメントなどを読んで

動機：jetsonNX+jetpack4.5にtensorflow2の環境を作成したい。
本家ドキュメント
https://pip.pypa.io/en/stable/cli/
## pip基本
pip自体のアップグレード（バージョンアップ）必要に応じてpython3と明示
python -m pip install --upgrade pip
または、
pip install --upgrade pip

python -m はパイソンのモジュールという意味

pip check で依存関係が壊れていないかを確認。
##オプション
--pre 開発版もインストールする。通常は安定版のみが対象。
--extra-index-url 通常のパッケージインデックス(Pypi)以外のURLからも探してインストールする。
--no-cache-dir キャッシュを使わない。インストールの試行錯誤繰り返すときに利用した。


-U or --upgrade パッケージのアップデート　ハイフン - が１個だったり２個なのは省略だったりフルスペルということか。

## インストール先
pip show [パッケージ名]　で確認出来る。

パッケージのインストールをpip, sudo pip, apt install python3-pakkage とするとインストール先が異なる。
https://qiita.com/gaichi/items/b3a7b566cece3a5a06cc

### インストール先を指定

pip install package -t folder とのこと　t : target

https://qiita.com/non_cal/items/1f3a910eb55427b193a3#%E6%B0%97%E8%BB%BD%E3%81%ABpython%E3%81%AE%E3%83%A9%E3%82%A4%E3%83%96%E3%83%A9%E3%83%AA%E3%82%92%E4%BD%BF%E3%81%84%E3%81%9F%E3%81%84

## 仮想環境の保存と再現
仮想環境に限らなくても、ライブラリの一覧リストを保存しておくことで、そのリストに従って再構築ができる。
ライブラリの一覧は pip list でも取得できるが、この目的のためにはpip freezeが適している。

pip freeze > requirements.txt でリダイレクトでテキストファイルに一覧を保存。
pip freeze --all > requirements.txt とすれば、パッケージ管理ツール(pip setuptools wheelなど）を含めて出力する。 --allオプションを付けない解説が多いが、付けた方が良いように感じている。
復元は
pip install -r requirements.txt 　　　-r オプションはリスト一覧を参照するときのオプション
pipが古いとうまく行かないことがあるので、アップグレードを先に行う。

ライブラリのインストールを特殊な場所から行っていると再構成できない。
この場合、requirements.txt に次の一行をエディタなどで追加する。
--extra-index-url https://....nvidia/jp/v45 リスト全体をこのURLからも探すので記述場所はどこでも良い。
リモートリポジトリへ接続する際に登録したはずのssh_keyでエラーが出た時の対処法

## 事象
GitLabのPrivateリポジトリにPushしようとした時に以下のエラーに遭遇しました。
しょうもないことだったのですが解決法を書いておきます。

```shell
% git push origin demo
no such identity: /Users/●●/.ssh/id_e25519: No such file or directory
git@gitlab.com: Permission denied (publickey,keyboard-interactive).
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.
```

## 解決法
`.ssh/config` 内のIdentityFileで指定していた秘密鍵のファイル名の記載が誤っていたため、
ファイル名を修正してあげればよかったです。

## 解決に時間がかかった理由
GitLabにssh_keyの秘密鍵を登録した後、リモートリポジトリへpush等ができていたためです。
なので、ファイル名が間違ってないと決めつけてしまってました。

`.ssh/config` ファイル内の値が変わっていた理由が不明なのですが、、、
念の為と思っても原因切り分けのためには確認を怠ってはいけないなと思いました。
Material-UIのボトムナビゲーションに「追加ボタン」追加してみる。

#概要
Next.js でボトムナビゲーションを実装した時のソースコードの紹介です。
Reactを使っている場合は、`router.push("./create");`を画面遷移処理に変更すれば良いと思います。

[Material-Ui](https://material-ui.com/) の
[Bottom Navigation](https://material-ui.com/components/bottom-navigation/) というコンポーネントを使います。

##目標
下記の赤枠ようなUIを作成することを目標とします。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/640981/d70b15da-85ac-d390-d2ed-6f20b7aba734.png" width="300">

##実際に実装したもの
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/640981/9f179071-6342-5e2f-29ac-b78a33c1aab2.png" width="300">

「ボタンが３つしかないか！」と突っ込みが入りそうですが、割愛します。
書いたコードがこちらになります。

ほぼ公式サイトのソースコードをコピー＆ペーストして
「追加ボタン」を
`position: "fixed",
bottom: 70,
right: 30,
`で記載するだけでした。
ClassにBootstrapを使っていますが、この説明も割愛します。いつかGithubにコードを載せます。

#ソースコード
```BottomNavigation.jsx
import React from "react";
import { makeStyles } from "@material-ui/core/styles";
import BottomNavigation from "@material-ui/core/BottomNavigation";
import BottomNavigationAction from "@material-ui/core/BottomNavigationAction";
import { useRouter } from "next/router";
import HomeIcon from "@material-ui/icons/Home";
import PersonIcon from "@material-ui/icons/Person";
import QuestionAnswerIcon from "@material-ui/icons/QuestionAnswer";
import AddIcon from "@material-ui/icons/Add";
import Button from "@material-ui/core/Button";

const useStyles = makeStyles({
  root: {
    width: 500,
  },
});

export default function SimpleBottomNavigation(props) {
  const router = useRouter();
  const classes = useStyles();
  const [value, setValue] = React.useState(router.pathname.slice(1) || "./"); // アクセス時のURLを解析して、適切なナビゲーションボタンをアクティブにする。

  return (
    <>
      <Button
        style={{
          borderRadius: 50,
          minWidth: 50,
          width: 50,
          height: 50,
          position: "fixed",
          bottom: 70,
          right: 30,
        }}
        className="z-depth-1 p-2 d-flex justify-content-center align-items-center"
        onClick={async () => {
          router.push("./create");
        }}
      >
        <AddIcon style={{ fontSize: 28 }} className="text-primary" />
      </Button>
      <BottomNavigation
        value={value}
        onChange={async (event, newValue) => {
          setValue(newValue);
          router.push(newValue);
        }}
        showLabels
        className={(classes.root, "fixed-bottom z-depth-1")}
      >
        <BottomNavigationAction value="./" label="ホーム" icon={<HomeIcon />} />
        <BottomNavigationAction
          value="settings"
          label="設定"
          icon={<PersonIcon />}
        />
        <BottomNavigationAction
          value="help"
          label="Help"
          icon={<QuestionAnswerIcon />}
        />
      </BottomNavigation>
    </>
  );
}

```

以上です！いかがでしたか？

Muiを使うとUIの実装が簡単になりますね！！