OmniAICreator/Qiita-1.07M huggingface dataset:
グラフ描画のためのデータベース操作

#グラフ描画のためのデータベース操作
##どうやってデータを間引くか
###剰余系を使って間引く

データベースに記録したデータをグラフにしたい場合、あまりにもデータが多いので間引く必要がある。
そもそも、データベースはスキップという操作があまり得意ではない。
それでもテーブルのIDを単純に剰余系で間引くSQLは、こんな感じ。

```
SELECT id,`CreateAt`,`機器ID`,`温度` 
      FROM data_table 
      WHERE MOD(id,100)=0
```

これだと、複数の機器がデータベースに記録されていた時に、データの最初と最後が欠けてしまう機器が出てくる。
そこで機器ごとの連続した番号が必要と思い、データベースに記録する時に連番を振っておくseq列を追加。

```
SELECT id,`CreateAt`,`機器ID`,`温度`
      FROM data_table 
      WHERE `機器ID`='XXXX-XXXX' AND MOD(seq,100)=0
```

一応もれなく計算出来るが、機器毎にSQLを発行して読み出すので、機種が増える毎に計算時間が遅くなって行く。

###データベースの得意なのは集計

ある時、別件で1時間毎にデータを集計する機能を追加して気づいた。
スキップするのではなく、1時間毎の平均を取るSQLを書いてみた。

```
SELECT DATE_FORMAT(`CreateAt`, '%Y-%m-%d %H:00:00') AS hour,
      `機種ID`,AVG(`温度`) AS tempr 
      FROM data_table 
      GROUP BY `機種ID`,hour 
      HAVING tempr 
```

別の書き方で、こう書ける事も分かった。

```
SELECT FROM_UNIXTIME(TRUNCATE(UNIX_TIMESTAMP(`CreateAt`)/3600,0)*3600) as sec,
      `機器ID`,AVG(`温度`) AS tempr
      FROM data_table 
      GROUP BY `機種ID`,sec 
      HAVING tempr
```

この書き方だと任意の秒数で集計ができるのに気づいた。
グラフの横軸は時間なので、横軸に表示する範囲の日時を描画点数で割って、あらかじめ描画点の間隔の秒数を求めておく。

```
$start = strtotime(最初のdatetime); 
$end   = strtotime(最後のdatetime); 
$diff  = $end - $start;
$secPerPoint = intval($diff/描画点数);
```

```
SELECT FROM_UNIXTIME(TRUNCATE(UNIX_TIMESTAMP(`CreateAt`)/{$secPerPoint},0)*{$secPerPoint}) as sec,
      `機器ID`,AVG(`温度`) AS tempr
      FROM data_table
      GROUP BY `機種ID`,sec 
      HAVING tempr
```

間引くよりも平均を取る。そうすればGROUP BYが使えるので、一度のSQLで機器単位の平均を求めることができる。プログラムも単純になる。
肝心のスピードだが、多少早くなったが、グラフに送るデータの量が多いところがボトルネックになってた。例えばX軸の時間とかは、全機種共通なので１つだけ送るとかデータ転送量減らす予定。
goss を使ったサーバ構築のテスト

<!-- goss を使ったサーバ構築のテスト -->

# はじめに

以前 [InSpec でデプロイを自動テスト化する] という記事で InSpec というテストフレームワークの紹介をしましたが、最近 goss という Go 言語製のテストフレームワークを使い始めたのでそのご紹介です。

# goss とは

[goss] は YAML でテストケースを記述し、その内容に従ってテストを実行できるフレームワークです。

## 特徴

- シングルバイナリなのでライブラリのインストールなどが不要
- 記述が YAML なので覚えることが少ない
- 速い

## goss でできるテストの例

goss を使えば下記のようなことがテストできるようになります。

- ファイルが存在するか
- ファイル属性は正しいか
- プロセスやサービスは起動しているか
- パッケージはインストールされているか
- HTTP レスポンスのヘッダやボディは正しいか

# インストール

開発用途の環境に入れるのであれば下記でインストールできます。

```shell
$ curl -fsSL https://goss.rocks/install | sh
```

本番用途の環境であればこのインストール方法は推奨されてないので、代わりに下記のようにインストールします。

```shell
$ curl -L https://github.com/aelsabbahy/goss/releases/download/v0.3.9/goss-linux-amd64 -o /usr/local/bin/goss
$ chmod +x /usr/local/bin/goss
```

# 使い方

試しに Apache が正しく動いているかどうかをテストしてみたいと思います。 `goss.yaml` という名前で下記のようにファイルを作成します。

## 動作環境

- CentOS 7
- Apache 2.4.6

```yaml:goss.yaml
package:
  httpd:
    title: httpd 2.4.6 がインストールされていること
    installed: true
    versions:
      - 2.4.6

file:
  /etc/httpd/conf/httpd.conf:
    title: 設定ファイルが存在すること
    exists: true

service:
  httpd:
    title: httpd がサービスに登録されていること
    enabled: true
    running: true

process:
  httpd:
    title: httpd が起動していること
    running: true

port:
  tcp:80:
    title: 80 ポートをリッスンしていること
    listening: true

http:
  http://localhost:
    title: 疎通できること
    status: 200
```

テストをするには `goss.yaml` を保存した場所で下記のコマンドを実行します。


```shell
$ goss validate
```

もしテストに失敗すれば下記のようなエラーメッセージが出力されます。

```shell
$ goss validate
F..F..F.

Failures/Skipped:

Title: 80 ポートをリッスンしていること
Port: tcp:80: listening:
Expected
    <bool>: false
to equal
    <bool>: true

Title: 疎通できること
HTTP: http://localhost: status:
Expected
    <int>: 403
to equal
    <int>: 200

Title: httpd がサービスに登録されていること
Service: httpd: enabled:
Expected
    <bool>: false
to equal
    <bool>: true

Total Duration: 0.045s
Count: 8, Failed: 3, Skipped: 0
```

テストレポートは JSON や JUnit 形式で出力することもできます。レポート形式を指定するには `-f` を使用します。

```shell
$ goss validate -f junit
```

# goss を使ったヘルスチェック

Serverspec や InSpec にはない機能として、goss をサーバとして起動しておき、テストのレポートを HTTP で受け取る機能が便利でした。

下記コマンドを実行すると goss サーバがポート 8080 で起動します。

```shell
$ goss serve -f junit
```

curl やブラウザから `http://<host>:8080/healthz` にアクセスするとテストレポートを取得できます。

```shell
$ curl http://localhost:8080/healthz
```

テストレポートを JUnit 形式で取得できるようにしておき、これを CI で定期実行させると単体テストを CI で実行する感覚でヘルスチェックが行えるようになります。

# 注意点

Serverspec や InSpec はリモートサーバを対象にテストを実行できますが goss にはリモート実行の機能は実装されていません。これは goss の設計をシンプルに保つことと簡単なシェルを書けば goss ファイルの転送と実行はできるからという作者の意向によるものです。（参考：[ssh and exec support]）

ちなみにコンテナを対象に goss を実行する場合は [dgoss] という goss ラッパが使用できますが、これは単にコンテナに goss ファイルを送るだけのシンプルなシェルスクリプトとして実装されています。

リモート実行をしたい場合は dgoss と同様のスクリプトを書いて運用するのが良いと思います。ただ個人的には HTTP でテスト結果を受け取れる機能が使いやすいので、テスト対象のサーバであらかじめ goss サーバを起動させて使用しています。

# さいごに

Serverspec や InSpec と比べて実行速度が圧倒的に速いことと YAML でテストを記述できるという点が goss の魅力ではないかと思いますので是非お試しください。

[InSpec でデプロイを自動テスト化する]: https://qiita.com/navitime_tech/items/2ad207e7fdff5b3ed727
[goss]: https://github.com/aelsabbahy/goss
[dgoss]: https://github.com/aelsabbahy/goss/tree/master/extras/dgoss
[ssh and exec support]: https://github.com/aelsabbahy/goss/issues/6
【Python】　1行でbool値反転　

#####python初学者の自分用リマインドメモ

ご指摘を受けて編集
returnするまでもなく変数にnotで反転して格納できるとのこと。
つまり下記でOKでした。。。

```python:python.py
li = []
result = bool(li)


turned_result = not bool(li)


print('result: ',result)
print('turned_result: ',turned_result)
# result: False
# turned_result: True 

```

