OmniAICreator/Qiita-1.07M huggingface dataset:
【RuboCop】複数行の引数の最後の値にカンマを付けたい

# 複数行の配列や引数を書くとき
### 最後にカンマを付けない派
```seeds.rb
User.create!(
  name: 'foo bar',
  email: 'foo@baa.com',
  password: 'password',
  password_confirmation: 'password'
)
```
`rubocop -a`で自動整形すると、デフォルトでは上記のように整形されます。
ruby以外の言語だと、引数や配列の最後にはカンマを付けるとエラーになったりするので、一般的に使われている書き方だと思います。
### 最後にカンマを付ける派
```seeds.rb
User.create!(
  name: 'foo bar',
  email: 'foo@baa.com',
  password: 'password',
  password_confirmation: 'password',
)
```
分かりづらいですが、先程の例と比べると、最後の引数の後にカンマが付いているのが分かります。
rubyでは上記のように最後の引数にカンマを付けても問題なく動きます。
慣れていないと気持ち悪く感じるかもしれませんが、引数を追加したい時などに素早くコピペできるので便利だったりします。
# 最後にカンマを付けるためのrubocopの設定
### `Style/TrailingCommaIn~~` を設定する
引数/配列/ハッシュでそれぞれ設定するスタイルが異なります。

|種類  |スタイル名  |
|---|---|
|引数  |Style/TrailingCommaInArguments  |
|配列  |Style/TrailingCommaInHashLiteral  |
|ハッシュ  |Style/TrailingCommaInArrayLiteral  |

それぞれ`EnforcedStyleForMultiline`プロパティを`comma`または`consistent_comma`に設定すればOKです。

```.rubocop.yml
Style/TrailingCommaInArguments:
  EnforcedStyleForMultiline: comma

Style/TrailingCommaInArrayLiteral:
  EnforcedStyleForMultiline: comma

Style/TrailingCommaInHashLiteral:
  EnforcedStyleForMultiline: comma
```
これで`rubocop -a`を実行したときに引数/配列/ハッシュの値にカンマがつくようになります。`comma`を`consistent_comma`にしても同様の結果が得られます。

