OmniAICreator/Qiita-1.07M huggingface dataset:
Amazon Chime SDKでスライドをバーチャル背景に設定する

`この記事はこちらでも紹介しています。 
https://cloud.flect.co.jp/entry/2020/08/24/123607`



前回は、Amazon Chime SDKでビデオセッションの上限（16セッション）を超えて映像配信する実験をご紹介しました。
https://qiita.com/wok/items/683561486c7b79c25edc

今回もAmazon Chime SDKについて、最近他のビデオ会議ツール等で話題になっていた機能を実現する方法をご紹介したいと思います。

今回ご紹介するのは、パワーポイントなどのスライドをバーチャル背景にする方法です。
最初に大きな話題になったのは、[mmhmm](https://www.mmhmm.app/)でしたね。その後、Zoomでも同様の機能が[リリース](https://blog.zoom.us/filters-reactions-lighting-features-zoom-meetings-2/)されました。リモートで行うプレゼンに臨場感が出て良いと思います。

これをAmazon Chime SDKを用いて実現する方法をご紹介します。
Amazon Chime SDK(js)を使うので、特にソフトウェアをインストールすることなく使えちゃいます！！
また、スライド以外にも、画面共有可能なウィンドウをすべて背景にすることができます。
なので、例えばエディタとスピーカーを表示しながらライブコーディング、なんてことも出来たりします。

実際の動作イメージはこちらです。
![demo_ppt.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/365991/fc065b24-c356-622b-0c0e-e1291abaa28e.gif)

<!-- more -->
### Amazon Chime SDKでカメラの映像を送信する方法

以前、[バーチャル背景の記事](https://qiita.com/wok/items/962929e63bc98e4033b9)でもご説明した内容ですが、チュートリアルやサンプルなどではカメラの映像を送信する際の一般的な方法としてカメラデバイスのIDを登録する方法が紹介されています。しかし、実は同一のメソッドでMediaStreamを登録することもできるようになっています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/365991/10f1dfba-a19a-2a6c-d62d-7b9e976ac20b.png)

つまり、実はAmazon Chime SDKではMediaStreamさえ取得できれば、何でもシェアできるという柔軟な設計になっているのです。
たとえば、HTMLCanvasElementからはMediaStreamが取得できます。このため、HTMLCanvasElementになにか描画して、それを配信することが出来ます。
上述の記事では、これを利用してバーチャル背景は実現しました。
今回も、これを利用してスライドをバーチャル背景にします。

### スライドの画像取得

バーチャル背景では、カメラの映像をBodyPixを用いて人物の領域と背景の領域を識別し、背景部分を指定された背景画像の映像に置き換えてHTMLCanvasElementに描画していました。
今回は、この背景画像を、パワーポイントなどのアプリケーションのウィンドウから取得します。下記のようにを呼び出すことで、アプリケーションの映像をMediaStreamとして取得できます。これをHTMLVideoElementのソースに設定した後に、カメラ映像と同じサイズのHTMLCanvasElementにフレームを描画します。そして、カメラの映像のフレームごとに、このHTMLCanvasElementのイメージをキャプチャして背景画像として用います。

```
    navigator.mediaDevices.getDisplayMedia().then(media => {
       ...
    })
```
処理の流れを纏めると次のようになります。図中上部は前述の通常のバーチャル背景の処理の流れです。図中下部が今回の処理です。赤字部分が変更点となります。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/365991/2bbf77f6-593c-c096-79a1-2eeb6f5654a9.png)


### バーチャルフォアグランドもやってみた。
ここまでの説明で、Amazon Chime SDKでは、様々な加工をした映像を配信できることがおわかりになるかと思います。
例えば、下図は人物を線画にしたり、Asciiアートにしたりしてみたものです。
バーチャル背景（バックグラウンド）ではらぬ、バーチャルフォアグラウンドといったところでしょうか。

![demo_vfg2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/365991/378806ab-cb47-eb20-e807-c77e775ef681.gif)


このように、Amazon Chime SDKでは、カメラの映像配信用にMediaStreamを受け付けることで、さまざまな拡張が可能になっています。楽しいですね。

### デモ
今回ご紹介したものと同等のロジックを組み込んだサイトを用意しました。

https://flect-lab-web.s3-us-west-2.amazonaws.com/001_virtual_background/index.html

### npmパッケージ
また、簡単に使えるようにnpmパッケージも作ってみました。

https://www.npmjs.com/package/local-video-effector

### FLECT Amazon Chime Meeting
また、ビデオ会議の新機能のテストベッドとしてビデオ会議室システムを作成しており、リポジトリを公開しています。
今回ご紹介した機能も、こちらに実装されていますので、興味があればアクセスしてみてください。

https://github.com/FLECT-DEV-TEAM/FLECT_Amazon_Chime_Meeting

### 最後に
今回は、Amazon Chime SDKでスライドをバーチャル背景に設定する方法をご紹介しました。
また、この方法は、画面共有可能なアプリケーションであれば何でも背景に設定することができます。
このため、例えばライブコーディングを配信してみるなど、様々な活用の仕方が考えられると思いますので、是非お試しください。

次回は、またAmazon Chimeで遊ぶか、以前紹介したマルチバーコードリーダの技術的な内容をご紹介するかをしようと思ってます。
では。
Raspberry PiにPython3のKivyをインストールする

Python2で動かしていたが、漢字でUnicodeWarningが出てしまうので3系に移行した。
インストール手順。

```
sudo apt update && \
sudo apt install -y libsdl2-dev libsdl2-image-dev libsdl2-mixer-dev libsdl2-ttf-dev \
   pkg-config libgl1-mesa-dev libgles2-mesa-dev \
   python-setuptools libgstreamer1.0-dev git-core \
   gstreamer1.0-plugins-{bad,base,good,ugly} \
   gstreamer1.0-{omx,alsa} python-dev libmtdev-dev \
   xclip xsel libjpeg-dev && \
python3 -m pip install --upgrade --user pip setuptools && \
python3 -m pip install --upgrade --user Cython==0.29.9 pillow && \
python3 -m pip install --user https://codeload.github.com/kivy/kivy/zip/1.11.1
```

参考
https://teratail.com/questions/200843
Docker内でcomposer require したらkilledになったときの対応

Mac上で Docker （docker-compose） で開発環境を作り、開発中の Laravel のアプリケーションに `composer require` をしたら、中断されてしまいました

```sh
composer require ****/*****
（中略）
killed
```

composer が途中で終わってしまうといえば、メモリ不足が定石かなと思います。
会社の先輩からこのリンクを送ってもらい、疑惑が確信に変わりました。

[PHP] composer install が killed で失敗するときの原因と対処
https://webbibouroku.com/Blog/Article/composer-killed

## PHP memory_limit の引き上げ

メモリ不足とわかったところで、まずDocker内で使っている `php.ini` の memory_limit を増やしました。
どのくらい必要なのかわからなかったけど、とりあえず２GB（2048MB）にしました。

```ini
memory_limit = 2048M
```

設定変更後、 docker build して再起動

## Docker for Mac のメモリ割り当てを増やす

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18306/b89b4a26-ab31-17f6-3535-d13cd90a3106.png)

Docker for Mac で指定しているDockerが利用できるリソースが、当初 2GBとなっていました。使っている MacBook Pro には 64GBものメモリを積んでいるので、ドドーンと 8GB まで増やしました。ここはマシンスペックとの相談かなと思います。

変更後、Dockerホストの再起動がかかりました。

## 解決！！

上記2点でメモリの設定を変更して、 `composer require` が無事実行できました。
`composer update` でも同様に大量のメモリが必要なので、同じような対応が必要になるかもしれません。
【IAM】IAMとは

## IAMとは
**AWS Identity and Access Manegement** の略
AWSのサービスを利用するための権限を管理し、各サービスへのアクセスを制御する仕組み


### 主要トピック
- ユーザー
- グループ
- ポリシー
- ロール

## ユーザー
### 1. ルートユーザー
AWSアカウント作成時に作られるアカウント
全てのAWSサービスとリソースを使用できる権限を有する
**※ 基本的に、日常的なタスクには使用しない**

### 2. IAMユーザー
IAMポリシー内でAWSサービスを使用出来るユーザー
**※ 基本操作はIAMユーザーアカウントで行う**

- 1アカウント5,000ユーザーまで作成可能
- 1ユーザー10グループまで所属可能

### 3. パワーユーザー
IAMユーザーやグループの管理以外の全てのAWSサービスにフルアクセス権限を有するユーザー

## グループ
IAMユーザーをグルーピングし、権限管理を容易にする仕組み

- 1アカウント300グループまで作成可能

## ポリシー
どのAWSリソースにどのサービスのどのような操作を許可/拒否するかを定義するもの
JSON形式で記述

### 1. 管理ポリシー
**AWS管理ポリシー**：AWSが作成・管理するポリシー
**カスタム管理ポリシー**：AWSアカウントで作成・管理するポリシー

### 2. インラインポリシー
1つのプリンシパルエンティティ（ユーザー、グループ、またはロール）に埋め込まれた固有ポリシー

### JSONに記述する設定内容
| key | value |
| :-: | :-: |
| Effect | Allow / Deny |
| Action | 対象のAWSサービス |
| Resource | 対象のAWSリソース |
| Condition | アクセス制御が有効となる条件 |

### ポリシー適用
**ユーザーベースのポリシー適用**：IAMユーザー、IAMグループ、IAMロールにアタッチ
**リソースベースのポリシー適用**：AWSリソースにアタッチ

## ロール
AWSサービスやIAMユーザーの役割を定義し、アクセス権限を管理する概念

### 1. AWSサービスロール
付与先がAWSリソースであるロールのこと

