OmniAICreator/Qiita-1.07M huggingface dataset:
Error: Cannot find module '@types/node/package.json'の解決法

#結論

```sh:
$ tsc --init
```


---

ts-node を使った際に以下のエラーが出た際の解決方法です

```sh
~/Workspace/(master ✗) ts-node index.ts
Error: Cannot find module '@types/node/package.json'
Require stack:
- /usr/local/lib/node_modules/ts-node/dist/index.js
- /usr/local/lib/node_modules/ts-node/dist/repl.js
- /usr/local/lib/node_modules/ts-node/dist/bin.js
    at Function.Module._resolveFilename (internal/modules/cjs/loader.js:794:15)
    at Function.resolve (internal/modules/cjs/helpers.js:80:19)
    at /usr/local/lib/node_modules/ts-node/src/index.ts:746:52
    at Array.map (<anonymous>)
    at Object.resolveTypeReferenceDirectives (/usr/local/lib/node_modules/ts-node/src/index.ts:734:33)
    at actualResolveTypeReferenceDirectiveNamesWorker (/usr/local/lib/node_modules/typescript/lib/typescript.js:109514:143)
    at resolveTypeReferenceDirectiveNamesWorker (/usr/local/lib/node_modules/typescript/lib/typescript.js:109773:26)
    at Object.createProgram (/usr/local/lib/node_modules/typescript/lib/typescript.js:109612:35)
    at synchronizeHostData (/usr/local/lib/node_modules/typescript/lib/typescript.js:153746:26)
    at Object.getProgram (/usr/local/lib/node_modules/typescript/lib/typescript.js:153878:13)
```
Python　printについてメモ

# Pythonのprintの多機能さ

C言語経由でPythonを学んでいます。
この記事は自分用のメモとしてつらつらと書いているものになります。

print関数がC言語のprintf関数とけっこう異なっているのでdocumentを読んでみました。

## Documentの説明

```py
print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)
```

`objects` を `sep` で区切りながらテキストストリーム `file` に表示し、最後に `end` を表示します。

`sep` 、 `end` 、 `file` 、 `flush` を与える場合、キーワード引数として与える必要があります。

キーワードなしの引数はすべて、 `str()` がするように文字列に変換され、 `sep` で区切られながらストリームに書き出され、最後に `end` が続きます。`sep` と `end` の両方とも、文字列でなければなりません。

これらを `None` にすると、デフォルトの値が使われます。
objects が与えられなければ、 `print()` は `end` だけを書き出します。

`file` 引数は、 `write(string)` メソッドを持つオブジェクトでなければなりません。
指定されないか、 `None` である場合、 `sys.stdout` が使われます。
表示される引数は全てテキスト文字列に変換されますから、 `print()` はバイナリモードファイルオブジェクトには使用できません。代わりに `file.write(...)` を使ってください。

出力がバッファ化されるかどうかは通常 `file` で決まりますが、`flush` キーワード引数が真ならストリームは強制的にフラッシュされます。

バージョン 3.3 で変更: キーワード引数 `flush` が追加されました。

## Pythonにおけるオブジェクト

> `file` 引数は、 `write(string)` メソッドを持つオブジェクトでなければなりません。

C言語にはオブジェクトという考え方がないので、戸惑いました。

Pythonにおけるオブジェクトとは以下のような定義です。

> object
> (オブジェクト) 状態 (属性や値) と定義された振る舞い (メソッド) をもつ全てのデータ。もしくは、全ての 新スタイルクラス の究極の基底クラスのこと。

