OmniAICreator/Qiita-1.07M huggingface dataset:
【Go】goenvにおけるGoバージョンの優先順位を検証してみる

# 概要

[前回](https://qiita.com/boutan/items/e4988a90e4bac0bfece0)は、goenvを使用してグローバルのバージョン設定をするまでをやりました。
今回は、バージョンの切り替えと優先順位について調べてみたいと思います。

# バージョン指定の選択肢
ざっくり3種類あります

- 環境変数（GOENV_VERSION）
- ローカル（.go-version）
- グローバル（~/.goenv/version）

# 優先順位
結果は、以下の順になります。
（強い）　環境変数　＞　ローカル　＞　グローバル　（弱い）

# 検証

検証のために、Goのバージョンをこのように設定してみたいと思います。

- 環境変数　1.8.0
- ローカル　1.6.0
- グローバル　1.11.0

## 準備
Goのバージョンをインストールしてない場合は、goenvコマンドで事前にインストールしておきましょう。

```
$ goenv install 1.11.0
$ goenv install 1.8.0
$ goenv install 1.6.0
```

## グローバルに設定
デフォルト設定です。
グローバル一強時代の始まりです。

```
# 設定
$ goenv global 1.11.0

# 確認
$ goenv version
1.11.0 (set by /Users/yourpath/.goenv/version)
```

## ローカルに設定
ディレクトリ別に指定したいときなんかに使います。
グローバル vs ローカル になります。

```
# ディレクトリ作っておく
$ mkdir goenvv160 && cd goenvv160

# 設定
$ goenv local 1.6.0

# 確認
$ goenv version
1.6.0 (set by /Users/yourpath/go/src/goenvv160/.go-version)
```

goenv local でバージョン指定をすると、`.go-version`ファイルがディレクトリ直下に作られます。
ローカルのバージョンが優先されていることが分かります。

ディレクトリ別の設定をやめたいときは、unsetすると`.go-version`ファイルがなくなりデフォルトのバージョンになります。

```
$ goenv local --unset
$ goenv version
1.11.0 (set by /Users/yourpath/.goenv/version)
```
localの設定をなくしたので、glovalのバージョンが表示されていますね。


## 環境変数に設定

goenv shellを設定すると、`$GOENV_VERSION`にバージョンが設定されます。
グローバル vs 環境変数 になります。

```
# 事前確認
$ echo $GOENV_VERSION

# 設定
$ goenv shell 1.8.0

# 確認
goenv version
$ 1.8.0 (set by GOENV_VERSION environment variable)
$ echo $GOENV_VERSION
1.8.0
```
ここでは、環境変数が優先されていることが分かります。
環境変数への設定をやめたいときは、unsetします。

```
$ goenv shell --unset
$ goenv version
1.11.0 (set by /Users/yourpath/.goenv/version)
```

## 最終確認

ローカル vs 環境変数 の確認だけしておきたいと思います。

```
# ローカル設定有効
$ cd goenvv160
$ goenv local 1.6.0
$ goenv version
1.6.0 (set by /Users/yourpath/go/src/goenvv160/.go-version)

# 環境変数有効
$ goenv shell 1.8.0

# どっちも有効なときは、環境変数の勝ち
$ goenv version
1.8.0 (set by GOENV_VERSION environment variable)
```

# 最後に
これでgoenvの良さが分かってきた気がします。
古いバージョンをいつまでも動かし続けることはあまり想定されませんが、新しいパッケージを入れたときに最新だと動かないけどひとつ前に戻したら動いたー。とかありそうですね。

Goのインストールが簡単にできたので、これからGoのなんたるやを学びたいと思います。
Rails application.cssのrequire_tree 簡易メモ

```css:application.css
/*
 ## 中略 ##
 *
 *= require_tree .
 *= require_self
 */
```
application.cssには、どのcssを読み込むかの設定が書かれている。
require_treeには、引数として与えられたディレクトリ以下のscss・cssファイルをアルファベット順に全て読み込むという意味がある。
上記の場合、require_treeの引数は.(ドット)なのでカレントディレクトリ以下のscss・cssファイルは全て読み込まれる。
（一見コメントアウトされてるように見えるけれどもちゃんと機能している。）
Testcafeを触ってみた

# テストツール
基本的に自動テストツールで有名なものはseleniumですが、
2016年あたりに__Testcafe__というツールが出始めてこれがどうやらseleniumに依存していないらしい。
実態を確認するためインストールして使用してみた

# node.js

## install

```
npm install -g testcale
```

こんな感じで(node.jsある前提)

```
testcafe-v
```
これでバージョン帰ってくればok

---

```javascript:test.js
import {Selector} from 'testcafe';

fixture('sample test')
  .page('https://www.yahoo.co.jp');

test('Qiitaで検索先で正しく情報が保持されているか？', async t => {
  const txtsrch   = await Selector('#srchtxt');
  const btnsrch = await Selector('#srchbtn');
  await t
    .setNativeDialogHandler(() => true)
    .typeText(txtsrch, 'Qiita')
    .click(btnsrch);
  await t.expect(Selector('#yschsp').value).eql('Qiita');
});
```
後は上記のjsファイルを作成して適当なフォルダに配置して

```console
testcafe chrome C:\test.js
```

コンソールから下記コマンドを叩くと

こんな感じで書くとyahooのページから検索フォーム立てて遷移
みたいなテストが出来ます。
簡単！


ちなみに起動時のスクショが↓
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46786/c1ab83c4-bc58-f97c-3f13-02aa3c09e8c2.png)



# GUIツール

後日記載
統計入門　区間推定のまとめ


### 不偏分散

```math
s^2 = \frac{1}{n-1}\sum_{i=1}^{n}  (x_i - \bar{x})^2
```

### 標準誤差

```math
SE = \sqrt{\frac{s^2}{n}} = \frac{s}{\sqrt{n}}
```

### 母平均の95%信頼区間（母分散既知）

```math
\bar{x}-1.96\times\sqrt{\frac{\sigma^2}{n}}\leq\mu\leq\bar{x}+1.96\times\sqrt{\frac{\sigma^2}{n}}
```

### 母平均の信頼区間（母分散未知）

```math
\bar{x}-t_{\alpha/2}(n-1)\times\sqrt{\frac{s^2}{n}}\leq\mu\leq\bar{x}+t_{\alpha/2}(n-1)\times\sqrt{\frac{s^2}{n}}
```

### プールされた分散

```math
s^2_p = \frac{(n_1-1)s^2_1+(n_2-1)s^2_2}{n_1+n_2-2}
```

### 母平均の差の信頼区間（母分散未知）

```math
(\bar{x_1}-\bar{x_2})-t_{\alpha/2}(n_1+n_2-2)\times\sqrt{s^2_p\left(\frac{1}{n_1}+\frac{1}{n_2}\right)}\leq\mu_1-\mu_2\leq(\bar{x_1}-\bar{x_2})+\\t_{\alpha/2}(n_1+n_2-2)\times\sqrt{s^2_p\left(\frac{1}{n_1}+\frac{1}{n_2}\right)}
```
### 母比率の95%信頼区間

```math
\hat{p}-1.96\times\sqrt{\frac{\hat{p}(1-\hat{p})}{n}}\leq\mu\leq\hat{p}+1.96\times\sqrt{\frac{\hat{p}(1-\hat{p})}{n}}
```

### サンプルサイズの算出

```math
2\times z_{\frac{1-\alpha}{2}}\times\sqrt{\frac{\hat{p}(1-\hat{p})}{n}}
```

### 母比率の差の95%信頼区間

```math
(\hat{p_1}-\hat{p_2})-1.96\times\sqrt{\frac{\hat{p_1}(1-\hat{p_1})}{n_1}+\frac{\hat{p_2}(1-\hat{p_2})}{n_2}}\leq\mu\leq(\hat{p_1}-\hat{p_2})+\\1.96\times\sqrt{\frac{\hat{p_1}(1-\hat{p_1})}{n_1}+\frac{\hat{p_2}(1-\hat{p_2})}{n_2}}
```

### 母分散の信頼区間

