OmniAICreator/Qiita-1.07M huggingface dataset:
enum検索入力


##enum定義

```customer.rb
 enum status: { not_app: 0, app: 1 , cancel: 2}
```
statusの型はinteger

参考：https://qiita.com/shizuma/items/d133b18f8093df1e9b70



```customer.rb

def self.search(params)
  customers = customers.where(status: params[:status]) if params[:status].present?
end
```

##検索(コントローラ)

```customers_controller.rb
def index
 @customers = Customer.search(params)
end
```
##検索(ビュー)
```index.html.erb
<%= form_tag( {:action => :index}, :method => :get) do %>
===========================
#ラジオボタンの時
<tr>
  <th scope="row">ステータス</th>
   <td> 
     <%= radio_button_tag :status, 1, params[:status] %><label 
      for="status_1">有効会員</label> 
      <%= radio_button_tag :status, 0, params[:status] %><label 
      for="status_0">退会済</label> 
      <%= radio_button_tag :status, 2, params[:status] %><label 
      for="status_2">ブラック会員</label> 
   </td>
===========================
#セレクトボッックスの時
<tr>
  <th scope="row">ステータス</th>
    <td colspan="3">
      <%= select_tag :status, Customer.statuses.keys.map {|k| [I18n.t("enums.customer.status.#{k}"), k]} %>
    </td>
 </tr>
===========================
<% end %>
```

##gemインストール
```gemfile.
gem 'enum_help'
```

```
$ bundle install
```

##日本語化
```ja.yml
enums:
  customer:
    status:
      app: 有効会員
      not_app: 退会済
      cancel: ブラック会員

　#これ書かないとセレクトボックスのところでちゃんと表示されない
```


受け取ったstatustの値が見たいときは`status_i18n`で表示できる

参考:(i18n): https://tech.misoca.jp/entry/2015/08/10/132419
参考(select): https://qiita.com/HrsUed/items/56677d6c266d8a53ffa7
django heroku デプロイ後 おっちょこちょい

django girlsのチュートリアル通りにデプロイをした後に、コンタクトフォームから何かを送信すると「internal server error 500」が。

なんでやろ〜って考えてたらおっちょこちょい仙人登場。

djangoはデフォルトでsplite3をデータベースとして使うようになっているけど、
herokuでは、postgresqlを使うのである。

なのでデプロイ後に、
$ heroku run python manage.py migrate
をする必要が。

管理者サイト（admin）に入るのであれば再度
$ heroku run python manage.py createsuperuser
をする必要があるんです。

忘れないように、俺。

以上おっちょこちょい劇場でした。
anyenv から入れた nodenv で Node.js を入れたときのメモ

# 本記事について

「りあクト！」[^1]を読みはじめ、本のように「anyenv 経由で ndenv をインストールして、ndenv で Node.js をインストール」しようと思ったら、anyenv で ndenv をインストールできないなど、状況が変わっていてハマったため残したメモです。

# 環境

- OS：macOS Mojave
- シェル：zsh
- homebrew インストール済み
- これまで nvm を使用

# 概要

結局今回は以下でインストールが完了しました：

1. anyenv をインストール
1. anyenv 経由で nodenv をインストール
1. nodenv で Node.js をインストール
1. これまで使っていた nvm のアンインストール

# anyenv のインストール方法