### `consistent_comma` と `comma` の違い
[こちら](https://www.rubydoc.info/gems/rubocop/RuboCop/Cop/Style/TrailingCommaInArguments)のようなドキュメントを読んでも違いがわからなかったのでいくつか試してみたところ、複数行に引数を書きつつも、**１行に複数の引数がある場合**に違いが出る事がわかりました。

```seeds.rb
# consistent_comma
User.create!(
  name: 'foo bar',
  email: 'foo@baa.com',
  password: 'password', password_confirmation: 'password',
)

# comma
User.create!(
  name: 'foo bar',
  email: 'foo@baa.com',
  password: 'password', password_confirmation: 'password'
)
```
分かりづらいですが、最後２つの引数を同じ行に書いています。
このようなとき`consistent_comma`だと最後の引数にカンマが付き、`comma`だと付きません。

### ちょっとハマったところ
下記の様にメソッドの行から引数を書き始めると、どの設定にしても下記のように整形されてしまいますのでご注意ください。

```seeds.rb
User.create!(name: 'foo bar',
             email: 'foo@baa.com',
             password: 'password',
             password_confirmation: 'password')
```

なお古いバージョンのrubocopでは引数/配列/ハッシュでのカンマ有無をすべて`Style/TrailingComma`で設定していたようですが、現在こちらは削除されているので使えません。

# 参考
- [RuboCop | Style/TrailingComma](https://qiita.com/ritukiii/items/74ee3274c3f218511a0c)
- [Class: RuboCop::Cop::Style::TrailingCommaInArguments](https://www.rubydoc.info/gems/rubocop/RuboCop/Cop/Style/TrailingCommaInArguments)
- [Class: RuboCop::Cop::Style::TrailingCommaInArrayLiteral](https://www.rubydoc.info/gems/rubocop/RuboCop/Cop/Style/TrailingCommaInArrayLiteral)
- [Class: RuboCop::Cop::Style::TrailingCommaInHashLiteral](https://www.rubydoc.info/gems/rubocop/RuboCop/Cop/Style/TrailingCommaInHashLiteral)
tweet_idから得られる情報(Python)

2本目の記事です。こんな感じでツイッターについていろいろ書いていきます。

<h2>完成コード</h2>


```python:tweetid.py
from datetime import datetime

tweet_id = 279622981959970816
print("tweet_id =",tweet_id)

tweet_raw = format(tweet_id,'016b')
print ("tweet_raw =",tweet_raw)
tweet_raw=format(int(tweet_raw), '064')[1:]

sequence = tweet_raw[51:]
worker_id = tweet_raw[46:-12]
datacenter_id = tweet_raw[41:-17]
machine_id = datacenter_id + worker_id
timestamp_id = tweet_raw[:-22]

seq=int(sequence,2)
work=int(worker_id,2)
data=int(datacenter_id,2)
machine=int(machine_id,2)
timestamp=int(timestamp_id,2)
unixtime = (timestamp + 1288834974657)/1000
time = datetime.fromtimestamp(unixtime)

print("sequence =",seq)
print("worker_id =",work)
print("datacenter_id =",data)
print("machine_id =",machine)
print("timestamp_id =",timestamp)
print("unixtime=",unixtime)
print(time)
```

こうprintされます。
![bandicam 2020-02-08 01-14-41-754.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/522233/6a158a1d-175d-cad2-6139-07e32124e096.jpeg)

本当に合ってるのかよ！ってことについては、
![bandicam 2020-02-08 00-50-10-563.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/522233/8ff085d0-a78d-e4f9-acff-c47b49afb316.jpeg)
https://www.slideshare.net/pfi/id-15755280
ここと一致させているのでしっかり取得できているはずです。


<h2>説明</h2>
ツイートidを2進数に分解し、最終的に左に63桁になるように0埋めして、
tttttttttttttttttttttttttttttttttttttttttdddddwwwwwssssssssssss
000001111100001011010111001111011011110110000100111000000000000![bandicam 2020-02-08 01-09-57-277.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/522233/0a3264a3-5a60-2fcb-af6f-f19c51bc3705.jpeg)

t=timestamp(UNIX時間を修正したもの)
d=datacenter_id(文字通り)
w=worker_id(文字通り)
dw=machine_id(文字通り)
s=seqence(連番)
というようになっています。

時間だけ取得する関数が欲しい！という場合はこちらをどうぞ

```python:gettime.py
def get_time(id):
 two_raw=format(id,'016b').zfill(64)
 unixtime = int(two_raw[:-22],2) + 1288834974657
 ime = datetime.datetime.fromtimestamp(unixtime/1000)
 return ime
```

定型文
[ツイッター(@kenkensz9)にいつもいるので何かあればどうぞ](https://twitter.com/kenkensz9)
よろしければいいねお願いします！
複数NICを持つマシンでポリシーベースルーティング

## はじめに

私はデータベース、特にPostgreSQLが専門（？）なのですが、求められれば付け焼き刃で勉強しながらネットワークの設定もやったりします。
今回は、複数NICを持つLinuxマシンに対して、1つのNICのみを持つマシンから両方のNICに対して通信をすることになりました。

## どういうことかというと

次の図を御覧ください。
![001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/70076/3b4e1c43-cce4-2b50-6672-e5b227e4b5e9.png)

青のLANは192.168.10.0/24のセグメントであり、緑のLANは192.168.20.0/24のセグメントです。

マシンAにNICが2つあり、それぞれのNICが青と緑に接続しています。

 * NIC0
  * IP:192.168.10.2
  * GW:192.168.10.254
 * NIC1
  * IP:192.168.20.2
  * GWは設定していません。

マシンBはNICが1つのみであり、緑のLANにしか接続していません。

 * NIC0
  * IP:192.168.20.201
  * GW:192.168.20.254
 
このネットワーク構成でつまり、次の図のようなことがしたいわけです。

![002.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/70076/25e317bd-fafb-05f4-7f97-1772130bf76b.png)

## 非対称ルーティング

実はこのネットワーク構成では、やりたいことが上手くできません。pingを飛ばしても返ってこないのです。
どうしてそうなるのか。マシンBからマシンAへの通信がどうなっているかを説明します。

まず、マシンBは同一セグメント上にない「192.168.10.2」というIPアドレスがどこにあるか自分ではわかりません。そういうときは、デフォルトゲートウェイに問い合わせに行きます。

![0003.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/70076/51a522e7-1f35-ec50-ba99-532450f174b8.png)

ゲートウェイはルーティング情報から、宛先のアドレスのネットワークに向けて中継します。

![004.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/70076/b0ed3cd9-4e05-1e86-9637-c0abcd391f4b.png)

マシンAまで届くとマシンAは何を血迷ったか、**受信したNIC1ではなく送信元のマシンBが接続している緑のセグメントと同セグメントのNIC0から返信しようとします。**
![005.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/70076/843e1a51-647c-9f0f-1610-47bb689096fb.png)

NIC0から返信してしまうと、受信した経路と送信した経路が異なる**非対称ルーティング**となります。そして、Linuxではデフォルトではこれを禁止しており、マシンBまで返信は返りません。

## 2つの対策

対策としては2つ考えられます。

### 非対称ルーティングを許可

1つは非対称ルーティングを許可してあげること。しかし、非対称ルーティングはマシンのなりすましなどの可能性があるため、ホイホイ許可するのは考えものです。本記事ではやり方には触れませんが、許可したい場合は**rp_filter**で検索してみてください。

### 静的ルーティングを設定

本記事の本命はこちら。要するにマシンAの振る舞いの何が悪いのかというと、NIC1で受信したのにNIC0から返信しようとしているところです。だったら、NIC1で受信したならNIC1から返すように、無理矢理にでも設定してあげればいいわけです。その設定方法が、**静的ルーティング**です。

## 静的ルーティング設定手順

ポリシーベースルーティングというものの設定をしてみたいと思います。

### ルーティングテーブルファイルに追加

/etc/iproute2/rt_tablesに次の2行を追加します。

```
100     rule01
101     rule02
```

### ルールファイルを作成

/etc/sysconfig/network-scriptsディレクトリの下に、NIC0とNIC1のインタフェースそれぞれに適用させるルールファイルを作成します。

```shell
# vi rule-nic0
from 192.168.20.2/32 table rule02 priority 200
# vi rule-nic1
from 192.168.10.2/32 table rule01 priority 100
```

### ルーティングファイルを作成

同じく/etc/sysconfig/network-scriptsディレクトリの下に、NIC0とNIC1のインタフェースそれぞれに適用させるルーティングファイルを作成します。

```shell
# vi route-nic0
192.168.20.0/24 dev nic0 table rule02
default via 192.168.20.254 dev nic0 table rule02
# vi route-nic1
192.168.10.0/24 dev nic1 table rule01
default via 192.168.10.254 dev nic1 table rule01
```

### ネットワークを再起動

```
# systemctl restart network
```

これで、設定が上手くいっていれば、当初の目的が実行できているはずです！お疲れ様でした！

## 余談

次の図を御覧ください。

![006.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/70076/daac5250-4174-86eb-46ba-07405b40134e.png)

このような通信は、同一セグメント内であり、全く問題なく行えます。それなら別に、マシンAには到達できているわけだしわざわざ異なるネットワークセグメントから通信する必要あるのかどうか、疑問に思った方もいるかもしれません。

**私だってそう思います。**

でも、**やれって言われたらやるしかないじゃん。**

いったいどういう目的があってこんなことをやらされたのか、終わった今でも謎です。
QAチームが品質活動できる条件

そもそも、どのようにプランニングすると**プロダクトサービス品質**が良くなるか。考えてみました。

当然、**サービス**によって異なりますが何を持って**品質向上**と言えるのか。

品質向上担保がQAチームだけではなく　**「プロジェクト品質」**、**「スケジュール品質」**、**「作業品質」**、**「コミュケーション品質」**、**「ドキュメント品質」**、**「開発品質」**、**「リリース品質」**、**「運用品質」**、**「エンジニア採用品質」**、全てが**品質**だということを心得。事業全体が一つの品質活動ということになる。

| 品質       |       内容 |  
|:-----------------|:------------------|
| **プロジェクト品質**  | PMもしくはPMOが**サービス**、**開発**、**インフラ**、**QA**スキルを持ち合わせている、**承認**する立場、**責任の所在**が明確 |             
| **スケジュール品質**  | 企画、開発、インフラ、QA、運用がきちんと作業できる、**リスク**に備えた**バッファ**、**各工程の作業理解** 、差し込み案件の対応 |            
| **作業品質**   |  集中力、モチベーション、休息 、脱長時間勤務、キャリアパス|       
| **コミュケーション品質**   | きちんと伝わっている、相手に応じた説明である、対象者全員、フルリモート下では1on1の定期実施 |  
| **ドキュメント品質**   |   記載している内容が正しい、アサインすべきレビューア|   
| **開発品質**   | 利用フレームワーク、サーバ設計、サーバーパフォーマンス、DB設計、DBパフォーマンス、ログ精査、単体テスト基準、単体テストケース、検証環境の構築 |   
| **リリース品質**           |  使用ブランチ、リリース手順、時間、担当者が明確 | 
| **運用品質**           |   運用手順、障害対応手順、利用ツール、担当者が明確 | 
| **エンジニア採用品質**  | **担当案件**もしくは**作業**を遂行できる能力がある人材である、メンタル面、体調面に問題がないかを見極める |  



:frowning2:これが**前提**にあって、初めてQAが**品質活動**をすることができる。
この品質も担保されず、QAをしたところで何を示すことができるでしょうか。


QAチームだけが**品質活動**をしたところで、**良い結果**にはなりません。

:scream:**なぜか？**

:relaxed:**QA側**で考えてみると！！！
全体の品質を高めることが、まずは必要であると言えます。

| 項目       |       内容 |  
|:-----------------|:------------------|
| **プロジェクト品質**  | PMもしくはPMOがQAの作業や役割をきちんと認識していない |  
| **スケジュール品質**  | 何も考えずに線だけが引かれている。QAの見積が考慮されない |  
| **作業品質**  | 作業精度が落ち、本来確認できる不具合も見落としてしまう |
| **コミュケーション品質**  | 作業領域や優先度がわからず、工数だけ使ってしまう |
| **ドキュメント品質**  | 設計、仕様書に落とし込んでいる内容と異なる。メンテナンス工数だけ膨れる |
| **開発品質**  | 単体レベルの不具合が、たくさん見つかりQA実施ができない。使用している環境も正しいのか不安になる |
| **リリース品質**  | QAが完了し、リリースに取り掛かっても、ブランチを間違ったり、リリースの手順をミスすると、不具合となる |
| **運用品質**  | 障害ばかりで、一向に収束しない |
| **エンジニア採用品質**  | 作業進捗や、工数の変更、稼働コスト |

この状況下で、品質活動をしてはいけない。まずは、改善しましょう:closed_umbrella:
全体の品質を高めることが、まずは必要であると言えます。
DBFluteメモ

#DBFluteについて自分なりまとめ

##DBFluteとは
DBへの接続をしてくれるORマッパーのフレームワークです。
このフレームワークの特徴は、DBの変更に強いことです。
DBのEntityを読み込み自動でそれに対応したクラスとメソッドを生成しそれを利用し、
DDLを書くことなくレコードの取得や更新、追加、削除ができます。

##使い方メモ
###ConditionBean
これにレコードの条件を付けていく。

```
List<Member> memberList = memberBhv.selectList(cb -> {
    // 3. 取得したい関連テーブルを指定 (取得したい関連テーブルは何か？)
    //  {select句, join句}
    cb.setupSelect_MemberStatus();
    // 4. 絞り込み条件・並び替え条件を設定 (どんな絞り込み、並び替えをしたいか？)
    //  {where句, order-by句, (from句, on句)}
    cb.query().setMemberName_PrefixSearch("S");
    cb.query().addOrderBy_Birthdate_Desc();
    cb.query().addOrderBy_MemberId_Asc();
});
```
上記はアローを使った無名関数で条件を決めてるが、
CBを決めてBhvに投げればよい。

CBの条件は下記
http://dbflute.seasar.org/ja/manual/function/ormapper/conditionbean/index.html#function

###Bhv
ConditionBeanに条件を詰めた後このBhvのselectList（）で検索やinsert()登録処理を行える。

```
List<xxxxConditionBean> = xxxxBhv.sekectList(ConditionBean);
xxxxBhv.insert(ConditionBean);
```
汎用的に使う単テーブルに対しての検索等はBhvにBeanの設定まで追記しておくと、
ほかの機能からも呼び出しやすく、使いまわしやすい。

基本的には開発者としてはConditionBeanとBhvを把握すれば問題ない。

##なんでDBFluteを使っているのか

###メリット①
上記で紹介したConditionBeanやBhvはDBのエンティティを自動で読み取ってくれるため、非常にDB変更の強い。
カラムの増減があったから影響調査が必要…っていうときは問題がある個所はコンパイルエラーになるので見つけやすい。

###メリット②
SQLを記載しないので検索条件の追加などが気軽にできる。
テーブルの結合もキーを用いて自動で行ってくれるのでSQLを実際に考えなくてもよい。
SQLが苦手な方はこっちのほうが楽かも。

###メリット⓷
カラムの値に対して区分値を設定できるため、できるだけハードコーディングをしなくても済む。
他画面でも同じカラムを参照すれば、自動で取得できるため整合性を気にしなくてもよい。
ConditionBeanにもその区分値対応した条件設定メソッドが自動生成されるため、
視覚的にもわかりやすい。

###メリット④
replace-schemaというDBを構成するSQLがまとめられたバッチが存在する。
これのCREATE文を修正して流しなおすだけで、単体環境にDBを構築しなおすことができる。
利点としては同時開発時に一瞬こっちの想定したテーブル構成にしたい・・・ということができる。
Bluespec Compilerをstack環境のghcでビルドしてみた

# はじめに
BluespecSystemVerilogとはVerilogやVHDLと同じくハードウェア記述言語の一種です。十年ほど前から商用の処理系としてBluespec Compilerが存在していたのですが、つい先日オープンソースになりました。

https://github.com/B-Lang-org/bsc

BluespecSystemVerilogはHaskellベースの文法を持っていて、処理系もHaskellで書かれています。
早速ビルドしてみようと思ってREADMEを見ると「cabalでライブラリをインストールしてmakeせよ」と書いてあります。
しかし今時のHaskell環境はstackを使っていることが多いと思うので、このためだけにcabalや素のghcを入れるのはいまいちです。
というわけでstackでBluespec Compilerをビルドしてみることにしました。

# 準備

まずリポジトリをクローンしてサブモジュールを取得します。

```console
$ git clone https://github.com/B-Lang-org/bsc
$ cd bsc
$ git submodule update --init --recursive
```

また依存ライブラリとビルドに使うツールがいくつかあるので入れておきます。

```console
$ apt-get install libfontconfig1-dev libx11-dev libxft-dev
$ apt-get install gperf flex bison
```

# stackのインストール

既にstackを使っている場合は不要ですが、そうでない場合は以下のようにインストールしてデフォルトのghcを取得しておきます。

```console
$ curl -sSL https://get.haskellstack.org/ | sh
$ stack update
```

# Haskellのライブラリインストール

元のREADMEでは「cabalでインストールする」となっている部分です。
普通stackの依存ライブラリはプロジェクトディレクトリのpackage.yamlに書きますが、今回はプロジェクトがないのでグローバルな場所にライブラリをインストールします。

```console
$ stack install regex-compat syb old-time
```

# ビルド

stackのプロジェクトなら`stack build`でいいのですが、残念ながらそうではないのでmakeでビルドします。`Makefile`内では`GHC`変数でghcコマンドを定義しているのでstackのghcを使うように変更してやります。

```console
$ make GHC="stack ghc -- "
```

うまくいけばこれでビルド完了まで通るはずです。
Python3学習記録#1

#変数の宣言
```python:variable
# 変数の宣言
age = 18
name = '太郎'
is_ok = True

# 出力
print(age)
print(name)
print(is_ok)
```
Pythonでは、型の宣言不要。


#変数の型の調べ方

```python:variable_type
age = 18
name = '太郎'
is_ok = True

# 変数の型を出力
print(age, type(age))
print(name, type(name))
print(is_ok, type(is_ok))
```
型がわからないときは、type関数を使う。

#型の変換
```python:type_casting
age = 18
number = '18'

# #型の変換(キャスト)
new_age = str(age)
new_number = int(number)

print(new_age, type(age))
print(new_number, type(number))

```

#Pythonはスネークケース
すべての単語を小文字にして、単語と単語はアンダーラインでつなげる。
Pythonは変数や関数でスネークケースを採用しています。
【Rails6】ActiveStorage::Blob#purge すると FrozenError

# 環境
- Ruby: 2.6.3
- Rails: 6.0.2.1

# 入力エラー時の purge でエラーが発生するようになった

こんな感じの has_one_attached の項目を持つmodelで、

```ruby:post.rb
class Post < ApplicationRecord
  has_one_attached :image
  # 他にもいくつか項目・・
end
```

入力エラー時に has_one_attached の項目を purge するとエラーが発生しました。
※Rails5.2.4.1までは正常に動作していました

```ruby:posts_controller.rb

def create
  Post.create!(post_params)
rescue ActiveRecord::RecordInvalid => e
  post = e.record
  post.image&.purge # <= ここでエラー！！
end
```

エラーメッセージはこんな感じでした。

```
FrozenError
can't modify frozen Hash
```
ほう、Rails6からFrozenになったのか？ :thinking: 

調査してみると既にissueがありました。
[ActiveStorage `has_one_attached` not purging attachments · Issue #37069 · rails/rails](https://github.com/rails/rails/issues/37069)

以下のコメントに原因がめちゃめちゃ詳しく書いてありました。

https://github.com/rails/rails/issues/37069#issuecomment-525972179
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/290998/df8bf7e3-561e-c269-c0f4-8588be6b3c94.png)

今回の例に合わせて要約すると、

- `ActiveStorage::Blob＃purge` は、blobレコード（imageの情報を持っているレコード）を destroy し、そのレコードの項目をFreezeします。


```ruby:/activestorage/app/models/active_storage/blob.rb
# https://github.com/rails/rails/blob/v6.0.2.1/activestorage/app/models/active_storage/blob.rb#L232-L239
def purge
  destroy # <= ココ！！
  delete
rescue ActiveRecord::InvalidForeignKey
end
```

- その後、 `delete` で保存されたファイルを削除します。

```ruby:/activestorage/app/models/active_storage/blob.rb
# https://github.com/rails/rails/blob/v6.0.2.1/activestorage/app/models/active_storage/blob.rb#L227-L230
def delete
  service.delete(key) # <= ココ！！
  service.delete_prefixed("variants/#{key}/") if image?
end
```

- `ActiveStorage::Blob＃delete` は `#key` を呼び出します。 Postレコードが保存されていないため、blobにはキーがありません。`#key` は、blob にまだキーがない場合にキーを生成しようとします。 生成されたキーをblobのFreezeされた項目に設定しようとするとエラー発生します。

```ruby:/activestorage/app/models/active_storage/blob.rb
# https://github.com/rails/rails/blob/v6.0.2.1/activestorage/app/models/active_storage/blob.rb#L115-L118
def key
  # We can't wait until the record is first saved to have a key for it
  self[:key] ||= self.class.generate_unique_secure_token
  # ^ self[:key]が無いので右辺が実行されるが、selfの項目はFreeze済みなので FrozenError!!
end
```

原因はそんなところです。

回避策としては、 `#purge` を呼ぶ代わりに `nil` を設定すればOKです。

```ruby:posts_controller.rb

def create
  Post.create!(post_params)
rescue ActiveRecord::RecordInvalid => e
  post = e.record
  post.image = nil # <= purge を呼ぶ代わりに nil 設定で回避
end
```

異常系のテストもしっかりしとかないとダメですね。
【Pandas高速化】奇数行 or 偶数行にフラグを立てる

# はじめに
データを処理する上で、奇数行 or 偶数行にフラグを立てるという作業が発生した。
その際に高速化のために色々と試したのでメモっておく。

# 前提条件
前提条件として、以下のような10000行のデータフレームを持っているとする。

```python
df = pd.DataFrame({'hoge':np.zeros(10000)}
df
```
|  | hoge |
|:--|:--|
| 0 | 0.0 |
| 1 | 0.0 |
| 2 | 0.0 |
| 3 | 0.0 |
| 4 | 0.0 |
| ... | ... |
| 9995 | 0.0 |
| 9996 | 0.0 |
| 9997 | 0.0 |
| 9998 | 0.0 |
| 9999 | 0.0 |


このデータフレームに、'target_record'という奇数行 or 偶数行にフラグがたった以下のような列を追加する。

```python
df['target_record'] = [1,0,1,0,1,...,0,1,0,1,0]
df
```

| | hoge | target_record |
|:--|:--|:--|
| 0 | 0.0 | 1 |
| 1 | 0.0 | 0 |
| 2 | 0.0 | 1 |
| 3 | 0.0 | 0 |
| 4 | 0.0 | 1 |
| ... | ... | ... |
| 9995 | 0.0 | 0 |
| 9996 | 0.0 | 1 |
| 9997 | 0.0 | 0 |
| 9998 | 0.0 | 1 |
| 9999 | 0.0 | 0 |

このtarget_record列を作る際の時間を計算する。
ちなみに、処理時間は10000回計測した平均を求めた。


# 処理速度比較
## loc + スライス
まずは、最も単純？な方法から
全レコードに0を代入した'target_record'列を追加し、loc + スライスで指定の行に1を代入するというもの。

```python
df['target_record'] = 0
df.loc[0::2, 'target_record'] = 1  # 偶数行の場合は df.loc[1::2, 'target_record'] = 1

# 平均処理時間: 0.0009912237882614137 sec
```

ちなみにilocだと、

```python
df['target_record'] = 0
df.iloc[0::2, 1] = 1

# 平均処理時間: 0.0009658613920211792 sec
```

若干locよりも早い？


## np.zeros + スライス
locの処理速度が遅いのは有名な話なので、numpyで配列を作ってスライスで1を代入するというもの。

```python
target_record = np.zeros(10000, dtype=int)
target_record[0::2] = 1  # 偶数行の場合は target_record[1::2] = 1
df['target_record'] = target_record

# 平均処理時間: 0.00035130116939544677 sec
```

処理時間が約1/3になった。


## np.arange + 剰余
np.arange(10000)で0~9999の配列を作って、2で割った余りの値を代入するというもの。

```python
target_record = np.arange(10000)
df['target_record'] = (target_record + 1) % 2  # 偶数行の場合は df['target_record'] = target_record % 2

# 平均処理時間: 0.00046031529903411863 sec
```

ちょっと工夫した処理だけどnp.zeros + スライスの方が0.0001秒速いらしい。


# まとめ
奇数行 or 偶数行にフラグを立てるときは、np.zeros + スライスが最速？
<br>
<br>

ちなみに、処理ごとに時間を測ってみると、処理速度の差を分けたのは
剰余の計算かスライスで代入かという違いだった。
np.zerosとnp.arangeの処理速度にはほとんど差がなかった（1.0e-06秒だけzerosが速い）。
Android でもとりあえず  Ubuntu のデスクトップ環境を使いたい（UserLAnd 版）

## はじめに

先に公開した Android Studio を使うための最低限のデスクトップ環境の構築方法を記載します。
日本語入力もありませんが、その代わり最短で構築できると思います。

Android の上で最も手軽に Ubuntu の環境を構築するなら UserLAnd が一番楽だと思われます。
Termux でもできますが、UserLAnd の方が手間が少なくて済みます。
その代わり、Termux より動作速度が遅いです。
どちらが良いかはお手持ちのスマートフォンの速度と好みで選ぶと良いと思います。

## 注意点

デスクトップ環境（LXDEやXfce）のインストールは数時間かかります。
時間を確保してから実施するほうが良いと思います。

## インストール

Play ストア で UserLAnd と XSDL をインストールしてください。
UserLAnd は Debian や Ubuntu といった Linux 環境を簡単に構築するためのアプリケーションになります。
XSDL はデスクトップ画面を担当するアプリケーションです。
UserLAnd はコマンドラインまでしかサポートしませんので、XSDL でデスクトップ画面をサポートしてもらいます。

## Ubuntu のインストール

UserLAnd を立ち上げて、Ubuntu と書かれた項目をタップします。
ユーザーIDとパスワードを入力して CONTINUE をタップします。
接続の種類に SSH, VNC, XSDLを選択するように言われますので、SSH を選択して CONTINUE をタップします。

環境によりけりですが、1時間は待つことになると思います。

## Ubuntu デスクトップ環境のインストール

ここからは Ubuntu での操作になります。

まずは apt でパッケージ（Linux アプリケーションの倉庫のようなもの）を更新します。

```

sudo apt update
sudo apt upgrade -y

```

次にデスクトップ環境をインストールします。
調べた限りでは、LXDE, Xfce の２種類が使えます。
LXDE の方が軽いそうですが、Xfce の方が見た目が良くLXDE程ではないですけれども十分な軽さを持っているそうです。
ここは好みで選択すれば良いと思います。

なお、ここでネットワークやスマートフォンの速度にもよると思いますが数時間掛かります。

・ LXDE のインストール

```

sudo apt install -y lxde

```

・ XFCE のインストール

```

sudo apt install -y xfce4

```

### 環境の設定

XSDL を立ち上げてしばらく待って下さい。
最後なにやら文字列を表示している画面が出るので以下をメモしてください。

上から２行目に以下の文字列が出るはずです。DISPLAY のポート番号をメモしてください。

export DISPLAY=（何かのIPアドレス）:（ポート番号）

上から３行目に以下の文字列が出るはずです。同様に PULSE_SERVER のポート番号をメモしてください。

export PULSE_SERVER=（何かのIPアドレス）:（ポート番号）

IPアドレスはメモする必要はないです。
再び UserLAnd の Ubuntu に戻って下さい。
XSDL に接続するために、設定ファイルに先程メモしたポート番号とローカルのIPアドレスを記載します。

```

# テキストエディタ vim をインストールしていない人はインストール
sudo apt install -y vim

# startXDSL にXDSLの接続設定を記載する
vim /support/startXSDLServerSteo2.sh

```

4行目、8行目、16行目辺りを修正します。

```

# 4行目辺り。4721 の値をメモを行った DISPLAY のポート番号に書き換えます。
  DISPLAY=:4721
    ↓ 書き換え後
  DISPLAY=:（さっきメモした DISPLAY のポート番号）

# 8行目辺り。4721 の値をメモを行った PULSE_SERVER のポート番号に書き換えます。
  PULSE_SERVER=localhost:4721
    ↓ 書き換え後
  PULSE_SERVER=localhost:（さっきメモした PULSE_SERVER のポート番号）

# 16行目辺り。/usr/bin/twm の値を exec startlxde または、exec startyxfce4 に書き換えます。exec を付けないと動作しないので付けて下さい。
  echo '/usr/bin/twm' > /home/$INITIAL_USERNAME/.xinitrc
    ↓ 書き換え後
  # LXDE を使う場合
  echo 'exec startlxde' > /home/$INITIAL_USERNAME/.xinitrc

  # Xfce を使う場合
  echo 'exec startxfce4' > /home/$INITIAL_USERNAME/.xinitrc

```

vim の操作方法を知らない人は以下だけ覚えればなんとかなります。

| キーボードのキー | 役割 |
| --- | --- |
| i | コマンドモードから入力モードに入る |
| ESC | 入力モードを抜けてコマンドモードに戻る |
| :wq | 保存して終了する。コマンドモードで操作すること。 |

## デスクトップ環境の起動

UserLAnd に戻って Ubuntu を長押しし、Stop App を選んで終了して下さい。
（終了しない場合には、下の Sessionsにある Ubuntu を長押しして Stop Session を選択して下さい。）
再び Ubuntu を長押しし、App Info を選択し XSDL を選択してください。
下の Apps を押してから Ubuntu を押して起動してください。
しばらくすると Ubuntu のデスクトップ環境が立ち上がります。

UserLAnd の場合には XSDL の立ち上げまで行ってくれるので、手動で XSDL を立ち上げる必要はありません。

## 参考サイト

https://www.hiroom2.com/2018/05/06/ubuntu-1804-xfce-ja/
[Docker]クソ重いHello,  World!イメージを劇的に軽くする

Docker v17くらいからMultiStageBuildという機能が実装されています。
今まで、「Hello,Worldを出力するだけのImageなのに、ベースImageサイズが大きくて、結局出来上がるImageも数百MBになるんだけど、、、」と、なっていたものが、BuildはGoのImage,実行はalpineのImageとできるようになりました。(v17以前でもできなくはなかったけど、めんどくさかった)
これが一体どういうことなのかをみていきたいと思います。

今回は、`Hello, World!`を出力するコンテナを作成していきます。

```main.go
package main

import "fmt"

func main() {
        fmt.Println("Hello, World!")
}
```

#MultiStageBuildを使わない場合


Dockerfileは以下のようになります。

```
FROM golang:1.13.7-alpine3.11

COPY ./main.go ./

RUN go build -o ./hello ./main.go

ENTRYPOINT ["./hello"]
```

それぞれ同じディレクトリに存在する状態で、以下のコマンドを打ってみましょう。

```
$ docker build -t hello:0.1 .
```

ビルド出来たらRunしてみます。

```
$ docker run hello:0.1
Hello World!
```
ちゃんとmain.goがbuildされて、実行されました。では、この時のImageサイズをみてみます。

```
$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
hello               0.1                 ea6e8238c063        49 seconds ago      361MB
golang              1.13.7-alpine3.11   87eefb76f0a8        9 days ago          359MB
```

このように、golangのcontainer Imageがベースになっているため、サイズが大きくなっています。
`Hello, World!`を出力するだけのコンテナなのに、これじゃあ重すぎですね。。。

#MultiStageBuildを使う場合

Dockerfileは以下のようになります。

```
#Stage 1
FROM golang:1.13.7-alpine3.11 as builder
COPY ./main.go ./
RUN go build -o /hello ./main.go

#Stage 2
FROM alpine:3.11
COPY --from=builder /hello .
ENTRYPOINT ["./hello"]
```

Stage1はgolangのImageを使っていて、ここでmain.goをbuildしています。そしてその実行ファイルをStage2に持ってきて、こっちで実行すると言う形です。

```
$ docker run hello:0.1
Hello World!
```

こちらもちゃんと実行されました。同様に、Imageのサイズをみてみます。

```
$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
hello               0.1                 15f814bf3a87        12 seconds ago      7.6MB
<none>              <none>              6f908ead16f8        13 seconds ago      361MB
golang              1.13.7-alpine3.11   87eefb76f0a8        9 days ago          359MB
alpine              3.11                e7d92cdc71fe        2 weeks ago         5.59MB
```

ここで`<none>`はStage1のImageで、`<hello>`がStage2のImageになっています。Hello, Worldを出力するImageは`<hello>`なので、そのサイズなんと**7.6MB**です！MultiStageBuildを使わない場合と比べて**約350MB**もImageサイズを削減することを実現できました！！

#まとめ
ということで、今回はDockerのMultiStageBuildの機能について、触れてみました。サイズの重たいBuild環境を分離することで、Imageサイズの削減を可能にすることを挙げましたが、他にもStageで分けることで、Dockerfileの保守のしやすさが上がる、セキュリティに強くなるなど、良い事が沢山あります！みなさまも使った事がない方は一度チャレンジしてみてください！
ログインをrsyslog経由でslackに通知させる

#はじめに
サーバ(CentOS)に対するログインを全てslackで通知させたかった．

そこでrsyslogからシェルスクリプトを呼び出してslackに通知させてみる．

#Slackトークンの取得
今回は[こちら](https://qiita.com/kou_pg_0131/items/56dd81f2f4716ca292ef)を参考に取得させていただいた．

#rsyslogの設定
rsyslogの設定を追加する．`/etc/rsyslog.d/slack.conf`を作成して以下を書き込む．これでログイン時に`slack.sh`が実行されるようになる．

```bash:/etc/rsyslog.d/slack.conf
$template login_msg, "%fromhost% %msg%"

if \
      ( $msg contains 'pam_unix(' ) \
  and ( $msg contains 'session opened' ) \
then ^/etc/rsyslog.d/slack.sh;login_msg
```

次に`/etc/rsyslog.d/slack.sh`を作る．例として，チャンネル名はalertとしている．

```bash:/etc/rsyslog.d/slack.sh
#!/bin/sh
curl -XPOST -d "token=アクセストークン" -d "channel=#alert" -d "text=${1#* * * * * }" "https://slack.com/api/chat.postMessage"
```

`text=${1#* * * * * * }`の部分で下の例のような形にログを切り出している．

```
pam_unix(sshd:session): session opened for user root by xxxxx(uid=xxxx)
#これを切り出すと
root by xxxxx(uid=0)
```

#動作確認
まずは普通にSSHでログインしてみる．
![無題.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/382909/b1e27a93-dbfa-a415-0970-b1fd2d1a64d3.png)
ちゃんと通知が来た．

次に`sudo`や`su -`を使ってみる．
![無題.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/382909/8d9e854f-4c05-8bf5-2b21-812c860899cd.png)
rootへのログインも通知が来た．

#最後に
自分しかユーザがいないサーバで動かしてるので，不意の通知が来ないよう祈る．

#参考文献
* [【ssmtp】CentOSでログイン通知【rsyslog】](https://qiita.com/nobu-maple/items/34d052ddfe2fbab4e79c)
* [Slack APIを使用してメッセージを送信する](https://qiita.com/kou_pg_0131/items/56dd81f2f4716ca292ef)
networkxの頂点に対応する量をAxes3Dを使って縦に可視化する

タイトルの通りですが，networkxを使っていると可視化に悩むことがそこそこあります．例えば

- ノードに実数値が対応している場合 → ノードの大きさ(s)を変化させる
- ノードに離散値が対応している場合 → ノードの色を変化させる

という感じで簡単に区別することができますが，なかなか2次元だけではうまく数値を読みづらいことも多いです．ここではmatplotlibのAxes3Dを利用して，できるだけ手抜きをして可視化をやってみました．例として，関東の県庁所在地の緯度経度を取ってきて，各地点に都道府県の人口が乗っていると考えます．次のように可視化しました．


| 2次元 | 3次元 |
| :-- | :-- |
| ![plot2d.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7181/2d453b4e-5264-2273-2d62-3b7914b9a61c.png) | ![anim.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7181/62986922-9a66-a88d-56d1-64825f73af57.gif) |

# データ

適当に取ってきました (参考: https://www.benricho.org/chimei/latlng_data.html )．接続関係は適当に作りました．間違ってたらすいません．

```txt
8,茨城県,36.34139,140.44667,2868041
9,栃木県,36.56583,139.88361,1942312
10,群馬県,36.39111,139.06083,1937626
11,埼玉県,35.85694,139.64889,7337330
12,千葉県,35.60472,140.12333,6279026
13,東京都,35.68944,139.69167,13942856
14,神奈川県,35.44778,139.6425,9200166
```

```txt
8,9
8,11
8,12
9,8
9,10
9,12
10,9
10,11
11,8
11,9
11,10
11,12
11,13
13,12
13,14
14,13
```

# 実装

Axes3Dを使うのですが，networkxの描画関数nx.drawなどはAxes3Dを渡しても怒られてしまいます．そのためz軸方向のデータを入れて強引に描画することにしています．具体的には

- グラフを描いている地点は$z=0$に設定する
- ノードに対応している数値を$z$軸で描く

としています．こうして得られた結果が上の図です．

https://github.com/cocomoff/PlotMapHeight
Eclipseのヒープサイズを増加させる（メモリ不足エラーを解消する）

# はじめに
Eclipseのプラグインを追加するとき、メモリ不足エラーと表示され実行できなかった。
そこでヒープサイズを増加させ、問題を解決した。

# 環境
Eclipse Photon Release 4.8.0

# 試みたが失敗したこと

Eclipseのインストール先にある"eclipse.ini"を書き換える。

```
-startup
plugins/org.eclipse.equinox.launcher_1.3.0.v20120522-1813.jar
--launcher.library
plugins/org.eclipse.equinox.launcher.win32.win32.x86_1.1.200.v20120913-144807
-product
org.eclipse.epp.package.jee.product
--launcher.defaultAction
openFile
--launcher.XXMaxPermSize
256M
-vmargs
-Dosgi.requiredJavaVersion=1.5
-Dhelp.lucene.tokenizer=standard
-Xms256m
-Xmx512m
-Xverify:none
-javaagent:dropins/MergeDoc/eclipse/plugins/jp.sourceforge.mergedoc.pleiades/pleiades.jar

```

以上のコード内の

-Xms256m
-Xmx512m

の2箇所を書き換えるようなのだが、バージョンの違いのためか、
ファイル自体はあるものの内容が記載のものと一致せず、書き換え以前の問題。

# 試みて成功したこと

友人の助言に従い、
自身の"eclipse.ini"のコードの末尾に以下の内容を追加した。

```
-vmargs
-Xms512m
-Xmx1024m
```

"eclipse.ini"全体のコードとしては以下のようになる。


```
-product
org.eclipse.epp.package.jee.product
--launcher.defaultAction
openFile
--launcher.appendVmargs
-vmargs
-Dosgi.requiredJavaVersion=1.8
-XX:+UseG1GC
-XX:+UseStringDeduplication
--add-modules=ALL-SYSTEM
-Dosgi.dataAreaRequiresExplicitInit=true
-Xverify:none
-javaagent:dropins/MergeDoc/eclipse/plugins/jp.sourceforge.mergedoc.pleiades/pleiades.jar
-vmargs
-Xms512m
-Xmx1024m
```

これによってヒープサイズが確保され、目的のプラグインを追加できた。
QuantaサーバのBMCをipmitoolでShared NICにする方法

# 試した環境
- 型名
    - Quanta Plex T21P-4U
- OS
    - Cent OS 7.6

###現在のBMCのLAN card type取得
```
ipmitool raw 0xc 0x2 0x1 0xff 0x0 0x0
# 11 00ならDedicated NIC
# 11 01ならLOM Shared NIC
# 11 02ならOCP Mezzanine　Shared NIC
# 11 03ならQCT Mezzanine　Shared NIC
```
### ipmitoolでLOMをShared NICにする方法
```
ipmitool raw 0x0c 0x01 0x01 0xff 0x01
```
### ipmitoolでOCP MezzanineをShared NICにする方法
```
ipmitool raw 0x0c 0x01 0x01 0xff 0x02 
```
### ipmitoolでQCT MezzanineをShared NICにする方法
```
ipmitool raw 0x0c 0x01 0x01 0xff 0x03
```
【Mac】Mac初心者ユーザーが膨大な時間を費やして得た基本操作メモ

##完全究極パーフェクトアルティメット自分用メモ

>Dear.将来おうちにMacを買うであろう自分へ

>また一からググってイライラしないようにメモを残しておいたよ。
体に気を付けてね。あともっと勉強しろよ。

>ps.たまには実家に帰りなさい。 
From Mac初心者おじさん

##マウスホイールの向きが違う
`システム環境設定`→`マウス`→スクロールのチェック外す


##ターミナルの出し方
`Command`+ `Space`入力後、ターミナルと打つ
※以後Dock(アイコンいっぱい並んでるやつ)に加える


##隠しファイル、フォルダ表示

ターミナルで入力

```
defaults write com.apple.finder AppleShowAllFiles TRUE
```
一回Finder閉じる

```
killall Finder
```
以後、ショートカットでOK

```
[command] + [shift] + [.(ドット)]
```


【参考リンク】：[【Mac】隠しファイル・隠しフォルダを表示する方法](https://qiita.com/TsukasaHasegawa/items/fa8e783a556dc1a08f51)

##adb command打ちたい

ターミナルでこれ打ったら`bash_profile`が開くらしい

``` 
vi ~/.bash_profile
```

`i`でInsert(挿入)モードにして下記入力

``` 
export PATH=$PATH:Android SDKの場所(/platform-tools まで)
```
`Esc`押してInsert終了して
`:wq`と打ち込んで保存してターミナルに戻る

ターミナルで下記打てば完了

``` 
source ~/.bash_profile
```

【参考リンク】：[adbをMacのターミナルで使えるようにする](https://qiita.com/furusin_oriver/items/f956848788c7a63922bd)

##スクショ
スクリーンショットというプリインストールのアプリがある

場所は`Launchpad`で`その他`の中見るとだいたいあるらしい

##GIF

Windowsで使えた[最強のGIF作成ツール](https://github.com/NickeManarin/ScreenToGif/releases)が
Macでは使えないらしいので見つけ次第加筆予定。。。

##ショートカットキーいろいろ

| 呼び出せる機能   |     Key | 
|:-----------------|:------------------|
| ファンクションキーの機能いろいろ| `Fn`+ `Function Key` |     
| Windowサイズ最大化＆解除 | `Ctr`+`command`+`F` |     
| Spotlite(検索的なやつ)|`command`+ `Space`|      
| Finder起動時、任意のフォルダへ移動 | `command`+`Shift`+`G`|  
| Finder起動時、パスをコピー |`Option`+`command`+`C`| 
| Finderをもう一つ開く|`command`+`N` | 
| フォルダ、ファイルをリネーム | 選択して`Enter` | 
| フォルダ、ファイルを消す |`command`+`Delete` | 
| Chrome?で閉じたタブをもう一度開く |`Shift`+`Command`+`T` | 
| Chrome?の文字サイズ縮小|`command`+`-(マイナス)` | 
| Chrome?の文字サイズ拡大|`command`+`Shift`+`+(プラス)` | 
| ローマ字の大文字小文字固定|`Fn`+`Shift`+`Tab` | 
|アプリの強制終了画面呼び出し|`command`+`Option`+`Esc` | 



※`Chrome?`は他のブラウザで検証してないってことです

##辞書登録
右上の**あ**とか**A**を押して登録
memcachedについて

#概要
memcachedとは、分散型のキャッシュシステムを構築するためのソフトウェアである。
今まで、サーバーとDBの接続にはRDBMSが主流で使われていたが、大規模なシステムには
向かなかった。（処理が重くなりすぎるため）

そこで、memcached（メムキャシュトゥ）が登場すると。

# 特徴
- メモリ上にデータ保存を保存しているので、高速に読める。
- クライアントの設定で分散処理にできる。（スケールアウトが用意である）
- 設定した容量を超えると、アクセスされていないモノから消される（LRU）

# こんな感じ
![スライド1.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/514625/6effb127-e0bd-b1ee-3393-e7e47c348438.jpeg)



# 参考
https://gihyo.jp/dev/feature/01/memcached/0001
https://qiita.com/juve_534/items/54f7732641a406f31b55
Rails6 テーブル作成時のmigrateでエラーが出た話

# 目的

- テーブル作成を行なった際にmigrateでエラーが出た話をまとめる

# エラー内容

- 下記コマンドでモデルファイルを作成した。

    ```terminal
    $ rails g model user name:string
    ```

- その後、下記コマンドでmigreteを実行した。

    ```terminal
    $ rails db:migrate
    ```

- 下記のエラーが発生した

    ```
    [14:50:10]MacBook-miriwo~/workspace/study/rails/tropical_fish_sns_of_rails$ rails db:migrate
    == 20200206055010 CreateUsers: migrating ======================================
    -- create_table(:users)
    rails aborted!
    StandardError: An error has occurred, all later migrations canceled:
    
    Mysql2::Error: Table 'users' already exists
    /Users/admin/workspace/study/rails/tropical_fish_sns_of_rails/db/migrate/20200206055010_create_users.rb:3:in `change'
    /Users/admin/workspace/study/rails/tropical_fish_sns_of_rails/bin/rails:9:in `<top (required)>'
    /Users/admin/workspace/study/rails/tropical_fish_sns_of_rails/bin/spring:15:in `<top (required)>'
    bin/rails:3:in `load'
    bin/rails:3:in `<main>'
    
    Caused by:
    ActiveRecord::StatementInvalid: Mysql2::Error: Table 'users' already exists
    /Users/admin/workspace/study/rails/tropical_fish_sns_of_rails/db/migrate/20200206055010_create_users.rb:3:in `change'
    /Users/admin/workspace/study/rails/tropical_fish_sns_of_rails/bin/rails:9:in `<top (required)>'
    /Users/admin/workspace/study/rails/tropical_fish_sns_of_rails/bin/spring:15:in `<top (required)>'
    bin/rails:3:in `load'
    bin/rails:3:in `<main>'
    
    Caused by:
    Mysql2::Error: Table 'users' already exists
    /Users/admin/workspace/study/rails/tropical_fish_sns_of_rails/db/migrate/20200206055010_create_users.rb:3:in `change'
    /Users/admin/workspace/study/rails/tropical_fish_sns_of_rails/bin/rails:9:in `<top (required)>'
    /Users/admin/workspace/study/rails/tropical_fish_sns_of_rails/bin/spring:15:in `<top (required)>'
    bin/rails:3:in `load'
    bin/rails:3:in `<main>'
    Tasks: TOP => db:migrate
    (See full trace by running task with --trace)
    ```

# 原因調査

- 下記コマンドを実行して現在のmigrateのステータスを確認した。

    ```terminal
    $ rails db:migrate:status
    ```

- 以前にmigrateを実施した際のmigrationファイルのが無いことが判明した。

    ```terminal
    [14:52:57]MacBook- 
    miriwo~/workspace/study/rails/tropical_fish_sns_of_rails/db/migrate$ rails db:migrate:status

    database: tropical_fish_sns_development

     Status   Migration ID    Migration Name
    --------------------------------------------------
       up     20200206025324  ********** NO FILE **********
       up     20200206025916  ********** NO FILE **********
      down    20200206055010  Create users
    ```

# 解決法

- 下記コマンドを実行してDBのリセットを行なった。

    ```terminal
    $ rails db:migrate:reset
    ```

- DBの状態を確認した。

    ```terminal
    [14:54:33]MacBook-miriwo~/workspace/study/rails/tropical_fish_sns_of_rails/db/migrate$ rake 
    db:migrate:status
    (in /Users/admin/workspace/study/rails/tropical_fish_sns_of_rails)

    database: tropical_fish_sns_development

     Status   Migration ID    Migration Name
    --------------------------------------------------
       up     20200206055010  Create users
    ```

- 正常に反映されていることをがわかった。
Torブラウザの設定

# Torブラウザとは
torproject.orgが提供する簡単にTorネットワークへ接続してくれるブラウザ

# ダウンロード
https://www.torproject.org/download/ からTorブラウザをダウンロードする.
日本語版もlanguagesにある.


# IPが替わっているかチェック
Torを使えているか,ipが替わっているかチェックする.
https://check.torproject.org


<img width="976" alt="スクリーンショット 2020-02-07 22.00.26.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152284/eee23360-12f4-72d5-9f99-4a96354a0754.png">
<img width="1184" alt="スクリーンショット 2020-02-07 22.02.40.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152284/061b8391-f0ac-f32d-f678-9bb97a762cdf.png">

無事替わっていた.

# アドオン
Torブラウザはfirefox系フレームワークで動いている.よってアドオンも流用できる.

## uBlock (Origin)
広告,アクセス解析,SNS shareボタンなどを無効にすることでよりセキュアにしてくれるアドオン.
さらにマルウェアに関するドメインもブロックしてくれるのだとか.

## Decentraleyes
CDN(コンテンツデリバリーネットワーク)を利用しないことにより,CDNに追跡されないようにするアドオン.
CDNとは簡単に言うとアクセス先のサーバーを分散させることで,オリジナルのサーバーの負荷を減らすサービスである.
hoge.comにhoge.co.jpをCDNで紐付けることでドメイン名はあたかもhoge.comのようでありながらその実データはhoge.co.jpのサーバーから取得する.
これはその過程でトラッキングされてしまうため,CDNを使わせないアドオンが意味を持つ.

## Privacy pass
「私はロボットではありません」のチェックボックスを自動で押してくれる.
Torブラウザでwebページのいろいろなものを非表示にするとこの認証を押すことができなくなる.それを解決してくれる.






# vpn
## protonvpn
無料アカウントでも使えるvpn
しかし"secure core"という機能は使えない.secure coreはスイスを始めとした監視されにくいとされる国のサーバーを経由させることでセキュアする機能.




# 参考

https://knowledge.sakura.ad.jp/19191/
razzle start時にエラーログ出力させる

## はじめに
SSRを実現するビルドツール: [razzle](https://github.com/jaredpalmer/razzle)は `razzle start`でdevelopment modeで実行できるが、client/serverビルドに失敗しても、コンソールにログが表示されない。 

デバッグしやすくするために、エラーログを表示させる方法をまとめました。

## 対応方法。
まず、[friendly-errors-webpack-plugin - npm](https://www.npmjs.com/package/friendly-errors-webpack-plugin) をインストール。 

```bash
yarn add friendly-errors-webpack-plugin -D
```

`razzle.config.js` に以下を追記。エラーがあるファイルや内容を教えてくれるようになります。

```js
// filename: razzle.config.js

'use strict';

// ココ
const FriendlyErrorsWebpackPlugin = require('friendly-errors-webpack-plugin');

module.exports = {
  plugins: [...],
  modify: (config, { target, dev }, webpack) => {
    // ココ
    config.plugins = [new FriendlyErrorsWebpackPlugin()];
    return config;
  }
};
```

本音としては、デフォルトで出力されてほしい。。

## 関連情報
- [razzle in dev mode does not print error log · Issue #1009 · jaredpalmer/razzle · GitHub](https://github.com/jaredpalmer/razzle/issues/1009)
AfterEffects から Lottie のアニメーション JSON を作成する手順

![Lottie_to_JSON_00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425967/ac970c5d-f411-268c-342e-74c2ef78d5e0.png)
日頃からアイコンアニメーションばかり作っているわけではないのですけど
新しい環境をセットアップする時だったり、久々に Lottie 実装する時に
いつも何となく忘れて検索してしまうので
自分への備忘録を兼ねて手順を纏めて記事にしました。

# ❶ まずは素材となるアニメーションを AfterEffects で作成
まずは素材となるアニメーションを AE で作成します。
![Lottie_to_JSON_01.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425967/fe687751-c78a-4d8c-c8f6-7a2ba87b2d93.gif)
**Tips メモ**
イラレからファイルを持って来た時などは予め「ベクトルレイヤーからシェイプ」を作成を選択してレイヤーをベクター（SVG）化しておきましょう
※これをしておかないと JSON で書き出しが出来なくなるので注意しましょう
方法 ＞＞＞ レイヤーを右クリック → 作成 → ベクトルレイヤーからシェイプを作成

AE側の設定で必要なのは
環境設定のスクリプトとエクスプレッションメニュー内の
「スクリプトによるファイルへの書き込みとネットワークへのアクセスを許可」
にチェックを入れておきましょう！
![Lottie_to_JSON_02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425967/b6fd943c-900a-b498-aed3-2a7f273f907d.png)

# ❷ コード書き出しする為の Bodymovin をダウンロードする
Bodymovin
https://exchange.adobe.com/creativecloud.details.12557.bodymovin.html
<img width="720" alt="Lottie_to_JSON_03.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425967/00d55a85-0560-c5af-6256-26a5acb97026.png">
落としてきたこのファイルを開こうとして、上記のようなZXPを開けないというアラートが出る場合は
**アドビアプリケーションのエクステンションとアドオンのインストール**
https://helpx.adobe.com/jp/creative-cloud/kb/installingextensionsandaddons.html

あるいは
https://aescripts.com/learn/zxp-installer/
https://zxpinstaller.com/

これらの ZXP Installer をダウンロードしてインストールしてください。
ちなみに私は上の方を使いました。

# ❸ AE のエクステンション Bodymovin から JSON を書き出す
エクスプレッションから「Bodymovin」を選択します。
![Lottie_to_JSON_04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425967/7ea2c73b-baa9-9749-b8f2-bb0a40f56c6b.png)
プラグインのウィンドウが立ち上がります。
![Lottie_to_JSON_05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425967/085e9895-1419-ca9f-a5f9-0b699720287b.png)
Settings メニューから「Glyphs」が選択されていることを確認。
![Lottie_to_JSON_06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425967/d3338bc3-1d98-50c1-8118-122b0376cade.png)
「Render」ボタン押下したら任意の場所に data.json が書き出されます。
![Lottie_to_JSON_07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425967/d0e57a99-fb63-99f7-5fc8-3035073bc5fd.png)
これで実装に必要な JSON ファイルが出来上がりました。
あとは、見た目に問題がないか Lottie 公式サイトのプレビューで見てみるフローです。

# ❹ Lottie にログインしプレビューページで確認する
生成された data.json を下記のプレビューページで確認することが出来ます。
https://lottiefiles.com/preview

問題なくうまく書き出されていれば、こんな風に確認できます。
![Lottie_to_JSON_08.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425967/3f52e27e-fb97-cfa7-6036-7bbd87b3f0e0.gif)
https://lottiefiles.com/share/O4iV4G
↑ 実際の作成ファイルのプレビューです

ちなみに JSON 本体のコードの中身覗くと、こんな風にちょっと怖いんですけど（笑）
![Lottie_to_JSON_09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425967/42ae8e89-946b-7368-b87e-2ad09ffadb80.png)
コードで動いている SVG なので、大きな解像度のものでもディティールが美しいのと、なんといっても軽量実装が実現出来るのが嬉しいですね！


まとめは以上となります。

アプリにもWebにも使える！
マルチプラットフォームに対応している
Lottieアニメーション
https://lottiefiles.com/

この記事が、これからトライする方など
どこかの誰かのお役に立てたら嬉しいです！
【Java】じゃんけんの手の出し方 (paizaランク A 相当)

#paizaって？
[paiza公式サイト](https://paiza.jp/)
なんかプログラムを書いて、それにランク付けて評価してくれるところ
求人中の企業に対して自分のプログラミング能力をアピールできる
（実務的とは思えないがちゃんと解ければ最低限の能力があると見れるだろう）

#今回解く問題
[問題：じゃんけんの手の出し方](https://paiza.jp/works/mondai/skillcheck_sample/janken?language_uid=java&t=2fe1248410effabab1f3cfb75c9aace8)
・総勝負数N
・総指数M
・相手のハンド列S
の３つが入力として与えられ、総勝負数および総指数をきっちり使った時の相手ハンドに対する最大勝利数を割り出す問題
細かくはリンク先

#解答コードと結果
```java
import java.util.ArrayList;
import java.util.Scanner;

/**
 * じゃんけんの手の出し方 (paizaランク A 相当)
 */
public class AS001{

	public static void main(String[] args) {

		//入力
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		int m = sc.nextInt();
		char[] handArray = sc.next().toCharArray();


		//相手ハンド分析
		int[] handCount = new int[3]; //{G, C, P}
		for(char hand : handArray) {
			switch(hand) {
			case 'G':
				handCount[0]++;
				break;
			case 'C':
				handCount[1]++;
				break;
			case 'P':
				handCount[2]++;
				break;
			}//switch
		}//for


		//ハンドパターン列挙
		ArrayList<Integer[]> patternList = new ArrayList<>(100);
		for(int i = 0; i <= n; i++) {
			for(int j = 0; j <= n; j++) {
				int yubi = i * 2 + j * 5; //指数
				int remain = n - i - j; //残勝負数

				if(yubi == m && remain >= 0) {
					//総勝負数内に指を使い切る組み合わせ
					Integer[] pattern = {remain, i, j}; //{g, c, p}
					patternList.add(pattern);
				}else if(yubi > m || remain < 0) {
					//勝負数を使い切るか、指数がオーバーしたら次のループ
					break;
				}//if
			}//for
		}//for


		//最大勝利数のパターンを計算
		int maxWin = 0;
		for(Integer[] pattern : patternList) {
			int win = 0;
			win += Math.min(handCount[0], pattern[2]); //相手がグー、自分がパー
			win += Math.min(handCount[2], pattern[1]); //相手がパー、自分がチョキ
			win += Math.min(handCount[1], pattern[0]); //相手がチョキ、自分がグー
			if(win > maxWin) maxWin = win;
		}//for


		//出力
		System.out.println(maxWin);
	}//main
}//class
```

#結果
全ての実行時間が0.10秒以内

|![じゃんけんの出し方_結果.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570931/3b89440d-0050-1be6-a8af-9cf450cb714f.png)|
---
【Heroku課金者向け】AutoIdleアドオンでDynoのコストを節約！


Herokuでサービス開発を進めていると、本番以外のテスト用の環境が欲しい！なんてことありますよね。
ここで Dyno もう一台建てるのか〜〜お金が〜。。なんて気持ちになると思います。

**Dynoを常に起動しておく必要ないし、必要なときだけ起動したい。**


そこで今回ご紹介するのは、HerokuのAutoIdle add-onです。
https://elements.heroku.com/addons/autoidle

AutoIdle add-onのダッシュボード↓
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32950/b7b2bb2f-984d-81d7-c908-b6705f998b09.png)

どれくらい節約できているかを表示してくれます。

この add-on を設定すると、DynoのFreeプランと同様、30分でスリープするようになります。
また、このadd-onの追加にも料金がかかるので注意ですが、ずっと起動させておくよりもコストを抑えることが可能になります。

誰かのお役に立てれば幸いです。
【errorgroup】並行処理中にエラーハンドリングをする場合の注意点【Golang】


# 概要
Golangの並行処理をしつつerrorハンドリングをしたい場合は、errorgroupパッケージを使うことができます。
GoDocはこちら
https://godoc.org/golang.org/x/sync/errgroup

## とりあえず実装してみる（期待していない値が返ってくる例）

```golang
import "golang.org/x/sync/errgroup"

var g errgroup.Group
for _, url := range urls {
    g.Go(func() error {
        // Fetch the URL.
        resp, err := http.Get(url)
        if err == nil {
            resp.Body.Close()
        }
        return err
    })
}
```

こんな感じで書くと、urlsの末尾の要素のみ参照してしまい、期待通りに動作しません。なぜなのか。
GoDocを読むと以下のように(後章に記載しています)サンプルコードが書いてあります。

## 期待通りに動作する例

```golang
import "golang.org/x/sync/errgroup"

var g errgroup.Group
for _, url := range urls {
    // Launch a goroutine to fetch the URL.
    url := url // https://golang.org/doc/faq#closures_and_goroutines   <- この代入の意味はなんだろう :thinking_face: 
    g.Go(func() error {
        // Fetch the URL.
        resp, err := http.Get(url)
        if err == nil {
            resp.Body.Close()
        }
        return err
    })
}
```

コメントに記載したリンク( https://golang.org/doc/faq#closures_and_goroutines )に飛ぶと以下の文とサンプルコード発見

> Even easier is just to create a new variable, using a declaration style that may seem odd but works fine in Go:

このように記述するとより簡単に書くことができます。

> This behavior of the language, not defining a new variable for each iteration, may have been a mistake in retrospect. It may be addressed in a later version but, for compatibility, cannot change in Go version 1.

新しい値をイテレーションの中で定義するのは、振り返ると言語仕様として間違っていたが、Goの1系では直せない。

# まとめ
errorgroupではこのイテレーションの方法を取るしかなさそう。

ということで、イテレーションの中でerrorgroupを利用する場合はご注意下さい。

# 関連記事

この記事を執筆した後に、過去に同様の内容の記事が投稿されていましたのでリンクしておきます。
https://qiita.com/sudix/items/67d4cad08fe88dcb9a6d
Nuxt+Typescript : モーダル(ダイアログ)上のVideoタグで動画再生

簡単なようで意外とハマってしまったのでまとめておく

# やりたかったこと
- モーダルの枠一杯に動画を表示
- モーダルを開いて自動再生
- モーダルを閉じたら一時停止
- またモーダルを開いたら自動再生

# 実装したもの ※ElementUIを使ってモーダルを表示させています
```vuejs:MovieDialog.vue
<template lang="pug">
  el-dialog(
    :visible.sync="dialogVisible"
    :before-close="hideDialog"
    :title="title"
    class="movie-dialog"
    width="80%")
    video(
      :src="src"
      @play="isPlaying = true"
      @pause="isPlaying = false"
      @canPlay="playMovie()"
      @click="test"
      controls
      width="100%"
      style="border: 2px solid #bababa"
    )
</template>

<script lang="ts">
import { Vue, Prop, Component, Watch } from 'nuxt-property-decorator';

export default class MovieDialog extends Vue {
  @Prop(Boolean) readonly dialogVisible!: boolean;
  @Prop(String) readonly src!: string;
  @Prop(String) readonly title!: string;

  isPlaying = false;

  @Watch('dialogVisible')
  playMovie(): void {
    const video = this.$el.querySelector('video');
    if (video && this.dialogVisible) {
      video.play();
    }
  }

  pauseMovie(): void {
    const video = this.$el.querySelector('video');
    if (video) {
      video.pause();
    }
  }

  hideDialog(): void {
    this.$emit('closeMovie');
    this.pauseMovie();
  }

```

# なぜハマったか
### 取り敢えずググってみた
「Vue.js Videoタグ」で検索すると以下の記事が一番最初に出てくる.
https://kuranabe.hatenablog.com/entry/2018/09/20/211007
カスタムディレクティブを使うと楽とあるが、nuxt & typescriptでいい具合にカスタムディレクティブを書くには…こんな感じ？

```
import { Vue, Prop, Component, Directive } from 'nuxt-property-decorator';

中略

@Directive
playMovie()....

```

結果、Diretiveがいなくてエラー

### カスタムディレクティブをNuxtで書く方法は？
調べたらこんな記事が
https://imatomix.com/imatomix/notes/1516891080
>/plugins 以下にファイルを作成し、そこに記述する
追加したファイルを nuxt.config.jsに記述する

とはいえ、わざわざplug-inに差し込むのもなんかなぁ…コンポーネントだけで全部書いてしまいたい。

### 次の案：ディレクティブ使わずにiframeつかったら外部サイトのコントローラーとかもよしなについて来て良くね？

結果、iframeのWidthをパーセンテージで可変にした際に、Heightが追従しない。
超横長のiframeの中央で小さい動画が再生される始末…。
動画も縦横のサイズが必ずしも統一されるとは限らず、高さを指定するのが困難。
何よりも酷いのは、iframe内はコントロール不能で、モーダルを閉じてもずっと再生され続けているという事。
一度コンポーネントごと消すという事しないと駄目でかつ、モーダルを閉じるごとに最初から再生という地獄が…

### 原点回帰したら色々わかった

Videoタグの仕様を見てみる。
http://www.htmq.com/video/

知ったこと…

- videoタグにはいい具合のオプションが存在する
    - autoplay : 自動再生
    - controls : コントローラーを表示
```
video(autoplay controls src="...後略)
```
これだけで諸問題が色々解決される。

- videoタグには優れたイベントがあること
    - play : 再生された時
    - pause : 止まった時
    - canplaythrough : いま再生を再開すれば、現在の再生レートで最後まで再生できて、途中でバッファリングのために停止することはないと推定される時

```
video(@play="isPlaying = true" @pause="isPlaying = false" ...後略)
```

みたいな書き方で、再生状態の取得も出来てしまう。美味しい！

困ったら、まずは仕様の確認というのは改めてやっておきたい。
#twitch　の配信中のチャットログを　#discord　でロギングするBOT

githubと改行ルールが違って二重管理になるため、ここにはgithubのREADME.mdのコピペを載せます。
(githubにあっても検索で探せないため。)
https://github.com/github895439/twitch_chat_logging_bot

```plaintext:README.md
本内容を利用した場合の一切の責任を私は負いません。

環境
OS
OS 名: Microsoft Windows 10 Home
OS バージョン: 10.0.18362 N/A ビルド 18362
システムの種類: x64-based PC

node.js
node-v10.16.0-win-x64
discord.js@11.5.1
tmi.js@1.5.0

概要
以前に使用していた配信サイトは掲示板の機能を使っていたためなのか、配信中にチャットのログを視聴者が遡ることができた。
これができると、配信を途中から見た人も話の流れがわかる。
twitchとyoutubeはこれができないのが不便。
てことで、discordでロギングすればいいのではと思った。
(もちろん、遡るためには視聴者がdiscordに参加する必要がある。)
実現方法は、twitch BOTとdiscord BOTを組み合わせる。
twitch BOTがtwitchチャットのメッセージを検出したら、そのメッセージをdiscordチャネルに送信する。

手順
BOT用twitchアカウント作成

BOTのOAuthトークン作成
BOT用twitchアカウントでログインして下記で作成する。
(tmi.jsを使わない場合はこの限りではないかも。)
https://twitchapps.com/tmi/

discord bot設定
公式でわかりやすいものが見つからなかったので、参考のWebページで設定する。
BOT PERMISSIONSはチャネルの作成・削除もするため、下記をONにする。

Send Messages
Manage Channels
Manage Roles
node.jsにtmi.jsモジュールをインストール(※markdownのせいで番号がおかしく、手順の続き)
npm install tmi.js

node.jsにdiscord.jsモジュールをインストール
npm install discord.js

本ツールをダウンロード
https://github.com/github895439/twitch_chat_logging_bot

ダウンロードしたものを展開

ツールの設定
twitch_chat_logging_bot.js内の下記を設定する。

const config =
    {
        twitch:
            {
                botUsername: "<BOT用twitchアカウント名>",
                botPassword: "<twitch BOTのOAuthトークン(Webページにある先頭の「oauth:」も含めて)>",
                channel: "<配信者のアカウント名>"
            },
        discord:
            {
                guild: "<ロギングするdiscordサーバ名>",
                token: "<discord BOTのOAuthトークン>"
            }
    };
ツールを実行(※markdownのせいで番号がおかしく、手順の続き)
>node twitch_chat_logging_bot.js
INPUT 'E' TO STOP
Connected Discord.
[21:30] info: Connecting to irc-ws.chat.twitch.tv on port 80..
[21:30] info: Sending authentication to server..
[21:30] info: Connected to server.
[21:30] info: Executing command: JOIN #cyacya_1451
Connected Twitch.
[21:30] info: [#cyacya_1451] <twitch_chat_logging_bot>: I am ready for Twitch!
Ready Twitch.
Ready Discord.
[21:31] error: No response from Twitch.
BOTの終了(※markdownのせいで番号がおかしく、手順の続き)
「e」キーを押し、Enterキーを押すと停止する。
(discordチャネルを削除するため。
Ctrl+cで強制終了した場合はロギングしているdiscordの#twitch_chat_logチャネルが増殖していくと思う。)
備考
配信中を目的としているが、アーカイブ内のシーク的な使い方もできるため、discordチャネルの削除はツールの開始時に行う。
(次回の配信まで直近の配信のコメントが残る。)
ログなので、discordチャネルはサーバオーナとBOT以外はpostさせない。
参考に書かれているが、discordの開発サイドではサーバのことをギルドというらしい。

参考
twitch API
https://dev.twitch.tv/docs/api/reference

twitch Chatbots & IRC
https://dev.twitch.tv/docs/irc

tmi.js
https://gist.github.com/twitchdevelopers/afda75fe0a43453e97e97b25232778de https://github.com/tmijs/docs https://github.com/tmijs/docs/tree/gh-pages/_posts

discord developer portal
https://discordapp.com/developers/applications/

discord bot設定
https://note.com/bami55/n/ncc3a68652697 https://qiita.com/PinappleHunter/items/af4ccdbb04727437477f https://liginc.co.jp/370260

discord.js
https://discord.js.org/#/ https://github.com/discordjs/discord.js

主な履歴
2020/02/25
　discordチャネルの削除をツール終了時ではなく開始時に変更
　　最新アーカイブのコメントをdiscordに残し、アーカイブ内のシーク的な使い方をできるようにするため。
```
プロジェクト毎にJVMを切り替えるには

#起動時、コンパイル時にJDK,JVMを切り替えたい

Javaの勉強をしているとプロジェクトによって別のバージョンを使いたい時がある。例えば私は最新のjava10以降のvar型推論が好きだけど、業務ではjava8しか使えない。常駐先によってはjava4のところも
あった。
あえて古い環境で勉強しないといけない事もあるわけです。
というより2020年現在、業務でjava10なんてまず使えない・・
eclipseとかだとjvmの指定する画面があるけど、実際コマンドラインではどうやって指定するのだろうか、という実験です。
#java -version でどこのJVMを読み込んでいるか確認する

java12でコンパイル済みのMain classがあり、
環境変数JAVAHOME には java12のJVMへのパスが設定されているとする。
その状態で任意のディレクトリにjava8のJVMのJVMを配置し、その中のjavaコマンドがあるディレクトリに入って

```bash:bash
java -version 
```

コマンドを叩く。
すると

```
java version "12.0.1" 2019-04-16
```

と表示された。つまりカレントディレクトリであっても環境設定JAVAHOMEのクラスパスを通したJVMが動いていることになる。

そこで、

```bash:bash
./java -version 
```

と明示的にカレントディレクトリのjavaコマンドを指定してみた。すると、

```
java version "1.8.0_144"
```

とカレントディレクトリのJVMが起動した。
ということはjavaコマンドをフルパスか相対パスにすればJVMをどこに配置してもパスを通せるのでは？

ということで、プロジェクトルートの直下にJVMを置いた状態でプロジェクトルートで以下のコマンドを打ってみた

```bash:bash
./jdk1.8.0_144.jdk/Contents/Home/bin/java -cp ./bin Main
```

すると

```
Exception in thread "main" java.lang.UnsupportedClassVersionError: Main has been compiled by a more recent version of the Java Runtime
```

こんなエラーが出た。このMainクラスはjava12でビルドされているのでjava8では動かせないと言われている。つまり切り替え成功です。