OmniAICreator/Qiita-1.07M huggingface dataset:
自然言語ベクトル化用Pythonモジュール(text-vectorian)をリリースしました

# 自然言語ベクトル化用Pythonモジュール(text-vectorian)をリリースしました

## TL;DR

`text-vectgorian`は、自然言語をベクトル化するためのPythonモジュールです。
TokenizerやVectorizerの詳細を気にすることなく、任意のテキストから簡単にベクトル表現を取得することが可能です。
日本語Wikipediaで学習済みのモデルを同梱しているため、モジュールをインストールしてすぐに利用することができます。

`text-vectorian`はオープンソースとしてGitHubで公開しています。ライセンスは`MIT License`です。

* [text-vectorian](https://github.com/lhideki/text-vectorian)

## 開発理由

自然言語を機械学習で処理する場合に、何らかの方法で数値化する必要があります。
数値化する方法も様々ですが、何れの場合も文を単語や文字のトークン単位に分割(Tokenize)した上で、トークンの出現順で連番を振ったり、(特定コンテキストにおける)トークンの出現確率で分散表現を得る(Vectorize)ことになります。

日本語の場合はTokenizeの方法も選択する必要があったり、専用の辞書が必要であったりと英語に比べて数値化するまでの手順が煩雑です。
このような手間を省略するために、任意のテキストから簡単にベクトル表現を取得するためのPythonモジュールとして`text-vectorian`を作成しました。

## 利用方法

```bash
pip install text-vectorian
```

## 利用例

`SentencePieceVectorianクラス`のオブジェクトを作成し、任意のテキストをfitメソッドに渡す事でベクトル化した結果を得る事ができます。

```python
from text_vectorian import SentencePieceVectorian

vectorian = SentencePieceVectorian()
text = 'これはテストです。'
vectors = vectorian.fit(text).vectors

print(vectors)
```

Keras用のEmeddingレイヤーを取得することができるため、インデックスを渡す事でファインチューニングも可能です。

```python
from text_vectorian import SentencePieceVectorian

vectorian = SentencePieceVectorian()
text = 'これはテストです。'
indices = vectorian.fit(text).indices

print(indices)

from keras import Input, Model
from keras.layers import Dense, LSTM

input_tensor = Input((vectorian.max_tokens_len,))
common_input = vectorian.get_keras_layer(trainable=True)(input_tensor)
l1 = LSTM(32)(common_input)
output_tensor = Dense(3)(l1)

model = Model(input_tensor, output_tensor)
model.summary()
```

## Editor's Note

### 2018/01/22

文字ベースエンベディング(Char2VecVectorian)の実装をリリースしました。
ABテスト結果をベイズ統計で見る①

##だれに向けた内容か
・ABテスト知ってるよ。
・数学や統計は苦手。数式じゃなくて図で見たい！
**かつ**
・Pythonとか知らんけど、コピペとShift+Enterくらいはできるよ。
・自分で数字を動かして結果を見たい！
という人向けです。（ニッチ過ぎてゴメンナサイ）
##やること
ABテストの結果として、訪問数とコンバージョン数が与えられたときに
Pythonを使ってコンバージョン率の分布をグラフ化します。(今回①ではここまで）
また、各テストパターンの勝率計算の考え方について説明します。(次回②でやる予定です)
##おことわり
ベイズの理論や内容については書籍やブログなどでたくさんの方々が説明してくださっています。
ですので、この記事では**グラフの表示**と、確率分布を**見て、動かして**もらうことのみを目指します。

##環境
Python 3.6.7
numpy 1.15.4
matplotlib 3.0.2
※手元に環境がなければGoogle Colabを使うのもよいかもしれません。

##コード
確率分布を作るための関数を用意します。

```Python
from scipy.stats import beta
import numpy as np

def GetSamplesPosteriors(vs, cs):
    
    a, b = 1, 1
    ps = np.array([beta(a + c, (b + v - c)) for v, c in zip(vs, cs)])

    samples = 100000
    samples_ps = np.array([p.rvs(samples) for p in ps])

    return samples_ps
```
つぎに、訪問数とコンバージョン数を与えます。
（visitとconversionsの配列内の数字をいろいろ変えてみてください。）

```Python
visits = [100,100,100]
conversions = [5, 11, 15]
```

最後に、グラフの表示。

```Python
import matplotlib.pyplot as plt

SPs = GetSamplesPosteriors(visits, conversions)
c = ["b", "g", "r"]
for i, prob in enumerate(SPs):
    plt.hist(prob, bins=100, alpha=0.8, histtype='stepfilled', color=c[i]) 

plt.show()
```
上の３つのコードブロックをコピペして実行してみてください。
↓こんなグラフが表示されると思います。

![ABテスト.png](https://qiita-image-store.s3.amazonaws.com/0/342142/639de0d1-b383-4324-1b95-a4166eeb549f.png)
縦軸が発生頻度、横軸がコンバージョン率に対応します。

今回はグラフの表示までです。
次回は勝率の考え方と計算方法について書きます。
C++でフォルダ以下のファイル一覧を取得する

#1 はじめに
大量の画像をOpenCVで画像処理するときに、フォルダ以下にあるファイル一覧を取得したかったので、その関数を作成しました。
(2019/1/18 追記)
コメントで教えて頂いたfilesystemを使う方法も追記しました。

#2 WinAPIを使う
参考サイト[1]を参照して作成しました。C++17以降が使用できる環境であれば、後述しているfilesystemを使う方法がおすすめです。

#2.1 ソースコード

```FileNames.cpp
/**
* @brief フォルダ以下のファイル一覧を取得する関数
* @param[in]	folderPath	フォルダパス
* @param[out]	file_names	ファイル名一覧
* return		true:成功, false:失敗
**/
bool getFileNames(std::string folderPath, std::vector<std::string> &file_names)
{
	HANDLE hFind;
	WIN32_FIND_DATA win32fd;
	std::string search_name = folderPath + "\\*";

	hFind = FindFirstFile(search_name.c_str(), &win32fd);

	if (hFind == INVALID_HANDLE_VALUE) {
		throw std::runtime_error("file not found");
		return false;
	}

	/* 指定のディレクトリ以下のファイル名をファイルがなくなるまで取得する */
	do {
		if (win32fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
			/* ディレクトリの場合は何もしない */
			printf("directory\n");
		}
		else {
			/* ファイルが見つかったらVector配列に保存する */
			file_names.push_back(win32fd.cFileName);
			printf("%s\n", file_names.back().c_str());
		}
	} while (FindNextFile(hFind, &win32fd));

	FindClose(hFind);

	return true;
}
```

#2.2 出力結果
関数の実行結果は下図の通りです。
![result.png](https://qiita-image-store.s3.amazonaws.com/0/242136/1cc97d05-0cda-1a26-7143-8098e5c242db.png)

#3 filesystemを使う
C++17で標準入りしたfilesystemを使う方法を書きました。こちらの方法では絶対パスが得られます。
Visual Studio 2017でC++17を使う方法は参考サイト[2]を参照してください。

#3.1 ソースコード

```FileNames.cpp
/**
* @brief フォルダ以下のファイル一覧を取得する関数
* @param[in]	folderPath	フォルダパス
* @param[out]	file_names	ファイル名一覧
* return		true:成功, false:失敗
*/
bool getFileNames(std::string folderPath, std::vector<std::string> &file_names)
{
	using namespace std::filesystem;
	directory_iterator iter(folderPath), end;
	std::error_code err;

	for (; iter != end && !err; iter.increment(err)) {
		const directory_entry entry = *iter;

		file_names.push_back( entry.path().string() );
		printf("%s\n", file_names.back().c_str());
	}

	/* エラー処理 */
	if (err) {
		std::cout << err.value() << std::endl;
		std::cout << err.message() << std::endl;
		return false;
	}
	return true;
}
```

#3.2 出力結果
vector配列にフォルダ以下にあるファイルの絶対パスが格納されます。サブフォルダは格納されません。
![result.png](https://qiita-image-store.s3.amazonaws.com/0/242136/0c8d12cb-d522-9486-741a-2fe3914df5a5.png)

#4 参考サイト
[1] http://d.hatena.ne.jp/s-kita/20100129/1264776052
[2] https://codezine.jp/article/detail/10890
ほんの少しだけツールを使いやすくするかもしれないエディタ拡張

みなさんエディタ拡張していますか？


中には業務で作ったにも関わらず、一切使われることがなく、作ったものだけが残ってしまって
「あいつらは全然説明書を見ようともしねぇ」といった文句を言った経験があったりするかもしれません。

#今回の話の趣旨

###その原因、本当に使う側だけでしょうか？
詳しくはこの記事では、言及しませんが、何事も何か新しい事を覚える上で人というのは、何かしらの抵抗が存在するものなので、それを少し減らすために手軽に手が付けれるUI部分で少しでも工夫しましょうって話
↑の抵抗を少しでも減らすためのエディタ拡張上で行えるUIの実現を少し紹介する記事です。


#開発環境
Unity2017.4.8f1
VisualStudio2017Community


#例えばこんなの

普通に文字の羅列が並んでいるだけより
![見ずらいUI.png](https://qiita-image-store.s3.amazonaws.com/0/101366/aea95aa4-84b2-9030-95b8-8c8dcf2c11f1.png)


こうしたほうが見やすい
![少し見やすくなったUI.png](https://qiita-image-store.s3.amazonaws.com/0/101366/ae7aa024-311e-e638-b0db-311d34ae872f.png)


理由としては、
・判然と並んでいるよりメリハリがついたー＞太文字、枠組み
・一つのまとまりとしての項目内容がわかりやすくなった。ー＞枠組みと線


今回の適応した内容としては以下
・太文字
・線引き
・枠組み
・段落
の4種類になります。



#やり方

###太文字

``` bold_sample.cs

        GUIStyle _style = new GUIStyle()
        {
            fontSize = EditorStyles.boldFont.fontSize,
            fontStyle = FontStyle.Bold

        };
        EditorGUILayout.LabelField(_message, _style, _layout);

```

###線引き
ただし線引きの際は、BegineVertical～～　とか　BegineHorizontalに準拠した上での線引き

``` 縦引き
 GUILayout.Box(GUIContent.none, GUILayout.Width(1f), GUILayout.ExpandHeight(true));
```

```横引き
GUILayout.Box(GUIContent.none, GUILayout.ExpandWidth(true), GUILayout.Height(1f));
```

###枠組み

```
       Rect _rect = EditorGUILayout.BeginVertical(GUI.skin.box);
        {
           //ここに囲いたいUIを記述する。
        }
        EditorGUILayout.EndVertical();

```

###段落

```
                Label("項目名");
                EditorGUI.indentLevel++;　　　　　　//＜－これによって段落を変えている　
                Label("ここに項目が入るよ");
                EditorGUI.indentLevel--;           //＜－最終的に戻す必要あり。
```



よいエディター拡張ライフを
dplyr使いのためのpandas dfplyでもJOIN編

#はじめに
pandasデータフレームをRのdplyr同様に操作可能にするdfplyライブラリについてまとめるシリーズです。今回は100%中の100%大事なjoin関数です。複数のデータフレームを結合する関数ですね。

関連記事はこちら
[dplyr使いのためのpandas dfplyすごい編](https://qiita.com/T_Shinomiya/items/c039451869382e0790f4)

dplyrのjoin関数についてはmatsuou1氏が解説している記事が分かりやすいです。
[dplyrを使いこなす！JOIN編]
(https://qiita.com/matsuou1/items/b1bd9778610e3a586e71)

#事前準備、例データ
```Python:Python：事前準備
import pandas as pd
import numpy as np
from dfply import * #dfply読み込み

#例データ
a = pd.DataFrame({
    'x1': ['A', 'B', 'C'],
    'x2': [1, 2, 3]
})
b = pd.DataFrame({
    'x1': ['A', 'B', 'D'],
    'x3': [True, False, True]
})
```


![ab.png](https://qiita-image-store.s3.amazonaws.com/0/318124/460fe3be-c3fd-f1ee-5f77-901590966092.png)

##各種join
dplyrと同様です。

```Python:Python：dfply-join
#aとbを結合
a >> inner_join(b, by='x1')
```
![joins.png](https://qiita-image-store.s3.amazonaws.com/0/318124/8a82e6bd-91dc-8e8b-b35d-eed3104e7f3d.png)

結合キー列（by=指定）は両データフレーム共通でなくてはなりません。
そのためdplyrで可能であった **by = c('x1' = 'y1')** のような書き方はできません。

```Python:Python：dfply-join
#aとaを結合
a >> left_join(a, by='x1')
#同じ列名があると'_x', '_y'がついて分けてくれます。
```
![image.png](https://qiita-image-store.s3.amazonaws.com/0/318124/011d1de8-fb06-a17f-ded5-32275c91e5fa.png)

##各種bind
dplyrと同様です。
###bind_rows 縦結合
```Python:Python：dfply-bind_rows
a >> bind_rows(b, join='inner')
a >> bind_rows(b) #join='outer' #ignore_index=False
  #ignore_indexでindexがリセット
```
![bind_rows.png](https://qiita-image-store.s3.amazonaws.com/0/318124/09166948-c346-0e23-a5d7-8cdcff2f9f39.png)

###bind_cols 横結合
```Python:Python：dfply-bind_cols
#例データ：cを追加
c = pd.DataFrame({
    'x1': ['B', 'C', 'D', 'E'],
    'x2': [2, 3, 4, 5]
})

#aとcを横結合
a >> bind_cols(c) # join='outer', ignore_index=False) 
  #ignore_indexでindex（列名）がリセット
```
![image.png](https://qiita-image-store.s3.amazonaws.com/0/318124/449577c1-09b1-2578-eec7-9d59eba7f0e1.png)
単純に結合すると同じ列名があったとしてもjoinのように'_x', '_y'をつけてくれませんし、select()で'x1'を指定しても最初の列しか認識してくれません。

#まとめ
いかがでしたでしょうか。dfplyのjoin関数も今まで紹介した関数同様にdplyrと同じように機能します。dplyr使いには本当に便利ですね。
rbenvでバージョン管理する

# これはなに？
駆け出しrubyエンジニアのnyagato_00です。
職場で、rubyのバージョンアップを行うためにrbenvの使い方などを調べまとめたものです。

# rbenvのインストール
Macをお使いであれば、Homebrewでインストールします。

```
$ brew install rbenv
```

`init`コマンドでshellへ登録します。

```
$ rbenv init
```


# rubyのバージョン確認
自環境にインストールされているrubyのバージョンを確認してみます。

```
$ rbenv versions
  system
* 2.4.1 (set by /Users/nyagato_00/.rbenv/version)
```

＊が付いているものが、現在使用されているrubyのバージョンです。

# インストール可能なrubyの一覧を取得する
`$ rbenv install --list`コマンドで、インストール可能なrubyバージョンの一覧を取得します。

```
$ rbenv install --list
Available versions:
  1.8.5-p52
  1.8.5-p113
  1.8.5-p114
  1.8.5-p115
  1.8.5-p231
  1.8.6
~略
  2.2.0
  2.2.1
  2.2.2
  2.2.3
  2.2.4
  2.2.5
  2.2.6
  2.2.7
  2.2.8
  2.2.9
  2.2.10
  2.3.0-dev
  2.3.0-preview1
  2.3.0-preview2
  2.3.0
  2.3.1
  2.3.2
  2.3.3
  2.3.4
  2.3.5
  2.3.6
  2.3.7
  2.4.0-dev
  2.4.0-preview1
  2.4.0-preview2
  2.4.0-preview3
  2.4.0-rc1
  2.4.0
  2.4.1
  2.4.2
  2.4.3
  2.4.4
  2.5.0-dev
  2.5.0-preview1
  2.5.0-rc1
  2.5.0
  2.5.1
  2.6.0-dev
  2.6.0-preview1
```

# rbenvでバージョンを指定してインストールする
バージョン2.5.1をインストールしてみます。

```
$ rbenv install 2.5.1
```

インストール後のバージョン確認してみます。

```
$ rbenv versions
  system
* 2.4.1 (set by /Users/nyagato_00/.rbenv/version)
  2.5.1
```

# 使用するrubyバージョンを切り替える
切り替えには2通りの方法があります。
ローカルのアプリケーションのバージョンを指定する方法と、環境全体で使用するrubyのバージョンを指定する方法です。

ローカルの場合

```
$ rbenv local 2.5.1
```


グローバルの場合

```
$ rbenv global 2.5.1
```

# rbenvで特定のバージョンを削除する
バージョン2.5.1をインストールし、こちらを使うように指定しまいしたので、古いバージョンは削除したいと思います。

```
$ rbenv uninstall 2.4.1
```

# bundle installを忘れずに
これまで使用していたバージョンのrubyも削除しましたし、新しいバージョンのrubyをインストールしましたので、忘れずに`bundle install`をしておきましょう。

```
$ bundle install
```


## 参考
https://github.com/rbenv/rbenv
プログラマが知っているとよい設計指針（3）国際単位系

プログラマが知っているとよい設計指針（3）国際単位系

国際単位系で表す量を使うことが大事である。
各国の単位系を使う場合には、各国の単位系と国際単位系の変換式を持ち、いつでもどこでも、どちらからどちらへも変換できるようにするとよい。

例えば、localeなどの地域コードによって、優先的に表示する単位系を用いても良い。

#基本単位
| 量 | 名称 | 記号 |
|:--|:--|:--|
| 長さ | メートル(metre) | m |
| 質量 | キログラム(kilogram) | kg |
| 時間 | 秒(second) | s |
| 電流 | アンペア(Ampere) | A |
| 熱力学温度 | ケルビン(Kelvin) | K |
| 物質量 | モル(mole) | mol |
| 光度 | カンデラ | cd |

国際単位系は、mks単位系と呼ぶことがある。

#組立単位
| 組立量 | 名称 | 記号 | SI組立 |
|:--|:--|:--|:--|
| 平面角 | ラジアン (radian) | rad | m/m |
| 立体角 | ステラジアン(steradian) | sr | $m^2/m^2$ |
| 周波数 | ヘルツ (hertz) | Hz | $s^{−1}$ |
| 力 | ニュートン (newton) | N | $m·kg·s^{−2}$ |
| 圧力(応力) | パスカル (pascal) | Pa | m−1·kg·s−2 |
| 仕事(熱量・エネルギー) | ジュール (joule) | J | $m^2·kg·s^{−2}$ |
| 仕事率(工率) | ワット (watt) | W | $m^2·kg·s^{−3}$ |
| 電荷 | クーロン (coulomb) | C | $s·A$ |
| 電位差 (電圧) | ボルト (volt) | V | $m^2·kg·s^{−3}·A{−1}$ |
| 電気容量 | ファラド (farad) | F | $m^{−2}·kg^{−1}·s^4·A^2$ |
| 電気抵抗 | オーム (ohm) | Ω | $m^2·kg·s^{−3}·A^{−2}$ |
| コンダクタンス | ジーメンス (siemens) | S | $m^{−2}·kg^{−1}·s^3·A^2$ |
| 磁束 | ウェーバ (weber) | Wb | $m^2·kg·s^{−2}·A^{−1}$ |
| 磁束密度 | テスラ (tesla) | T | $kg·s^{−2}·A^{−1}$ |
| インダクタンス | ヘンリー (henry) | H | $m^2·kg·s^{−2}·A^{−2}$ |
| セルシウス温度 | セルシウス度 | ℃ |  |
| 光束 | ルーメン (lumen) | lm | $cd·m^2/m^2$ |
| 照度 | ルクス (lux) | lx | $m^{−2}·cd$ |
| 放射性核種の放射能 | ベクレル (becquerel) | Bq | $s^{−1}$ |
| 吸収線量 | グレイ (gray) | Gy | $m^2·s^{−2}$ |
| 線量当量 | シーベルト (sievert) | Sv | $m^2·s^{−2}$ |
| 酵素活性 | カタール (katal) | kat | $s^{−1}·mol$ |

今、計算している値が、どういう単位なのかを注釈等で記述しておくと、
単位の違うものを比較したり、単位の違う変数、定数に値を代入することが少なくなるかもしれない。
Windows 10にGoogle Cloud SDKをinstall 

# インストール失敗
[公式のページ](https://cloud.google.com/sdk/docs/quickstart-windows?hl=ja)通りにやっても、
windows10のPCにGoogle Cloud SDKをインストールがうまくいかなかった。

環境：Windows 10 Pro, 64bit
SDK version：229.0.0

# 原因
### 1. pythonエンコーディングエラー
- 発生したエラー

    > UnicodeDecodeError: 'ascii' codec can't decode byte ....
- 解決
    - **Pythonの初期エンコーディングをasciiからshift-jisに変更すればいいようです。**
- 参考
    - [Google Cloud SDKのセットアップはどこまでWindowsユーザーを苦しめれば気が済むのか？](https://qiita.com/hirocueki2/items/1789998804c4e7ec1ef3)

### 2. バッチファイルで日本語文字のユーザフォルダが読み取れない
- 発生したエラー

    > Welcome to the Google Cloud SDK!
    > 指定されたパスが見つかりません。
- 解決
    - 1. installバッチファイルを開く
        - 場所：installフォルダ\google-cloud-sdk\install.bat
        - （例）：C:\Users\(User名)\AppData\Local\Google\Cloud SDK\google-cloud-sdk\install.bat
    - 2. 47行目を書き換え
        - 修正前
            - `SET CLOUDSDK_PYTHON=%%i`
        - 修正後：**日本語を入れるとエラーが起きたので、相対パスで書きました。**
            - `SET CLOUDSDK_PYTHON=".\platform\bundledpython\python.exe"`
    - 3. install.batの実行
- 参考
    - [Windows版Google Cloud SDKのインストールに失敗する](https://qiita.com/amama-nagigi/items/f617960fa341a6040010)
[PHP]体重が気になるあなたへ 〜privateの特殊ケース〜

皆さん、健康診断の結果はどうでしたか？

えっ、またお医者さんに「太り過ぎ」と言われた？ 
奥さんに怒られるし、上司からも「痩せろ」と言われるしで、大変ですよね。

だったら、体重は `private` プロパティーにして秘密にしておきましょう！

```php
class Person
{
  private $name;

  // 最高機密
  private $weight;

  public function __construct($name, $weight)
  {
    $this->name = $name;
    $this->weight = $weight;
  }
}
```

はい、これで体重を隠せましたね。めでたしめでたし。


# メソッドを追加してみる

でも、自分より太ってそうな、あの同僚の体重、知りたいですよね。[^1]

[^1]: 知って何が楽しいかって？ 「俺はあいつよりも痩せている」という優越感に浸りたいじゃないですか。


はい、そんなあなたのために、こんなメソッド書いてみました。

```php
class Person
{
  private $name;
  private $weight;

  public function __construct($name, $weight)
  {
    $this->name = $name;
    $this->weight = $weight;
  }

  /**
   * 体重が同じかを比較する
   */
  public function isWeightEqual($other)
  {
    return $this->weight === $other->weight;
  }
}
```

あっ、でも `$other->weight` は `private` プロパティーだからダメなんじゃない？と思った方。

残念。これはちゃんと動きます。

```php
$a = new Person("山田太郎", 60.5);
$b = new Person("田中次郎", 60.5);
var_dump($a->isWeightEqual($b)); //--> bool(true)
```

もっと頑張れば、`isWeightGreaterThan()` とか `isWeightLessThan()` とかも作れるでしょう。

**体重を隠そうとしても無駄なんだぞ！**


# まじめに考えてみる

実は、PHP マニュアルの [他のオブジェクトからのアクセス権](http://php.net/manual/ja/language.oop5.visibility.php#language.oop5.visibility-other-objects) にちゃんと書いてあります。

> 同じ型のオブジェクト間では、たとえ同一のインスタンスでなくても お互いの private メンバーや protected メンバーにアクセスすることができます。 これは、そのオブジェクトの内部ではオブジェクトの実装の詳細が既知であるからです。 

なんか難しいこと書いてありますが、要するに ***同じ型だったらインスタンスが違ってても `private` や `protected` メンバーにアクセスできるぞ*** と言っています。

## なんでこんな面倒なことしてるの？

実は、この仕様、Java でも同じなのですが[^2]、[[Java]同一クラスであれば他インスタンスのprivateフィールドにアクセスできるのは何故か？](https://qiita.com/ksugimori/items/0e87e098c03391900cbf) という記事に、とても良いコメントを見つけました。

[^2]: C++ や C# でも同様らしいです。[privateメンバ変数へのアクセス](https://www.anarg.jp/personal/t-tugawa/note/cpp/private.html) 参照。

> @shirakamus
> もし private が thisからしかアクセスできない仕様だったら、equalsメソッドの実装はどうなるかな・・・

Java ではオブジェクトの比較は `equals()` メソッドで行います。どのオブジェクトも、以下のような `Object.equals()` を継承しています。

```java
public boolean equals(Object o) {
    return this == o;
}
```

通常はこれで十分なのですが、`equals()` メソッドをオーバーライドすることもできます。たしか、こんな感じ。[^3]

[^3]: 本当は `hashCode()` もオーバーライドしないといけないらしいけど、一旦、措いておきます。詳しくは [equals をオーバーライドする時は一般契約に従う](https://maku77.github.io/java/effective/08.html) 参照。


```java
public class Person
{
  private String name;
  private double weight;

  Person(String name, double weight)
  {
    this.name   = name;
    this.weight = weight;
  }

  @Override
  public boolean equals(Object other)
  {
    if (this == other) {
      return true;
    }

    if (other instanceof Person) {
      Person person = (Person) other;

      // private フィールドにアクセスしている！！！
      return person.name == this.name
        && person.weight == this.weight;
    }

    return false;
  }
}
```

重要なのは `person.weight == this.weight` の部分です。
この `person.weight` は、引数で渡されたインスタンスの `private` フィールドですが、同じ `Person` 型なのでアクセスすることができるわけです。

もし、これが不可能だった場合、`person.getWeight()` というように、わざわざゲッターを介したアクセスになるでしょう。


# まとめ
PHP には Java のような `equals()` は存在しませんが、思想としてオブジェクト指向を取り入れた際に、Java をはじめとするオブジェクト指向言語と同じような動きをするようにしたのでしょう（たぶん）。

まぁ、積極的に使うべきかと言われると、あんまり知られていないようにも思われるので、止めておいたほうがいいのかなとも思いますが。

あと、そもそも、痩せれば、こんな面倒なことまで気にしなくて済むはずです。

**だから、お前は痩せたほうが良い。**


(2018/1/13) サブタイトルを付けました。
高解像度モニター設定の覚え（Intel/Altera Quartus Primeなどで）

# 高解像度ディスプレイにもデフォで対応して欲しいなぁ
わたしが家で使用しているPCは Surface Book です。高解像度ディスプレイに惹かれて購入したのですが、日曜工作やらお勉強で AutoCAD や Quartus Prime を利用しようとすると文字やアイコン表示が非常に小さくなり、目が悪いわたしには非常に酷な表示になります。
多分、4Kモニターを導入しているデスクトップでも同様の現象が出るかと思います。
これの改善の為にあれこれ設定の変更を試してみたので、その覚えとして残しておきます。

## 設定方法
わたしは以下の様に設定しました。この設定であれば、Quartus Prime の回路図表示にした場合でも文字が隠れることはありません。

1. 右クリックでディスプレイ設定
2. 拡大縮小とレイアウト・・・125%
3. 解像度・・・1920 x 1200

折角の高解像度が活かせないのですが、Quartus Prime を用いるときには已む得ず変更しています。

デフォで対応が一番の嬉しいのですが。。。
安倍総理の発言を各年毎に集計してグラフにしてみた

[安倍総理が今年一番多く発言した単語を調べてみた](https://qiita.com/Sak1361/items/350cf0cb9d925e3c0924)の続きみたいな感じ。
これ各年毎にグラフに出したらその年の傾向がなんとなく分かるんじゃないかなと思ったのでやってみました。

## 集計する範囲を決める
せっかくなので第一次安倍内閣(2006年9月~2007年9月)と第二次安倍内閣以降(2012年12月~現在)の範囲を１年区切りで集計したいと思います。これだと計7個のグラフができそうです。早速貼り付けていきます。
## 集計する際の品詞の選択
[安倍総理が今年一番多く発言した単語を調べてみた](https://qiita.com/Sak1361/items/350cf0cb9d925e3c0924) でやってみた感じだと、**名詞＋一般形or名詞＋固有名詞**の二種類に絞るとよりその年の傾向が見えてきそうでしたので、今回はこの条件で集計してみたいと思います。

# 2006年9月~2007年9月(第一次安倍内閣)の発言集
![Figure_1.png](https://qiita-image-store.s3.amazonaws.com/0/339669/a018e671-aba6-d825-d71d-9a9c678b6134.png)

# 2012年12月~2013年12月(第二次安倍内閣)の発言集
![Figure_1.png](https://qiita-image-store.s3.amazonaws.com/0/339669/50b4cc29-a83a-141b-84b1-b22b5673aaa2.png)

#2014年1月~2014年12月の発言集
![Figure_1.png](https://qiita-image-store.s3.amazonaws.com/0/339669/7ab52719-5eb6-13be-a21c-bf44dfa3ec96.png)

#2015年1月~2015年12月(第三次安倍内閣)の発言集
![Figure_1.png](https://qiita-image-store.s3.amazonaws.com/0/339669/3ecc5c19-c791-3add-c76c-b2f357bdd311.png)

#2016年1月~2016年12月の発言集
![Figure_1.png](https://qiita-image-store.s3.amazonaws.com/0/339669/749c54c6-55ad-ab25-46d8-b096dad3f64b.png)

#2017年1月~2017年12月(9月より第四次安倍内閣)の発言集
![Figure_1.png](https://qiita-image-store.s3.amazonaws.com/0/339669/79cc0289-100c-9731-e990-a3647c895a37.png)

#2018年1月~現在までの発言集
![Figure_1.png](https://qiita-image-store.s3.amazonaws.com/0/339669/519ea3d6-88ee-8353-ea26-6f028ba34e9f.png)


# グラフから何が読み取れるか
どの年を切り取っても「日本」や「政府」と言った単語は必ず入っていますね。面白いのは「責任」という言葉が入ってたり入ってなかったりしていたり、その年だけに入っている単語がちらほら見受けられました。軽くまとめて見ます。
## 各年毎の特徴的な単語まとめ
| 集計年       |      特徴的な単語 |      その他特徴|
|------------:|------------------:|------------------:|
|2006年~2007年| 社会・世界・子供たち・年金・先生 |
|2012年~2013年| 社会保障・デフレ・大臣 |「経済」の発言が比較的多い
| 2014年      | 地方・憲法 |
| 2015年      | 要件・自衛隊・集団自衛権・武力攻撃|「我が国」が一番多く自衛隊に関する発言が多い
| 2016年      | TPP・年金・大臣・社会保障|「TPP」が一番多い
| 2017年      | 北朝鮮・米国・|総単語数が他に比べて少ない
|2018年~現在  |北朝鮮・米国・TPP・大臣・責任|「政府」が一番多い

上位の単語はどの年を取っても一定数以上は必ず出現していますね。ただその年々で発言数が変わったり変動している点から比較することができそうです。毎回出現している単語を省けば、よりその年を表すような単語が見えてきそうです。

# 最後に
安倍総理一人を切り取って年別に比較して見ました。議事録を用いてまだまだ遊べそうなので色々試していきたいですね。
Mac で Ruby で Firefox の selenium でちょっとつまづいた

Firefox でウェブのフォームにちょっと値を入れた状態にする，ということを Mac 上の Ruby で自動化したかった。

selenium-webdriver という gem を使えば簡単（Rails のデフォルトの Gemfile にもこの gem は書かれている）。

ところが久々に動かそうとしたらつまづいた。

# コード

こんな感じで，とりあえずページを開こうとした

```rb:Gemfile
# 該当部分
gem "selenium-webdriver"
```


```rb
# 該当部分
driver = Selenium::WebDriver.for(:firefox)
driver.navigate.to("http://localhost:3000/")
```

# エラー

```
Selenium::WebDriver::Error::UnknownError: newSession
```

と怒られた。

# 解決

もともと `brew install geckodriver` で geckodriver は入ってたんだけど，以下の手順で入れ直したら解決した。

```
rm '/usr/local/bin/geckodriver'
brew install geckodriver
brew link geckodriver
```

# 環境

macOS 10.13.6（High Sierra）
ruby 2.5.3p105 (2018-10-18 revision 65156) [x86_64-darwin15]
geckodriver 0.23.0
Firefox 64
すごろく作ってみた(CUI)

$GREEDに引き続きすごろくを作ってみました。
Classを活用したいと思っていたのですが、なかなか難しいですね。

```Python
from random import randint
import unicodedata


def get_length_unicode(line):
	lng = 0
	for i in line:
		if unicodedata.east_asian_width(i) in "WFA":
			lng += 2
		else:
			lng += 1
	return lng


def dice_roll():
	return randint(1, 6)


class Mas:
	def __init__(self, step=0, jump=None, wait=0, evnt=""):
		self.evnt = evnt
		self.step = step
		self.jump = jump
		self.wait = wait
	def exe(self,now,name):
		if self.evnt:
			print(self.evnt)
		if self.jump != None:
			now = self.jump
			print("{} > jump:{}".format(name,self.jump))
		if self.step:
			print("{} > step:{}".format(name,self.step))
		now += self.step
		return now,self.wait

class Player:
	def __init__(self, name):
		self.name = name
		self.mas = 0
		self.wait = 0


def get_player_date():
	players = []
	name_max_len = 0
	pon = ""
	while True:
		pon = input("number of player:")
		try:
			pon = int(pon)
			break
		except ValueError:
			print("TypeError: write int")
	for i in range(1,pon+1):
		name = input("PL{}'s name:".format(i))
		name_max_len = max((get_length_unicode(name),name_max_len))
		players.append(
			Player(
				name if name else "PL{}".format(i)
			)
		)
	for i in players:
		i.name += " " * (name_max_len - get_length_unicode(i.name) + 1)
	return tuple(players)


def map_(*mas):
	return {i+1:v for i,v in enumerate(mas)}


def print_map_view(pl,map_):
			m = list("■"*len(map_))		

			
			m[pl] = "□"
			print("".join(m))

def play(players,map_):
	clear = []
	while True:
		for i in players:

			if i in clear:
				continue
			if i.wait > 0:
				print(str(i.name)+" > wait: "+str(i.wait))
				print("====================================")
				i.wait -= 1
				continue
			
			roll = dice_roll()
			i.mas += roll

			if i.mas >= len(map_):
				print_map_view(len(map_)-1,map_)
				print(i.name+" > roll: "+str(roll))
				input(str(i.name)+" > total: "+str(i.mas)+"/{}".format(len(map_)-1))
				print("clear!:{}".format(i.name))
				print("====================================")
				clear.append(i)
				continue
			if i.mas:
				i.mas,i.wait = map_[i.mas].exe(i.mas,i.name)

			print_map_view(i.mas,map_)
			print(i.name+" > roll: "+str(roll))
			input(str(i.name)+" > total: "+str(i.mas)+"/{}".format(len(map_)-1))
			print("====================================")

def main():
	m = map_(
		Mas(step = 5),
		Mas(step = 5),
		Mas(step = 5),
		Mas(step = 5),
		Mas(step = 5),
		Mas(step = 5),
		Mas(),
		Mas(),
		Mas(),
		Mas(),
		Mas(),
		Mas(evnt = "ものまねしてくれ"),
		Mas(),
		Mas(),
		Mas(wait = 1),
		Mas(wait = 1),
		Mas(wait = 1),
		Mas(),
		Mas(),
		Mas(),
		Mas(),
		Mas(),
		Mas(jump = 5),
		Mas(jump = 5),
		Mas(),
	)
	p = get_player_date()
	print("===========")
	play(p,m)


main()
```
そのprotocol導入、意味ないかも

導入したはずのprotocolが`conformsToProtocol`に認識されない現象に遭ったので、それを読み解く。

前提
====

- protocolはclass、extension、categoryのどちらも導入できる
- extensionは静的、categoryは動的[^1]

結論
====

- protocolをextensionで書きたいなら、classのimplementationの見えるところ[^2]に書こう
- protocolをcategoryで書きたいなら、categoryのimplementationの見えるところに書こう

実験
====

`UNUserNotificationCenterDelegate`が`conformsToProtocol`に認識されるか確認してみた。


- `AppDelegate.h`をimportしているファイル
    - `AppDelegate.m`
    - `AppDelegate+Hoge.m`
- `AppDelegate+Hoge.h`をimportしているファイル
    - `AppDelegate+Hoge.m`
- AppDelegateのimplementationは`AppDelegate.m`にある
- AppDelegateのcategoryのimplementationは`AppDelegate+Hoge.m`にある
- チェック＝conformsToProtocol

結果
----

- AppDelegateでprotocolを導入
    - `AppDelegate.h`で定義
        - `AppDelegate.m`でチェック => YES
        - `AppDelegate+Hoge.m`でチェック => YES
    - `ViewController.h`で定義
        - `AppDelegate.m`でチェック => NO
        - `AppDelegate+Hoge.m`でチェック => NO
- AppDelegateのextensionでprotocolを導入
    - `AppDelegate.h`で定義
        - `AppDelegate.m`でチェック => YES
        - `AppDelegate+Hoge.m`でチェック => YES
    - `AppDelegate+Hoge.h`で定義
        - `AppDelegate.m`でチェック => NO
        - `AppDelegate+Hoge.m`でチェック => NO
    - `ViewController.h`で定義
        - `AppDelegate.m`でチェック => NO
        - `AppDelegate+Hoge.m`でチェック => NO
- AppDelegateのcategoryでprotocolを導入
    - `AppDelegate.h`で定義
        - `AppDelegate.m`でチェック => NO
        - `AppDelegate+Hoge.m`でチェック => NO
    - `AppDelegate+Hoge.h`で定義
        - `AppDelegate.m`でチェック => YES
        - `AppDelegate+Hoge.m`でチェック => YES
    - `ViewController.h`で定義
        - `AppDelegate.m`でチェック => NO
        - `AppDelegate+Hoge.m`でチェック => NO

上記の結果から分かるのは、

- protocolの導入するinterfaceは、implementationが伴わないと`conformsToProtocol`は認識しない
- ただし、種類によって認識するimplementationが違う：
  - AppDelegateに導入 => AppDelegateのimplementation
  - **AppDelegateのextensionに導入 => AppDelegateのimplementation**
  - **AppDelegateのcategoryに導入 => AppDelegateのcategoryのimplementation**


[^1]: http://quesera2.hatenablog.jp/entry/2014/02/22/202900
[^2]: importされるヘッダーに、もしくは同じファイルに書く
ゼロから作るディープラーニングをgoogle colaboratory上で動かす

#　ゼロから作るディープラーニングをgoogleColaboratory上で動かす

## TL;DR
個人的にディープラーニングを勉強しはじめたけどGUIとか高くて使えねえよと思っている貧乏学生です。
ゼロから作るディープラーニングくらいならCUIでも動きますがただでGUI使えるなら使ってしまおうという目論見の備忘録。

## Google Colaboratoryとは
１日12時間制限でgoogleが提供してるGPUとTPUを無料で使えてしまう素晴らしいサービス。
Jupyter notebookっぽい形式でPythonのコードが書ける。現状はPython3しか使えないらしい。
詳しくは公式FAQ読んで
>[公式FAQ](https://research.google.com/colaboratory/faq.html)

##　実行
### 1. Google Driveにファイルをアップロード
ゼロから作るディープラーニングを買うと、GithubのURLがついてくるので`git clone`して自分のPCに落とします。
deep-learning-from-scratchってフォルダをMy Driveにアップロードします。こんな感じ。
Google Colaboratory起動して直接`git clone`もできるけどローカルにも欲しかったので。
<img width="676" alt="マイドライブ_-_Google_ドライブ.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/306203/0bd8b888-04ab-9f8d-d641-5743dff06f57.jpeg">

### 2. Google Colaboratoryを起動して設定
Google Drive内で右クリック→アプリを追加→google colaboratoryで検索。Python3のノートブックが作れるようになるので作る。
<img width="727" alt="マイドライブ_-_Google_ドライブ.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/306203/903bd7d9-bf68-b1f9-c067-820aeb607e8f.jpeg">

こんな感じの画面が出てくる。
<img width="1382" alt="Untitled0_ipynb_-_Colaboratory.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/306203/d91aaefc-07ed-5ad9-8be2-074e15d16fa7.jpeg">

### 3. 実行環境を整える
まずはGoogle DriveをマウントしてGoogle Drive内のファイルを使えるようにする。

```python
from google.colab import drive
drive.mount('/content/drive')
```

URLと入力枠が表示される。URLをクリックするとGoogle Driveへのアクセスを許可するかどうかみたいなのを聞かれるので許可すると16進数のコードが出てくる。このコードを入力枠に入れるとマウントされる。

`!{command}`でLinuxコマンドが利用できる。しかし、`!cd`では作業ディレクトリは変更されないのがめんどう。
なのでosをimportしてカレントディレクトリ変更したけどもっといい方法がないのか。

```python
import os
os.getcwd()
#'/content'
os.chdir('/content/drive/My Drive/deep-learning-from-scratch')
os.getcwd()
#'/content/drive/My Drive/deep-learning-from-scratch'
```

### 4. ランタイムを変更
ランタイム→ランタイムのタイプの変更を行うと
<img width="516" alt="Untitled0_ipynb_-_Colaboratory.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/306203/923b4141-2408-228a-814a-7c14bd32ad20.jpeg">
こういう画面になるのでハードウェアアクセラレータをGPUに変更する。すでに変更してるけどCPUだとNone typeってなってる。

実際にGUIが動いてるのかを確認する。

```python
import tensorflow as tf
tf.test.gpu_device_name()

#'/device:GPU:0'
```

### 5. コードを動かす
two_layer_net.py関連を動かしてみたが無事動いた。早い！（%timeで測ろうかと思ったがめんどくさくなりました）これで勉強が捗る！

### 追記
numpyはGPUに対応していないので、pytorchのTensorなどを使ってコードは随時
変更しましょう。
JavaScriptで超簡素スロットゲーム

動画学習サイトを使用してですが、人生で初めてプログラムっぽいプログラムを書きました。
備忘録がてら記載。


◾️Demo
[スロットチャレンジ！](http://practice.back.jp/js/slot/)

◾️使用学習サイト
[JavaScript実践 〜スロットアプリの制作〜 - schoo](https://schoo.jp/class/1908?view=1)

かなり丁寧に解説されているので、分かりやすかったです。
各セクションの最後にある質疑応答も役に立ちました。
とりあえず初月無料のプレミアム会員になりました。


## ゲーム・処理の内容

2つのスロットの数字が揃ったら特典獲得。

- 2つのスロットの数字を９まで加算し、その後０に戻す。
- STOPボタンを押したら対応したスロットの数字を止める。
- 2つのスロットの数字が揃った場合、得点獲得。
- 次のゲームでは、数字の変わるスピードを早める。


```html:index.html

<head>
  <style>
    .slot {
      float: left;
      width: 150px;
      text-align: center;
      font-size: 40px;
    }
  </style>
</head>

<body>
  <h1>スロットチャレンジ！</h1>
  <p>得点:<span id="score">0</span></p>
  <div class="slot">
      <div id="slot0">0</div>
      <input type="button" value="STOP" id="stop0">
  </div>
  <div class="slot">
      <div id="slot1">0</div>
      <input type="button" value="STOP" id="stop1">
  </div>
</body>
```

```javascript:index.js
  // 即時関数で囲っておく（スコープを限定）
  (function(){
    var score = 0;
    var interval = 400;
    var timers = []; // スロット
    var results = []; // スロットを止めた時の数字
    var stopCount = 0; // スロットを何個止めたか判別に必要

    // イベントの登録（今回はクリックした時）
    // 左のスロットをクリックした時、タイマーを止める
    document.getElementById('stop0').onclick = function() {
      stopSlot(0); // 左のスロット
    }

    // 右のスロットをクリックした時、タイマーを止める
    document.getElementById('stop1').onclick = function() {
      stopSlot(1);
    }

    // スロットをスタートさせる
    startSlot();

    // 左右のスロットをスタートさせる処理の中身
    function startSlot() {

      // 初期化（空の状態に戻す）
      stopCount = 0; // スロットを何個止めたか判別に必要
      timers = []; // スロット
      results = []; // スロットを止めた時の数字

      // スロット開始
      runSlot(0);
      runSlot(1);
    }

    // スロットを回す処理の中身
    function runSlot(num) {

      // 全てのスロットの現在表示されているテキストを取得
      var slotValue = document.getElementById('slot' + num);

      // 9より上の数字になったら0へ戻る
      if(slotValue.textContent < 9) {
        slotValue.textContent ++;
      } else {
        slotValue.textContent = 0;
      }

      // スロットの数字をカウントさせる
      timers[num] = setTimeout(function() {

        // スロットの数字をカウントさせる処理
        runSlot(num);
      }, interval);
    }

    // スロットを止める処理の中身
    function stopSlot(num) {

      // スロットを止める
      clearTimeout(timers[num]);

      // スロットを止めた際の数字を取得
      results[num] = document.getElementById('slot' + num).textContent;

      // 何個めのスロットかを判別
      stopCount++;

      // 2個めのスロットを止めた場合に結果を表示する
      if (stopCount == 2) {
        checkResult();
      }
    }

    // 全てのスロットを止めた結果
    function checkResult() {

      // 2つの数字が同じであれば次へ、そうでなければGAMEOVER
      if (results[0] == results[1]) {
        alert('おめでとう！');

        score += 200; // 得点を足す
        interval *= 0.8;
        // 得点追加の処理
        getScore();
        // 次のゲームに進む
        startSlot();
      } else {
        gameover();
      }
    }

    // 得点追加時の処理
    function getScore() {
      var target = document.getElementById('score');
      target.textContent = score;
    }

    // 揃えられなかった時
    function gameover() {
      alert('ゲームオーバー…。');
    }

  })();
```

やっぱり「書いてみる」が１番の学習方法ですね。
ハングル データ 扱い方 一方法

今日、google patentで"deep learning"を検索した。

https://patents.google.com/

Asigneeの一覧にアルファベット以外に、漢字（日本、中国）、ハングルの名前があった。


エディタにコピペして、csvファイルとして保存して、Excelで読み込んだら、ハングルだけ文字化けした。

エディタで、Shiftjisで保存しようとすると、変換できない文字があるとして保存できなかった。

そこで、MS Wordにはりつけて、Shift JISで保存する際に、韓国語（MCA)を選択して保存した。

MS Wordの韓国語（MAC)の状態でハングルをMS Excelにコポペしたら、ハングルで保存できた。

忘れないようにメモメモ。
paizaでアセンブラ その7


# 概要

paizaでアセンブラ、やってみた。
クワインとやらをやってみる。

# 参考にしたページ

https://qiita.com/fujitanozomu/items/1108c16a4712c14c58db

# サンプルコード

python2です。

```
import subprocess
import os

def gcc():
    p_file = 'quine.S'
    test_p = """
.text
.global main
main:    
mov $1,%eax
mov $1,%edi
mov $m,%esi
mov $138,%edx
syscall
mov $60,%eax
dec %edi
syscall
m:.incbin "quine.S"
"""
    with open(p_file, 'w') as f:
        f.write(test_p)
    c_file = 'fizzbuzz.s'
    test_c = """
.text
.global main
main:    
mov $1,%eax
mov $1,%edi
mov $m,%esi
mov $138,%edx
syscall
mov $60,%eax
dec %edi
syscall
m:.incbin "quine.S"
"""
    with open(c_file, 'w') as f:
        f.write(test_c)
    os.system("gcc -no-pie %s" % c_file)
    os.system("uname -a")
    os.system("gcc --version")
    result = subprocess.Popen('./a.out', stdout = subprocess.PIPE).communicate()[0]
    for i, v in enumerate(result[ : -1].split('\n')):
        print v

if __name__ == '__main__':
  gcc()
  

```

# 実行結果

```
Linux 8e7123c5ab55 4.15.0-1025-aws #25-Ubuntu SMP Wed Oct 10 14:23:49 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
gcc (Ubuntu 7.3.0-27ubuntu1~18.04) 7.3.0
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.


.text
.global main
main:    
mov $1,%eax
mov $1,%edi
mov $m,%esi
mov $138,%edx
syscall
mov $60,%eax
dec %edi
syscall
m:.incbin "quine.S"
```

# 成果物


https://paiza.io/projects/2BVFsITnlS6FwIL00yhO5A


以上。
Carthage メモ

## よく使うコマンド
### バージョン確認

```bash
carthage version
```

### Carthage自身のアップデート
`brew update` && `brew upgrade carthage`

```bash
brew update
brew upgrade carthage
```

### ライブラリのインストール＆アップデート（iOS指定）

```bash
carthage update --platform iOS
```

### Xcodeのバージョンアップなどの際
Module compiled with Swift 3.1 cannot be imported in Swift 3.2 ... とかでたら。
Xcodeを再起動して治ることも。

```bash
carthage update --platform iOS --no-use-binaries
```

### プライベートリポジトリを使う時
`--use-ssh`を使う。

```bash
carthage update --use-ssh --platform iOS
```

### 1つだけ更新したい時

```bash
carthage update --platform iOS SwiftyUserDefaults
```
MySQL で知っておきたいInnoDBのクラスタインデックスとセカンダリインデックス

##本記事の対象
MySQLでクエリのパフォーマンスを気にし始め、
index回りについて調べ始めたがいまいちピンとこない人向けの記事になります。

テーブルのストレージエンジンはInnoDBを前提としています。

##クラスタインデックスとセカンダリインデックス
InnoDBにおいて、一口にインデックスといっても
1. クラスタインデックス
2. セカンダリインデックス
の2種類があります。  
  
MySQLやらInnoDBのインデックスの記事をググるで良い記事が色々と出てきますが、
上記について理解がないと割と内容にピンとこないことが多いんじゃないかなぁと思います。

##結論
InnoDBにおいて<b>「クラスタインデックス」</b>とは、ずばり<b>「主キー」</b>のことです。
それ以外のキー（ユニークインデックスなど）はすべて「<b>セカンダリインデックス」</b>です。

以下から「料理本」を例えて説明したいと思います。

##クラスタインデックス
クラスタインデックスは料理本でいう所の、「ページ番号」です。
料理本の内容は「ページ番号」によって整列されていますね。
同じ作品であれば、どの本でも「ページ番号」で整列された同じ内容です。

また、ページ番号が書かれたページ（紙）にレシピそのものが記載されてますね。（当たり前ですが）

これは言い換えるとクラスタインデックスでは、
<b>キー（ページ番号）</b>が示す<b>場所（ノード）</b>に、<b>データ(料理のレシピ)</b>そのものが格納されている、ということです。

##セカンダリインデックス
セカンダリインデックスは料理本でいう所の、「索引」です。
料理本では料理の名前で索引があり、「料理名」で整列されてますね。
料理名からページ番号を見つけることで目的の料理の作り方を知ることが出来ます。

これを言い換えると、
キー（料理名）</b>が示す<b>場所（ノード）</b>には、<b>主キー(ページ番号)</b>が格納されている、ということです。

もし索引から卵焼きのレシピを調べるとき、
1. セカンダリインデックス（索引）から卵焼きのレシピが載っているページ番号（主キー）を調べる
2. 1をもとに、クラスタインデックス（ページ番号）から卵焼きのレシピがのっているページ（データ）を得る

という工程を取ることになります。
つまり、セカンダリインデックスから検索を行うと検索処理を2回行うこととなります。
なので、InnoDBでは主キーでの検索のほうがパフォーマンスが良いです。

セカンダリインデックスは実質あるテーブルに対して、「セカンダリキー」と「主キー値」を持つテーブルのようなものです。
※索引でいえば「料理名」と「ページ番号」です。

##Covering Index について
クラスタインデックスとセカンダリインデックスについての前提があるとインデックス回りを調べる際に色々と捗りますが、例としてCovering Indexをみてみます。

Covering Indexをググってみると
>該当の問い合わせ（クエリ）をインデックスのみで解決できることを示す。


的な説明があっていまいちピンと来なかったりしますが、セカンダリインデックスについての前提があれば理解できます。

例えば、料理本から、「あ」で始まる料理の数を知りたいとします。
この場合セカンダリインデックス（索引）から「あ」で始まる料理を数えます。
次に、索引にあるページ番号をもとに、、、と思った処、索引を見るだけですでに目的が果たせていることにきがつきます。
つまり「クラスタインデックス」への検索が省略できました。

セカンダリインデックスで検索をすると本来2回の検索が必要となりますが、
Covering Indexが効いていると1回の検索で済むため、より高速です。

Covering Indexはクエリが「セカンダリインデックス」のみで解決できることを示しています。

また、セカンダリインデックスの知識があれば、
Covering Indexはクエリが「インデックスで定義されているカラム、もしくは主キーのカラム」のみ参照する場合に効く、という所部分も理解できるかと思います。
【JavaScript】filterとincludesで配列のデータを抽出


#２つの配列の要素を比較
JavaScriptで２つの配列を比較して、他方の配列に含まれる要素のみを抽出したい場面があり、
同じような内容の記事が見当たらなかったので書きました。
##おことわり
forを使った場合との比較を書いたりすると親切なんでしょうが
自分の備忘用なので超サラっと書いてます。あしからず。

##環境
node v11.6.0

##やりたいこと
２つの配列alphabet, targetがあって、

```JavaScript
var alphabet = [{id:1, name:'alpha'}, 
                {id:2, name:'beta'},
                {id:3, name:'gamma'}, 
                {id:4, name:'delta'}];
  
var target = [1, 4];
```
配列alphabetの中から、idの値がリストtargetの要素と一致するものだけを抽出したい。
（↓こんなアウトプットが欲しい。）

```JavaScript
[ { id: 1, name: 'alpha' }, { id: 4, name: 'delta' } ]
```
SQLならこんな感じ。

```SQL
SELECT * FROM alphabet WHERE id in (target);
```

##使うもの
filterと~~indexOf~~ includes。(※includesのほうが良いよとご指摘いただいたので修正)
さっそくコードを、

```JavaScript
console.log(
  alphabet.filter(x => target.includes(x.id));
)
```
結果

```JavaScript
[ { id: 1, name: 'alpha' }, { id: 4, name: 'delta' } ]
```
はい出来上がり！
iMacを外部SSD起動にして高速化する

# 最近iMacが重い
最近iMacが遅くなってきたな。古くなってきたからか？と思って変態的な疑似Fusion Drive環境から外部SSD環境にMacOSのお引越しを考えました。

## これまでの環境
iMac (21.5-inch, Late 2015)
Core i5
Mem 8GB
**1TB HHD**

モデルを利用してきました。
既にお察しのとおり、このご時世にHDDは遅いので、これまで自作Fusion Driveを使うことで、
外付けSSD 128GB + 内蔵HDD 1TBでFusion Driveを組んでいました、
実際にどう作るかはこういった記事が参考になるかと思います。
https://www.fusenstage.com/archives/20141019170858791.html

# 状態の確認
ディスクのWtite/Read速度はこんな感じ。とてもSSDを噛ませているとは思えない速度。
<img width="400" src="https://qiita-image-store.s3.amazonaws.com/0/8190/53681504-07ff-4e4b-86a7-1970491a721d.png">

そこで今回は1TBのSSDを購入し、USB3.0接続をした上で外部SSDにMacOSをインストールしました。

# SSDの接続とフォーマット
フォーマットのために、アプリケーション→ユーテリティ→ディスクユーティリティから初期化を行います。
ここで選択するフォーマットはMacOSを入れる際に上書きされるためなんでも良いはずですが、今回はMac OS拡張を選択します。
<img widch="600" src="https://qiita-image-store.s3.amazonaws.com/0/8190/b191eae1-b972-eeca-3827-3defbfffe642.png">

# MacOS Mojaveの準備
MacのAppStoreから、Mojaveのダウンロードを行います。ダウンロード完了後Mojaveのインストーラを起動しこれまで同様にMojaveをインストールする。
<img width="600" src="https://qiita-image-store.s3.amazonaws.com/0/8190/7406601f-c5bb-5e2a-41a1-9ffe55143683.png">

インストーラの起動
<img width="600" src="https://qiita-image-store.s3.amazonaws.com/0/8190/acd88944-ac5a-2589-1d7c-0faa591f85dd.png">

# スクリーンショットが撮れていないので、結果のみ
内蔵HDDによって低速化しているのでは？と思っていたiMacですが、全てをUSB3.0接続のSSDに変えることで、下記のような性能になりました。大体当初よりは3~4倍のR/W性能に見えます。
<img width="400" src="https://qiita-image-store.s3.amazonaws.com/0/8190/def04df3-5252-70b5-8d50-d975d2e8203e.png">

# おわりに
もともと盛ったMacを買えという話ですが、iMacが据え置きということもあり、外部接続SSDを使うことで体感を含めかなり高速に使うことができます。
また、USBは遅いイメージがありますが、USB3.0では5Gbps(理論上）の速度があるため、USB接続のDiskでも十分でした。
iMacを買い換える前にこういった方法も試してみると良いかと思います。
Node.js(cheerio) を使ってスクレイピング

## この記事の目的
[映画.com](https://eiga.com/now/all/rank/)さんより、公開中の映画のタイトルを20件取得していきます。

## 開発環境
- MacOS Mojave v10.14.2

## 使い方
cheerioの[公式ページ](https://github.com/cheeriojs/cheerio)によれば、下記3つの特徴があります。
>
❤ Familiar syntax: Cheerio implements a subset of core jQuery. Cheerio removes all the DOM inconsistencies and browser cruft from the jQuery library, revealing its truly gorgeous API.
>
ϟ Blazingly fast: Cheerio works with a very simple, consistent DOM model. As a result parsing, manipulating, and rendering are incredibly efficient. Preliminary end-to-end benchmarks suggest that cheerio is about 8x faster than JSDOM.
>
❁ Incredibly flexible: Cheerio wraps around @FB55's forgiving htmlparser2. Cheerio can parse nearly any HTML or XML document.

ようするに、
#####1. jQueryライクに記述可能
#####2. 動作が早い、例えばJSDOMという別のライブラリと比較すると8倍程度
#####3. ほぼ全てのHTML/XMLドキュメントをパース可能
ようです。
それでは、cheerioをインストールしてスクレイピングしていきます。

## セットアップ
##### cheerioという、スクレイピング用のライブラリ をインストールします。

```Bash
$ npm init -y
$ npm i request cheerio
```

## デモ
##### 下記コードを実行すると、取得した映画のタイトルを配列にして表示してくれます。

```JavaScript:getmovies.js
const request = require('request')
const cheerio = require('cheerio')
const url = 'https://eiga.com/now/all/rank/' // 映画.comランキングページ
const titles_arr = []

request(url, (e, response, body) => {
    if (e) {
        console.error(e)
    }
    try {
        const $ = cheerio.load(body)              //bodyの読み込み
        $('h3', '.m_unit' ).each((i, elem) => {   //'m_unit'クラス内のh3タグ内要素に対して処理実行
            titles_arr[i] = $(elem).text()        //配列にタイトルを挿入していく
        })
        console.log(titles_arr)

     } catch (e) {
         console.error(e)
     }
})
```


## 終わりに
以上で、欲しいテキストをスクレイピングできました。

## 参考記事


https://qiita.com/ledsun/items/0965a60f9bdff04f2fa0#cheerio

https://github.com/cheeriojs/cheerio
Flutterでビルドするときに、「FormatException: Bad UTF-8 encoding 0x83」のエラーが出続ける

エラー原因が全く分からなくて、まさに悪夢。
結論としては、どっかでビルドエラーになっているため。

今回確認した環境は

* Flutter 1.0.0
* VS Code 1.30.2
* Windows10 x64

今回、僕が遭遇したのは、Android側でビルドエラーになっていたため。
VS Codeを使用している場合、Android側のソースを編集しても、ビルドエラーが分からない。
androidフォルダをAndroidStudioでインポートして、ビルドエラーを解消し、flutter build apkを実行したところ、無事ビルドできた。

ちなみに「FormatException: Bad UTF-8 encoding 0x92 (at offset 0)」が出る場合は、もう一度ビルドすると解消するみたい。
PoAのプライベートチェーンネットワークに後からsignerノードを追加する方法(geth)

# 背景
- 現状サーバー2台、ノード2つだけでPoAのプライベートチェーンネットワークを構成している
- この状態だと1ノード死亡しただけでブロックの生成が止まってしまうので、もう1ノード追加したい
- ブロックを生成できる(signが可能な)ノードじゃないといけないので、単につないで同期するだけでは駄目
- geth@ v1.8.20-stableを使用

# 手順
https://ethereum.stackexchange.com/questions/45578/how-can-we-add-new-nodes-under-poa を参考に手順を以下にまとめる。

## 新しいノードの準備
- 既に動いている2つのノードをそれぞれnode1, node2、新しいノードをnode3と呼ぶことにする
- 新しく立てたサーバーにgethを入れる
- アカウントを作成する

```
$ geth --datadir node3/ account new
Your new account is locked with a password. Please give a password. Do not forget this password.
Passphrase:
Repeat passphrase:
Address: {(新しいEOAのアドレス)}
```
- このとき使ったパスワードをファイルに入れておく

```
$ echo 'hogehoge' > node3/password.txt
```
- 既に使っているgenesis.jsonをそのまま新しく立てたサーバーに持っていってinitする

```
$ geth --datadir node3/ init genesis.json
```

## node3の接続
- 各ノードの`static-nodes.json`にnode3のenodeを追加する(bootnode使ってる場合は当然不要)

```
[
  "enode://(node1のenode)",
  "enode://(node2のenode)",
  "enode://(node3のenode)"
]
```

- この状態でnode1とnode2を起動し直し、node3を起動するとブロックの同期はできるが、node3のログに

```
WARN [01-13|16:32:47.353] Block sealing failed err="unauthorized signer"
```
と出てnode3はブロック生成を許されていないことがわかる。

## 新しいsignerのpropose
- node1のコンソールにアタッチする

```
geth attach node1/geth.cpc
```
- コンソールで`clique.propose("新しく作ったnode3のEOAのアドレス", true)`とする。

```
> clique.propose("(新しく作ったnode3のEOAのアドレス, 0x始まり)", true)
null
```
- node2についても同様のコマンドを打つ。
- 51%以上(今回は2つ)のノードでproposeがされたため、node3の新しいアカウントがsignerに追加される。なお、即追加されるわけではなく、いくつかブロックの生成を待たないといけない(かも)。

```
> clique.getSigners()
["(node1のcoinbaseアドレス)", "(node2のcoinbaseアドレス」)", "(新しく作ったnode3のEOAのアドレス)"]
```
これで例えばnode1とnode3しか動いてなくてもブロックが生成されるようになる。
npm install時に「--save」オプションはいらない

> 正直なところもうこの記事はいらないかなと思ったけど他のところから参照されていたりするっぽいので残しておきます

# 結論

`npm 5.0.0` 以降からは `install` 時にデフォルトで `save` してくれるので `--save` や `-S` オプションを指定する必要はない。

## `--save` オプションとは？

パッケージのインストール時、`package.json` の `dependencies` に追加してくれる機能。

npm v5 以降はインストール時にデフォルトで `package.json` の `dependencies` に追加してくれるようになったので `--save` オプションは不要になった。

> npm install saves any specified packages into dependencies by default. 

## 参考

https://docs.npmjs.com/cli/install
https://blog.npmjs.org/post/161081169345/v500
Githubで２要素認証を設定したときの追加設定

# はじめに
先日、Githubのログインも２要素認証を設定してみました。
その後、しばらく自分の個人リポジトリを触ってなかったのですが、
ふとコマンドを実行するとエラーが発生してました。

```
$ git push origin master
Password for 'https://<<username>>@github.com': 
remote: Invalid username or password.
fatal: Authentication failed for 'https://<<username>>@github.com/<<username>>/<<repo-name>>/'
```
ということで、解決手段です。

# 参考URL
https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line/

# 手順
## 1. ブラウザでGithubにアクセス
まずは利用されているブラウザでGithubにログインしてください。

## 2. 設定メニューを選択
右上のプロフィール画像をクリックして、「Settings」をクリックします。

## ３． 開発メニューを選択
左側のメニューの下側にある「Developer settings」をクリックします。

## ４． 個人アクセストークンメニューを選択
左側のメニューの下側にある「Personal access tokens」をクリックします。

## ５． トーク作成ボタンをクリック
「Generate token」ボタンをクリックします。

## ６． トークン詳細の入力
画面上部に「Token Description」枠があるので、任意の文字を入力します。

## ７． チェックボックスをチェック
「repo」と書かれたところのチェックボックスにチェックします。

## ８． トークンの作成
「Generate Token」ボタンをクリックします。

## ９． トークンのコピー
表示されたトークンの右側にコピーマークが表示されるのでクリックします。

## １０． cloneもしくはpushの実行
git cloneもしくは、git pushを実行したときにパスワードを聞かれます。
そのときに、先程コピーしたトークンをペイストしてください。

# さいごに
調べればすぐに見つかったのですが、自分がどっかでミスしてるのでは？と思い、色々環境を見てたため時間がすごくかかってしまいました。
問題が発生したときはまずは検索が一番ですね。
ゼロからのkaggleチャレンジ #3 - Digit Recognizer(データ前処理)

# はじめに
[前回はDigit Recognitionに挑戦した全容を紹介](https://qiita.com/landmark-b/items/f245f8c29ca3e8620314)しましたので
引き続き今回からは具体的にデータの前処理についてソースコードとともに紹介していきたいと思います。
[全体のソースコードはkaggleで公開してます](https://www.kaggle.com/yuta0001/keras-cnn-in-japanese-score-0-99442)のでそちらも参照ください。

# データの前処理
データの前処理としては以下を実施しています。
- 画像データの正規化
- one-hot Encoding
- データの増強（Data Augmentation)

### 画像データの正規化


```python:python3
random_seed = 1
X_train_split, X_test_split, y_train_split, y_test_split = train_test_split(X_train, y_train, random_state=random_seed)

# 正規化
X_train_split = X_train_split/255
X_test_split = X_test_split/255
X_test = X_test/255
X_train_all = X_train/255

```

###one-hot Encoding
機械学習では２つの数字が近い場合、例えば”２と３”や”６と７”、は”２と７”のように離れた数字よりも
似ていると判断します。
ただ、今回画像から分類する数字(０〜９)は数が近いからといって似ているわけではないので
One-hot Encodingを行いこれを解決します。  

```python:Python3
y_train_split = to_categorical(y_train_split, num_classes)
y_test_split = to_categorical(y_test_split, num_classes)

# 出力例
to_categorical(y_train[0:3])
# array([[0., 1., 0., 0., 0., 0., 0., 0., 0., 0.],
#        [1., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
#        [0., 1., 0., 0., 0., 0., 0., 0., 0., 0.]], dtype=float32)
```

###データの増強
機械学習ではデータの量と質が性能に直接影響しますので、
人工的に加工することでオリジナルデータを増強(Data Augmentation)し性能向上を図ります。
データの増強とは元の画像データに回転、反転、ズームなど加工を行った画像を追加し、変化に強い学習を行うための学習データを増やす処理になります。

[Kerasで用意されいてるData AugmentationのクラスImageDataGenerator](https://keras.io/ja/preprocessing/image/)を使用し,
オリジナル画像を加工した画像を追加します。
行った加工は画像の回転、ズーム、水平シフト、垂直シフトになります。

```python3:Python3
from keras.preprocessing.image import ImageDataGenerator
datagen_split = ImageDataGenerator(
    featurewise_center=False,
    featurewise_std_normalization=False,
    rotation_range=10, # randomly rotate images in the range (degrees, 0 to 180)
    zoom_range=0.1, # ランダムにズームする範囲
    width_shift_range=0.1, # ランダムに水平シフトする範囲
    height_shift_range=0.1, # ランダムに垂直シフトする範囲
    )
datagen_split.fit(X_train_split)
```

# おわりに
次回はMNISTデータ分類のために実装したCNNモデルについて紹介したいと思います。

# 参考資料
・Keras Documentation 画像の前処理、https://keras.io/ja/preprocessing/image/
・Hands-on Machine Learning with Scikit-Learn
scalaでxmlをjsonへ変換する

# 問題
xmlでとってきたRSSをjsonに変換して扱いを楽にしたい。

# 解決
scalaライブラリjson4sを使うと、かなり簡単にxmlをJson形式へ変換できます。

準備は、build.sbtへjson4s-xmlを追加するだけ。

```scala
libraryDependencies += "org.json4s" %% "json4s-xml" % "3.6.3"
```

xmlをjsonへ変換します。
正確には、scalaのxmlを扱う標準クラスであるscala.xml.Elem型からJValueへの変換をします。

```scala:main.scala
package json

import org.json4s.JValue
import org.json4s.Xml.toJson

import scala.xml.Elem

object ScalaXml extends App {
  val xml: Elem =
    <body>
      <h1>title</h1>
      <div>
        <p>content</p>
      </div>
    </body>

  val json: JValue = toJson(xml)

  println(json) // => JObject(List((body,JObject(List((h1,JString(title)), (div,JObject(List((p,JString(content))))))))))
}
```

JValue形式をjsonの文字列にしたり、値の取り出しなどしたい場合は、Json4sをご参照ください。
[json4s/json4s: A single AST to be used by other scala json libraries](https://github.com/json4s/json4s)

# 余談
今回この問題に取り組んで、初めてscalaのｘｍｌリテラルについて知りました。JSXと同じようにコード内にhtmlを直書きできます。
intellijのReformat Codeできれいにインデントしてくれて見やすく便利ですね。
下から（上から）nビットを立てたビットマスクを作る

下から（LSBから）nビットが1のビットマスクを作りたいとき。もしくは上から（MSBから）について同様のものがほしい場合について。
ビット演算としては基本的だけど、定期的に自信がなくなってしまうのでまとめた。

## 下からnビットを立てたビットマスク

全部のビットが立ったものを左シフトしてからビット反転すればよい。
定数のロード、シフト、NOTで合計3命令。

```c
uint32_t f(int n)
{
  return ~(0xffffffffu << n);
}
```

x86かつHaswell世代以降のCPUに特化していいのであれば、BMI2に[bzhi](https://www.felixcloutier.com/x86/bzhi)という命令がある。
演算が1命令で済むようになる。

```c
#include <immintrin.h>

uint32_t g(int n)
{
  return _bzhi_u32(0xffffffffu, n);
}
```

## 上からnビットを立てたビットマスク

ほぼ同様のやり方ができる。全部のビットが立ったものを右シフトしてからビット反転すればよい。

```c
uint32_t h(int n)
{
  return ~(0xffffffffu >> n);
}
```

下からnビットには特化した命令としてbzhiがあったが、bzloというものは存在しない様子。

## アセンブリの確認
出力の確認はCompiler Explorerを使った。とても便利。
https://godbolt.org/z/mtStCk

```nasm
f(int):                                  # @f(int)
        mov     eax, -1
        shlx    eax, eax, edi
        not     eax
        ret
g(int):                                  # @g(int)
        mov     eax, -1
        bzhi    eax, eax, edi
        ret
h(int):                                  # @h(int)
        mov     eax, -1
        shrx    eax, eax, edi
        not     eax
        ret
```
submitされない？何故なのか。備忘録

##やりたい事
ラジオボタンを配置。
選択されていれば、submitし、選択されていなければ、アラートを表示し、submitさせない。

##事象

![ezgif.com-video-to-gif (1).gif](https://qiita-image-store.s3.amazonaws.com/0/267738/95189c9b-f29e-34f9-ab46-8776db56ecfc.gif)

##対象コード

```html:sample.html
<form action="hoge/index" method="post" id="register-form">
    <div>
        <p>
            <input type="radio" name="plan_type" value="リンゴ" id="select-fruits-apple"><span>リンゴ</span>
            <input type="radio" name="plan_type" value="バナナ" id="select-fruits-banana"><span>バナナ</span>
        </p>
    </div>

    <div>
        <button type="button" id="submit">送信</button>
    </div>
</form>

<script type="text/javascript">
    $(function() {
        $('#submit').on('click', function() {
            if ($('#select-fruits-apple').prop('checked') == false
                && $('#select-fruits-banana').prop('checked') == false) {
                alert('選択して下さい');
                return false;
            } else {
                $('#register-form').submit();
            }
        });
    });
</script>
```


##原因

**button**タグの**id**属性が`submit`となっている事が原因でした。

<img width="453" alt="スクリーンショット_2019-01-13_15_59_02.png" src="https://qiita-image-store.s3.amazonaws.com/0/267738/8bdf6cdd-f80c-a289-13ba-c774896c58db.png">

※**何がどうなってどうだからid属性にsubmitという命名をしてはいけないのか、という内部的ロジックについては不明。**

##気づき

- **button**タグの**id**属性の命名がそもそも悪い
→どういうボタンなのか、どういう挙動をするのか、という情報を名前に含めるべきである。

- **既存コード**だとしても、本当に良いのか、という疑いを持つ事。必要であればリファクタリングをする、あるいはリファクタリング対象として挙げておく。

##まとめ

「**思わぬ罠**」に掛かってしまった訳ですが、気づき・学びがあったので**良い経験**となったのかなと。
命名に関しては非常に大切な部分ですので、既存コードといえど**疑い**の視点を持って行きたいと思います。

上記でも記載しましたが、**内部的に何がどうなってどうだからbuttonタグのidにsubmitという命名にしてはいけないのか**、については不明な為、分かる方がいらっしゃいましたら、ぜひ教えて頂きたいので、コメントの方よろしくお願い致します。

##参考
[jQueryでsubmitしたり無効にする方法](https://www.flatflag.nir87.com/submit-1356)

##おまけ

Twitterやってます！外部のエンジニアの方ともどんどん繋がりたいと考えていますので、是非フォローして頂ければと思います！[@Tatsuo96](https://twitter.com/Tatsuo96)
ブログ始めました！
https://note.mu/tatsuo_iriyama