[組み込み関数 — Python 3.9.4 ドキュメント](https://docs.python.org/ja/3/library/functions.html?highlight=object#object)
[3. データモデル — Python 3.9.4 ドキュメント](https://docs.python.org/ja/3/reference/datamodel.html?highlight=object#object.__ceil__)

> `file` 引数は、 `write(string)` メソッドを持つオブジェクトでなければなりません。

というのは、write関数を持つクラスのインスタンスを指しているようです。

Pythonを理解するには、オブジェクトとはなにか、ということを毎回注目していけばいい感じに学習が進みそうという手応えを得ました。

## リストを出力する際に使えるアンパックを使った書き方

ここらへんのテクニック的な書き方は、その都度、出会うたびに習得していくしかなさそうです。

アンパックとは、パックの逆なので、展開のことです。

> 引数がすでにリストやタプルになっていて、個別な位置引数を要求する関数呼び出しに渡すためにアンパックする必要がある場合には、逆の状況が起こります。
> 例えば、組み込み関数 range() は引数 start と stop を別に与える必要があります。
> 個別に引数を与えることができない場合、関数呼び出しを * 演算子を使って書き、リストやタプルから引数をアンパックします。

[4. その他の制御フローツール — Python 3.9.4 ドキュメント](https://docs.python.org/ja/3/tutorial/controlflow.html?highlight=%E3%82%A2%E3%83%B3%E3%83%91%E3%83%83%E3%82%AF#unpacking-argument-lists)

### アンパックを使わない書き方

```py
def writeNew(tl):
    with open('newtext.txt', 'w') as f:
        for i in tl:
            f.write(f"{i}\n")
```

### アンパックを使った書き方

```py
def writeNew(tl):
    with open('newtext.txt', 'w') as f:
        print(*tl, file=f, sep='\n')
```

## 参考

[Python3.xのアスタリスク逆引き - Qiita](https://qiita.com/LouiS0616/items/1bbe0a9bb93054f6c380)
DockerでSparkクラスタの環境構築

## Docker環境の用意

DockerでSparkの環境構築をしてみました。

```Dockerfile
FROM openjdk:8

ARG SPARK_VERSION=3.0.3
ARG HADOOP_VERSION=3.2

RUN wget -q http://apache.mirror.iphh.net/spark/spark-${SPARK_VERSION}/spark-${SPARK_VERSION}-bin-hadoop${HADOOP_VERSION}.tgz \
    && tar xzf spark-${SPARK_VERSION}-bin-hadoop${HADOOP_VERSION}.tgz \
    && mv spark-${SPARK_VERSION}-bin-hadoop${HADOOP_VERSION} /spark \
    && rm spark-${SPARK_VERSION}-bin-hadoop${HADOOP_VERSION}.tgz

EXPOSE 8080
```

バージョンなどについてはこちらのウェブサイトで確認しました。

http://apache.mirror.iphh.net/spark/

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

services:

  master:
    build: .
    ports:
      - 4040:4040
      - 8080:8080
    command: /spark/bin/spark-class org.apache.spark.deploy.master.Master --host 0.0.0.0

  worker:
    build: .
    depends_on:
      - master
    ports:
      - 8081-8089:8081
    command: /spark/bin/spark-class org.apache.spark.deploy.worker.Worker spark://master:7077 --host 0.0.0.0

```

意外と構築まで時間がかかりました（５分程度）。

`localhost:8080`にアクセスすると、以下のようになっていました。

![Screen Shot 2021-06-29 at 19.29.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396623/d6fa9290-bc01-59ce-0ba0-5cd2079f173b.png)

## コンテナの中に入ってみる

自分のコンテナの名前である`apache-spark-experiment_master_1`で入っています。

```
$ dx apache-spark-experiment_master_1 /spark/bin/spark-shell --master spark://localhost:7077
21/06/29 11:08:35 WARN NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
Using Spark's default log4j profile: org/apache/spark/log4j-defaults.properties
Setting default log level to "WARN".
To adjust logging level use sc.setLogLevel(newLevel). For SparkR, use setLogLevel(newLevel).
21/06/29 11:08:44 WARN SparkContext: Please ensure that the number of slots available on your executors is limited by the number of cores to task cpus and not another custom resource. If cores is not the limiting resource then dynamic allocation will not work properly!
Spark context Web UI available at http://92e2a6cc4096:4040
Spark context available as 'sc' (master = spark://localhost:7077, app id = app-20210629110845-0000).
Spark session available as 'spark'.
Welcome to
      ____              __
     / __/__  ___ _____/ /__
    _\ \/ _ \/ _ `/ __/  '_/
   /___/ .__/\_,_/_/ /_/\_\   version 3.0.3
      /_/

Using Scala version 2.12.10 (OpenJDK 64-Bit Server VM, Java 1.8.0_292)
Type in expressions to have them evaluated.
Type :help for more information.

scala>
```

## scalaを走らせてみる

以下のようにデータの操作を行うことができました。

```
scala> sc
res0: org.apache.spark.SparkContext = org.apache.spark.SparkContext@4fa91d5b

scala> val ds = Seq(1, 2, 3).toDS()
ds: org.apache.spark.sql.Dataset[Int] = [value: int]

scala> ds.show()
+-----+
|value|
+-----+
|    1|
|    2|
|    3|
+-----+

scala> ds.map(_ * 2).show()
+-----+
|value|
+-----+
|    2|
|    4|
|    6|
+-----+
```

Pythonに飽きているので、これからScalaとSparkを使って色々やってみたいです。

## 参考文献

https://qiita.com/hoto17296/items/12366c9f9965ce28a780
font awesomeのアイコンをボタンに入れ込む記述

#はじめに

![スクリーンショット 2021-06-29 19.16.33（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1264460/b4299442-d260-3be5-9717-1691efe8b2a3.png)

このようにヘッダーに投稿ボタンを付けて、クリックすると投稿ページに遷移するようにしました。
少しだけオサレにするために**font awesome**に取得したアイコンも含めてみました。

# font awesomeとは

https://fontawesome.com/

Font Awesomeとはアイコンを文字として扱うことを可能にしたツールです。

自分が使いたい画像などを記述する場合は下記のように記述すると思います。

```.html.erb
<%= image_tag 'icon.png', class:'icon' %>
```

しかし、Font Awesomeはサイト内にある使いたいアイコンをコピペするだけで使えます。

![スクリーンショット 2021-06-29 19.27.49（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1264460/16f8b0bf-1489-f986-bb86-9afb9e275d40.png)

**※登録しないと使えません**

#文字と画像を含めたリンクの仕方

link_to doにしてブロックで囲みました。

```.html.erb
<%= link_to(new_review_path, class: 'post-btn') do %>
   <span class='post-btn-text'>投稿</span>
   <i class="far fa-paper-plane"></i>
<% end %>
```

```
 <i class="far fa-paper-plane"></i>
```

上記の記述はFont Awesomeからそのままコピペしてきました。
後はcssで下線部などを消して整えたら出来上がりです！
GTMとGAを使って、クリックイベントを計測する方法

GTM(GoogleTagManeger)とGA(GoogleAnalytics)を使って、クリックイベントを計測する方法をまとめる。

## クリックイベント使って計測できること
- 外部ページへのリンクがクリックされた回数
    - GAのタグが貼られているだけだと、サイト内のページ遷移しか計測できない
- モーダルが開かれた回数
- 特定のリンクをクリックして、サイト内でページ遷移した回数

## GTMの用語
**タグ**
ページ上で実行されるコードの内容。

**トリガー**
タグを配信する条件やタイミング。タグには必ず1つ以上のトリガーを設定する。

**変数**
タグやトリガーの設定時に使えるサポートツールのようなもの。
例えばPage URLという変数を使って、特定のURLでだけタグが発火するようなトリガーを作ることがでいる。
「組み込み変数(デフォルトで存在する変数)」と「ユーザー定義変数(自分で作る変数)」の2種類がある。

## 設定方法
### 前提
GAやGTMのアカウント登録、タグの埋め込み等ができている。

### トリガーを作成
左メニュー`トリガー`より

- パスが`/articles/[記事ID]`から始まるページで
- `button-hogehoge`というクラスの要素がクリックされた時

という条件でトリガーを作成
![ 2021-06-29 19.28.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244893/c7e4d2e6-7bf2-c8d6-7276-52e41a8f981f.png)

(2021/7/8追記)
1つのDOM要素に複数のclassが付与されている場合、Click Classes部分は「等しい」じゃなくて「含む」としないと発火しないので注意

### タグを作成
左メニュー`タグ`よりタグを作成。`カテゴリ`、`アクション`、`ラベル`は自由に設定でき、設定した値がGA上に表示される。(同じカテゴリのイベントで絞り込んだりできる)

![ 2021-06-29 19.42.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244893/33289a0b-e7dd-2ff5-e2e5-9599ba47e848.png)

### 公開
公開しないと、変更が反映されないので注意
![ 2021-07-02 12.51.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244893/c9683ce0-53a3-f1d8-8010-d01a931ac483.png)


### GAで確認
GoogleAnalyticsにアクセスし、`行動`>`イベント`メニューよりデータを確認することができる。
![ 2021-06-29 19.46.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244893/619b2eaa-67ff-50bf-960c-a623a929427b.png)
Amazon Linux2で、Zabbix5.0を構築してみた

#はじめに

本記事は、Amazon Linux2の環境にZabbix5.0を構築したので、その備忘録として記載したものである。

#Zabbix5.0構築

##(0)OS情報確認

```
$ cat /etc/os-release
NAME="Amazon Linux"
VERSION="2"
ID="amzn"
ID_LIKE="centos rhel fedora"
VERSION_ID="2"
PRETTY_NAME="Amazon Linux 2"
ANSI_COLOR="0;33"
CPE_NAME="cpe:2.3:o:amazon:amazon_linux:2"
HOME_URL="https://amazonlinux.com/"
```

##(1)タイムゾーンを変更

▼現在(デフォルト)のタイムゾーンを確認

```
$ timedatectl
      Local time: Tue 2021-06-29 10:38:20 UTC
  Universal time: Tue 2021-06-29 10:38:20 UTC
        RTC time: Tue 2021-06-29 10:38:20
       Time zone: n/a (UTC, +0000)
     NTP enabled: yes
NTP synchronized: yes
 RTC in local TZ: no
      DST active: n/a
```

▼タイムゾーンを「Asia/Tokyo」に変更

```
$ sudo timedatectl set-timezone Asia/Tokyo
```

▼タイムゾーンの変更後の確認

```
$ timedatectl
      Local time: Tue 2021-06-29 19:38:41 JST
  Universal time: Tue 2021-06-29 10:38:41 UTC
        RTC time: Tue 2021-06-29 10:38:41
       Time zone: Asia/Tokyo (JST, +0900)
     NTP enabled: yes
NTP synchronized: yes
 RTC in local TZ: no
      DST active: n/a
```


##(2)Zabbix5.0をインストール

▼Zabbix5.0のリポジトリをインストール

```
$ sudo yum -y install https://repo.zabbix.com/zabbix/5.0/rhel/7/x86_64/zabbix-release-5.0-1.el7.noarch.rpm
```

▼yumのキャッシュクリア

```
$ sudo yum clean all
```

▼Zabbixをインストールする上で必要なパッケージをインストール

```
$ sudo yum install http://mirror.centos.org/altarch/7/extras/aarch64/Packages/centos-release-scl-rh-2-3.el7.centos.noarch.rpm
$ sudo yum install http://mirror.centos.org/centos/7/extras/x86_64/Packages/centos-release-scl-2-3.el7.centos.noarch.rpm
```

▼Zabbix5.0をインストール

```
$ sudo yum install -y zabbix-server-mysql zabbix-agent mariadb mariadb-server zabbix-web-japanese.noarch zabbix-web-mysql-scl zabbix-apache-conf-scl
```

▼MariaDBを起動

```
$ sudo systemctl start mariadb
```

▼Zabbix用のデータベースを設定

```
$ sudo mysql

MariaDB [(none)]> create database zabbix character set utf8 collate utf8_bin;
MariaDB [(none)]> grant all privileges on zabbix.* to zabbix@localhost identified by 'zabbix';
MariaDB [(none)]> quit;
```

▼データベースにZabbix用のデータを流し込む

```
$ zcat /usr/share/doc/zabbix-server-mysql*/create.sql.gz | mysql -uzabbix -p zabbix
```

▼Zabbix側のタイムゾーンを変更　※末尾に追記

```/etc/opt/rh/rh-php72/php-fpm.d/zabbix.conf
php_value[date.timezone] = Asia/Tokyo
```


▼データベースの接続情報を記載

```/etc/zabbix/zabbix_server.conf
DBPassword=zabbix
```

▼Zabbixの関連サービスを起動&自動起動

```
$ sudo systemctl start zabbix-server zabbix-agent httpd rh-php72-php-fpm && sudo systemctl enable zabbix-server zabbix-agent httpd rh-php72-php-fpm mariadb
```

##(3)WEBで動作確認

①下記のURLへアクセスし、Zabbix側に問題が無いことを確認する。(併せて初期設定を実施)
http://IPアドレス/zabbix

②下記、ログイン情報を入力し、ログのログインができることを確認する。

|ユーザ名|Admin|
|:---|:---|
|パスワード|zabbix|


③ユーザ設定で、言語を「Japanese (ja_JP)」を変更する。(任意)
※今回は、ここまでで作業完了とする。


#最後に

Zabbix5.0をまだ試せていないことが多いので、これから色々と試していこうと思います。
終わり(●´ω｀●)

#参考URL

[Amazon Linux2 Zabbix 5.0 インストール](https://naiggy.blogspot.com/2020/04/amazon-linux-2-ami-zabbix-50.html)
初学者がlaravel 8.x でリクエストフォームを使ってみた

フォームを実装する際にはもれなくついてくるであろうバリデーションをフォームリクエストで実装する方法。
自分用の備忘録です。

##環境
OS: Windows 10 home
CPU: AMD Ryzen 2700X
GPU: NVIDIA GTX 1060
RAM: 16GB 2666Mhz
PHP: ver 8.0.3
Laravel: ver 8.45.1
MySQL(MariaDB): ver 15.1

##1.Requestの作成

```
php artisan make:request ImageRequestt
```
例としてImageRequestを作成。


##2.Requestの中身

```ImageRequest.php
<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

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

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
     return [
            'image' => 'required|mimes:jpg,jpeg,png|max:20480',
            'title' => 'required|min:2|max:100',
         ];
    }
    }
}

```

作成直後では、上記のようになっている。
authorizeメソッドの戻り値は基本的にtrueにしておく。
rulesメソッド内に必要なだけバリデーション内容を記述していきます。


##3.コントローラーの中身

```ImageUploadController.php
<?php

namespace App\Http\Controllers;

use App\Models\Image_upload;
use Illuminate\Http\Request;
use App\Http\Requests\ImageRequest;

class ImageUploadController extends Controller
{
	public function store(ImageRequest $request)
    {
        $newImage = new Image_upload();
        $newImage->title =$request->input('title');
        if($request->hasfile('image')){
            $file = $request->file('image');
            $extention = $file->getClientOriginalExtension();
            $filename = time().'.'.$extention;
            $file->storeAs('public/images',$filename); 
            $newImage->image = $filename;
        }
        $newImage->save();

    }

}

```

ImageRequestクラスが使えるよう冒頭に名前空間とクラスを足したuse宣言を記述しておきます。

```
use App\Http\Requests\ImageRequest;
```
次にstoreメソッド内のタイプヒントでImageRequestクラスを指定します。

```
public function store(ImageRequest $request)
```
これでstoreメソッドでは、ImageRequestで定めたrulesメソッドに基づいて入力された値をバリデートすることが出来ます。
Nuxt.js　リダイレクト設定

/before　→ /after へリダイレクト させたい場合

```/plugins/redirect.js
export default ({ route, redirect }) => {
  if (route.name === 'before') {
    redirect('/after')
  }
}

```

```nuxt.config.js
plugins: [
  { src: '~/plugins/redirect' }
]
```
S3静的webサイトへのアクセスをCloudFront経由のみに制限する

CloudFrontのOrigin Custom HeaderとS3バケットポリシーを設定していきます。
CloudFront経由時のみに付加されるヘッダーを利用してバケットポリシーで制御する、という仕組みです。

#前提条件

今回の記事は、CloudFrontのOriginをS3の静的ホスティングエンドポイントに設定している場合について言及しておりますのでご注意ください。URLに「website」がついてる方です。

CloudFrontのOriginの指定先

```
○ http://bucket-name.s3-website.Region.amazonaws.com
× http://bucket-name.s3.Region.amazonaws.com
```
単なるS3オブジェクトの場合はこちらの記事が役に立つと思います。

https://qiita.com/NaokiIshimura/items/46994e67b712831c3016

#CloudFrontにOrigin Custom Headersを設定する

###該当DistributionでOrigins and Origin Groupsを選択
![スクリーンショット 2021-07-21 19.07.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/726987/1ec26097-69bf-2b94-88bd-ffae2d5177b8.png)


###Origin Custom Headersにヘッダー情報を入力
![スクリーンショット 2021-06-29 18.09.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/726987/411b190f-d9d0-25ec-ddde-2ed887277898.png)



Header Name：Referer
Value：cf（任意の値）

#バケットポリシー
「パブリックアクセスをすべてブロック」がオフになっていることを確認してください。オフになっていないとバケットポリシーが適用されません。
![スクリーンショット 2021-06-29 18.29.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/726987/71c1b81d-137e-eb42-0749-de52449a0389.png)


###バケットポリシーの例
Refererヘッダーに"cf"が入っている場合のみアクセス許可

```json
{
    "Version": "2008-10-17",
    "Id": "PolicyForCloudFrontPrivateContent",
    "Statement": [
        {
            "Sid": "Referer-Allow",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::（バケット名）/*",
            "Condition": {
                "StringLike": {
                    "aws:Referer": "cf"
                }
            }
        },
        {
            "Sid": "Referer-Deny",
            "Effect": "Deny",
            "Principal": "*",
            "Action": "s3:*",
            "Resource": "arn:aws:s3:::（バケット名）/*",
            "Condition": {
                "StringNotLike": {
                    "aws:Referer": "cf"
                }
            }
        }
    ]
}

```

この設定をしている状態で、各アクセスしてみると、

・bucket-name.s3-website.Region.amazonaws.com
→403エラー
・xxxxxxx.cloudfront.net
→アクセス可能

となるはずです。
リーダブルコードのまとめ

#はじめに
本記事は、リーダブルコード（著：DustionBoswell,TrevorFoucher）を筆者なりに簡単にまとめたものです。丸コピなどはしてません。

#名前に情報を詰め込む

名前を見ただけで、その変数や定数の情報が読み取れるようにする。

- 明確な単語を選ぶ。例えばGetではなく、場合によってはFetchやDownloadが好ましい。
- tmpなどの汎用的な名前は、特段の理由がなければ使用しない。
- 具体的な名前を使って、物事の詳細を説明する。（ex.CanListenOnPort()）
- 変数名に大切な情報を追加する。例えば、_msとして単位を明らかにする
- スコープの大きい変数には長い名前をつける。
- 大文字やアンダースコアに意味を含める。

#美しい一貫性のあるコードの整形をする

- 複数のコードブロックで同じようなことをしていたら、シルエットも同じようにする。（改行位置などは特に意識すること）
- コードの列を整列して、概要を把握しやすくする。
- 並び順は必ず一貫性を持たせる。（一方でA,B,Cとなっていて、他ではC、B、AはNG）
- 空行を使って大きなブロックを論理的な段落とする。

#コメントすべきことを知る

- コードを読んだ人が「ん？どういうこと」と思うところを予想してコメントする。
- 読み手が驚くような動作は文書化
- ファイルやクラスには全体像を描いておく
- 読み手が細部にとらわれないように、コードブロックにコメントをつけて概要をまとめる

#コメントは正確に簡潔に

小さな領域にできる限り詳細な情報を詰め込むためのコメントの記述の仕方についてまとめる。

- 複数のものを指す可能性がある場合は、「それ」や「これ」などの代名詞を避ける。
- 関数の動作はできるだけ正確に説明し、コメントに入出力例を記述する。
- コードの意図は詳細レベルではなく、高レベルで記述する。
- よくわからない引数にはインラインコメントを使う。
- 多くの意味が込められた言葉や表現を使って、コメントを簡潔に保つ。

#制御フローを読みやすくする

- 比較を書くときは変化する値を左に、安定的な値を右に配置する
- if/else文のブロックは定説に並び替え、一般的には肯定形や単純なもの、目立つものから処理しておく。
- 三項演算子やdo/whileループなどのプログラミング構成要素を使うとコードが読みにくくなることがあるので気を付ける。
- ネストが深いと読みづらいので、早めに返したり、ネストを削除するように努める。

#巨大な式を分割する

巨大な式の取り扱いについてまとめる。

- 説明変数を導入することで、式の分割をし、簡潔な名前で式を説明することができる。また、コードの主要な概念を読み手が意識しやすくなる。
- ド・モルガンの法則を使って、論理式を読みやすい形に書き直す。

#変数と読みやすさについて

変数が増えるとコードは読みにくくなる。変数をできるだけ減らして、できるだけ軽量にすればコードは読みやすくなる。

- 邪魔な変数は削除する。例えば、中間結果の変数は削除する。
- 変数のスコープをできる限り小さくする。
- 一度だけ書き込む変数を使う。

#その他

- プロジェクト固有のコードから汎用コードを分離することで、無関係の下位問題を抽出する。
- 一度に1つのタスクを行うという考え方を意識して、各タスク分割する。
- おばあちゃんに説明して理解してもらえるレベルまで言語化する。プログラム内のタスクを簡単な言葉で列挙してみる。
- 最も簡単に課題が解決できる方法を考える。
Google ColabでCUDAとtorchのバージョンを変更する。

## 背景
Google Colaboratory(略称:Colab)では、基本無料でnotebook形式の処理を実行できます。必要なパッケージやGPUでの計算などもできるため簡単に充実した環境を用意できる一方で、インストールされているソフトやパッケージのバージョンがGoogleの意思次第で変わることがあります。
ここでは、意図せずに変わってしまったCUDAとtorchのバージョンに悩まされることなく環境を整備する方法をまとめます。

##執筆時の環境と変更先
CUDA:11.0  -> 10.1
torch:1.9.0+cu102  -> 1.8.0


##ソースと解説

#### CUDAとtorchのバージョンを確認します。

```py
!nvcc --version
```
nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2020 NVIDIA Corporation
Built on Wed_Jul_22_19:09:09_PDT_2020
Cuda compilation tools, release 11.0, V11.0.221
Build cuda_11.0_bu.TC445_37.28845127_0

```py
!python -c 'import torch; print(torch.__version__) '
```
1.9.0+cu102


#### 変更可能なCUDAのバージョンを確認します。

```py
!ls -d /usr/local/cuda-*
!which nvcc
```
/usr/local/cuda-10.0  /usr/local/cuda-10.1 /usr/local/cuda-11.0  /usr/local/cuda/bin/nvcc

#### CUDAのPATHを変更し、変更されたことを確認します。

```py
import os
p = os.getenv('PATH')
ld = os.getenv('LD_LIBRARY_PATH')
os.environ['PATH'] = f"/usr/local/cuda-10.1/bin:{p}"
os.environ['LD_LIBRARY_PATH'] = f"/usr/local/cuda-10.1/lib64:{ld}"
!nvcc --version
```

nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2019 NVIDIA Corporation
Built on Sun_Jul_28_19:07:16_PDT_2019
Cuda compilation tools, release 10.1, V10.1.243

#### torchのインストール

インストールには公式の推奨方法を確認してください。
使いたいバージョンによって入れ方が変わる場合があります。
(本記事のように、torchだけでなくtorchvisionやtorchaudioも合わせて入れる場合がある)

https://pytorch.org/get-started/previous-versions/

```py
!pip install torch==1.8.0 torchvision==0.9.0 torchaudio==0.8.0
```

Requirement already satisfied: torch==1.8.0 in /usr/local/lib/python3.7/dist-packages (1.8.0)
Requirement already satisfied: torchvision==0.9.0 in /usr/local/lib/python3.7/dist-packages (0.9.0)
Requirement already satisfied: torchaudio==0.8.0 in /usr/local/lib/python3.7/dist-packages (0.8.0)
Requirement already satisfied: numpy in /usr/local/lib/python3.7/dist-packages (from torch==1.8.0) (1.19.5)
Requirement already satisfied: typing-extensions in /usr/local/lib/python3.7/dist-packages (from torch==1.8.0) (3.7.4.3)
Requirement already satisfied: pillow>=4.1.1 in /usr/local/lib/python3.7/dist-packages (from torchvision==0.9.0) (7.1.2)

#### torchの確認とassert
```py
import torch, torchvision
print(torch.__version__, torch.cuda.is_available())
assert torch.__version__.startswith("1.8")
```
1.8.0 True

以上で、CUDAとtorchの環境設定が完了し変更後のバージョンで実行するはずです。
【講義07.sql基礎】データベースの命名規則について学んだことのまとめ

#本記事について
今後のデータベース設計時の参考になればと思い、データベースの命名規則について、講義内容や現職での体験をまとめたもの。
読みやすくメンテナンスしやすいコードを書くため、開発プロセスを効率良く進めるヒントとなることを目的とする。

##データベースの設計・命名で一番大切なこと
何のために何に使うのか「目的」を持つこと。
そのカラムやテーブルが何をしているか分かる名前にする。
とりあえず使うかもしれない、あったらいいなでカラムを作成することや、とりあえずで命名すると後で集計などを行う際に自分に跳ね返るので注意。

##記号を使用しない。以下の記号は使用不可。
| 記号 | 名称 | 記号 | 名称 |
|:-|:-|:-|:-|
| ! | 感嘆符 | ‘ | シングルコート |
| “ | ダブルコート | ()「」{} | 括弧 |
| # | 番号記号 |*| アスタリスク |
| $ | ドル記号 | , | カンマ |
| % | パーセント | :; | コロン，セミコロン |
| ¥ | 円記号 |　/　| 斜線 |
| @ | 単価記号 | . | ピリオド |
| ? | 疑問符 | - | ハイフン |
| ~ | チルダ | | |

##複数単語からなる場合は，「_」 で区切る。数字(連番)は使用しない。
悪い例では、電話番号と携帯番号など類似した値で複数のカラムが存在するものを定義しようとしている。
しかし、カラム名＋数値の命名では値を確認しなければならず、どちらが何を意味しているか判別がつかない。
　　良い例)customer_name
　　悪い例)tel01、tel02
 
##英語と日本語を混在しない
英語と日本語が混在すると作成者しか理解できないケースが発生するため。
悪い例ではkokで顧客の意味を持たせている。
　良い例)customer_cd
　悪い例)kok_cd

##テーブル名、カラム名に大文字を利用しない
言語により、大文字小文字を区別するもの、しないものがあるため小文字で統一する。

##その他
おすすめしない命名
～flg
例）削除フラグ (delflg)
値を0,1（または1,2)で持つため、削除フラグの場合は1が削除なのか、0が削除なのか、判別がつかない。
削除されたか？（deleted）や、削除された日(delete_date)を推奨。

以上。
powershellでファイル内容を比較

自分用メモ。詳しくは[公式ドキュメント](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/compare-object?view=powershell-7.1)へ。

# Compare-Objectコマンドでファイル内容を比較

powershellで、2つのファイルの内容を比較したいときは次のように書く。

```powershell:
> Compare-Object (Get-Content fileA.txt) (Get-Content fileB.txt)       


InputObject SideIndicator
----------- -------------
AAA         =>
BBB         <=
DDD         <=
```

# エイリアスを利用
`Compare-Object`は`diff`、`Get-Content`は`cat`がエイリアスとして利用できる。
Linuxっぽく書けるが、`cat`が必要であることに注意。

```powershell:
> diff (cat .\fileA.txt) (cat .\fileB.txt)


InputObject SideIndicator
----------- -------------
AAA         =>
BBB         <=
DDD         <=
```

# `Get-Content`しなかった場合
`Get-Content`しないと、単に`fileA.txt`と`fileB.txt`が文字列として比較される。

```powershell:
> Compare-Object fileA.txt fileB.txt                            


InputObject SideIndicator
----------- -------------
fileB.txt   =>
fileA.txt   <=
```
PMP(第6版、アジャイルたっぷり版）オンライン受験感想記

# 受験のきっかけ

元々2019年に申し込みだけして後は場所と受験日を選ぶ状態って時に転職が決まり、次の仕事ではPMっぽいことやらないだろうと思って放置していたんですよ。
1年以上経ってもう期限も切れたろと思っていたところ、コロナ等で受験可能期限が6/30まで伸びてるようなメールが来てて、ちょうど仕事でもPMOの話が来ていたので、せっかくなので受験しようと思い立った感じでした。


# 準備期間
問題の出題傾向が変わり、以前のような１５０時間くらい勉強しないと受からない、という感じではないように感じました。
実務でしっかりアジャイルやPMの方法論に取り組んでいる人はそれ程いらない感じがします。
自分の場合はWFは７，８年、アジャイル(スクラム)で3年程度PM(SM)っぽいことをやってましたが、ここ2年くらいはPMじゃなくなったので、思い出しのための期間がそれなりに必要でした。
実勉強期間は6/1〜6/29、総時間は60時間弱です。

# 勉強方法
以下の教材を利用しました。

+ 前職時に貰った模試 250問
+ [Udemyの模試](https://www.udemy.com/course/pmp-test-prep/)
+ [プチまなのPMP試験 合格編](https://pmana.jp/pc/student.php?mode=view_kentei&kentei_gid=4343)

結果としてはほぼ役に立たなかった気もするのですが、、、一応以下勉強方法です。
1日目：Udemyを解き、弱点がまんべんなくあることを理解（正答率は53%）
2日目〜4週目：プチまなを一通り実施、Udemyも週1で再試験（正答率は95,97,95%）
2週目くらいに前職で貰った模試も実施。こちらも正答率は最初は低く64%くらいの正答率。
直前：前日にやれる模試を全部再実施。とりあえず自信をつける。
最終的には正答率はどれも95%程度まで行きました。

# 準備
## 場所
部屋はごちゃごちゃしてるリビングで実施。以前CKA、CKAD受けた時も大丈夫だったから大丈夫だろうと思って選んだが、特に何も言われず。
テーブルに物を置いていなければいける気がします。

## PC
会社から借りてるPC(MacBookPro)を利用しました。
私物のノートPCはLinuxなんですが、Linuxは「厳禁」との制約がピアソンのWebに載ってたのでやむなく。
会社のPCだとVPNやセキュリティソフトが悪さするんじゃないか不安だったんですが、会社の人でピアソンでの受験者が既におり、自環境での事前テストも問題なかったので強行（後でこれでトラブルが。。。）
その他準備すべきこととしては、アプリの準備とどのプロセスを落とすか決めておくことくらいでしょうか。
会社の人でPMPではないですがピアソンで、OneDriveを終了してもバックグラウンドでプロセスが生きてて受験に失敗した話を聞いていたので、心配性な人はpsコマンドなどで確認した方がいいかとは思います。

# 本番
ログイン可能時間にピアソンにログインすると、表示画面が変わって試験へ進めるようになってます。
スマホで部屋の写真と自分の写真、免許証の写真を撮影してupload。
その後に試験官（中国の方だったが、日本語は出来る人）が出てきて、免許証の再提示および部屋のカメラ撮影を要求されたので、指示に従い実施。
この後試験官がテストデータを送ってくれるのですが、ここでトラブル。
クリックしても激重でチャットも入力できなくなり、試験がまともに出来ない状態に。
試験データが起動されるタイミングでOnVUEのアイコンが３つくらい表示されておかしな状態になってたので、上手く起動しなかった気がする。
とりあえず画面越しに手で✗マークを送ってピンチを伝えると電話が掛かってきて、Macを強制再起動してくれとのことだったので、再起動を実行。このタイミングで１５分経過しててちょっと焦りだす。
再起動後、やっぱりOnVUEが２つ起動してておかしな状態。チャットも激重のままだが試験画面のクリックは軽くなったのでチャットは無視して試験開始。
ホワイトボードや電卓は激重のままで、活用する問題が多かったらどうしようとヒヤヒヤでした。

# 試験の内容
6版が'21/1/2に改定されて、今までの知識体系での区切りから人、プロセス、ビジネス環境での区切りと変更されています。
試験内容はというと、PMBOKは変わっていないので出題範囲は変わっていないのですが、比率が大きく変わりアジャイル系の問題が多く、ハイブリッドと合わせると体感で7割くらいになってます。
計算問題はほぼなし。EVMについて問われる問題があるものの、脳内でどうにか出来るレベル。EAC系の計算が無敵になってたのに、全然要らなかった。。。。
あと複数選択の問題やマッピング問題が結構ありました。
表現の仕方に癖があり、恐らくPMBOKと違う言葉で出てたので言葉よりも意味をしっかり覚えておく必要があるかと。
※ちなみに勉強時にPMBOKは一度も使いませんでした。なので言葉が本当に違うかは分かりません。
あとITTOはしっておいて損はなかったかなと。数は少ないですがスコアは稼げた気がします。

# 試験後
見直し終了を押すと即結果が出ます。
合格していれば日本語で「おめでとうごさいます」的なものが出ます。
この後アンケートに答えてアプリを終了したら、OnVUEのアイコンが１０個以上並んでるのが見えて、そのままハング。。。。
マシン再起動しましたが、数分後にピアソンからメールが来て、無事合格がピアソン側からも確認できるようになりました。
スコアは
People：Target
Process：Above Target
Business Environment：Needs Improvement
で、全体スコアはTargetの上位の方でした。
Processの比率が多かったのかもしれません。

# 試験を終えて
## 試験勉強
前職でアジャイルを導入する立場で、どうやったら管理職の人に理解してもらえるかとかを考えていたので、運良く合格できましたが、やってなかったら死んでました。
やった教材で役立ったのはプチまなのアジャイル関連部分くらいでした。
（ただしDADは出ず、スクラムとハイブリッドの話がほとんどでした。LESS,SAFe,XPなども出ず）
今から勉強する人は模試とかやるよりはアジャイルサムライやアジャイルブートキャンプとかの有名な本を読む方がよいかと思われます。
おそらく第７版も似たような傾向にはなるかと思われます。

## 試験環境
しびれました。
恐らくMacよりはWindows、かつ会社のではなく個人ので受けるのが間違いないです。
まだピアソンのオンライン受験は始まって間もないので、技術的に安定するのも時間が掛かるかと思ってます。
私のように事前テストで上手く動いていても、本番では上手く動かないこともあるので、不安な方は代替機の準備等も念頭に入れておいた方がいいかと思います。
Qt for Windowsのアプリを相手にRPAするときのちょっといい話（＝バッドノウハウ）

# RPAは技術的負債のバイバイン

　操作されるアプリの開発者としては、RPA friendlyにするより先にAPIを用意するでしょ常識的に考えて。APIのないところを無理やり強行突破するのがRPA。
　どんな世の中でも、こういう協調性ゼロの行為には、それなりの代償が伴う。
　協調的な開発（APIを使う普通のスタイル）が手数$n$に対して$a*n$の技術的負債を生むとすると（本当？）、RPAのような強行突破は、$a^n$の技術的負債を生む。
　技術的負債で破産する前に職場からトンズラする用意はOK?

# Qt for Windowsはカスタムドローだらけ

　カスタムドローのコンポーネントはUI Automationなどでは操作できない。そこでpyautoguiなどのスクリーンショット＋画像テンプレートマッチングを使って、いかにもRPAらしく強行突破するわけだが、数時間で早くもバッドノウハウを2つ発見したので、ここに記す。

## 操作したいウィンドウを最前面に持ってくる方法

　ずっと前から慣れっこになってしまっていて急には思い出せないかもしれないが、Windowsには昔々からずっと、「ウィンドウを最前面に持ってくる」という動作にバグがある。
　たとえば、タスクバーに出ている動作中アプリのアイコンをクリックしても最前面に出てこない場合があることを、どうか思い出していただきたい。そんなときは脊髄反射でAlt+TabするのがWindows使い。あまりにも長いこと体に染み付いた動作なので、いまさら意識するのは難しいかもしれない。
　スクリーンショットをキャプチャするときには、操作相手のウィンドウを最前面に持ってこなければならないので、このバグを回避する必要がある。[PyGetWindow](https://pypi.org/project/PyGetWindow/)なら以下のとおり。

```python
import pygetwindow as gw
w = None
for t in gw.getAllTitles():
    if 'Foo Bar' in t:
        w = gw.getWindowsWithTitle(t)[0]
        break

# bug workaround
w.minimize()
w.maximize()
```

　最小化して最大化する。以上。

## Qt for Windowsのカスタムドローコンポーネントにクリックを認識させる方法

　`pyautogui.moveTo()`でマウスポインタを動かして`pyautogui.click()`でクリック…　では、たいていクリックを認識してくれない。
　Qt for Windowsの実装を調べていないので推測だが、「マウスポインタを高速で動かしている最中のクリックは誤入力として弾く」という機能があるのではないか。`pyautogui.moveTo()`で遠くから一発でクリック反応領域に飛び込んでくる、という動きに対しては、この機能が働いているのではないか。
　というわけで、人間が狙って操作しているらしいマウスポインタの動きを偽装する必要がある。クリックする地点がx, yとして、

```python
pyautogui.moveTo(x - 2, y)
time.sleep(0.1)
pyautogui.moveTo(x - 1, y)
time.sleep(0.1)
pyautogui.moveTo(x - 0, y)
time.sleep(0.1)
```

　以下なにかまた見つけたら追記する。
Git, GitHub, source tree _part 1

##Gitとは何か？

プログラムを作る時、あるいは作られたプログラムを運営する時に修正することになる。 
しかし、そのような過程の中で、以前作った機能を持ってきたい場合が発生したり、復旧したい場合が生じる。 
そして、誰かがミスをしたことがあるのか過去の内訳を確認しなければならない時もある。 
そのため、途中で保存しなければならないが、圧縮してそれぞれの状態を保存していると、後で探すのも難しく、容量も多く消耗するようになる。 

それに加え、プロジェクトの進行において協業をする場合が多いのですが、 
Gitというバージョン管理ツールがそのような役割をしてくれると考えると簡単である。 

Gitは、カミットする瞬間を保存しておくが、全てをコピーするのではなく、変更された事項を記録することである。
そのため、容量をあまり取らず、修正された内訳を復旧することもできる。 

加えて作業しているものから別のバージョンを作って進行できるようにBranchという枝切り作業ができる。 
枝(branch)を通して様々な試みを進め、主要作業ラインに枝(branch)で作った機能を追加することもできる。 

コードを過去の視点に回すこともできる機能があり、協業の過程でも有用に使われる。 

Eclipse を使うときは、少し方式が異なり、まずはVSCode ベースで使う方法を説明する。
Eclipseでの使い方は、http://gasaesososo.tistory.com ブログで説明がとても上手だった。

http://git-scm.com/
サイトに入ってgitを自分のコンピューターに合うものを選んでダウンロードすれば良い。 

VSCodeを実行してワークスペースを作った後、ファイルを生成してくれる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1465875/f4ab5634-d086-0055-a172-c2f2bff0a2a2.png)

その後、ターミナルを開いてくれる。 [ ctrl + ` ]
コマンドのpwdを書くと、現在のターミナルの経路を教えてくれる。 
>gitconfig--global user.name "自分の名前"
>git config --global user.email "自分のEメール"
ワークスペースの位置でなければ、cdを書き込んで現在のフォルダーの位置に移動させてくれる。
それからgit statusと入力すると「not a git repository (or any of the parentdirectiories)」と表示されるが、gitリポジトリがないことを示している。 
そのため、「git init」を使ってリポジトリを作ってくれる。
すると、Initialozed empty Gitrepository in_現住所が表示されることで作られることが確認できる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1465875/a4f1019a-1f13-1856-a191-146f172b7f21.png)
> pwdで確認すると、pathがユーザまでであることが分かる。
CDを使って現在のワークスペースの経路に移動
ファイルエクスプローラで位置アドレスをコピペしても良いし..DesktopComputerStudyGitTest このような方式を使っても良い.
> git statusで確認
> git initでgitリポジトリを作成
ここまで来たら、「git」を通じてファイルを管理することができるようになった。

今日はここまで、、、
Slackで自分の代わりに自動投稿する方法（PHP編）

# 準備
以下の１～３を行えば、10～30分程度で実装できるはずです。

# その１：OAuth Access Token入手のためのSlack Apps準備
こちらの「OAuth Access Token入手のためのSlack Apps準備」の1~7の項目を実施します。
https://dev.classmethod.jp/articles/slack-schedule-message/#toc-4

# その２：必要項目
- OAuth Access Token ・・・xoxpから始まるコード[1]
- 投稿先のチャンネル名 [2]
- 投稿したいメッセージ [3]

# その３：以下の[1]～[3]に代入
```php:test.php
define('SLACK_SCHEDULED_MESSAGE', 'https://slack.com/api/chat.postMessage'); // 予約メッセージ機能のURL(共通部分のため変更不要)

// 設定項目[全部で3つ]
define('USER_OAUTH_TOKEN', 'xoxp-aaaaaaa-bbbbb-ccccc-dddd'); // [1]トークンを記載(xoxpで始まるトークン)
$channel = '#general';   // [2]チャンネル名を記載(例：#random, 営業部, など)

// [3]メッセージ内容を記載
$message = <<<EOT
おはようございます、勤務開始。
EOT;

// ※以下、共通プログラムのため変更不要

// ヘッダーに追記します
$headers = array(
    'Authorization: Bearer ' . USER_OAUTH_TOKEN,
    'Content-Type: application/json; charset=utf-8',
);

// POST送信するデータを格納します
$data = json_encode(array('channel'=> $channel, 'text' => $message));

$curl = curl_init(SLACK_SCHEDULED_MESSAGE);
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
curl_exec($curl);
curl_close($curl);
```
JavaScriptでcsvダウンロードを実装する方法


#はじめに
フロント(React)でcsvダウンロードを実装する機会があったため、備忘録です。
どうぞご活用ください。

#実装

```javascript

  const handleDLcsv = async () => {
    //アイテムの定義
    const download_items = [
            {'id': 1, 'name': 'apple', 'price': 100},
            {'id': 2, 'name': 'orange', 'price': 120},
            {'id': 3, 'name': 'melon', 'price': 800}
    ];
    //csvヘッダー
    const array_data = [['id', 'name', 'price']];

    //文字コード
    const bom = new Uint8Array([0xEF, 0xBB, 0xBF]);

    //csv用データ作成
    download_items.map((item) => {
      const item_data = [item.id, item.name, item.price];
      array_data.push(item_data);
    })
    let csv_data = array_data.map(function(l){return l.join(',')}).join('\r\n');

    //BLOB生成してダウンロード実行
    const blob = new Blob([bom, csv_data], { type: 'text/csv' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = 'csv_file.csv';
    const clickHandler = () => {
      setTimeout(() => {
        URL.revokeObjectURL(url);
        a.removeEventListener('click', clickHandler);
      }, 150);
    };
    a.addEventListener('click', clickHandler, false);
    a.click();
  }

```
sakuraエディタの便利な使い方

#はじめに
自分が便利だと思った使い方を随時更新します。

#入力言語を設定する
設定＞タイプ別設定一覧
該当の言語を選んでダブルクリック

ctrl + 4　でもこの画面開ける

#おわりに
随時更新します。
JavaScriptの論理演算子 && ||の意味

If文の条件でよく使う&&や||ですが、こんな使われ方もあるのかと思いまとめてみました。

##条件式を省略し使用できる
- &&  
**左側がtrueの場合右側を返します。**左側がfalseならそのまま左側を返します。
- ||  
**左側がfalseの場合右側を返します。**左側がtureならそのまま左側を返します。  
なのでIf文を書かずに条件式として使用できます。

```javascript
console.log(true && false)
=> false

// 1はtrueなので右側の結果が返る
console.log(1 && 0);
=> 0

console.log(false || true)
=> true

// nullはfalseなので右側の結果が返る
console.log(null || 1);
=> 1

```

###上記のような特徴から&& ||は結果的に且つ、またはという意味になる

```javascript
const aa = true
const bb = true

if (aa && bb) {
  console.log("どちらもtrue");
}
=> "どちらもtrue"
```
左側のaaがtrueなので右側の結果を返します。右側のbbもtrueになるので、最終的にtrueが返り条件式が読まれます。
仮にaaがfalseだとすると、&&はfalseを返すので、結果的に且つという意味になります。

```javascript
const aa = false
const bb = true

if (aa || bb) {
  console.log("どちらかがtrue");
}
=> "どちらかがtrue"
```
左側のaaがfalseなので右側の結果を返しtrueになります。
仮にaaがtrueであっても||は左側の結果を返しtrueになるため、またはという意味になります。
Retrofit2でRxJava2からRxJava3に変更したときの注意点

Retrofit2 で RxJava を使用する場合、 Retrofit2 標準の Factory を使うと思いますが、 RxJava2 と RxJava3 の Factory の create 関数で出来上がるものが同期、非同期が逆になっています。 注意しましょう。

リリースノートにもちゃんと記載がありますね。

https://github.com/square/retrofit/blob/master/CHANGELOG.md#version-290-2020-05-20


### RxJava2CallAdapterFactory
```java
  /**
   * Returns an instance which creates synchronous observables that do not operate on any scheduler
   * by default.
   */
  public static RxJava2CallAdapterFactory create() {
    return new RxJava2CallAdapterFactory(null, false);
  }

  /** Returns an instance which creates asynchronous observables. */
  public static RxJava2CallAdapterFactory createAsync() {
    return new RxJava2CallAdapterFactory(null, true);
  }
```

https://github.com/square/retrofit/blob/master/retrofit-adapters/rxjava2/src/main/java/retrofit2/adapter/rxjava2/RxJava2CallAdapterFactory.java#L62-L66


### RxJava3CallAdapterFactory
```java
  /**
   * Returns an instance which creates asynchronous observables that run on a background thread by
   * default. Applying {@code subscribeOn(..)} has no effect on instances created by the returned
   * factory.
   */
  public static RxJava3CallAdapterFactory create() {
    return new RxJava3CallAdapterFactory(null, true);
  }

  /**
   * Returns an instance which creates synchronous observables that do not operate on any scheduler
   * by default. Applying {@code subscribeOn(..)} will change the scheduler on which the HTTP calls
   * are made.
   */
  public static RxJava3CallAdapterFactory createSynchronous() {
    return new RxJava3CallAdapterFactory(null, false);
  }
```

https://github.com/square/retrofit/blob/master/retrofit-adapters/rxjava3/src/main/java/retrofit2/adapter/rxjava3/RxJava3CallAdapterFactory.java#L62-L69
なーんだVuexのstateってmutation以外でも変更できるんだ。という話。

**stateをmutation以外で変更しない方がいい理由に「バグに繋がりやすい」しか知らないので、もし他にも理由があるよ！って方がいましたらコメントでご教授してくれると嬉しいですm(_ _)m**

***

タイトル通り、Vuexのstateをmutation以外でも変更できる方法があることを知りました。

その方法が、`this.$store.state`を使って、stateの情報を取得することです。

例えば、下記のようにすれば、inputフィールドに値を入力すると、自動的にstateの`user.name`も変更されることになる。

```vue
<template>
  <input type="text" v-model="user.name">
</template>

<script>
  export default {
    created() {
        this.user.name = this.$store.state.user.name;
    },
  }
</script>
```

ただ、これは**非推奨**なやり方。

このようにしてしまうと、どこでstateの値が変更されているのか意味不明になってきて、よきせぬ挙動を起こす可能性があるので、よくない。

stateはちゃんと`getter`を利用して取得。変更するときは`mutation`を利用する。

ってことを、ちゃんと守ろう。

まぁ、個人でやる分にはいいのかもしれません。。。多分。
１８．ネストしたリストの内包表記の理解

本記事を読む前にpythonチュートリアルをご参照ください。

https://docs.python.org/ja/3/tutorial/datastructures.html

上記は5.1.4. ネストしたリストの内包表記についてまとめられています。

python3エンジニア認定基礎試験の模擬サイトにこのような問題が出題されました。

```
19問目　
次の実行結果を得たい場合に、コードの【A】に入るものとして正しいものはどれか。

[実行結果]
[5, 25, 125]

[コード]
matrix = 【A】
power = [row[2] for row in matrix]
print(power)
```

まずは全体的な特徴を理解しましょう。
リストとは[]のこと。これらに数値を入れて、カンマで区切ります。
ここでイメージすることは、3×３の表です

row[2]っていうのは、リストでイメージした表の列を０，１，２としていると考えましょう。つまり、正解例は

```
正答: [[2, 3, 5], [4, 9, 25], [8, 27, 125]]
```

である。まとめると

```python
matrix = [[2, 3, 5], [4, 9, 25], [8, 27, 125]]
power = [row[2] for row in matrix]
print(power)
```

もし仮に
`[row[1] for row in matrix]`だったら真ん中の数が出てくる。
この問題の考え方は、リストの表の３列目が5,25,125となるのはどれかというものだ。このポイントを抑えればこの問題はすんなり解ける。
自作(制御)コンポーネントにReact Hook Formでバリデーションをかける


## やりたい事

React Hook Form を使って自作(制御)コンポーネントにバリデーションをかける。

## やり方

テキストを入力する以下のようなコンポーネントを作成する。

```React
import React from 'react';

type Props = {
  onChange: (value:string) => void
  value: string
}

const TextInput:React.VFC<Props> = ({onChange, value}) => {
  return (
    <div>
      <input type="text" onChange={(event)=> onChange(event.target.value)} value={value}/>
    </div>
  );
};

export default TextInput;
```

以下のようにReact Hook Form が用意してくれている Controller というラッパーコンポーネントを利用する。テキストを入力しない状態で送信ボタンをクリックすると入力必須というエラーメッセージが表示されるのが確認できると思います。

```React
import React from 'react';
import TextInput from "~/components/TextInput"
import { useForm, Controller } from "react-hook-form"

const input = () => {
  const { handleSubmit, control, formState: {errors} } = useForm({
    mode: 'onChange',
    defaultValues: { name: ''}
  })

  return (
    <div>
      <h2>フォーム</h2>
      <form onSubmit={handleSubmit(data => console.log(data))}>
        <Controller
          control={control}
          name='name'
          render={({ field: { onChange, value } }) => (
            <TextInput value={value} onChange={onChange} />
          )}
          rules={{ required: '入力必須です！！' }}
          defaultValue=''
        />
        <p>{errors.name?.message}</p>
        <input type="submit" />
      </form>
    </div>
  );
};

export default input;

```


## 参考にした記事

バリデーションにreact-hook-formが便利だった
https://qiita.com/282Haniwa/items/20ecd8addd1517cd622e

React Hook Form Controller
https://react-hook-form.com/api/usecontroller/controller
1週間RealmSwiftを勉強してわかった事 Part1

# RealmSwiftについてわかった事

* Realmについて  
  * ios,Androidアプリで使えるのクロスプラットフォームモバイルデータベース! ...らしいです。
  * 保存するデータが増えても、パフォーマンスへの影響が少ない！　

## Realmを使う為に(インストール編)
私はCocoaPodsを使用して、Realmをインストールしています。
1.XCodeでプロジェクトを作成して、一度閉じます。
2.ターミナルで`cd`の後に作成したプロジェクト名を入力するか、ドラッグ&ドロップしてEnterします。
3.その後`pod init`を入力してEnterすると、プロジェクトファイルにPodfileが作成されます。
4.Podfileを開いて、`pod 'RealmSwift'`を入力して閉じる
5.ターミナルで`pod install`を入力してEnterします。
6.インストールが始まりますので、完了するまで待ちます。
7.インストールが完了したら、ターミナルに`exit`を入力して閉じます
8.プロジェクトファイルに白のxcworkspaceが出来ているので、開いて作業開始です。

## 今回はここまで
* 次回
 * Modelの作成
 * CRUDのC(Create) について書きます　

初めて投稿なので、練習のつもりで書きました。
次から、もう少しプログラミングらしい内容を書きます。書き方の勉強も必要ですね泣
(多分、自分しか見ないし気にしなくても良いかも？)
分類モデルの評価-混同行列(Confusion Matrix)と関連指標

## 正解率(Accuracy)

正解率は、全体に対して予測が当たった割合です。

正解率が評価指標として適切でない場合があります。
例えばスパムメールの分類です。
99%のメールは本物、1%のメールはスパムだと仮定すると、全てのメールを本物と予測するモデルは99%の正解率になりますが、
実際にスパムメールを分類できていません。
この場合、正解率以外の評価指標が必要になります。

## 混同行列(Confusion Matrix)

混同行列は分類モデルの評価を考える際の基本となる行列で、モデルの予測値と観測値の関係を表すものです。

||予測：スパム|予測：本物|
|---|---|---|
|__実際：スパム__|True Positive (TP)|False Negative (FN)|
|__実際：本物__|False Positive (FP)|True Negative (TN)|

混同行列は、sklearn.metricsモジュールのconfution_matrix関数で取得できます。

```python
from sklearn.metrics import confusion_matrix

y_pred = model.predict(X_test)

print(confusion_matrix(y_test, y_pred))
```

出力

```text
[[176  30]
 [ 52  50]]
```

ちなみに混同行列で正解率を計算する式は以下になります。

```math
\frac{tp + tn}{tp + tn + fp + fn}
```

## 適合率(Precision)、再現率(Recall)、F1スコア(F1score)

適合率は、スパムと予測した中で実際にどれだけスパムであったかの割合です。

```math
\frac{tp}{tp + fp}
```

再現率は、実際はスパムのうち正しくスパムと予測できた割合です。

```math
\frac{tp}{tp + fn}
```

F1スコアは適合率と再現率の調和平均です。適合率と再現率のどちらを優先すべきかが決まっていない場合、モデルを統合的な評価に使用します。

```math
\frac{2}{\frac{1}{適合率} + \frac{1}{再現率}}
```

高適合率は、スパムと予測された本物が少ないことを意味します。
高再現率は、ほとんどのスパムを予測できたことを意味します。

上記関連指標は、sklearn.metricsモジュールのclassification_report関数で取得できます。

```python
from sklearn.metrics import classification_report

y_pred = model.predict(X_test)

print(classification_report(y_test, y_pred))
```

出力

```text
             precision    recall  f1-score   support

          0       0.77      0.85      0.81       206
          1       0.62      0.49      0.55       102

avg / total       0.72      0.73      0.72       308
```
【Ruby】each_with_indexを使って配列内の順番を特定する

　「each_with_index」とはRubyで使えるメソッドです。繰り返し処理と同時にその要素が何番目に処理されたのかが分かるようになります。

　　では任意の数字が何番目に格納されているかを確認できるプログラムを作っていきます。下記の配列を用います。

```ruby
input = [2, 6, 7, 14, 15, 21, 29, 38, 42, 51, 60, 78, 81, 84, 95, 102]
```

　プログラミング初心者らしく、初歩的なミスを含め、単純な発想でコードを書いては修正するプロセスを見せたいと思います。以下の流れで説明していきます。

1. each_with_indexを使う
2. 探したい値を入力させる
3. 条件分岐で出力
4. 必要な情報だけ表示されるようにする


##1. each_with_indexを使う
　　では「each_with_index」を用いるとどのような出力結果が得られるかを見てみます。

```ruby
input = [2, 6, 7, 14, 15, 21, 29, 38, 42, 51, 60, 78, 81, 84, 95, 102]

input.each_with_index do |num, i|
  puts "#{num}は#{i}番目にあります"
end
```

　上記のコードを実行すると出力結果は以下のようになります。

```erb
2は0番目にあります
6は1番目にあります
7は2番目にあります
14は3番目にあります
15は4番目にあります
21は5番目にあります
29は6番目にあります
38は7番目にあります
42は8番目にあります
51は9番目にあります
60は10番目にあります
78は11番目にあります
81は12番目にあります
84は13番目にあります
95は14番目にあります
102は15番目にあります
```

　ここから特定の値だけを取り出す処理を考えていきたいと思います。


##2. 探したい値を入力させる
　では、入力された値が何番目にあるかを特定できるようにします。このseachメソッド内に処理を記述していきます。

```ruby
def search(target, input)
  #each_with_indexを用いた処理を記述
end

input = [2, 6, 7, 14, 15, 21, 29, 38, 42, 51, 60, 78, 81, 84, 95, 102]
puts "整数を入力してください"
target = gets.to_i
search(target, input)
```


##3. 条件分岐で出力
　そして入力した「target」が、「num」と同じ値だった時に、「target」の順番を表示させるようにコードを書き直しました。

```ruby
def search(target, input)
  input.each_with_index do |num, i|
    if target == num 
      puts "#{target}は#{i+1}番目にあります"
    else
      puts "その数は配列に含まれていません" 
    end
  end
end

input = [2, 6, 7, 14, 15, 21, 29, 38, 42, 51, 60, 78, 81, 84, 95, 102]
puts "整数を入力してください"
target = gets.to_i
search(target, input)
```

　15を入力した場合、出力結果は以下のようになりました。

```erb
その数は配列に含まれていません
その数は配列に含まれていません
その数は配列に含まれていません
その数は配列に含まれていません
15は5番目にあります
その数は配列に含まれていません
その数は配列に含まれていません
その数は配列に含まれていません
その数は配列に含まれていません
その数は配列に含まれていません
その数は配列に含まれていません
その数は配列に含まれていません
その数は配列に含まれていません
その数は配列に含まれていません
その数は配列に含まれていません
その数は配列に含まれていません
```

　ここから、「15は5番目にあります」だけを表示させるようにしていきます。


##4. 必要な情報だけ表示されるようにする
　必要な情報だけ表示されるように「return」を加えてみました。

```ruby
def search(target, input)
  input.each_with_index do |num, i|
    if target == num 
      puts "#{target}は#{i+1}番目にあります"
      return
    else
      puts "その数は配列に含まれていません" 
    end
  end
end

input = [2, 6, 7, 14, 15, 21, 29, 38, 42, 51, 60, 78, 81, 84, 95, 102]
puts "整数を入力してください"
target = gets.to_i
search(target, input)
```

　しかしこれでは出力結果は以下のようになります。配列に含まれていない値を入力した場合は「その数は配列に含まれていません」というワードが16回繰り返されます。

```erb
その数は配列に含まれていません
その数は配列に含まれていません
その数は配列に含まれていません
その数は配列に含まれていません
15は5番目にあります
```

　ということで、「その数は配列に含まれていません」というワードをeach_with_indexの外に追いやると、意図した結果を得られるようになりました。

```ruby
def search(target, input)
  input.each_with_index do |num, i|
    if target == num 
      puts "#{target}は#{i+1}番目にあります"
      return
    end
  end
  puts "その数は配列に含まれていません" 
end

input = [2, 6, 7, 14, 15, 21, 29, 38, 42, 51, 60, 78, 81, 84, 95, 102]
puts "整数を入力してください"
target = gets.to_i
search(target, input)
```



　以上です。
DRM開発入門 (1) 公開鍵暗号と共通鍵暗号とハイブリッド暗号

私はソフトウェアを開発するうちにDRM(ライセンス認証)の実装に興味を持つようになりましたが、その開発は困難を極めるものでした。

理由としては、日本語のリソースが殆ど無いことが一番にあげられるかと思います。

このシリーズでは、DRMの開発(主にロジック)について、出来得る限り説明していく予定です。

第一回は公開鍵暗号と共通鍵暗号について説明していきます。

**この記事は私の理解に基づいています。
業務で使用する場合は、適切なセキュリティの専門家に相談する事をお勧めします。**

※こちらの記事は私のブログからの転載です。[英語で読みたい方はこちら (English version)](https://satoh.dev/blog/introduction-to-drm-development-1-public-key-cryptography-symmetric-key-cryptography-and-hybrid-cryptosystem/)。

## 暗号化とは
暗号化とは具体的に何なのでしょうか？
例えば以下のような文章を、AさんからBさんに、友達伝いで伝えるとします。

``Why don’t we go out for dinner sometime?``

Aさんは友達にはこの内容を知られたくありません。

この場合、何らかの方法-具体的にはAさんとBさんしか知り得ない方法-で文章を暗号にして、それを解読できるようにする必要があります。

単純な暗号化のひとつに、**シーザー暗号**というものがあります。
![512px-Caesar_cipher_left_shift_of_3.svg_.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/185096/21e5b399-3866-e42a-add4-deba4008c7eb.jpeg)

これは英語のEをBに、DをAに、という風に、決められた数だけスライドさせていく、という暗号化方式です。
例として先程の文章を1文字ずつ次の文字にずらすと、以下のような文章になります。

``XIZ EPO’U XF HP PVU GPS EJOOFS TPNFUJNF?``

これが暗号化です。

この例は単純ですが、例えばAはCに、CはXに、というように暗号化の方式を複雑にすることで、ある程度の強度を保つことが可能です。


## 共通鍵暗号とは
共通鍵暗号 (対称暗号) とは、**暗号化する側と復号化する側が同じ鍵を使用する暗号化方式**です。

AESやDESなどが代表として挙げられます。
また、先程のシーザー暗号も共通鍵方式です。

AES暗号方式では、平文、暗号文、鍵に加え、**saltとiv**というものが登場します。
これについて初心者には理解が難しいため、ここで説明します。

**salt(ソルト)は鍵をハッシュ化する際に使用**します。
この値はユーザーごとに固有である必要があります。
また、**このsaltは復号化時に必要ですが、秘密である必要はありません。**

**iv(initial vector/初期化ベクトル)は、暗号文を毎回ランダムにする**ために使用します。

同じ鍵を使用するため、計算コストが低いという特徴がありますが、トレードオフとして、**鍵の交換を安全に行う必要がある**、という点は留意しなければなりません。

この鍵の交換にはディフィー・ヘルマン鍵共有が使用されることが多いです。LINEのLetter Sealingにもこの技術が使用されています。
これについては非常に複雑で、私の理解も追いついていないため、[LINE Engineeringのブログ](https://engineering.linecorp.com/ja/blog/new-generation-of-safe-messaging-letter-sealing/)を閲覧することをおすすめします。

要するに鍵を盗まれてしまうと暗号化も復号化も出来てしまうということが大きなデメリットですね。

## 公開鍵暗号とは
公開鍵暗号 (非対称暗号) とは、**暗号化する側と復号化する側が別々の鍵を使用する暗号化方式**です。

RSAが代表として挙げられます。
![19DfiKodi3T25Xz7g9EDTyvF9di2SzvJo6JebRJaCN-1P.width-1616.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/185096/a4253023-acb2-1606-1aae-56d0685a8764.jpeg)
名前の通り、公開鍵は基本的に暗号化のみに使用されるもので、第三者に盗まれたとしてもそれを利用して復号化することはできません。

対して秘密鍵は、受信者のみが所持するもので、公開鍵とは全く別の鍵です。これは基本的に復号化のみに使用されます。

公開鍵の作成には秘密鍵が必要です。
言い換えると、秘密鍵があれば公開鍵をいくらでも作成できてしまいます。
そのためクライアント側で公開鍵を使用し暗号化、サーバー側で秘密鍵を使用し復号化する、というのが一般的な流れとなっています。

後の章で触れますが、リバースエンジニアリングという技術でソフトウェア内部のテキストとロジックを見ることや改変することが可能です。

そのため、秘密鍵をクライアントサイドに渡して復号化、という流れには大きなセキュリティリスクを伴います。

それを解決するのがハイブリッド暗号です。

## ハイブリッド暗号
ハイブリッド暗号とは、その名の通り**共通鍵暗号と公開鍵暗号を組み合わせた暗号化方式**です。
この方式では以下のようなフローで暗号文と鍵の送信を行います。

1. 送信者が共通鍵Aを作成
2. 平文をその共通鍵Aで暗号化 (=暗号文A)
3. 共通鍵を事前に用意していた公開鍵で暗号化 (=暗号鍵A)
4. 暗号文Aと暗号鍵Aを受信者に送信

暗号の受信者のフローは以下の通りです。

1. 受信者は、送信されてきた暗号鍵Aを秘密鍵を使用して復号化
2. その復号化された鍵を使用して、送信されてきた暗号文Aを復号化

このハイブリッド暗号にはいくつかの利点がありますが、最も大きい点が２つあります。

**第一に送信者が鍵を作成するということ、次にその鍵を公開鍵で暗号化する、という点です。**

この方式を採用することによって、比較的安全に鍵の交換が可能です。

## 終わりに
この章では暗号化方式について解説しました。

適切な暗号化を破ることは非常に難しいですし、現代の一般的なコンピュータでは解析に時間がかかります。

それでも留意していただきたいことは、**暗号化を破るよりその前後のロジックを破る方が遥かに簡単である**という点です。
(CrackProofなど、商用のクラッキング対策ソフトウェアを使用しても、その事実は変わりません)

これについては次章以降で説明します。
Pythonで作ったアプリをGCPでデプロイするための色々

# デプロイの準備
「こういうときにDockerが必要なんだ」、ということがわかった。
にわか知識でDockerFileというものを作ってもダメで、ビルドする必要がある

1.dockerのインストール(Dockerコマンドを使用可能にする)
・インストーラーに従う

2.インストールされているか、確認、ログイン
Powershellにて
$>docker version

$>docker login

3.ubuntuをdocker上にインストール

ubuntuとはOSでLinuxを操作する、コマンドプロンプトのようなものだと思えばよい。

$>docker pull ubuntu:18.04

4.ubuntuを起動

$>docker run -it -d --name ubuntu18.04 ubuntu:18.04
$>docker exec -it ubuntu18.04 /bin/bash
そうするとroot@ほにゃらら
のような形でLinuxコマンドが使用可能になる。

apt update
(sudo)は要らない
apt install -y python3 python3-pip
option -yはサーバー側から聞かれるクエスチョンにY, yesで答えますよ、の意。ここは時間がかかる。

5.python3起動


#DockerFile
仮想環境を構築するためのパッケージ一括管理ファイル、pip(python用コマンド)のrequirements.txtのようなもの

#DockerFile作成

```
一例
FROM ubuntu:18.04

RUN apt-get update
RUN apt-get install -y python3 python3-pip
RUN pip3 install numpy matplotlib
```

# build
(python終了はquit(),ubuntu終了はCtrl+Z)
$>docker build .

#　備忘録(デプロイとは関係ない)
Ubuntu はWindowsでLinuxを使うための色々。
sudo apt install software-properties-common

上手くインストールされているか確認する。
sudo dpkg -S /usr/bin/add-apt-repository
※sudo apt-file search add-apt-repositoryは使えない

sudo add-apt-repository 'deb http://security.ubuntu.com/ubuntu xenial-security main' #ここでadd-apt-repositor と打ち間違い(コピペミス)をしてかなり迷った。またシングルクウォーテーションのみ適用されるので注意。
sudo apt upgrade
sudo apt update
sudo apt install libjasper1 libjasper-dev
Flutter入門メモ

#はじめに

Flutter入門する際にお世話になった日本語ページをメモしておく。
英語公式サイトが整備されているが、日本語の方がやはり学習コストは下がるのでありがたい。

FlutterはGoogle開発。
アップデートが頻繁にされるので、記事の内容が時代遅れになっている可能性もある。


#リンク
##1
[Flutter実践入門 ～環境構築からAndroid/iOS/Webに広告を付けて同時にリリース!!～](https://zenn.dev/kazutxt/books/flutter_practice_introduction)
[おまけ1:公式サイト/優良サイト](https://zenn.dev/kazutxt/books/flutter_practice_introduction/viewer/appendix_sites)

ハンズオン込みで非常にわかりやすい。

##2
[「Flutterで始めるモバイルアプリ開発」連載一覧](https://codezine.jp/article/corner/830)

月一更新だが、わかりやすい。CodeZine記事一覧。


##3
[Flutterの効率良い学び方](https://medium.com/flutter-jp/flutter-learning-c5640c5f05b9)

Flutter学習のロードマップになった。

##4
[Flutter 全部俺 Advent Calendar 2019](https://adventar.org/calendars/4140)

2019年末の内容だが、基本が網羅されていて図解もある。

##5
[Flutter開発する前に知っておきたい35のWidget一覧](https://qiita.com/coka__01/items/dedb569f6357f1b503fd)

Widgetのソースとイメージがまとめられている。
Widgetチートシート。
何やっても npm does not support Node.js のエラーが出た話


新しいReactアプリを作成しようと思い
`npx create-react-app`しようとすると、下記のようなエラーが出ました。

```
warn npm npm does not support Node.js v16.3.0
warn npm You should probably upgrade to a newer version of node as we
warn npm can't make any promises that npm will work with this version.
warn npm Supported releases of Node.js are the latest release of 6, 8, 9, 10, 11, 12.
warn npm You can find the latest version at https://nodejs.org/
```

私のMacにはNode.jsはバージョン@16.3.0が入っていたのですが、
npmのバージョンは@6.9.2でした。

Nodeの[リリース一覧](https://nodejs.org/ja/download/releases/)を見ると、
どうやらNodeとnpmのバージョンが、私のMacでは一致していないようでした。


## Node.jsをダウングレードしようとした

エラーメッセージにも「より新しいnodeにアップグレードすべきです」的なことが書いているので
Node.jsを新しくすれば良いのかなと思ったのですが、
リリース一覧を見たところ最新バージョンのNodeがダウンロードされていました。
ってことはnpmのバージョンをアップグレードすれば良いのかな、と思いましたが
「Supported releases of Node.js are the latest release of 6, 8, 9, 10, 11, 12.」
（npm サポートしているNode.jsのリリースは、6, 8, 9, 10, 11, 12の最新リリースです。）
と書いているので、Node.jsをv12までダウングレードすれば良さそうです。


## Node.jsのダウングレードができない！！
いろんな記事を漁ったのですが、Nodeをダウングレードしようにも
「npm」というコマンドが入ったものは全て
「npm does not support Node.js v16.3.0」のエラーが出てしまいます。

どうしろっちゅーねん・・・


## 直接フォルダを削除したら解決した

荒技なのかもしれませんが、ひとまずダウンロードされているNodeのファイルをごっそり削除しました。
ターミナルで下記を実行して、nodeが入ったフォルダをFinderで開く。

```
cd .nvm
cd versions
cd node
open .
```

そうしたら「v16.3.0」のフォルダを見つけました！
この数字何度見たことか！忌まわしい！！（）


このフォルダをごっそり削除して、
先ほどの[リリース一覧](https://nodejs.org/ja/download/releases/)からv12をダウンロードして
同じフォルダ階層に突っ込んで、本来やりたかったcreate-react-appを実行したところ
エラーなく実行できました！！やったー！！


## 何やってもnpm実行できなくて戸惑った
どの記事を見ても、Node.jsをダウングレード(アップグレード)するには
「npm　●●●　を実行する。」と書かれていて本気で詰みましたが
意外にも簡単な方法で解消できてよかったです。。
同じようなエラーでつまづいている方の参考になれば嬉しいです◉