OmniAICreator/Qiita-1.07M huggingface dataset:
ES6における変数宣言の基礎

#前置き
ES2015における変数宣言には3種類ある。
```var```,```let```,```const```の3種。```var```は推奨されない。
#var
再宣言、再代入が可能。

```javascript
var a;
a = 1; //二種類の書き方。
var b = 2; //どちらの書き方でもよい。
console.log(a); // 1
console.log(b); // 2
var a = 3; //再宣言
console.log(a); // 3
a = 4; //再代入
console.log(a); // 4
```
関数スコープである。

```javascript
if(true){
	var a = 1;
}
console.log(a); // 1
//　これは通る。
```
```javascript
function hello(){
	var b = 1;
}
hello();
console.log(b); // b is not defined
// これはエラー。
```
変数の再定義や再代入を防ぐため、基本的にvarは使わない方がいい。
#let
再定義ができない。再代入が可能。

```javascript
let a = 1;
console.log(a); // 1
a = 2; // 再代入はできる。
console.log(a); // 2
let a = 3; // ここでエラー。
console.log(a); // 再宣言はできない。 
```
ブロックスコープである。

```javascript
if(true){
	let a = 1;
}
console.log(a); // エラー: a is not defined
//　ブロック外では呼び出せない。
```
```javascript
function hello(){
	let b = 1;
}
hello();
console.log(b); // エラー: b is not defined
// 同様に、ブロック外では呼び出せない。
```
#const
再宣言も再代入もできない。

```javascript

const a = 1;
console.log(a); // 1
const a = 2; // エラー。再宣言できない。
a = 2; // エラー。再代入できない。a++;とかも勿論だめ。
```
ブロックスコープである。ブロック外で呼び出せない例はletの場合と同じなので省略。
#宣言時に```var```,```let```,```const```どれも書き忘れると

```javascript
function hello(){
	a = 1;
}
hello();
console.log(a);// 1
// グローバル変数になる。
```
もちろん非推奨。グローバル変数を作りたいなら関数外で宣言しよう。
#まとめ
関数宣言時は```let```、もしくは```const```を使おう。
Elixir~Enumと&記法、パイプライン演算子

※さらに編集後記追加しました！

Elixir完全初学、四則演算をEnum.map、filterに絞って記法を覚えたいド素人によるドキュメントです。

# いままでわからなかったこと

パイプライン演算子？Enum？触ってはいるけど実際に自分で考えて全く書けない！赤子のようだ！

そんなことを思っていた過去の自分に向けて、記事を書いてみます。
同じことで悩んでいる方の助けになればと思います。

# 本題


ここにEnum.mapのコードがあります。
第一引数のリストに２をかけろという内容です。

```elixir
iex>Enum.map([1, 2, 3], fn x -> x * 2 end)
[2, 4, 6]
````

まずは第一引数の[1, 2, 3]はそのままに、fn~ endの部分を&記法で書き換えていきます。

```elixir
iex>Enum.map([1, 2, 3], & &1 * 2)
[2, 4, 6]
```

さらに、パイプライン演算子を用いて、第一引数の「1, 2, 3」を行頭に持ってきます。

```elixir
iex>[1, 2, 3] |> Enum.map(& &1 * 2)
[2, 4, 6]
```

最後のパイプライン演算子と&記法を用いたものがかなり簡潔だと思います。
同様に、Enum.filterでも同じ試みをします。
３で割って余りがゼロになるものをリストしろという内容です。

```elixir
iex>Enum.filter([3, 5, 9], fn x -> rem(x, 3) == 0 end)
[3, 9]
```

こちらも第一関数のリストはそのままに、fn~endを&記法で書き換えます。

```elixir
iex>Enum.filter([3, 5, 9], & rem(&1, 3) == 0)
[3, 9]
```

さらに、パイプライン演算子を用いて第一引数のリストを先頭に持ってきた記法です。
やはりこれが一番スマートでしっくりきます。

```elixir
iex>[3, 5, 9] |> Enum.filter(& rem(&1, 3) == 0 )
[3, 9]
```

こんな感じで、引数や乗数、除数の条件を変えて何パターンか計算してエディタに記録したのが、以下のスクリーンショットです。こうしてEnumに特化した記法を叩き込んでいこうと思います。

<img width="1136" alt="スクリーンショット 2019-02-12 16.48.03.png" src="https://qiita-image-store.s3.amazonaws.com/0/306722/4b842cd0-37db-99fa-63b4-32ee5db559cc.png">

# まとめ

例えば、下記のようなfn~endの第二引数を用いたEnum.mapおよびfilterの記述

```elixir
iex>Enum.map([1, 2, 3], fn x -> x * 2 end)
[2, 4, 6]
````


を、&記法と、パイプライン演算子によって、次のように左辺に第一引数を集めつつ簡潔なものにすることができた！

```elixir
iex>[1, 2, 3] |> Enum.map(& &1 * 2)
[2, 4, 6]
```

このパイプライン演算子が極私的には強烈なもので、第一引数のリストをまるっと左辺にブチ込んでしまえる！簡潔！これでプログラムが読みやすい！
、、、と思いました。



# 編集後記、困ったこと

Enum.sortに関して、

```elixir
[323,999,54] |> Enum.filter(fn(n) -> n!= 999 end)
```

```elixir
[323,999,54] |> Enum.filter(& &1 != 999)
```

の書き換えをここまでの知識で導き出すことができた！やった！

・純然な用語の理解
引数ってJavaでやったけど関数とごっちゃになっててこれは関数？第二引数？若干書き方をボカしてしまったぞ？

・パイプライン演算子
これは==とかの演算子と同じで第一引数は左辺にある、と言い切っていいのか？そこも曖昧にしてしまったな。。

コメントなどで解決の御指南あればお願いいたします！
rbenvメモ

## rbenvメモ
環境構築することになったので今後のためにメモしとく。

## rubyのインストール
```terminal
$ruby install -list

Available versions:
  1.8.5-p52
  1.8.5-p113
  .
  .
  .
```
これでインストール可能なrubyバージョンが表示される
指定のバージョンをインストールしたいときは

```terminal
$ruby install 2.5.0

ruby-build: use openssl from homebrew
....
...
..
.
```
これでinstallできる。

## インストール済みのrubyバージョンの表示
```terminal
$rbenv versions

2.5.0
.
.
```
これでインストールされているrubyのバージョンが確認できる。

### 環境全体のrubyバージョンの指定
```terminal
$rbenv global 2.5.0
```

### プロジェクト固有のrubyバージョン指定
```terminal
$rbenv local 2.5.0
```

## 確認
あとはプロジェクトrootに行き

```terminal
$ruby -v
2.5.0~~
```
これを実行すればどのrubyのバージョンが指定してあるか確認できる。
depでのパッケージ管理で、インストール時にc/c++が必要な場合に発生する可能性があるエラーについて


## 概要
depを使ってvendor内に必要パッケージをインストールするが、その過程でC/C++の開発環境を使ったパッケージがあると、それらはインストールされないので、`go test`などでテストを実行する過程でエラーが発生した。


```bash
$ go test 
# .../vendor/github.com/karalabe/hid
.../vendor/github.com/karalabe/hid/hid_enabled.go:38:11: fatal error: 'hidapi/mac/hid.c' file not found
        #include "hidapi/mac/hid.c"
                 ^~~~~~~~~~~~~~~~~~
1 error generated.
FAIL	... [build failed]

```

## 解決策
vendorの中のパッケージを消して、githubから直接`git clone`するのが対症療法としては一番速い。と思ったものの、 `Gopkg.toml`での記述を工夫すれば同じく解決した。


デフォルトでは、depの仕様により、次のオプションはtrueになっている。


|オプション名|機能|初期値|
|:--|:--|:--|
|unused-packages| 未使用パッケージを除外|true|
|go-tests| テストコードを除外|true|
|non-go| Go言語コード以外のファイルを除外|true|

したがって、Goに関係のない(未使用 or test)部分は、自動的にvendorの中身から排除される仕組みになっている。
しかし、今回のように、Goとは関係ないが、インストールするときに依存しているパッケージも含まれている場合は、`Gopkg.toml`で次のように記述すれば良い。

```toml

[[prune.project]]
    name = "github.com/karalabe/hid"
    unused-packages = false
```
Horos 3.x を Source から build する

Horos は OsiriX を fork して Free DICOM Medical Image Viewer として開発されている macOS 上の 64bit アプリです
現在 Horos Project で有意な協力者により開発が続けられておりソースが LGPLv3 ライセンスの元に公開されているので Source から Build する
開発環境は macOS Mojave + Xcode 10.1 
macOS High Sierra の場合は Xcode 9.4.1 で build 可能
尚、Horos は薬機法（医薬品、医療機器等の品質、有効性及び安全性の確保等に関する法律）未認可です

##１．開発環境を整える
1. CMake と pkg-config  が必要なので先ず Homebrew をインストールします    
  mac のターミナルを開いて    
  ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"    
これで Homebrew がインストールされます
2. 次に brew install cmake で CMake をインストール
3. brew install pkg-config で pkg-config をインストールします

##２．ソースを入手する
Horos Project から Source を入手します
mac のターミナルを開いて
　　git clone https://github.com/horosproject/horos.git  horos3
これで当該ディレクトリの「horos3(任意)」にソースが clone (down load) されます