<br/>
####以前のもの
[notでreturn値を返すと反転できる！](https://scrapbox.io/amanatsu-knit-note/【Python】return時にbool値をnotで反転する)とのことでlambdaの即時実行で応用

```python:python.py
li = []
result = bool(li)


turned_result = (lambda x: not bool(x))(li)


print('result: ',result)
print('turned_result: ',turned_result)
# result: False
# turned_result: True 

```

<br/>
経験１年未満の初心者です。
もっといい方法や可読性の可否等、諸先輩のご意見伺えたらありがたいです。
scalikeJDBC One-to-X APIを使いこなす（1:N:N編）

[scalikeJDBC One-to-X APIを使いこなす（基本編）](https://qiita.com/natsumisawa/items/c644fdb4043d63a6629d)の続編です。
今回は1:N:Nのテーブルの扱い方についてです。

[One-to-X API Document]((http://scalikejdbc.org/documentation/one-to-x.html)) をみるとtoManiesで1:N:Nの取得ができそうですが、そこには落とし穴があり・・・😱
3つのテーブルが連なっている形の1:N:Nの場合はgroupByをしないと意図しない形でデータを扱ってしまう可能性があり危険です。

まずシチュエーションの確認からしたいと思います。

![iOS の画像.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137322/d341a783-0036-299b-ceb4-1af3657cab5e.jpeg)

こういう関係の3つのテーブルがあったとします。

これを、以下のように表示したいとします。

![iOS の画像 (1).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137322/5b194e52-c69d-3931-cbb7-3c39345008b2.jpeg)

企業によっては、事業部とユーザーの登録をしていないかもしれないので、こういったブランクの表示二なるパターンもあります。

![iOS の画像 (2).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137322/e32360e3-a9c2-f287-879a-30ffcbe57a8a.jpeg)

このとき、DBから取得した値は👇のように、
企業に複数の事業部がひもづいていて、事業部に対して複数のユーザーが紐づいて欲しいですね。

![iOS の画像 (2).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137322/e463b9c6-9d78-4094-8cd5-a0d29df8da76.jpeg)

これをtoManiesで書いてみます🎉

```scala
withSQL[Corporates] {
  select
    .from(Corporates.as(corporatesTable))
    .leftJoin(Departments.as(departmentsTable))
    .on(corporatesTable.corporateId, departmentsTable.corporateId)
    .leftJoin(Users.as(usersTable))
    .on(departmentsTable.departmentId, usersTable.departmentId)
}.one(Corporates(corporatesTable))
  .toManies(
    rs => rs.longOpt(departmentsTable.resultName.corporateId).map(_ => Departments(departmentsTable)(rs)),
    rs => rs.longOpt(usersTable.resultName.departmentId).map(_ => Users(usersTable)(rs)),
  )
  .map((corporate, departments, users) => (corporate, departments, users))
  .list()
  .apply()
```

[前回の記事](https://qiita.com/drafts/c644fdb4043d63a6629d) を参考に書くと、こういう感じになります。
ここで、この行に注目してください、

```scala
.map((corporate, departments, users) => (corporate, departments, users))
```

怪しさMAXですね。
これは図で表すと、こういう形で取得されています。

![iOS の画像 (3).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137322/d4e4905e-2b86-d57d-3ee5-44a2b58f32a8.jpeg)

この時点では、ある企業のユーザーは、どの事業部に紐づているのかを表せていません・・・😱
なので、ユーザーを事業部IDでグルーピングしてあげる必要があります。
もしそれを考慮せずに👇このようにしてしまうと、ある企業のすべての事業部に同じユーザーが所属しているような表示になってしまいます。
グルーピングを忘れるだけで、大惨事を起こしかねません。

```scala
.map((corporate, departments, users) => 
CorporatesModel(corporate.name, departments.map(department => DepartmensModel(department.name, users.map(user => UsersModel(user.name)))))
```

グルーピングをするためには、このように書くのが良さそうです。

```scala
  ...
  .map((corporate, departments, users) =>
     val groupedUsers: Map[Long, Seq[Users]] = users.groupBy(user => user.departmentId)
     CorporatesModel(corporate.name, departments.map(department => DepartmensModel(department.name), groupedUsers(departments.departmentId).map(user => UsersModel(user.name)))  
  )
 ...
```

groupByを使ってusersをMAP型にし、departmentIdで束ねてある形にします。
これで、ある事業部にユーザーが紐づいている、という正しい形にマッピングすることができます👏
そして、正しいタイミングで事業部IDを元にユーザーのリストを取得すれば欲しいモデルの形に変換することができました。

1:NであればscalikeJDBC内で対応でき流のでグルーピングの考慮は不要ですが、
1:N:N...だと考慮が必要であり、このように実装するのがベストだと思っています。
（※もしscalikeDJBCのコード内で同じことが表現できるのであれば知りたいです・・・）
Node.jsとDynamoDBで日時データの処理

#DynamoDBに日時データを持たせる2つの方法

1. データ型を`String`にして`2016-02-15`や`2015-12-21T17:42:34Z`のように文字列で持たせる。
2. データ型を`Number`にして`1579740176030`のように数値で持たせる。

2.項のNumber型の実用例としては、エポック時間 (1970 年 1 月 1 日の 00:00:00 UTC 以降の秒数) を利用することができる。([UNIXTIMEの詳細](https://ja.wikipedia.org/wiki/UNIX%E6%99%82%E9%96%93))

#Node.jsでエポック時間を扱う
##現在の日時をDateオブジェクトで取得する
```javascript
const date = new Date();
console.log(date);   // 2020-01-23T01:09:41.444Z
console.log(typeof date);    // 'object'
```

##現在の日時をエポック時間で取得する
```javascript
const date = Date.now();
console.log(date);   // 1579740176030
console.log(typeof date);    // 'number'
```

##DynamoDBから取得したエポック時間をDateオブジェクトへ変換する
```javascript
const unixtime = 1579740176030;  // DynamoDBから取得したエポック時間と想定
const date = new Date(unixtime);
console.log(date);   // 2020-01-23T01:09:41.444Z
console.log(typeof date);    // 'object'
```
フォルダごとに分かれている画像を一箇所に集める

最近業務で画像のデータを使って〜する場面があったのですが、サーバー上にある画像がフォルダごとに分かれてしまっていたり、階層もばらばらだったりと不便だったので、ちょっとした効率化ツールを作ってみました。

使っているのはGo言語です。

# ソースコード

```Go
package main

import (
	"image"
	"image/jpeg"
	"image/png"
	"log"
	"os"
	"path/filepath"
)

const imgQt int = 60

func main() {

	// 実行ファイル直下のパスを取得
	path, _ := os.Getwd()
	dataPath := filepath.Join(path, "data")
	dataAllPath := filepath.Join(dataPath, "*")

	list, _ := filepath.Glob(dataAllPath)
	var textList []string

	// 画像を１枚づつ読み込む
	for _, item := range list {

		textList = append(textList, readItem(item)...)

	}

	for _, text := range textList {

		exc(text)

	}

}

func exc(text string)  {
	path, _ := os.Getwd()
	outputPath := filepath.Join(path, "result")

	println(text)
	// 画像を読み込む
	img := input(text)

	if img == nil {
		return
	}

	out := filepath.Join(outputPath, filepath.Base(text))

	output(img, out, "jpg")
}

func readItem(item string) []string {

	fInfo, _ := os.Stat(item)
	var text []string

	if fInfo.IsDir() {
		itemList := filepath.Join(item, "*")
		list, _ := filepath.Glob(itemList)
		for _, l := range list {
			// 再帰処理
			text = append(text, readItem(l)...)
		}
	} else {
		text = append(text, item)
	}

	return text
}

// 画像を読み込む処理
func input (filePath string) image.Image {

	// 画像を読み込む
	file, err := os.Open(filePath)

	if err != nil {
		println(err)
		return nil
	}

	// 変換
	img, _, err := image.Decode(file)

	return img
}

func output (outputImage image.Image, filePath string, format string) {

	dst, err := os.Create(filePath)

	if err != nil {
		log.Fatal(err)
	}

	switch format {
	case "png":
		// PNGの場合
		err = png.Encode(dst, outputImage)
		if err != nil {
			log.Fatal(err)
		}
		break
	case "jpg":
		// JPGの場合
		qt := jpeg.Options{
			Quality:imgQt,
		}
		err = jpeg.Encode(dst, outputImage, &qt)
		if err != nil {
			log.Fatal(err)
		}
		break
	case "gif":
		// GIFの場合
		log.Println("can't output gif")
		break
	default:
		// 標準で対応していないフォーマットの場合
		println("no file")
		break
	}
}
```

実行ファイルと同じ階層にdataフォルダ、resultフォルダを作っています。
dataフォルダ直下にはフォルダ分かれ、階層分かれした画像データが入っているフォルダを丸々入れてもらえれば、resultフォルダに画像が出力されると思います。

こういうちょっとしたツールを作りやすいのがGo言語の良いところですね。
Neo4jでスタートノードからnホップのノードを求めたい時


# はじめに

スタートノードから$n$ホップのノードをもとめたいとします．

つまり，グラフ$G= (V, E)$において，スタートノード$s$から
移動距離が$n$以下のノードをダイクストラっぽく求めたいときです．

# 対処法

[Neo4j 2.9. Patterns](https://neo4j.com/docs/cypher-manual/current/syntax/patterns/)に乗っていました．

```
MATCH (me)-[:KNOWS*1..2]-(remote_friend)
WHERE me.name = 'Filipa'
RETURN remote_friend.name
```

のようにすればよいです．

上記のコマンドは，ノードme(ただしnameがFilipa)から最低$1$以上$2$以下の距離のホップ数のノードを取得する

というコマンドです．

```
[:Relation3..]
```
上記は$3$以上

```
[:Relation*..5]
```
上記は$5$以下のように，`*`などで指定します．
RDSとIAMでパスワードレス認証（Python）

MySQLのパスワードベタ書きしないでよくなります
{}内は適宜置き換えてね

# 1. ユーザ作成

```bash
CREATE USER '{MySQLユーザ名}'@'%' IDENTIFIED WITH AWSAuthenticationPlugin as 'RDS'; # ユーザ作成
GRANT ALL PRIVILEGES ON {MySQLDB名}.* TO '{MySQLユーザ名}'@'%' REQUIRE SSL; # 権限
```

# 2. IAMポリシー

こんな感じでポリシーを作る

jsonで直接アタッチするならこんな感じ

```json
{
    "Effect": "Allow",
    "Action": "rds-db:connect",
    "Resource": "arn:aws:rds-db:{AWS::Region}:{AWS::AccountId}:dbuser:cluster-{リソースID}/{MySQLユーザ名}",
}
```

CloudFormationならこんな感じ

```yaml
iamRole:
    - Effect: Allow
        Action:
        - "rds-db:connect"
        Resource:
        - 'Fn::Join':
            - ':'
            - - 'arn:aws:rds-db'
                - Ref: 'AWS::Region'
                - Ref: 'AWS::AccountId'
                - 'dbuser:cluster-{リソースID}/{MySQLユーザ名}'
```

# 3. 一時パスワードで接続！

こんな感じでトークン（一時パスワード）を発行する

```python
client = boto3.client("rds")

# トークン取得
token = client.generate_db_auth_token(
    DBHostname=RDS_HOST,
    Port=RDS_PORT,
    DBUsername=RDS_USER_NAME
)

db_connection = mysql.connector.connect(
    host=RDS_HOST,
    port=RDS_PORT,
    database=RDS_DB_NAME,
    user=RDS_USER_NAME,
    passwd=token
)
```


たったこんだけ
かんたんにゃ〜〜
[メモ]openapi-generatorの参考サイト

OpenAPI GeneratorでRESTful APIの定義書から色々自動生成する
https://ky-yk-d.hatenablog.com/entry/2019/01/13/234108

github openapi-generator-cli
https://github.com/OpenAPITools/openapi-generator-cli

OpenAPI generatorを試してみる
https://qiita.com/amuyikam/items/e8a45daae59c68be0fc8

OpenAPIGeneratorを使って必要なファイルを自動生成する方法
https://gist.github.com/kino-puehddby/dcce951f1bb0443a920a1d5562402b9f
【ふくだ学習録】SQLアンチパターン part1【15日目】

# ふくだ学習録とは？
ふくだが学習したことの備忘録。
目に見える形で残すことによってやる気を出す個人的な作戦です。
他人に見せるように書いているわけではないので、すごく読みにくいです。

### 読了した本
[データベースエンジニア養成読本 [DBを自由自在に活用するための知識とノウハウ満載!]](https://www.amazon.co.jp/dp/4774158062/ref=cm_sw_r_tw_dp_U_x_FPphEbQFPPQRM )
[ゼロから作るDeepLearning](https://www.amazon.co.jp/dp/4873117585/ref=cm_sw_r_tw_dp_U_x_y3UiEbF3P6EG7)
[PHPフレームワーク CakePHP 3入門](https://www.amazon.co.jp/dp/4798048577/ref=cm_sw_r_tw_dp_U_x_.YIjEbS1K4JY2)

### 今読んでいる本
[SQLアンチパターン](https://www.amazon.co.jp/dp/4873115892/ref=cm_sw_r_tw_dp_U_x_XlokEbJQK2N7P )

# SQLアンチパターンを読んで

### 「愚者は経験に学び￥、賢者は歴史に学ぶ」は造語説
本当は「愚者は自分が痛い目を見ることでしか学ばず、賢者は他者の失敗経験からも学ぶ」らしい。
賢者も歴史から学ぶだけじゃなくて自分で行動してる！
ガンガン失敗していこ！

### EAVとは？
EAV(エンティティ・アトリビュート・バリュー）。端的に言うと、RDB上でKVSをやるみたいなこと。
データ型の制約がないため、どんなデータでも入ってしまうように設計されているため、「データ整合性が確保できない」「バリデーションがかけられない」「SQLが冗長化する（属性をフェッチしてデータ取得しなければならないため）」などリレーショナルデータベースの特性を活かせなくなってしまう。
そのためRDBにおいてのアンチパターンとして認識されている。

下記記事がわかりやすくまとめてくれていた。（と言っても書籍にも十分わかりやすくまとめてくれている。）
[SQLアンチパターン勉強会　第五回：EAV(エンティティ・アトリビュート・バリュー)](https://qiita.com/skyc_lin/items/37365a36416d0dc42431)
[ある日 Entity Attribute Value に出会った](https://medium.com/@HKDnet/%E3%81%82%E3%82%8B%E6%97%A5-entity-attribute-value-%E3%81%AB%E5%87%BA%E4%BC%9A%E3%81%A3%E3%81%9F-baef11414840)


# 今日の一言
前書きとか読んでたら本章ほぼ読めなかった！！
明日からの勉強楽しみ！ベローチェの黒糖カフェオレ癖になる！！
【Python】Pandasで縦にCSVを書き込むメモ

結論

```python
import pandas as pd

n0 = ["a", "b", "c"]
n1 = ["aa", "bb", "cc", "dd", "ee", "ff", "gg"]
n2 = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]

nn = [n0, n1, n2]
print(nn)

df = pd.DataFrame(nn)
df = df.T

print(df)

savefile = "testcsv.csv"
df.to_csv(savefile, encoding="utf_8_sig")
```
[卒論・修論を守れ！]Cloud LaTeXとGitの連携[まだ間に合う！]

2020年1月23日改稿

Cloud LaTeX 便利ですよね。テキストエディタにこだわりがなく、論文を書くPCは気分で決めたい僕はとても重宝しています。決してtexの環境を整えるのが面倒くさいというわけではないです。

しかし、Cloud LaTeXの恐ろしいところは、一度消してしまったファイルはすぐには復元できないことです。~~俺みたいな卒論のtexファイル消して泣いたアホ野郎、他に、いますかっていねーか、はは~~（運営の方に連絡すれば復旧してもらえるらしいですが）
また、ファイルごとの更新履歴は残りますが、差分が見れないのは厳しいところです。

そこで、Cloud LaTeX標準のDropbox連携機能を応用し、Gitを導入することでバージョン管理ができるようにします。

#大事なこと
データはクラウドに保存されるため、PCが水没した！データ復旧できない！というような問題からは解放されます。
しかし、texのコンパイルをクラウドサービスのみに頼るのは危険です。本稿の内容を行うことで、ドロップボックスを介してローカルにもファイルは保存されるようになりますが、卒論・修論提出寸前にCloud LaTeXが落ちてtexファイルがコンパイルできなくなる、ということがあるかもしれません。
そのため、必ずローカルでtexをコンパイルできる環境、または24時間いつでもtexをコンパイルしてくれる友達（通称tex友）を用意しておきましょう。

#前提
PCにDropboxのアプリをインストールし、Dropboxフォルダとしてアクセスできるようにしてください。
(※Dropbox ダウンロードなどで検索してください。Windows Mac Linuxのいずれでもできます。）

また、gitのインストールも済んでいるものとします。

#git連携のための手順
Cloud LaTeXにはDropboxからインポートという機能があります。また、Dropboxには自動でローカルのファイルを更新してくれます。これらをうまくつなぎ合わせてgitで管理していきます。

1. Cloud LaTeXマイページ右上のユーザ名をクリック、Dropboxとの連携設定で、PCに設定したアカウントと同じものを連携
2. Cloud LaTeX上でプロジェクトを作成
3. 右上のプロジェクト設定(三のようなマーク)からDropbox同期をonにする
4. Dropboxのフォルダに(Dropbox)/アプリ/Cloud LaTeX/(プロジェクト名)というプロジェクトフォルダができていることを確認
5. (Dropbox)/アプリ/Cloud LaTeX/ でgit initし、(プロジェクト名)ファイルをgitに追加

（※注　(Dropbox)/アプリ/Cloud LaTeX/（プロジェクト名）フォルダでgitを管理したいところなのですが、この中に.gitファイルが存在するとcloud latex側でおかしくなるため、(Dropbox)/アプリ/Cloud LaTeX/に.gitを置いて管理するようにします。
）

IDE派の方もいらっしゃるかもしれませんが、一応gitコマンドを置いておきます。()内は各自のフォルダ名で読み替えてください。

```
cd (Dropbox)/アプリ/Cloud LaTeX/
git init
git add (プロジェクト名)
git commit -m "first init"
```
以上でGitとの連携が可能になります。
以後は、こまめにgit add & git commitを繰り返しましょう。

さらにGithubとの連携も行ってリモート管理も行いたい場合はこちらが参考になると思います。
参考：https://qiita.com/sodaihirai/items/caf8d39d314fa53db4db


#問題点
プロジェクトファイルの一つ上の階層でgit管理しているため、複数プロジェクトを別々のgitで管理できません（ダメでは）
ま、まあ卒論とか修論とか大事なやつをちゃんと守ろうという話ですね...
ちなみにちょっと前までのCloud latexだったらプロジェクトフォルダの中に.gitを入れることができたので、プロジェクトごとのgit管理が可能でした。なんでできなくなったんだろう...


#さいごに
texの環境を整えるのが面倒だから使っていたのに余計な面倒を抱え込んでしまいました。（でもやっぱりいろんなPCで同じ環境で論文書けるのは楽）
spring-batchでreaderの値に応じてwriterを動的に切り替える

たとえば、readerが整数を読み込み、偶数・奇数で異なるwriterを呼び出す、という例を考える。

```java
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.support.ClassifierCompositeItemWriter;
import org.springframework.batch.item.support.ListItemReader;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
@EnableBatchProcessing
public class App {
	@Bean
	public Job job(JobBuilderFactory jobs, StepBuilderFactory steps) {
		return jobs
				.get("job")
				.start(step1(steps))
				.build();
	}

	ItemWriter<Integer> evenWriter() {
		return items -> items.forEach(i -> System.out.println("偶数" + i));
	}

	ItemWriter<Integer> oddWriter() {
		return items -> items.forEach(i -> System.out.println("奇数" + i));
	}

	public Step step1(StepBuilderFactory stepBuilderFactory) {
		ItemReader<Integer> reader = new ListItemReader<Integer>(IntStream.range(0, 100).boxed().collect(Collectors.toList()));

		ClassifierCompositeItemWriter<Integer> compositeWriter = new ClassifierCompositeItemWriter<Integer>();
		compositeWriter.setClassifier(number -> {
			if (number % 2 == 0) {
				return evenWriter();
			}
			return oddWriter();
		});

		return stepBuilderFactory
				.get("step1")
				.<Integer, Integer>chunk(4)
				.reader(reader)
				.writer(compositeWriter)
				.build();
	}

	public static void main(String[] args) {
		new SpringApplicationBuilder(App.class).run(args);
	}
}

```

<code>ClassifierCompositeItemWriter</code>は自身がwriterで、指定されたルーティングパターンを基に呼び出すwriterを切り替える。

これを実行すると以下のようになる。

```
偶数0
偶数2
奇数1
奇数3
...
```

<code>chunk(4)</code>なので、4件ごとに偶数・奇数writerがそれぞれ1度ずつ呼び出されている。
【Tableau】年度の開始月を4月～にする

##　はじめに
Tableauは大量データの可視化に優れたモダンBIツールです。
世界中で相当数のユーザーがいて、コミュニティも大変機能しております。
今回の主題も、[Tableau Community](https://community.tableau.com/docs/DOC-6116)に記載があるのですが、
私のようなものは文字だけだと分からない！ということで"可視化"してみました。

##　本題
年度ごとに推移を見たい！といった時には、ディメンションの日付項目を年単位にすれば良いのだけど、
それでは1月～年が開始してしまう。

![tempsnip.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/571214/7b7104ba-de3c-5aca-5ebf-dafc5475adc9.png)

これを4月開始にしたい！

ちなみに、

![キャプチャ1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/571214/f9d81149-eed9-562e-1d65-6a41cfb86986.png)

とすると4月開始になる！んだけど、2020年4月が2021年4月になってしまうので、別の方法を考えなければならない。

##　計算フィールドを作ろう！

じゃあマイナス1年してあげれば出るじゃん！的な発想で計算フィールドを追加します。
以下のような計算式の計算フィールドを作ってあげればいいです。

![キャプチャ2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/571214/8a1d6c53-61f2-74b6-e9c5-bbe317b0ca82.png)

指定した日付項目(Order Date)に対して、-12のインクリメントを、"月"に対して行う、という意味です。

そうすると、

![キャプチャ3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/571214/1a03937d-f1a3-db7e-c116-ef929cc1ae12.png)

のように2016年のデータが12月分マイナスになります。

そして、「既定のプロパティ」から「会計年度の開始」を4月にすると、

![キャプチャ4.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/571214/1d56bc5b-bc90-3e5f-6c41-2c66b664d044.png)

表現したい状態（4月～3月が1年度）になります。

![キャプチャ5.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/571214/52655324-41f8-46d9-b39c-2db70efd79a6.png)

年度開始月が異なる場合でも使えると思いますので、ご活用ください。
♨️【CentOS】wkhtmltopdfのインストール方法

## 環境

CentOS 7.4.1708

## やりたいこと

[wkhtmltopdf](https://wkhtmltopdf.org/)はHTMLを取り込んでそのままPDFファイルを生成してくれる便利なライブラリ

## やったこと

次の4つのコマンドを順に実行

```centos.sh
1.
cd /usr/local/bin
2.
wget https://downloads.wkhtmltopdf.org/0.12/0.12.4/wkhtmltox-0.12.4_linux-generic-amd64.tar.xz
3.
xz -dv wkhtmltox-0.12.4_linux-generic-amd64.tar.xz
4.
tar -xf wkhtmltox-0.12.4_linux-generic-amd64.tar
```

### エラー発生時

2.の実行時に下記のエラーで進行しない場合は--no-check-certificateを付けて再実行

```centos.sh
[root@localhost bin]# wget https://downloads.wkhtmltopdf.org/0.12/0.12.4/wkhtmltox-0.12.4_linux-generic-amd64.tar.xz
--2020-01-23 00:02:50--  https://downloads.wkhtmltopdf.org/0.12/0.12.4/wkhtmltox-0.12.4_linux-generic-amd64.tar.xz
Resolving downloads.wkhtmltopdf.org (downloads.wkhtmltopdf.org)... 107.174.217.167, 107.174.217.167
Connecting to downloads.wkhtmltopdf.org (downloads.wkhtmltopdf.org)|107.174.217.167|:443... connected.
ERROR: cannot verify downloads.wkhtmltopdf.org's certificate, issued by ‘/CN=GlobalProtect.com’:
  Self-signed certificate encountered.
To connect to downloads.wkhtmltopdf.org insecurely, use `--no-check-certificate'.
```

```centos.sh
wget https://downloads.wkhtmltopdf.org/0.12/0.12.4/wkhtmltox-0.12.4_linux-generic-amd64.tar.xz --no-check-certificate
```

### バージョン確認

下記が通ればインストール成功

```centos.sh
[root@localhost bin]# /usr/local/bin/wkhtmltox/bin/wkhtmltopdf -V
wkhtmltopdf 0.12.4 (with patched qt)
```
enumを導入すると起きるエラー【rails】

#概要
数字を文字列に変換してくれる最強助っ人「enum」ちゃんを導入するとエラー発生。

エラー文
'x'ArgumentError in xxx 
'x' is not a valid xxx

<img width="596" alt="スクリーンショット 2020-01-09 18.22.23.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/504349/2c9bc06f-2103-0e04-b12f-7f1413fdaa9c.png">


#解決方法

Shift_user.model(enumを書いているモデル)での定義ミス。
###詳細
**Before↓**

```model.rb
class ShiftUser < ApplicationRecord

enum work_type:{
"午前": 1,
"午後": 2,
"一日": 3,
}
end
```

**After↓**

```model.rb
class ShiftUser < ApplicationRecord
  enum work_type: {
    am: 1,
    pm: 2,
    all_day: 3
  }
  # 英語から日本語
  WORK_TYPE = {
    am: '午前',
    pm: '午後',
    all_day: '1日'
  }
```

そもそもenumで日本語でも指定はできるが、
よく使われるのが「アルファベット or _」を使って命名するらしい。
Pythonでやりたいこと（リストのみ）

#Pythonでやりたいこと（ToDoリスト）
- 基礎知識を勉強する（随時）
- Google Cloudの基礎知識を勉強する（随時）  
- DeepLearningの基礎を勉強する（半年内）
- 音声認識の基礎を勉強する（半年内）
  - 歌の歌詞の認識（１年内）
- ソースコード（プログラミング言語）の解析（１年内）
  - ネーミング自動化
  - コーディング自動化
  - テスト自動化
  - 仕様アウトプット自動化
【ふくだ学習録】CakePHP3入門 part6【15日目】

# ふくだ学習録とは？
ふくだが学習したことの備忘録。
目に見える形で残すことによってやる気を出す個人的な作戦です。
他人に見せるように書いているわけではないので、すごく読みにくいです。

### 読了した本
[データベースエンジニア養成読本 [DBを自由自在に活用するための知識とノウハウ満載!]](https://www.amazon.co.jp/dp/4774158062/ref=cm_sw_r_tw_dp_U_x_FPphEbQFPPQRM )
[ゼロから作るDeepLearning](https://www.amazon.co.jp/dp/4873117585/ref=cm_sw_r_tw_dp_U_x_y3UiEbF3P6EG7)

### 今読んでいる本

[PHPフレームワーク CakePHP 3入門](https://www.amazon.co.jp/dp/4798048577/ref=cm_sw_r_tw_dp_U_x_.YIjEbS1K4JY2)

# CakePHP3入門を読んで

### ビヘイビア
モデル拡張させるためのプログラム。
ビューにとってのヘルパー、コントローラに対してのコンポーネントのようなもの。

### プラグイン
pluginsフォルダ内に格納されている。
プラグインを使用可能にするには、下記の記載が必要。

```php:bootstrap.php
# routes.phpの場合もある？
Plugin::routes();
```

### シェルプログラムの配置
`Shell`フォルダ内にまとめられている。

### $this->inメソッド
シェルプログラムを作成するときに使用する「ユーザー入力機能」を提供するもの。

```php
$変数 = $this->in( メッセージ, 選択肢の配列, デフォルトの値 )
```

### シェルのオプション設定
オプションを作成することができる。（例えば`-h`みたいなもの）

```php
public function getOptionParser() {
  $parser = new ConsoleOptionParser('mycmd');
  # $parserに設定する。
  return $parser;
}
```

# 今日の一言
終盤はほぼメモることなかった！笑

Rails使ってたからってのもあるけど、今後MVCモデルのフレームワークの勉強は、
・そのフレームワークでのデフォルトの記述方法
・そのフレームワークでは何ができるのか
・どこで何を設定するのか
ぐらいで、実際の関数名とか記述方法は都度都度調べるので良いかな。

次はSQL！！
世界一速い Hello World サーバを V 言語で作ってみた

### はじめに
「世界一速い」の定義なんですが 2020/01/23 時点での話になります。

### ベンチマークの結果
- 秒間 734万リクエストの対象のベンチマーク結果です (pico.v というマイクロフレームワーク)

[![スクリーンショット 2020-01-23 8.21.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109145/de44efc9-1992-b8b4-9096-a153ccd8e8db.png)](https://www.techempower.com/benchmarks/#section=test&runid=7f65c127-fad2-4a88-a6cb-5333c68362ef&hw=ph&test=plaintext)

### 対象の実装

```scala
import json
import syou.picoev
import syou.picohttpparser as hp

struct Message {
    message string
}

[inline]
fn json_response() string {
    msg := Message{
        message: 'Hello, World!'
    }
    return json.encode(msg)
}

[inline]
fn hello_response() string {
    return 'Hello, World!'
}

pub fn callback(req hp.Request, res mut hp.Response) {
    if hp.cmpn(req.method, 'GET ', 4) {
        if hp.cmp(req.path, '/t') {
            res.http_ok().header_server().header_date().plain().body(hello_response())
        }
        else if hp.cmp(req.path, '/j') {
            res.http_ok().header_server().header_date().json().body(json_response())
        }
        else {
            res.http_404()
        }
    }
    else {
        res.http_405()
    }
}

pub fn main() {
    picoev.new(8088, &callback).serve()
}
```

### 利用ライブラリなど
イベントリープの部分で kazuho さんの [picoev](https://github.com/kazuho/picoev) を利用しています。 HTTP リクエストのパーサも [picohttparser](https://github.com/h2o/picohttpparser) を一部利用しています。

HTTP のレスポンスの部分は ulib ほどはチューニングしていないのでその内 ulib に抜かれるとは思いますが、まぁ、最初の実装としては良い結果かなぁと思いました。

### 環境
サーバの環境としては、こちらのTechEmpower の[リンク](https://www.techempower.com/benchmarks/#section=environment&hw=ph&test=fortune)に最新情報ありますが、
- 物理サーバで Dell R440 に Intel Xeon Gold 5120 CPU, 32 GB メモリー, SSD. Cisco の 10G スイッチなどが使われています。
- クラウド版は Azure 上の D3v2インスタンスにありますが、そちらは２位でした。[リンク](https://www.techempower.com/benchmarks/#section=test&runid=05db376e-f327-4c18-a4ab-76df009de84d&hw=cl&test=plaintext)

### V 言語に関して

[V 言語](https://vlang.io/)は C にトランスパイルされるので、gcc/clang などのコンパイラ Optimization の恩恵を受けられます。あと、開発スピードもかなり速いので今後に期待しても良いではないかと思っています。
Sigfox Callbackとenebular連携

IoTセンサデータをSigfoxクラウドで受け、Callbackを使って、株式会社ウフルさんのenebularと連携する方法を記載します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172313/77a80ebb-5adf-5a2f-5acc-e6a5f7c94641.png)
今回は、単純に、Sigfox CallbackのBodyにあたるJSONメッセージをenebularのデバッグウィンドウに表示するだけです。もし、より高度なことをやりたければ、enebularの[マニュアル](https://docs.enebular.com/en/?_ga=2.80128468.2122792103.1579703861-1433413255.1579703861)を参考にしてください。

#enebular側の設定
enebularのSign-upから、プロジェクトを作成し、Flow編集するまでは、[enebular introdutionのページ](https://docs.enebular.com/en/GetStarted/Introduction.html)見れば、簡単にできます。
##Nodeを配置
今回は、Sigfox Callbackとの連携ですので、`http in`Nodeと`debug`Nodeをワークスペースにドラッグ＆ドラッグしてください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172313/43a456a7-2def-a58d-36b0-117a3f7647cd.png)
###http inノードの設定
http inノードをダブルクリックすれば、編集画面が表示されます。
メソッドを`POST`、URLを`/sigfox`としておきます。このURLの/sigfoxをデプロイ後の生成されるURLに追加するので覚えておいてください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172313/4e43c225-7bf8-4e26-2305-6571e160045f.png)
###debugノードの設定
デバッグノードの設定は特に変更する必要はありません。デフォルトで対象が`msg.payload`となっています。これが、Sigfox CallbackのBody（JSON）部分に相当します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172313/2954cc66-4f8b-458e-2632-822d098f7c6f.png)
###httpNodePath
デプロイ後、デプロイボタンの左にある(i)マークにマウスオーバーすると、httpNodePathが表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172313/355f74e7-386f-d623-5656-5c8cfc4c3b66.png)
後にSigfox Callbackに設定するURLは、このパスに先程http inノードで設定したURLを追加します。今回の場合、フルパスは、
`https://ev2-prod-node-red-******.herokuapp.com/sigfox`
となります。

#Sigfox Cloud側の設定
対象デバイスタイプのCALLBACK設定から、新規にCustom Callbackを作成してください。
Callbackの作成方法は[こちら](https://qiita.com/ghibi/items/53259381a30363538a6d)を見てください。
##enebular用Callbackの設定
いくつか方法はありますが、今回は、Typeを`DATA_UPLINK`、Channelを`URL`とし、シンプルな上りメッセージのコールバックを作成することとします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172313/a9088351-23a5-23a4-eb77-6d8a5f0a9c91.png)
Url patternには、先程enebular側で確認した`httpNodePath + /sigfox`を入力、Use HTTP Methodも、enebular側設定にあわせて`POST`、Content typeは`application/json`、Bodyは、Sigfoxルールに合わせて記載します。今回は、デバイスIDとメッセージ受信時刻、メッセージペイロードの3項目を送ることとし、下記のJSONを入力します。

```sigfox-callback.json
{
  "device":"{device}",
  "time":{time},
  "data":"{data}"
}
```
#Sigfoxメッセージをenebularのデバッグウィンドウで確認する
両プラットフォームの設定に問題がなければ、下図のようにデバッグ画面にmsg.payloadが表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172313/1ee45080-b2e1-b95f-c51b-7bc801248afb.png)

enebular連携をすることにより、ソーシャルメディアへのアウトプットや、関数処理、他プラットフォームとの連携もnode-redライクにできるようになりますね。

[Sigfox Japan KCCS](https://qiita.com/organizations/sigfox)
[Twitter ghibi](https://twitter.com/ghibi)
【Rails】 DataTables のテーブルに関連付けされたモデルのデータを表示する方法

# はじめに
DataTableへデータを渡すときに json 形式に変換する必要があります。
関連付けされたモデルのデータを簡単に json 形式に変換することができます。

#### 関連リンク
関連リンクを下記に載せておくので、必要であれば参考にしてください。。

* 【Rails】 DataTables 実装方法
    * https://qiita.com/syukan3/items/5ac9f0d1b43334b5eb13
* 【Rails】 DataTables 動的にカラムを変更する方法
    * https://qiita.com/syukan3/items/83c4ecd351db57911943
* 【Rails】 DataTables 検索結果の保持方法
    * https://qiita.com/syukan3/items/4be6ba8ef22aff189fc4

# 関連付けされたモデルのデータを表示する方法
as_json の include をすることで user に関連付けされた post のデータを一緒に json のデータとして作成してくれます。

```Ruby:app/datatables/users_datatable.rb
class UsersDatatable
  # *** 省略 ***

  def as_json(options = {})
    {
        recordsTotal: User.count, # 取得件数
        recordsFiltered: users.total_count, # フィルター前の全件数

        # user モデルに関連付けされた post モデルを include して json ファイルを作成する。
        data: users.as_json(include: :post), # 表データ
    }
  end

  # *** 省略 ***
end
```

# まとめ
こちらは突き詰めると、 DataTable 特有の使い方ではなく、 json ファイルの作り方の記事になってしまっています。
使い方が全くわからないという方には少しは参考になるかなーと思い投稿させていただきました。

---
### 会社紹介

**株式会社 Mosaica**  
最先端テクノロジーで社会課題を解決し、持続可能な未来を創造する IT カンパニー。
AI ソリューション、クラウド統合、DX 推進、経営コンサルティングなど包括的なサービスでビジネス変革を支援しています。  

詳しくは [公式サイト](https://mosaica.co.jp/) までお気軽にご相談ください。
公式サイト： https://mosaica.co.jp/
Embulkをファイルの解凍、文字コード変換だけに使ってみる

Embulkは有志が開発したプラグインを活用することで簡単に機能拡張ができます。
私はS3に置いてあるCSVファイルをBigQueryに入れる際によく活用するのですが、scriptで書くとちょっと面倒な複数のファイルの解凍、sjisからutf8への変換が少量の設定を記述するだけでできてしまいます。

ある時、微妙にスキーマが異なるのファイル群を処理する必要があり、
一旦、`ファイルの解凍、sjisからutf8への変換`をしたいものの、
スキーマが異なるために複数のyamlを作成する or 動的な処理を迫られる場面がありました。

Embulkで動的な処理をしたことが無かったため、他の方法を考えました。
embulk-parser-noneというプラグインを使えば、parseしない=スキーマが異なるファイルでも1つのyamlで処理できると考え、実践したところ、複数のファイルを解凍、sjisからutf8への変換をすることができました。

その際、Embulkをファイルの解凍、文字コード変換だけに使った設定を書き残します。

# embulk-parser-none とは

[作者の紹介記事](https://qiita.com/sonots/items/6cf9f1e6ce74778be71f) をご参照ください。

# Embulkをファイルの解凍、文字コード変換だけに使ってみる

1つの圧縮されたsjisのcsvを解凍して、文字コードをutf8に変換するデモです。
(Embulkはinstall済みとする)
https://github.com/nnashiki/embulk_as_decoder に必要なファイルを置いたので、試すことができます。


### 必要なプラグインをinstallする

紹介したembulk-parser-noneと、解凍するためのプラグインembulk-decoder-commons-compressをinstallしてください。

```
$ embulk gem install embulk-parser-none
$ embulk gem install embulk-decoder-commons-compress
```

### 用意した圧縮ファイルがsjisのcsvであることの確認

ターミナルのエンコードがutf-8であれば、以下の様に文字化けするはずです。

```
$ unzip unzip_charset_test_sjis.csv.zip 
Archive:  unzip_charset_test_sjis.csv.zip

$ nkf --guess unzip_charset_test_sjis.csv
Shift_JIS (CRLF)

$ cat unzip_charset_test_sjis.csv
���O,�^�C�v
�q�g�J�Q,�ق̂�
�[�j�K��,�݂�
�t�V�M�_�l,����%  
```


### yamlの中身に関して

[unzip_charset_test_sjis.csv.zip](https://github.com/nnashiki/embulk_as_decoder/blob/master/unzip_charset_test_sjis.csv.zip)を解凍して、文字コード変換し、result.csvを出力する設定です。
parserのtypeは`none`ですが、`charset`と`newline`を設定する必要があります。
outのformatterですが、[作者の紹介記事](https://qiita.com/sonots/items/6cf9f1e6ce74778be71f) の通りに、元の内容のまま吐き出す設定をします。ただし、`charset`と`newline`を設定しましょう。
execの`min_output_tasks`は複数ファイルが出力されるのを防ぐために設定しました。


``` embulk_test.yaml
in:
  type: file
  path_prefix: unzip_charset_test_sjis.csv.zip
  decoders:
    - {type: commons-compress}
  parser:
    type: none
    column_name: payload
    charset: MS932
    newline: CRLF
exec:
  min_output_tasks: 1    # disable page scatterings
out:
  type: file
  path_prefix: result
  sequence_format: ""
  file_ext: .csv
  formatter:
    type: csv # embulk-parser-none の説明通り
    charset: UTF-8
    newline: LF
    delimiter: 0 # embulk-parser-none の説明通り
    quote_policy: NONE # embulk-parser-none の説明通り
    header_line: false # embulk-parser-none の説明通り
```


### runする

出力したresult.csvがutf-8になっている事を確認できたかと思います。

```
$ embulk run embulk_test.yaml

# result.csvが作成される 

$ nkf --guess result.csv 
UTF-8 (LF)

$ cat result.csv
名前,タイプ
ヒトカゲ,ほのお
ゼニガメ,みず
フシギダネ,くさ
```

embulk-parser-noneでEmbulkの活用方法が広がりますね :sunglasses:
ベクトル化による計算効率の良さをPythonで実感する

# ベクトル化が必要な理由
n次元ベクトルのwとxがあったとき、$z = w_1x_1 + w_2x_2...w_nx_n$を計算するのにfor文だと効率が悪い。
ベクトル化すると$z = w^Tx + b$とすることで効率よく計算できる。
Pythonだと以下のコードで比較できる。

```python
import numpy as np
import time

a = np.random.rand(1000000)
b = np.random.rand(1000000)

tic = time.time()
c = np.dot(a, b)
toc = time.time()
print(f'{"Vectrized version":20}:{str(1000 * (toc-tic))} ms')

c = 0
tic = time.time()
for i in range(1000000):
    c += a[i] * b[i]
toc = time.time()
print(f'{"For loop":20}:{str(1000 * (toc-tic))} ms')
```
```
Vectrized version   :3.9501190185546875 ms
For loop            :1007.7228546142578 ms
```

## 指数演算で
1000000次元ベクトル$v$に指数演算を実行したいとする。

```Python
import numpy as np
import time
import math

v = np.random.rand(1000000)
u = np.zeros((1000000, 1))
tic = time.time()
u = np.exp(v)
toc = time.time()
print(f'{"Vectrized version":20}:{str(1000 * (toc-tic))} ms')

c = 0
tic = time.time()
for i in range(1000000):
    u[i] = math.exp(v[i])
toc = time.time()
print(f'{"For loop":20}:{str(1000 * (toc-tic))} ms')
```
```
Vectrized version   :3.992319107055664 ms
For loop            :857.1090698242188 ms
```

# まとめ
ベクトル化したものとしていないもので約300倍もの差が出ている。
for-loopを使いたくなったときは使わずに済む方法を考えるようにしたい。
言語処理100本ノック-96(Gensim使用):国名に関するベクトルの抽出

[言語処理100本ノック 2015](http://www.cl.ecei.tohoku.ac.jp/nlp100/)の96本目「国名に関するベクトルの抽出」の記録です。
[ノック90本目](https://qiita.com/FukuharaYohei/items/0ab5e4ccca7e1083db1f)で保存したGensim版の単語ベクトルから国名に関するものだけを抽出します。技術的には簡単ですが、国名に関する部分が少し面倒です。

# 参考リンク

|リンク|備考|
|:--|:--|
|[096.国名に関するベクトルの抽出.ipynb](https://github.com/YoheiFukuhara/nlp100/blob/master/10.%E3%83%99%E3%82%AF%E3%83%88%E3%83%AB%E7%A9%BA%E9%96%93%E6%B3%95%20(II)/096.%E5%9B%BD%E5%90%8D%E3%81%AB%E9%96%A2%E3%81%99%E3%82%8B%E3%83%99%E3%82%AF%E3%83%88%E3%83%AB%E3%81%AE%E6%8A%BD%E5%87%BA.ipynb)|回答プログラムのGitHubリンク|
|[素人の言語処理100本ノック:96](http://qiita.com/segavvy/items/650c3e1254d8c5aef8e1)|言語処理100本ノックで常にお世話になっています|

# 環境

|種類|バージョン|内容|
|:--|:--|:--|
|OS|Ubuntu18.04.01 LTS|仮想で動かしています|
|pyenv|1.2.15|複数Python環境を使うことがあるのでpyenv使っています|
|Python|3.6.9|pyenv上でpython3.6.9を使っています<br>3.7や3.8系を使っていないことに深い理由はありません<br>パッケージはvenvを使って管理しています|

上記環境で、以下のPython追加パッケージを使っています。通常のpipでインストールするだけです。

|種類|バージョン|
|:--|:--|
|gensim|3.8.1|
|numpy|1.17.4|
|pandas|0.25.3|

# 課題
## [第10章: ベクトル空間法 (II)](http://www.cl.ecei.tohoku.ac.jp/nlp100/#ch10)
> 第10章では，前章に引き続き単語ベクトルの学習に取り組む．

### 96. 国名に関するベクトルの抽出
> word2vecの学習結果から，国名に関するベクトルのみを抜き出せ．

#### 課題補足(国名に関して)
[「言語処理100本ノック-81(一括置換):複合語からなる国名への対処」](https://qiita.com/FukuharaYohei/items/67be619ce9dd33392fcd)で使った国名ファイルを使おうと考えたのですが、そのファイルには1単語の国名("England"など)がありません。[ステップ「4. 単一名削除」](https://qiita.com/FukuharaYohei/items/67be619ce9dd33392fcd#4-%E5%8D%98%E4%B8%80%E5%90%8D%E5%89%8A%E9%99%A4)で消してしまったからです。
もう一度、[ステップ「4. 単一名削除」](https://qiita.com/FukuharaYohei/items/67be619ce9dd33392fcd#4-%E5%8D%98%E4%B8%80%E5%90%8D%E5%89%8A%E9%99%A4)で削除した国名を追加して使いました。

# 回答
## 回答プログラム [096.国名に関するベクトルの抽出.ipynb](https://github.com/YoheiFukuhara/nlp100/blob/master/10.%E3%83%99%E3%82%AF%E3%83%88%E3%83%AB%E7%A9%BA%E9%96%93%E6%B3%95%20(II)/096.%E5%9B%BD%E5%90%8D%E3%81%AB%E9%96%A2%E3%81%99%E3%82%8B%E3%83%99%E3%82%AF%E3%83%88%E3%83%AB%E3%81%AE%E6%8A%BD%E5%87%BA.ipynb)

```python
import numpy as np
import pandas as pd
from gensim.models import Word2Vec

model = Word2Vec.load('./090.word2vec.model')
print(model)

index = []
vector = []

with open('./096.countries.txt') as file_in:
    for line in file_in:
        country = line.rstrip().replace(' ', '_')
        try:
            vector.append(model.wv[country].tolist())
            index.append(country)
        except KeyError:
            pass

pd.DataFrame(vector, index=index).to_pickle('096.country_vector.zip')
```

## 回答解説
ファイルを1行ずつ読んで、国名のベクトルを取得しリストに追加しています。スペースをアンダーバーに置換しているのは[「言語処理100本ノック-81(一括置換):複合語からなる国名への対処」](https://qiita.com/FukuharaYohei/items/67be619ce9dd33392fcd)で同じことをやったからです。
中にはコーパスに含まれていないものや出現回数が少なく除外したものもあるので、`except KeyError`でエラー捕捉しています。

```python
for line in file_in:
    country = line.rstrip().replace(' ', '_')
    try:
        vector.append(model.wv[country].tolist())
        index.append(country)
    except KeyError:
        pass
```

あとはDataFrameに国名をインデックスとして入れてあげてファイル出力です。238ヶ国が出力されます。元ファイルには416ヶ国だったので6割弱の単語ベクトルが存在しています。

```bash
pd.DataFrame(vector, index=index).to_pickle('096.country_vector.zip')
```
俺では全くわからなかったRDS 証明書更新のトラップと回避方法

俺です。

普段RDS Auroraをご利用されている俺達は、最近AWSコンソールにアクセスする度に表示されるRDS SSL/TLS証明書交換の通知と毎日のようにﾁｭｯﾁｭしていると思います。1週間後にﾘﾏｲﾝﾄﾞ送信ﾌﾌｯ...RDS♥⇔♥俺みたいな感じですよね。みんなもきっとそう。

なので証明書の強制ローテーションに伴うrebootがあるってことは誰もが知ってるので書きませんが、

[緊急かつ重要なお知らせ ー Amazon RDS、Aurora、DocumentDB の証明書をローテーションしてください](https://aws.amazon.com/jp/blogs/news/urgent-important-rotate-your-amazon-rds-aurora-and-documentdb-certificates/)を見てメンテRTAにチャレンジした結果ドツボにハマって絶望したので、近い未来に同じ轍を踏みそうな世界のどこかにいる会ったことのない名前も知らない俺たちのために記録を残しておきます。
メンテタイムを短縮したい。もしくはCA交換時の再起動をコントローラブルにしたい方は参考にどうぞ。

- 対象RDS Aurora: MySQL/PostgreSQL

# RDS 証明書更新のアナウンスに期待した結果

[アナウンス記事](https://aws.amazon.com/jp/blogs/news/urgent-important-rotate-your-amazon-rds-aurora-and-documentdb-certificates/)上は`2020 年 1 月 14 日 ー この日以降、作成されるインスタンスは、新しい証明書 (CA-2019) を使用するようになります。必要性がある場合は、一時的に古い証明書に戻すこともできます。`とあります。

と、いうことは...Aurora Clusterに新しくInstance追加したらCA2019として起動してくるんじゃないの。
と、いうことは...CA-2015なRDSインスタンスをCA-2019に変更せずに、新しくRDSインスタンスをクラスタへ追加しておけばCA-2019で起動されるってこと...?
と、いうことは...Failoverしたら終わりってメンテタイム爆縮できるやん**最高やんけ抱いて！**。と思ってしまいますが、実際にCA-2019のインスタンスで起動させるには...

- Writerインスタンスの証明書が`CA-2019`になっていることが前提です。
- Writerインスタンスの証明書が`CA-2015`だと新規追加したReaderインスタンスの証明書は`CA-2015`のままです。はい絶望します。
- `--no-certificate-rotation-restart` でwriterのCA-2019に変更しておくだけでもOKです(内部でCAフラグがCA-2019になるため)

## 超図解

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42755/f3903f1f-cf66-1e2b-9419-e3ba48da25d5.png)


#よってRDS再起動を最小限に抑えて証明書を更新するやり方は以下です。

1.RDS AuroraのWriterインスタンスを`--no-certificate-rotation-restart` 指定でrds-ca-2019に更新する。

```
aws rds modify-db-instance \
--db-instance-identifier chucchu-0 \
--ca-certificate-identifier rds-ca-2019 \
--no-certificate-rotation-restart \
--apply-immediately
```

2.Readerインスタンスを追加する

- chucchu-ca2019-1と2を追加します。
- CA-2019として起動してくれます。

```
aws rds describe-db-instances --db-instance-identifier chucchu-0 --query DBInstances[].CACertificateIdentifier --output text
rds-ca-2019
aws rds describe-db-instances --db-instance-identifier chucchu-1 --query DBInstances[].CACertificateIdentifier --output text
rds-ca-2015
aws rds describe-db-instances --db-instance-identifier chucchu-ca2019-1 --query DBInstances[].CACertificateIdentifier --output text
rds-ca-2019
aws rds describe-db-instances --db-instance-identifier chucchu-ca2019-2 --query DBInstances[].CACertificateIdentifier --output text
rds-ca-2019
```

3.Writerフェイルオーバーを実行します

```
aws rds failover-db-cluster --db-cluster-identifier chucchu --target-db-instance-identifier chucchu-ca2019-1
```

4.CA2015のReaderインスタンスを削除します。

chucchu-0と1を消しますさようならー。クラスタごと消さないようにオペミス考慮してクラスタのDeletion Protectionは仕掛けておきましょう

# terraformを使う場合

今回試さなかったけどAWS Provider 2.44以上でサポートされたca_cert_identifierを使えばWriterのCAがCA-2015のままでもCA-2019のReaderインスタンス追加いけるんじゃないのって思ってます

- terraform AWS Providerを2.44以上にverupする
- [ca_cert_idenfier](https://www.terraform.io/docs/providers/aws/r/rds_cluster_instance.html#ca_cert_identifier)を使う
- terraform applyして既存aws_rds_clusterにCA-2019なaws_rds_cluster_instanceを追加する
- Writer Failoverする
- aws_rds_clusterからCA-2015のaws_rds_cluster_instanceを削除する
- **抱いて!!**


次は混乱しないようにまた証明書の有効期限が近づくまでアディオス


完
GR-SAKURAⅡFULLにE2 Lite接続するにはハンダ付け必要

ルネサステクノロジのRX63Nを積んだボードMTK-RX63Nついて、先日習いました。

MTK-RX63Nは販売停止で、GR-SAKURAが同じRX-63Nを積んでいる、と言う事で、そちらで勉強の続きをします。

まずは、CC-RXコンパイラと、e2 studio をインストールしました。
(習った時に使っていたため)

CC-RXコンパイラは60日過ぎるとプログラムサイズ128kB制限がかかる、とのことですが、遊びで使うには十分でしょう、多分。

e2 studioでデバッグ実行したかったので、E2 Liteも準備しました。



しかし、GR-SAKURAⅡFULLには、E2 Liteを接続する端子が存在しないので、ピンヘッダーのはんだ付けが必要とのことでした。


不器用なので、はんだ付けは避けたかったのですが。



なので、デバッグ実行は当面置いといて、ライブラリのソースコード読解をしてみようと思います。

で、ソースコード読解となると、マイコンの型番やオプションの選択肢に応じてソースを自動生成するe2 studioより、ボードの種類を選ぶだけでコンパイルできるIDE for GRの方が簡単そうです。

問題は、ライセンス的に、読解した結果をネットに上げてOKか否か、ですね。
AutoHotKey の衰退及び復権

#「おじいさんおばあさん、AutoHotKey ってなぁに？」

2020年現在、日本の AutoHotKey(L) は見る影もない。
日本語ネットの世界を覆わんとしていたかつての勢力は
既に衰え今や風前の灯。
そう、2010年。今から10年前のあのとき、
AutoHotKey は我が世の春を謳歌していた。
これを語るには、それが何かを説くと同時に、
どのように興りそして廃れたのかも伝えなければならない……。

## AutoHotKey とは何だろう。
それは、キーボード即ち鍵盤の機能を好き勝手にいじることができる
大変に便利なものだ。
たとえば君が運命の悪戯でちょいと、
右手の小指を失ってしまったと仮定してごらん。
もう君の生涯の辞書から
・「Enter(エンターキー)」
・「BS(バックスペース)」
・「Del(デリートキー)」
という大切な3項目が無くなってしまった。
しかし！そんなときでも下のような呪文をメモ帳に書いて
AutoHotKey に頼めば、君の辞書は元通りになるのだ。

・無変換キー :: BS
・シフトキー+無変換キー :: Del
・変換キー :: Enter

(正確にはちょいっと違いますがだいたいこんな感じ)

これ……とくに説明しなくてもどんなことが起きるのか……想像できますよね……？
そんな馬鹿な！
いいえこれが本当なのです。
代償として貴方の人生から無変換キーと変換キーは失なわれてしまうが……
え？もともとそんな項目無かった？それは結構！ますます好きになりますよ！

あれ？これひょっとして右手の小指を失う前から
こっちの方が良かったんじゃない？
っていうか今までどうして小指で主要編集キーを推してたの？
なぜ小の指にむざむざ主要キーを充てていたの？

## AutoHotKey 団による AHK 革命の狼煙
そう！淑女紳士の賢明なる諸君らは！全く洗脳されている！
今こそ我らが AutoHotKey 団がより正しい習慣と常識を指導し
悪しき因習を断固打破するのである！！

それが若かりし AutoHotKey 同志たちの夢であった。
貧しく暗い部屋の隅で彼らが微笑んでいたのは何故だろう。
それは必ずしも狂気に支配されての笑顔ではなかった。
同族、友朋の明るい未来が我らの肩にかかっている。
自らの塗炭の苦難が世界を照らす光となる。
その遠い憧れの正義を目指す魂から漏れ出づる希望が彼等の笑顔になった。

だが現状を振り返れば！
憧れた正義とは裏腹に穢らわしい爛れた世界が
この日本にまだ貼付いたまま離れない。
その未来は遠かったのか？いや違う。
その原因は……。

## ようこそ AutoHotKey の世界へ
AutoHotKey 同志は、子供を作るのが下手だったのだ。
肉体が……という意味ではなく、ソフトウェアの互換性と言う意味で……。
いやまあそう言っちゃあそうなんだけどそんな下世話な話はあたしゃ御免蒙るよ。

何という呪われた運命！
正義を広めんと犠牲にした己の身の上の因果は
彼等自身、ひいては同族の未来に報い応えてしまった。
仕舞った！
そう嘆いてももう遅いことに気付いた時には
既に10年の歳月が失われて了った。

かつて同志たちは一生懸命 AutoHotKey の使い方を記述し、教え、広めていた。
鍵盤配列勢や特殊IME教の者とも交流を重ねて自己研鑽に没頭していた。
それが正義だと信じていたからだ。己を犠牲にし鍛え戦いに挑む。
戦士(サムライ)としてあるべき姿だ。嬉しいことだ。
鍛え抜かれた鎧の AutoHotKey スクリプトは
野も越えれば山も越え！行く先向う所正に敵無し！
「応！AHKだ！
要らぬ鍵は要る鍵へ！無駄な鈕の一つも無し！
能率！能率！」
勇敢なる彼等の声を耳にすれば激しい疲労に洗脳された労働者たちも
屹度革命の心を取り戻しその腕に再び力を取り戻したものだ。
だが時は無情にも流れを止めぬ。言葉もぞやがて変わりぬる。

##信じた AHK が AHKL に豹変！？
『き～らンに～ちわぁ～ン！』
(えっ！？)
『AHKL、一緒に行くンだよン！』
(ええ！事情はよくわかりませんが、AHKに違ひは在りませぬわ！)
(然うだね！)(イヱース！)
「「「行っけェエー！！」」」
「私達の！」『いいねぇン』
「色の！」『すンごぉ～いン』
「鍵盤配列！」『ひゅぅンひゅぅ～ン』
振り咲け見れば春日なる、越えて見せられなかった山……。

(AHK に、何が、あったのかな……？)

##刻々進む超異世界！見せてあげるわたしの脳内映像！欲しいモノには形無し！
六つかしい話は省くが兎に角、平たく言えば、
古い老人言葉は、手続き命令で文字列型を読んでいたのに、
若者言葉だと、関数命令で変数型を読むようになって了った。
つまり AHK ちゃんもとい AHKL ちゃんは、
カナから漢字を使うようになったのだコンピュータ的に。
それは後に、実はもっと高次元の鍵盤配列世界へ旅立つための
ときめきシンギュラリティの一環であると判ったのだが
しかし当時の AHK 戦士たちには到底理解の及ばないことであった。
増してや使い熟すことなど。
果たして！ AHK に一体何があったのか！？
私、あんな姿の AHK、見たこと無い……。
これは只事じゃないよォ！バグかはたまたイメージチェンジか！？
次回！ AHKL が謎の！大変身！でぃよ～ン。

##昨日の私はもうそこにいないよ
手段を磨くのに血道を上げるのは楽しく素晴らしいことだ。
でもね、クルクルと求められるものは変わる。
旧悪を破るため未来革命を目指すなら、
今の古い革命活動にすらわざときつい言葉を言わねばならない。
もっと凄いと確信しているから……。
なにより、立つ場所で映り方も移り変わるから……。

しかし自己犠牲と自己批判と総括！の嵐の中でやがて彼等は、
その厳しさに耐えかねて絶望に彷徨って真っ暗で孤独でいるうちに、
力の全てを大衆と言う名の「運命の女(ファム・ファタール)」に奪われてしまった。

だからね。
大切なのは鍛えることではない。
大切なのは夢を追うこと、夢を忘れないことだ。
「こんなに凄い技術がある！」
それは楽しいことだけど、それを嬉しがってはいけない。
貴方の夢は叶いましたか？
叶った？それは嬉しいですね。
叶ってない？それならまだまだ楽しめますね。
面白いじゃない、ゆめ！(泣きながら)

##辛くないと言えば嘘になるけど、幸せです
やはり僕たちの AHK 活動は残念だけれど何か
大切な処で道を間違えたようですね。

私はまた今更 AutoHotKey L の復権に立ち向います。
便利なソフトを究極に研ぎ澄ますような使い方ではなく、
指を失くした人、不便に喘いでいる人、肩凝りに悩む人のために。
パソコンを使いこなしたい人のためではなく、
もうパソコンなんか触りたくない！という人のために。
言語の仕様が変われば失われてしまうような精緻さのためではなく、
パソコンが苦手だけれど少なくとも心は僕より健康な人たちのために。

追伸
私が今でもこの惨めな AutoHotKeyL にしがみついているのは、
小指を失くしてしまったことと関係があるかもしれません交通事故で。
私の夢？ちょびっとだけ、叶いましたよ。ええ。
Chromeオプション --disable-web-securityでCORS解除が効かなくなった

# CORS解除ができなくなった件についての備忘録
Chromeバージョンは  79.0.3945.130 for macOS です。

Webフロントエンドの開発時に、ローカルの開発環境から別ドメインにアクセスしたい場合というのはよくあるシチュエーションだと思います。
私はAngular-CLI開発が多いため、Angularドメインはlocalhost:4200で、データサーバは別で立てるシチュエーションが常時発生しますが、CORS制限によりアクセスできません。

今までは、

```
$ open "/Applications/Google Chrome.app" --args --disable-web-security --user-data-dir
```

でクロスドメイン制限を解除できていましたが、最近のアップデートでいつの間にか使えなくなってしまいました。古いアップデートで似た現象が起きたときは、`--user-data-dir`をつければ良い旨の情報は出てきましたが、すでに付けてます。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">なんかChrome78ぐらいから--disable-web-security効かなくなった？<br>flagsから <a href="https://twitter.com/hashtag/site?src=hash&amp;ref_src=twsrc%5Etfw">#site</a>-isolation-trial-opt-out をdisabledにしたら効くようになったけど</p>&mdash; ゆきみす/雪見酒🍶🍹🎩🐤🏴‍☠️ (@yukimis) <a href="https://twitter.com/yukimis/status/1196648312092315649?ref_src=twsrc%5Etfw">November 19, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

こんなツイート見つけたので、ためしてみたものの、なぜか有効状態を維持できませんでした。
常時オプション切ってるのも不安です。Warningでチラッと見えるオプションを追加してみたら上手くいきました。

```
$ open  "/Applications/Google Chrome.app" --args --disable-web-security --user-data-dir --disable-site-isolation-trials
```

`--disable-site-isolation-trials` オプション名がトライアルぽいのでいつまで使える手なのかわかりませんが、ひとまずこれで凌げました。
クリーンアーキテクチャから学ぶSOLID : SRP

# クリーンアーキテクチャから学ぶSOLID : SRP

クリーンアーキテクチャを読んでいる。

[Clean Architecture 達人に学ぶソフトウェアの構造と設計](https://amzn.to/2tK6fki)

TL;DR : `モジュールはたったひとつのアクターに対して責務を負うべきである` が結論。

# SRP:  `単一責任の原則`

要約すると `アクターごとにモジュールを分けましょう。そうすると変更影響がアクター単位に閉じるから。` と言っている。



SRPはSingle Responsibility Principleの略で`単一責任の原則`と呼ばれる。


原著ではこう書かれている。


>  `モジュールを変更する理由はたったひとつであるべきである`

と書いてあるのだけど これが分かりにくい。

Unix哲学の `一つのことを上手くやる` と混同しやすい表現になっている。

# モジュールを変更する理由はたったひとつであるべきである = ひとつのことをうまくやる?

[UNIXという考え方―その設計思想と哲学](https://amzn.to/2vfsoaP) によると

>  ひとつのことをうまくやるようにプログラムを作れないのであればおそらく問題をまだ完全には理解していないのだろう

自分は名前からはこう解釈した。

`コードベースの変更理由が1つでない` =>  `機能に持たせる役割が1つでない` => `問題の切り分けが不完全` と誤解してしまう。

少なくともでもそうではないのだ。

# SRPとは `アクターごとにモジュールを分ける` 提案をしている

SRPは `機能を小さくするべき` ではなく、`アクター(ユーザやプレースホルダー)ごとに機能を切り分けるべき` と言っている。

クリーンアーキテクチャ では Facadeパターンを使って説明している。
[TechScore Facadeパターン](https://www.techscore.com/tech/DesignPattern/Facade.html/)

Facadeパターンは機能の入り口となるクラスが他のクラスを利用することで機能を提供する。

他クラスの使い方を知っており、一連の機能を提供するManager, Serviceクラスとその従属クラスのようなものを想像すればいい。

# 共通で使うクラスからアクターごとに違う振る舞いを他のクラスに移譲する

たとえ話をしよう。

3つの異なる役職のアクターがいるとする(例えばCTO, CFO, COO)。

こららアクターが共通で使うEmployeeクラスがある。

Employee には `calculatePay` 関数があり CFO, COOが利用している。


`calculatePay` をCOOの都合で書き換えた時、COOにも影響を与える。

CFOは知らないうちに数万ドルの損失を出すかもしれない。

複数のアクターで全く同じクラスを使うと、変更の影響が伝搬する。

<facadeを使うと…?>

このとき CFO, COOごとに (`CfoCalculatePay`のように) 機能を別のクラスに移譲する。

Employeeはアクターに適した振る舞いを持つ個々のクラスを呼び出す形にする。

そうすることで CFO都合の変更は `CfoCalculatePay` に閉じるし、 COO都合の変更は ``CooCalculatePay``に閉じる。

> `モジュールを変更する理由はたったひとつであるべきである`

は主語が抜けていて誤解しやすい。 

実際には `モジュールはたったひとつのアクターに対して責務を負うべきである` 。

クリーンアーキテクチャ では SRPをこのように解説している。

>  コンウェイの法則から導かれる当然の帰結。個々のモジュールを変更する理由がたったひとつだけになるように、ソフトウェアシステムの構造がそれを使う組織の社会的構造に大きな影響を受けるようにする

[『Clean Architecture』における単一責任の原則とコンウェイの法則について](https://ky-yk-d.hatenablog.com/entry/2019/03/14/080002)

コンウェイの法則

>  システムを設計する組織は、組織のコミュニケーション構造をコピーした構造の設計を生み出す。

つまり、組織の構造をそのままアプリケーションの構造に取り入れましょう、と言う話なのだろう。

SRPについてそこそこ深く理解できた気がする。