AWSリソースがIAMロールの内容に応じて別のAWSリソースにアクセスする際には、**AWS STK（Security Token Service）**から一時的なアクセスキーを取得し、利用する
→ アクセスキーとシークレットキーのペアは不要

### 2. クロスアカウントアクセス用ロール
AWSアカウントをまたいだAWSサービスへのアクセスを一時的に許可するためのロール

### 3. AWSの外部ユーザー用ロール
**IDフェデレーション**という仕組みを利用し、AWS外のユーザーIDに対してAWSアカウント内のAWSリソースへのアクセスを許可出来る

## IDフェデレーション
複数のシステムやサービスをまたがってIDを利用できるようにする認証連携機能
利用しているIDプロバイダーやディレクトリによって適切なIDフェデレーションを選択する

### ・ SAML2.0
IDプロバイダーがSAML2.0に対応している場合は、**IAM SAML2.0 IDプロバイダー**によるIDフェデレーションが可能

### ・ OpenID Connect
IDプロバイダーがOpenID Connectに対応している場合は、**IAM OpenID Connect IDプロバイダー**によるIDフェデレーションが可能

**ウェブIDフェデレーション**：FacebookやTwitterなどのOpenID Connectに対応しているソーシャルIDを利用するIDフェデレーション

### ・ LDAP
LDAPなど、SAML2.0に対応していないIDフェデレーションを使用する場合は、**カスタムIDブローカー**を開発することでIDフェデレーションを実装出来る

### ・ AD（ADFSなし）
オンプレミスでActive Directoryを使用し、ADFSを使用していない場合、**AWS Directory Service AD Connector**を使用することで直接IDフェデレーションが可能

### ・ モバイル（ソーシャルID）
モバイルアプリケーションがS3やDynamoDBなどのAWSリソースにソーシャルIDを使用してアクセスする場合には、**Amazon Coginfo**を使用出来る

## ユーザーのアクティビティの記録
**1. Access Advisor**：IAMエンティティ（ユーザー・グループ・ロール）が最後にAWSサービスにアクセスした日時を表示する機能

**2. Credential Report**：利用日時などが記録されたIAM認証情報に関わるレポートファイル

**3. AWS Config**：IAMのユーザー・グループ・ロール・ポリシーに関して、変更履歴・構成変更を管理・確認することが出来る機能

**4. CloudTrail**：AWSインフラストラクチャ全体でアカウントアクティビティをログに記録し、継続的に監視し、保持することが出来る機能
OpenPoseのビルドで#error -- unsupported GNU version!が出たときの対処法

## 状況
私はOpenPoseをビルドしようとしたときにこのエラーに遭遇しました。その時どのように対処したかについてこの記事にまとめます。

なお、この記事ではOpenPoseのビルドの仕方については説明しません

## 環境
環境|バージョン
----|---
OS | Linux(Pop_OS) 20.04
CUDA | 10.2

## エラー文の内容
OpenPoseをビルドするために次のようにコマンドを実行しました。

```bash
# 予めcloneしておく
$ mkdir build && cd build
$ ccmake .. # ここでどのようにビルドするか設定します。公式ではguiを使っていた気がします。
$ make -j`nproc`
```

すると、次のようなエラーが出るようになりました。

```
/usr/lib/cuda/include/crt/host_config.h:138:2: error: #error -- unsupported GNU version! gcc versions later than 8 are not supported!
  138 | #error -- unsupported GNU version! gcc versions later than 8 are not supported!
      |  ^~~~~
```

これは、gccのバージョンが新しすぎると起きるエラーのようです。
今回は「`gcc-8`までしかサポートしていませんよ」というふうに表示されています。

私の環境では`gcc-9`が使われていたのでそれが問題だとわかりました。

## 対処法
予め`gcc-8`をインストールし、ビルドするとき次のように実行します。

```bash
$ CC=gcc-8 CXX=g++-8 ccmake .. # ここでどのようにビルドするか設定します。公式ではguiを使っていた気がします。
$ make CC=gcc-8 CXX=g++-8 -j`nproc`
```

こうしておくと自動的にコンパイルに`gcc-8`が使われるようになり、コンパイルができるようになります。

## 参考文献
CUDA incompatible with my gcc version
https://stackoverflow.com/questions/6622454/cuda-incompatible-with-my-gcc-version
certbot-auto更新スクリプト

動作未検証
そのうちやる

```
#!/bin/bash

DOMAIN='example.com'
SLACK_INCOMING_HOOK='https://hooks.slack.com/services/{hook_id}'
CERTBOT_AUTO='/usr/bin/certbot-auto'
POST_HOOK='sudo /opt/bitnami/ctlscript.sh restart apache'

EXPIRATION=`openssl s_client -connect ${DOMAIN}:443 < /dev/null 2> /dev/null | openssl x509 -text | grep Not | grep -v Before | awk '/Not After : / {print $4, $5, $6, $7, $8}'`

curl -X POST -H 'Content-type: application/json' --data "{'attachments':[{'title':'Start：${DOMAIN} 期限：${EXPIRATION}', 'color':'#0000FF'}]}" ${SLACK_INCOMING_HOOK}

sudo ${CERTBOT_AUTO} renew --post-hook ${POST_HOOK}

if [ $? -eq 0 ] ;then

curl -X POST -H 'Content-type: application/json' --data "{'attachments':[{'title':'Success：${DOMAIN}', 'color':'#00FF00'}]}" ${SLACK_INCOMING_HOOK}

else

curl -X POST -H 'Content-type: application/json' --data "{'attachments':[{'title':'Failed：${DOMAIN}', 'color':'#FF0000'}]}" ${SLACK_INCOMING_HOOK}

fi
```
namespaceとは

## namespaceとは
リナックスオブジェクトに名前を付けて同じ名前のオブジェクトを１つとして管理すること

## ６つの独立環境
Linuxのオブジェクトに名前を付けることで以下のような６つの独立された環境を構築できます。

- PID namespace
 - プロセスに与えられたユニークなIDを指す。これを利用してプロセスを隔離できる。
 - namespace異なる場合はアクセスができない。


- Network namespace
 - ネットワークリソース（IPアドレス、ポート番号、Routing Tableなど）がnamespaceごとに独立に与えられる。
 - この機能を利用するとOS上で使用中のPortがあってもコンテナ内で同じPortを使用できる。


- UID namespace
 - ユーザーID（UID）とグループID（GID）をnamespaceごとに区分（独立に持っていける）
 - コンテナではルート権限を持っていてもポストの管理権限を持てないように隔離する機能。
 - namespace内とホストOS上で異なるUID、GIDを持つことができる。

- MOUNT namespace
 - Linuxでデバイスを認識するためマウントが必要。
     - マウント：コンピュータにつながっている機器及び記憶装置をOSに認識させ、使用可能状態にすること
 - ファイルシステムなどマウントされたデバイスをnamespaceごとに隔離。
 - ホストOSとnamespaceが異なるファイルシステムのツリーを持つことができる。

- UTS namespace
 - namespaceごとにホスト名やドメイン名を独自に持つことができる。（独自に設定可能）

- IPC namespace
 - プロセス間通信（IPC：Inter Process Communication）オブジェクトをnamespaceごとに独立的に持つことができる。
 - 共有メモリ（Shared Memory）、セマフォ（Semaphore）、メッセージキュー（Message Queue）などを独立的に使用。
古いmacOSのインストーラーを入手する

#はじめに
古いmacOSやOSXのインストーラーを作成するにあたってインストーラーファイルが必要になるが、古いmacOSでダウンロード履歴がない場合はAppStoreから入手することが不可能である。また、証明書の期限切れなどが理由で過去に作成したUSBからOSをインストールできなかったり、macOSを再インストールできないトラブルに遭遇することがあるようだ。

#インストーラーの入手
今回、古いmacOSから最新のmacOSまで配布している海外のサイトを見つけたので紹介する。