##３．build の実行
1. Finder 移動メニューから Souce を clone したフォルダに移動します  
2. その中に「Horos.xcodeproj」があるのでクリックして Xcode を起動します
3. Xcode メニューの「Product」「Scheme」「Unzip Binaries」を選択して Build します
4. 次に「Product」「Scheme」「Horos」を選択して Build します    
(少し時間がかかります)

##４．app の実行
Xcode 左側の「Products」の中に「Horos.app」が作成されていますのでクリックして実行します
あるいは「Show in Finder」で表示させてから実行しても OK です
##５．日本語環境について
Horos 3.1 から「ja-JP.lproj」と云う日本語リソースが組み込まれていますがこの日本語リソースでは 2DViwer が動作しないと云う問題があります
Horos の環境設定で Global・Languages の「日本語(日本)」のチェックを外して再起動すれば(英語表記になるが) 2DViwer は動作します
尚、「ja-JP.lproj」を廃棄して日本語リソース「ja.lproj」を新しく作成して組み込んだ「日本語版 Horos」が https://www.horos.jp/?p=181 で公開 されています
##参考
- [Horos-Project](https://github.com/horosproject/horos)
- [Horos の日本語化](https://www.systemcraft.co.jp/index.php?action=pages_view_main&active_action=journal_view_main_detail&post_id=451&comment_flag=1&block_id=96#_96)
- [日本語版 Horos](https://www.horos.jp/)
python入門(4)~リスト~

#リスト
##リストとは
複数のデータをまとめて格納できる箱のようなものです．リストを作るには要素を「,」で区切って「[]」で囲みます．また，リストの各要素には添字が振られています．
###リストの基本操作

```python:list.py
a = [1, 2, 3]
b = list()
#b = []
c = ['リスト', 10]
print(a[0], a[1], a[2], c[0], c[1])
a[0] = '壱'; a[1] = '弐'; a[2] = '参'
print(a[0], a[1], a[2])
```

```text:実行結果
1 2 3 リスト 10
壱 弐 参
```
リストとは他言語の配列に似ているが，それらとは異なる部分も多い．pythonにおけるリストでは一つのリストに複数の型の値を代入することができます．それに伴いリストの要素を変える時も違う型の値を入れることができる．また，空のリストを作るときはlist()もしくは[]を使います．
##リストの操作
リストには様々な機能が存在します．

```python:ope:py
a = ['A', 'B', 'C']
length = len(a)
print(length)
judg1 = 'A' in a
judg2 = 'Z' in a
print(judg1, judg2)
b = list('DEF')
print(b[0], b[1], b[2])
c = [a, b]
print(c[0], c[1])
```

```text:実行結果
3
True False
D E F
['A', 'B', 'C'] ['D', 'E', 'F']
```
上記のプログラムではまず，二行目でlen()を使いリストの要素数を取得します．次に四、五行目で「A」がリスト「a」含まれているかを調べ「True」または「False」で返します．また，七行目ではlist()を使い文字列などの型をリストに変換しています．九行目ではリストのリストを作っています．
##要素の削除と分割
###添字を特定して削除する時
上記のような場合はpop()を使います．また，添字の範囲外を指定するとエラーになります．

```python:list2.py
a = ['A', 'B', 'C']
print(a[0], a[1], a[2])
p = a.pop(1)
print(a[0], p, a[1])
```

```text:実行結果
A B C
A B C
```
`list2.py`では添字の二つ目を削除して`p`に代入しています．
###特定の要素を削除する時
上記の場合はremove()を使います．しかし，同じ値が複数あれば最初に見つかった値を削除します．また，削除したい値がリスト内になければエラーになります．

```python:list3.py
a =['c', 'java', 'python', 'java']
print(a[0], a[1], a[2], a[3])
r = a.remove('java')
print(a[0], r, a[1], a[2])
```

```text:実行結果
c java python java
c None python java
```
実行結果を見れば分かりますが，pop()では削除した値を変数に代入できますが，remove()ではそれができずに「None」と出力されます．
###delを用いた削除
delを使うと要素のオブジェクト自体がメモリから削除されます．

```python:list4.py
a = ['d', 'e', 'l']
print(a[0], a[1], a[2])
del a[0]
print(a[0], a[1])
```

```text:実行結果
d e l
e l
```
###変数への分割
リストの各要素を変数に振り分けることもできます．

```python:list5.py
a = ['c', 'java', 'python']
x, y, z = a
print(x, y, z)
```

```text:実行結果
c java python
```
##要素の追加と連結
###要素の追加
要素の追加にはappend()とinsert()という二通りのやり方があり，append()はリストの末尾に要素を追加し，insert()はリストの特定の場所に要素を追加します．

```python:add.py
a = ['い', 'ろ']
a.append('は')
b = ['い', 'は']
b.insert(1, 'ろ')
print(a)
print(b)
```

```text:実行結果
['い', 'ろ', 'は']
['い', 'ろ', 'は']
```
###リストの連結
リストは+演算子，もしくはextend()によって連結できます．

```python:con.py
list1 = ['a', 'b', 'c']
list2 = ['d', 'e', 'f']
list3 = list1 + list2
print(list3)
list1.extend(list2)
#list1+=list2
print(list1)
```

```text:実行結果
['a', 'b', 'c', 'd', 'e', 'f']
['a', 'b', 'c', 'd', 'e', 'f']
```
##ソート
ソートとは値の順番を並び替えることです．小さい方から並べることを昇順，大きい方から並べることを降順と言います．
###sort()を使う
sort()を使うとリスト自体を昇順に並び替えます．なお，sort()の引数に`reverse = True`を入れると降順に並び替えます．

```python:so.py
a = [4, 34, 2, 86, 15, 127]
a.sort()
print(a)
a.sort(reverse = True)
print(a)
```

```text:実行結果
[2, 4, 15, 34, 86, 127]
[127, 86, 34, 15, 4, 2]
```
###sorted()を使う
sorted()は元のリストはそのままにして新しいリストに並べ替えた要素を返します．

```python:so2.py
a = [4, 34, 2, 86, 15, 127]
b = sorted(a)
print(a)
print(b)
```

```text:実行結果
[4, 34, 2, 86, 15, 127]
[2, 4, 15, 34, 86, 127]
```
##最後に
pythonで行える操作はたくさんあるので少しずつ覚えていきましょう．
ubuntu18.04でなぜかipが二つになってしまったとき

kvmでubuntu18.04のサーバーを立ててクローンした後、netplanで書き換えて反映させたら

```
2: ens2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether yy:xx:00:04:cc:44 brd ff:ff:ff:ff:ff:ff
    inet 172.24.0.10/16 brd 172.24.255.255 scope global ens2
       valid_lft forever preferred_lft forever
    inet 172.24.0.11/16 brd 172.24.255.255 scope global secondary ens2
       valid_lft forever preferred_lft forever
    inet6 fe80::1145:14:scte:2b32/64 scope link
       valid_lft forever preferred_lft forever

```


なんかうまく設定できないかなと思ったけど、ipコマンドで無理やり消した。

```
ip addr del 172.24.0.10 dev ens2
```

しょうがない？
とりあえずmongoDBでfindしたかった話

## ゴール
タイトルの通り、この記事はmongoDBでfindして結果を参照できるまでをゴールとしています。

- mongoDBがどういうものかわからないけど、DBに登録されている情報を確認したい
- とりあえず触れる環境があるから試しにfindくらいしてみよう

といった方向けの記事です。
環境構築はもちろん、updateやinsertのお話も登場しませんのでご了承ください。
本記事はWindows環境を想定して記載しています。

## findするための準備
ここでは下記の2つの方法でfindする方法を記載します。

- NoSQLBooster for MongoDB
- mongo Shell

## NoSQLBooster for MongoDB
### インストール
[公式サイト](https://nosqlbooster.com/downloads)から環境にあったものをダウンロード後にインストールしてください。
### 設定
起動後にConnect⇒Createから設定を行います。
<img src="https://qiita-image-store.s3.amazonaws.com/0/321130/184590ee-0416-1e08-7990-fa6d401289a0.png" width=50%>

- **Server**にURLを設定してください
- **Name**は任意の名称にしてください

その他の設定タブに関しては、環境によって入力する必要があるかと思います。
パスワードや秘密鍵などは管理者に確認をとって必要な設定を行ってください。
**Test Connection**をクリックして、接続が成功すれば設定完了です。
### サンプル画面(公式サイトより)
<img src="https://qiita-image-store.s3.amazonaws.com/0/321130/90ad0f09-71d2-c873-80b7-f0db3741aa54.png" width=80%>

- **Connection Tree**に接続設定したDBが表示されます
- **test:unicorns**タブがQuery実行対象のDB、そのしたのエリアが実行するQureyになります
    - Qureyは直接入力するか、「Qurey」ボタンをクリックすればGUIベースで作成もできます
<img src="https://qiita-image-store.s3.amazonaws.com/0/321130/f4d7e3e1-3bee-0448-34bf-02e8edbbdf09.png" width=50%>
 - Qurey実行結果が画面右下部分に表示されます
     - 実行結果が複数になる場合は「Tree」から「Table」に変更するとカラムが1行で表示されるためおすすめです

## mongo Shell
### インストール
[公式サイト](https://www.mongodb.com/download-center/community)から環境にあったものをダウンロード後にインストールしてください。
必須ではないですがMongoDBをインストールしたフォルダを環境PATHに登録しておくと便利です。
インストール後に、コマンドプロンプトで`mongo`と入力して、
mongo shellが起動すれば準備完了です。

## findしてみる
単純に全件検索をするだけなら下記のQureyを実行すればOKです。
```db.getCollection("unicorns").find({})```

ちなみにサンプル画像で他に使用されているものについては下記のとおりです。

　 | 説明
----- | ----- |
projection | 検索結果に表示するカラム名<br>・設定しない場合はすべて表示されます<br>・サンプルの場合はname列とloves列だけ表示されます
sort | ソート順です。<br>・設定しない場合は昇順です<br>・-1を設定すると降順になります
limit | 取得件数です

詳細は[公式のDocumentation](https://docs.mongodb.com/manual/reference/operator/aggregation-pipeline/)を参照して下さい。

### 条件を付けたfind
下記のように記載すると、
カラム名「name」が「Dunx」かつ
カラム名「time」が2019/01/01～2019/01/02未満
のレコードを検索することができます。

```
db.getCollection("unicorns").find(
    {name: "Dunx",
     time:{ "$gte" : ISODate("2019-01-01T00:00:00+09:00"),
            "$lte" : ISODate("2019-01-02T00:00:00+09:00")},
    }
);
```
Operator | 説明
----- | ----- |
$eq | 一致("name"で使用しているとおりこれは省略可能)
$gt | より大きい
$gte | 以上
$in | 含む
$lt | より小さい
$lte | 以下

他のOperatorについては[公式のDocumentation](https://docs.mongodb.com/manual/reference/operator/query-comparison/)で確認できます。

## おまけ
### mongoの実行結果をcsvに出力
mongo Shellを使えば検索結果をcsvに出力することができます。
mongo Shellからjsファイルを実行することができるので、そのファイルに実行コードを記載します。

```javascript:sample.js
var results = db.getCollection("unicorns").find({time:{"$gte" : ISODate("2019-01-01T00:00:00+09:00"),"$lte" : ISODate("2019-01-02T00:00:00+09:00")}, });

// タイトル
print("_id"
      + '\t' + "name"
      );

// 検索結果整形
results.forEach(function(result) {
  if (result) {
    print(result._id
          + '\t"' + result.name +'"'
          );
  }
});
```

あとはWindowsで環境PATHを設定していれば
下記をコマンドプロンプトで実行するとファイルが出力されます。

```
mongo --username [ログインユーザ名] --password [パスワード] --authenticationDatabase [DB名] --host [ホスト名] .\sample.js > [出力ファイル名]
```

目的のリストを作成したり、Excelなんかでリストをこねくり回したりしたいときなんかに便利です！
正規表現を使用して都道府県コードを抽出する。また配列から該当する要素を抽出する。


国土交通省だかどこだかかが出している都道府県コードを判定する正規表現が必要だったので書きました。
おまけでPHPを使用した「配列から都道府県コードに該当する要素を抽出する」コードも載せておきます。

# 正規表現

`^([1-9]|0[1-9]|[1-3][0-9]|4[0-7])$`

1~47までの数字と0埋めの01~09に当てはまる文字列を検索します。
`[1-9]`の部分で1～9を、`0[1-9]`の部分で0埋めの01～09を定義しています。
コピペする場合は必要に応じて該当部分を消すとよいと思います。

# 配列から都道府県コードに該当する要素を抽出する

※ PHP用に正規表現の文字列にバックスラッシュを追記しています。

```a.php
$prefectures = [
    '0',
    '01',
    '2',
    '47',
    '48',
    '100',
    'hogehoge'
];

// 正規表現にマッチする要素のみ抽出する
$match_prefecture = preg_grep('/^([1-9]|0[1-9]|[1-3][0-9]|4[0-7])$/', $prefectures);

// 結果を出力
print_r($prefectures, true);
print_r($match_prefecture, true);
```

上記コードの出力結果

```
Array
(
    [0] => 0
    [1] => 01
    [2] => 2
    [3] => 47
    [4] => 48
    [5] => 100
    [6] => hogehoge
)

Array
(
    [1] => 01
    [2] => 2
    [3] => 47
)
```

めでたしめでたし
<input>要素の maxlength を絵文字にも対応させる

サロゲートペア文字列に対する対応が、最近の JS では意外と簡単にできるようになっていたので覚え書きです。:sunglasses:
**ちなみに IE :shit: は非対応なので、IE 対応が必要な方は本気を出してください。**

[追記] タイトルが微妙に嘘をついてました。`maxlength` は使わずに、最大入力文字数の制御をします。

## サロゲートペア文字列を正しくカウントする

### :no_good_tone1: NO GOOD

```js
'𥹖𥹢𥹥'.length // 6
'𥹖𥹢𥹥'.split('').length // 6
```

### :ok_woman_tone1: OK

```js
[...'𥹖𥹢𥹥'].length // 3
Array.of(...'𥹖𥹢𥹥').length // 3
'𥹖𥹢𥹥'.match(/./ug).length // 3
```

参考までに、以下は`<input>` 要素にサロゲートペア文字列を入力すると、`maxlength` が正しく動作しない問題を、このやり方を使い改善したサンプルです。Vue でコンポーネント化しています。

<p class="codepen" data-height="683" data-theme-id="0" data-default-tab="result" data-user="megurock" data-slug-hash="jdxRvG" style="height: 683px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid black; margin: 1em 0; padding: 1em;" data-pen-title="TextInput">
  <span>See the Pen <a href="https://codepen.io/megurock/pen/jdxRvG/">
  TextInput</a> by Eiji Meguro (<a href="https://codepen.io/megurock">@megurock</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>


## サロゲートペア文字列の文字コードを正しく取得する

[String.prototype.charCodeAt()](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/charCodeAt) の代わりに、[String.prototype.codePointAt()](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/codePointAt) を使います。

### :no_good_tone1: NO GOOD

```js
'𥹖'.charCodeAt(0) // 55383
```

### :ok_woman_tone1: OK

```js
'𥹖'.codePointAt(0) // 155222
```


## サロゲートペア文字列を文字コードから正しく表示する

[String.fromCharCode()](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/fromCharCode) の代わりに、[String.fromCodePoint()](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/fromCodePoint) を使います。

### :no_good_tone1: NO GOOD

```js
String.fromCharCode(155222) // "幖"
```

### :ok_woman_tone1: OK

```js
String.fromCodePoint(155222) // "𥹖"
```
MarkLogic独自の更新系XQuery関数

概要
===
MarkLogicで実行できるXQueryの関数は、W3C標準のものに加えてMarkLogic独自の関数が用意されています。W3C標準の関数はfn:docのような検索やfn:replaceのような変換を行います。これに対して本稿ではMarkLogic独自の関数のうち更新処理を行うものを取り上げます。

ドキュメント挿入クエリ
===
ドキュメントの挿入は[xdmp:document-insert](https://docs.marklogic.com/xdmp:document-insert)を使います。この関数は第１引数に挿入先、第２引数に挿入内容を設定します。第３引数はオプションです。コレクションやアクセス権を任意に設定したいときに用います。これらは後々設定するよりも、挿入時にこの関数で決めておいた方が良いと思います。ver9から第３引数の記入方法が大きく変わっていますので、ver9へのバージョンアップではくれぐれもご注意ください。
下記のサンプルは異なる記述方法で同じ挿入内容を作り、それぞれ別々のドキュメントURIで挿入を行うというものです。最もやりやすい記述方法を選んでいただければと思います。なおxdmp:document-insertは戻り値を返しません。
サンプルコードはクエリコンソール(ポート8000番)などで試してみて下さい。

```
xquery version "1.0-ml";
(: 挿入先URIヘッダ :)
let $dir := "/insTest/"
(: 挿入内容 :)
let $content1 := element {"root"}{element {"a"}{"x"}}
let $content2 := <root><a>x</a></root>
let $content3 := xdmp:unquote("<root><a>x</a></root>")
let $content-seq := ($content1, $content2, $content3)
(: 挿入 :)
for $content at $cnt in $content-seq
  let $uri := fn:concat($dir, $cnt, ".xml")
  return xdmp:document-insert($uri, $content)
```

挿入されたドキュメントは、いずれもこんな感じになります。

```
<root><a>x</a></root>
```

ドキュメント更新クエリ
===
ドキュメントの部分更新は、xdmp:node-replaceなどを使います。他の関数も含めて表にまとめます。経験的には一旦入れたドキュメントを更新するよりも、同じURIにxdmp:document-insertなどで上書き挿入した方が性能が良いような気がします。

| 関数 | 説明 |
| --- | --- |
| [xdmp:node-insert-before](https://docs.marklogic.com/xdmp:node-insert-before) | 指定した要素の前に要素を挿入する |
| [xdmp:node-insert-after](https://docs.marklogic.com/xdmp:node-insert-after) | 指定した要素の後ろに要素を挿入する |
| [xdmp:node-insert-child](https://docs.marklogic.com/xdmp:node-insert-child) | 指定した要素の子供として要素を挿入する |
| [xdmp:node-replace](https://docs.marklogic.com/xdmp:node-replace) | 指定した要素を取り換える |
| [xdmp:node-delete](https://docs.marklogic.com/xdmp:node-delete) | 指定した要素を削除する |

xdmp:node-insert-beforeでサンプルを作ってみました。URI名に設定した数字を基にno要素を追加していきます。

```
xquery version "1.0-ml";
(: 更新対象URIヘッダ :)
let $dir := "/insTest/"
(: 更新対象の確認 :)
let $uri-seq := cts:uris((), (), cts:directory-query("/insTest/", "1"))
(: 更新 :)
for $uri in $uri-seq
  let $doc := fn:doc($uri)
  let $uriTokenized := fn:tokenize($uri, "/")[fn:last()]
  let $cnt := fn:substring-before($uriTokenized, ".xml")
  let $nodeInserted := element {"no"}{$cnt}
  return xdmp:node-insert-before($doc/root/a, $nodeInserted)
```

更新されたドキュメントのうち/insTest/1.xmlはこんな感じになります。

```
<root><no>1</no><a>x</a></root>
```

このクエリ自体は挿入クエリ内を書き換えることで、挿入クエリに統一できますが、何らかの形で既存データの修正を求められる場合には必要になると思います。大量のデータを処理する場合は、このようなforループではなく、AP側のマルチスレッド処理かxdmp:spawn系関数でタスクサーバを使うなどの並列処理をお奨めします。

ドキュメント削除クエリ
===
ドキュメントの削除は、xdmp:document-deleteを使います。ここで挿入・更新してみた3つのドキュメントを削除するサンプルを作りました。cts:urisという関数を使って削除対象となるURIシーケンスを作成して、forループで1個ずつ削除しています。大量のデータを対象にする場合は、やはり並列処理を視野に入れておくべきです。

```
xquery version "1.0-ml";
(: 削除対象URIヘッダ :)
let $dir := "/insTest/"
(: 削除対象URI :)
let $uri-seq := cts:uris((), (), cts:directory-query($dir, "1"))
(: 削除 :)
for $uri in $uri-seq
  return xdmp:document-delete($uri)
```

雑感
===
W3C標準関数を補完する形で存在するこれらの関数は、単に検索だけでなくCRUDを備えたデータベースとしての機能を整えるものです。一方で製品独自の関数というのは個別の勉強が必要となり取っ付きにくくなる要因です。ひとまずここにある関数ぐらいは記憶しておきたいですね。


------------------------------------------------------------------------
AWS CDK(TypeScript)でリソース毎にファイルを作る


```
$ cdk --version
0.23.0 (build 1d705e7)
```

## やりたいこと
AppSyncなど、いろんなリソースを作る必要がある場合、`lib/aws-cdk-stack.ts`ファイルが冗長になる。
リソース毎に別ファイルで管理して、見通しを良くしたい。

## やったこと

こんな感じのクラスを作る。

```typescript

import cdk = require('@aws-cdk/cdk');
import IAM = require('@aws-cdk/aws-iam')

class IAMRole {
  static create(stack: cdk.Stack, name: string) {
    const servicePolicy = new IAM.Policy(
      stack,
      'AppSyncInlinePolicy', {
        policyName: `${name}InlinePolicy`,
        statements: [
          new IAM.PolicyStatement()
            .allow()
            .addActions(
              "dynamodb:GetItem",
              "dynamodb:Query",
              "dynamodb:Scan",
            )
            .addResources(
              "arn:aws:dynamodb:us-east-1:*:table/MyTable"
            )
        ]
      }
    )

    const serviceRole = new IAM.Role(stack, `${name}DynamoDBRole`, {
      assumedBy: new IAM.ServicePrincipal('appsync.amazonaws.com'),
      path: '/service-role/'
    })
    serviceRole.attachInlinePolicy(servicePolicy)
    return serviceRole
  }
}

export default IAMRole
```

元ファイルでは以下のように呼び出す。

```typescript

import cdk = require('@aws-cdk/cdk');
import IAMRole from './iam'

export class AwsCdkStack extends cdk.Stack {
  constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
    const serviceRole: IAM.Role = IAMRole.create(stack, id)
  }
}
```

## 雑多なこと

### クラスにする必要ある？
`IAMRole.create`って書きたかったからそうした。特に意味はなく、関数にしても良いと思う。

```typescript

const createIAMRole = (stack: cdk.Stack, name: string): IAM.Role => {
    const servicePolicy = new IAM.Policy(
      stack,
      'AppSyncInlinePolicy', {
        policyName: `${name}InlinePolicy`,
        statements: [
          new IAM.PolicyStatement()
            .allow()
            .addActions(
              "dynamodb:GetItem",
              "dynamodb:Query",
              "dynamodb:Scan",
            )
            .addResources(
              "arn:aws:dynamodb:us-east-1:*:table/MyTable"
            )
        ]
      }
    )

    const serviceRole = new IAM.Role(stack, `${name}DynamoDBRole`, {
      assumedBy: new IAM.ServicePrincipal('appsync.amazonaws.com'),
      path: '/service-role/'
    })
    serviceRole.attachInlinePolicy(servicePolicy)
    return serviceRole
  }
```

このあたりは好みでしょう。
RubyXLでシートの順番を変えたい

## 概要

調べてもどこにも見つからなかったのでメモ。  
案外普通にできた。

```ruby
xl = RubyXL::Parser.parse('hoge.xlsx')
xl.worksheets = xl.worksheets.reverse
xl.write('hoge2.xlsx')
```

## 解説

workbookオブジェクトのworksheetsを並び替えすればいい。
シートの削除もできた。
Amazon WorkDocs 導入

# 概要

DropBox 的なものを社内で急遽用意しなければならなくなりました。そこで Amazon WorkDocs を使ってみることにしました。今回は、導入編です。

以下でも同様の記事をアップしていますので、よろしければどうぞ。  
[Amazon WorkDocs その 1 -- 導入](https://stangler.hatenablog.com/entry/2019/02/12/124148)

# 参考サイト
  
*  [Amazon WorkDocs ドキュメント](https://docs.aws.amazon.com/workdocs/index.html#lang/ja_jp)

# クイックスタート

まずは、AWS のコンソールで、WorkDocs のページを開き、「今すぐ開始する」ボタンをクリックします。  
  
![20190125_WorkDocs_01.png](https://qiita-image-store.s3.amazonaws.com/0/344724/1944c596-3594-e165-6d44-4ae16a3a713e.png)
 
  
次のページ「 WorkDocs の使用を開始する方法 」で、とりあえず今回はクイックスタートの「起動」ボタンをクリックします。  
  
![20190125_WorkDocs_02_クイックスタート01.png](https://qiita-image-store.s3.amazonaws.com/0/344724/46dc2129-bee5-4627-f3c5-048ee32774d5.png)

  
次に、必要事項を記入し、「セットアップの完了」ボタンをクリックします。  
  
![20190125_WorkDocs_03_クイックスタート02.png](https://qiita-image-store.s3.amazonaws.com/0/344724/a7a25c5f-d211-e2f4-e19e-0e14c7a163e0.png)

  
次のページで、ステータスが「初期化中」と表示されますので、しばらく待ちます。  
  
![20190125_WorkDocs_04_プロビジョニング中.png](https://qiita-image-store.s3.amazonaws.com/0/344724/8a7aa08d-fd84-395e-d1a3-0873456aeb64.png)

  

# 管理者の設定
  
ステータスが「有効」になったら、「アクション」ボタンをクリックし、プルダウンメニューの「管理者の設定」 をクリックします。  
  
![20190125_WorkDocs_05_管理者設定01.png](https://qiita-image-store.s3.amazonaws.com/0/344724/cc5b2b4f-2ec4-9278-23b3-df3275194b8e.png)

  
次に「ユーザー名」のところに、先ほど登録したメールアドレスを記入して「管理者の選択」ボタンをクリックします。  
  
![20190125_WorkDocs_06_管理者設定02.png](https://qiita-image-store.s3.amazonaws.com/0/344724/6e3ee6e0-d8c4-6b6c-a8d2-6376e75aa76d.png)

  
次の画面で以下のように表示されれば OK です。  
  
![20190125_WorkDocs_07_管理者設定03.png](https://qiita-image-store.s3.amazonaws.com/0/344724/3d783968-df09-f9c3-05b4-97d3ffe9e025.png)

  
# メール確認
  
この時点で、先ほど登録したメールアドレスに「 Welcome to Amazon WorkDocs 」という件名で、メールが届いているので、それを開いてみて、「 Get Started! 」ボタンをクリックしてください。  
  
![20190125_WorkDocs_08_メール確認01.png](https://qiita-image-store.s3.amazonaws.com/0/344724/736f2841-a9e8-b67e-cf84-37a78e1c3b2e.png)

  
### 認証情報設定
  
「 Get Started! 」ボタンをクリックすることによって、ブラウザが開かれ、次のような入力画面になるので、適宜、必要事項を入力してください。  
  
![20190125_WorkDocs_09_認証情報設定01.png](https://qiita-image-store.s3.amazonaws.com/0/344724/649efb9a-fc7c-852a-5e03-b201c653460f.png)


「ユーザーの更新」ボタンをクリックして以下のような画面が表示されれば、WorkDocs の導入完了です！  
  
![20190125_WorkDocs_10_導入完了.png](https://qiita-image-store.s3.amazonaws.com/0/344724/33c013e6-b3d0-2215-10f5-ff19654e6a0e.png)

以上です。
Kotlin: Map や List のような [ ] でのアクセスを実装する方法 

Kotlin で Map, List などで使える `[ ]` でのアクセスを実装するには次のようにする。

```kotlin
class Something {
    operator fun get(): Any {
        // ...
    }
}
```

`[ ]` では この `get` を使ってアクセスしている。
janomeで名詞をいい感じに取り出す

# どんな記事？
データフレームから普通名詞のみを抽出する処理をテンプレ化した記事です。
コピペで動きます。品詞の設定や記号の除去など毎回覚えて書くのは難しいので自分用の備忘録として書きました。

# 設定
### データの準備
data が以下のような構造になっていることを想定しています。

|index|text|
|:-:|:--|
|0|がっかりした。届いた時点で商品が壊れていました。本当…|
|1|個人的には満足です。価格が安いので何回でも…|
|2|丁寧に対応していただき感謝です。問題は…|

### モジュールの読み込み

```py
from janome.tokenizer import Tokenizer
from janome.analyzer import Analyzer
from janome.tokenfilter import *
from janome.charfilter import *
```

### 形態素解析器の設定

```py
char_filters = [UnicodeNormalizeCharFilter(), RegexReplaceCharFilter(r"[IiⅠｉ?.*/~=()〝 <>:：《°!！!？（）-]+", "")]
tokenizer = Tokenizer()
token_filters = [POSKeepFilter(["名詞"]), POSStopFilter(["名詞,非自立", "名詞,数", "名詞,代名詞", "名詞,接尾"]), LowerCaseFilter()]
analyzer = Analyzer(char_filters=char_filters, tokenizer=tokenizer, token_filters=token_filters)
```
### 実行
```py
data.loc[:,'words'] = data.text.apply(lambda x: " ".join([token.surface for token in analyzer.analyze(x)]))
```
Kivyで日本語入力

[こちら](https://github.com/Naotonosato/MilletPie/blob/master/ime_operator.cpp)にあるようにWindows APIの一つであるIMM APIを直に叩いてパッチを作成しました。

IMM APIは具体的な使用例などが載ったドキュメントなどは少なく、ctyepesを使った事もなかったのでそこそこ苦労しました。
ですので本記事がグラフィックライブラリのIME関連の実装をやってみようという方の一助となれば幸いです。

## IMM API
さて、基本的な使い方ですが

```c++
HWND hWnd = GetActiveWindow();
HIMC hImc = ImmGetContext(hWnd);
ImmReleaseContext(hWnd, hImc);
```

とすることでhImcを取得し、各IMM関数に引数として渡す、という感じです。
最後のImmReleaseContextは忘れないでくださいね。IMMを利用するときのお約束みたいなものです。

本記事ではKivyのIME対応に必要としたIMMの機能について解説します。
まずは未確定文字列（コンポジション文字列）を取得する方法について。

```c++:get_composition.cpp
HWND hWnd = GetActiveWindow();
HIMC hImc = ImmGetContext(hWnd);

char compStr[1028];
int size = ImmGetCompositionStringA(hImc, GCS_COMPSTR,NULL,0);

ImmGetCompositionStringA(hImc, GCS_COMPSTR, compStr, size);
compStr[size] = '\0';
ImmReleaseContext(hWnd, hImc);

//return compStr;
```
こんな感じにしてやればいいわけです。
ところでget_composition.cppではImmGetCompositionString関数を二回呼び出していますが、
一度目の呼び出しはコンポジション文字列のサイズ(バイト単位)を得るためだけの呼び出しです。
このようにサイズの取得を目的とする場合は、第三、第四引数にNULLと0を渡します。
ちなみに第二引数は「俺が得たいのはコンポジション文字列だよ」ということを表しています。
この辺の定数はMicrosoftのドキュメントを参照してください。


次は
確定された文字列を取得する方法です。
これも先ほどと同じように

```c++:getEnteredString.cpp
HWND hWnd = GetActiveWindow();
HIMC hImc = ImmGetContext(hWnd);

char compStr[1028];
int size = ImmGetCompositionStringA(hImc, GCS_RESULTSTR, NULL, 0);

ImmGetCompositionStringA(hImc, GCS_RESULTSTR, compStr, size);
compStr[size] = '\0';
ImmReleaseContext(hWnd, hImc);
//return compStr;
```
こんな感じにしていけばいいわけです。
さっきと違うのは第二引数のGCS_RESULTSTRですね。
こいつを引数として渡してやることで「俺が得たいのは確定済み文字列だよ」ということを伝えています。

次は、コンポジション文字列をセットする方法について見ていきましょう。

```c++:set_composition_string.cpp
HWND hWnd = GetActiveWindow();
HIMC hImc = ImmGetContext(hWnd);
char cmpStr[] = "テスト文字列～この文字列が表示される～"

ImmSetCompositionStringA(hImc, SCS_SETSTR, cmpStr, sizeof(cmpStr), NULL, 0);
ImmNotifyIME(hImc, NI_COMPOSITIONSTR, CPS_CONVERT, 0);
ImmReleaseContext(hWnd, hImc);
```
今回は新しい関数が出ましたね。まずはImmSetCompositionStringについて。
この関数は第二、第三引数にそれぞれセットしたい文字列のポインタとそのサイズを渡してやることでコンポジション文字列をセットできます。
あ、第二引数のNI_COMPOSITIONSTRは「俺がセットしたいのはコンポジション文字列だよ」ということを表しています。

次のImmNotifyIME関数は、「コンポジション文字列をセットさせてもらったからよろしく」
ということをIME側に伝える関数です。この関数の引数についてはMicrosoftのドキュメントを参照してください。

最後にIMEが開いているか否かを得る方法について。

```c++:is_openIME.cpp
HWND hWnd = GetActiveWindow();
HIMC hImc = ImmGetContext(hWnd);
bool is_opening = ImmGetOpenStatus(hImc) ? true:false;
ImmReleaseContext(hWnd, hImc);
```
これは解説するまでもないですね。
以上ーーー！！

##kivy
kivy側の解説は後日やる気があったら

##ctypes 
c++ <=> python間の連携はctypesを使いました。やる気があったら後日載せます。

#Usage
試してみたい方は[こちら](https://github.com/Naotonosato/MilletPie) をcloneして
`python multi_language_textinput.py`
もしくは
`python3 multi_language_textinput.py`
として試してみてください。
SPSS ModelerでExcelの日付データを読み込む

SPSS ModelerでExcelの日付データを読み込むときには注意があります。

#１ 「yyyy-mm-dd」のフォーマットで読み込む
一番手堅いのがこの方法です。
Excelのセルを「yyyy-mm-dd」のフォーマットで指定します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/223763/6539fd15-5026-a81c-b850-88fc29cd50c4.png)

Modelerのストリームのオプションでも同じフォーマットを指定します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/223763/1a925fd8-14e7-0a18-0364-ecf8dd69ec78.png)

#2 「yyyy/m/d」、「*yyyy/m/d」、「*yyyy年m月d日」などの自動変換が可能なフォーマットを使う
一部のフォーマットはModelerが自動的に変換をかけてくれます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/223763/0e4fef70-a7af-96cf-3eeb-5d3153d1fea2.png)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/223763/779ea277-7824-36ad-5cbb-3092d2ad55c7.png)

#3 「m月d日」などのシリアルで読み込んでしまうフォーマットをModeler側で変換する
「m月d日」のようなフォーマットは日付型としては読み込めません。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/223763/c4ca853f-b8b0-6e6c-d248-6967128bf502.png)

以下のようにシリアル値になってしまいます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/223763/732f0e6c-dcf4-44b0-2361-b2e47736aff0.png)

以下のように置換ノードで`datetime_date(to_integer(日付-2)*60*60*24)`で変換をすると日付データとして扱えるようになります。（シリアル値の起点などにExcelとの差があるため-2しています。）
![image.png](https://qiita-image-store.s3.amazonaws.com/0/223763/9914a685-c2a6-362d-a09d-3c9ce913d7c6.png)


![image.png](https://qiita-image-store.s3.amazonaws.com/0/223763/7fd50e5c-8a5d-d48b-e852-b4e7c3c43ea4.png)

# テスト環境
SPSS Modeler 18.2
Windows 10 64bit
Microsoft Excel 365

# 参考
IBM Excel 2007形式ファイルに含まれた「YYYY/MM」書式日付型セルのインポート方法 - Japan
http://www-01.ibm.com/support/docview.wss?uid=swg21972892
UiPath ログレベルに関して

## UiPathの "Log Message" アクティビティのログレベルについて

- テストのために以下のWFを作成  
![image.png](https://qiita-image-store.s3.amazonaws.com/0/158953/f54cc34b-53ab-931a-c059-9f2fcb42e1fc.png)

UiPath Robotの"Robot Logging"のLevelを変更して出力されるログを確認
- 下記設定画面
![003.png](https://qiita-image-store.s3.amazonaws.com/0/158953/72b19808-bcbe-c16d-452c-1babbfce61b5.png)

### Level : Information
出力されたログ
- Info , Warn , Error , Fatal

### Level : Trace
出力されたログ
- Trace , Info , Warn , Error , Fatal

## 結論
UiPath Robotの "Robot Logging" で設定できるのは、ロボット開発時に設定したログごとのレベルについて出力する絞込みが行える。

反対に"Trace"にしておけば、UiPath Studio のデバッグ時みたいに、アクティビティごとの開始、終了ログまで出力してくれるわけではない。
Rails Docker環境でメール送信の動作確認 （mailcatcher）


[RailsプロジェクトでSMTPサーバ持ってないけど、メール送信機能が正常に動作してるか確認したいとき！](https://qiita.com/shinofara/items/3ea9591f7bd2f0348227)
こちらの記事を参考にさせていただきましたが、少しつまずいたの記録します。

## docker-compose.yml

```yml:docker-compose.yml
  smtp:
    image: schickling/mailcatcher
    ports:
      - "1080:1080"
      - "1025:1025"
```


## development.rb

（つまずいた所）addressはlocalhostではなく`docker-compose.yml`で定義したservice名(smtp)を指定しないとうまくいかない。

```rb:config/environments/development.rb
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = { :address => "smtp", :port => 1025 }
config.action_mailer.raise_delivery_errors = true
```

## 実行

```sh
docker-compose up
```

http://localhost:1080
にアクセスするとWEB上でメールが確認できます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/123603/ac52ecfc-598c-61b7-0727-48dc4dacc937.png)


`rails c` `rails runner`等でメール送信するとこちらに送信されることが確認できます。

動作確認などでご活用ください。
簡単に構築できます。
【ACCESS】完全なテーブルのコピーをする方法。（インデックス付き）

備忘録として残します。

ACCESSで作業用のテーブルをオリジナルからコピーすることあると思いますが、私は下記のSQLを実行して作業用テーブルを作成していました。
`select * into 作業用テーブル from オリジナルテーブル`

しかし、上記の場合は、インデックス関係のキー情報まではコピーされないため、完全なコピーではありません。
インデックス関係も込み込みでコピーしたい場合は、VBA上で下記のコードを実行するとキー情報等も付いてコピーができます。

```vb
DoCmd.CopyObject , "作業用テーブル", acTable, "オリジナルテーブル"
```
#■追記（重要）
*上記の方法は`リンクテーブルでない`物理的なテーブルがコマンドを実行するACCESSにある場合に限りテーブルの複製ができます。
そのため、リンクテーブルのオブジェクトをコピーする場合はリンクテーブル情報がオブジェクトとして複製されるため、物理的なテーブルの複製はできません。*
git cryptを導入する

# git-cryptを使って公開したらやばい情報を暗号化して管理する
社内で開発プロジェクトにgit-cryptを導入しようとした時のまとめ
※ クライアントはmac前提でhomebrew導入済み
GPGを使って公開鍵秘密鍵を用い、gitリモート上は暗号化したファイルを管理し、ローカルでは秘密鍵で復号化したファイルを扱う。
## パッケージインストール
**【やる人：プロジェクトメンバー全員】**
以下をローカルインストール

* GPG関連
 
```
$ brew install gnupg gnupg2 pinentry-mac
$ mkdir ~/.gnupg
$ echo "pinentry-program /usr/local/bin/pinentry-mac" >>~/.gnupg/gpg-agent.conf
```
* git-crypt

```
brew install git-crypt
```
## 鍵を作る
**【やる人：最低導入者一人。個々に管理したい場合は全員】**
ローカルで以下を実行

* キーペア作成

```
$ gpg --generate-key
# 対話形式でuserid, email, password(任意)を入力
```
* 公開鍵エクスポート

```
$ gpg --output [任意の公開鍵名].gpg --export [作成したキーのemail]
```
## gitリポジトリへの導入
**【やる人：導入者】**

* 自分以外のチームメンバーの鍵を登録する場合(公開鍵のインポート)

```
# 公開鍵をインポート(事前に公開鍵をもらっとく)
$ gpg --import [貰った公開鍵ファイル]
# 鍵を信頼する手続き
$ gpg --sign-key [上の鍵で登録したemail]
```
* リポジトリ適用

```
# gitリポジトリルートで実行
$ git crypt init
# 対象メンバーを登録。自分もしくは自分以外の事前に上で公開鍵をインポートしたメンバーを指定(人数分実行)
$ git crypt add-gpg-user [鍵登録してるemail]
```
リポジトリルートに `.git-crypt` ディレクトリが作成され、 `.git-crypt/keys/default/0/` に公開鍵が配置される

* 秘密情報ファイルの指定  
暗号化してgit管理したいファイルをリポジトリルートの `.gitattributes` に記載

```
# ファイル数分記載する
$ vi .gitattributes
[暗号化したいファイル名] filter=git-crypt diff=git-crypt
...
```
* gitに登録  
普通にaddしてcommit  
ローカル上は暗号化されてないように存在しているが、リモートにプッシュしてリモート上で見ると暗号化されたファイルとなっている  
**※ `.git-crypt` `.gitattributes` をgitignoreしたらダメ**

## プロジェクト導入
**【やる人：リポジトリ導入者以外全員】**  
何もしないと暗号化されたファイルがローカルに存在する事になるので復号化処理をする。
たまに暗号化してたら同様に行う。

```
# 対象リポジトリクローンとか導入後のmasterを反映したのち
$ git-crypt unlock
```
## 一つの鍵でチーム運用
以下のいずれかで行う
### 1. 対象鍵を共有する場合
* 鍵作成者
   
```
# 対象鍵を生成 （例:taishoukagi.key）
git-crypt export-key taishoukagi.key
```
* 鍵貰う人  
事前に上記で生成した `taishoukagi.key` を貰っておく

```
# ローカルに配置 (例:~/.gnupg/) 後、unlockする
git-crypt unlock ~/.gnupg/taishoukagi.key
```

### 2. 秘密鍵を共有する場合
* 鍵作成者

```
# 公開鍵のエクスポート
$ gpg -a --export [キー登録されてるemail] > public.txt
# 秘密鍵のエクスポート
$ gpg -a --export-secret-keys [キー登録されてるemail] > secret.txt
# 公開鍵の信用情報エクスポート
$ gpg --export-ownertrust > trust.txt
```
* 鍵貰う人  
事前に上記で作成した `public.txt` `secret.txt` `trust.txt` を貰っておく

```
# 公開鍵のインポート
$ gpg --import public.txt
# 秘密鍵のインポート
$ gpg --import --allow-secret-key-import secret.txt
# 公開鍵の信用情報インポート
$ gpg --import-ownertrust trust.txt
# 状態の確認 uidが[究極]になってたらOK
$ gpg --list-secret-keys
```

## 参考
https://dev.classmethod.jp/tool/git/git-crypt/
https://text.baldanders.info/openpgp/openpgp-key-management/
https://lpi.or.jp/ex/303/ex_755.shtml
https://cast-a-spell.at.webry.info/200701/article_16.html
PhpSpreadsheetでセル内改行する

PhpSpreadSheetでExcelファイルを出力する際、セル内改行が必要な場面に遭遇。
とりあえず\nを織り交ぜてみたが、半角スペースみたいなスペースが空くのみで改行されず。

色々試した結果、以下のような記述で実装可能。

```php:hoge.php
require 'vendor/autoload.php';
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Reader\Xlsx as XlsxReader;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx as XlsxWriter;
```

```php:hoge.php
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();

//セル内改行指定
$sheet->getStyle('A1:C3')->getAlignment()->setWrapText(true);
$sheet->setCellValue("A1","hello\nhello\n");
$sheet->setCellValue("B2","hello\nhello\n");
$sheet->setCellValue("C3","hello\nhello\n");

$writer = new XlsxWriter($spreadsheet);
$fileName = 'test.xlsx';
header("Content-Description: File Transfer");
header('Content-Disposition: attachment; filename="'.$fileName.'"');
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Transfer-Encoding: binary');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Expires: 0');
ob_end_clean();
$writer->save('php://output');
```

getStyle('A1:C3') のところだけ書き換えればOKですね。


【追記】
DLしたファイルが「破損している」的なことを言われる時は、最後の行に

```php:hoge.php
$writer->save('php://output');
exit;
```

と、exit; を入れてみて下さい。
enumを使って日本語表記セレクトタグを作ったので覚え書き

##概要
複数の父親を持つ複雑な家庭環境を表現してみましょう。
(本来こんなことで使わないでしょうが、いろいろこれ用に書き換えてたらこうなりました…
この場合、普通に"dad"はChildのカラムとして使うことならありそうかな…テーブル分ける必要はゼロですね。)

##環境
Rails5.1
jquery3.3.1
mysql

###データベース
親
*Father*

|id |dad|
|:-:|:--------:|
|1  |0|
|2  |1|
|3  |2|

子
*Child*

|id|name|father_id|
|:-:|:--|:----:|
|1 |hoge|1|
|2 |fuga|1|
|3 |hogehoge|2|
|4 |hiroshi|2|

(母：マダム)

##コード

father（単数）ー children（複数）
の関係です。
子モデル設定▼

```models/child.rb
class Child < ApplicationRecord
  belongs_to :father
end

```
親モデル設定▼

```models/faher.rb
class Father < ApplicationRecord
  has_many :children
  enum fathers: {dad_1: 0,dad_2: 1,dad_3: 2}
end
```

フォーム部分でも表示される変換後の内容▼

```config/locale/ja.yml
ja:
  children:
    fathers:
      dad_1: '最初のお父さん'
      dad_2: '今のお父さん'
      dad_3: '未来のお父さん'
```

コントローラーはテキトー設定をして
…

フォーム部分▼

```view/form.rb
= form_for(@child, url: hoge, html: {method: :post}) do |f|
= f.text_field :name, placeholder: "new_baby"
= f.select :father, Child.fathers.map{
|k, v| [t("children.father.#{k}"), v]
}, prompt: "—"
```

はい、
これで末っ子のヒロシくんの次に生まれてくるとしたら誰の子なのかはっきりしますね笑
（実際はみんな一人目の子供みたいですね。
てかこのために調べたら４人兄弟とか、某大企業元代表の子って、知らなかったです。）

冒頭でも書いているように使用する場面は違うでしょうが、覚書程度に使い方の復習メモです。

※この内容はフィクションです。実在の人物や団体などとは関係ありません。

勉強中の身のため、
ご指摘等あればコメントにてお願いいたします。
役に立つか未知数、不思議なVSCodeの拡張機能まとめ

# はじめに
役に立つのか首を傾げてしまうようなおすすめ(？)の拡張機能です
どんな言語でも使える(？)不思議な拡張機能をまとめました

## 遊べる拡張機能
### [line-erase-game](https://marketplace.visualstudio.com/items?itemName=taiki.line-erase-game)
>This is a game similar to Tetris .
>上から降ってくるブロックを横一列に並べて消す例のあれです。

###[Mr Smiley](https://marketplace.visualstudio.com/items?itemName=bbaker13.mrsmiley)
敵を避けながらゴールへ進む見下ろし型のアクションゲームです

##見た目を変える拡張機能
### [background](https://marketplace.visualstudio.com/items?itemName=shalldie.background)
![40583705-7105dda8-61c6-11e8-935a-3c5d475a1eb1.gif](https://qiita-image-store.s3.amazonaws.com/0/212160/1bdffedc-041e-4fb5-2a00-5270772dd77e.gif)
痛Monoのようにエディタの背景に画像を設定できるようにする拡張機能

###[Cage Icons](https://marketplace.visualstudio.com/items?itemName=stepanog.cage-icons)
![example.png](https://qiita-image-store.s3.amazonaws.com/0/212160/33af59a2-199b-c024-f0d9-8debc3c8779f.png)
アイコンをケイジさんの顔写真に変更する拡張機能
ファイルによって顔写真が変わるようになっているが全く判別がつかない…

## その他
### [Twitter Client](https://marketplace.visualstudio.com/items?itemName=austin.vscode-twitter)
![3_columns.png](https://qiita-image-store.s3.amazonaws.com/0/212160/9b71981a-eae4-7e5f-67ee-1608fb5b7087.png)

VSCode上でTwitterを見られるようにする拡張機能
フォロワーからやる気をもらってる人には便利かも
mongo-express で複数DBを見る方法

こんにちは。[@koshi_life](https://twitter.com/koshi_life) です。

前回 [3分で導入できる MongoDB データ可視化ツール mongo-express](https://qiita.com/koshilife/items/dcc2b17e4c880d65ba78) 書いたように、MongoDBの可視化ツール[mongo-express](https://github.com/mongo-express/mongo-express) を使ってるのですが、複数DBを見る方法を調べたので備忘です。

# これだけ

環境変数 `ME_CONFIG_MONGODB_ENABLE_ADMIN` を true にしてadmin接続許可をするだけ。

```
$ env ME_CONFIG_MONGODB_ENABLE_ADMIN=true node app
```

### 起動例


```
$ env ME_CONFIG_MONGODB_ENABLE_ADMIN=true node app
Welcome to mongo-express
------------------------


Mongo Express server listening at http://localhost:8081
basicAuth credentials are "admin:pass", it is recommended you change this in your config.js!
Database connected
Admin Database connected
```

<img width="８００" alt="スクリーンショット 2019-02-12 13.49.38.png" src="https://qiita-image-store.s3.amazonaws.com/0/51734/fb13aae6-a3b3-eefc-c772-9a1099e8cd0c.png">


- 参考:
  - [How to connect to multiple databases?](https://github.com/mongo-express/mongo-express/issues/336)
Mosquittoサーバー起動及びパブリッシュとサブスクライバの使い方

# Mosquittoの場所
Mosquittoは、こちらの環境に置いておく場所は以下の通りです

- /usr/sbin/
 - Mosquitto
- /usr/bin/
 - mosquitto_pub
 - mosquitto_sub
- /etc/mosquitto/
 - ca_certificates  
 - certs  
 - conf.d  
 - mosquitto.conf

# Mosquittoサービスの起動と確認

```bash
$ cd /usr/sbin
# サーバー起動
$ mosquitto -c /etc/mosquitto/mosquitto.conf -v
# 利用中ポート確認
$ ss -ilt4
State   Recv-Q   Send-Q   Local Address:Port     Peer Address:Port                  
LISTEN  0        128      127.0.0.53%lo:domain   0.0.0.0:* cubic cwnd:10 
LISTEN  0        128      0.0.0.0:ssh            0.0.0.0:* cubic cwnd:10 
LISTEN  0        5        127.0.0.1:ipp          0.0.0.0:* cubic cwnd:10 
LISTEN  0        100      0.0.0.0:1883           0.0.0.0:* cubic cwnd:10 
```
ポート1883が見ればMosquittoサーバが起動済です。

# メッセージをサブスクライバ
まず、メッセージをサブスクライバしてみましょう。

```bash
$ cd /usr/bin/
$ mosquitto_sub -h localhost -p 1883 -t topic01 
```

# メッセージをパブリッシュ
新しいTerminalを開けて、Brokerとして下記のように「hello mosquitto」メッセージをパブリッシュして置くと、サブスクライバの画面にはメッセージが受信できるはずです。

```bash
$ cd /usr/bin/
$ mosquitto_pub -h localhost -p 1883 -t topic01 -m "hello mosquitto"
```

# mosquittoサービスの停止
直接にmosquittoサービスを止めて行くことができませんが、以下でmosquittoサービスを停止して行きましょう。

```bash
$ ps -A | grep mosquitto
21674 ?        00:02:38 mosquitto
$ kill -9 21674
```
laradock メモ

とりあえずlaradock上でphp artisanしたいときは
docker-compose exec --user=laradock workspace php artisan
ここでのlaradockは指定されたユーザーの名前（多分）

mysql上で何かしたいときは
docker-compose exec mysql mysql -uroot -proot laradock
ここでのlaradockはDBの名前（多分）
自作JavaScriptライブラリを公開できるCDNサービス

npmもしくはGitHubに登録したリソースをCDNで配信してくれるサービスを利用すると、簡単に自作JavaScriptライブラリを公開できる。以下の2サービスがよく使われている。

- [jsDelivr](https://www.jsdelivr.com/)
  - npmとGitHubに対応
  - ファイルのminifyや結合もできる。
- [UNPKG](https://unpkg.com/)
  - npmに対応

※ [RawGit](https://rawgit.com/)というサービスも有名であったが2019年10月サービス終了予定となっている。
三大クラウドのrunc脆弱性(CVE-2019-5736)対応状況メモ

2019/2/13 Azureについて追記しました

## はじめに
コンテナのラインタイム runc にImportantレベルの脆弱性(CVE-2019-5736)が発表されました。
悪意のあるイメージを実行するとホストノード上でroot権限を取得することが可能になります。

各プラットフォームの対応状況についてはSIOSさんのセキュリティBlogが参考になります。

**runcの脆弱性情報(Important: CVE-2019-5736)**
https://security.sios.com/vulnerability/runc-security-vulnerability-20190211.html

この記事ではAWS/Azure/GCPの対応状況をまとめておきます。

## AWS
**Container Security Issue (CVE-2019-5736)**
https://aws.amazon.com/jp/security/security-bulletins/AWS-2019-002/

### Amazon Linux/Amazon Linux 2
Dockerのアップデート版がAmazon Linux 2およびAmazon Linux AMI 2018.03リポジトリで提供済み
https://alas.aws.amazon.com/ALAS-2019-1156.html

### ECS
最新のECS-Optimized AMIからコンテナインスタンスを起動する。

* [ECS-Optimized Amazon Linux AMI](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs-optimized_AMI_launch_latest.html)
* [ECS-Optimized Amazon Linux 2 AMI](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/al2ami.html)
* [ECS GPU-Optimized AMI](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/gpuami.html)

（言語を英語で表示すると最新のAMI IDが表示されます）

### EKS
最新のEKS Optimized AMIからワーカーノードを起動する

EKS-Optimized AMI
https://docs.aws.amazon.com/eks/latest/userguide/eks-optimized-ami.html

### Fargate
Platform Version 1.3.0で問題を軽減可能
古いプラットフォームバージョン（1.0.0/1.1.0/1.2.0）は2019年3月15日までにパッチが提供される

AWS Fargate Platform Versions
https://docs.aws.amazon.com/AmazonECS/latest/developerguide/platform_versions.html

修正プログラムが適用されていないすべてのタスクは、2019年4月19日までに**強制的に停止**される

Task Retirement
https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-retirement.html

### AWS Batch
最新のECS-Optimized AMIを使用するようにCompute Environmentを変更する。
Compute Environment のデフォルトAMIとして最新のECS-Optimized AMIが使われるよう変更されている。

### Elastic Beanstalk
最新のプラットフォームバージョンを使用する。
Managed Platform Updatesが有効な環境の場合は自動で更新される。

Release: AWS Elastic Beanstalk Docker platform updates on February 11, 2019
https://docs.aws.amazon.com/ja_jp/elasticbeanstalk/latest/relnotes/release-2019-02-11-docker.html

### Cloud9
初回起動時に自動でパッチが適用される。
既存のEC2ベースで使用している場合は、新しいCloud9バージョンでインスタンスを作成する必要がある。

### SageMaker
2月11日以降に起動されたすべてのリソースには最新の更新が含まれている。
2月11日より前に作成されたカスタムコードを使用している場合は手動のジョブ再起動が推奨される。
稼働中のすべてのエンドポイントは2月11日より前に作成されたすべてのエンドポイントは、3月11日までに
自動的に更新される予定。

## Azure
### AKS
**AKS 2019-02-12 - Hotfix Release**
https://github.com/Azure/AKS/releases/tag/2019-02-12

Kubernetes 1.12.5、1.11.7、1.10.12、1.9.11がリリースされた。
12am PST 2019-02-13 までにロールアウトされる予定。
問題を軽減するには上記のバージョンにAKSクラスターをアップグレードする必要がある。

### IoT Edge
CVE-2019-5736 fix for Azure IoT Edge
https://azure.microsoft.com/en-us/updates/iot-edge-fix-cve-2019-5736/

Azure IoT Edgeデバイス向けのコンテナーランタイム修正プログラムが配布された。
更新が推奨されている。

## GCP
February 11, 2019 (runc) - Security bulletins
https://cloud.google.com/kubernetes-engine/docs/security-bulletins

> What should I do?
In order to upgrade your nodes, you must first upgrade your master to the newest version.

このパッチは GKE 1.10.12-gke.7, 1.11.6-gke.11, 1.11.7-gke.4, 
および1.12.5-gke.5以降のリリースで利用可能です。
 
Ubuntuで実行するノードだけが影響を受ける。
Container-Optimized OS（COS）を利用している場合は影響を受けない。
バッチ実行で現在時間を使って絞り込みをしてはいけない理由

## はじめに
コードレビューをしていて、年に一回ぐらいは、バッチのコードに対して実行時間の絞り込みに現在時間を使ってはいけないといという指摘をするので、
`なぜそれがいけないのか`を説明する資料を作っておくことにした。

うまくテストコードを書かないと見つけにくく、本番環境でしばらく運用してからそのミスに気づいたり、ずっと気づかなかったりすることになる。
定期的な課金処理であるユーザの課金処理をずっとやり損なうなんて事故もありうるのだ。

Railsのコードを用いて説明するが、どんなプログラミング言語でも応用は可能である。

### 前提条件
Ruby: 2.5.1
Rails: 5.2
テーブル: usersテーブルに更新日付が入ったupdated_atというカラムがあるものとする。


## バッチのコードに時間の絞り込みに実行時間を使う問題点
1日前までに更新されたデータを取得するコード

```
User.where(updated_at: (Time.zone.now - 1.day)...Time.zone.now)

# 発行されるSQL
User.where(updated_at: (Time.zone.now - 1.day)...Time.zone.now).to_sql
=> "SELECT \"users\".* FROM \"users\" WHERE \"users\".\"updated_at\" >= '2019-02-11 03:26:21.992358' AND \"users\".\"updated_at\" < '2019-02-12 03:26:21.992952'"
```

バッチ実行する場合(Cron)などで同じように

```
User.where(updated_at: (Time.zone.now - 1.day)...Time.zone.now)
```

とやってはいけない。

0:00:00にCronを実行を設定したとしても、対象のコードが実行されるのが
0:00:00に実行される保証がない。`バッチが起動してライブラリがロードされ実際にバッチの処理が実行される時間が0:00:01になる可能性が大いにある`

境界値テストで考えてみると
updated_atの時間が

現在時間が2/13 0:00:00として、2/12に更新されたユーザのデータ
つまり`updated_atが2/12 00:00:00から2/13 0:00:00未満のデータ`を取得したい。

下記のようなデータがある場合、取得したいデータは2, 3, 4だ

1. 2/11 23:59:59
2. 2/12 00:00:00
3. 2/12 00:00:01
4. 2/12 23:59:59
5. 2/13 00:00:00

```
User.where(updated_at: (Time.zone.now - 1.day)...Time.zone.now)
```

これをバッチの起動に時間がかかり2/13 00:00:01に実行された場合、2のデータは取得できず、不要な5を取得してしまう。

バッチ実行時してユーザを取得するタイミングが00:00:00(厳密に言えばミリ秒単位で)でない限りは現在時間で絞り込んではいけないのだ

## この問題を解決するには

バッチの実行される時間にある程度ずれるのを考慮したコードを書けば良い。
つまりバッチの実行が00:00:00に厳密に実行されなくても00:00:01や02:12:42に実行されても大丈夫なようにしておけば良い(もちろんバッチが失敗した際のリトライ処理なども必要だがこれはまた別のお話)

`絞り込みする期間を明示的にその日の00:00:00`にしてあげれば良い。
具体的には`Time.zone.now.beginning_of_day`を利用すると良い。

これを利用して書き直したコードはこちら

```
User.where(updated_at: (Time.zone.now.beginning_of_day - 1.day)...Time.zone.now.beginning_of_day)

# 発行されるSQL
User.where(updated_at: (Time.zone.now.beginning_of_day - 1.day)...Time.zone.now.beginning_of_day).to_sql
=> "SELECT \"users\".* FROM \"users\" WHERE \"users\".\"updated_at\" >= '2019-02-11 00:00:00' AND \"users\".\"updated_at\" < '2019-02-12 00:00:00'"

# 少し冗長なので時間を変数にするとこうなる
midnight = Time.zone.now.beginning_of_day
User.where(updated_at: (midnight - 1.day)...midnight)
```
Java11のSpringBootのプロジェクトからからMySQL8へ接続した時に発生した問題の解決

Java11のSpringBootのプロジェクトからMySQL8へ接続した時に発生した問題の解決と、Windows10でのMySQLの操作について

#環境
Windows10
MySQL 8.0.15(記述時点の最新)
Scoopによるインストール[^1]
[^1]: --initialize-insecureによる簡略化されたインストール。ツールでインストールを自動化するときはこのオプションが必須。
Java11(OpenJDK11.0.11-28,11.0.2-9)でSpringBootを使用してMySQLへの接続を試した

##mysql.ini内の[mysqld]の編集
###default-time-zone
サーバー全体のデフォルトのタイムゾーン。
デフォルトのタイムゾーンを指定していないとJDBCからの接続の際にエラーが発生[^2]する。
タイムゾーンはデフォルトではUTCからの時差の指定でないと設定できない模様で、日本(JST)の場合は`+9:00`と設定する。

[^2]: URLのパラメータで接続時のtime_zoneを指定していても発生する。仕様かバグかは未調査。

###collation_server
サーバー全体の照合順序。MySQL8以降デフォルトの文字セットがutf8mb4になったが、設定がない場合の照合順序はutf8mb4_0900_ai_ciで、これだと**アクセントを無視**してしまう。
日本語では濁音、半濁音を区別せず、絵文字の一部などでも問題が発生するため、utf8mb4_0900系列の新しい照合順をデフォルトに設定する。
ひらがな、カタカナの区別が必要か、ソートの順序などでいくつか選択肢があるが、使用するのはおそらくutf8mb4_ja_0900_as_csかutf8mb4_ja_0900_as_cs_ks。
カタカナと平仮名の区別を行うのがutf8mb4_ja_0900_as_cs_ks。
条件が増えるほど負荷が高くなると思われるので要件に合わせて検討してテストも必要。

####character_set_serverについて
MySQL8ではutf8mb4がデフォルトで指定されている。新規に使い始めるなら特に設定は要らない。

##MySQLの操作
###mysqldの起動
コマンドプロンプトから`mysqld --console`を実行[^3]。プロンプトを閉じるとサーバーも落ちる。このため、プロンプトを開きっぱなしで作業をすることになる。
[^3]: コマンドプロンプトが最も軽いから。

###mysqldの停止
正式な手順としては`mysqladmin shutdown`。起動させたプロンプトを閉じても停止するが正式なシャットダウンの手順を踏まない可能性があるので避けている。

###サーバーへの接続
mysqldを起動したものとは別のコマンドプロンプトかPowerShellから`mysql -u root`[^4]。
[^4]: --initialize-insecureでインストールされているため。インストール時の設定やオプションで当然変わる。短時間のテスト時以外はパスワードは必ず設定、変更する。

##JDK11.0.11-28以降とConnctor/Jの問題
###アプリケーションを一定時間以上動作させるとSSLのエラーが発生する
```
javax.net.ssl.SSLException
MESSAGE: closing inbound before receiving peer's close_notify
```
スタックを追うとコネクションプールから発生していた。`Connection.close()`を実行するとエラーが発生するとの情報を発見。
その後さらに調査すると、JDKとConnector/jの間でどちらに原因があるが議論されていたようだが、[JDK11のバグ](https://bugs.openjdk.java.net/browse/JDK-8215102)である模様。既に修正案も出ているようなので近い将来には解消されると期待したい[^5]。
####2019/11/19追記
上記の問題はConectorJの問題としてJavaコミュニティでは修正されないことになった

###SSLExceptionの回避策
URLにパラメータを追加してSSLを無効にする。

```
#<=8.0.12
jdbc:mysql://localhost:3306/db_name?useSSL=false

#>=8.0.13
jdbc:mysql://localhost:3306/db_name?sslMode=DISABLED
```
8.0.13以降でも経過措置でuseSSL=falseも使えるが、[非推奨](https://dev.mysql.com/doc/connector-j/8.0/en/connector-j-reference-configuration-properties.html)。
アプリケーションからのみ接続するのであればこれで対応するのもあるかと思う。

[^5]: 11-28からバージョンアップしていなかったので2-9にしてみたが解消されていなかった

##2019/03/06追記：Spring Boot（HiKariCP）とMySQL8の問題
###コネクションプールにHikariCPを使用するとDB内で文字化けが発生する
Spring Bootで追加設定なしで使用していると特に問題は発生しないのだが、コネクションプールをHikariCPに変更すると、DB内への書き込み時に文字化けが発生する。
HikariCPは[MySQLの使用に消極的](https://github.com/brettwooldridge/HikariCP#popular-datasource-class-names)なようで、また、上記のSSLの例外の問題もあってか、最新のドライバをあえて使用しないようになっているのかもしれない。

これはJDBCのurlのパラメーターにcharacterEncoding=utf8を追加することで解消できる[^6]。

[^6]: ようやくこのおまじないから解放されると思っていたのに…。