```math
\frac{(n-1)s^2}{\chi^2_{\alpha/2}(n-1)}\leq\sigma^2\leq\frac{(n-1)s^2}{\chi^2_{1-\alpha/2}(n-1)}
``
距離と距離空間を詳しく

機械学習やデータ分析のときに、データ間の距離を算出することが多くあります。マハラノビス距離、ユークリッド距離、マンハッタン距離など学習を進めていくと〇〇距離といったキーワードがよくでてきますが、同じデータでもデータ間の距離の測り方が違います。

#距離の例
（例１）１次元数直線上に点$5$と点$-1$があるとき、その２点間の距離は$5-(-1)=6$になります。一般的には点$b$と点$a$の距離$d$は、$d(a,b)=|b-a|$です。

（例２）２次元平面座標上で原点$(0,0)$から点$(3,4)$までの距離は、$\sqrt{3^2+4^2}=5$となります。これは三平方の定理により、距離を求めました。一般的には座標$a=(a_1,a_2)$と座標$b=(b_1,b_2)$の距離$d$は、$d(a,b)=\sqrt{(a_1-b_1)^2+(a_2-b_2)^2}$です。

（例３）３次元空間座標$a=(a_1,a_2,a_3)$と座標$b=(b_1,b_2,b_3)$間の距離$d$は、三平方の定理を２回使い、$d(a,b)=\sqrt{(a_1-b_1)^2+(a_2-b_2)^2+(a_3-b_3)^2}$と求められます。

#距離の定義を考える１
（例１）、（例２）、（例３）の測り方は全て**ユークリッド距離**といいます。ユークリッド距離は特に意識せず使っているはずです。３次元までは実際に図を書くことで距離を求めることができました。しかし、４次元以上の$n$次元空間だったらどうでしょうか。図が書けないのでそこから距離を求めることができません。そこで逆に、$n$次元座標での２点間$a=(a_1,・・・,a_n),b=(b_1,・・・,b_2)$の距離を、下記のように定義します。
$$d(a,b)=\sqrt{(a_1-b_1)^2+(a_2-b_2)^2+・・・+(a_n-b_n)^2}$$
こうすれば、１次元～３次元のときの距離は上記と一致して、$n$次元空間へ一般化することができます。この距離$d$を**$n$次元ユークリッド距離**といいます。

#距離の定義を考える２
ユークリッド距離を定義しましたが、データ間の距離は全てユークリッド距離で測らないといけない決まりはなく、その都度距離をアレンジしてもいいのです。ただし、距離というからには距離として機能するものでないとだめです。例えば、距離なのにマイナスになったりするとおかしいわけです。

ここで一般的な距離の定義を紹介します。

**定義（距離・距離空間）**
データの集合を$X$として、データ間の関数$d:X*X→R$に対して下記が成立するときに、$d$を**$X$の距離**といい、$(X,d)$の組を**距離空間**という。

　　$a,b,c$を$X$内の任意のデータとする。
　　１．$d(a,b)\geqq0$
　　２．$d(a,b)=0⇔a=b$
　　３．$d(a,b)=d(b,a)$
　　４．$d(a,b)\leq(a,c)+d(c,b)$

意味：１．距離はマイナスになってはいけない　２．距離が０になるのは同じ点のときだけ　３．$a$から$b$を測るのと$b$から$a$を測るのは同じになるべき、距離空間とは２点間の距離にだけ興味があるので、測り方までは考えないと言う意味　４．$a$から$b$の距離は、まっすぐ行くより$c$を経由した方が遠くなるという意味、もしこの条件がないと第3のデータを経由した方が近いということになる。

#どんな距離が考えられるか
（例１）$n$次元ユークリッド距離
これは上記の距離の定義を満たします。定義の１・２・３は明らかに満たして、（４）についても証明は省略しますが、コーシー・シュワルツの不等式から成立します。これにより、ユークリッド距離は距離になる、といえます。

（例２）マンハッタン距離
これは$d(a,b)=|a_1-b_1|+・・・+|a_n-b_n|$で定義されます。これも上記の距離の定義１・２・３は明らかに満たします。（４）もコーシー・シュワルツの不等式から成立します。よって、マンハッタン距離も距離の定義を満たします。
Flutterアプリでリリースビルド時にAPIが叩けない - permission (Android)

Flutterでアプリ開発を進めている際に、リリースビルドしたapkを実機にインストールし動きを確認したところAPIが叩けない問題があったので備忘として。
(超初歩的なミス、、)

具体的なエラー内容は以下の通り。

```
Error: SocketException: Failed host lookup: 'ドメイン名' (OS  Error No address associated with hostname, error = 7)
```
デバッグビルド時は普通に叩けていたAPIだがリリースビルドすると上記エラーが発生して叩けない。

調べるとAndroidManifestにINTERNET permissionを追加しないといけないらしい。

`android/src/main/AndroidManifest.xml`に以下を追加

```xml
<uses-permission android:name="android.permission.INTERNET" />
```

再びリリースビルドし、確認すると正常にAPIが叩けた。
MeCabで何が何でも記号で区切りたい。

日本語形態素解析エンジンといえば[MeCab](https://taku910.github.io/mecab/)。

文章を単語ベースで扱いたい時に、よく分かち書きでお世話になる。

でも最近、属性値抽出(と言いつつほぼNER)に使おうとして以下のような問題に直面した。
辞書はipadic。

~~~bash
mecab -Owakati
バラエティー番組『めちゃ×2イケてるッ!』（フジテレビ）
バラエティー 番組 『 め ちゃ × 2 イケ てる ッ !』（ フジテレビ ）
~~~

分かりにくいかも知れないが、
"ッ" , "!』（" , "フジテレビ" のように切れている。 
固有名詞としてラベル付けしたいのは、"めちゃ×2イケてるッ!"の部分なので、
"!』（"が一語にまとまってるのは後々困る原因になる。 

## 解決策
 
後処理でなんとかしてしまっても良いけど、 
今後のため、ユーザー辞書を追加して**半角全角ほとんどの記号**で切れるようにする。
(固有名詞切り出したいならNEologd使えば良いじゃんってなるけど、ipadicでやりたいが故のこのエントリー。)

[半角英数字記号と全角英数字かなカナ記号の一覧まとめ](https://qiita.com/sta/items/848e7a8c4699a59c604f)を参考に、user_dic.csvを作った。

~~~:user_dic.csvの一部
 ,-1,-1,1,記号,*,*,*,*,*, ,*,*
　,-1,-1,1,記号,*,*,*,*,*,　,*,*
	,-1,-1,1,記号,*,*,*,*,*,	,*,*
!,-1,-1,1,記号,*,*,*,*,*,!,*,*
          .
          .
          .
~~~

コストを1に設定しているので何が何でも記号で区切るマンです。

user_dic.csv全体は[k141303/symbol_dic](https://github.com/k141303/symbol_dic)に置いておきます。 

## コンパイルしてパスを通す。
手元の環境はMacだったので、[mecabユーザ辞書を追加](https://qiita.com/takaheraw@github/items/286cdb27887bd00e2245)を参考に、コンパイルしてパスを通した。
環境によってmecabがインストールされているパスが異なるので、説明は省きます。 
(コンパイル済みのユーザー辞書も[k141303/symbol_dic](https://github.com/k141303/symbol_dic)に置いておきます。)

Macユーザー以外はこのあたりの記事を参考に。
Win => [Window PCでMeCabの辞書を追加する方法](https://winlabo.com/post-1601) 
Linux => [Mecabのシステム辞書・ユーザ辞書の利用方法について](https://qiita.com/hiro0217/items/cfcf801023c0b5e8b1c6)

## できた

~~~bash
nakayamakoutanoMacBook-Air:~ nakayamakouta$ mecab -Owakati
バラエティー番組『めちゃ×2イケてるッ!』（フジテレビ）
バラエティー 番組 『 め ちゃ × 2 イケ てる ッ ! 』 （ フジテレビ ） 
~~~

やったぜ。
Docker Registryの保存先にIBM Cloud Object Storageを使う

#はじめに
IBM CloudでOpenShiftのオフライン環境インストールをするのにDockerRegistryが必要で、
そのDocker Registryの保存先として、IBM Cloud Object Storageを使いたかったのですが、Docker Registry Storage Driverの設定でS3互換のIBM Cloud Object Storageのドキュメンテーションが無くて接続するまで、四苦八苦したのでメモとして残しておきます。

# 前提
事前に以下のサイトを参考にCentOS7のdocker-distributionを使ってプライベートレジストリは構築済み

- (参考サイト）Docker RegistryをinstallしてSSLの設定とimageをS3に保存する  
https://ishiis.net/2017/01/12/docker-distribution-install/

# IBM Cloud Object Storageの必要な情報

```
(設定名)                                (例)
{cos_hmac_keysのccess_key_id} 　　　 => xxxxyyyy86a4e6d8ceb76487f1b0c19
{cos_hmac_keysのsecret_access_key}  => xxxxeyyyy17c753dcd229fbb8b0ee56a69fcca82be032ef
{ロケーション}                        => us-geo
{ロケーションのエンドポイント}           => https://s3.private.us.cloud-object-storage.appdomain.cloud/
{バケット名}                          => denno
{バケットのパス}:                      => /
```

- cos_hmac_keysは バケットのサービス資格情報作成時に、[ Include HMAC Credential 」を選択しないと出力されません。（最初気がつかなくてハマりました。）
<img width="606" alt="cos-スクリーンショット 2019-06-21 16.37.45.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/209170/fcbe368b-86d6-2f80-ee8c-f766ea30488b.png">

# docker-distributionの設定

- config.xml

```
version: 0.1
log:
  fields:
    service: registry
storage:
    cache:
        layerinfo: inmemory
    #filesystem:
    #    rootdirectory: /var/lib/registry
    s3:
      accesskey: {cos_hmac_keysのccess_key_id} 
      secretkey: {cos_hmac_keysのsecret_access_key} 
      region: {ロケーション}
      regionendpoint: {ロケーションのエンドポイント}
      bucket: {バケット名}
      encrypt: true
      secure: true
      v4auth: true
      chunksize: 5242880
      rootdirectory: {バケットのパス}
http:
    addr: :5000
    tls:
      certificate: /var/lib/registry/certs/registry.lab.example.com.crt
      key: /var/lib/registry/certs/registry.lab.example.com.key
