OmniAICreator/Qiita-1.07M huggingface dataset:
Docker/Kubernetesなど コマンド一覧

仕事および趣味で利用した、Docker/Kubernetesのコマンドの備忘。
ついでに使わないとすぐ忘れるLinuxなどその他色々コマンドの情報のせます。。

Docker
---

|  コマンド  |  概説 | 例 |
| ---- | ------- | ------- |
| docker ps  |  稼働コンテナの一覧表示  | 実行中：docker ps <br> 終了状態含む：docker ps -a |
| docker images  |  ローカルで保持しているイメージリストを表示  |
| docker rmi [id名] |  ローカルのイメージを削除  | 削除できない場合は、 docker rmi [id名] -f で実行する<br> -f:強制的に削除| 
| docker build [-t リポジトリタグ] |  Dockerfileからイメージのビルド  |
| docker pull [コンテナイメージ] |  コンテナイメージのダウンロード |
| docker run [コンテナイメージ] |  コンテナイメージを指定して起動  |
| docker run -it [image名] shell |  コンテナを起動して対話型シェルを実行  | docker run -it  centos bash |
| docker logs [Container ID] | ログ表示 | | 
| docker hisotry [images ID] | イメージへの履歴 | | 
| docker tag ローカルイメージ名:タグ リモートリポジトリ:タグ名|ローカルリポジトリのイメージをリモートリポジトリ名にタグ付け| |
| docker push タグ付けしたリモートリポジトリ名 | リモートリポジトリへの登録 | | 
| docker commit containerID image:tag | コンテナイメージの登録 | | 
| docker start containerID | コンテナの開始 | | 
| docker stop containerID | コンテナの停止 | | 
| docker stop $(docker ps -q) | 稼働中の全コンテナの停止 | | 
| docker network ls | コンテナネットワークをリスト表示 | | 
| docker network inspect [networkID] | コンテナネットワークの詳細設定を表示 | | 
| docker network create [ネットワーク名] | コンテナネットワークを新規作成 | docker network create mynet1| 
| docker built -t イメージ名:tag名 DockerfileのPATH名 | Dockerイメージの作成 | docker build --tag mydaemon:0.1 ./Dockerfile | 



Kubernetes
---

|  コマンド  |  概説 |
| ---- | ------- |
|  docker ps  |  稼働コンテナの一覧表示  |
|  TD  |  TD  |
|  TD  |  TD  |




Linux
---
ほぼCent0Sの例です。

**Cent0S**

|  コマンド               |  概説         | 例 |
| -------------------- | ------------------ |------------------ |
|  systemctl list-unit-files -t service   |  サービス一覧と自動起動設定の確認 <bk> （旧 chkconfig --list） | |
|  cat /etc/redhat-release                   |  バージョン確認  | |
|  yum list installed                   |  yumでインストールされた一覧の確認  | |
|  nslookup dns(ip)                   |  DNSサーバーへの名前解決問い合わせ | ||                     
|  pubcopy                   |  cliの中身をクリップボードにコピー  |pbcopy <~/.ssh/id_ed25519.pub ||


sshの設定ファイル
--
* /home/.ssh ※ `cd ~/.ssh `で移動できれば存在する。sshするときのhostネームなどが格納できる


参考
---
Docker reference
https://docs.docker.com/engine/reference/commandline/build/

Docker コマンドチートシート
https://qiita.com/wMETAw/items/34ba5c980e2a38e548db

awkコマンド
https://www.atmarkit.co.jp/ait/articles/1706/08/news015.html
Ubuntu19.10 への docker のインストール

# Ubuntu 19.10 への docker のインストール

```
#!/bin/sh -e

sudo true
sudo apt-get update  -y
sudo apt-get install -y \
    apt-transport-https \
    ca-certificates \
    curl \
    gnupg-agent \
    software-properties-common

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

sudo apt-key fingerprint 0EBFCD88

sudo add-apt-repository \
   "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
   $(lsb_release -cs) \
   stable"

sudo apt-get update -y

sudo apt-get install  -y docker-ce docker-ce-cli containerd.io
sudo systemctl start  docker
sudo systemctl enable docker

sudo apt install -y docker-compose
```

## $(lsb_release -cs) に関して

```
$ sudo add-apt-repository \
   "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
   $(lsb_release -cs) \
   stable"
```

Ubuntu 19.10 では ```$(lsb_release -cs)``` の値は ```eoan``` になります。

新しい ubuntu のバージョンが出たばかりだと ```$(lsb_release -cs)``` を指定するとインストールできないことがあります。

```$(lsb_release -cs)``` の部分を例えば ```disco``` (=Ubuntu 19.04) など古いリリースを指定することで対応するモジュールがリリースされていなくてもインストールできます。

https://download.docker.com/linux/ubuntu/dists/ を確認することで対応するモジュールがあるか確認できます。

## リンク

https://docs.docker.com/install/linux/docker-ce/ubuntu/
要素の配置するためにかなり便利なCSS機能、、position

#初めに、、

日本語に翻訳すると

position ＝　場所
absolute　＝　絶対
relative = 相対的

です


##使い方

今回は、白い箱を基準に動かしていきます
デフォルトでは、top:0px;・left:0px;のところに配置されている

----------------------------------------------------------------------------------

指定なしの場合

```
position:relative;
```

<img width="833" alt="スクリーンショット 2020-03-22 15.27.34.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538355/ca7143f0-82be-6397-1aa6-df01b5ceafa3.png">



赤いprodactをrightに200px動かすと、、

```
position:relative;
right:0px;
```

<img width="778" alt="スクリーンショット 2020-03-22 15.35.53.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538355/edf1dab0-ad63-64e6-58fc-93555b57e2cb.png">


赤いprodactをtopに0px動かすと、、

```
position:relative;
top:0px;
```

<img width="827" alt="スクリーンショット 2020-03-22 15.35.06.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538355/1fb7a4af-900c-3037-7394-04c879dc4dc1.png">



赤いprodactをbottomに0px動かすと、、

```
position:relative;
bootm:0px;
```

<img width="776" alt="スクリーンショット 2020-03-22 15.33.20.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538355/b09d1709-0c6e-317c-c38f-80dcebf26333.png">


赤いprodactをleftに200px動かすと、、

```
position:relative;
left:0px;
```
<img width="786" alt="スクリーンショット 2020-03-22 15.37.41.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538355/944ec591-5eb8-feec-1f64-981298018cd3.png">


##最後に
ポジションの指定は、複数合わせる事ができて、例えば、、、

top 200px
left 200px
指定すると、、、

```
position:relative;
top:200px;
left:200px;
```

<img width="828" alt="スクリーンショット 2020-03-22 15.44.43.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538355/f3aaafb7-56e9-e506-c475-52776494cc2a.png">

上記のように配置されます
【Linux】遺伝統計ソフトPLINKでeQTL解析

#はじめに

最近、遺伝統計ソフトのPLINKを使い始めた。
この本を参考にPLINKの使い方を勉強。