[macOS配布サイト](https://themacgo.com/category/macos/page/2/)

本サイトでは.dmgファイルでOSインストーラーが配布されているため、ダウンロード後に展開し、インストーラーを取り出してUSBを作成する。USBの作成手順は下記の項を参照。


#起動USBの作成
macOS/OSXの起動可能USBを作成する手順は以下の記事にまとめた。

[macOS/OSXの起動可能USBを作る](https://qiita.com/Nether_2046/items/67a8c9b9dfdc229835c9)
AIにネットを巡回させ、週1更新のガジェットランキングWebサービスを作ってみた

<h2>まえがき</h2>
私はガジェットが好きだ。とにかくガジェットを愛している。

中でもタブレットについては尋常ではないほど執着している。7, 8年ほど前にSurface RTと呼ばれる「これ一つで仕事も遊びも完璧！」というどう考えても勝ちなガジェットを購入して痛い目にあって以来、毎年数十万から100万近い価格を費やしながらも果てなきベストタブレットへの旅は今も続いている。

今のところはiPad Pro 12.9とSurface Pro Xで落ち着いているのだが、早速Galaxy Tab S7とかいう約束された勝利のタブレットは発表されるし、Surface Duoも控えているし、ちょっとお財布ポイントの危険が危ない。そもそもアークナイツとSNSしかやらないんだからAntutu旧スコアベースで20万もあれば十分なはずなのに。

こんな有様なので、ガジェットサイトはかなり頻繁にチェックしている。その他のテックメディアやリークサイト、海外で言えば9to5macなどのガジェットに関連するあらゆるサイトも含めれば毎日数時間かけて読んでいることになる。

正直なところ、ちょっと健全ではない。更新されてもいないのに同じサイトを何回も繰り返し見ていることすらある。もはやガジェットゾンビだ。じゃあどうしよう。

<b>そうだ、面倒なことはPythonにやらせよう。</b>

<h2>作ったもの</h2>
https://gadget-busters.com
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/696052/dd0a55fe-71cd-314f-b725-ce8b58a35d08.png)

これ。ガジェットバスターズという名前は昔好きだったミスバスターズという番組とガジェットをがっちゃんこしただけで特に何も考えていないことが窺える。

一週間に1度、その週に話題になっているガジェットをランキング形式で掲載しているので手っ取り早く今話題のガジェットを知りたい人にはお勧めできるかと思う。

バックエンドではインターネット上の記事をクローリングし、ガジェットに関連する記事から自然言語処理と自ら学習させた予測アルゴリズムを使って商品名を抽出。その後スコアを付与してランキングを作成している。

基本的にはより多くのサイトで、より多くの回数言及されているガジェットほど今旬のガジェットという判定となっている。 ただし出現回数だけでは”もう知ってるよ”となる可能性もあるので、アルゴリズムの中でtf-idfでいうidf的に珍しい商品名も拾うようにしている。具体的にはより少ないサイトで高頻度のキーワードを重要視するような項も導入している。

上記のような処理を自動で週に1度実行し、上記サイトを更新している。

<h2>今後の展開</h2>

データが溜まってきたら月間ランキングや年間ランキング、またガジェットのトレンド変遷リストを見られるページも作ってみたい。2015年に流行ったガジェット何があったっけ？という時に2015年のサイトをクリックすればタイムラインと共にトレンドの変遷が見られるというものだ。名前は...ガジェットタイムマシン？

また、商品名の抽出部分ももう少しアルゴリズムを細かくしてノイズを拾わないようにしたい。具体的には広告などに含まれる商品名の繰り返しを無視する、といった具合に。デザインもオシャンティにしたいし、これからもどうぞガジェットバスターズをよろしくお願いします。

また、使っている技術も備忘録も兼ねて少しづつ記事にしていきたい。さほど大したことはしていないが。

<h2>利用している技術</h2>
- Webクローリング
- 自然言語処理
- 機械学習
- React + Material UI
- AWS
/wp-admin/ は悪なのか？

/wp-admin/ にアクセスするとログインページが表示される。これはダメなことなのでしょうか？

## この記事を書こうと思ったきっかけ
Twitterで、2,3ヶ月毎に1回くらいのペースでこんな内容のツイートがTLに流れてきます。

> /wp-admin/ にアクセスしてログインページが表示されるサイトはクソ

/wp-admin/ はWordPressの管理画面のパスです。ログインしていないと /wp-login.php にリダイレクトされID/パスワードの入力フォーム、いわゆるログインページが表示されます。 /wp-admin/ にアクセスすることでログインページが表示されるのはよくない、という内容です。
結構多いのでぼくの考えをまとめて記事にしようかと思いました。

※WordPressについて書きますが、WordPressに限ったことじゃないです。
※WordPressすげー！って記事じゃないです。

## /wp-admin/ でログインページが表示されることはダメなのか？
さて、ログインページが表示されると何がまずいのでしょうか？ログインページが表示されるということは、攻撃者に攻撃されてしまうリスクがあります。WordPressなサイトでは、 /wp-admin/ にアクセスさえすればログインページが表示されるので、『攻撃できる場所』を容易に見つけることができます。

では、これはダメなのか？
ぼくはこれがダメだとは思いません。これは家で例えると『＊＊ホームが2x4で売り出している家は玄関が必ず駐車場の奥』っていう感じで、玄関の場所がわかったところで、攻撃できる場所がわかっただけで、『玄関の場所がわかる = 誰でも家に入ることができる』ではないからです。戸締りさえしっかりしていれば、家に入ることはできません。

※そもそも認証自体に脆弱性があった（＝ドアがベニヤ板で簡単に蹴り破ることができる）ときを除く

## ログインページのURLを変える効果は？
ログインページのURLを推測しにくいものにし攻撃者にログインページをわかりにくくする、というのは一定の効果はあります。これは間違いないです。でも、これって玄関の場所がわかりにくいってだけで見つけさえしてしまえば攻撃できますし、ドアにダイヤル式の南京錠とかを使っているのであれば、セキュアな状態ではありません。

## セキュリティ向上を目指すのなら
ログインページのURL変更は、攻撃をされにくくするもので、RPGで例えると回避率がすこし上がったといった感じです。しかし推測可能なID/PWなどをつかっていて、ぼうぎょ力が低いとあっという間にやられてしまいます。なので、回避率を上げるだけではなくぼうぎょ力も上げることが重要です。以下はその一例です。

### 強固なID/パスワードを使う（ぼうぎょ力UP）
上記で述べたとおり、ログインページのURLを変えてセキュリティ向上をしたところで、肝心のID/パスワードが推測可能であれば台無しです。ID/パスワードは推測されにくい強固なものを使うようにします。基本はこれです。自分では強固なパスワードが用意できない場合は、1Password, LastPassなどで自動生成するのもありです。というか推奨です。IDやパスワードにadminとかadministratorとか1234とかadmin1234とかはやめましょう。

### 回数制限する（ぼうぎょ力UP）
何回も攻撃をゆるしてしまうと、そのうち突破されてしまう可能性があります。プラグインなどでログインしようとする回数を制限し、際限なく攻撃されることを防ぎます。Limit Login Attempts Reloadedなどのプラグインがあります。

### 2段階認証・2要素認証にする（ぼうぎょ力UP）
ID/パスワードだけで認証せず、もう1段階・1要素追加して認証させることで、より強固な認証にすることができます。Jetpackなどのプラグイン+wordpress.comなどでWordPressを2段階・2要素認証に変えることができます。

例：Jetpack+WordPress.com
![Untitled-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/9882/f7cc20bd-618f-a0e1-21ff-9bb5025f5262.png)
WordPress.comのアカウントで認証したあと、iOS Appなどで承認しないとログインできません。

### 特定の条件に一致した場合だけ、ログインページにアクセスできるようにする（ぼうぎょ力、回避率UP）
ログインページが誰でもアクセスできるから、IPアドレスで制限をかける、Basic認証をかけるなどして/wp-admin/に特定のユーザしかアクセスできないようにします。特定の場所から執拗に攻撃を受けてるならこの制限が役立ちます。

例：ホワイトハウス
![スクリーンショット 2020-08-24 10.12.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/9882/2188d9ea-12f2-59ef-14f4-1d2756e98c71.png)
https://www.whitehouse.gov/
/wp-admin/にはぼくたちはアクセスすることができません。

### 管理画面を設けない（ぼうぎょ力、回避率UP）
そもそも管理画面があるからアクセスされるので、管理画面を設けないという作戦。WordPressをHeadless CMSとして扱い、公開サイトと管理画面を別ドメインにすることで、公開サイトに管理画面を設けないようにしたり、Shifterを使って静的出力して同じく公開サイトに管理画面を設けないようにします。

参考：Shifter
https://www.getshifter.io/

## まとめ
というわけで、ぼくの答えは『/wp-admin/ でログインページが表示されることは悪ではない。』です。
tmuxでクリップボード連携していい感じにコピペする

tmuxを使えるようになりたいけど、マウス操作やコピペ周りがbashと違っていて、どうしても敬遠してしまいがち。
この辺の操作感だけでも普段のターミナルと同じにして、恐怖心をなくしてガンガン使っていこう！

まずはクリップボード連携をするため、`xsel`をインストール

```
sudo apt install xsel
```
あとは.tmux.confをこんな感じに書き換える。



```.tmux.conf

# mouse
set -g mouse on

# vi copy (clipboard)
set-window-option -g mode-keys vi

bind-key -T copy-mode-vi v send-keys -X begin-selection
bind-key -T copy-mode-vi C-v send-keys -X rectangle-toggle
bind-key -T copy-mode-vi y send-keys -X copy-pipe-and-cancel "xsel -bi"
bind-key -T copy-mode-vi Enter send-keys -X copy-pipe-and-cancel "xsel -bi"

# Explicit `C-c` key fires copying the selection
unbind -T copy-mode MouseDragEnd1Pane
unbind -T copy-mode-vi MouseDragEnd1Pane
bind-key -T copy-mode C-c send-keys -X copy-pipe-and-cancel "xsel -bi"
bind-key -T copy-mode-vi C-c send-keys -X copy-pipe-and-cancel "xsel -bi"
```

#解説

・マウススクロールを有効にする

```
set -g mouse on
```

・viのキーバインドを使う

```
set-window-option -g mode-keys vi
```

・マウスアップ時に選択完了せず、選択状態を維持し、Ctrl-cでクリップボードにコピーする

```
unbind -T copy-mode MouseDragEnd1Pane
unbind -T copy-mode-vi MouseDragEnd1Pane
bind-key -T copy-mode C-c send-keys -X copy-pipe-and-cancel "xsel -bi"
bind-key -T copy-mode-vi C-c send-keys -X copy-pipe-and-cancel "xsel -bi"
```
GASを使ってGoogle Drive内のフォルダ、ファイルの権限をチェックする

DevRel/Asia 2020というカンファレンスを企画、推進しています。

[DevRel/Asia 2020](https://devrel.dev/asia-2020/)

アジア9カ国/地域の主催者たちと一緒に行っているのですが、データの管理はGoogle Driveで行っています。基本的に最初のディレクトリに全員書き込み権限ありで追加しているだけなのですが、人の入れ替わりなどもあって、だんだんと管理が煩雑になってきました。

そこで、特定のフォルダ以下の権限状態がどうなっているのかチェックするGoogle Apps Scriptを書いてみました。[Drive Permissions Auditor](https://gsuite.google.com/marketplace/app/drive_permissions_auditor/370134017754)とか[WhoHasAccess.com](https://www.whohasaccess.com/)、[morimorihoge/google-drive-permission-search: Search Google Drive's permission](https://github.com/morimorihoge/google-drive-permission-search)、[DriveChecker](https://www.drivechecker.com/)などがあるっぽいんですが、Google Drive全体がやりたい訳でもないし、お金払うほどでもないし（コミュニティイベントだし）、google-drive-permission-searchは動かないし…。

コードはこんな感じ。フォルダを取得して権限チェックして、フォルダも同じようにチェックして…って感じでたいしたことはしていないです。

```js
function permissionCheker(prefix = null, id = '1mK...AdH') {
  // 出力先のシート
  const sheet = SpreadsheetApp.getActive().getSheetByName('Files');
  // フォルダを取得
  const folder = DriveApp.getFolderById(id);
  // ファイルだけ取得
  const files = folder.getFiles();
  // 順番にチェック
  while (files.hasNext()) {
    writeRow(sheet, prefix, files.next());
  }
  // 中にあるフォルダを取得
  const folders = folder.getFolders();
  // 順番にチェック
  while (folders.hasNext()) {
    // フォルダを取得
    const sub = folders.next();
    writeRow(sheet, prefix, sub);
    // 再帰的に実行
    permissionCheker(`${prefix || ""}/${folder.getName()}/${sub.getName()}`, sub.getId());
  }
}

function writeRow(sheet, prefix, obj) {
  let rowIndex = sheet.getLastRow() + 1;
  // フォルダパスを出力
  sheet.getRange(rowIndex, 1).setValue(prefix ? `${prefix}/${obj.getName()}` : '');
  // ファイル名を出力
  sheet.getRange(rowIndex, 2).setValue(obj.getName());
  // 権限を持った人たちをリストアップ
  const editors = obj.getEditors();
  if (editors.length === 0) return;

  // 権限を持った人数を出力
  sheet.getRange(rowIndex, 3).setValue(editors.length);
  // 権限を持った人の名前を出力
  sheet.getRange(rowIndex, 4).setValue(editors.map(a => a.getName()).join(","));  
}
```

今回の目的ではとりあえず人数さえ分かっていればだいたい判断ができて、もし削除し忘れた人がいてもスプレッドシートの検索でどうにかなるので、こんな感じで十分でした。

![ScreenShot_ 2020-08-24 11.28.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/d4954435-bdb4-0c7e-5b99-b04f7945b516.png)

主催者は一覧で管理しているので、権限の付与や剥奪についてもGoogle Apps Scriptでやれば楽そうだなって感じました。
parquetファイルのチューニングポイント

# 概要
presto等のクエリの速度・負荷の改善に当たって、parquetへの理解が必要だったので、ポイントをまとめたい。

# 参考
+ [The Parquet Format and Performance Optimization Opportunities Boudewijn Braams (Databricks)
](https://www.youtube.com/watch?v=1j8SdS7s_NY)
+ [https://github.com/apache/parquet-format/blob/master/Encodings.md](https://github.com/apache/parquet-format/blob/master/Encodings.md)
+ [Amazon Athena のパフォーマンスチューニング Tips トップ 10](https://aws.amazon.com/jp/blogs/news/top-10-performance-tuning-tips-for-amazon-athena/)


# 観点
## Encodingへの意識
parquetの用いるEncodingの手法（Dictionary EncodingやDelta Encoding）などを意識して、parquetファイルを作りたい。 
Encodingを効率的に行うことでデータの圧縮が効率的にできる。これはpre-sortやDictionary sizeやrow groupの長さなどの調整などによりできる。

## parquetの持つ統計情報を有益なものにする
parquetは統計情報としてデータのまとまり（row group, column chunk, page）でmin/max/countなどを持っている。この統計情報を有益なものにするためにはpre sortが必要になることがある。

## ファイルサイズを最適化する
よくあるのはpartitionしすぎて、小さいファイルが大量にあるケース。parquetファイルを読むときはクエリーエンジンは内部のデータ構造を初期化したり、統計情報をparseしたりと様々な処理を行う。それが多すぎるとperformanceの劣化に繋がる。逆に大きなファイルが1個あると、これはこれでperformanceは劣化する。いずれもrepartitioning（もしくはそれに相当する処理）が必要だが、repartitioning自体様々な困難（関係者に通達、適切な粒度を見つけることの難しさ、バックアップを一々取らなければならないetc）があるので、repartitioningをしてくれるopen sourceやツールを使った方が良いだろう。

## 圧縮アルゴリズム
parquetではデフォルトではsnappyという圧縮アルゴリズムが使われている。基本的にはsnappyで構わないと思うが、問題があった場合他の圧縮アルゴリズムを使うことを検討すれば良い。
PG::UniqueViolation: ERROR:  duplicate key value violates unique constraintエラーの解決

PGデータベースにデータをインポートの後など、このエラーが発生する場合があります。

```
PG::UniqueViolation: ERROR:  duplicate key value violates unique constraint "<sample_tables>_pkey"
```

## 原因

データインポートなどの場合、PostgreSQLが指定したカラムの最大値を取ってくれず、別に保存してある最大値になってしまいます。


## 解決

Railsコンソールで以下のコードを実行すれば治ります。

```ruby
ActiveRecord::Base.connection.tables.each do |t|
  ActiveRecord::Base.connection.reset_pk_sequence!(t)
end
```
本番環境やテスト環境のインフラで同一IPのサーバにSSHするときにREMOTE HOST IDENTIFICATION HAS CHANGEDエラーを発生させないように、known_hostsファイルを環境ごとに用意する方法

## 結論

`UserKnownHostsFile` を使う。

## 問題

テスト環境や本番環境でIPアドレスが同一のホストに接続する際に`REMOTE HOST IDENTIFICATION HAS CHANGED`エラーが発生する。

## 設定例

```
Host *.test
  UserKnownHostsFile test_known_hosts

Host *.prod
  UserKnownHostsFile prod_known_hosts
```

このように環境ごとに別のknown_hostsファイルを使用することで解消する

## 参考

* [SSH config file for OpenSSH client](https://www.ssh.com/ssh/config/)
c++における文字列から数値への変換 (stol, stodの使い方と注意点)

# はじめに

C++において文字列から数値に変換する方法は以下のようにいくつか存在する。

- 関数`atol`, `atof`を使う
    - http://www.c-tipsref.com/reference/stdlib/atol.html
- `strtol`, `strtof` 関数を使う
    - http://www.c-tipsref.com/reference/stdlib/strtol.html
- `stringstream`を使う
    - http://www.cplusplus.com/reference/sstream/istringstream/
- `stol`, `stod` 関数を使う (C++11)
    - https://cpprefjp.github.io/reference/string/stoul.html

この中からどれを選んでも良いが、特にこだわりがなければ最後の`stol`, `stod`がもっとも簡単である。エラーケースのハンドリングなども扱いやすい。
この記事ではこの関数の使い方および注意点を紹介する。

# 基本的な使い方

まずはもっとも基本的な使い方から

```sto.cpp
#include <iostream>
#include <string>

int main() {
  std::cout << std::stol("1234") << std::endl;  // => 1234
}
```

文字列を引数にして、stolを呼ぶだけ。これでlongに変換できる。doubleに変換したい場合は、`stod`を呼ぶ。

```cpp
    std::cout << std::stod("123.456") << std::endl;   // => 123.456
```

当然ながら、文字列の先頭に"+"や"-"などの符号がついていても問題ない。

```cpp
    std::cout << std::stol("-1234") << std::endl;  // => -1234
    std::cout << std::stol("+1234") << std::endl;  // =>  1234
```

# 注意点

変換できない文字列が与えられた場合、`std::invalid_argument`が発生する。

```cpp
    long l = std::stol("abc");  // => throws an exception (std::invalid_argument)
```

しかし、**途中まで数値として解釈できる場合は例外が発生しない**。

```cpp
    std::cout << std::stol("3abc") << std::endl;   // => 3
```


範囲外の大きな数値を指定すると、`std::out_of_range`が発生。
ただし、`stoull`などの関数でunsignedの変数に変換する場所で**マイナスつきの文字列を指定しても、例外は発生せず変換できる**。

```cpp
    // std::cout << std::stoull("18446744073709551616") << std::endl;  // 2^64-1 より大きい値を指定すると std::out_of_range が発生
    std::cout << std::stoull("18446744073709551615") << std::endl;  // 2^64-1 は変換可能
    
    // std::cout << std::stoll("18446744073709551615") << std::endl;  // std::out_of_range. 2^64-1 はlongでは表せない。
    std::cout << std::stoul("-1") << std::endl;   // => 18446744073709551615 (例外を投げてくれない)
  }
```

引数で何も指定しない場合、デフォルトで10進数として解釈される。基数は第３引数で指定することができる。

```cpp
  {
    std::cout << std::stol("0xFF") << std::endl;  // => 0 (デフォルトでは10進数として解釈される)
    std::cout << std::stol("0xFF", nullptr, 16) << std::endl;  // => 255 (16進数として解釈される)
    std::cout << std::stol("01101", nullptr, 2) << std::endl;  // => 13 (2進数として解釈される)
  }
```

第３引数に`0`を指定することにより、8進数、16進数の表記を解釈できるようになる。
**ただし、２進数表記`0b...`は解釈できない。**

```cpp
  { // 第３引数に0を指定すると、"0...", "0x..."の記法を解釈してくれる。ただし"0b..."の表記は解読してくれないので注意。
    std::cout << std::stol("100", nullptr, 0) << std::endl;    // => 100
    std::cout << std::stol("0b100", nullptr, 0) << std::endl;  // => 0 (binaryの判定はできない)
    std::cout << std::stol("0100", nullptr, 0) << std::endl;   // => 64
    std::cout << std::stol("0x100", nullptr, 0) << std::endl;  // => 256
  }
```

数値として解釈できない文字が存在する場合、その情報は第二引数に入る。
全文字列が数値として変換されたかチェックするためには、以下のように`s.size() == idx` のチェックが必要。

```cpp
  { // usage of the second argument
    size_t idx = 0;
    std::string s = "30";
    std::stol(s, &idx);
    assert(s.size() == idx);  // idx == s.size() == 2

    s = "30%";
    std::stol(s, &idx);   // idx => 2
    if (idx != s.size()) {
      std::cout << s[idx] << std::endl;   // => "%"
    }
  }
}
```

# リファレンス

- https://cpprefjp.github.io/reference/string/stol.html
- https://cpprefjp.github.io/reference/string/stoul.html
- https://cpprefjp.github.io/reference/string/stod.html
Redashのデータソースを作成する

前回の記事でAWSのRDSにデータをインポートしてデータの準備が出来ましたので、今回はRedashにログインしてデータソースを作成してみたいと思います。

## Redashへのログイン

① 最初にAWSのEC2インスタンスとRDSが起動されていることを確認します。
​　 起動されていない場合は、起動しておいてください。
② EC2インスタンスのパブリックIPアドレスをコピーします。
![EC2アドレス](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691277/154fd73d-96b3-29ed-acc6-b9a5ec3b49e2.png)
③ コピーしたIPアドレスをブラウザのURLに入力します。
![URL入力](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691277/0c2bfb38-3ab5-ff70-9e54-50cf88c433af.png)
④ Redashの初期設定画面が表示されますので、各項目を入力し、「セットアップ」ボタンを押下します。
![redash初期設定](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691277/0d499679-a6a3-5d76-dd7d-970e692105f8.png)
⑤ 以下の画面が表示され、ログイン完了です。
![ログイン完了](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691277/8597dc3a-d321-2830-6edb-b3c9dd8af4de.png)

## データソース（Amazon  RDS）作成
① ツールバー右の「v」を選択し、表示されたリストから「Data Sources」を選択します。
![redashプルダウンメニュー](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691277/d38f799b-5197-4acd-74b6-50e31dd95a90.png)
② 設定画面が表示されますので、「＋ New Data Source」ボタンを押下します。
![データソースボタン押下](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691277/8f1e5797-ea16-727d-6999-6fb7dcf93d0d.png)
③ データソースを選択するサブウインドウが表示されますので、ここでは「MySQL (Amazon RDS)」を選択します。選択したら「Create」ボタンを押下します。
![サブウィンドウ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691277/497c4841-8481-525e-7724-86331a04ea82.png)
④ データソースの接続情報を入力し、データソースの作成を行います。
![データソース接続情報入力](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691277/a6a9fd43-c0d5-66e3-0ccd-e00aa66dd05a.png)
⑤ 接続テストを行い、成功と表示されたら「保存」ボタンを押下します。
![接続テスト](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691277/91dc1ca2-9d31-ecfd-c92e-6dfffef31e78.png)
⑥ Data Sourcesタブにデータソースが作成されました。
![image-20200818164819546.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691277/2fc51944-de9f-541f-e262-4e3b6aa7cde6.png)
以上で、データソース（Amazon RDS）の作成は終了です。

株式会社メソドロジック
赤尾　一優　@Kaz_akao
Visual Studio Codeのショートカットキー(自分用メモ)

VSCodeのショートカットキーの自分用メモです。
環境はMacです。


##覚えたい

###移動
`option` + `↑` or `↓`


###複製
`shift` + `option` + `↑` or `↓`




##参考
* [#10 実践的なショートカットキーを使おう | Visual Studio Code入門 - プログラミングならドットインストール](https://dotinstall.com/lessons/basic_vscode/50210)
PHP掲示板に検索機能の実装

PHPで作成した掲示板に、検索機能を実装したので振り返りつつ。

参考にした記事は[こちら](https://www.sejuku.net/blog/104455)。

具体的な機能は、
名前を検索すると、それに紐づいたIDと発言内容を表示する
という形。

トップページに検索内容の入力フォーム→別ファイル検索機能(`search.php`)の作成
で行った。

#検索内容の入力フォームの作成
TOPページにこんな感じで作成した。
実際に機能が動くのは`search.php`。
ここでは入力フォームで文字を受け取り、`search_name`という名前で受け取る。

```php5:index.php
<h2>検索</h2>
<form action="search.php" method="post">
    <!-- 任意の<input>要素＝入力欄などを用意する -->
    <input type="text" name="search_name">
    <!-- 送信ボタンを用意する -->
    <input type="submit" name="submit" value="名前を検索する">
</form>
```

#検索機能の作成
検索機能に関して、DB接続の前半部と、検索されてきた文字を表示する後半部に分けて説明。

##DBから任意のデータを検索する前半部。

```php5:search.php
<?php
try{
    //DBに接続
    $dsn = 'mysql:dbname=test_bbs2; host=localhost';
    $username= 'root';
    $password= 'root';
    $pdo = new PDO($dsn, $username, $password);

    //SQL文を実行して、結果を$stmtに代入する。
    $stmt = $pdo->prepare(" SELECT * FROM contacts WHERE  submit_name LIKE '%" . $_POST["search_name"] . "%' "); 

    //実行する
    $stmt->execute();
    echo "OK";
    echo "<br>";
} catch(PDOException $e){
    echo "失敗:" . $e->getMessage() . "\n";
    exit();
}
?>
```

DB接続に関しては割愛。
大事なのは

```php5:search.php 
    $stmt = $pdo->prepare(" SELECT * FROM contacts WHERE  submit_name LIKE '%" . $_POST["search_name"] . "%' "); 

```
ここの部分。

```sql:
SELECT * FROM contacts WHERE  submit_name LIKE '%" . $_POST["search_name"] . "%'
```
ここのSQL文で
・`contacts`テーブルから(FROM contacts)
・`submit_name`の条件で(WHERE submit_name)
・`$_POST["search_name"]`を**含む**値を取得する

`$_POST["search_name"]`の前後の%や、LIKEがないと、
田中という名前があった時に、「田」一文字では田中をヒットできない。
「田中」という全部一致しないと検索されてこない、という状況が起こる。

%(ワイルドカード）の使い方の詳細については
[こちら](https://qiita.com/ika_katsuo/items/40e7784284344c7d8697)の記事を参考に。

LIKEによる検索はあいまい検索という。

#DBから取得したデータを画面に表示する後半部。
DBから取り出したデータを、HTMLとPHPで記述して画面に表示する。
コードはこんな感じになっている。

```php5:search.php
<html>
    <body>
        <table>
            <tr><th>ID</th><th>Name</th><th>remark</th></tr>
            <!-- ここでPHPのforeachを使って結果をループさせる -->
            <?php foreach ($stmt as $row): ?>
            <tr>
                <td><?php echo $row[0]?></td>
                <td><?php echo $row[1]?></td>
                <td><?php echo $row[2]?></td>
            </tr>

                <?php endforeach; ?>
        </table>
    </body>
</html>
```

ここではhtmlで記述し、`foreach`で`stmt`のオブジェクトから値を取り出しています。

 - `$row[0]`でIDを、
 - `$row[1]`で名前を、
 - `$row[2]`で投稿内容を

それぞれ表示します。

あとはテーブルの形になるようにtableタグが使われています。


以上です。
個人的に大事そうだと思ったLINUXのコマンド集

<h2>GNUとUNIXコマンド</h2>

GNU：OSSのみでLinuxなどと繋がるソフト群を開発・公開しているプロジェクト.
　⇒　http://e-words.jp/w/GNU.html

>コマンドのまとめ

***pwd ; ls***…最初のコマンドが正常終了してもしなくても次のコマンドを実行する.

***ls && pwd***…最初のコマンドが正常終了したら次のコマンドを実行する.

***cat {ファイル名} || echo 'file not found'***…最初のコマンドが正常終了しなかったら次のコマンドを実行する.

***(date ; pwd ; ls) > test.txt***…()で囲むと複数のコマンドをまとめて実行する.

***echo "カレントディレクトリは$(pwd)です***"…「カレントディレクトリは/.*です」と返ってくる.

***history | tail -n 10***…コマンドの履歴を表示する.
　※![1-9]{1,}指定で該当するコマンドを実行可能

find コマンドのオプション
‣***{検索先} -atime {日数}***…任意の日数にアクセスされたディレクトリやファイルを検索する.{検索先}は未記載でも可.{日数}は当日なら0、3日以内なら-3、3日よりも前なら+3
‣***-mtime {日数}***…任意の日数にアクセスされたディレクトリやファイルを検索する.
‣***-name　[ディレクトリ名] "{あいまいな名前}"***…あいまいな名前検索.
・***-not -name"{あいまいな名前}"***…あいまいな名前を含まないファイルまたはディレクトリを検索します.

その他、容量や拡張子、パーミッション(数字指定)などで絞れる.

cpコマンドのオプション
‣***-p***…コピー元ファイルの属性(所有者、所有グループ、アクセス権)を保持してコピー
‣***-r***…ディレクトリ内を再帰的にコピーする

　※複数のオプションを実行するときは***-pr***と入力する.

mvコマンドのオプション
‣***-i***…移動先に同名ファイルがあれば上書きするか確認する

mkdirコマンドのオプション
‣***-m {パーミッション(数字)} {ディレクトリ名}***…指定したアクセス権でディレクトリを作成する.

uniqコマンドのオプション
‣***sort | uniq -d {ファイル名}***…重複している行のみ出力する.

wcコマンドのオプション
‣***-l {ファイル名}***…行数を表示する.
　※***ls | wc -l***…ディレクトリとファイルの総数を表示する.

grepコマンドのオプション
‣***-i***…大文字小文字を区別せずに検索する.

chmodコマンド(アクセス権の変更)
‣***chmod [u,g,o,a]{1,}[+,-][r,w,x]{1,}***
　※aはすべてのユーザーを表す.

chownコマンド(所有者の変更)のオプション
‣***-R***…指定したディレクトリとその中にあるすべてのファイルの所有者を変更する.
Rails でherokuデプロイ時にPrecompiling assets failedが出た

# 環境
Rails 5.2
Ruby 2.6

フロント側ではvue+vuex+vue-routerを使用

# 症状
herokuにプッシュしようとしたら、`Precompiling assets failed`のメッセージが出て、デプロイが失敗する。

ログの上のほうには
`Field 'browser' doesn't contain a valid alias configuration`
のメッセージあり。

# 原因
パッケージの依存関係に問題あり?

> https://stackoverflow.com/questions/61956924/rails-field-browser-doesnt-contain-a-valid-alias-configuration-when-pushing

package.json

``````
{
  "name": "mapApp",
  "private": true,
  "dependencies": {
    "@rails/webpacker": "5.1.1",
    "axios": "^0.20.0",
    "google-maps-api-loader": "^1.1.1",
    "leader-line-vue": "^2.1.1",
    "vue": "^2.6.11",
    "vue-loader": "^15.9.2",
    "vue-router": "^3.4.3",
    "vue-template-compiler": "^2.6.11",
    "vuex": "^3.5.1"
  },
  "devDependencies": {
    "webpack-dev-server": "^3.11.0"
  }
}
``````

# 解決方法
片っ端からパッケージのアンインストールとインストールをしたら、デプロイできました。
（npmとyarnを共存させると良くないと思ったので、インストール時にはyarnを使ってます）

``````
npm uninstall vuex 

yarn add vuex

//vuexだけでなくvue-routerや他のパッケージにも同じ操作
``````

Precompiling assets failedの原因は、scssとcss起因のものなど色々あるそうですが、
とりあえず今回はこれで解決できました
LINUXのファイルとプロセスについて

<h2>ファイルとプロセスの管理</h2>
>ハードリンクとシンボリックリンクについて

　ほとんどのOSはファイルやディレクトリに別名を付けて、異なる名前で同一ファイルにアクセスできる仕組みが幾つかあります.LINUXでいうと、ハードリンクとシンボリックリンクの2種類です。
　話しの流れ上、先にiノードについて触れます。すべてのファイルはiノード番号という重複のない番号が割り当てられており、そこにはファイル種別やサイズ、アクセス権などが記録されています.
　ここから本題に入りますと、ハードリンクは、ディスク上に保存さえているデータが1つでも、それを参照するファイルが複数あれば、それぞれのファイル名からそのデータを参照できます.ただし、元ファイルと作成したファイルに割り当てられるiノード番号は変わりません。つまり、どちらかを変更したらどっちも変わるのです。
　続いて、シンボリックリンクは、リンク元を指すポインタ自身です。このため、リンク元だけ削除することができてしまい、こうなるとシンボリックリンクからはリンク元を参照不可となります。

>リンクの作成

　構文：***ln [オプション] {リンク元} {リンクファイル名}***
オプション -s を付ければシンボリックリンクで、付けなければハードリンクを作成できる.

 ※シンボリックリンク自体をコピーしたい場合は、***cp -d***を用いる.

>プロセスの監視

プロセスとは、OSがプログラムを管理する際の基本単位です。

　構文：***ps [オプション]***

オプションは ***-ef*** あたりをよく使っています。


top - 18:04:13 up 17 days,  1:47,  2 users,  load average: 0.00, 0.00, 0.00
Tasks: 128 total,   1 running, 127 sleeping,   0 stopped,   0 zombie
Cpu(s):  0.0%us,  0.3%sy,  0.0%ni, 99.7%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Mem:   1020488k total,   816472k used,   204016k free,   186292k buffers
Swap:  2064376k total,        0k used,  2064376k free,   369096k cached

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
 1874 root      20   0  433m  39m 9536 S  0.3  3.9  24:51.55 java
    1 root      20   0 19360 1544 1224 S  0.0  0.2   0:01.25 init
    2 root      20   0     0    0    0 S  0.0  0.0   0:00.00 kthreadd
    3 root      RT   0     0    0    0 S  0.0  0.0   0:00.00 migration/0
ViewとしてのSwiftUI

SwiftUIを今までのXibやStoryboardの代わりとして使うための方法をまとめました。
Playgroundで実行します。
ViewControllerを使わない、SwiftUIとModelだけのアーキテクチャにはまだ慣れないですが、コードレイアウトとしてのSwiftUIはメリットが大きいので、取り入れていきたいです。

## 登場人物と関係

|クラス|説明|
|---|----|
|MyViewController|SwiftUIで作ったViewを表示するためのViewController|
|ContentView|SwiftUI|
|ContentViewDelegate|ボタンをタップした時のdelegate|
|ViewModel|タップ回数の変数を格納する`ObservableObject`|

それぞれの主な役割は以下の図です。

![SwiftUI+ViewController.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/297014/53e617b3-8030-ae4a-90dd-753788994dc9.jpeg)

基本的なMVCです。


## 実装

```swift
import UIKit
import PlaygroundSupport
import SwiftUI

class ViewModel: ObservableObject {
    
    @Published var count: Int = 0
    
    func increment() {
        count += 1
    }
    
}

protocol ContentViewDelegate: AnyObject {
    func didTapAdd()
}

struct ContentView: View {
    
    @ObservedObject var viewModel: ViewModel = .init()
    
    weak var delegate: ContentViewDelegate?
    
    var body: some View {
        VStack(spacing: 16) {
            Text("count : \(self.viewModel.count)")
            Button.init("Add") {
                debugPrint("Add")
                self.delegate?.didTapAdd()
            }
        }
    }
    
}

class MyViewController : UIViewController {
    
    private var contentView = ContentView.init()
    
    override func loadView() {
        super.loadView()
        view.backgroundColor = .white
        
        contentView.delegate = self
        
        let hostingVC = UIHostingController.init(rootView: contentView)
        hostingVC.view.frame = view.bounds
        view.addSubview(hostingVC.view)
        
        debugPrint(view.subviews)
        
        self.view = view
        
    }
}

extension MyViewController: ContentViewDelegate {
    
    func didTapAdd() {
        debugPrint("didTapAdd")
        contentView.viewModel.increment()
    }
    
}

// Present the view controller in the Live View window
PlaygroundPage.current.liveView = MyViewController()

```

ソース
https://gist.github.com/usk2000/394d70cba327e095f2b8002542721697

画面
<img width="50%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/297014/4d260454-652e-6aaa-bba4-a79966f1c06d.png"/>
📗【数秒で簡単】ejsでもルート相対パスでインクルードする方法

## process.cwd()

Node.jsの`process.cwd()`は、コマンドが実行されたディレクトリを返します。

たとえば、次のようなファイル構成だったとしましょう。

```plaintext
./project
└ src/
　└ *.ejs
└ package.json
└ gulpfile.js
```

この場合、`project`ディレクトリで`gulp`コマンドをたたくことになります。
その時に`process.cwd()`が返す値は`path/to/project`になるので、次のように1つ変数化しておけばルート相対URLのような感覚でパス名を記述することができます。

```js
<% const ROOT = `${process.cwd()}/src`; %>
<%- include(`${ROOT}/path/to/_include.ejs`) -%>
<%- include(`${ROOT}/path/to/_include.ejs`) -%>
<%- include(`${ROOT}/path/to/_include.ejs`) -%>
<%- include(`${ROOT}/path/to/_include.ejs`) -%>
```
4次元四目で遊ぼう


## はじめに

みなさんは，立体四目という遊びをご存知でしょうか。
[ググってみると](https://www.google.com/search?q=%E7%AB%8B%E4%BD%93%E5%9B%9B%E7%9B%AE)なんとなくお分かりいただけると思いますが，4×4×4の空間内で四目並べをするものです。
これを安易な気持ちで4次元に拡張してしまったので，そのことについて書いてみたいと思います。

## できたもの

こんな感じのものができました。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211353/3d791bd2-31a4-d336-aaec-0acadf6e165f.jpeg" width="60%">

iOS上でPythonを動かす[Pythonista 3](https://itunes.apple.com/jp/app/pythonista-3/id1085978097?l=en&mt=8)を使用して，iPadで作成しました。

### できること

- 4次元四目で遊ぶ
- 盤面の保持 (閉じてもリセットされない)
- 棋譜の保存・読み込み
- CPU対戦

## 実装の話

一応[GitHub](https://github.com/IkuzakIkuzok/4-4-4-4)にも上げておきますが，環境が限定的なので具体的なUIの実装については端折ります。

### 集計

真面目に集計しようとすると組み合わせが膨大なので，以下のような手順ですべての並びを網羅することにしました。

1. 走査する方向を表すベクトルを決める
2. その方向について，走査開始点として適当な座標をすべて列挙する
3. 開始点から指定の方向に向かって走査する

#### 1. 方向ベクトルの列挙

例えば

- x軸 → $(1, 0, 0, 0)$
- y-z平面の対角線 → $(0, \pm1, 1, 0)$
- x-z-w立方体の対角線 → $(\pm1, 0, \pm1, 1)$
- 超立方体の対角線 → $(\pm1, \pm1, \pm1, 1)$

といった感じです(すべて複号任意)。

1次元での走査では$(1, 0, 0, 0)$の軸をずらしていけばいいので，

```py
for i in range(4):
  _aggregate([[1, 0, 0, 0][i:]+[1, 0, 0, 0][:i]])
```
とすればOKです。
(`_aggregate`は2以降で出てくる関数です)

2次元以上での走査は，統一的な実装にすると可読性が悲しくなるので，あきらめて全パターンを書きました。
複号任意とするために，直積を返してくれる`itertools.product`を利用しました。
例えば，x-z-w立方体については，`product([-1, 1], [0], [-1, 1], [1])`とすることで4つの対角線を表すことができます。

#### 2. 開始点の列挙

ある軸について，走査方向が+1となっている場合には，0→1→2→3と進むために開始点の座標は0でなければなりません。
逆に，-1となっている場合には3→2→1→0と進むために3から開始する必要があります。
0の場合には，0, 1, 2, 3のすべてがあり得ます。
これを素直に書いてあげます。

```py
def start(val):
  if val == 1:
    return [0]
  elif val == -1:
    return [3]
  else:
    return range(4)
```

#### 3. 走査する

可能なすべての開始点から，指定の方向に向かって走査していきます。
開始点は，4つの軸それぞれについて複数ある中からすべての組み合わせを列挙するので，再び`itertools.product`の出番です。
具体的にはこんな感じになります

```py
def _aggregate(vec):
  for X, Y, Z, W in vec:
    if (X, Y, Z, W) == (0, 0, 0, 0):
      continue
    for x, y, z, w in product(start(X), start(Y), start(Z), start(W)):
      s = sum(
        self.get_cell(x+X*i, y+Y*i, z+Z*i, w+W*i).player for i in range(4)
      )
      if s == 4:
        self.black += 1
      elif s == -4:
        self.white += 1
```

各マスの状態は，●が+1，○が-1，何も置かれていなければ0としてあるので，全部足してみて絶対値が4なら揃っていることがわかります。

### CPU対戦

CPUは，現時点では以下のような非常にシンプルなものです。

1. 自分が3目揃っていれば，4目揃える
2. 相手が3目揃っていれば，阻止する
3. 相手が2目揃っている筋について，多くの筋で共通している箇所を阻止する
4. 自分が2目揃っている筋について，多くの筋で共通している箇所に置く
5. 上の4つで決まらなかった場合は開いているところに適当に置く

このゲームでは3を同時に2つ作れば勝ちなので，3と4のような処理が入っています。
(同じ優先順位の箇所が複数ある場合にはランダムで選ぶ)
単純なアルゴリズムの割には強いです。

## さいごに

Pythonistaをお持ちの方はぜひ遊んでみてください。
それ以外の環境に移植したという方がいらっしゃったらおしえていただけると嬉しいです!
「神経衰弱風カードフリップアプリ」の作り方

# 「神経衰弱風カードフリップアプリ」の作り方
「神経衰弱風カードフリップアプリ」を見て、自分も何か「カードゲームを作ってみたい！！」という欲求が日に日に強くなってきました。
カードをめくって、「同じ数字のペア」のカードを探すゲームなのですが、自分の「記憶力」がスコア化されるので、記憶力を強化したい意欲も湧いてきました。
## ゲームの内容
カードの枚数を「１６枚」と「３６枚」から選ぶことができるのですが、「３６枚」はかなり難しいです。
残念ながら正解率は平均「７%」くらいになってしまいました・・・
ゲームのメイン画面はこんな感じです。
![image_1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313518/3446e464-d3f8-0e34-cc4d-b881468055eb.jpeg)
「１０ゲーム」遊ぶと自分のランクが１０段階のどの位置になるのかが表示されます。
ランクは「最低が１」で「最高が１０」なのですが、自分は「１６マス」が「３」で「３６マス」が「２」でした。
記憶力には自信あったのに・・・・
## １６マスのゲーム
マス目の数が少ない「１６マス」のゲームは、
![image_2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313518/443a501a-42c9-b901-0d65-0f42e40f4b26.jpeg)

のような感じで、「４×４」の１６枚のカードの中から「同じ数字のペア」を見つけていきます。
正解率が、良い時は「５０％」を超えました。
だいたいの位置を覚えているだけでも「３０％」くらいの正解率になったので、「初心者向け」のモードです。
##３６マスのゲーム
まったく数字を覚えられなかったのが「６×６」の「３６マス」のモード。
だいたいの位置すらも自分には覚えられないレベルでした・・・
![image_3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313518/211623f7-0a17-5d93-0f6f-b05d28633532.jpeg)
「マス目」の位置を覚えるというより、特定ターゲットの数字を絞ってその数字を探した方が、結果的に早くクリアできました。
それでも、１０％ちょっと超えるくらいの正解率でしたが・・・
## プログラム言語
ゲームの処理は「Javascript」で作られているのですが、「ゲームエンジン」は使っていないみたい。
UIは「HTML5/CSS3」を使っているとのことで、自分も何かカードを利用したゲームが作れるようになりたいな~

ゲームの作り方は、

[～プログラミング初心者のための「神経衰弱風フリップカードアプリ」開発入門～](https://www.programming-fun.net/article/article_134.html)

から見ることができます。
実際にゲームで遊ぶこともできるので、「自分の記憶力を試したい方」や「ゲームの作り方を知りたい方」はぜひ一度見てみてください。

## 余談・・・
このゲームの作成のお話を一度いただいたのですが、自分には難しそうだったので断ってしまいました。
自分のゲームプログラミングのスキルをもっと上げていかないとまだまだ「カードゲーム」を作るのは難しそう。
いろんなゲームのプログラムを見ると、良い刺激になりますね。
最近はサボり気味なので、またプログラムの勉強を始めたいと思います。
プライベートIP範囲(CIDR)ホスト数早見表

プライベートIP範囲をCIDRで表記したときのホスト数の早見表です。

IP範囲(CIDR)|最初のホスト|最後のホスト|ホスト数|ネットワーク部
---|---|---|---:|---
__192.168.0.0/16__|192.168.0.1|192.168.255.254|65,534|11000000.10101000.
192.168.0.0/17|192.168.0.1|192.168.127.254|32,766|11000000.10101000.0
192.168.0.0/18|192.168.0.1|192.168.63.254|16,382|11000000.10101000.00
192.168.0.0/19|192.168.0.1|192.168.31.254|8,190|11000000.10101000.000
192.168.0.0/20|192.168.0.1|192.168.15.254|4,094|11000000.10101000.0000
192.168.0.0/21|192.168.0.1|192.168.7.254|2,046|11000000.10101000.00000
192.168.0.0/22|192.168.0.1|192.168.3.254|1,022|11000000.10101000.000000
192.168.0.0/23|192.168.0.1|192.168.1.254|510|11000000.10101000.0000000
__192.168.0.0/24__|192.168.0.1|192.168.0.254|254|11000000.10101000.00000000.
192.168.0.0/25|192.168.0.1|192.168.0.126|126|11000000.10101000.00000000.0
192.168.0.0/26|192.168.0.1|192.168.0.62|62|11000000.10101000.00000000.00
192.168.0.0/27|192.168.0.1|192.168.0.30|30|11000000.10101000.00000000.000
192.168.0.0/28|192.168.0.1|192.168.0.14|14|11000000.10101000.00000000.0000
192.168.0.0/29|192.168.0.1|192.168.0.6|6|11000000.10101000.00000000.00000
192.168.0.0/30|192.168.0.1|192.168.0.2|2|11000000.10101000.00000000.000000
192.168.0.0/31|-|-|0|11000000.10101000.00000000.0000000
192.168.0.0/32|-|-|0|11000000.10101000.00000000.00000000
【Vue.js】`v-for`, `v-if` を一緒に使うのは避けよう

# はじめに
[Vue.jsスタイルガイド](https://jp.vuejs.org/v2/style-guide/#v-for-%E3%81%A8%E4%B8%80%E7%B7%92%E3%81%AB-v-if-%E3%82%92%E4%BD%BF%E3%81%86%E3%81%AE%E3%82%92%E9%81%BF%E3%81%91%E3%82%8B-%E5%BF%85%E9%A0%88)によると、`v-if` と `v-for` を一緒に使うのは避けるべきとされています。

一緒に使うというのは

```vuejs/hoge.vue

<template v-for="item in items"  v-if="item.key === 1" :key="item.id">
      <li>
        <router-link :to="item.url">{{ item.pages }}</router-link>
      </li>
 </template>
```
上記のような、同一のタグの中にv-forとv-ifを詰め込んでいる状態のことを指しています:point_up_2_tone2:

とある記事のコメントにてv-forとv-ifの併用を勧めてしまって、（もちろん訂正コメントも送信しています:ok_hand:）
今後同じことを勧めないようにアウトプットで書きました。


## なぜだめなのか
Vue がディレクティブを処理するとき、v-forは v-if よりも優先度が高いとされていて
上の例の中身の処理をJavaScriptで書くと

```JavaScript/hoge.js
this.items.map(function (item) {
  if (item.key === 1) {
    return item.url
  }
})
```
このようになります
これだとresultに変更があった際に実際に表示されるitemの変更の有無にかかわらず
再度繰り返し処理されるのです:imp:


## じゃあどうしたいいんか

実際に表示されるitemに変化があったり条件に合うitemが増減したりする際にのみ
繰り返し処理を行うようにします。:pig_nose:

```vuejs/hoge.vue
<ul>
　　<li v-for="item in resultKey">
 　　　<router-link :to="item.url">{{ item.pages }}</router-link>
　　</li>
</ul>

~~~省略

computed: {
  resultKey: function () {
    return this.items.filter(function (item) {
      return  item.key  === 1
      }
    })
  }
}
```

今回は算出プロパティを使って解決しました。
こうすることで以下の利点が得られます:moneybag:
> フィルタリングされたリストは items 配列に関連する変更があった場合に のみ 再評価されるので、フィルタリングがはるかに効率的になります。
v-for="item in activeUsers" を使用して、描画中にkeyが1のitem のみ 繰り返し処理するので、描画がはるかに効率的になります。
ロジックがプレゼンテーションレイヤから切り離され、メンテナンス(ロジックの変更/拡張)がはるかに容易になります。
（参照：　[Vue.js スタイルガイド　v-for-と一緒に-v-if-を使うのを避ける-必須](https://jp.vuejs.org/v2/style-guide/#v-for-%E3%81%A8%E4%B8%80%E7%B7%92%E3%81%AB-v-if-%E3%82%92%E4%BD%BF%E3%81%86%E3%81%AE%E3%82%92%E9%81%BF%E3%81%91%E3%82%8B-%E5%BF%85%E9%A0%88)）



## おわり
Vue.jsって結構なんでもできちゃうのでおっこれでいけるじゃん！と思っていたものは実は推奨されていない書き方って結構あるかもですね（ドキュメントしっかり読んでいるからそんなことないわって思っている方もいるかもですが）
つまりドキュメント最強です
これ大丈夫なのかって思ったらとりあえずドキュメントですね:writing_hand_tone4:



## 参照記事
[Vue.jsドキュメント スタイルガイド](https://jp.vuejs.org/v2/style-guide/#v-for-%E3%81%A8%E4%B8%80%E7%B7%92%E3%81%AB-v-if-%E3%82%92%E4%BD%BF%E3%81%86%E3%81%AE%E3%82%92%E9%81%BF%E3%81%91%E3%82%8B-%E5%BF%85%E9%A0%88)
＃２【備忘録】Javaで九九の計算をしてみました。

# はじめに
　連日、暑い日が続いていて頭も体も鈍っているけど頑張って記事の更新は続けますので！
　今回は九九の計算ということで自分なりに見やすさとコードのシンプル化を意識して勉強してみました。
「ここはこうした方が良い」や「ここはそれじゃない」などご指摘がありましたらコメントよろしくお願いいたします。

#開発環境
今回も"Eclipse"で総合開発環境でやってみました。
こちらの記事を参考に開発環境を構築してみてください。

[EclipseでJava開発環境を作る（Mac編）](https://codeaid.jp/eclipse-java-mac/)
※今回もMacでの作業となります。

#実装
```java

class Main {
     public static void main(String[] args) {
          //九九の計算
          for(int i = 1; i < 10; i++) {
               for(int j = 1; j < 10; j++) {
                    System.out.print(" " + i + "×" + j + "=" + i * j);
               }
               //改行
               System.out.println();
          }
     }
}
```
上記コードを上から順に解説します！

　Mainクラスの中にmainメソッドを定義します。

```java
class Main {
  public static void main(String[] args) {
```

　for文を使い九九の段をループします。
まずは段について、for文の中にはint型の変数iを定義して中には1を入れ、
iは１０未満、そして変数の更新を`i++`とします。


```java
for(int i = 1; i < 10; i++) {
```

　次に段の中身のループをします。
記述は一つ前の変数名をjに変えてあげるだけです。

```java
for(int j = 1; j < 10; j++) {
```

　出力結果が◯×◯=◯のようにしたかったので以下のようにしました。

```java
 System.out.print(" " + i + "×" + j + "=" + i * j);
}
```

　そして最後に出力をしてあげます！
ここの`""`はループが終わり次のループに入る際に改行するために記述するスペースです。

```java

System.out.println();
```

　Mainクラスとmainメソッドの閉じかっこも忘れずに！]

```java
 }
}
```

#実行
```sh:実行結果
 1×1=1 1×2=2 1×3=3 1×4=4 1×5=5 1×6=6 1×7=7 1×8=8 1×9=9
 2×1=2 2×2=4 2×3=6 2×4=8 2×5=10 2×6=12 2×7=14 2×8=16 2×9=18
 3×1=3 3×2=6 3×3=9 3×4=12 3×5=15 3×6=18 3×7=21 3×8=24 3×9=27
 4×1=4 4×2=8 4×3=12 4×4=16 4×5=20 4×6=24 4×7=28 4×8=32 4×9=36
 5×1=5 5×2=10 5×3=15 5×4=20 5×5=25 5×6=30 5×7=35 5×8=40 5×9=45
 6×1=6 6×2=12 6×3=18 6×4=24 6×5=30 6×6=36 6×7=42 6×8=48 6×9=54
 7×1=7 7×2=14 7×3=21 7×4=28 7×5=35 7×6=42 7×7=49 7×8=56 7×9=63
 8×1=8 8×2=16 8×3=24 8×4=32 8×5=40 8×6=48 8×7=56 8×8=64 8×9=72
 9×1=9 9×2=18 9×3=27 9×4=36 9×5=45 9×6=54 9×7=63 9×8=72 9×9=81
```

と表示されていれば成功です！

#エラーになってしまう場合
可能性としては`;`が抜けている場合があると思いますので確認してみてください！

#最後に
　最近、学習時間が取れていないので「どこか空き時間を作らなきゃ」と切羽詰まっています汗
でも、自分で自分を追い込むのは好きではないので色々と戦ってます、、、
頑張ります！
.NET Core（3.1）セットアップ

# .NET Coreを使用した開発について

.NET Coreで開発するためには、最低限、.NET Core SDKをインストールすればよい。
開発には、Visual Studio Code使用を推奨。
CLIコマンドでプロジェクト作成、ビルド、実行等を行う。

# Windows10での.NET Core（3.1）のセットアップ方法

1. https://dotnet.microsoft.com/download#/sdk にアクセスする。
![download.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/695430/1c9e8fa7-5173-862f-4a36-4afd6ba56b56.png)

2. Download .NET Core SDKからSDKをダウンロードする。
3. ダウンロードされたdotnet-sdk-3.1.401-win-x64.exeを実行、インストールする。
4. Visual Studio Codeに以下の拡張機能をインストール
![vscode.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/695430/d28f1895-21c9-bdb7-967d-392dd44e0004.png)

# .NET Coreインストール確認
1. 適当なパスで`dotnet new`を実行する。
2. 以下のような説明文が表示される。

```
.NET Core 3.1 へようこそ!
---------------------    
SDK バージョン: 3.1.401  

テレメトリ
---------
.NET Core ツールは、エクスペリエンスの向上のために利用状況データを収集します。データは...
```

# Hello World!

1. Hello Worldアプリケーションを作るフォルダを作成し、移動する。
2. ターミナルよりCLIコマンド`dotnet new console`を実行する。プロジェクトが作成される。

```
The template "Console Application" was created successfully.

Processing post-creation actions...
Running 'dotnet restore' on C:\work\dk\DG-Connect\tmp\tmp.csproj...
  復元対象のプロジェクトを決定しています...
  C:\work\dk\DG-Connect\tmp\tmp.csproj を復元しました (167 ms)。

Restore succeeded.
```
3．プロジェクトが作成されたら`dotnet run`を実行する。ターミナルに`Hello World!`が表示される。
【Axios】Nuxt.jsで、axiosを使ってサーバーとの通信を行う。

Nuxt.js下で、サーバーとの通信を行うことができるaxiosについてまとめたいと思います。

具体的にできることとしては、**サーバーからのデータを取得したり(GET)**、サーバーのデータを更新したり(PATCH / PUT)することができる。

今回は、GETリクエストに絞って使い方についてみていきましょう。

#モジュールを利用できるようにする

axiosではなく、@nuxtjs/axiosをインストールすることで、**ファイルごとにimportする必要がなく**なる。
また、レスポンス値がdataプロパティであるため、```res.data```にする必要がなくなる。（後述）

```shell
$ yarn add @nuxtjs/axios
```

```nuxt.config.js
  modules: [
    '@nuxtjs/axios',  
  ],
```


#リクエスト後のレスポンスによって、処理を変える

###基本形

```javascript
$axios.$get(URL)
  .then(function (res) {
    //通信が成功した後の処理
  })
  .chach(function (error) {
    //通信が失敗した後の処理
  })
  .final(function () {
    //通信後に必ず実行される処理
  })
```

1. getの引数にURLを取ることで、GETリクエストを送信
2. レスポンスの値は、functionの引数に格納される

###実践

今回は、無料の外部サービスである[JSONPlaceholder](https://jsonplaceholder.typicode.com/)を利用させてもらって、外部のデータを取得していきます。

```javascript:Vue.js
<script>
export default {
  data () {
    return {
      posts: []
    }
  },
  mounted ()  {
    const res = $axios.$get('https://jsonplaceholder.typicode.com/posts/')
    .then(function (res) {
      this.posts = res
    })
  }
}
</script>
```

ページが読み込まれた後に、外部データを取得し、postsに格納することができる。

axiosの場合だと```res.data```にしなければならないが、@nuxtjs/axiosだとレスポンス値がdataプロパティであるため、```res```だけでデータを取得できる。


#簡略化したリクエスト後の処理

###基本形

```javascript
async function () {
  const res = await $axios.$get(URL)
  //通信後の処理
}
```

###実践

```javascript:Vue.js
<script>
export default {
  data () {
    return {
      posts: []
    }
  },
  mounted ()  {
    async function (context) {
      const res = await context.$axios.$get('https://jsonplaceholder.typicode.com/posts/')
      this.posts = res
    }
  }
}
</script>
```