```

# 結果
設定反映後、Docker Registryに対してdocker pushすると、IBM Cloud Object Storageのバケットの画面にDocker Registryに保存されたファイルが出力されます。
<img width="1108" alt="スクリーンショット 2019-06-21 16.50.27.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/209170/cab9db23-b180-b9c3-2645-00ef5b9c8180.png">

# 最後に
IBM Cloud Object Storageは S3互換サービスなので、他のS3互換のサービスでも参考になると思います。

(参考)Use minio as docker registry storage driver
https://medium.com/@enne/use-minio-as-docker-registry-storage-driver-c9c72c72cc87

# 追記
わざわざObjectStorageに放り込むのは、DockerRegistryが動作する仮想インスタンスを必要な時にだけ、契約すればいいかなって
発想からでした。
emacsclient 使用時に自動的にフレームをポップアップ/最小化する

Emacs をすばやく使うために、みなさん`emacsclient`を活用されていることかと思います。いちいち Emacs を起動しなくてよいため非常にべんりですが、いつからか(最初からかも？)`emacsclient`を叩いた際にかってにフレームを前面にもってきてくれなくなっていて、つらい思いをする日々が続いていました。

ということでめんどくさがらずに、ちゃんとコードを書いて使いやすいようにしましたというお話です。

# 用意するもの
ここでは`wmctrl`というツールを利用します。コマンドラインから X ウィンドウマネージャを制御するものです。Wayland 環境のみなさんはごめんなさいですが、今回の方法は使えないと思います。

(余談: 個人的に SKK ユーザということもあり、SandS を実現するために`xcape`を利用しているので、X11 を使いつづけています。Wayland 環境での SandS ベストプラクティス情報ほしいです……)

閑話休題、`apt`なりなんなりでインストールしましょう

```
# apt install wmctrl
```

# Emacs の設定
Emacs のフレーム(一般的用語におけるウィンドウですね)を最小化するには`iconify-frame`、ポップアップするには`raise-frame`という関数が用意されている……のですが、`raise-frame`を使っても最小化された Emacs のフレームがポップアップされません。なぜだ。

ということで外部ツールを利用する必要があります。先ほど紹介した`wmctrl`ですね。Elisp には`call-process`という関数があり、これで外部プログラムを実行できるため、この仕組みを利用します。

```elisp
(defun raise-frame-with-wmctrl (&optional frame)
  ;; (call-process "wmctrl" nil nil nil "-s" "1")  ;; 仮想デスクトップ使ってるときはこれも追加で必要
  (call-process "wmctrl" nil nil nil "-i" "-R"
                (frame-parameter (or frame (selected-frame)) 'outer-window-id)))
(advice-add 'raise-frame :after #'raise-frame-with-wmctrl)
(add-hook 'server-switch-hook #'raise-frame)
(add-hook 'server-done-hook #'iconify-frame)
```

上記のコードを`init.el`に書いておきましょう。やっていることは単純で、現在のフレームの Window id を取得し、それを`wmctrl`に渡しているだけです。

最小化する`iconify-frame`については、特に問題ない(と思う)ので、そのまま hook に追加しておくだけでよいでしょう。

これで、端末から`emacsclient`でファイルを開いた際に勝手にウィンドウがポップアップし、編集を終了すると勝手に最小化されるはずです。

# 追記(2019-08-29)
この設定だと Magit で commit メッセージを書いた後にも Emacs のフレームが最小化されてしまいます。これは commit メッセージ入力用のバッファを開く際に emacsclient が利用されているためです。このような仕組みになっている理由は[こちら](https://github.com/magit/magit/wiki/Emacsclient)にまとめられていますが、なんにしてもこれではとてつもなく不便なので、この挙動を修正しましょう。

```emacs-lisp
(defun suppress-iconify (&rest arg)
  (remove-hook 'server-done-hook #'iconify-emacs-when-server-is-done))
(defun apply-iconify (&rest arg)
  (add-hook 'server-done-hook #'iconify-emacs-when-server-is-done))
(advice-add 'magit-run-git-with-editor :before #'surpress-iconify)
(advice-add 'with-editor-finish :after #'apply-iconify)
```

commit メッセージ入力用のバッファを開く関数が `magit-run-git-with-editor` です。なのでこの関数が呼ばれる前に `server-done-hook` から最小化用の関数を外します。同様に編集を完了させる関数が `with-editor-finish` なので、この後に再度最小化用の関数を`server-done-hook`に追加しています。1つの hook に同じ関数が2つ以上設定されることはないようになっているので、ふつうに emacsclient を使った場合でも問題はありません。
바카라카지노^ 784YES.COM ^바카라카지노사이트

<a href="http://laviolle.com/?s=%EB%B0%94%EC%B9%B4%EB%9D%BC%EC%B9%B4%EC%A7%80%EB%85%B8%E2%9E%A0+784YES.COM+%E2%9E%A0%EB%B0%94%EC%B9%B4%EB%9D%BC%EC%B9%B4%EC%A7%80%EB%85%B8%EC%82%AC%EC%9D%B4%ED%8A%B8+%EB%B0%94%EC%B9%B4%EB%9D%BC%EC%B9%B4%EC%A7%80%EB%85%B8%EC%A3%BC%EC%86%8C+%EB%B0%94%EC%B9%B4%EB%9D%BC%EC%B9%B4%EC%A7%80%EB%85%B8+%EB%B0%94%EC%B9%B4%EB%9D%BC%EC%B9%B4%EC%A7%80%EB%85%B8%EC%B6%94%EC%B2%9C+%EB%B0%94%EC%B9%B4%EB%9D%BC%EC%B9%B4%EC%A7%80%EB%85%B8%EC%82%AC%EC%9D%B4%ED%8A%B8+%EB%B0%94%EC%B9%B4%EB%9D%BC%EC%B9%B4%EC%A7%80%EB%85%B8%EC%B6%94%EC%B2%9C+%EC%B9%B4%EC%A7%80%EB%85%B8+%EC%82%AC%EC%9D%B4%ED%8A%B8+%EB%B0%94%EC%B9%B4%EB%9D%BC%EC%B9%B4%EC%A7%80%EB%85%B8%EC%9D%B8%ED%84%B0%EB%84%B7" target="_blank">바카라카지노</a>
<br><br>
<a href="http://laviolle.com/?s=%EB%B0%94%EC%B9%B4%EB%9D%BC%EC%B9%B4%EC%A7%80%EB%85%B8%E2%9E%A0+784YES.COM+%E2%9E%A0%EB%B0%94%EC%B9%B4%EB%9D%BC%EC%B9%B4%EC%A7%80%EB%85%B8%EC%82%AC%EC%9D%B4%ED%8A%B8+%EB%B0%94%EC%B9%B4%EB%9D%BC%EC%B9%B4%EC%A7%80%EB%85%B8%EC%A3%BC%EC%86%8C+%EB%B0%94%EC%B9%B4%EB%9D%BC%EC%B9%B4%EC%A7%80%EB%85%B8+%EB%B0%94%EC%B9%B4%EB%9D%BC%EC%B9%B4%EC%A7%80%EB%85%B8%EC%B6%94%EC%B2%9C+%EB%B0%94%EC%B9%B4%EB%9D%BC%EC%B9%B4%EC%A7%80%EB%85%B8%EC%82%AC%EC%9D%B4%ED%8A%B8+%EB%B0%94%EC%B9%B4%EB%9D%BC%EC%B9%B4%EC%A7%80%EB%85%B8%EC%B6%94%EC%B2%9C+%EC%B9%B4%EC%A7%80%EB%85%B8+%EC%82%AC%EC%9D%B4%ED%8A%B8+%EB%B0%94%EC%B9%B4%EB%9D%BC%EC%B9%B4%EC%A7%80%EB%85%B8%EC%9D%B8%ED%84%B0%EB%84%B7" target="_blank">바카라카지노</a>
<br><br>
<a href="http://laviolle.com/?s=%EB%B0%94%EC%B9%B4%EB%9D%BC%EC%B9%B4%EC%A7%80%EB%85%B8%E2%9E%A0+784YES.COM+%E2%9E%A0%EB%B0%94%EC%B9%B4%EB%9D%BC%EC%B9%B4%EC%A7%80%EB%85%B8%EC%82%AC%EC%9D%B4%ED%8A%B8+%EB%B0%94%EC%B9%B4%EB%9D%BC%EC%B9%B4%EC%A7%80%EB%85%B8%EC%A3%BC%EC%86%8C+%EB%B0%94%EC%B9%B4%EB%9D%BC%EC%B9%B4%EC%A7%80%EB%85%B8+%EB%B0%94%EC%B9%B4%EB%9D%BC%EC%B9%B4%EC%A7%80%EB%85%B8%EC%B6%94%EC%B2%9C+%EB%B0%94%EC%B9%B4%EB%9D%BC%EC%B9%B4%EC%A7%80%EB%85%B8%EC%82%AC%EC%9D%B4%ED%8A%B8+%EB%B0%94%EC%B9%B4%EB%9D%BC%EC%B9%B4%EC%A7%80%EB%85%B8%EC%B6%94%EC%B2%9C+%EC%B9%B4%EC%A7%80%EB%85%B8+%EC%82%AC%EC%9D%B4%ED%8A%B8+%EB%B0%94%EC%B9%B4%EB%9D%BC%EC%B9%B4%EC%A7%80%EB%85%B8%EC%9D%B8%ED%84%B0%EB%84%B7" target="_blank">바카라카지노</a>
<br><br>
<a href="http://laviolle.com/?s=%EB%B0%94%EC%B9%B4%EB%9D%BC%EC%B9%B4%EC%A7%80%EB%85%B8%E2%9E%A0+784YES.COM+%E2%9E%A0%EB%B0%94%EC%B9%B4%EB%9D%BC%EC%B9%B4%EC%A7%80%EB%85%B8%EC%82%AC%EC%9D%B4%ED%8A%B8+%EB%B0%94%EC%B9%B4%EB%9D%BC%EC%B9%B4%EC%A7%80%EB%85%B8%EC%A3%BC%EC%86%8C+%EB%B0%94%EC%B9%B4%EB%9D%BC%EC%B9%B4%EC%A7%80%EB%85%B8+%EB%B0%94%EC%B9%B4%EB%9D%BC%EC%B9%B4%EC%A7%80%EB%85%B8%EC%B6%94%EC%B2%9C+%EB%B0%94%EC%B9%B4%EB%9D%BC%EC%B9%B4%EC%A7%80%EB%85%B8%EC%82%AC%EC%9D%B4%ED%8A%B8+%EB%B0%94%EC%B9%B4%EB%9D%BC%EC%B9%B4%EC%A7%80%EB%85%B8%EC%B6%94%EC%B2%9C+%EC%B9%B4%EC%A7%80%EB%85%B8+%EC%82%AC%EC%9D%B4%ED%8A%B8+%EB%B0%94%EC%B9%B4%EB%9D%BC%EC%B9%B4%EC%A7%80%EB%85%B8%EC%9D%B8%ED%84%B0%EB%84%B7" target="_blank">바카라카지노</a>
<br><br>
スプレッドシートをBigQueryのテーブルとして取り込む

# 背景

定期的に変わるマスタデータをBigQueryで扱う場合、BigQueryにデータを取り込んでしまうと洗い替えが必要になる。
マスタデータを変更する際にはスプレッドシートで作業し、そのままデータをBigQueryで扱いたい。

# 方法

スプレッドシートをBigQueryの外部テーブルとしてBigQuery上に定義できる。
BigQueryでテーブルをクエリする際に、スプレッドシートを見に行く動きとなる。

# サンプルデータ

スプレッドシートに文字、数値、日付の値を入れる。
ヘッダ部を英字で書いておくと、自動的にカラム名としてくれるので便利。
この例で試したところ、2行目に英字で書いておくとカラム名になった。1行目と2行目を逆にするとエラーだった。
![スクリーンショット 2019-06-21 16.44.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175280/6ddf8fab-8088-38e4-04eb-311b48922451.png)

# テーブル作成

BigQueryのテーブル作成画面で、ソースを`ドライブ`にするとスプレッドシートのURIを指定できるようになる。
以下のように、スプレッドシートのfile_idまでを残して貼り付ける。
`https://docs.google.com/spreadsheets/d/1OPvJyOVGuWyBGarRq4Nfww9GrRpr0iCTpSl2jZcXwC7/edit#gid=0`
↓
`https://docs.google.com/spreadsheets/d/1OPvJyOVGuWyBGarRq4Nfww9GrRpr0iCTpSl2jZcXwC7`

今回の例では1シートのみなので、シートの指定や範囲は指定しない。
スキーマは`自動検出`にチェックを入れる。これでカラム名と型を自動でセットしてもらえる。
ヘッダは２行あるので、`スキップするヘッダー行`は2で設定する。

![スクリーンショット 2019-06-21 16.49.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175280/c2d8f335-b0a8-7d67-d465-950d72434667.png)

# 作成したテーブル

フィールド名がスプレッドシート2行目で指定したものになっている。
型も自動検出できている。
日付型のところは説明に日付フォーマットを付けてくれた。
![スクリーンショット 2019-06-21 16.56.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175280/24fa67b4-a0cb-c470-649f-d5fea1f408c4.png)
データも検索できた。
![スクリーンショット 2019-06-21 16.56.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175280/33af105e-5e36-f138-06e3-a0ba90e7ab4c.png)

# 注意点

型に合わないデータをスプレッドシートで入力すると、BigQueryでクエリする際にエラーとなる。
不正なデータが入らないようにするには、スプレッドシート側で工夫が必要。
Futureでの副作用に気をつけないといけないお話。特にRepoとかの永続化時

```ruby:qiita.scala

type ProcessR[T] = EitherT[Future, Errors, T]

override def add(
    e: AccountingEvent
  )(implicit op: DBOperation): ProcessR[AccountingEvent] = ProcessR.success {
    val added = exec { implicit s =>
      val uid = applyUpdateAndReturnGeneratedKey(insert.into(~~~~~)) <- DBへ永続化している
      e.copy(uid = uid)
    }
    added
  }
```
こんな感じのRepoのaddがあったとして、
insertした結果のjeneratedKeyを戻り値の中に含めているので、副作用ではないからと油断していると痛い目に会う

## ①副作用を残してしまう例


```ruby:qiita.scala
 j <- ProcessR.success{
          Seq(journal1,journal2,journal3).foldLeft(Seq.empty[Journal]){case(js, j) =>
            eventRepo.add(event)
            js :+ j
          }
        }
      } yield {
        (j, errors) ==> ここの段階でeventRepo.addの中身の処理が終わっている確証はない。
      }
```

## ②副作用を残さない例

```ruby:qiita.scala
 j <- ProcessR.success{
        Seq(journal1,journal2,journal3).foldLeft((Seq.empty[Journal], Seq.empty[ProcessR[AccountingEvent]])){case((js, es), j) =>
            val event = eventRepo.add(event)
            (js :+ j, es :+ event)
          }
        }
      } yield {
        (j._1, errors) ==> ここの段階でeventRepo.addの中身の処理は確実に終わっている
      }
```

foldLeftを使っているから、必ず１処理ごとに完了してから次の処理が行われるはずなのに

## なぜこの現象が起こるのか？

①の例だとeventRepo.addの結果をfoldLeftの戻りにbindしていない。
なのでeventRepo.addの処理はFutureで走っているので、別スレッドで評価が開始される。
全部回りきる頃には、Seq[Journal]と言う実態が完成している。
が、裏側ではまだeventRepo.addが頑張って永続化をしている。

```ruby:qiita.scala
for{
  j <- Seq(journal1,journal2,journal3)
} yield {
  ここに来るのはjが完全に評価されたタイミング
}
```
となるので、jにeventRepo.addの結果を含めていないとyieldにきても副作用が残ってしまっている。

②の例だと、

```ruby:qiita.scala
val event = eventRepo.add(event)
```
と結果をeventにbindしている。
そしてfoldLeftの結果にも含めているので、

```ruby:qiita.scala
      } yield{
   (j._1, errors) 
}
```
に来る頃には、必ずjの処理が終わっていることが確約される。

### 最後に

もしかしたら間違えて理解している説もあるので、そうなら優しく指摘してください(マサカリはだめ)
Excel (Office 365) > 手順 > 20本の折れ線を持つグラフを10秒で作る

```txt:動作環境
Windows 8.1 Pro(64bit)
Excel Office 365
```

### 概要

- 20本の折れ線を持つグラフを10秒で作る
    - **Note: データ入力時間はこれに含めていない**

### 手順

1. 例として、2列、20行のデータを用意する
2. 1行分で折れ線グラフを作る
3. 残りの19行を選択しCtrl+Cする
4. グラフ上でCtrl+V

手順2-4の作業が10秒程度。


手順1
![2019-06-21_16h58_17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32870/e371fe6e-0e57-0534-5549-f88b25e1052c.png)

手順2
![2019-06-21_16h58_38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32870/2f1261d1-a0e6-906d-cc9d-bea09323154f.png)

手順3
![2019-06-21_16h59_26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32870/486df59d-807c-1edf-b674-fc827cfa0ffa.png)
【Libra】Libraの環境構築メモ

# 概要
Libraの環境構築をする

###最終的にインストールされるツール
- Libra core
- Go
- Rust/Cargo
- Cmake
- Protocol Buffer

#Clone
```
$ git clone https://github.com/libra/libra.git
$ cd libra
```

#Setup
```
$ ./scripts/dev_setup.sh
```

#Debug Buildとクライアントソフトの実行(テストネットへの接続)
```
$ ./scripts/cli/start_cli_testnet.sh
```

# Happy Hacking :sunglasses: !

# 参考文献
https://developers.libra.org/docs/my-first-transaction
EitherTを使ってfor内包表記で並列に動かすやり方


## これは並列処理されない
```ruby:qiita.scala
type ProcessR[T] = EitherT[Future, Errors, T]

for{
  a <- ProcessR(~~~)
  b <- ProcessR(~~~)
} yield (a, b)
```
flatMapは前のbindが完了してから次の処理に進むため


## これは並列処理される
```ruby:qiita.scala
val aPr = ProcessR(~~~)
val bPr = ProcessR(~~~)
for{
  a <- aPr
  b <- bPr
} yield (a, b)
```
valで定義した瞬間にFutureが走るため

for内包表記が使いたいが、直列では動かしたくない！
って時は自分で拡張しよう

```ruby:qiita.scala
  def join[A, B](
    aF: ProcessR[A],
    bF: ProcessR[B]
  )(implicit ec: ExecutionContext): ProcessR[(A, B)] =
    for {
      a <- aF
      b <- bF
    } yield (a, b)
```
このようにProcessRのコンパニオンか何かによく使う関数を定義しておけば

val   aF: ProcessR[A],
val   bF: ProcessR[B]
と引数でval宣言しているのと同義なので、これは

```ruby:qiita.scala
for {
a <- join(ProcessR(~~~), ProcessR(~~~))
} yield (a._1, a._2)
```
とfor内包表記で書きながらも並列に処理ができる
AWS Well-Architected Framework ホワイトペーパーまとめ 2 【運用上の優秀性】

## はじめに
運用上の優秀性が高い状態、細かいことをざっくり省いて一言でいうと、

***システムを継続的に改善できる状態***

になろうかと思います。

***継続的に***というのがキーです。

お客さんの要望を反映する形で、日々便利なサービスが登場しています。これらを積極的にアーキテクチャに反映させることで、より優秀な運用ができるようになります。


#### 連載目次
[AWS Well-Architected Framework ホワイトペーパーまとめ 1 【導入編】](https://qiita.com/Catetin0310/items/6e5bd6cb573aa38f0fc0)
AWS Well-Architected Framework ホワイトペーパーまとめ 2 【運用上の優秀性】 → 本記事
[AWS Well-Architected Framework ホワイトペーパーまとめ 3 【セキュリティ】](https://qiita.com/Catetin0310/items/08e1c4843cc5571cd3a5)
[AWS Well-Architected Framework ホワイトペーパーまとめ 4 【信頼性】](https://qiita.com/Catetin0310/items/c973552de5098fdda795)
[AWS Well-Architected Framework ホワイトペーパーまとめ 5 【パフォーマンス効率】](https://qiita.com/Catetin0310/items/12837377ab2d1c8f6c77)
[AWS Well-Architected Framework ホワイトペーパーまとめ 6 【コスト最適化】](https://qiita.com/Catetin0310/items/cc57d8018a3392dd9f73)

## 設計の原則
ではこの柱の設計原則を見てみましょう。

![01.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363781/0c434a6b-3351-003a-e554-23dfd2a94efc.jpeg)


## ベストプラクティスとチェック項目
原則だけだと具体的にどんなポイントに留意すべきか、なかなかつかめませんね。ベストプラクティスとチェック項目を見てみましょう。

![02.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363781/10076838-3eba-becf-5671-81649558f618.jpeg)


ではどのような作業を行う必要があるでしょう？
各ベストプラクティスの概要を抜き出してみます。

|-|概要|
|:--:|:---|
|***準備***|アプリケーションや顧客の体験と反応をモニタリングし、インサイトを取得するメカニズムを備えたシステムを設計する|
|***運用***|期待される成果を定義して、どのように成果が測定されるかを決定し、正しく運用できているかどうかを判断するために使われるシステムと運用に関するメトリクスを特定する|
|***進化***|システムと運用手順の両方に関して、定期的に改善できる部分を評価し優先順位付けビジネスや顧客の成果に対しての運用やデプロイの影響を分析する|

流れだけ抽出すると、

- しっかり準備をすれば運用が簡単になる、
- 簡単になればどこをどう変えればもっといい運用方法になるか見つけやすい、
- 見つけられればアーキテクチャを進化させられる、

という感じでしょうか。

## 候補サービス一覧
具体的にどのようなサービスを活用すればよいのか、一覧表にまとめます。
CloudFormationを軸に、CloudWatchやCloudTrailなどを組み合わせて活用していく形です。

![03.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363781/544b472a-3168-35e8-fa1c-d4f899ade864.jpeg)

## まとめ
運用上の優秀性を高めるうえで留意しなくてはいけないポイントと、活用するサービスの概要、つかめましたでしょうか？次回はセキュリティの柱についてお送りします！

## 参考リンク
[オフィシャル W-Aホワイトペーパー](https://d1.awsstatic.com/International/ja_JP/Whitepapers/AWS_Well-Architected_Framework_2018_JA_final.pdf)
ls -Fコマンドのマーク(ファイル識別子)

# ls -F：名前の後ろにファイル識別子を付ける

```bash

$ ls -F
a.txt  b.txt*  c.txt  test/  test2@
```

## ファイル識別子
* / : ディレクトリ
* @ : シンボリックリンク
* * : 実行可能形式ファイル(実行可能パーミッションがついているもの)
Aurora ServerlessにAWS LambdaのPythonからData APIで色々やってみたのでメモ

# これ is 何
東京リージョンのAurora ServerlessでData API（HTTPエンドポイント）が使えるようになったものの日本語の情報が少なくて苦労したのでメモ。

# 著者がPython苦手問題
AWS Lambdaのために必要に駆られて書き始めたばかりなのでコード的にイケてないところが多いと思います。
こうした方が良いとかあればぜひとも教えていただきたいです:bow:

# LambdaのBoto3古い問題
Layersを使って解決

```bash
$ mkdir python
$ pip install -t ./python boto3
$ zip -r boto3-x.y.z.zip python
```
できたZIPをLayersに登録、LambdaからそのLayerを選択すれば`import boto3`がLayerのboto3を使用してくれます。

# Lambdaが使うIAMに追加で与える必要のある権限
- secretsmanager:GetSecretValue
- rds-data:ExecuteStatement
- rds-data:BeginTransaction ※
- rds-data:CommitTransaction ※
- rds-data:RollbackTransaction ※

※ トランザクションを使わない場合には不要

# テーブル
```sql
CREATE TABLE `test` (
  `id` bigint NOT NULL AUTO_INCREMENT PRIMARY KEY,
  `str` varchar(255) NOT NULL,
  `date` timestamp NOT NULL,
  `val` int)
```


# Pythonコード
※ 実際のコードから有用そうな部分を抜粋したのでこのままで動くわけじゃないので注意してください。

```python
import boto3

def lambda_handler(event, context):
    cluster_arn = 'arn:aws:rds:ap-northeast-1:xxxxxxxxxxxx:cluster:yyyyyyyyyyyy'
    secret_arn = 'arn:aws:secretsmanager:ap-northeast-1:xxxxxxxxxxxx:secret:zzzzzzzzzzzz'
    
    rds_data_client = boto3.client('rds-data')
    
    try:
        transaction = rds_data_client.begin_transaction(
            resourceArn = cluster_arn,
            secretArn = secret_arn,
            database = 'dbname'
        )

        # ここらへんでdictに色々詰めてる感じ
        # dict['date']にはUNIX時間（秒）が入ってると思ってください

        rds_data_client.execute_statement(
            resourceArn = cluster_arn,
            secretArn = secret_arn,
            database = 'dbname',
            transactionId = transaction['transactionId'],
            sql = 'insert into test(str, date, val) values (:str, from_unixtime(:date), :val);',
            parameters = [
                {'name': 'str', 'value': {'stringValue': dict['str']}},
                {'name': 'date', 'value': {'longValue': dict['date']}},
                {'name': 'val', 'value': {'longValue': dict['value']} if dict['val'] else {'isNull': True}},
            ]
        )

        rds_data_client.commit_transaction(
            resourceArn = cluster_arn,
            secretArn = secret_arn,
            transactionId = transaction['transactionId']
        )

    except Exception:
        rds_data_client.rollback_transaction(
            resourceArn = cluster_arn,
            secretArn = secret_arn,
            transactionId = transaction['transactionId']
        )
error: [Intervention] Unable to preventDefault inside passive event listener due to target being treated as passive. 

エラー:
[Intervention] Unable to preventDefault inside passive event listener due to target being treated as passive. See <URL>

解決策:
以下をCSSに追加

```css
.container {
    touch-action: none;
}
```

source:
[reactjs - Intervention Unable to preventDefault inside passive event listener due to target being treated as passive - Stack Overflow](https://stackoverflow.com/questions/53387138/intervention-unable-to-preventdefault-inside-passive-event-listener-due-to-targe)
Ansible Playbook内でシェルのような文字列操作をする

# Ansible Playbook内での文字列操作の難しさ

Playbook内でシェル芸をしようとすると、Ansibleから警告が出て鬱陶しいです。しかし、かといってPlaybookの中で文字列操作をするには、Jinja2というテンプレートを使いこなす必要があります。これが、なかなかの曲者で、PythonのようでPythonとは異なる作法がところどころに見られ、ドキュメントも[Ansibleのもの](https://docs.ansible.com/ansible/latest/user_guide/playbooks_templating.html)だけでは不十分で、[Jinja2公式のもの](http://jinja.pocoo.org/docs/)を合わせても物足りません。

そこで、本記事はPlaybook内でシェル芸もどきをするのに必要なノウハウに絞って解説します。

# Task実行中に変数に値を代入したい

`set_fact`モジュールを使います。

```yaml
- tempfile:
    state: directory
  register: working_directory_info
- set_fact:
    working_directory: '{{ working_directory_info.path }}'
```

この例だと、`working_directory`という変数を宣言しています。

# ページの内容を変数に入れる
`uri`モジュールを使用します。`get_url`モジュールは、ページの内容をファイルとして保存することしかできません。もう1つの注意点として、`return_content`を`true`にしないと、ページの内容が変数に保存されないので、注意してください。

```yaml
- uri:
    url: http://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu1804/x86_64/
    return_content: yes
  register: repo
- debug:
    msg: '{{ repo.content }}'
```

# コマンドの出力結果を変数に入れる
`command`・`shell`などのモジュールを実行し、結果を変数に保存します。その変数の要素`.stdout`・`.stdout_lines`(改行で区切られた配列)が実行したコマンドの出力結果(標準出力)となります。なお、末尾の改行は削除されるようです。

```yaml
- command: runlevel
  register: runlevel_result
  changed_when: no
- debug:
    # ↓現在のrunlevelを出力
    msg: '{{ runlevel_result.stdout.split(" ") | last }}'
```

# 文字列をシェルスクリプトのように行単位で処理したい
まず、`(文字列).splitlines()`で行ごとに分割します。

## grep
`select("match", "(正規表現)")`というフィルタで正規表現にマッチする行だけを抽出することができます。

## head・tail
`head -n 1`は`first`というフィルタで書き換えられます。`tail -n 1`は`last`です。

## sed
`sed 's/(置換前)/(置換後)/(オプション)'`というパターンに対しては、`regex_replace("(置換前)", "(置換後)")`というフィルタを使用します。`grep -o`相当のことをする場合は、丸括弧及び`\1`,`\2`,・・・を上手く活用してください。

## スペース等による文字列の分割
`変数.split("(区切り文字)")`で行います。スペースが2つ以上並んでいる文字列に対しスペースで分割すると、空文字が要素に混じります。`{{ 変数.split(" ") | reject("eq", "") }}` で取り除きます。`reject`はPythonの`filter`に似ていますが、要素の除去条件が逆です。(`True`で除去)

## 文字列の連結
フィルタ`join("\n")`を使用します。

# テンプレート内で引用符2種(`"`・`'`)を両方とも使いたい

ブロックスタイル文字列を使用するのですが、制御記号には必ず最終行の改行を取り除く`-`を指定してください。それ以外の行の改行を保存する`|`か、スペースに置き換える`>`かはお好みですが、基本は`>`でいいと思います。

```yaml
- set_fact:
    variable_from_complex_template: >-
      {{ ansible_distribution_version | replace(".", "'") }}
```
未実行のマイグレーションファイルを削除する方法

#間違えてrails g modelコマンドを実行して、未実行のグレーションファイルを生成してしまった場合の削除方法と手順


ターミナル上で以下のコマンドを実行して、マイグレーションファイルの実行状況を確認する

```
$ rake db:migrate:status
```

そうすると、以下のような表示がされる。

```
Status   Migration ID    Migration Name
--------------------------------------------------
   up     20190618115638  Devise create users
   up     20190620183857  Create groups
   up     20190620183912  Create group users
  down    20190621063102  Add devise to users
```

up 　　→　マイグレーションファイル実行済み
down　→　マイグレーションファイル未実行

削除したいマイグレーションファイルが未実行(down)になっていれば、そのままエディタ上にあるマイグレーションファイル(今回であれば、 20190621063102  Add devise to usersというファイル)を右クリックして「削除」のボタンを押せばよい。

最後に、再度マイグレーションファイルの実行状況を確認するコマンドを実行して、ファイルが削除されているかを確認する。

```
Status   Migration ID    Migration Name
--------------------------------------------------
   up     20190618115638  Devise create users
   up     20190620183857  Create groups
   up     20190620183912  Create group users
```

　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　以上
プログラミングが気になる人向けのまずは触ってみ講座(html css編その１)

##　あらすじ
html css を超ざっくり説明する。因みに友人に教えながら書いているぞ！情報は9割強カットするつもりなので足りないなと思えば各自検索をよろしく！

##　htmlとは
[まずはここを見よう](http://www.htmq.com/htmlkihon/001.shtml)
大雑把に言えばサイトの見た目の構造を決める言語。

##　cssとは
[まずはここを見よう](http://www.htmq.com/csskihon/001.shtml)
大雑把に言えばhtmlで決めた構造に対し幅、色、枠線、位置などを定義することができる。

##　htmlのベース

まずはこのベースを覚えよう。よく使うのでコピペok

```sample.html
<!--これはコメント、ビューには基本影響しないぞ。メモ感覚で使おう-->
<html>
  <head>
<!--head要素　約束事を記入するためのスペース。タブの名前や使用するcss等を設定できる。-->
    <title>ウェブページのタイトル</title>
<!--cssは同じディレクトリ(フォルダ)にいれば下の書き方でOK、違うならアドレスの指定が必要-->
    <link rel="stylesheet" type="text/css" href="sample.css">
  </head>
  <body>
<!--body要素 見た目に必要な要素はここに記述する -->
  </body>
</html>

```

##　cssのベース
```sample.css

/*これもコメントメモ感覚で使おう*/

/*　○○{}でスタイルの指定ができます。classで指定するときは.○○{} idで指定するときは#○○{}と書きます　*/
body{
/*　height(高さ) & width(幅): 高さ,幅を指定できる。値は固定値ならpx,割合なら%を使う。　*/
  height:100%;
  width: 100%;
/*　color(フォント色) & background-color(背景色): 色を指定できる。
カラーコードで指定するか、名称で指定する。 　*/
　color: #6fe7bd;
  background-color: green;
}


```

##　黒板(授業中書いたもの)
```index.html
<html>
  <head>
    <title>ウェブページのタイトル</title>
    <link rel="stylesheet" type="text/css" href="index.css">
  </head>
  <body>
    <div class="apple"></div>
    <div class="banana"></div>
    <div class="apple"></div>
    <div class="cheese"></div>
    <h1>ウェブページの見出し</h1>
    <p>ウェブページを作成しました！</p>
  </body>
</html>

```

```index.css
html{
  height:100%;
  width: 100%;
  background-color: green;
}
h1,p{
  color: white;

}
.apple{
  height: 200px;
  width: 200px;
  background-color: red;
}

.banana{
  height: 300px;
  width: 150px;
  background-color: yellow;
}
.cheese{
  height: 30px;
  width: 30px;
  background-color: white;
}
```

##　宿題とテンプレ
```homework1.html
<html>
<head>
<title></title>
<link rel="stylesheet" type="text/css" href="homework1.css">
</head>
<body>
</body>
</html>

```

```homework1.css
body{
  height:100%;
  width: 100%;
}
```
黒板でやったことを思い出しながら以下の問題を答えること。
1.幅高さともに50%の背景緑でできたclass名content1を作る。
2.幅高さともに200pxの背景黄色でできたclass名content2を作る。
3.(発展)幅高さともに200pxの背景赤色でできたclass名content3をcontent1の中に作る。
4.(発展)content3に白色で書かれた「hello world」の文字を記入する。
ニートの自然言語処理100本ノック:51

ちょこちょこ更新していくうう。
前回のモジュールを単語に分割して整形して別のファイルに書き込んだだけ。
なんか前半の100本ノックでも同じ感じのものがあった気がする。
無駄に長ったらしいことしてる気がする...

```python
"""
51. 単語の切り出し
空白を単語の区切りとみなし，50の出力を入力として受け取り，1行1単語の形式で出力せよ．ただし，文の終端では空行を出力せよ．
"""
from nltk import sent_tokenize
from pprint import pprint
from n50_exercise import load_text,find_specialchar_index,sent_tokenize_Plus
import re


# split by 空白
def sentence_ToWords(tokens):
    '''
    文章を単語にする

    Parameter
    ========
    words_list:list
        センテンスの単語全て
    sentence:
        文章トークン化されたもの
    Return
    ========    
    words_list,len(words_list)
    '''
    words_list = []
    word_spliter = re.compile(r"\s")

    for token in tokens:
        words_list.extend(word_spliter.split(token))
    
    return words_list,len(words_list)

# 50個ずつまとめる+最後に空行 |別ファイルに書きこむ

def write_50word_ToText(word_list,word_len):
    '''
    新規ファイルに50文字づつ単語を書きこむ。
    PArameter
    ========
    PATH:str
        ファイルのパス
    path:str
        新規生成されるファイルのパス(末尾には何個目までのファイルが入ってるかが入る)
    start:int
    end:int
        50区切りのために使用(単語のインデックス)
    re_format:
         単語以外の文字列を削除するためのもの
    Return
    ========  
    None
    '''
    PATH = "words.txt"
    start = 0
    end = 49

    re_format = re.compile(r"""
    \(| # (
    \)| # )
    \.| # .
    , |# ,
    \"| # "
    \\n{2} # 空白2連続
    """,re.VERBOSE)

    while word_len > end:
        path = PATH + str(end)
        with open(path,'w') as file:
            for word in word_list[start:end]:
                # maxで4回単語フォーマット化処理すると仮定
                word = re_format.sub('',word,4)
                file.write(word+'\n')
            else:
                file.write('\n')
                start = end
                end += 50
                      

if __name__ == "__main__":

    path = "nlp.txt"
    # テキストの読み込み
    sentence = load_text(path)
    # 特殊な文字の位置を取得する
    index = find_specialchar_index(sentence)
    # token化　一文化
    sent_token = sent_tokenize_Plus(sentence,index)
    # print(sent_token[0])
    # とりあえず一区切りだけ入れる
    samp_text,length = sentence_ToWords(sent_token)
    # samp を区切る

    write_50word_ToText(samp_text,length)


 ```
cocos2d 3.17.1の環境構築 (Mac)

#はじめに
必要になったので、環境構築した。
備忘録も兼ねて書いただけなので、ご容赦ください。
結構雑です。



##環境　<これだけあればいけると思う>
|       |       バージョン | 
|:-----------------|------------------ |
| cocos2d          |            3.17.1 |  
| AndroidNDK       |           r14b    |     
| AndroidStudio    |              3.2.1|   
| apache-ant       |            1.10.5 |       
  

##Cocos2dでのパッケージ作成<これまでと同じ>
頑張れ！

※これとか参考にしました
https://qiita.com/rr_RrR__rRrr/items/03b3047f37369de976ea







##プロジェクトの作成
このコマンド叩けば、ホームディレクトリ以下に`FirstGameプロジェクト`が作成される
`$ cocos new FirstGame -p com.FirstGame -l cpp -d ~/`


new : FirstGame がプロジェクト名
-p : Android のパッケージ名
-l : 言語、cpp lua js を指定可能
-d : プロジェクトを作成するディレクトリのパス


##プロジェクトをAndroid Studioで編集　<エラー出ると思う>
※最初、Gradle周りでアップデートする？って聞かれたらしてもいいと思う。（特に関わってこないはず）

Android Studioを立ち上げると、緑三角形のRunボタンがグレーアウトして動かない！！（ビルドエラー）
<img width="576" alt="スクリーンショット 2019-06-21 16.02.59.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328210/6a9be3cf-3f65-c413-134c-65f13cb224ff.png">

しかも、`Add Configuration`の文字


１、ninjaないよみたいなエラーがあったので直ちに`ninja`入れてみる
->`$ brew install ninja`叩く

※`brew`がなかったらこちらを参考に
->https://qiita.com/pypypyo14/items/4bf3b8bd511b6e93c9f9

###====ちなみに、Cmake =====
cocos2dではビルドするのにCmakeを使っているのかな（知識不足）
Cmakeでは、軽量な動作で有名なNinja用のファイルを生成できるらしい
###======================
２、`$ gradle build`叩く（かなり時間かかった） OR Run
->Runできるようになった
<img width="504" alt="スクリーンショット 2019-06-21 16.01.35.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328210/924dc4ae-9a6f-30d5-8df5-fca459fe15fd.png">



ここで、エミュレータ上で動くはず！（ここで動いた方は終了！）
->**Device supports x86, but APK only supports armeabi-v7a**

「デバイスはx86をサポートしてるけど、APKはarmeabi-v7aしかサポートしてない」

3,`Build.gradle`ファイルにて

```
ndk {
    abiFilters "armeabi-v7a", "x86"//追記
}
```


動いた！
<img width="676" alt="スクリーンショット 2019-06-21 15.18.44.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328210/3490a495-1516-753e-cb79-4ac1f8f93add.png">








##参考
https://qiita.com/puttyo_bubu/items/c72b47ddf197b42ca568
https://qiita.com/AtsushiUemura/items/68947c2809c41f57168f
【備忘録】Azure AD から Google Cloud Platform に SSOする方法

# 今回の記事は・・・

備忘録になりますのでご容赦を。
あと基本的な手順は他サイトを参照しています。

# とりあえず、SSOの設定について

非常に為になるサイトはこちらです。
[チュートリアル:Azure Active Directory と G Suite の統合](https://docs.microsoft.com/ja-jp/azure/active-directory/saas-apps/google-apps-tutorial)

基本はこちらを参考に作業を進めます。

## 注意
Azure AD上にある既存ユーザをSSOさせる場合は
G Suite側にも同じUPN名でのアカウントを作成しておく必要があります。

# やってみたけど　躓いた。
こんなエラー
（ログイン資格情報を確認できないため、このアカウントにはアクセスできません。）
が出るんすよ。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269159/1f1cd321-5ea5-4917-706a-69c53387145c.png)

# いろいろ調べて分かったこと

どうも、アカウント情報の紐づけに使用する
Azure ADのユーザ属性情報（下図参照）と
G Suiteのユーザ属性情報とでアンマッチが起きているんじゃないかと推定。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269159/8dfebd7b-b7d4-32fc-67d4-192e959e52e8.png)

特に日本だと2バイト文字使ってるから・・・💦

# というわけで・・・

Azure AD上で定義している
GCPのSSO設定にあるユーザ属性をこのように変えてみた。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269159/a4d1a028-8d6c-8020-2087-70c48675477d.png)

簡単にいえば、姓、名、名前、メールアドレスを紐づけに使うのをやめて
ユーザID一本にしちゃったってこと。


これでうまくいきました！
Firebase CLIのfirebase-toolsバージョン7でfirebase initすると動かないエラー

firebase-toolsのバージョンを最新にし、firebase hostingを使うために初期化しようとfirebase initコマンドを続行したら、プロジェクトのディレクトリを選択するところから一切動かせなくなった。

stackoverflowにも同じような問題が挙げられていて、どうやら最新版のfirebase-toolsだとこうなるようだ。
https://stackoverflow.com/questions/33944731/arrow-keys-do-not-work-with-firebase-init-command

## 対策：ダウングレードをする
firebase-toolsのダウングレードをしたら解決した。自分の場合はバージョン6でもダメだったので、バージョン5.1.1まで落とした。

npm install -g firebase-tools@^5.1.1

firebaseはプログラミング初心者も最近は取り組んでいるので、このエラーはしんどいなぁと思った。
【Mac】Laravel環境　artisan tinkerでDBアクセス　ついでにpsyshのインストールからHelloWorld

# Laravel環境でtinkerを利用してPHPを実行しDBアクセスする
## tinkerとは？
* Replライブラリ、インタラクティブ（対話）シェルの一つで、artisanのオプションの一つ 
* rubyでいうirbみたいな事ができる
* デバッグとか色々できるらしい

## 実行手順
* DBアクセスしたいので、DB起動（この例ではPostgreSQL）

```
➜ pg_ctl -D /usr/local/var/postgres/xxxx -l logfile start
waiting for server to start.... done
server started
```

* artisan の tinker起動

```
➜ php artisan tinker

Psy Shell v0.9.9 (PHP 7.2.19 — cli) by Justin Hileman
>>>
```

* とりあえず何かしらのテーブルのデータを取得  
例）publisherテーブルのレコード全件取得  
　　publishsherモデルクラスは作成済みであることを前提とする

```
>>> publisher::all()
[!] Aliasing 'publisher' to 'App\publisher' for this Tinker session.
=> Illuminate\Database\Eloquent\Collection {#2940
     all: [
       App\publisher {#2941
         id: 1,
         publisher_name: "aaaaaaaa",
         fax_number: "0311112222",
         tel_number: "0355556666",
       },
       App\publisher {#2942
         id: 2,
         publisher_name: "bbbbbbbb",
         fax_number: "0377779999",
         tel_number: "0388889999",
       },
       App\publisher {#2943
         id: 3,
         publisher_name: "cccccccc",
         fax_number: "0344445555",
         tel_number: "0355554444",
       },
     ],
   }
>>> 
```

## tinkerの終了

```
➜ q
```

または

```
➜ quit
```

または

```
➜ exit
```



# 素のｐｈｐのReplならpsysh
## psyshとは？
* rubyでいうirbみたいな事ができる
* Replライブラリ、インタラクティブ（対話）シェル　って言うらしい
* 他にborisってのがあるが、ｐｓｙｓｈの方が便利らしい
* デバッグもできる
* [参考サイト](https://pgmemo.tokyo/data/archives/1380.html)

# インストール
* 下記をコマンドラインから実行し、インストール

```
composer g require psy/psysh:@stable
```

* パスの追加（どこからでも実行できるようにする）

```
echo 'export PATH="$HOME/.composer/vendor/bin:$PATH"' >> ~/.zshrc
```

* 下記のようになれば、インストール成功

```
➜ psysh

Psy Shell v0.9.9 (PHP 7.2.19 — cli) by Justin Hileman
>>>
```

#hello world

```
>>> $temp = "hello world"
=> "hello world"
>>>
```

## ｐｓｙｓｈの終了

```
➜ q
```

または

```
➜ quit
```

または

```
➜ exit
```
git submoduleにprivateレポジトリを追加した際の注意点

GitHubでSubmodule使ってた際に躓いたのでレポート

---

SubmoduleとしてPrivateレポジトリを追加している既存のレポジトリをクローンした時に、`git submodule update`でパーミッションエラーが出た。

(エラーメッセージから一部抜粋)`git@github.com: Permission denied (publickey).`
とあるように`git@github.com`としてアクセス拒否されている、モジュールを追加してる大元のレポジトリにある`.gitmodules`を見てみると以下のようになっていた

```
[submodule "hoge"]
     path = hoge
     url = git@github.com:FOO/hoge.git
```
ここのurlをSSHじゃなくHTTPS経由に変更する

```
[submodule "hoge"]
     path = hoge
     url = https://github.com/FOO/hoge.git
```
これで`submodule update`でエラーが起こらなくなる
巷を騒がせているYahoo!スコアが勝手に企業に提供されるの件について

#Yahoo!スコアをオフにする方法
ヤフーが先日発表した信用スコア「Yahoo!スコア」について、「オフにしないと個人情報が企業に売り渡される」といううわさが流れており、ユーザーの同意なしで外部企業にスコアを提供することはないと否定されてはいるもののオフにしないと不安なYahooユーザーも多いかと思われます。
念のため手順を画像付きでご説明いたします。

##1.Yahooのトップページから登録情報をクリック
![1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/247810/d7679532-c0b5-c3d1-dc73-d80836b9fcae.jpeg)

##2.登録情報ページから、「プライバシー・メール配信」をクリック
![2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/247810/4f98a78d-b259-9491-8f58-cfb7dcd91cdc.jpeg)

##3.プライバシー・メール配信ページから「Yahoo!スコアの作成・利用」をクリック
![3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/247810/43f1d8b0-072e-4de0-09ed-96b20b7b6108.jpeg)

##4.Yahooスコアの作成利用の設定をオフにする
![4.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/247810/f9c7980d-c298-7b12-deae-73deb68fa566.jpeg)

完了です！！！

Twitterフォローお願いします（ゲーム、趣味垢）
https://twitter.com/webfrontend118
Laravelでメールをデフォルトとは別のメールサーバーで送信したい、かつ、キューも使用

# 前置き
[Laravelでメールをデフォルトとは別のメールサーバーで送信したい](https://qiita.com/shima0218/items/b3815d04a6d9a6e02e02)の続きです。

メール送信処理を画面で待ってると遅いなぁと思うときに、`Mail::queue($mail)`って書いて、キューに追加できるお膳立てをしておけば、メール送信処理はキューに入るので、サクッと次の画面いけちゃうあれです。

非常によい！！が、メールサーバーはそりゃデフォルトの使いますよね。
でも、デフォルトじゃないメールサーバー指定したいんだよという人のための記事です。
（キューの設定とか、supervisorうんぬんは、もうできちゃってる前提で行きます！！）

この記事を参考に作りました↓あざます！！！
[Laravel5でAWSのSQSを使う　複数のキューを処理する方法](http://nohohox.hateblo.jp/entry/2016/02/26/030616)

# 作業
## とりあえずJob作ろう

```
$ php artisan make:job MailSendJob
```

```php:app/Jobs/MailSendJob.php
<?php
namespace App\Jobs;

use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;

use App\Mail\AllMailSend;

use Swift_Mailer;
use Swift_SmtpTransport;

class MailSendJob implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    //メールの内容とかはプロパティに入れよう
    protected $content;

    public function __construct($content)
    {
        $this->content = $content;
    }

    public function handle()
    {
        //メール送信処理
        $backup = \Mail::getSwiftMailer();

        $transport = new Swift_SmtpTransport(config('mail.batch_mail_send.host'),
                                            config('mail.batch_mail_send.port'),
                                            config('mail.batch_mail_send.encryption'));

        $transport->setUsername(config('mail.batch_mail_send.username'));
        $transport->setPassword(config('mail.batch_mail_send.password'));

        $otherMailSetting = new Swift_Mailer($transport);

        \Mail::setSwiftMailer($otherMailSetting);

        $allMailSend = (new AllMailSend($this->content)->onConnection('batchMailSend'));
        \Mail::send($allMailSend);

        //メールの設定をもとに戻す
        \Mail::setSwiftMailer($backup);
    }
}
```

## キューに入れる側の処理
```php
<?php
//これだけ
\Queue::push(new \App\Jobs\MailSendJob($content));
```

# まとめ
これで、無事にキューに入れたメールも、指定したメールサーバーで送信できるようになりました。
おめでとう！
Ruby2.5.2以上でpryがどこかに飛んで行ってしまう

### 起きた現象

pryが正常に動かない

```ruby
class HomeController < ApplicationController
  before_action :redirect_signed_in_user, only: :welcome

  def welcome; end

  def redirect_signed_in_user
    binding.pry
    redirect_to root_url if user_signed_in?
  end
end
```

1度目は正常に動くが

```ruby
[20, 29] in /Users/ashwinhegde/code/apps/o3_crm/app/controllers/home_controller.rb
   20:
   21:   private
   22:
   23:   def redirect_signed_in_user
   24:     binding.pry
=> 25:     redirect_to root_url if user_signed_in?
   26:   end
   27:
```

2度目から

```ruby
[117, 126] in /Users/ashwinhegde/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/devise-4.4.3/lib/devise/controllers/helpers.rb
   117:             opts[:scope] = :#{mapping}
   118:             warden.authenticate!(opts) if !devise_controller? || opts.delete(:force)
   119:           end
   120:
   121:           def #{mapping}_signed_in?
=> 122:             !!current_#{mapping}
   123:           end
   124:
   125:           def current_#{mapping}
   126:             @current_#{mapping} ||= warden.authenticate(scope: :#{mapping})
(byebug)
```

このように謎のコードに進んで行ってしまう。

### 解決策

byebugのリポジトリに同じ現象のissueが立てられていた。

https://github.com/deivid-rodriguez/byebug/issues/452

Ruby2.5.2以上でbootsnapがインストールされている場合、pryが正常に起動しないらしい。

bootsnap/setupをdevelopmentのみでしかrequireしないようにboot.rbを修正。

```boot.rb
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
env = ENV['RAILS_ENV'] || 'development'

require 'bundler/setup' # Set up gems listed in the Gemfile.
require 'bootsnap/setup' if env != 'development' # Speed up boot time by caching expensive operations.
```
[AI,機械学習]画像認識をやってみた（不均衡データに対する簡単な対処法）

# 自作のデータセットで画像認識（分類）をするには？

今回が初めての記事の投稿となるので拙い文章およびプログラムですがご容赦ください。

昨今ディープラーニングをはじめとする機械学習技術が流行しています。僕自身（大学生）、自分が専攻する学部で流行っており、その流れに乗っかった一人です。
たくさんのわかりやすい本が毎日新しく出版されている中、僕や機械学習初心者が最初につまずくのはやはり、「自分の解決したい課題に向き合った時どうすればいいの？」という点だと思います。
今回はいわゆる画像認識のチュートリアルであるMNISTやcifer-10ではなく、自分で用意したデータセットで簡単に画像認識するにはどうすればいいのか、という点に焦点を絞って記事を書いていきたいと思います。（自分用のメモ程度ですww）
また少しだけ不均衡データの対処法ついても触れます。


## CNN and Clustering
ここら辺の技術等に関してはもうたくさんの解説がqiitaにもあるので割愛します。

## mnistライクなデータセットの作り方
いかにコードを載せます。
必要なモジュール等に関してはあらかじめ環境に入れといてください。
Laravelのイベントディスカバリを試してみる

皆さんEvent使ってますか？
わしは最近初めて使いました😇
イベント・リスナを使うとOberverパターンの実装ができるので
処理が独立化し、Controller等がよりスッキリしますよ☺️

さて今回は、Laravel 5.8.9から実装された **イベントディスカバリ** を使う機会があったので
サクッと紹介してみたいと思います！

## イベントディスカバリとは
Laravelでイベントを作成した場合は `EventServiceProvider` や `Subscriber` の中でイベント・リスナを登録する必要があります。
これを
**「所定のディレクトリにイベントを置いておけば自動で登録しといてあげるよー！」**
という親切機能がイベントディスカバリです。

詳細は公式ドキュメントの「イベントディスカバリ」項をご参照ください。
https://readouble.com/laravel/5.8/ja/events.html

## 何が嬉しいのか
イベント・リスナの登録作業は地味に面倒です。
もっとビジネスの本質に集中したい😤

また、サブスクライバを使う場合はイベント登録を忘れると「なぜか動かない」状態になってしまい、
原因追及に時間がかかってしまうことがあります（ありました）。

その点、イベントディスカバリは一度設定してしまえば、
イベント・リスナを所定のディレクトリに**作成するだけ**で登録できるので、
面倒な作業やハマりから解放されますね☺️

## 使い方
`EventServiceProvider`で`shouldDiscoverEvents()`をオーバーライドします。

```php:EventServiceProvider
public function shouldDiscoverEvents()
{
    // 親クラスでfalseになってるのをtrueで上書きする
    return true;
}
```
これで、Listenersディレクトリに作成したリスナが自動で登録されます！🙌

### 以上
簡単ですねー！


## [補足]何をやっているのか
シンプルでいいのですが記事としてあまりに寂しいのでもうちょっと調べてみました。

ソースを追っていくとメインの処理はこのあたりのようです

```php:DiscoverEvents.php
    protected static function getListenerEvents($listeners, $basePath)
    {
        $listenerEvents = [];

        foreach ($listeners as $listener) {
            $listener = new ReflectionClass(
                static::classFromFile($listener, $basePath)
            );

            foreach ($listener->getMethods(ReflectionMethod::IS_PUBLIC) as $method) {
                if (! Str::is('handle*', $method->name) ||
                    ! isset($method->getParameters()[0])) {
                    continue;
                }

                $listenerEvents[$listener->name.'@'.$method->name] =
                                optional($method->getParameters()[0]->getClass())->name;
            }
        }

        return array_filter($listenerEvents);
    }
```

`ReflectionClass`や`ReflectionMethod`を使って
所定のディレクトリからListerのhandleメソッドを取得し、
`$listenerEvents[リスナ@handle名] = イベントのクラス名`の形式にして返してます。

他のところでデータの加工などしていますが、最終的には`EventServiceProvider`（親クラスの方）で、
手動登録したイベント・リスナとガッチャンコで処理されるという仕組みのようです！

## [補足]サブスクライバー使ってるとどうなるの？
結論から書くと、Subscrivberを使っていても問題なかったです！
今回元の実装がSubscriberのhandleの引数にイベントクラスの`interface`を取っていたけど、
これはこれで別に問題ないらしい。

```php:PiyoEventSubscriber
class PiyoEventSubscriber implements ShouldQueue
{
    public function subscribe(Dispatcher $dispatcher)
    {
        // 前はここで $dispatcher->listen() してイベント登録していた
    }

    // PiyoEventはinterface
    // これを実装したイベントクラスがたくさんある
    public function handle(PiyoEvent $event)
    {
        $event->send();
    }
}
```

## 以上
指摘・補足などあればコメントいただけると嬉しいです！