[ゼロから実践する　遺伝統計学セミナー](https://www.yodosha.co.jp/yodobook/book/9784758120920/index.html)

この本はWindows用に書かれているので、Macでのやり方を備忘録的に書いていく。
今回は、PLINKでeQTL解析をやってみた。

#####参考
PLINKの基本的な使い方、GWAS解析方法は以前に投稿済み
[【Linux】遺伝統計ソフトPLINKを使ってみた](https://qiita.com/fogdiffusion/items/790553a5a92d759c6ab3)
[【Linux】遺伝統計ソフトPLINKでGWAS](https://qiita.com/fogdiffusion/items/b901ccc52c2bc9c44f3a)

#使うデータ

####bed|bim|fam形式ファイル
- SNP_QC.bed
- SNP_QC.bim
- SNP_QC.fam

SNPをフィルタリング済みのファイル

####表現型ファイル
- Exp_BLK.txt

BLK遺伝子の発現量データ

#eQTL解析
eQTL解析では、遺伝子発現量という量的形質に対して解析するため、線形解析を行う。
使うコマンド一覧。
``--pheno``：GWASに使う表現型ファイル（今回はExp_BLK.txt）を入力
``--linear``：線形回帰を実施
``--ci 0.95``：95%信頼区間を出力

```sh:GWAS（線形解析）
$ ./plink --bfile SNP_QC --out SNP_QC_Exp_BLK --pheno Exp_BLK.txt --linear --ci 0.95
```

作業ディレクトリに**SNP_QC_Exp_BLK.assoc.linear**という名前のファイルが出力されているのを確認して、テキストエディタで開く。
1列目が染色体番号、2列目がSNP ID、3列目が染色体位置、12列目が*p*値となっている。

#AWKによる要素の抽出

GWAS結果から、AWKコマンドで「染色体番号」、「SNP ID」、「染色体位置」、「*p*値」の列を取り出す。
AWKコマンドで、入力ファイルを**SNP_QC_Exp_BLK.assoc.linear**、出力ファイルをテキストファイルとした**SNP_QC_Exp_BLK.assoc.linear.P.txt**とする。
AWKでは' 'で区切って、この中にコマンドを書いて実行する。
``{print $2"\t"$1"\t"$3"\t"$12}``によって、
「2列目[SNP ID]　1列目[染色体番号]　3列目[染色体位置]　4列目[*p*値]」というデータフレームになる。
``"\t"``はタブで区切るというコマンド。
``>``によって指定したテキストファイルとして出力する。


```sh:AWKコマンドでGWAS結果から要素を抽出し、テキストファイルを出力
$ awk '{print $2"\t"$1"\t"$3"\t"$12}' SNP_QC_Exp_BLK.assoc.linear > SNP_QC_Exp_BLK.assoc.linear.P.txt
```

このGWAS結果を使ってマンハッタンプロットを描く。

#マンハッタンプロットの描画

マンハッタンプロットを描いてみたらこうなった。
![1KG_EUR_QC_Exp_BLK.assoc.linear.P_position_P_15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/471633/2df12dd2-fed6-4c7a-1964-4f43f7ba595d.png)

#SNPの特定
eQTL効果を示したSNPを抜き出してみる。

```sh:AWKでSNPを抽出
awk '$4<=10^-12 {print $0}' 1KG_EUR_QC_Exp_BLK.assoc.linear.P.txt
```

出力

```sh
rs13255193	8	11309192	4.539e-13
rs13257831	8	11332964	6.545e-13
rs2736345	8	11352485	1.707e-14
rs1478898	8	11395079	6.882e-16
rs2244894	8	11448659	1.497e-13
rs2244648	8	11450422	2.068e-14
rs13273172	8	11461111	1.188e-14

```

*p*値が最小のSNPは**rs1478898**であった。
【初心者メモ】Pythonでのライブラリ読み込みパス指定の仕方


パスの勉強のお時間がやってまいりました。

自作したPythonファイルで、別のファイルを読み出すという時にパスの指定方法でつかえました。メモとして残します。内容は初心者向けです。

## 要約
- sys ライブラリ、 osライブラリを使ってsys.path.append(os.pardir)という形はよく使われる
- sys.path.append("hoge")のhoge部分に相対パスを指定すればそこから読み出してくれる

## 本論

#### 前提
下記のファイルで、main.pyからfunctions.pyを読み出したい想定

```
/application
  /common
    functions.py
  /main
    main.py #今自分がここにいるとする

```

#### 方法1：sys.path.append(os.pardir)を使う。

```
import sys, os
sys.path.append(os.pardir)

# 読み出したいファイル名
from common.functions import hogehoge

```
#### 解説
- sys, os -> それぞれPythonの基本ライブラリ(=インストール不要でimport指定だけで使えるようになるライブラリ)。sysはpythonの実行環境に関連する操作、osはOSに関わる基本操作を可能にするもの。
- sys.path -> ライブラリを読み込むパス(C:/hogehoge/hogehoge/みたいな)を 表す
- sys.path.append("hoge") -> 上記をhogeに変更する
- os.pardir -> OS依存の親ディレクトリを表す文字列を表す。Windowsの場合、***「..」***に相当する(コマンドプロンプトに ```cd ..``` って打つ時の```..```に相当)
- 上記コードでは、sys.path.append(os.pardir)とコードが読まれた瞬間に、ライブラリの読み込みディレクトリが/applicationsに変更されるので、そのあとcommon.functions.pyの読み込みが可能となっている


#### 方法2：sys.path.append()の括弧内に相対パスを指定する

```
import sys
sys.path.append("../common")
```
#### 解説
- やっていることは方法1と同じです
- ただし、こちらなら複雑なディレクトリを表現できます
- 例えば```sys.path.append("../../another_application/lib/hogehoge")```



(以上)
JavaScript debounce

```typescript
let timeoutId: NodeJS.Timeout | null = null;

const debounce = (func: Function, delay = 1000): void => {
  if (timeoutId != null) {
    clearTimeout(timeoutId);
  }

  timeoutId = setTimeout(() => {
    func();

    timeoutId = null;
  }, delay);
};
```

<p class="codepen" data-height="265" data-theme-id="light" data-default-tab="js,result" data-user="yoshiharu2580" data-slug-hash="RwPYoGp" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="debounce">
  <span>See the Pen <a href="https://codepen.io/yoshiharu2580/pen/RwPYoGp">
  debounce</a> by Yoshiharu (<a href="https://codepen.io/yoshiharu2580">@yoshiharu2580</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>
SpringBoot × OpenAPIGenerator  × Springdoc

# 更新履歴

|日付|内容|
|:--|:--|
|2021.02.14|記事の情報に一部追記|
|2020.03.20|初版|

# はじめに

WebApiを新規製造することになった。
プロダクトの構成などはほとんど僕が決めてよくなった為、OpenAPIGeneratorを試してみることにした。
今回はSpringBoot 2.x , Gradle , Jdk >= 8での構築を前提とする。

# OpenAPIGenerator

使用したバージョンは `4.2.3`

2021.02/14 時は `5.0.1` が存在する

## OpenAPIGenerator とは

簡単に書くと、WebApiの仕様をOpenAPIの仕様通り記載した `yaml` , `json` から各種コードを生成してくれるツール群。
今回はGradleのプラグインからSpringベースのコードを生成した。
また、参考は少なかったがyamlでなくjsonで作成した。

## セットアップ

1. yamlにエンドポイントやレスポンス構造を記入 -> https://editor.swagger.io
2. jsonにコンバートし、プロジェクトに保存
3. build.gradleにプラグインを設定
4. コード生成

## build.gradle

```groovy:build.gradle
plugins {
    id "org.openapi.generator" version "4.2.3"
}

openApiGenerate {
    generatorName = "spring"
}
```

詳しくは[README](https://github.com/OpenAPITools/openapi-generator/blob/v4.2.3/modules/openapi-generator-gradle-plugin/README.adoc)

## 自動生成コード

今回生成したコードについては原則バージョン管理を行わない。
自動生成に任せたい責務についてはI/F、バリデーションのみ。
自動生成されたインターフェースをコントローラで実装(implements)する。
コントローラー内の処理についてはスクラッチで書く。

# Springdoc

使用したバージョンは `1.3.0`

2021.02/14 時は `1.5.4` が存在する

## Springdoc とは

自動生成したコードをSwagger-UIなどで表示したかった。
以前はSpringFoxなどを活用していたが、ネットを検索していたらSpringdocに辿り着いた。
build.gradleのdependenciesに追加、application.yamlに設定を追加すると始められる。

## セットアップ

1. build.gradleにプラグインを設定
2. bootRun

## build.gradle

```groovy:build.gradle
dependencies {
    // springdoc-openapi-ui
    implementation("org.springdoc:springdoc-openapi-ui:1.3.0")
}
```

## Swagger-UI

OpenAPI 3.0ベースのアノテーションとSpring系のアノテーションからSqagger-UIを生成してくれる。
ただし、OpenAPIGeneratorは `springfox` のアノテーションを付与してコードを自動生成する為、大部分が表示されない。
コントローラーに別途OpenAPI 3.0ベースのアノテーションを付与すれば表示をカスタマイズされる気がしている。(やっていないけど

# おわりに

APIの軽い動作確認をする際は、ローカルのApiクライアントツールで実行するよりも、Swagger-UIを実行した方が楽である。
仕様書と(自動生成)コードが1:1なので、I/Fとコードが解離する現象にはならなそう。
※ jsonを置き去りにしたら解離するだろうが、、、笑
WSL上にnuxtをインストール

気になっていたWSL環境で入れてみた。導入したのはUbuntu18.04、何も考えずにnuxtのインストールを試みたらエラーの嵐だったが、原因はnpmとnodeのアップデートをしていなかったことが原因だった。アップデート大事。nuxtをインストールする前にnpmとnode.jsのアップデートをしておこう。
####npmのアップデート

```Console
$ sudo npm update -g npm
```

####nodeのアップデート
nodeをアップデートするために n というパッケージを使用する。

```Console
$ sudo npm install -g n
```
--stableで現在の推奨バージョンを確認できる。

```Console
$ n --stable
```
stable版のインストール

```Console
$ sudo n stable
```
####nuxtのインストール
npxかyarnが必要である。私はnpxを使用した。

```Console
$ sudo npm install -g npx
```
nuxtをcreate-nuxt-appで導入する。

```Console
$ sudo npx create-nuxt-app <project-name>
```
導入を終えたら<project-name>ディレクトリ内へ移動して、パッケージインストールを済ませる。

```Console
$ cd <project-name>
$ sudo npm install
```
サーバー起動

```Console
$ npm run dev
```
ローカルサーバーが起動するはず。
Djangoの対話シェルにおけるエラー ( KeyError: "'__name__' not in globals")


クラスのインポート仕方が誤っています。
以下でオッケーです

```python
from <アプリ名>.models import <クラス名>
```


以下のようにアプリ名がないとKeyErrorがでるみたいです。

```python
from .models import <クラス名>
```
xkeysnailでCAPS LOCKをCtrlにリマップする in debian buster

## 追記 2020.3.23

``/etc/modules-load.d`` へ uinput をロードする設定を追記する必要があるのを失念していたため追記．


## 参考にした記事

- [mooz/xkeysnail: Yet another keyboard remapping tool for X environment](https://github.com/mooz/xkeysnail#installation)
- [xkeysnailをsystemdでデーモン化 \- Qiita](https://qiita.com/samurai20000@github/items/2e1d779e806a7e8543d6)

ExecStartPreを削らないとdebianでは動作しなかった．ということに気付くのに結構時間がかかったという話．

## 目標

ノートPCに入れた debian buster で xkeysnail を使って CAPS LOCK を 左Ctrl として使いたい．

## 手順

### 1. install xkeysnail  

xkeysnail をインストールする．
python2 では importerror を吐くので，諦めて公式（[mooz/xkeysnail: Yet another keyboard remapping tool for X environment](https://github.com/mooz/xkeysnail#installation)）に従い python3 で導入する．

```sh
sudo apt install python3-pip
pip3 install -U
pip3 install xkeysnail
```

### 2. input/uinput を write mode で開けるよう設定

基本的には，この記事に従って設定する．  
[xkeysnailをsystemdでデーモン化 \- Qiita](https://qiita.com/samurai20000@github/items/2e1d779e806a7e8543d6)

group を作って，自分を groupに所属させる．

```shell
sudo groupadd uinput
sudo gpasswd -a hadacchi input
sudo gpasswd -a hadacchi uinput
```

次に /dev/input/* や /dev/uinput の設定．

```config:input.rules
KERNEL=="event*", NAME="input/%k", MODE="660", GROUP="input"
```

```config:uinput.rules
KERNEL=="uinput", GROUP="uinput"
```

kernel moduleのロードを設定．

```config:/etc/modules-load.d/uinput.conf
uinput
```

設定ファイルをコピーし，記事のコマンドでは，やはりうまいくかないので再起動する．

```shell
sudo cp input.rules uinput.rules /etc/udev/rules.d/
sudo reboot
```

### 3. xkeysnailの設定

今回はCAPS LOCKを左Ctrlに変換するだけなので，マッピングの設定はここまで減らせる．

```python:~/.xkeysnail/config.py
from xkeysnail.transform import *

define_modmap({
    Key.CAPSLOCK: Key.LEFT_CTRL
})
```

次にxkeysnailを自動起動させる設定を行なう．
ここが一番ハマった．

systemd の service ファイルはこう．
xhostにrootで接続するための設定は，今回の方法ではいらない．DISPLAY変数は，リモートアクセスする場合に必要となる可能性はあるけど，ノートPCなのでリモートアクセスの予定もないし，試していないのであしからず．

```config:~/.config/systemd/user/xkeysnail.service
# 1. Copy this from ~/.config/systemd/user/xkeysnail.service
# 2. systemctl --user enable xkeysnail

[Unit]
Description=xkeysnail

[Service]
KillMode=process
ExecStart=/usr/local/bin/xkeysnail /home/hada/.xkeysnail/config.py
#ExecStartPre=/usr/bin/xhost +SI:localuser:root
#↑input/uinputグループの権限で実行するのでrootでxhostに接続する必要なし．
# むしろ，こいつがエラーを引き起こす
Type=simple
Restart=always

# Update DISPLAY to be the same as `echo $DISPLAY` on your graphical terminal.
#Environment=DISPLAY=:0
#↑sudoでxkeysnailを起動する時は，上のxhostのコマンドとセットで必要となるが，今回はいらない．

[Install]
WantedBy=default.target
```

xkeysnail.service を動作させる．

```shell
systemctl --user enable xkeysnail
```

CAPS LOCKでCtrlとして動作するか確認．
次にリブートして最初から動作するか確認．

完了．

# hadacchiの設定

ノートPCで日本語キーボードのため変換キーとか無変換キーとか無駄なキーが多い．
今はこうなっている．

```python:~/.xkeysnail/config.py
from xkeysnail.transform import *

define_modmap({
    Key.CAPSLOCK: Key.LEFT_CTRL,
    Key.MUHENKAN: Key.LEFT_ALT,
    Key.HENKAN: Key.RIGHT_ALT,
    Key.KATAKANAHIRAGANA: Key.RIGHT_ALT,
    Key.LEFT_ALT: Key.LEFT_META,
})
```
Git の push 時のパスフレーズ省略

# はじめに
Windows + Git で SSH 通信の環境を対象としています。
パスフレーズの省略方法は複数ありますが、一番かんたん & セキュリティ的によさそうな方法
と個人的に思うものを記載します。

# 環境
* [Microsoft Windows 10 Pro](https://www.amazon.co.jp/Microsoft-Windows-April-Update適用-パッケージ版/dp/B07765H5G4/ref=sr_1_4?ie=UTF8&qid=1538288847&sr=8-4&keywords=windows10%2Bpro&th=1)  

# `~/.bashrc`

`~/.bashrc`に以下を記入します。`~/.bashrc`がない人は新規作成してください。
ssh-add の行には、.pub ではない鍵(秘密鍵)を指定してください。
※`~/`は`%HOME%`を指しています。今回の場合は`C:/Users/<ユーザー名>`フォルダに`.bashrc`を新規作成してください。

```bash:~/.bashrc
#ssh-agent
eval $(ssh-agent -s)
ssh-add ~/.ssh/キー名
```

`~/.bashrc`は、Git Bash 起動時のみ実行されるので起動中の場合は再起動してください。
または、bash コマンドを叩くでも OK。

# `~/.bash_logout`

ターミナルを閉じたときに、`~/.bashrc`で起動した ssh-agent を終了させるため
`~/.bash_logout`に以下を記入します。`~/.bash_logout`がない人は同じく新規作成してください。

```bash:~/.bash_logout
ssh-agent -k
```

# Git Bash 起動時
Git Bash 起動時にパスフレーズを聞かれるようになります。
Git Hub (Git Lab) のパスワードを入力してください。入力後は、Git Bash を新たに立ち上げるまでパスフレーズを聞かれることはありません。

```bash
Agent pid 553
Enter passphrase for /c/Users/username/.ssh/id_rsa:
```

`~/.bashrc`を新規作成した人は、以下の警告が出ることがありますが

> <font color="Red">WARNING: Found ~/.bashrc but no ~/.bash_profile, ~/.bash_login or ~/.profile.</font>
> <font color="Red">This looks like an incorrect setup.</font>
> <font color="Red">A ~/.bash_profile that loads ~/.bashrc will be created for you.</font>

~/.bash_profile、 ~/.bash_login または ~/.profile が見つからないので、~/.bashrc を読み込む ~/.bash_profile を作りました！
といった内容のため、気にしなくても問題はありません。

パスフレーズ入力後、以下のように出力されれば OK。

```bash
Agent pid 553
Enter passphrase for /c/Users/username/.ssh/id_rsa:
Itentity added: /c/Users/username/.ssh/id_rsa
```

# さいごに
パスフレーズ省略の記事はいくつかありますが、
`_netrc`・`.gitconfig`等の複数ファイルを編集する、パスフレーズをファイルに平文で記入するなど
むずかしそう & ファイルにパスフレーズを直接記入するのはセキュリティ的に不安だと思い
この方法に落ち着きました。
angularでcypressのunit test

#内容
 angularでcypressにunit test結果をcode-coverageに追加する方法
注：この投稿のあと、code-coverrageが更新されまして、最新バージョン(2020/4/25現在)には以下は適用できません。最新バージョンはhttps://github.com/bahmutov/cypress-angular-coverage-example を参照してくださいませ

#準備と内容の細部
 https://github.com/skylock/cypress-angular-coverage-example
 に従えば、angular + cypress + code-coverageまでは可能

 問題は、cy.visitのe2eのやり方ではなく、直接コードの単体試験を行った結果(importで検証モジュールを持ってきて検証)をcode-coverageにマージする方法が、reactあたりはあるんだが、angularでの可能な方法がなかった。

#修正の概要
　ng sでコンパイルしている方は、準備の中でngx-build-plusでistanbule--instrumenter-loaderを追加して、code-coverage用のコンパイルを行っているんだが、*.spec.ts側はcypress/pluginsの中のcy-ts-preprocessor.jsでtypescript変換をしているだけなので、ここに「istanbule--instrumenter-loader」を追加すれば、OKっちゅうことですね。

#詳細
改修前のcy-ts-preprocessor.js

```javascript:cy-ts-preprocessor.js
const wp = require('@cypress/webpack-preprocessor')

const webpackOptions = {
  resolve: {
    extensions: ['.ts', '.js']
  },
  module: {
    rules: [
      {
        test: /\.ts$/,
        exclude: [/node_modules/],
        use: [
          {
            loader: 'ts-loader'
          }
        ]
      }
    ]
  }
}

const options = {
  webpackOptions
}

module.exports = wp(options)
```

```javascript:追加部分[use]
        use: [
          {
            loader: "istanbul-instrumenter-loader",
            options: { esModules: true },
          },
          {
            loader: 'ts-loader',
          }
        ]
```
これだけで、e2eのやりきれない部分をimportしたソースで単体試験を追加することが可能！
ああ、しんど！
【Rails】バリデーションによるエラーメッセージ表示の手順

##はじめに
Railsで、バリデーションによるエラーメッセージの表示をしようとしたら
エラーが出てしまい、調べてみたらとても初歩的なミスを犯していたので
忘れないよう、エラーメッセージ表示の手順を、自分用のメモみたいな感じでまとめました！


##手順
「新規投稿」を例にとることにします。

まず、新規投稿が行われる手順から
順を追って、バリデーションによるエラーメッセージの表示方法について説明していきます。
<br>
1.まずは、modelフォルダの中のpost.rbファイルの中で、バリデーションを設定します。
これによってバリデーションに弾かれたデータには自動でエラーメッセージが取得されます。

```ruby:models/post.rb
class Post < ApplicationRecord

  validates :content, presence: true,
                      length: {maximum: 140}

end
```

<br>
2.「new.html.erb」で投稿ボタンを押すと、form_tagで指定したURL("/posts/create")へデータが送信されます

```ruby:new.html.erb
 <%= form_tag("/posts/create") do %>

   <textarea name="content"> </textarea>
   <input type="submit" value="投稿">

 <% end %>
```
<br>
3.送信されたデータをルーティングで取得し、createアクションへ

```ruby:routes.rb
post "posts/create" => "posts#create"
```
<br>
4.送信されて来たデータの保存が完了した場合→("/posts/index")画面へ。
バリデーションに弾かれ、保存されなかった場合→再び("/posts/new")画面へ転送する。

```ruby:posts_controller.rb
 def create
   @post = Post.new(content: params[:content])
     if @post.save
       redirect_to("/posts/index")
     else
       render("posts/new")
     end
 end
```
<br>

この後、データベースに保存された全ての投稿データを取得し、繰り返し処理によりビューで表示することで、投稿が一つずつ表示されるわけですが

私は、バリデーションに弾かれたエラーメッセージの取得が、手順３の段階でされるのだと思っていました。

それゆえ、以下のように３の手順で取得した@postから、エラーメッセージを表示させようとしたら

```ruby:new.html.erb
 <% @post.errors.full_messages.each do |message| %>

    <%= message %>

 <% end %>
```
「__undefined method `errors' for nil:NilClass__」
といったように、エラーメッセージが定義されてませんと怒られてしまいました…ごめんなさい…。
<br>
何故取得できないのかというと、２の手順でバリデーションに弾かれたデータは
newアクションへ転送され、__newアクションで取得する必要がある__からでした。

__つまり、弾かれたデータは直前のアクションに送信されます。
しかし、それ以前に「new.html.erb」で「createアクションで定義した変数」を使えるわけないのですから当然でした……__
(ただしrenderで転送した場合は、そのまま変数の転送も行ってくれる)

ですので、以下のように、newアクションで変数を定義してあげることで
ここに、バリデーションで弾かれたデータが作成されるようになります。

```ruby:posts_controller.rb
  def new
    @post = Post.new
  end
```
<br>
あとは、「new.html.erb」で、エラーメッセージを表示するためのコードを書いてあげれば
ちゃんとエラーメッセージが表示されるようになるはずです。

```ruby:new.html.erb
 <% @post.errors.full_messages.each do |message| %>
    <%= message %></p>
 <% end %>
```

##参考
[【Rails】バリデーションのエラーメッセージを表示する](https://blog.yuhiisk.com/archive/2018/05/22/rails-display-error-message.html)
[Progate](https://prog-8.com/)
フォルダ内のすべてのxlsxファイル名を自然順のリストで取得して、絶対パスを構築する

# 背景・前提・仕様とか

仕事用でExcelファイルを扱うツールを作るときの備忘テンプレ。

意図した動作の前提として、下記の状態と想定しています。

- デスクトップ上に任意の名前（下記コード中のfolder_name）でフォルダを作り、その中に扱いたいxlsxをすべて放り込んだ状態で動かす。

- フォルダ内の全xlsxのファイル名リストを、自然順のリストで取得

- ファイル名リストをfor文で順繰り取得して、各ファイルの絶対パスを構築するところまで。


# 自然順とは

「ファイル名＋番号」みたいなリストを、人間から見ていい感じに整列させたときの順序。

例えば、

```
["n5", "n1", "n10"]
```

というリストを普通にソートすると、

```
["n1", "n10", "n5"]
```

となるけど、自然順だと、

```
["n1", "n5", "n10"]
```

になる。


※参考にさせていただいたページ
[[python] os.listdir()の出力を数字順にsortして、それらを順番にpd.read_csvで読み込みたい|teratail](https://teratail.com/questions/157006)



# 実行環境

実行環境と各ライブラリのバージョンは下記の通り。

- Windows10 pro
- Python 3.7.3
- natsort 7.0.1


# フォルダ内のすべてのxlsxファイルの名称を自然順のリストで取得して、絶対パスを構築する。

```python:for_all_xlsx.py
import os
from natsort import natsorted


# デスクトップに作った任意のフォルダ名称

folder_name = "******"


# 定数
desktop_path = os.getenv("HOMEDRIVE") + os.getenv("HOMEPATH") + "\\Desktop"
folder_path = os.path.join(desktop_path, folder_name)


# Excelファイル名リストを自然順で取得
files = natsorted(os.listdir(folder_path))

#ファイル名リストをfor文でまわして各ファイルの絶対パスを構築
for filename in files:
    filepath = os.path.join(folder_path, filename)
'''以下、処理したい内容を記述'''
    
```
EC2インスタンスでWindowsServerの日本語版を選択する方法

#はじめに
EC2の作成時にWindow Server 2016を入れた際に英語版OSを入れた為に、日本語版で作成してくれという事で丸ッと作り直しになってしまったので備忘録的に残していく。

#日本語版を選択する方法
AWSマネジメントコンソール⇒EC2⇒インスタンス⇒インスタンス作成⇒
検索欄で**Windows server 2016 Japanese**と入力
※Windows japanese等でもOK

AWS使い始めで指定のAMIを探すのに選択欄の「クイックスタート」から探しがちになるが、
選択肢としてはそれほど多くは無く、見つからない場合が多い。
##コミュニティAMIを確認
![EC2②.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/594936/841828e0-e96e-571b-dd41-2a302d5285a2.png)

**コミュニティAMI**は公式を見てみると･･･

「AMI を作成したら、自分だけがそれを使用できるようにプライベートとして保存したり、AWS アカウントの指定リストと共有したりできます。コミュニティで利用できるように、**カスタム AMI** を公開することもできます。」

･･･とあり､日本語版を見つけたは良いものの、自由に個人がAMIを作成して放流できるようなので信頼性としてどうなのと思っていたが、
ここにもAWS側から提供しているAMIがあるのでそれを使用できる。
確認方法は、AMIの名称に**AMI provided by Amazon**との記載がある。
![EC2③.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/594936/ce68e176-15ed-4fd4-e0c5-218953485e44.png)

#念のため調べてみた

カスタムAMIとして自由に提供出来るのであれば、
名称の中にprovided by Amazonと入れてしまえば偽る事も可能なのではないかと勘繰ってみた。
・EC2⇒AMI⇒選択欄で｢パブリックイメージ｣を選択、対象のAWS名を入力⇒所有者を確認

![EC2④.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/594936/4f90ef10-e973-dafc-1bd8-f8ac87b492df.png)

こちらの所有者**801119661308**がAWS公式の配布元であることが確認出来た。

#マネージド AWS Windows AMI
AWS公式を見てみると、提供しているAMIの紹介、更新情報等が記載されている。
困った時の参照元はここを見ればよいのかも。
[インスタンスユーザーガイド AWS Windows AMI](https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/WindowsGuide/windows-ami-version-history.html)

#終わりに
今回は日本語版を入れてくれという要望だったが、
別に英語版を入れても日本語設定してしまえばいいのではと思った。。
またそれは別途調べてみるとする。
クイズアプリにおけるデータベース設計のアンチパターン

## 想定する読者

- ポートフォリオとしてクイズ系アプリを作成している方

## アンチパターン例 3つ

例えば4択クイズを作りたいというとき、以下のようなDB設計を思いつくかもしれません。
※筆者が思いつきました。
これらは明確なアンチパターンです。
何故アンチパターンかというと、仕様変更に弱いからです。

#### part1 マジックナンバーカラム

|  id  |  question |  choice1  |  choice2  |  choice3  |  choice4  |  answer_number  |
| ---- | ---- | ---- | ---- | ---- | ---- | ---- |
|  1  |  次のうち偶数なのは？ |  3  |  7  |  8  |  1  |  3  |
|  2  |  「令和」はどう読む？ |  れいわ  |  へいせい  |  しょうわ  |  たいせい  |  1  |

仕様変更さん「○×クイズもできるようにしたい〜〜選択肢を2つに減らすだけだし簡単ですよね？選択肢も4つだけじゃなくて、5つとかもあり得るかも♪」

教訓: カラム名にマジックナンバーが入ってたらアンチパターンの合図

#### part2 フィールドに配列ぶちこみ

|  id  |  question |  choices  |  answer_number  |
| ---- | ---- | ---- | ---- | ---- | ---- | ---- |
|  1  |  次のうち偶数なのは？ |  [3, 7, 8, 1]  |  3  |
|  2  |  「令和」はどう読む？ |  [れいわ, へいわ, しょうわ, たいせい]  |  1  |
|  3  |  今は平成か？ |  [○, ×]  |  2  |
|  4  | 次のうち一番大きい数字はどれか？  |  [5, 10, 9, 8, 4, 1]  |  2  |

仕様変更さん1「よーし、検索機能を入れることになりました！検索機能って基本的な機能なので簡単ですよね？選択肢の中の文でも検索がかけられるようにしたいです♪」

仕様変更さん2「特定の選択肢は後で編集ができるようにしたいですね〜〜ユーザーさんって誤字とかしちゃうこともあるじゃないですか♪」

教訓: フィールドに配列を入れたくなったらアンチパターンの合図


#### part3　テーブルを分けて1対多にする(が、分けきれてない)

questionsテーブル

|  id  |  content | answer_number  |
| ---- | ---- |  ---- |
|  1  |  「令和」はどう読む？ |  1  |
|  2  |  今は平成か？ |  2  |

choicesテーブル

|  id  |  content | question_id
| ---- | ---- | ---- |
|  1  |  れいわ |  1  |
|  2  |  へいせい |  1  |
|  3  |  しょうわ |  1  |
|  4  |  たいせい |  1  |
|  5  |  ○ |  2  |
|  6  |  × |  2  |


仕様変更さん「複数の答えを用意できるようにしたいです！ この複雑な世の中で、答えって一つじゃないと思うんです♪」

何がダメだったのか: answer_numberはどちらかというとchoicesテーブルにあるべき情報だと思います。関心の範囲と、テーブルの範囲を合致させるように気をつけると、仕様変更による影響が少なくできると思います。

## (おそらく)正しい設計

questionsテーブル

|  id  |  content |
| ---- | ---- |
|  1  |  「令和」はどう読む？ |
|  2  |  次のうち偶数のものはどれか？ |

choicesテーブル

|  id  |  content |  is_answer  |  question_id
| ---- | ---- | ---- | ---- |
|  1  |  れいわ |  true  |  1  |
|  2  |  へいせい |  false  |  1  |
|  3  |  しょうわ |  false  |  1  |
|  4  |  たいせい |  false  |  1  |
|  5  |  11 |  false  |  2  |
|  6  |  12 |  true  |  2  |
|  7  |  15 |  false  |  2  |
|  8  |  99 |  false  |  2  |
|  9  |  18 |  true  |  2  |

アンチパターンと上から目線で言いながら、これが最適かと言われれば微妙です笑
ただし、現役のエンジニアさんに見せたら「良いんじゃない？」って言われたんで、そこまで悪くない設計だとは思います。
マサカリ頂けると有難いです。

## ちなみにRailsだったら、どんなmigrationファイル作ればいいの

```
$ ruby -v
ruby 2.6.5
$ rails -v
Rails 5.2.4
```

```ruby:db/migrate/時間_create_questions.rb
class CreateQuestions < ActiveRecord::Migration[5.2]
  def change
    create_table :questions do |t|
      t.text :content, null: false # 問題文の中身
      t.references :user, foreign_key: true # クイズを作った人を想定

      t.timestamps
    end
  end
end
```

```ruby:db/migrate/時間_create_choices.rb
class CreateChoices < ActiveRecord::Migration[5.2]
  def change
    create_table :choices do |t|
      t.text :content, null: false
      t.boolean :is_answer
      t.references :question, foreign_key: true

      t.timestamps
    end
  end
end
```
HTMLページをHerokuにデプロイ

# この記事について
（お金をかけずに）SPAやアプリをインターネットに公開したいのにgithub pagesはもう使用済みでどうしよう、と思っていたところ、Herokuをおすすめしてもらい、実際に無料で公開できたので、手順を記録しておきたく記事にしました。

今回はHTML、CSS、JSで作ったSPA（Single Page Application）をHerokuにデプロイしました。とりあえずこの記事ではデプロイするところまでをまとめています。

デプロイ後のログの確認や、コードの追加修正を反映させる操作などについては、別途まとめたいと思っています。

# 1. まず、HTMLで作ったSPAをアプリにする
HTMLやCSS、JSだけで構成されたファイルはherokuではアプリとして認識されないため、と同じディレクトリに`index.php`と`package.json`を追加して、phpアプリに変身させます。

```index.php
<?php include_once("index.html"); ?>
```

```package.json
{}
```

[HTMLとJavaScriptで作ったサイトがHerokuにデプロイできねええって時の対処法](https://qiita.com/bitcoinjpnnet/items/ee5b4064279996c4d5ad)
↑の記事を参考にさせていただきました。

# 2. Herokuアカウントを作る
[Heroku](https://jp.heroku.com/)でアカウントを作成します。

# 3. デプロイしていく
[Getting Started on Heroku with PHP](https://devcenter.heroku.com/articles/getting-started-with-php)に沿ってデプロイをしていきます。

下記3-1. 〜 3-6. は上記のリンクと同じ内容です。

## 3-1. まず必要な準備
上記リンクに飛び、「Get started with php」をクリックすると、↓の画面に遷移します。
<img width="786" alt="スクリーンショット 2020-03-21 19.24.24.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570918/702299c5-2bfd-cb0c-c0ed-406862897962.png">

↑始める前に、必要なもの準備できてますか？！という確認です。
下記の３つの準備が整っていることを求められています。

- Herokuアカウントがあること
- PHPがローカルにインストールされていること
- Composerがローカルにインストールされていること

phpはMacにはデフォルトで入っているのでインストール不要でした。
ComposerはHomebrewからインストールします。
`$ brew install composer`

## 3-2. herokuをインストール
必要な準備が終わったら「I'm ready to start」をクリックして次に進みます。
次はherokuをインストールします。
<img width="404" alt="スクリーンショット 2020-03-21 19.25.03.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570918/b2c13843-a767-3aba-2d53-e0f14c571b2b.png">
インストールコマンドが載っているのでターミナルで実行。
`$ brew install heroku/brew/heroku`

## 3-3. herokuにログイン
herokuのインストールが完了したらログインしてみます。

`$ heroku login`
と打つと、
`heroku: Press any key to open up the browser to login or q to exit:`
と返されるので、Enterします。

すると↓のページがブラウザに出るのでログインします。
<img width="829" alt="スクリーンショット 2020-03-21 19.39.38.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570918/9dee4258-a64d-0d11-e6ee-1f78e70584ca.png">

ログインした後に遷移するページは、そのページにも書いてありますが閉じてしまっても大丈夫なようです。

## 3-4. ツールのバージョン確認
php、composer、gitのバージョンを確認します。

バージョンの確認というか、インストールできてるかの確認です。下記それぞれのコマンドを実行してバージョンが表示されればインストールできているとわかります。

`$ php -v`
`$ composer -v`
`$ git --version`

## 3-5. herokuにデプロイするリポジトリをcloneする
githubからherokuにデプロイしたいリポジトリをローカルにcloneします。

`$ git clone <url>`

このリポジトリにはHTMLとCSS,JSで作られたSPAに、「1. まず、HTMLで作ったSPAをアプリにする」の手順で追加したphpファイルとjsonファイルが含まれています。

## 3-6. アプリをherokuにデプロイ
ローカルにクローンしたリポジトリに移動し、下記のコマンドを順番に実行していきます。

(1) `$ heroku create`

```
Creating app... done,
```
の後に続くワードが今回作成されたアプリ名になります。

(2)`$ git push heroku master`
(3)`$ heroku ps:scale web=1`
(4)`$ heroku open`

これでデプロイ完了です！　HTMLで作ったSPAが新しいタブに表示されるかと思います。
もし表示されなくても、Herokuのダッシュボードを見るとアプリ名が表示されているので、そこへ飛び、右上の「Open」をクリックするとSPAに遷移できます。

# 終わりに
作ったものをデプロイしてURLを渡すだけで色々な人に見てもらえるようになるのは嬉しいですね。

プログラミングの勉強をし始めた時にも感じましたが、努力が何かしら形になるとモチベーション上がります！！SPA作ったとか、フレームワークのインストールができたとか、そういうことでも嬉しかったです。

デプロイ作業は今回初めてで、まだまだわからない事ばかりで手探り状態ですが、とりあえずできたので、しっかり運用できるようにしていきたいと思います。
ダブルクリックで、pyplotのGUIを使ったプロットを見られるようにする

# はじめに
生きていると

```test.dat
1,1
2,4
3,9
4,16
5,25
6,36
7,49
8,64
9,81
10,100
```

のような数値データが得られることがあります. こういったデータファイルをプロットする方法はいくつかあります. 
例えば, python で matplotlib を用いてpyplot.show() すると GUI 上にグラフが表示されます. 最近気づいたのですが, この GUI 上のプロットは拡大が容易にでき便利です. そこで, いちいち python ~.py とせずにこのプロットを見れるようにした記録を記します.

# 方針
__ファイル__(データファイルとは言ってない) __をダブルクリックするとプロットがみられるようにしたい__です. 当然, ダブルクリック一発では何列目をプロットするか, 区切り文字は何かなどといった情報を伝えることはできません. このため, クリックされるファイルはこういった情報を保持している必要があります.
以上を踏まえて, ダブルクリックで.pyファイルを実行する, ようにします. ここでは, __データファイルをimportするとプロットの元となる.pyファイルを生成する__コードを作成することにします. .pyファイルをpythonw.exeに紐づけるとダブルクリックで実行できるようになるのですがこの部分はカバーしません.

# 参考になった記事
[ダブルクリックで.pyファイルを実行する方法について](http://pineplanter.moo.jp/non-it-salaryman/2018/01/01/pyqt-dbclick-start/)

# コード作成
作成するプログラムは二つの部分で構成されます. 一つはファイルを読み込んでデータをプロットする部分, もう一つはデータをプロットするプログラムを作成する部分です.
## データプロット部分
以下の通りです. 何の変哲もありません.この部分はプロットしたいファイルに応じて適当に書き換える必要があります.

``` python:a.py
# Import Packages
from matplotlib import pyplot as plt
import numpy as np

# Import Data
## input filename from console
Filename = input()
## import file to "data" 
data = np.loadtxt(fname = Filename, delimiter = ",")

# Plot Data
plt.plot(data[:,0], data[:,1])
plt.show()
```

##プロットプログラム作成部分
以下の通りです.

```python:a.py
    with open(__file__) as f:
        s = f.readlines()
    with open(Filename + ".py", mode='w') as f:
        for i in range(len(s)):
            if(s[i] == "if ExportEnabled:\n"):
                exit()
            s[i] = s[i].replace("## input filename from console\n", "")
            s[i] = s[i].replace("Filename = input()\n", "")
            s[i] = s[i].replace('Filename', "\"" + Filename + "\"")
            f.write(s[i])
```

open(file)で自身を開き, それを整形して書き出す,という内容です.プロットファイルをダブルクリックするたびにプロットファイルが作成される必要は全くないので元コードの前半部分のみを複製します.

#完成
コード全体は以下のようになります.

```python:a.py
# Import Packages
from matplotlib import pyplot as plt
import numpy as np

# Export Enabled
ExportEnabled = True

# Import Data
## input filename from console
Filename = input()
## import file to "data" 
data = np.loadtxt(fname = Filename, delimiter = ",")

# Plot Data
plt.plot(data[:,0], data[:,1])
plt.show()

if ExportEnabled:
    with open(__file__) as f:
        s = f.readlines()
    with open(Filename + ".py", mode='w') as f:
        for i in range(len(s)):
            if(s[i] == "if ExportEnabled:\n"):
                exit()
            s[i] = s[i].replace("## input filename from console\n", "")
            s[i] = s[i].replace("Filename = input()\n", "")
            s[i] = s[i].replace('Filename', "\"" + Filename + "\"")
            f.write(s[i])
```

これを実行して例えば冒頭の"test.dat"をimportすると, "test.dat.py"が作成されます. この"test.dat.py"をダブルクリックすると, matplotlib の GUI でプロットを眺めることができます. メモ帳を開いてデータを見るのと同じ手間で,拡大可能なプロットを眺められるので便利だと思います(たぶん).
【Ruby on Rails】Railsに超入門したいと思った。

###何故Rails

+ 人気のある言語として、ランクインしている。
+ 簡単にwebアプリが作成できる。（文法は後で覚えればいいや）
+ 日本語の資料が充実している。
+ javaとかより入りやすそう
+ そして何だか楽しそう！！！rubyという言語の名前がいい。

上記の勝手な思い込みからスタートしてみようと考えた。


###Rails入門参考動画
[Ruby on Rails 5入門(ドットインストール)](https://dotinstall.com/lessons/basic_rails_v3)


###やりたいこと(目標)

+ １．基本的なcrud作成
(create,show,index,delete)
+ ２．DBのselect結果を反映したセレクトボックスの作成
+ ３．入力データと登録済みデータの比較(登録済みデータが存在すれば、
エラーメッセージを出して登録させない)
+ ４．恐竜登録ツールのrails版の作成
+ ５．恐竜画像登録ツールのrails版

※下記はPHPで作成した画面の一部
![rails_try1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/494408/8242439b-8474-bc46-fcb6-844da256851f.jpeg)
[ancestry]編集画面でカテゴリー表示、選択

フリマアプリの作成で編集画面に遷移した時、出品時に設定したカテゴリーを親(parent)、子(child)、孫(grandchild)まで表示させたい

**※出品機能が完了した程で進めます**

#完成イメージ
[![Image from Gyazo](https://i.gyazo.com/a1e8d9dd4c2dd270174a38fa497588eb.gif)](https://gyazo.com/a1e8d9dd4c2dd270174a38fa497588eb)

#コントローラー
```items_controller.rb
  before_action :set_item

~~省略~~

  def edit

    grandchild_category = @item.category
    child_category = grandchild_category.parent


    @category_parent_array = []
    Category.where(ancestry: nil).each do |parent|
      @category_parent_array << parent.name
    end

    @category_children_array = []
    Category.where(ancestry: child_category.ancestry).each do |children|
      @category_children_array << children
    end

    @category_grandchildren_array = []
    Category.where(ancestry: grandchild_category.ancestry).each do |grandchildren|
      @category_grandchildren_array << grandchildren
    end

  end

~~省略~~

  def set_item
    @item = Item.find(params[:id])
  end
```

**edit内**
上２行は孫と子のレコードを取得してます。

下３セットは親、子、孫と配列を作り、親はnameを、子と孫はancestryを格納してます。

#ビュー

```edit.html.haml
  .main-items
    = form_with model: @item, local: true do |f|
~~ 省略 ~~
      .wrapper.category-wrapper
        = f.label :category_id , class: 'wrapper__label category-wrapper-label', id: "wrapper__label--category" do
          カテゴリー：
          %span.required ※必須
          .category-wrapper-box
            .category-wrapper-select
              .category-wrapper-select__box
                = f.select :parent_name, @category_parent_array, {selected:@item.category.parent.parent.name}, { class: 'category-wrapper__category form-control', id: 'parent_category'}
            .category-wrapper-select#children_wrapper
              .category-wrapper-select__box
                = f.select :child_id, options_for_select(@category_children_array.map{|b| [b.name, b.id, {data:{category: b.id}}]}, {prompt: "指定なし", selected: @item.category.parent.id}),{}, {class: 'category-wrapper__category form-control', id: 'child_category'}
            .category-wrapper-select#grandchildren_wrapper
              .category-wrapper-select__box
                = f.select :category_id, options_for_select(@category_grandchildren_array.map{|b| [b.name, b.id, {data:{category: b.id}}]}, {prompt: "指定なし", selected: @item.category.id}),{}, {class: 'category-wrapper__category form-control', id: 'grandchild_category'}
```

各要素コントローラーで配列格納したインスタンス変数を使用

selectタグの`selected:`で遷移直後の表示を指定

子と孫は`options_for_select`を使用してます。
これにより親要素を変更した際、`指定なし`となり、カテゴリーを選択できるようにしてます。

孫のidをitemテーブルに紐つけてカテゴリーを判断しているので、他でわかりやすくなるよう`:caregory_id`と指定してます。
docker-composeでrailsをdocker化したらBundlerバージョンで怒られる

最近は railsもdocker化するのが多くみられるのですが、ハマりポイントも多いみたいですね。
特にdocker-composeを使ったときには、キャッシュがかかってうまく修正反映できないことがあります。

# エラーで怒られた。
例えば、既存のbundlerバージョンが合わなくて、bundler version 2.x

```
You must use Bundler 2 or greater with this lockfile.
```
というエラー。

dockerでrubyのイメージを使うときには、bundlerも一緒に入ってるわけですが、
その時に作った時のGemfileに書かれているBundlerバージョンと合わないことがあります。


#解決法
その時には、Gemfile.lockを削除してからgemライブラリ達をビルドし直す必要があります。

```
$ rm Gemfile.lock
$ sudo docker-compose build
$ sudo docker-compose up
```

この時に気を付けなければいけないのは、docker-compose buildを使うこと、
どうやら、docker buildとdocker-compose buildはキャッシュが別物みたいです。
なので、いくらDockerでビルドし直しても、docker-compose には反映されなくて詰みます
(私は数時間失いました)。
エラーも出ないが、反映もされないのでキャッシュトラブルはとてもややこしい。

参考
https://qiita.com/azul915/items/5b7063cbc80192343fc0
https://qiita.com/yoshijbbsk1121/items/87250501b32c6433943e
MacでC言語の改行コード使う場合の書き方


# MacのC言語での改行コード使おうとしたときにハマったこと
- 改行コードは、¥だった気がしたのだが、Macだと改行できなくて困った。
- いろいろ試してみたので、まとめてみる。

# 結論は、¥ではなくて、\を使う
- \がキーボードに書いていないので、出し方を調べた。
- 出し方は、alt option + ¥ で、\の文字を出すことができた。

# 検証のプログラム
 - 下記のようなプログラムを書いて、どの文字だと検証した。

```
#include <stdio.h>

int main(void){
    printf("Hello World!! \n");
    printf("Hello World!! ¥n");
    printf("Hello World!! /n");
    return 0;
}
```

# 実行結果

```
ev@devPC vscode % gcc hello.c
dev@devPC vscode % ./a.out    
Hello World!! 
Hello World!! ¥nHello World!! /n%                                                                                     
dev@devPC vscode % 
```

- 1行目のHello World!!は改行されている。
- ¥(円記号)や/(スラッシュ)もついでに入れてみた。これらは改行されなかった。まあ、当然である。

よって、Mac環境でC言語を使うときには、alt option + ¥ コマンドで、 \ を使って改行するらしい。

# これらの内容の詳細はコメントをいただきました。ありがとうございます。コメントをご覧ください。
kintone アプリに項目追加時の null 値について 

kintone アプリに項目を追加すると、既存レコードの値がどうなるか検証してみました。
REST API でレコード取得すると、日付・時刻・ラジオボタン・ドロップダウンは、null になります。

# 概要

JavaScript カスタマイズ、プラグインなどで、項目の null が原因でエラーになることがあります。
これまでのトラブルから、後から項目を追加した場合に null になっていることがありましたので、検証してみました。
結果、REST API でレコード取得すると、日付・時刻・ラジオボタン・ドロップダウンは、null になります。
アプリ画面表示中に、kintone.app.record.get() でレコード取得すると、日付・時刻が null になります。
kintone のサーバー上のレコードは、項目を追加しても変更していないはずなので、REST API と kintone.app.record.get() の処理の違いによって、結果が異なっていると思われます。

結論
日付・時刻・ラジオボタン・ドロップダウンを JavaScript で扱うときは、値に null が設定されているケースを想定してコードを書きましょう。

# 検証手順

- アプリを作成し、文字列項目を一つだけ配置
- レコードを追加
- アプリに、項目の種類一式を追加
- REST API で、レコードの内容をチェック
- kintone.app.record.get() で、レコードの内容をチェック

#　アプリ追加とレコード追加

文字列項目を一つだけ配置

<img width="714" alt="2020-03-22_12h39_49.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/d334b6ac-d97f-5a1b-c8dd-09f9215b649e.png">

# アプリに、項目の種類一式を追加

<img width="792" alt="2020-03-22_12h41_33.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/440b686a-024d-037a-f706-a179821af871.png">

# REST API で、レコードの内容をチェック

目視と、下記で null チェック
日付・時刻・ラジオボタン・ドロップダウンが、null です。

```.js
resp = await kintone.api('/k/v1/records', 'GET', {app:720, query:'$id = 1'})
record=resp.records[0];
Object.keys(record).filter(function(fc){return record[fc].value==null;})
```

<img width="823" alt="2020-03-22_12h47_46.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/2b48f9b9-043e-8235-deec-46925fcbddf0.png">

# kintone.app.record.get() で、レコードの内容をチェック

目視と、下記で null チェック
日付・時刻が、null です。

<img width="823" alt="2020-03-22_12h45_19.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/d52933ca-9b16-bdda-b508-371edf12993f.png">
超複雑な処理の実装を劇的に短く実装する方法

## はじめに

手続き型プログラミング言語に、部分的に宣言型プログラミングの要素を入れることで、ある種の非常に複雑な処理を単純に実装することができるようになります。

今回はその話を書きます。

例として上げておくと、ウェブページの複雑なバリデーション処理や、
CSVやExcelの生成、インポート処理などが挙げられます。


この記事でいうところの「宣言的プログラミング」というのは自称で、「宣言型プログラミング言語」の本来の用語とはやや異なります。

宣言型プログラミング言語についてご興味の方は他の記事をご覧ください。


## 手続き型に書くのが向かない例

例えば、商品リストをExcelとして0から生成することを考えましょう。
全体が縦横の数値表になっているとして、カラムがたくさんあるケース。
仮に30カラムぐらいあったとします。(m=30)

- 商品名
- 商品コード
- 原価
- 販売価格
- メーカー型番
- etc..

各セルにはいくつもの属性があり、個別に設定する必要があります。

- 元データから取ってくるフィールド名や計算方法
- 値の型(文字列、整数、実数など)
- 文字のフォント、サイズ、ボールド、イタリックなど
- 文字色や背景色
- 罫線やセルの連結など

仮に10属性ぐらいあったとします(n=10)
それぞれの処理をモジュール化などして1行で書けるようにしたとしても、それでも長すぎるプログラムになってしまいます。

これらの属性がn個あるとして、mカラムある表を出力するには
1行処理するごとにm*n行のコードを書くことになります。
(例でいうと 30*10 = 3000)

表題、表の項目部分、表のデータ部分と処理が分けられているならば
これらを3パターン書くことになるでしょうか。
3*m*nですか？ うんざりしてきました。


## 処理手順をデータとして宣言する

そこで、処理そのものをいったんデータとして表現します。
ここでは仮にPHPで実装していたとしましょう。

```php
$columnList = [
    ['caption' => '商品名', 'type' => 'string', 'field' => 'productName', 'font' => 'normal', 'lines' => 'under'],
    ['caption' => '商品コード', 'type' => 'jan11', 'field' => 'productCode', 'font' => 'bold', 'lines' => 'under'],
    ['caption' => '原価', 'type' => 'decimal', 'field' => 'cost', 'font' => 'normal', 'lines' => 'under'],
    ['caption' => '販売価格', 'type' => 'decimal', 'field' => 'price', 'font' => 'normal', 'lines' => 'under'],
    ['caption' => 'メーカー型番', 'type' => 'alphanumeric', 'field' => 'makerCode', 'font' => 'normal', 'lines' => 'under'],
    /// etc..
];
```

このような感じで、出力したいカラムのリストを配列で表現してしまいます。
するとn属性あった処理内容が1行になり、全体でm行程度に収まるわけです。

あとは実際の処理を書いていくだけです。

```php

/** Excelデータを生成する本体 */
function generateProductExcel(PhpSpreadsheet $sheet, array $products)
{
    foreach($products as $product) {
        foreach($columnList as $column) {
            $field = $column['field'];
            generateColumn($sheet, $product->{$field}, $column);
        }
    }
}
/** Excelのカラム1個分を生成する */
function generateColumn(PhpSpreadsheet $sheet, $value, array $column)
{
    // 省略。ここにn個の属性分の処理内容を書く
}
```

つまり、全体でm*n個必要だった処理が、m+n個に分解されたわけです。
カラム数や属性数が多いケースだと劇的にコード量が減ります。

実装する言語はPHPに限らずどんな言語でも使えるので応用が効きます。

また、宣言部分は表データに非常に近い形式なので、JSON、CSV、YAMLなどでテキストデータとして外部化してもいいですし、
マスタテーブルに直接入れてしまっても良いでしょう。

以上です。
水戸黄門を使ってCORSを完全に理解した

# はじめに
「完全に理解した」はもちろんネットスラングです。マサカリお待ちしてます。でもわかりやすいと思います。

# ことの経緯
[かつて書いた記事](https://qiita.com/YoshitakaOkada/items/df9518520b39a5f140c9) をベースに、javascriptだけでgooglemapの情報が欲しいんだよね。っていう依頼があって、えっ？それやったことねぇなぁって思って。とはいえ多分DjangoのViewで googlemap api にコンタクトしてたやつを javascript に移植すればええんやろ？って思って、ajaxのurlにgoogleapiのurlを指定してみたら出てきたんだよね。うーわなにこれもしかして学習コスト高いやつ？？とか思ったよね。

# CORSとは
［オリジン間リソース共有 (CORS)］(https://developer.mozilla.org/ja/docs/Web/HTTP/CORS)
>オリジン間リソース共有Cross-Origin Resource Sharing (CORS) は、追加の HTTP ヘッダーを使用して、あるオリジンで動作しているウェブアプリケーションに、異なるオリジンにある選択されたリソースへのアクセス権を与えるようブラウザーに指示するための仕組みです。

もうね、日本語で書かれてるのに理解できないんだよね。オリジンってオリジン弁当かよって感じ。

# 助さん格さん
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94562/d19623e6-6488-fba6-eb81-799c4efcce02.png)
「この紋所が目に入らぬか！」ってやるじゃない？あれって、水戸黄門がいない世界線で、格さんがあの紋所を掲げても意味がないわけよ。なんやそのオブジェクトォー！みたいになるよね。つまりCORSの説明に都合がいいように表現すると、虎の威を借る狐が格さんなわけ。そういういわば「虎の威」がないと、爺さんのいない格さんは一般人なんだから、「委任状」がないなら大事なgoogleapiのデータはあげないもんねー！っていう仕組みがCORS。

# 俺、あの有名人と知り合いなんだよね
それを防ごうとしてるんじゃないか！？
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94562/a9771371-6e1a-e35c-9ce3-903b4d68dfa3.png)

# 委任状を書く（ヘッダーを加工する）必要がある
CORSは、ブラウザの「防衛機能」だ。つまり、サーバーサイド（Djangoでいう Views.py ね）の処理では何事もなく済んだapiデータ取得処理を、フロントエンドでやろうとすると出るエラーなんだ。わかってしまえば高速道路と下道。。。というのか「勘合貿易」みたいなもんよね。javascriptが単独でapiにアクセスしにいけないってこと。どっかのWebシステムからjavascriptファイルだけ取り出して別のWebシステムで再現できたら、googleapiさんは「誰にデータを渡した！？」となるわけだ。

# えっなんでそんなjavascriptハブられてんの？
多分の話をすると、昔ブラウザ戦争が起こってた頃に、みんながIEの設定項目で「javascript切れ」って言われてたことあったんだよね。そのあたりに根がありそうな気がする。とにかく、javascript自身が、別の（自身以外の）リソースにアクセスする場合は「保護者の同意」が必要なわけだ。それはスネ夫で言えばジャイアンを連れてくるだし、格さんであれば水戸黄門を連れてくる、っていうことなわけだ。いや、実際にはジャイアンも水戸黄門もいなくていい。その「気配」というか「虎の威」があればいいのだ。ジャイアンや水戸黄門が「委任状」を書いてスネ夫や格さんに「権利があります」を説明できればいいわけ。

# まとめ
ここまでべらべらといろんな単語や言い回しをわざと使ってきて、この状態でもういっかいこれを見てみましょう。
［オリジン間リソース共有 (CORS)］(https://developer.mozilla.org/ja/docs/Web/HTTP/CORS)
>オリジン間リソース共有Cross-Origin Resource Sharing (CORS) は、追加の HTTP ヘッダーを使用して、あるオリジンで動作しているウェブアプリケーションに、異なるオリジンにある選択されたリソースへのアクセス権を与えるようブラウザーに指示するための仕組みです。

なんか理解度上がってない！？
javascriptが直接apiにコンタクトしたかったらヘッダーに委任状付ける必要があるよってことよね。で、結局「ことの経緯」はどうなったかって？CORSの問題でjavascriptだけではモックアップは無理ですっていって、Djangoでサーバーサイドごと作って渡したってわけ。あくまでサーバーの処理はサーバーに（javascriptは委任状なんかもらわずに自分の親分（自オリジン）に、自分のことは自分でやれってリクエストをするだけ。Ajaxは自オリジンにしかコンタクトできん）ってこっちゃ
メモリの話

##メモリ
マスクROM：呼び出し専用のメモリ。記録された内容を書き換える事は出来ない。
DRAM(Dynamic Random Access Memory)：揮発性のメモリ。長期に保存するためにリフレッシュを行う。アドレス単位で読み書きや消去を行う。
フラッシュメモリ：書き換えできる不揮発性のメモリ。PROMの一種。ブロック単位で読み書きや消去を行う。

プロセッサ：命令のアドレス部で指定されたメモリアドレスにインデックスレジスタの値を加算したものを実効アドレスとする方式。
インデックスレジスタ：連続したアドレスを扱うときに使うレジスタ。
インデックス修飾(インデックスアドレス指定方式)：オペランドにインデックスレジスタの値を加えて実行アドレスを求める方法。
オペランド：プロセッサの処理の対象になるデータ。
【Mac】Skitch（スキッチ）でスクショを撮り、数秒で共有するワークフロー


## Skitchのインストール
[Skitch - 撮る。描き込む。共有する]
(https://apps.apple.com/jp/app/skitch-%E6%92%AE%E3%82%8B-%E6%8F%8F%E3%81%8D%E8%BE%BC%E3%82%80-%E5%85%B1%E6%9C%89%E3%81%99%E3%82%8B/id425955336?mt=12)


## 共有するまでの最短フロー

1.  Skitchでショートカット `Command+Shift+5` でスクショを撮る。 [参考](https://kenfuruta.com/4611)
2.  Skitchのウインドウが開いた状態で `Command+/` のショートカットで、クリップボードに共有URLがコピーされる。[参考](https://help.evernote.com/hc/ja/articles/208313408-Skitch-for-Mac-%E3%81%AE%E3%83%92%E3%83%B3%E3%83%88%E3%81%A8%E3%83%86%E3%82%AF%E3%83%8B%E3%83%83%E3%82%AF)
3. `Command+V` で共有URLをペーストする。


ちなみに、何かが入力されたSpreadsheetのセルを選択し、`Command+K`のショートカットで、セルにリンクを貼ることが出来ます。
Atcoderで当然のように出てきたLucasの定理を知らなかった件

# 経緯
はじめまして。
先週から競プロに取り組み始めた初学者です。

昨日、Atcoder Grand ContestというAtcoderの中でも難易度が高いコンテストがあり、初めて出場してみました。

昨日のものは、その中でも難化していて、スピードによっては２完で橙パフォがつくほどだったそうです。
私は１問しか解けずに終わりましたが、１問目の難易度にも驚きました(ABCと違いすぎた)

[２問目](https://atcoder.jp/contests/agc043/tasks/agc043_b)の解説を読んでいると**Lucasの定理**という定理が出てきました。
(気になる方は問題文も読んでみてください)
あたかも常識のように出てきて驚きました笑

*「Lucasの定理　競プロ」*でググったところ、Hitしたので覚えておくべきだと思い、説明と実装をしようと思い今に至ります。(pythonで実装しています)


ps.)競プロ界隈では常識の定理ですか？教えていただける方いましたら幸いです。

# Lucasの定理って一体？
p: 素数
m,n: 非負整数
C(n,k) := (n個の中からk個を選ぶ場合の数)
とした時に

```math
  C(m,n) \equiv \prod_{i=0}^l C(m_i, n_i) \ \ \ \  (mod\ p) \\
```

ただし、

```math
m_lm_{l−1}⋯m_1m_0 := (mのp進数表示)\\
n_ln_{l−1}⋯n_1n_0 := (nのp進数表示)

```
とする。


# 結局何がしたいのか
私なりにまとめてみると
**「C(n,k)の余りを求める時に楽するための定理」**
みたいに解釈しました。

# 今回の場合の例
今回のコンテストの問題では、入力の数字全てに対するC(n,k)の偶奇が必要な情報だったので、それを求めるためにLucasの定理が使用されています。
(p=2としている)

例えば、C(7,2)の偶奇を求める際は(n=5, k=2)

```math
7\ → 111\\
2\ → 010
```

とまずnとkを二進数に変換してから、
その各桁についてC(n,k)を求め、求めたC(n,k)を掛け合わせます。

```math
C(1,0)*C(1,1)*C(1,0) = 1*1*1 = 1
```

よってC(7,2)を2で割った余りは1と導出でき、奇数であることがわかります。


# 実装
実装自体はそんなに難しくありませんが、コンテスト中にやれと言われると手間なので、今後使えるように実装しておきました。
(間違いあれば指摘お願いします)

```python
from scipy.special import comb

# xをn進法表記に変換する関数
def n_ary(x, n):
	nums = '0123456789ABCDEF'
	result = ''
	while(1):
		result = nums[int(x % n)] + result
		x = x // n
		if x==0:
			break
	return result

# C(n,k)をpで割った余りを返す関数
def lucas(n, k, p):
	# nとkをp進法で表記
	n_p = n_ary(n, p)
	k_p = n_ary(k, p)
	# n_pとk_pの桁を揃える(左側を0で埋める)
	k_p = k_p.zfill(len(n_p))

	result = 1
	for n_i, k_i in zip(n_p, k_p):
		result *= comb(int(n_i), int(k_i), exact=True)
	return result
```

# まとめ
コンテストを終えて、解答を見たとき、「思いつくわけない」と感じました。
しかし、その後解説動画を見ていると、

- ある程度やってる方なら知ってると思いますが〜
- よくあるやり方ですが〜

みたいなフレーズを解説者が言っていて、自分の知識不足を知らされました。
ヒラメキの力に問題があるのかもしれませんが、その前に知識面が不足していると痛感したので、ヒラメキ面については知識が整ってから悩むことにしました。
(今回でいうとパスカルの三角形っぽいものが出てきた時点で二項係数絡みと考えなければならなかった)

次のGrand Contestでは2完できるように知識面の補強をしていこうと思います。
他の開発メンバーが途中まで進めたリモートブランチを引き継ぐ方法

```
git fetch　＊リモートリポジトリの情報をローカルへ

git branch [リモートブランチ名] [origin/リモートブランチ名]
＊ローカルリポジトリに同じ名前で引継ぐ
```
ディープラーニング　服装の分類機　素材集め編_2 

#【概要】
大目標として、女性服の分類機を作成します。今回はページ内の画像をすべて取得する手法について触れます。
前回のディープラーニングを行うための素材を集めるための手法の記事の続きです。

前回：ディープラーニング　服装の分類機　素材集め編_1
https://qiita.com/drafts/c74e1a5058234a4de66d/edit

#【目標】
ネットでディープラーニングに使用する画像を取得する

#【環境】
Windows10
google crome (ブラウザ)
python3.6
selenium (pythonライブラリ)

# Python + Selenium
私はセレニウムを実践する上でこちらの記事に大変お世話になりました。
https://qiita.com/Azunyan1111/items/b161b998790b1db2ff7a

###HTMLを見る
webページから情報や画像を取得したい場合、そのページのhtml構造を確認します。ウェブページ上でF12キーを押してみましょう。画面右側にhtmlを確認できると思います。それがこの記事のページのhtmlです。「開発者モード」といいます。

サンプルURL：https://item.rakuten.co.jp/mobacaba/k837/

![1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/265412/124a2d1e-6319-0703-5ba1-3f96ad0dc7a6.png)


まずはこのHTMLのどこに画像があるのかを探します。
大きなパーカーの画像で右クリック→「検証」を押しましょう。
すると開発者モードの画面に変化があると思います。そこを見てみると、下のようにかかれています。
< <img src="https:xxx......>

以下のサンプルコードではパージ内の画像をすべて取得します。

###サンプルコード
```py
def selenium_test():
    site_a = <"URL">
    savepath = <"画像を保存するパス">

    options = Options()
    options.add_argument('--headless')
    driver = webdriver.Chrome(options=options)
    driver.get(site_a)
    tg_img_items = driver.find_elements_by_tag_name('img')

    cnt = 0
    for elem_img_item in tg_img_items:
        try:
            cnt += 1
            imglink = elem_img_item.get_attribute("src")
            imgdata = req.urlopen(imglink).read()
            img_save = os.path.join(savepath, str(cnt) + "test.jpg")

            with open(img_save, 'wb') as f:
                f.write(imgdata)

        except:
            pass
        
        # 相手サイトへの負荷軽減のためのクールタイム設定
        time.sleep(2)


if __name__ == "__main__":
    selenium_test()

```

以上でページの取得できる画像は大方取得できます。
ただし、これだと不要な画像も取得してしまうため、工夫が必要となります。
次にはhtmlのタグをよく観察して必要な画像だけを取得できるための記事を書きます。


#終わりに
ディープラーニングの素材集めにこんな苦労しなくても、データセットがすでにある場合がほとんどなのでしょうな。。
気が向いたらこの次の記事は書きます。データセットが見つかったら書くのは後回しにします。

失礼します。