[GitHub - anyenv/anyenv: All in one for **env](https://github.com/anyenv/anyenv)

README にはまず homebrew でのインストールが紹介されているが、ブログや Qiita を見ると多くが git clone でインストールしている。homebrew 版はかなり最近なんだろうか。

こちらでは両方の方法が紹介されている。
https://qiita.com/rinpa/items/81766cd6a7b23dea9f3c

# anyenv のインストール

今回は homebrew でインストールしてみる。
[README](https://github.com/anyenv/anyenv/blob/master/README.md) に従う。

```
$ brew install anyenv

$ anyenv init
# Load anyenv automatically by adding
# the following to ~/.zshrc:

eval "$(anyenv init -)"
```

`$ anyenv init` を打ったら指示が出てきた。指示の通りに `~/.zshrc` に追記。
そしてターミナル再起動。すると（README の通り）次の warning が出る。

```
ANYENV_DEFINITION_ROOT(/Users/xxx/.config/anyenv/anyenv-install) doesn't exist. You can initialize it by:
> anyenv install --init
```

warning の通り実行。

```
$ anyenv install --init
Manifest directory doesn't exist: /Users/xxx/.config/anyenv/anyenv-install
Do you want to checkout ? [y/N]: y
Cloning https://github.com/anyenv/anyenv-install.git master to /Users/xxx/.config/anyenv/anyenv-install...
Cloning into '/Users/xxx/.config/anyenv/anyenv-install'...
remote: Enumerating objects: 44, done.
remote: Counting objects: 100% (44/44), done.
remote: Compressing objects: 100% (39/39), done.
remote: Total 44 (delta 1), reused 43 (delta 1), pack-reused 0
Unpacking objects: 100% (44/44), done.

Completed!
```

# ndenv のインストール（できない）

anyenv で ndenv が入れられない。

```
$ anyenv install ndenv
anyenv-install: definition not found: ndenv
```

[ndenv は非推奨になっていた](https://github.com/riywo/ndenv) 。

# nodenv のインストール

ndenv の代わりに nodenv が推奨になっていたため、こちらをインストール。

```
$ anyenv install nodenv
$ exec $SHELL -l
```

# Node.js のインストール

```
$ nodenv install -l
$ nodenv install 12.0.0
```

```
$ node -v
v7.6.0
$ npm -v
4.1.2
$ nodenv global 12.0.0
$ node -v
v7.6.0
$ npm -v
4.1.2
```

インストールしたはずの node v12.0.0 が呼び出せない。
（nvm など使ってない方はここで呼び出せるはず？）

# nvm のアンインストール（必要な人のみ）

ここで、自分がこれまで nvm を使っていたことを思い出し、nvm をアンインストールすることに。
（nvm 使ってなかった人は、すでに新しく入れた node が使えてるかと思うので以下は関係ないです。）
アンインストール方法は [GitHub の README を参照](https://github.com/creationix/nvm)。

```
➜  ~rm -rf "$NVM_DIR"
```

（つまり `~/.nvm` の削除）

そして `~/.zshrc` の下記を削除：

```
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"  # This loads nvm
```

確認：

```
$ node -v
v12.0.0
$ npm -v
6.9.0
```

呼び出せた :tada: 

~~やっと本の続きが読める~~


[^1]: https://oukayuka.booth.pm/items/1312652
Pythonについて勉強しなおしてみた

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/398359/180b2da4-0755-572c-ffeb-18c8705845d5.png)

恥ずかしながらPythonはググった内容をもとに雰囲気でLambda組んだりとあまり使いこなせていませんでした。
しかし機械学習の勉強の中でpythonを使っていくうちに使いやすい言語だなと感じ、いまさらながら勉強し直してみようと思いました。

#### 参考
https://ja.wikipedia.org/wiki/Python
https://docs.python.org/ja/3/tutorial/controlflow.html
https://qiita.com/yaju/items/5502115d7e3d06e6bbdd

## Pythonとは
#### 概要
- 1991年ごろに登場した汎用の高水準プログラミング言語
- すべてのリリースが**オープンソース**([PSFライセンス](https://docs.python.org/ja/3/license.html)。GPL互換)
- **インタプリタ**での実行
- 核となる機能は最小限であり、標準ライブラリ、サードパーティーライブラリなどを**目的に合わせて無料で機能拡張**できる
- **多くのプラットフォームに対応**：　Windows, Macintosh, iOS, Android, Linux・・・
- 名前の由来は、イギリスのテレビ局 BBC が製作したコメディ番組『空飛ぶモンティ・パイソン』。ロゴはpython=ニシキヘビを表している。

#### 特徴
- **読みやすく、効率的に、簡単で短いコード実装思想**。 →　開発における**作業性が高い**
- **動作の実装方法が基本的に一通り**。 →　だれが書いても同じ書き方になり**可読性が高い**
- その他特徴的な点
    - **動的な型付け**：　使用前の型宣言が不要。変更への対応が柔軟で、特にコレクションでは利便性が高い。
    - **ガベージコレクション**：　使用しなくなったメモリを自動で開放。
    - **マルチパラダイムプログラミング言語**：　オブジェクト指向、命令型、手続き型、関数型など複数の特性を併せ持つプログラミング言語
    - **モジュール、クラス、オブジェクト等の言語の要素が内部からアクセス可能であり、リフレクションを利用した記述が可能。
    - **インデントのオフサイドルール**：　インデントによって

#### 世の中の利用状況
- Webアプリケーションやデスクトップアプリケーションなどの開発はもとより、システム用の記述 (script) や、各種の自動処理、理工学や統計・解析など、幅広い領域で使用されている
- Google、Facebook、Yahoo、Lucasfilm Ltd.などの大企業で、社内言語として利用されている。
- YouTube、Instagramなどが開発されていることは有名。
- 機械学習についてはPythonほぼ一択

#### なんではやってんの?
- 開発のしやすさ、メンテナンスのしやすさが重要視される軽い処理にてPythonの特徴がマッチしていたよう。
- そのような理由からGoogle, Facebookなどが利用し始め、一般化した。
- 機械学習においては、listの対応などで早期から注目され、その後のライブラリの拡充（Matrix Object in Python、NumPy、SciPy）で一般化したよう

## 最後に
Pythonすごいですね
いままであまり使ってきませんでしたが、使ってみると非常に開発しやすく可読性も高いなと思いました。
たとえばインデントのオフサイドルールなどがいいなと思いました。会社の昔のソースコードはインデントが正しく行われていなかったり一行で書かれていたりするものもが多々あり可読性が低いなと感じてました。これがだれが書いても同じようにインデントされるというのは非常に良いと思います。
今後いろいろ使っていけたらなと考えております。
試し書き

VisualStudioのDataGridViewはデータベースの中身をそのまま見るにはすごく便利に見える
なのでデータの中身を確認するためにとりあえず下の単純なコードを書いてみた。
データベースはPostgresを使用しており、また「dbCon」はデータベースのConnectionを別の個所で宣言してある。

            DataSet ds = new DataSet();

            NpgsqlCommand cmd = new NpgsqlCommand();
            NpgsqlDataAdapter nda = new NpgsqlDataAdapter();

            cmd = new NpgsqlCommand();
            cmd.Connection = dbCon;
            cmd.CommandText = "SELECT dno , ddate FROM tbldetails AS detail ORDER BY ddate ASC;";

            nda.SelectCommand = cmd;
            nda.Fill(dt);

            dataGridView1.DataSource = dt;

いろんなサイトを見てみたがこれで問題はなさそうだ。
。。。。が、表示されない。

その後しばらくいくつかのサイトを見て回ると、DataSetの代わりにDataTableを使っているサイトがあった。
試しにやってみた。

            DataTable dt = new DataTable();※中略
            dataGridView1.DataSource = dt;

・・・・・表示された。なんでや。
確かにどこのサイトもSQLCommandを使用していてnpgsqlを使用しているサイトはなかった。

仕様かもしれないので今度調べて記事は更新したい。
ABC089 C - March(300点)

#問題概要
[問題のリンク](https://atcoder.jp/contests/abc089/tasks/abc089_c)

$N$人の人がいる。
以下の条件を満たすように3人選ぶ。

- 全ての人の名前が $M$,$A$,$R$,$C$,$H$ のどれかから始まっている
- 同じ文字から始まる名前を持つ人が複数いない

この時何通りの選び方があるか。ただし選ぶ順番は関係ない。

#制約条件
- $1≤N≤10^5$
- $S_i$ は英大文字からなる
- $1≤|S_i|≤10$
- $S_i≠S_j(i≠j)$

#考えたこと
先頭の文字が重ならないように選ぶ選び方を考える。

例えば、M,A,R,C,Hから名前が始まる人がそれぞれ1人ずついる場合、以下の選び方で全てであり10通りになる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326440/143fcfd0-ea94-0a3f-3d00-75608a296409.png)
上の図が基本モデルとなる。
まず名前の先頭の文字がM,A,R,C,Hである人の数を数え上げて配列に詰めていく。
重複があってはいけない、かつ選ぶ順番は関係ないので、M,A,R,C,Hを上の図のように組み合わせていき、乗算をしていく。

この時計算量は$O(N)$となるので、問題なくAC。

#解答
```c.cs
using System;
using System.Linq;

class Program
{
    static void Main(string[] args) {
        int n = int.Parse(Console.ReadLine());
        long[] l = new long[5] {0,0,0,0,0};
        for(int i = 0; i < n; i ++) {
           string s = Console.ReadLine();
           if(s[0]=='M') l[0] ++;
           if(s[0]=='A') l[1] ++;
           if(s[0]=='R') l[2] ++;
           if(s[0]=='C') l[3] ++;
           if(s[0]=='H') l[4] ++;
       }
       Console.WriteLine(solve(l));
    }
    static long solve(long[] l) {
        long count = 0;
        for(int i = 0; i < l.Length-2; i ++) {
            for(int j = i+1; j <= l.Length-2; j ++) {
                count += l[i] * l[j] * (l.Where((x,y) => y > j).Sum());
            }
        }
        return count;
    }
}
```
FileProvider.GetUriForFileでハマった（Java.Lang.NullPointerException、Java.Lang.IllegalStateException）

  
  
VIsualStudio2017, XamarinでAndroidアプリの勉強中、
FileProvider.GetUriForFileでハマりました。

##起こったエラーと解決方法
* ####Java.Lang.NullPointerException
  providerが<application>タグの外に出ていた。
入れ子になっていないと読み込んでくれなかった。

* ####Java.Lang.IllegalStateException
SpecialFolder.Personal（内部領域）を使用しているのに、
filepaths.xmlのタグがfiles-pathではなくexternal-pathになっていた

---
まず、前提として「file://～」を使った書き方はAPIが更新されていて使えないので、FileProviderを使ったやり方で実装しましょう（2019/4月）
※でも、Webのブログなどにはfileを使ったやり方がたくさんのっていて辛かった。

ちなみに、AndroidのReferenceは僕には合わなかった。
Xamarinのドキュメントが充実しているので（Androidのやきなおしだが・・・）
Xamarinを見るか、海外のフォーラムを見るのが情報が新鮮でよかったように思う。
みんなAPIとxmlの定義で苦戦していたので、どの世界も同じようだ。

```sample.cs

//Androidのファイル・ディレクトリ取得
var folderPath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
var fileName = folderPath + @"/sample.tsv";

/* 途中、省略 */

Android.Net.Uri uri = FileProvider.GetUriForFile(this,
                         this.ApplicationContext.PackageName+ ".provider",
                         new File(path));
```

```filepaths.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <files-path name="share" path="." />
</resources>
```

```AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="io.github.muyoku.MrTimeRecorder" android:installLocation="auto">
	<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="27" />
	<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
	<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
	<application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme">
		<provider android:name="android.support.v4.content.FileProvider" android:authorities="${applicationId}.fileprovider" android:exported="false" android:grantUriPermissions="true">
			<meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/filepaths" />
		</provider>
	</application>
</manifest>
```

ちゃんとAndroidの基礎も抑えずにコード書いてせいでハマッたんだと思う。
Xamarinといっても、普段慣れ親しんだ言語出かけるだけなので、
ライフサイクルとかファイル構成とかAndroidの基礎的な思想を学んでからのほうが近道だったように思う。

特にストレージを触るなら、内部領域と外部領域の話を抑えてからのほうがいいと思う。
以下、問題解決で参考にしたサイト

★外部領域と内部領域の話　
https://docs.microsoft.com/ja-jp/xamarin/android/platform/files/

★外部、内部領域でXmlのタグ名が違う。外部の場合のみexternalで始まるものを使用する。
http://yuki312.blogspot.com/2014/04/androidfileprovider.html

・AndroidManifest、providerがapplicationタグのそとに書かれていたので参照できずヌルぽが発生
http://mo3789530.hatenablog.com/entry/2018/07/30/093434

・親切な人の解説
https://stackoverflow.com/questions/40462245/fileprovider-xamarin-not-displaying-file

・getExternalFilesDirs（外部領域からのファイルパス取得API)
https://stackoverflow.com/questions/42516126/fileprovider-illegalargumentexception-failed-to-find-configured-root

ありがとうございました。
はじめてのC++ 【42日目】

# はじめに
この一週間ブロック崩しを作ってみて、オブジェクト指向の難しさに気づいた。
## ブロック崩し　【OF】
### 現在の進行状況

```:ファイル一覧
# main関数みたいなもの
Game.h       
Game.cpp

# オブジェクトクラス ( Circle, Box, Bar )　の親クラス
# 継承を使いたかったので無理やり導入
Object.h

# Objectクラスの子クラス
# ブロック崩しの "バー"　の部分を定義している
Bar.h
Bar.cpp

# Objectクラスの子クラス
# ブロック崩しの "ブロック"　の部分を定義している
Box.h
Box.cpp

# Objectクラスの子クラス
# ブロック崩しの "ボール"　の部分を定義している
Circle.h                       
Circle.cpp

# インスタンスを作るためのクラス
# 実装途中...。
CreateFactory.h
CreateFactory.cpp

# ゲーム作りは、 'pos.x' とかを使うと便利ときいたので、
# operator関数の練習も兼ねて実装した
# かなり勉強になった
# Objectクラスで使っている。
Vector2D.h           
Vector2D.cpp

# 当たり判定のクラス
# 実装途中...。
Collision.h 
Collision.cpp       
```

### オブジェクト指向
実際にブロック崩しを作っていると、もやもやした気持ちになった。それは、他のインスタンスの情報は、引数で受け取る方法をしていると、引数が10個くらいになってしまうと気がついた。

```.cpp:例
Bar bar;//インスタンス生成
Circle circle;
void execute(double bar.pos.x,double bar.pos.y, double circle.pos.x, ........ );
```
このように必要な情報を引数に入れて情報を渡していると、大規模プロジェクトならいつか限界が来ると感じた。そこで、「インスタンスのアドレスを関数で渡したら多少ましになるのでは？」と考えたが、インスタンスの数が多すぎるとこの方法も使えない。ネットで検索していると、オブジェクト指向を取り入れる必要があるという結果がでてきた。オブジェクト指向ってかなり難しいことを身をもって体感した。

### 今後
<img width="1194" alt="IMG_6B41CA1F256B-1.jpeg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298612/3a7bab8e-53d6-1f0b-8c56-4723f00dc5a6.jpeg">
このような実装を目指している。
`ボールの跳ね返り` や `Barをキーボードからの入力`　は、お互いのオブジェクトに干渉しないので、 `それぞれのクラスのヘッダファイル`　に実装してもおかしくないだろう。 問題は `setup` で生成したインスタンスをどのようにして、 `Bar_collisionクラス` や `Block_collisionクラス` で使用するのか。オブジェクト指向を学ぶいい機会かもしれない。
ブロック崩しといえば、 `Block`　を大量に生成しなければならない。この場合、インスタンスを大量に生成するにはどうすればいいのか？と、疑問に思った。ネットには、　`動的配列を使う` とか `newを使う`　など様々な意見があった。仮に `new`　を使うなら `std::make_shared`　を実践で使うときが来たのかなと感じて少しうれしい。もうすこし調べる必要がある。　
あと、ソースコードが大量にあるのでさすがに直接コードを貼るのは気が引ける。他の方たちは、gitで自分の制作物を作っているみたいなので、私もgitを使ってみようかなと考えている。
##ロベールのC++
ブロック崩しの実装に夢中になって手つけてなかったので久しぶりにやる。
###クラスのテンプレート
関数のテンプレートだけではく、クラスのテンプレートもできる。これは便利だな。
ふと思ったが、 `ブロック崩しのVector2Dクラス` も `Templete` で実装したほうが良さそう。いまは、double型で固定しているので、templeteになおしてみる。
#終わりに
ロボットプログラミングに興味が出てきました。 [ROS](https://qiita.com/srs/items/5f44440afea0eb616b4a) という （いまいちよくわかっていないが）　のを使うと C++で開発ができるみたい。しかも、 `ラズベリーパイ`　という 小さいコンピュータ？　を使って実際に動かすことができるのも面白そう。 プログラミングをできると、遊びの幅がかなり広がる。しかも、お金は電気代だけっていうね。最高だよほんとに。
Unity 2019 2.0βでのVRM Importerのバクの対処方法

#動機
unityの**2019 2.0β**が出ていたので、しばらく触っていたらVRMをインポートしたところ、下の写真のように目元や眉などがすごく変になっていました。
**2019 2.0β**だけではないかもしれないけれど、そこはまだ検証していません。
色々と試行錯誤していくうちに、無事に解決できたので、その方法を紹介したいと思います。

UniVRM-0.51.0_1b36を使っています。
![fall.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/404889/7bffb1f7-5041-b052-5670-78649c3e458b.png)
#原因
![fall2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/404889/2f705afc-0b45-aac4-b284-3859df03ff9b.png)
上の画像をよく見たら分かると思いますが、**Materialの余白の部分が透過処理されていない**のが原因です。本来あるべき余白の部分がUnityによって黒く塗りつぶされています。
#解決方法
下の写真の赤く囲っている部分をクリックして**Shaderを変えます**。
**VRM/unitcutout**に変えます。
VRMのMaterialを一つ一つ**VRM/unitcutout**にかえて、おかしくなった所は**VRM/Mtoon**のまま置いておくと、だいたいいけます。
しかし、**眉毛だけは白くなってしまう**ので、そこはPhotoShopなどでTextureを塗ってください。
![fall3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/404889/4ece8575-8e7b-42fc-0ee9-29d9dd4c486c.png)
#結果
![fall4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/404889/3d0fa57c-6284-1ade-1771-e436a7d383e7.png)
以上を行うとこうなります！
#最後に
3DゲームやVRゲームを作るとは、やっぱりVRMモデルを使う人も多いと思うので、バグったときは試してみてください！
AURにパッケージを登録するときの罠

ArchLinux には [AUR](https://aur.archlinux.org/) っていうコミュニティベースのパッケージリポジトリがあります。
AUR には個人が自由にパッケージが登録できるし、その登録も専用の git リポジトリに `PKGBULD` を push するだけなのでとても簡単です。

PKGBULD の作り方や AUR への登録の仕方は ArchWiki の [PKGBUILD](https://wiki.archlinux.jp/index.php/PKGBUILD) や [パッケージの共有](https://wiki.archlinux.jp/index.php/Arch_User_Repository#.E3.83.91.E3.83.83.E3.82.B1.E3.83.BC.E3.82.B8.E3.81.AE.E5.85.B1.E6.9C.89) を見て下さい。Qiita にもちょっと古いですが [簡単! パッケージを作成してAURへ登録しよう](https://qiita.com/dseg/items/32807a9305801f2d430c) という記事があります。

パッケージの登録はとても簡単なんですが、リポジトリに push するときにたまに登録をはじかれる事があったりします。git の update hook に https://git.archlinux.org/aurweb.git/tree/aurweb/git/update.py が登録されていて、この人が色々チェックしてるんですね。そんな罠をいくつか紹介します。

## 全ての commit に PKGBUILD と .SRCINFO がないといけない

`.gitignore` から作りはじめたり、`.SRCINFO` を後から追加したりするとはまります。

https://git.archlinux.org/aurweb.git/tree/aurweb/git/update.py?h=v4.7.0#n275 でチェックしてます。

## 全ての commit で PKGBULD や .SRCINFO のフォーマットが正しくないといけない

途中のコミットに中途半端なのがいたりすると怒られます。フォーマットが正しくないといけないのは分かるんですが、もうちょっと緩くてもいいのにと思います。

https://git.archlinux.org/aurweb.git/tree/aurweb/git/update.py?h=v4.7.0#n295 から先のあたりでチェックしてます。

## サブディレクトリが存在してはいけない

パッチを別ディレクトリに置いておいて整理するとかができません。
また、Github にもリポジトリを置いておいて、パッチのテストを CI したい時に CircleCI が使えません (`.circleci/config.yml` が無理)。TravisCI を使いましょう。

https://git.archlinux.org/aurweb.git/tree/aurweb/git/update.py?h=v4.7.0#n283 でチェックしてます。


## おわりに

こんな所でしょうか。たまーに困ることがありますが、大抵は rebase で何とかなる範囲です。それでは、良き AUR ライフを。
awkで表のラベルでフィールドにアクセスする


表のパースといえばawkなのだが、いかんせんコーディング時しかカラムとラベルの対応を覚えておらず後々コードが読めなくなるのでラベルでアクセスするimportを作った。

```shell:import_label_access
echo '\
function _set_label(   i) {
  for (i=1; i<=NF; i++) F[$i]=i
}
BEGIN {
  if (HEADER_LINE=="") HEADER_LINE=1
  if (HEADER_LEN=="")  HEADER_LEN=1
}
NR==HEADER_LINE {_set_label()}
NR<HEADER_LINE+HEADER_LEN {next}
'
```

### 例
```shell:sample
awk -v HEADER_LEN=2 "`./import_label_access`"'
  {print $F["label2"]}
'
```

```
$ cat << EOF | sh sample
label1 label2 label3
------ ------ ------
1      2      3
a      b      c
EOF
2
b
$
```
コンソール出力する CodePen を埋め込みたい

CodePen 上ではコンソール出力を確認することができるが、
埋め込むと確認できなくなるようだ。

なので HTML 上に出力する関数を作成した。

```JavaScript
function println(text) {
    const textNode = document.createTextNode(text);
    const div = document.createElement("div");
    div.appendChild(textNode);
    document.body.appendChild(div);
}
```

これで埋め込むと。

<p class="codepen" data-height="283" data-theme-id="0" data-default-tab="js,result" data-user="sdkei" data-slug-hash="MRPdwg" style="height: 283px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid black; margin: 1em 0; padding: 1em;" data-pen-title="FizzBuzz">
  <span>See the Pen <a href="https://codepen.io/sdkei/pen/MRPdwg/">
  FizzBuzz</a> by sdkei (<a href="https://codepen.io/sdkei">@sdkei</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>
Google AIY Voice Kitを改造してIoT部屋を作ってみた(2)

#前回の続き

※今回の記事では、内容がハードウェア寄りとなっております。

前回の作業でデモプログラムの「assistant_library_with_local_commands_demo.py」を編集して、任意のワードで照明をON,OFFすることができるようになりました。
今回はその筐体の設計と加工の様子について記載したいと思います。
#1. そもそもなんで入れ物を設計したの？
よくこの質問を友人からされることが多いです。そりゃそうですよね、キットには既にダンボールで作られたRaspberry Pi3とスピーカに合わせたサイズの簡単に組み立てられるボックスがついてるのに、それをただ組み立てて収めればいいだけなのに

ど　う　し　て　こ　う　な　っ　た
![DSC_0006.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399916/5bcbc04b-79d1-6dd4-a737-37f6616e76bf.jpeg)
![DSC_0007.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399916/ddcf23e9-44f0-b174-c581-5cb901b1fd9c.jpeg)

(めっちゃガチムチです。)
理由としては、僕がなかなか起きれないからです。AIスピーカに「Ok,Google △△時にアラームつけて」と言うと目覚ましの機能をONにして、任意の時刻に目覚ましをかけてくれます。そして、アラームを止める際に緑色のボタンを押すのですが、全力でたたいてしまい段ボールが逝きました・・・
このような事態を防ぐことが今回筐体を設計した理由になります。
#2. Inventorでの設計
筐体は3DCADであるAutodesk社のInventor 2017 Professionalを用いて設計を行いました。
緑の塊はRaspberry Piにキットに付属していたシールドをつけたときのサイズに合わせてあります。![SnapCrab_Autodesk Inventor Professional 2017 - [mainiam]_2019-4-24_15-51-54_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399916/449a1dda-a447-2763-b9aa-2a3d98842316.png)![SnapCrab_Autodesk Inventor Professional 2017 - [mainiam]_2019-4-24_15-54-20_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399916/c6b286a9-64bb-cdc3-dba0-a0e51f3dc290.png)
![SnapCrab_Autodesk Inventor Professional 2017 - [mainiam]_2019-4-24_15-54-39_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399916/97eb1654-7047-0dd6-69dc-910467c5d068.png)
#3. 加工
構成としては、強度を確保するために外側のフレームを10×10 t1の角管を、剛接合で組みました。
さらに、CNC(Computerized Numerical Control、一般的にCNCフライスと呼ぶ。)を用いて、天板やRaspberry Piを乗せておく台などの板パーツを加工しました。板厚はt1.5(筐体の側面部分)及びt2(ボタンとレベルメータを取り付けるための天板)を使用しています。

加工の様子↓
![DSC_0003.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399916/700b4873-51f6-81a2-5905-10c42cab4511.jpeg)

また、10×10の角管の加工はロータリーバンドソーで切断後、ボール盤で穴あけを行いました。
#4. 組み立て
初めにフレームを組み立てます。この時点でもう結構強い()![D3Ow1efUYAIcVsE.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399916/23f0a436-f7c7-0130-da66-892b8a7903e4.jpeg)次にCNCで加工した板をCAD通りに順にねじ止めしていきます。ついでに基板も取り付けます。![DSC_0008.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399916/a52330d0-51b2-3173-18c4-d265d5fcd3c0.jpeg)
#5. やっと完成！
筐体ができあがりました！あとはプログラムに機能追加しましょう！！![DSC_0009.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399916/b8dd6a97-2f8e-380a-059a-236e0f1876d6.jpeg)
文量が多くなってしまったので、次回は音楽を流す・webラジオを聴けるようにしていきたいと思います。さらに、音量に反応してLEDの点灯数が変化するレベルメータ回路の追加を行います。
virbr0を削除

■virbr0 削除
①ネットワークの状態を確認する。
[root@localhost network-scripts]# virsh net-list
 Name                 State      Autostart     Persistent
----------------------------------------------------------
 default              active     yes           yes

↑上記設定されている

②defaultネットワークがvirbr0を作っているか確認する。
[root@localhost network-scripts]# virsh net-dumpxml default
<network>
  <name>default</name>
  <uuid>e251bffe-f013-40ed-bd39-e238c95496a2</uuid>
  <forward mode='nat'>
    <nat>
      <port start='1024' end='65535'/>
    </nat>
  </forward>
  <bridge name='virbr0' stp='on' delay='0'/>
  <mac address='52:54:00:68:a5:1b'/>
  <ip address='192.168.122.1' netmask='255.255.255.0'>
    <dhcp>
      <range start='192.168.122.2' end='192.168.122.254'/>
    </dhcp>
  </ip>
</network>

↑作っている。

③virbr0を削除する
[root@localhost network-scripts]# virsh net-destroy default
Network default destroyed

④defaultネットワークの設定確認
[root@localhost network-scripts]# virsh net-list
 Name                 State      Autostart     Persistent

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

[root@localhost network-scripts]# brctl show
bridge name     bridge id               STP enabled     interfaces

⑤virbr0が再起動したときに作成されないようにする
[root@localhost network-scripts]# virsh net-autostart default --disable
Network default unmarked as autostarted
colaboratory上のMeCabで複数のユーザ辞書を指定する。

colaboratory上でmecabを動かす際に、ユーザ辞書を複数追加したくなったためやったもの。
科学技術系のワードをデフォルトの辞書ではなくて抜き出したかったため
[科学技術用語形態素解析辞書](https://dbarchive.biosciencedbc.jp/jp/mecab/desc.html)の中の
・JSTシソーラス見出し語・同義語辞書
・日化辞辞書
のdic＋自分で定義したdicの３つを追加した。

    
    #mecabのインストール
    !cd ../usr/local/lib
    !sudo apt install mecab
    !sudo apt install libmecab-dev
    !sudo apt install mecab-ipadic-utf8

    #ユーザ辞書用のフォルダ作成
    !mkdir ../var/lib/mecab/dic/userdic

    #日化辞、ＪＳＴのdicをダウンロード。上で作ったユーザ辞書用のフォルダに置く。
    !curl -o ../var/lib/mecab/dic/userdic/Nikkaji.dic ~~(適当な場所)/Nikkaji.dic
    !curl -o ../var/lib/mecab/dic/userdic/Thesaurus2015.dic ~~(適当な場所)/Thesaurus2015.dic

    #追加のユーザ辞書作成。上と同じフォルダに追加
    import pandas as pd    
    df_userdic = pd.read_csv("~~.csv",header=0) 
    #df_userdicはIPA品詞体系と同じ並び
    df_userdic.to_csv('../content/userdic.csv',header=None,index=False
    ,encoding='utf-8')

    !/usr/lib/mecab/mecab-dict-index \
    -d /var/lib/mecab/dic/debian \
    -u /content/userdic.dic \
    -f utf-8 \
    -t utf-8 /content/userdic.csv
    !mv -f /content/userdic.dic /var/lib/mecab/dic/userdic/userdic2.dic
    
 
    #mecabrcの置き換え:Nikkaji.dic、Thesaurus2015.dic、userdic2.dicを
    #ユーザ辞書として指定したmecabrcに置き換え。
    #colaboratoryだとviなど使えずmecarcを直接編集できないので、
    #一回他でmecabrcのuserdic=の部分を下記のような感じで書き換えておく。
    userdic = /var/lib/mecab/dic/userdic/Nikkaji.dic,/var/lib/mecab/dic/userdic/Thesaurus2015.dic,/var/lib/mecab/dic/userdic/userdic2.dic
    
    !curl -o /etc/mecabrc  ~~適当な場所/mecabrc
    !pip install mecab-python3==0.7
    import MeCab

これでmecabを複数のユーザ辞書を読み込んだ上で使えるようになった。
ユーザ辞書をgoogle spreadsheetで作成して、読み込み用にcsvファイルとして公開すれば、複数人で追加のユーザ辞書を追加しつつ、ほぼリアルタイムに更新後ユーザ辞書を
使った形態素解析ができる。
TestとTrainingデータを分けましょう

前回はここまでやりましたが↓、今回はまず変換されたデータをTestデータとトレーニングデータを分けようと思います。

画像データをnumpyに変化しよう
https://qiita.com/soup01/items/8aa977246de3bacfa7ed

#ライブラリーインストール
```
pip install scikit-learn
```

#コード
```
#Create the testing data and training data

#Split arrays or matrices into random train and test subsets
x_train,x_test,y_train,y_test=train_test_split(X,Y)
#map these files to a file
xy=(x_train,x_test,y_train,y_test)

#save as files
np.save('./animal.npy',xy)
```

ここで使われてるFunctionはsklearn.model_selection.train_test_splitです。
https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.train_test_split.html
ランダムでデータをTestingとTrainingデータ分けることができます、デフォルト値0.25です。
つまり、75%はTestingデータになり、Trainingデータは25%です。
そして最後numpyのsave()を使ってデータをテキストに保存します。

#Script全体
```
from PIL import Image
import os,glob
import numpy as np
from sklearn.model_selection import cross_validate

#the name of your classes but also the path name
classes=['clsA','clsB','clsC']
num_classes=len(classes)

#resize the image to 50px
image_size=50

#load the images

#image data
X=[]

#label data
Y=[]

for index,clss in enumerate(classes):
    photos_dir='./'+clss
    #get the same pattern of files
    #in this case is .jpg files
    files=glob.glob(photos_dir+'/*.jpg')
    for i,file in enumerate(files):
        #in this apps, only have 200 pictures
        if i >=200:
            break

        image=Image.open(file)
        image=image.convert('RGB')
        image=image.resize((image_size,image_size))
        data=np.asarray(image)

        X.append(data)
        Y.append(index)

#change to numpy array
X=np.array(X)
Y=np.array(Y)

#Create the testing data and training data

#Split arrays or matrices into random train and test subsets
x_train,x_test,y_train,y_test=train_test_split(X,Y)
#map these files to a file
xy=(x_train,x_test,y_train,y_test)

#save as files
np.save('./cls.npy',xy)

```
UnityでAnimationかParticleを使うか迷ったときの判断方法

## UnityでAnimationかParticleを使うか迷ったときの判断方法
Unityを学習していると、「これってAnimationとParticleどちらを使っても実現できるよな。どっちが良いんだろうか？」
と迷うことがあったので、調べてみました。
今の所僕なりの結論はこうです。

Particleでは１個１個の点が個別に描画されるため、処理が重くなる。その点Animationは軽い。
また、Particleには多種多様なエフェクトが用意されているため簡単に複雑なエフェクトが作れる。

そのため、基本的にはAnimationを使い明らかにParticleを使った方が開発がラクになる場合のみParticleを使う、と言う方針でやって行こうと思います。

ぜひ、コメントも歓迎しています。
## 終わりに
私は現在、Web3のサービスの開発をしています。詳しくはこちらの記事をご覧下さい。
        [無料でイーサリアムが当たる、Web3時代の寄付サイトを作った話](https://note.com/kenroda/n/n814347fbdcd7)
UILabelの文字を長押しでコピーする

# 概要
通常のUILabelは、フィールドの長押しでコピーができません。
UITextFieldのようにフィールドの長押しでコピーができるようにする方法です。

# UILabelの文字を長押しでコピーする画面イメージ
以下の図のLabel1と書かれたUILabelを長押しした時に、Label1の文字列をコピーします。コピーした後に、UITextFieldなどにペーストできます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/404406/398ad1cb-26a2-715d-cf1a-6f06e4e97edb.png" width=30%>

# 実装方法
UILabelで長押しでコピーするために、以下のコードを、CopyUILabel.swiftとして追加します。このCopyUILabelを、storyboardで、長押しでコピーしたいUILabelのCustom Classで設定します。以下の図は、storyboardでUILabelにCopyUILabelを設定している図になります。

<img width="258" alt="20190424-customClass.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/404406/f8a56c16-1d4c-4e38-5786-32a4cf31623e.png">

``` CopyUILabel.swift
class CopyUILabel: UILabel {
    override init(frame: CGRect) {
        super.init(frame: frame)
        self.copyInit()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        self.copyInit()
    }

    func copyInit() {
        self.isUserInteractionEnabled = true
        self.addGestureRecognizer(UILongPressGestureRecognizer(target: self, action: #selector(CopyUILabel.showMenu(sender:))))
    }

    @objc func showMenu(sender:AnyObject?) {
        self.becomeFirstResponder()
        let contextMenu = UIMenuController.shared
        if !contextMenu.isMenuVisible {
            contextMenu.setTargetRect(self.bounds, in: self)
            contextMenu.setMenuVisible(true, animated: true)
        }
    }

    override func copy(_ sender: Any?) {
        let pasteBoard = UIPasteboard.general
        pasteBoard.string = text
        let contextMenu = UIMenuController.shared
        contextMenu.setMenuVisible(false, animated: true)
    }

    override var canBecomeFirstResponder: Bool {
        return true
    }

    override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
        return action == #selector(UIResponderStandardEditActions.copy)
    }
}
```

# ソースコード
ここで説明したソースコードは、
[GitHub]
(https://github.com/hoge-san/sample-swift-copyUILabel)
で公開しています。

# 環境
- Xcode 10.2
- Swift 5

# 参考文献
- Apple公式マニュアル [canPerformAction](https://developer.apple.com/documentation/uikit/uiresponder/1621105-canperformaction)
- Apple公式マニュアル [canBecomeFirstResponder](https://developer.apple.com/documentation/uikit/uiresponder/1621130-canbecomefirstresponder)
SPAのサイトでTreasureDataにPVを送信する方法。

通常は、GTMの「pageview」イベントをトリガーにして、TreasureDataにPVを送信する。

メディアサイト「WWD JAPAN.com （ https://www.wwdjapan.com/ ） 」は、SPA（シングルページアプリケーション）のため、通常のGTMの「pageview」では、PVをTreasureDataに正確に送信できなかった。

この設定でうまくいった。

GTM、SPAでのTreasureDataへのPV送信設定は、以下の通り

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41550/0f0e09e2-cd32-77bf-15e8-05c6523befa9.png)


## 「loadPage （datalayerでのイベントpush） 」

SPAページの初期ロード完了トリガー（SPAでは初回1回のみサーバーからHTMLを受け取る。 WWD JAPAN.comでは、SPAでのHTML生成完了後、タイトルなどがHTMLで準備できたタイミングでトリガーしている。）

初回のロード時のみ、TreasureData SDKのロードと、PV送信を行う。

Treasure Data Load SDK and Send PV


```html

<script>
!function(t,e){if(void 0===e[t]){e[t]=function(){e[t].clients.push(this),this._init=[Array.prototype.slice.call(arguments)]},e[t].clients=[];for(var r=function(t){return function(){return this["_"+t]=this["_"+t]||[],this["_"+t].push(Array.prototype.slice.call(arguments)),this}},s=["addRecord","set","trackEvent","trackPageview","trackClicks","ready","fetchGlobalID","fetchUserSegments"],a=0;a<s.length;a++){var c=s[a];e[t].prototype[c]=r(c)}var n=document.createElement("script");n.type="text/javascript",n.async=!0,n.src=("https:"===document.location.protocol?"https:":"http:")+"//cdn.treasuredata.com/sdk/2.1/td.min.js";var i=document.getElementsByTagName("script")[0];i.parentNode.insertBefore(n,i)}}("Treasure",this);

  var td = new Treasure({
    host: '<< host >>',
    writeKey: '<< writeKey >>',
    database: '<< DB >>',
    startInSignedMode: true
  });
  td.set('$global', 'td_global_id', 'td_global_id');
  // 会員IDなどをセット
  td.set('pageviews', { '<< カスタム変数 >>': "{{<< カスタムバリュー >>}}" });
  td.trackPageview('pageviews');
</script>
```

## 「change （datalayerでのイベントpush） 」

SPAでのページ遷移は、サーバーを経由しないため、GTMのpageviewイベントはトリガーされない。

SPAでは、ページ遷移は、URLの変化を元に、サーバーのAPIをコールして、情報を取得して、ページを再描画している。そのため、URL変更され、ページが再描画されタイトルなどがHTMLで準備できたタイミングでトリガーしている。

すでに、TreasureData SDKのロードは完了しているため、PV送信のみを行う。


Treasure Data Send PV

```html
<script>
  td.set('$global', 'td_global_id', 'td_global_id');
  // 会員IDなどをセット
  td.set('pageviews', { '<< カスタム変数 >>': "{{<< カスタムバリュー >>}}" });
  td.trackPageview('pageviews');
</script>
```


## まとめ

WWD JAPAN.comは、SPA構成になっている。

タイトル、本文などが空のHTMLをロードして、javascriptからAPIを呼んでページの情報を取得してHTMLを作成する。

SSRで、タイトルなどが入ったHTMLを返すようにしているが、たまに、SSRが失敗してタイトルが空のHTMLが返却される場合がある。

GTMのall pageviewのタイミングだと、うまくタイトルが送信できないことがあるので、HTMLが完成したタイミングで、loadPageイベントを発行して、そのloadPageをトリガーにしてTreasure Data Load SDK and Send PVタグを発行

一度ページをロードすると、サイト内の回遊時、サーバーからHTMLをダウンロードしない。
URLが切り替わるタイミングでchangePageイベントを発行して、そのchangePageをトリガーにしてTreasure Data Send PVタグを発行

最初のページのロードは、SDKのロードと、PV送信
Treasure Data Load SDK and Send PV

次のページからは、PV送信のみ
Treasure Data Send PV
QiitaでRunKitを無理やり埋め込む

CodePenでRunKitのEmbedのコードを書いてQiitaで表示しています。

```RunKitEmbed|html
<script src="https://embed.runkit.com"
         data-element-id="my-element"></script>

<!-- anywhere else on your page -->
<div id="my-element">
    console.log("hello world");
</div>
```

<p class="codepen" data-height="265" data-theme-id="0" data-default-tab="result" data-user="hota1024" data-slug-hash="GLYLey" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid black; margin: 1em 0; padding: 1em;" data-pen-title="Qiita RunKit Test">
  <span>See the Pen <a href="https://codepen.io/hota1024/pen/GLYLey/">
  Qiita RunKit Test</a> by hota1024 (<a href="https://codepen.io/hota1024">@hota1024</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>
grok filterでハマったこと①

## あらすじ
AWS CloudTrailをLogstashで加工したときに[Grok Filter][00]でハマったので、つまづき事例の投稿です。
タイトルの「①」は今後もハマるような気がするからですｗ

## 利用バージョン
Logstash 6.6.2

## Logstashでやろうと思ったこと
AWS CloudTrailの`userIdentity.principalId`の`:(コロン)`の右側の値である
`(例)abcde@sample.co.jp`をKibanaの分析に利用するためにGrok Filterを使います。

```ruby:sample_log
    "userIdentity": {
        "type": "AssumedRole",
        "principalId": "FVG2RTG1FCDFW1R5SVK2:abcde@sample.co.jp",
        "arn": "arn:aws:sts::xxxxxxxxxxxx:assumed-role/iam-user/abcde@sample.co.jp",
        "accountId": "xxxxxxxxxxxx"
```
※CloudTrailのログサンプルの一部抜粋です。

## Grok Constructorを使う
LogstashのGrok Filterを使う上で欠かせないデバッグツールである[Grok Constructor][01]を使います。
①`Match`タブを選択し、②に正規化したい文字列を張り付けます。
※今回は1レコードのみですが、複数レコードを張り付けて全てにマッチする正規化フィルタになっているか確認が出来ます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211371/2e8b0602-a8a9-bbbf-9d21-f7268433622e.png)
コロンの左側(FVG2RTG1FCDFW1R5SVK2)は大文字英字と数値の組み合わせ
コロンの右側(abcde@sample.co.jp)はメールアドレス(小文字英字、数値、@、_、-、.等の記号の組み合わせ)
なので、[grok-patterns][02]にあるWORDとGREEDYDATAを利用します。
③には`%{WORD:principalid}:%{GREEDYDATA:userid}`と入力します。

```ruby:grok-patternsの抜粋
WORD \b\w+\b
GREEDYDATA .*
```

`Go!`ボタンを押すと下部に結果が出ます。こんな感じです。マッチしているので、OKですね！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211371/f76efbd8-b663-198d-9e8e-663775fe9006.png)
※1つ目のField名を`principalid`、2つ目をField名を`userid`としています。

## Logstashのconfを書く
Grok Constructorの結果を踏まえ、/etc/logstash/conf.d/logstash.confを書いてみました。
※以下、filter句の抜粋です。

```ruby:logstash.confの抜粋
filter {
  json {
    source => "message"
  }
  grok {
    match => { "userIdentity.principalId" => "%{WORD:principalid}:%{GREEDYDATA:userid}" }
    tag_on_failure => [ "_userIdentity.principalId_parse_failure" ]
  }
```

結果はなんと`tags: _userIdentity.principalId_parse_failure`となり、grok filterがマッチしませんでした。ここから原因特定のための切り分けを開始しましたが、以下の2点をまず疑いました。

1. 2つのgrok patternsの間に挟まっている:(コロン)をエスケープする必要があったのか？
2. grok patternsのファイルをなぜか認識出来ていないのでは？

これまでそんなことでハマったことはなく、`\(バックスラッシュ)`で`:(コロン)`をエスケープしてもNG
わざわざ、patterns_dirで明示的にパスをしてもNGでした。あたり前ですよねｗ

ちなみにRPMでlogstashをインストールしている場合、grok patternsは以下にあります。
`/usr/share/logstash/vendor/bundle/jruby/2.3.0/gems/logstash-patterns-core-4.1.2/patterns`

ここは勘に頼ることになりましたが、`userIdentity.principalId`というField名を認識出来ていないのでは？と思い、`.(ドット)`表記を止めて、`[userIdentity][principalId]`とすることで解決しました。

```ruby:logstash.confのOK版
filter {
  json {
    source => "message"
  }
  grok {
    match => { "[userIdentity][principalId]" => "%{WORD:principalid}:%{GREEDYDATA:userid}" }
    tag_on_failure => [ "_userIdentity.principalId_parse_failure" ]
  }
```

## まとめ
1～2時間ハマってしまいましたが、無事解決出来てホッとしました。
LogstashのPluginによって、`.(ドット)`で認識出来ない場合もあるので、注意が必要だなと改めて思いました。
階層構造になっているFieldを扱う場合は、`[](角括弧)`を使う方が無難ですね。

ハマったネタは恥ずかしがらずに公開すると意外と幸せになれる人がいると思っているので
投稿してみました^^;

[00]: https://www.elastic.co/guide/en/logstash/6.6/plugins-filters-grok.html "Grok filter"
[01]: https://grokconstructor.appspot.com/ "Grok Constructor"
[02]: https://github.com/logstash-plugins/logstash-patterns-core/blob/master/patterns/grok-patterns "grok-patterns"
RDS(PostgreSQL)からAuroraに移行した話

## はじめに
投稿者は普段RubyでWebアプリを作っています。
これまで業務でAWSを使ったことはありません。
今回たまたまAWSに触らせてもらえる機会を頂きました。
備忘のために、やったことをまとめておきます。

## 構成
変更前|変更後 
---|---
| Postgres9.6.1<br>MultiAZ + リードレプリカ | AuroraPostgreSQL 9.6.8<br>メイン ＋ リーダー（非常時昇格）|

## その他環境周り
- 言語: Ruby、Ruby on Rails
- WEBサーバ: Apache (Passengerも使用)
- その他: delayed_job(非同期処理用のgem)

## 移行に伴いやったこと

### 実行日、時間帯の検討
月半ばの月曜日、時間帯は早朝

＜理由＞
<dl>
  <dt>月半ばの月曜日</dt>
  <dd>月末月初はバッチ処理が走るので避けました。<br>
      また、週末は休日を跨ぐため、何かあった時にその週で対応できるように月曜に決定。</dd>
  <dt>早朝</dt>
  <dd>サービスのトランザクション量を調査し、一番少なかった早朝をチョイス。</dd>
</dl>

### 移行手順を考える
当日のメンテナンス時間を最小に抑えることを優先しました。
Auroraリードレプリカを前日に作成しておき、
当日メンテナンス中は昇格とDNS切り替えのみ行うような手順にしました。

#### 実際の手順
- 前日
  - Aurora用にSG、パラメータグループを作成
  - パラメータグループに関連付けしてAuroraリードレプリカ作成
  - イベントサブスクリプション作成、Auroraリードレプリカに適用
- 当日
  - Auroraリードレプリカへの接続を確認
  - 既存RDSとAuroraリードレプリカのレプリケーション確認
  - 既存RDSのイベントサブスクリプション解除（作業中のアラート抑止）
  - AutoScaling設定を1に変更（EC2操作）
<br>
  - __メンテナンスモードON__
  - Apacheの停止
  - delayed_job停止
  - Auroraリードレプリカ昇格
  - DNS切り替え(Route53操作 CNAME変更)
  - DNS切り替え確認
  - 既存RDSと昇格後Auroraのレプリケーション確認
  - Auroraにシーケンス同期用パッチを実行
  - 既存RDSと昇格後Auroraのシーケンス同期確認
  - 旧RDSのSG変更（アクセス不可用のSGを割り当て。　誤接続防止）
  - Apache起動
  - delayed_job起動
  - __メンテナンスモードOFF__
<br>
  - AutoScalingを元に戻す

### ポイント
- メンテンスモードについて
当日はmaintenance.htmlを所定の場所に配置/削除でON/OFF切り替え。
以下を参考にさせて頂きました。
[Apache httpd でメンテナンスモード](https://mallowlabs.hatenablog.com/entry/20140805/apache_maintenance_mode)

- AutoScaling設定
  - キャパシティを1にすることで作業対象を集約。作業時間の短縮ができました。<br>
   (__戻す手順も忘れずに！__）

- Apache、passenger 停止/起動
  - 残プロセスがあるとrails(ActiveRecord)のコネクションプールにより、<br>DNSを変えてもDBの向き先が切り替わりません。（はまった点。）

- delayed_job 停止/起動
  - 非同期処理をしているので、実行中プロセスをリセット後に実施した方が安全と判断。

- シーケンス同期用パッチ
  - PostgresはRDS→Auroraに切り替えるとシーケンスが重複する不具合があります。<br>
   （最新版では直っているかもしれません。）<br>
    [メモ: RDS PostgreSQL から Aurora PostgreSQL に移行したらシーケンスが巻戻る事があった件](https://qiita.com/koshigoe/items/e30fe448da476582bc66)<br>
    Rubyでパッチを作って対処しました。


### 作業時の気づき
- PostgresRDSのバージョンが9.6以前のインスタンスは、
  アクションに「Auroraリードレプリカの作成」項目が表示されない。
  
  - まずはRDSをバージョンアップするか、スナップショット経由で<br>移行する形式になりそうです。

- Auroraパラメータグループにはクラスター用とDBインスタンス用があり、<br>両方作成しておく必要がある。

- Auroraクラスター配下にリーダー（読み込み用インスタンス）を作成すると、
  クラスターの読み込みエンドポイント経由で自動でリーダーにアクセスできる。

- リードレプリカ昇格を待っている間にDNSの切り替えは可能であることがわかった。
  - 作業時間短縮に繋がりました。

- インスタンス作成時に拡張モニタリング設定をONにする場合、
  RDSの全アクセス権限だけでは足りないので確認が必要。
  - CloudWatchかと思いましたが権限を追加してもらってもできず、<br>
    結局パワーユーザーの人にお願いしました。

- RDSのセキュリティーグループはすべて外すとデフォルトが適用される。
  - 誤接続防止はインバウンドに何も指定しないSGを作成して適用すればOK！

- リードレプリカおよび昇格後のレプリケーションはきっちりされる。
  - 当たり前かもしれませんが、確認することでAWSの便利さを再認識しました。

- Railsからアクセス中にフェイルオーバーさせると、
  切り替えを検知できずに書き込み処理でエラーが発生する。
  - RailsではPG::Connectionエラーとなるので対処が必要です。

## まとめ
普段とは全然違う領域での作業で右も左もわからず、
色々な人を巻き込み（多大な迷惑をかけつつ）無事に移行できました。
協力頂いたみなさんには大変感謝しております。
今後もインフラ関連を勉強してエンジニアとしての視野を広げていきたいです。
Python正規表現、ひらがな・カタカナ・漢字にマッチさせるサンプルコード

## 目的
Pythonの正規表現で、対象の文字列が日本語に一致するかどうかをチェックします。
開発現場でさっとコピーして適用しやすいように簡単なサンプルコードを作成しました。

## サンプルコードの実行
python2.7で実行して確認済み。
`$ python re_japanese.py`

## サンプルコード
本体は[Github](https://github.com/MKJP/PythonSamples/blob/master/re_japanese.py)に設置してあります。 漢字は厳密にマッチさせるにはCJK統合漢字以外も取り入れる方がよいらしいですが、通常の用途では十分な実用性があると見て、これを基準としています。

```python:re_japanese.py
#!/usr/local/bin/python
# -*- coding: utf-8 -*-

import re

###
# すべて「ひらがな」であればマッチする
###
pattern = u'^[\u3040-\u3098]+$'

# 対象の文字列もUnicodeにあわせる
string = u'あいうえお' # 正常系
result = re.match(pattern, string)
assert result is not None
print(result)
# <_sre.SRE_Match object at ...>が出力される

string = u'XあいうえおX' # 異常系、前後に対象外文字あり
result = re.match(pattern, string)
assert result is None
print(result)
# Noneが出力される

string = u'あいXうえお' # 異常系、途中に対象外文字あり
result = re.match(pattern, string)
assert result is None
print(result)
# Noneが出力される

###
# すべて「カタカナ」であればマッチする
###
pattern = u'^[\u30a1-\u30fa\u30fc]+$'

# 対象の文字列もUnicodeにあわせる
string = u'アイウエオ' # 正常系
result = re.match(pattern, string)
assert result is not None
print(result)
# <_sre.SRE_Match object at ...>が出力される

string = u'XアイウエオX' # 異常系、前後に対象外文字あり
result = re.match(pattern, string)
assert result is None
print(result)
# Noneが出力される

string = u'アイXウエオ' # 異常系、途中に対象外文字あり
result = re.match(pattern, string)
assert result is None
print(result)
# Noneが出力される

###
# すべて「漢字」であればマッチする
###
pattern = u'^[\u4e00-\u9fff]+$'

# 対象の文字列もUnicodeにあわせる
string = u'文字列' # 正常系
result = re.match(pattern, string)
assert result is not None
print(result)
# <_sre.SRE_Match object at ...>が出力される

string = u'X文字列X' # 異常系、前後に対象外文字あり
result = re.match(pattern, string)
assert result is None
print(result)
# Noneが出力される

string = u'文字X列' # 異常系、途中に対象外文字あり
result = re.match(pattern, string)
assert result is None
print(result)
# Noneが出力される
```

## 参考資料
- [Python2.7 - 正規表現](https://docs.python.org/ja/2.7/library/re.html)
- [Python2.7 - Unicode](https://docs.python.org/ja/2.7/howto/unicode.html)
- [wiki: 平仮名 (Unicodeのブロック)](https://ja.wikipedia.org/wiki/%E5%B9%B3%E4%BB%AE%E5%90%8D_(Unicode%E3%81%AE%E3%83%96%E3%83%AD%E3%83%83%E3%82%AF))
- [wiki: 片仮名 (Unicodeのブロック)](https://ja.wikipedia.org/wiki/%E7%89%87%E4%BB%AE%E5%90%8D_(Unicode%E3%81%AE%E3%83%96%E3%83%AD%E3%83%83%E3%82%AF))
- [wiki: CJK統合漢字](https://ja.wikipedia.org/wiki/CJK%E7%B5%B1%E5%90%88%E6%BC%A2%E5%AD%97)
docker-composeで始めるnuxt.js

## 対象

* docker、docker-composeをインストールしている方
* vue.js,nuxt.js手軽に触ってみたいよという方
* 開発環境の構築にそんなに時間かけたくないよという方

## ゴール

* docker-composeを利用したnuxt.jsの開発環境を手に入れる

## docker-compose.ymlを書く

* 以下写経
* 実際Dockerfileだけで今回やる分には十分です。
  * storybookとか後々色々なもの導入したくなると思うので、先にdocker-compose.ymlで複数コンテナを管理できるようにしようという魂胆です。

```docker-compose.yml
version: '3'

services:
  node: &app_base
    image: node:11.14.0-alpine # dockerhubにすでに上がっている
    tty: true
    working_dir: /var/www
    volumes:
      - ./src:/var/www # ./srcをコンテナ内の/var/wwwにマウントする
    environment:
      PORT: 3000
      HOST: 0.0.0.0
    restart: always # エラーなどでコンテナが落ちた際に自動で再起動してくれる

  workspace:
    <<: *app_base
    ports:
      - "3000:3000" # localhost:3000にポートをマッピングする
    command: yarn dev # upする際に実行されるコマンド
```

## create-nuxt-appを使う

* まずはdockerコンテナにshで入ってみよう
`docker-compose run --rm node sh`

* 以下コンテナ内で実行

```
/var/www # yarn global add create-nuxt-app

/var/www # create-nuxt-app ./
> Generating Nuxt.js project in /var/www # この後色々聞かれます
? Project name myNuxtApp # プロジェクト名
? Project description My finest Nuxt.js project # プロジェクトの説明
? Use a custom server framework none # サーバーサイドのフレームワーク
? Choose features to install Axios # Axiosやlintなど一緒にインストールするもの
? Use a custom UI framework none # UIフレームワーク
? Use a custom test framework none # Jestなどのテストフレームワーク
? Choose rendering mode Single Page App # レンダリングモード
? Author name # アプリケーション作成者の氏名
? Choose a package manager yarn # パッケージ管理にnpmかyarn
```

これで準備完了。ローカルの./srcにマウントしているので./src内にnuxtのプロジェクトができているかと思います。
コンテナから出ましょう。

`/var/www # exit`

## いざ実行

* コマンド一つでnuxtサーバーが立ち上がります。

`docker-compose up workspace`

http://localhost:3000 を確認すると...

![スクリーンショット 2019-04-24 23.20.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/166596/73197d9d-3342-b2a0-93d6-5c0b489c2cec.png)

きちんと表示される！
nuxt.jsの開発環境がこれで整いました！

## 終わりに

* まず始めるという部分にフォーカスして、シンプルにまとめてみました。
* ここまででおよそ15分かからない位でnuxt.jsの環境が作れるのでぜひお試しください。
勉強、強(し）いて勉（つと）めず。楽しく訓練。仮説（29）

「勉強している」っていう人で、無駄にお金と時間を使っている人を見た気がする。
「それ勉強じゃなくて、「強いて」無駄なことに「勉めて」いるんじゃね。」と思った。

いくつかの無駄にならない方法を記録する。

# 1.試験勉強は過去問をやる。
試験勉強で解説本を読むのはお勧めしない。

## 1.1 経験則：情報処理試験勉強は、試験問題を３年分３回やればよい。

解説本で、問題の間違いや、あいまいなところを適切に指摘している本にほとんどであったことがない。
ほとんどと書いたのは、３０年くらい前には、試験を主催していた組織が出していた本には、試験の間違いの指摘があったから、「ほとんど」と書いている。

試験問題の間違いや、模範解答の間違いを指摘していない解説本は読まない方がよい。

解説本は、読めば読むほど、勘違いを増幅させる場合がある。

自分で試験問題を解いて見て、回答を見て、わからない問題でも、繰り返しやって慣れればいいというのが経験則。

３年分、３回やっても、問題と回答例に納得できない試験区分がある。
その試験区分は受けなきゃいいと思った。

情報処理技術者試験　ネットワークスペシャリストに合格
https://qiita.com/kaizen_nagoya/items/407857392ca5c5677ee4

IT系技術資格における法律問題の勉強の仕方
https://qiita.com/kaizen_nagoya/items/ca2d115d428f406bd2dc

無線網（Wi-Fi）空中線(antenna)(75)関連資格
https://qiita.com/kaizen_nagoya/items/506423d9db2f53be50b6

### 1.1.1 QC検定
QC検定では過去問を３年間分を３回やったがみごと不合格。
やればやるほど、正解率が低くなる場合があった。

プログラマにも読んでほしい「QCべからず集」
https://qiita.com/kaizen_nagoya/items/d8ada7b7fceafe2e5f0e

プログラマがQC検定を受けることの意味・価値・課題　https://qiita.com/kaizen_nagoya/items/b03216eb6ab09eacc957

QC検定に落ち「たか」らかける記事。20,000人の方に読んでいただけ「たか」ら書ける記事。「たかたか」分析の勧め。
https://qiita.com/kaizen_nagoya/items/2a371ee8c8f1b78cd5bb

統計と確率　プログラマによる、プログラマのための、統計と確率のプログラミングとその後　https://qiita.com/kaizen_nagoya/items/6e9897eb641268766909
# 2. セミナでは午前中から手を動かす。
手を動かさないセミナを受講するのではなく、自分で手を動かせば良い。

手を動かさないセミナの半分は役に立たない。
一人で考える時間のない、班構成で議論する演習も同様。

もし、セミナが１日コースで、午前中に手を動かさないようであれば、
自分でかってに手を動かすとよい。

@Nozomi-Hosaka 【個人開発】勉強方法と開発手法、そのスピード感について【勉強方法】
https://qiita.com/Nozomi-Hosaka/items/ca06fd2212223c741041

コードを入れて、コンパイルして、エラーをとって、試験コードを書いて、コンパイルして、エラーをとって、動かして。

# 3. どんな話題からでも掘り下げたり、幅を広げたりしてみる。
どうでもいい話題ばかりの会合に出ることはあり得ない。どんな話題からでも、現実の問題の解決策にたどり着けることは可能なはずだ。

どうでもいい話題ばかりの会合に出ても、
その会合で出てきたすべての単語の類語辞書とかつくって、
抜け漏れを指摘したり、重複・矛盾とかを指摘すれば役にたつかもしれない。

IT系勉強会をすべて当たりにする方法
https://qiita.com/kaizen_nagoya/items/9f001a79ab4162220406

# 4. 自己啓発本を書く
自己啓発本を読むのは、自己啓発本を書くためならいい。自分の経験を整理できるから。
自己啓発本は読むものじゃない。
まして、自己啓発本で読んだ内容を、他人に話すのはもっと無駄。

自分の生の経験を振り返ればよい。他人の経験によらず。

人生で影響を受けた本100冊。
https://qiita.com/kaizen_nagoya/items/16af53acbb147a94172e

自己啓発本ではないが、自分の書いた本を１０冊程度、ちゃっかり一覧に入れてある。

# 5. コンパイラを作る。
心理学の本を読むのではなく。

心理学の本を読むよりはコンパイラ書いた方がよくね。仮説（34）
https://qiita.com/kaizen_nagoya/items/fa715732cc148e48880e

CPUを作ってもいい。

CPUの創りかた, 渡波 郁
https://qiita.com/kaizen_nagoya/items/2e1b6b79ea3e6b2bf0c0

# 参考資料(reference)
@kazuo_reve 新人の方によく展開している有益な情報
https://qiita.com/kazuo_reve/items/d1a3f0ee48e24bba38f1

qiitaのいいところは、URLを書けば、そこに著者のIDがある。
著者名を別に記載しなくても、著者名を記載したことになる。

タグにして著者名を消すのは、無駄な作業かも。
##  自己参照
勉強　@kazuo_reve 新人の方によく展開している有益な情報（51)
https://qiita.com/kaizen_nagoya/items/bc3175d7525181826d95

# 文書履歴(document history)
ver. 0.01 初稿 20190424
ver. 0.02 表題追記 20190425
ver. 0.03 追記 20210501
ver. 0.04 表題変更 20220421
ver. 0.05 見出しを否定文から肯定文に転換。みだしに番号 20220427

さいごまでおよみいただきありがとうございました。
https://qiita.com/kaizen_nagoya/items/3387ded65f55a8303817

### 最後までおよみいただきありがとうございました。

いいね　💚、フォローをお願いします。

#### Thank you very much for reading to the last sentence.

Please press the like icon 💚　and follow me for your happy life.
【LT発表資料】お手軽屋内位置情報サービスアプリ

久しぶりのQiita記事投稿になります。今回は技術説明ではなく、社内有志のLT（Lightning Talk）大会で発表した資料の公開になります。
理由はGWの休暇中に何か作ろうかなと思ってたら、資料が見つかったからです、、、
スマホアプリを作ろう！と盛り上がっていた時期のものなので結構古いです。利用技術にAngularJSとか書いてあります:sweat_smile:

何か作ってみたいけど、作りたいものが思い付かない！という人がいればぜひ作ってみてください！

![スライド1.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/195748/f1c72bf2-8794-d4c1-4dc7-196193a6bf21.jpeg)

![スライド2.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/195748/d6d74f43-6da7-dca7-7140-6e4f32b4be33.jpeg)

![スライド3.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/195748/d5360e43-35d8-250f-66a6-ad1e2eac91ac.jpeg)

![スライド4.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/195748/0bf645e5-9e91-5d2a-0aca-360d5e5696cc.jpeg)

![スライド5.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/195748/6095e2fd-2551-3ccb-4620-3fb2f1d2b6b6.jpeg)

![スライド6.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/195748/3fc6aa75-5968-f0e4-a951-79e869551c8c.jpeg)

![スライド7.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/195748/7b902878-4e6b-7f61-e178-b26a38fdf0ec.jpeg)

![スライド8.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/195748/b595b1d3-fa2d-333c-f8e2-535f1a79559a.jpeg)

![スライド9.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/195748/5fa54fa6-9023-696c-309a-32b6dc1c575c.jpeg)

![スライド10.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/195748/78868324-f0ba-e009-ab76-57860ac56e83.jpeg)

![スライド11.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/195748/e17635d9-b3e9-54d9-0c71-ed1ae4c0e536.jpeg)

![スライド12.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/195748/6859b26c-bcd1-56e9-22ce-616ab4e36a39.jpeg)

![スライド13.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/195748/74e13372-c7de-0031-f23c-a76e5e7900db.jpeg)

![スライド14.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/195748/d1f92468-aa17-7d54-1d8b-8cb6d85e618f.jpeg)

![スライド15.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/195748/c76f9a4c-8555-f52d-d80c-6d134221ef8b.jpeg)

![スライド16.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/195748/1e4d7ce3-2c31-27dd-396a-53a1a482bc27.jpeg)

![スライド17.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/195748/8558e9eb-96c6-a0aa-f322-7514a870fe01.jpeg)

![スライド18.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/195748/bf0a7da5-14f1-71d0-5e21-4c2a95100473.jpeg)

![スライド19.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/195748/4a554044-08ed-028c-9a6b-cf23bd06fc9b.jpeg)

![スライド20.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/195748/9cd46607-d963-6a66-e09b-6234f353594e.jpeg)

![スライド21.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/195748/ab2ec3c8-4c2d-2b8a-7b88-408c7e7ea899.jpeg)
ansibleからwhenを消す。またはwhenのないrole切り替えについて

# when
例えばOSによって処理を分けたいとき、以下のように条件式で分岐する。

```yaml
- include: hoge.yml
  when:
   - ansible_distribution == "CentOS"
```
※ansible_distributionで構成管理対象OS名が取得可能

# 条件分岐のないrole切り替え
ansibleのwhenは、プログラミングにおけるif文なので増えるほど複雑さが増します。
個人的にはwhenは出来るだけ書きたくないなぁと思ったので以下のような書き方を考えてみました。

```yaml:playbooks/main.yaml
- hosts: all
  tasks:
    - name: update tasks
      include_role: 
        name: "{{ ansible_distribution }}"
```

最初はinclude_roleではなく、roleで実現しようと思いましたが、そこではansible_distribution変数が読めなかったのでこのように実現しました。
ansible変数のスコープがまだ良くわかっておりません。

ちなみにroles配下は以下のようになっており、各種ディストリビューションに合わせたディレクトリを切っています。

```shell
roles
├── CentOS
│   └── tasks
│       └── main.yaml
└── Ubuntu
    └── tasks
        └── main.yaml
```

## メリット
* 他のディストリビューションを後から追加する場合も`playbooks/main.yaml`を変更する必要はありません。`roles`配下に新たなディレクトリを切ればOK
 * 保守性の高いPlaybookとなります

# その他
調べててもこういう書き方があんまり出回っているように見えなかったので、実用性があるのか？ないのか？わかりません。
複雑な条件分岐がある場合だと`roles`配下のディレクトリの切り方を工夫したり、変数と変数を組み合わせるみたいなことが起きそう（つらそう）
roleの命名規則を定めないと運用できないかも。