OmniAICreator/Qiita-1.07M huggingface dataset:
Firestoreで不等価演算子が使えるようになった件

#Firestoreでそれまで不等価演算子が使えないと知り、絶望した
Web開発などにおいてFirestoreを使った開発をされる方も多くいらっしゃるかと思います。
先日私も初めてFirestoreを使った開発をしていたのですが、whereを使った条件指定が必要になり調べていたところ、Firestoreでは不等価演算子(!=)は使えないという記述を多く見ました。

何かと視野が狭くなりがちな私は、!= を使わな方法が思いつかんとか思っていたので、絶望に打ちひしがれつつ、わずかな期待を抱きながら某エンジニア質問サイトで、Firestoreで不等価演算子のようなものを使えないかという質問をしました。

#Firestoreが更新されて、不等価演算子が使えるようになっていた（ネ申）
質問を投稿すると、ある一人の方がすぐに回答してくださいました。
「バージョンアップで、!=が使えるようになりましたよ」と。

回答者の方が公式のURLも貼ってくださり、そこにはしっかり記述されていました。

https://firebase.google.com/support/release-notes/js#version_7210_-_september_17_2020
バージョンアップされたのは9月中旬とごく最近のことだったようです。

この情報が有名なのかどうかはわかりませんが、検索した限りでは出てこなかったのでQiitaに投稿することにしました。
少しでも誰かのために役立てることができればと思います。
会社の共用ライブラリをOSSで公開する時にGithubの設定でハマったこと

## 会社の共用ライブラリを公開しました。

弊社の広報・採用強化・Androidエンジニアへの貢献の一環として下記のライブラリモジュールを公開しました。
- https://github.com/arsaga-partners/AndroidViewExtensions
- https://github.com/arsaga-partners/AndroidViewModelExtensions
- https://github.com/arsaga-partners/AndroidGatewayExtensions

(鋭意改修中です！)

その際、githubで公開する際に3時間！ハマったことがありましたのでその共有の記事になります。

## github organization内のレポジトリの外部ユーザーのマージ権限について

会社内のレポジトリのmaster / developブランチにはブランチルールでマージに必要な条件を付けているので、
organization外部のユーザーからのマージコミットを弾く設定をしなければいけないものだと思い込んでしまったが、
そもそもorganizationのメンバーでもcontributorでもない人はマージコミットができないようになっていた。

## なぜ、3時間も気づかなかったのか。。。

普通に公開するだけで特にトラブルが起きないので、
会社のprivateレポジトリをpublicにする時のブランチルールについて書かれている記事が、
公式含めインターネット上で探してもなかったためでした。
pytorch で kernel を変えて同一画像に対して conv2d するメモ

# 背景

* 画像処理でフィルタを変えて同一画像にそれぞれ異なったフィルタ N 個を適用(conv2d)したい
* scipy.signal.convolve だと遅い(`mode=fft` で早くすることできるが, 近似的な結果になりそう...?)ので, pytorch で処理する(CUDA が使えれば GPU で高速化が見込める)
* モノクロ画像とする

depthwise convolution(`Conv2d` で `groups` を設定) が必要かと思いましたが, in_channel=1, out_channel=N で OK でした.

## 手順

weight を `[N, 1, KH, KW]` で作り用意します.

```
device = torch.device('cuda') if torch.cuda.is_available() else torch.device('cpu')


kernel_size = [3, 3]

num_kernels = 4

kernel = torch.zeros([num_kernels, 1, kernel_size[1], kernel_size[0]], dtype=torch.float32).to(device)

# テスト用に channel ごとに all 1s, 2s, 3s, ... なのを用意する
for i in range(num_kernels):
    kernel[i] = float(i) + 1

print(kernel)

```

```
tensor([[[[1., 1., 1.],
          [1., 1., 1.],
          [1., 1., 1.]]],


        [[[2., 2., 2.],
          [2., 2., 2.],
          [2., 2., 2.]]],


        [[[3., 3., 3.],
          [3., 3., 3.],
          [3., 3., 3.]]],


        [[[4., 4., 4.],
          [4., 4., 4.],
          [4., 4., 4.]]]], device='cuda:0')
```


あとは以下のようにして conv2d を設定 + 実行します!

```

# assume default stride and dilation and odd kernel size 
conv = torch.nn.Conv2d(1, num_kernels, kernel_size, padding=[kernel_size[1]//2, kernel_size[0] // 2], bias=False, padding_mode='replicate')
conv.weight = torch.nn.Parameter(kernel)

img = np.ones(img_size).astype('float32')

x = torch.from_numpy(img).to(device)

# [h, w] -> [1, 1(c), h, w]
x = torch.unsqueeze(torch.unsqueeze(x, 0), 0)

# forward pass(eval convolution)
with torch.no_grad():
    f = conv(x)

f = f.to('cpu')
print(f)
```

```
tensor([[[[ 9.,  9.,  9.,  ...,  9.,  9.,  9.],
          [ 9.,  9.,  9.,  ...,  9.,  9.,  9.],
          [ 9.,  9.,  9.,  ...,  9.,  9.,  9.],
          ...,
          [ 9.,  9.,  9.,  ...,  9.,  9.,  9.],
          [ 9.,  9.,  9.,  ...,  9.,  9.,  9.],
          [ 9.,  9.,  9.,  ...,  9.,  9.,  9.]],

         [[18., 18., 18.,  ..., 18., 18., 18.],
          [18., 18., 18.,  ..., 18., 18., 18.],
          [18., 18., 18.,  ..., 18., 18., 18.],
          ...,
          [18., 18., 18.,  ..., 18., 18., 18.],
          [18., 18., 18.,  ..., 18., 18., 18.],
          [18., 18., 18.,  ..., 18., 18., 18.]],

         [[27., 27., 27.,  ..., 27., 27., 27.],
          [27., 27., 27.,  ..., 27., 27., 27.],
          [27., 27., 27.,  ..., 27., 27., 27.],
          ...,
          [27., 27., 27.,  ..., 27., 27., 27.],
          [27., 27., 27.,  ..., 27., 27., 27.],
          [27., 27., 27.,  ..., 27., 27., 27.]],

         [[36., 36., 36.,  ..., 36., 36., 36.],
          [36., 36., 36.,  ..., 36., 36., 36.],
          [36., 36., 36.,  ..., 36., 36., 36.],
          ...,
          [36., 36., 36.,  ..., 36., 36., 36.],
          [36., 36., 36.,  ..., 36., 36., 36.],
          [36., 36., 36.,  ..., 36., 36., 36.]]]])
```

Voila! :tada:

Channel(layer)ごとに異なった kernel が適用されています!


## TODO

* [ ] RGB 画像で試す
[Python]アイシャドウのランキング上位１０位をグラフにしてみた

# 概要
化粧サイト[LIPS](https://lipscosme.com/)では化粧品のランキングが見れます。
今回はアイシャドウのランキングを取得し、
縦軸は商品の名前、横軸を星の評価にしてグラフにしたいと思います。
上から下への流れが順位となります。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/763295/c0f01547-fb99-72fe-0836-af967d8895ca.png" width=60%>

# 完成
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/763295/81b0a0d5-3c53-ddf8-39ef-064f0643f005.png" width=100%>

# コード
```Python
import requests
from bs4 import BeautifulSoup
import matplotlib.pyplot as plt

# LIPSのサイトをスクレイピング
urlName = "https://lipscosme.com/"
url = requests.get(urlName)
url.raise_for_status()
bs = BeautifulSoup(url.text, "html.parser")

url_list = []

# url_listにアイシャドウ、ファンデーション、口紅、化粧水のURLが入っている
# 今回はアイシャドウのみをグラフにする
for i in bs.select('a.ranking-products-list__more-link'):
    url_list.append(urlName + i.get('href'))
url_list.pop() # 化粧水のURLを削除
url_list.pop() # 口紅のURLを削除
url_list.pop() # ファンデーションのURLを削除

name_list = []
start_list = []
for i in url_list:
    url_temp = requests.get(i)
    url_temp.raise_for_status()
    bs_temp = BeautifulSoup(url_temp.text, "html.parser")

    for j in bs_temp.select('div.ProductListArticle'):
        for k in j.select('div.ProductListArticle__product'):
            for k2 in k.select('h2.ProductListArticle__productTitle-productName'):
                name_list.append(k2.text)
            for k3 in k.select('span.ratingStar__num'):
                start_list.append(k3.text)  

# グラフ作成
# 上位10位
start_list = start_list[:10]
name_list = name_list[:10]
# 上から下にかけて順位を表示させるため、逆順にする
start_list.reverse()
name_list.reverse()
labels = [float(i) for i in start_list] # 横のラベルに星の評価を入れる
height = name_list # 縦のラベルにアイシャドウの名前を入れる
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
ax.barh(height,labels,height = 0.5)

plt.xticks(rotation=90)
plt.title('アイシャドウのランキング10選', fontsize=15)
plt.ylabel("化粧品名", fontsize=15)
plt.xlabel("星の評価", fontsize=15)
plt.tick_params(labelsize=10)

plt.show()
```

# まとめ
ランキング１位から下に行くほどに星の評価が下がると思いきや
余り星が変わらない結果となりました。

アイシャドウ買う時はこのグラフを参考にしてもらえると嬉しいです！

次回はファンデーションとか他の化粧品のグラフを作ってみよう。
SQLServerのインデックス入門編

SQLServerのインデックスについて理解できていないところがあるので
学んだ内容をまとめてみました。

#1.インデックスとは
インデックスとは本の索引のようなもので、検索したいデータがテーブルのどこにあるのかを示すものです。
テーブルにインデックスが存在しないと検索したいデータが見つかるまでテーブルの端から端まで順に探す必要があります。このことをフルテーブルスキャンと言いますが、フルテーブルスキャンが発生すると多くの場合は検索に時間が掛かるので、インデックスを使用した検索が基本的には推奨されます。

* インデックスを使う場合
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/162114/31c3945f-868a-5ebd-1622-3df99859a8bf.png)
* インデックスを使わない場合(フルテーブルスキャン)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/162114/0f933a27-a3e1-4c7b-8d43-aa2e222433c3.png)

#2.SQLServerにおけるインデックスの種類
インデックスは下の図のように大きく2つに分類することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/162114/a78c5dd0-2741-5498-4d13-ea8736a4173c.png)

少し難しい単語が出てきましたが、それぞれの特徴を抑えればそれほど難しいものではありません。1つずつ説明していきます。

- クラスター化インデックス  
テーブルに主キー(Primary Key制約)を作成した際に自動で作成されるインデックス。
特徴としては以下の2つが挙げられます。  
    - 1つのテーブルに1つしか作成できない  
    - テーブルのデータはクラスターインデックスによって並び替えられる
- 非クラスター化インデックス  
ユーザが任意に作成したインデックス、またはカラムに一意キー(Unique Key制約)を作成した際に自動で作成されるインデックス。
特徴として以下のものが挙げられます。
    - 1つのテーブルに999個まで作成可能

#3.インデックスの構造
次に、インデックスは具体的にどのような構造になっているのか解説します。
クラスター化インデックスも非クラスター化インデックスも構造は同じでB-Tree構造をしていますが、データの持ち方は少し異なります。
B-Tree構造と言われると難しい話になってきたと思う方もいらっしゃると思うので
図を交えながらなるべく簡単に説明していきます。

例として以下のような社員ID,組織コード、名前を格納しているテーブルを考えます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/162114/132005f8-105d-a566-705c-602869703e1c.png)


### クラスター化インデックスの場合
社員ID列に対してクラスター化インデックスを作成するとインデックスはこのような構成になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/162114/d590f084-00ab-16d1-0ffc-edac365a0193.png)


赤い四角がルートノード、黄色い四角が中間ノード、緑の資格がリーフノードと呼ばれます。
ルートノードを起点としてルートノードの数値より小さいものは左側、大きいものは右側に配置するように中間ノードを組み立てます。
特徴としては以下のものが挙げられます。

* ルートノードにテーブルの情報がすべて格納されている  
(インデックス=テーブルとなっている)
* インデックスの値(ここでは社員ID列)でソートされているのが特徴です。

例えば、IDが「2」の行の名前を検索する際には
1.ルートノードの「3」と「2」を比較する　⇒　「2」は「3」より小さいので左に進む  
2.中間ノードの「2」と「2」を比較する　　⇒　「2」は「2」に等しいので右に進む  
3.リーフノードにたどり着いたのでその中で「2」に一致するデータを検索し、名前を取得する。

### 非クラスター化インデックスの場合

組織コード列に対して非クラスター化インデックスを作成するとインデックスはこのような構成になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/162114/e2d1c295-b33f-1302-6f1f-190987ecbed5.png)

見た目はクラスター化インデックスとよく似ていますが、大きな違いがリーフノードに表れています。
非クラスター化インデックスではリーフノードにインデックスに設定されたカラム以外は持たずに、代わりにその列のデータが格納されている場所を示す識別子を保持します。
この状態で組織コードを検索キーに名前を取得する際にはリーフノードまでたどり着いたらその識別子を参照して名前を取得します。
つまり、ツリーの階層の深さは同じだとしても非クラスター化インデックスのほうが識別子から参照するという手順が増える分どうしてもクラスター化インデックスよりも時間が掛かってしまうこちが多くなります。
しかし、非クラスター化インデックスでも検索されるカラムが決まっている場合はリーフノードに特定のカラムの値を持たせることができます。この追加したカラムは「付加列」と呼ぶそうです。
クラスター化インデックス、非クラスター化インデックスの理解についてはコチラのサイトが参考になったので合わせて紹介しておきます。
[【SQL Server】クラスター化インデックスと非クラスター化インデックス](http://memorandom-nishi.hatenablog.jp/entry/2017/02/05/232703)
if let b = a as? Intより if case let b as Int = a の方が速い

Swiftにおいてキャストしてその値を使うときは`as?`でキャスト、
`Optional`型にしてその`Optional`型に関する
`Optional Binding`によって値を取り出すことが多いと思います。

```swift
let a: Any = 120
if let b = a as? Int {
    // b を使う処理
}
```

しかし、これだと一回`Optional`を経由しているため流れが少し複雑です。

別の書き方があります。

```swift
let a: Any = 120
if case let b as Int = a {
    // b を使う処理
}
```

これだと、Optionalを通らず安全にキャストできます。


## 速度面

1万回実行時の速度

|`as?`|`case`|
|-----|------|
|  0.011s   |  0.001s  |

約10倍の差がある。

Swift Standart Libraryでも `case` の方が多用されている。

> Swift.printの中身から引用
>
> ![スクリーンショット 2020-10-12 18.00.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117659/d90e5b26-0aa2-42af-f6f4-6bd5ff9d8025.png)
> [https://github.com/apple/swift/blob/9af806e8fd93df3499b1811deae7729176879cb0/stdlib/public/core/OutputStream.swift#L375](https://github.com/apple/swift/blob/9af806e8fd93df3499b1811deae7729176879cb0/stdlib/public/core/OutputStream.swift#L375)
アプリエンジニアから見たピザ屋アプリのUX/UI

# はじめに

今回はAndroidエンジニアから見たアプリのUX/UIを見ていきたいと思います。

弊社のコンセプトである、
###**「バグを否定しない」**
###**「否定するなら代替案を」**
というコンセプトに従って、否定するのではなくもっとこうした方がいいのでは？というプラスの評価をしていきたいと思います。

# ホーム画面
![Point Blur_20200925_214608.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411927/640ec24d-8621-759a-4530-31db2a4be327.jpeg)

まずこのアプリはピザを注文させることが目的です。
しかしこのホーム画面だけ見ると、ユーザーの目線がちらついてしまいます。

いいUIというのは「誰が」「なんのために」「何をして欲しいか」というのがはっきりしているものだと思います。
ユーザーが何をしたいか、どうすればいいかがわからないだけで離脱率が上がります。

なので1ページに
###**情報を盛りすぎない**
###**情報に優先度をつける**

ことです。

まずこのアプリを開く人の多くはピザを頼みたい人です
ですので改善案を出すとすると

####キャンペーン類のバナーは他のページに移す
####ホーム画面はピザのメニューにする

などです。



#注文ページ
![Point Blur_20200925_220322.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411927/b5895e07-09aa-5f4b-a40c-d3358033a923.jpeg)

注文タブを開くとまずこの画面が出てきます。

この画面ではまずお持ち帰りかお届けかを選んでから次の画面に進むそうです。
しかし、ピザを頼む時点でお持ち帰りかお届けか決めている人は多いでしょう。

「お持ち帰りの方が早いからお持ち帰りにしよう！」
となったことは僕自身ありません(笑)

確かにピザが食べられるまで何分か知れるのはユーザーの不安を取り除くものとしていいと思うのですが、ここで表示するメリットがあまりない気がしています。


![Point Blur_20200925_220454.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411927/692dcaf5-300f-960c-26af-2b942187f573.jpeg)


![Point Blur_20200925_220422.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411927/f07a5cd4-9ac7-4e48-5b65-77dba11ec763.jpeg)


お持ち帰りかお届けを選んだあとはこの画面。

この画面は個人的にとてもいいと思います。
何よりこのデカデカとしたピザの写真が非常に食欲をそそりますね(笑)

ただ懸念点としてはMサイズかLサイズかこの場では選べないことですね。
一瞬「あれ？サイズ選べないのかな？」というユーザーの不安を煽ってしまうかもしれません。
あとは何回も入力をしなきゃいけないのは面倒ですよね

注文ページの改善案を出すとすると、

ホームページと同じにはなってしまいますが
####まずはピザを選ばせる（サイズもこの時点で）
####入力項目はなるべく少なく、ステップも少なくする

です。

弊社のデザイナーが言っていたのですが、

###いいデザインはかなり曖昧

###だけど悪いデザインには必ず原因がある。

###その悪いデザインを潰していけば自ずといいデザインになっていく。

これを聞いたときは、なるほどと深く頷いてしまいました。

#まとめ
今回はいつもの技術小ネタと違ったスタイルで書いてみました。

正直UX/UIには正解がないので、僕が言っていることが合っているとは思ってません。

皆さんがもしこのアプリに改善案を出すとしたらどんな改善案を出しますか？
KotlinでElmの便利関数実装してみた

# はじめに
タイトルの通りです。

## repeat
```kotlin
fun <T> repeat(count: Int, input: T): List<T> {
    val list = mutableListOf<T>()
    for (i in 0 until count) {
        list.add(input)
    }
    return list.toList()
}

repeat(3, 3)

出力
(3,3,3)
```

## range
```kotlin
fun range(a: Int, b: Int): List<Int> = (a..b).toList()

range(1, 3)

出力
(1,2,3)
```

## append
```kotlin
fun <T> List<T>.append(list: List<T>): List<T> {
    val acc = this.toMutableList()
    acc.addAll(list)
    return acc
}

listOf(1, 2, 3).append(listOf(4, 5))

出力
(1,2,3,4,5)
```

## concat
```kotlin
fun <T> List<List<T>>.concat(): List<T> {
    return this.fold(mutableListOf()) { acc, list ->
        acc.addAll(list)
        acc
    }
}

listOf(listOf(1,2,3), listOf(4,5,6), listOf(7,8,9)).concat()

出力
(1,2,3,4,5,6,7,8,9)
```

## head
```kotlin
fun <T> List<T>.head(): T {
    return this[0]
}

listOf(1, 2, 3).head()

出力
1
```

## tail
```kotlin
fun <T> List<T>.tail(): T {
    return this[this.size - 1]
}

listOf(1, 2, 3).tail()

出力
3
```
Github ActionsでAndroidのビルドをする

# はじめに
今回はGithub ActionsでAndroidのビルドをする

# 準備
###1. AndroidのProjectレベルに.github/workflowディレクトリを作る
###2. build.yamlを作る（名前はなんでも良い）

```yaml
name: CI

on:
  pull_request:
    branches: [ master ]

jobs:
  build:

    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v2
    - name: set up JDK 1.8
      uses: actions/setup-java@v1
      with:
        java-version: 1.8
    - name: Build with Gradle
      run: ./gradlew assembleDebug
```

###3. プッシュする

###4. 終わり！

# 説明

```yaml
on:
  pull_request:
    branches: [ master ]
```

pull_requestの部分はトリガーといい、githubのプッシュ、プルリクエスト、issueなどです。
branchesは任意のブランチを指定すれば、指定したブランチにトリガーが走った時に処理を始めてくれます。


```yaml
- uses: actions/checkout@v2
  - name: set up JDK 1.8
    uses: actions/setup-java@v1
    with:
      java-version: 1.8
```

Javaの環境を用意します。

```yaml
- name: Build with Gradle
  run: ./gradlew assembleDebug
```

ビルドします
プログラマーの3大美徳

# はじめに
現在弊社の一部のエンジニアの中で非常に神格化されている「プリンシプルオブプログラミング」に書いてある、
### プログラマーの3大美徳
について紹介します

# プログラマーは「怠慢」「短気」「傲慢」であれ

できるエンジニアはこの3つの特性を兼ね備えています

## 怠慢
>全体の労力を減らすために手間を惜しまない気質。
この気質の持ち主は、役立つプログラムを書いてみんなの苦労を減らしたり、
同じ質問に何度も答えなくてもいいように文書を書いたりする。

何度も同じコードを書かないため（サボるため）に手間を惜しみません。
クラスや関数を抽象化する、Viewをコンポーネントごとに切り分けて使い回せるようにする、CI/CDを導入し自動化するなどがあげられますね

## 短気
> コンピューターが怠慢な時に感じる怒り。
この怒りの持ち主は、今ある問題に対応するプログラムにとどまらず、
今後起こりうる問題を想定したプログラムを書く。
少なくともそうしようとする。

ユーザーの要望により変更されそうなところを先回りして変更しやすくしたり、依存関係を小さくしたりなどですね

## 傲慢
>神罰が下るほどの過剰な自尊心。
または人様に対して恥ずかしくないプログラムを書き、
また保守しようとする気質。

自分の書いたコードに責任を持ち、人に見せても恥ずかしくないコードを書きます。ここで言う人に見せても恥ずかしくないというのは、保守性や可読性、柔軟性の高いコードのことです。
gemfile書き換えによるBundler::Dsl::DSLErrorの対処法

gemfileを書き換えた際のエラー対処法について後発者のためにメモを残しておく。

#####開発環境
`windows 10 home
ubuntu 20.04 LTS
ruby 2.7.1
Rails 6.0.3
postgresql 11`

#エラー文

```
$ bundle
～～～～～中略～～～～～
 Permission denied @ rb_sysopen - /home/admin0/taskleaf2/Gemfile (Errno::EACCES)
～～～～～中略～～～～～
was an error while trying to read from `/home/admin0/taskleaf2/Gemfile`. It is likely that you need to grant read permissions for that path. (Bundler::PermissionError)
～～～～～中略～～～～～
 Bundler::Dsl::DSLError
```
今回は特に理由はないが3つ目のエラー文着目に着目して検索したところ以下のサイトに良さげな解決方法が記載されていたので実行してみる
https://stackoverflow.com/questions/57926553/bundle-install-gives-bundlerdsldslerror

```
$ chmod 644 Gemfile
```

これでエラーが発生しなくなったため、問題解決したと判断する。
【Java】Java8から追加されたTime APIを使って10日後の日付を取得・表示

#今までのおさらい

#新しく追加されたTime APIを使用してみる

####新しく追加されたAPI

| クラス | 年 | 月 | 日 | 時間 | ゾーン | 用途 |
|:--|:-:|:-:|:-:|:-:|:-:|:--|
| ZonedDateTime  | ○  | ○  | ○  | ○  | ○  | 厳密な日時情報  |
| LocalDateTime  |  ○ | ○  | ○  | ○  | X  | 日常使う日時情報  |
| LocalDate      | ○  |○   |○   |  X |  X |誕生日   |
| LocalTime      | X  | X  | X  | ○  | X  | アラーム時刻など  |
| Year           | ○  | X  | X  | X |  X | 著作発表年など  |
| YearMonth      | ○  | ○  | X  | X  | X  | カード有効期限など  |
| Month          |  X | ○  | X  | X  | X  | 決算月など  |
| MonthDay       |  X | ○  | ○  | X  | X  | 日本の祝日など  |

このうちLocalDateを使って10日後を計算してみました


```java:
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

// Java8から追加されたTime APIを使用
// 10日後の日付を取得する
public class TenDaysCalendarNewAPI {

	public static void main(String[] args) {
		LocalDate now = LocalDate.now();
		LocalDate future = now.plusDays(10);
		
		// フォーマットを指定せずに表示
		System.out.println("■ LocalDate型をそのまま表示");
		System.out.println(now);
		System.out.println(future);
		System.out.println();
		
		// フォーマットを指定して表示
		System.out.println("■ DateTimeFormatterを使って表示");
		DateTimeFormatter f = DateTimeFormatter.ofPattern("yyyy年MM月dd日");
		System.out.println(now.format(f));
		System.out.println(future.format(f));
		System.out.println();
		
		System.out.println("■ SimpleDateFormatを使って表示");
		SimpleDateFormat f2 = new SimpleDateFormat("yyyy年MM月dd日");
		System.out.println(f.format(now));
		System.out.println(f.format(future));
	}

}

```

```:実行結果
■ LocalDate型をそのまま表示
2020-10-12
2020-10-22

■ DateTimeFormatterを使って表示
2020年10月12日
2020年10月22日

■ SimpleDateFormatを使って表示
2020年10月12日
2020年10月22日

```

#新しいAPIの方が扱いやすいですね
自分の直感的には扱いやすいと感じました。それはformat指定の際にですね、

SimpleDateFormatは、SimpleDateFormatに日付情報を渡す
DateTimeFormatterは、日付情報にDateTimeFormatterの形式を指定する

という部分ですね。

何を入っているかわからんくなってきますが、

自分的には

```java
System.out.println(f.format(now));
```
という部分がわかりにくいというか、そういうやり方なんでしかたないですが、なんとなく釈然としない感じがありました。

```java
 System.out.println(now.format(f));
```

のように、`nowの日付情報をformatメソッドの引数に渡した形式の情報に変換する`というようなイメージの方がわかりやすいということでした！
【PDO】複文禁止オプションの注意点(ATTR_EMULATE_PREPARES)

# 環境
OS：CentOS 7.3
PHP：7.1.21
mariadb:10.1.22

# 概要
ＰＤＯで [PDO::ATTR_EMULATE_PREPARES](https://www.php.net/manual/ja/pdo.constants.php) を `false` にすると、
（機能のひとつとして）セミコロンでつなげたＳＱＬ（複文）を禁止できるようですが、
コメント(--) の部分は複文として検知してくれないようです。

※ 以下、[query()](https://www.php.net/manual/ja/pdo.query.php) メソッド使用。

``` php
$sql .= "select * from table1;\n";
$sql .= "select * from table2;\n";

//検知してくれる ＯＫ
You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'select * from table2' at line 2

```

``` php
$sql .= "select * from table1;\n";
$sql .= "-- select * from table2;\n";

//検知しなかった？？？

```

``` php
$sql .= "select * from table1;\n";
$sql .= "-- select * from table2;\n";
$sql .= "select * from table3;\n";

//これは検知するけど３行目なんだ・・・
You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'select * from table3' at line 3

```

# まとめ

複文禁止といっても「有効なＳＱＬの複文」を禁止するみたいで、
コメント行は有効なＳＱＬでないということなのでしょう。

コメント(--) を使ったＳＱＬインジェクションがありますが、
PDO::ATTR_EMULATE_PREPARES の設定だけでは不十分ということですね。

コメント使用の攻撃に対しては、
プリペアドステートメントを併用して防ぎましょう。
停まれ標識検知　可視化部分の開発part1 物体の検知と記録※今回は椅子を検出しています（モデルは自作ではありません）

## 初めに
前回は,看板検知の学習モデルについて記してきました.今回は,その検知したモデルを使って実際に検知し,それを可視化する為のプログラムを書いていこうと考えています.
## 実現したい機能
・yolov5で動画を使って推定し推定した動画を保存する.
・検知されたときに別システムに検知を可視化する.
・検知された時間やモノを記録する.
この辺を実際に実現していきたいなと思います.
## 実現したい機能の実現
### 前置き
実は,似た機能を前にtensorflowとpython,processingを利用して簡易的なものを作ったことがあるのでそのプログラムを流用して書いていきたいと思います.
プログラムはgithubに載せてあります.※学習モデルの作り方やどうそのモデルをlabelプログラムで動かしたかを作った本人は忘れています.
URL https://github.com/S-mishina/Personal-estimation
このプログラムのsketch_190628a/sketch_190628a.pdeが可視化部分です.
システムの全体についてもここに一応載せておきます.
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567360/5be0890c-dd90-30f5-42a5-74da2e6bacb9.png)
ここから実際にyolov5の改造をしていきます.
### 特定の何かが検知されたときに何かアクションを起こす.
今回は簡単に実装してみたかったので検知したいものが見つかったときにはそれを検知しましたよ
という通知を出すプログラムにした.

```detect.py
label1 = str((names[int(c)]))  # add to string
if label1=="chair":
 print("椅子を検知しました.")
```
まぁ簡単なコードなので誰でもわかると思いますが,一応説明すると,yoloでオブジェクトを検出するとおそらく検出したものがnames[int(c)]というところで記録されるみたいでした.なのでそれを文字列化して文字列化したものが自分が検出したいものとマッチしているかを見てマッチしていれば検出OK,マッチしていなければ検出NGという具合になっています.
#### このプログラムの展望
この実装した機能の展望としてはここからソケット通信で検出したかどうかを文字ベースじゃなくて可視化できるシステムにつなげていきたいと考えています.
### 検知された時間やモノを記録する.
今回は椅子を検出することを目的としているので椅子が検出されたときにログを取るプログラムを書いていきたいと思います.
インポート部分

```detect.py
import pathlib
```
ファイル作成部分

```detect.py
#初期化
    set_logging()
    device = select_device(opt.device)
    if os.path.exists(out):
        shutil.rmtree(out)  #出力フォルダーを削除します
    os.makedirs(out)  #新しい出力フォルダーを作成します
    d_today = datetime.date.today()
    
    f = pathlib.Path('daystext/'+ str(d_today) +'.txt')
    f.touch()
```
記録部分

```detect.py
                    label1 = str((names[int(c)]))  # add to string
                    if label1=="chair":
                     print("椅子を検知しました.")
                    with open('daystext/'+str(d_today)+'.txt', 'a') as f:
                     dt_now = datetime.datetime.now()
                     f.write(str(dt_now)+"椅子を検知しました."+"\n")

```
記録されたもの

```
2020-10-12 17:27:42.914446椅子を検知しました.
2020-10-12 17:27:42.941445椅子を検知しました.
2020-10-12 17:27:42.968444椅子を検知しました.
2020-10-12 17:27:42.996444椅子を検知しました.
2020-10-12 17:27:43.024443椅子を検知しました.
2020-10-12 17:27:43.051442椅子を検知しました.
2020-10-12 17:27:43.079441椅子を検知しました.
2020-10-12 17:27:43.108440椅子を検知しました.
2020-10-12 17:27:43.135454椅子を検知しました.
2020-10-12 17:27:43.162439椅子を検知しました.
2020-10-12 17:27:43.190452椅子を検知しました.
2020-10-12 17:27:43.218437椅子を検知しました.
2020-10-12 17:27:43.245436椅子を検知しました.
2020-10-12 17:27:43.274445椅子を検知しました.
2020-10-12 17:27:43.301448椅子を検知しました.
2020-10-12 17:27:43.329434椅子を検知しました.
2020-10-12 17:27:43.357433椅子を検知しました.
2020-10-12 17:27:43.384432椅子を検知しました.                  
```
こんな感じで記録されていきます.

###動画を記録する部分
ここは結構大変そうなのでとりあえず次回に回します.
ごめんなさい.
## 次回へ
主に今回はyolov5のデフォルトプログラムを改良して物体を検知した後に記録するというプログラムを主にして書いて行きました.
次回は可視化する部分を具体的に書いていけたらいいなと考えていますのでよろしくお願いします.
集計したTwitterデータを自動でWordPressにcronで投稿して、最高の自分ログを作成する

しょーもない自分アプリのアイデアを紹介する投稿です。

思いついたことをメモがわりにTwitterに投稿することが多いのですが、内容が細切れなのであとで見返すのに苦労します。かといって都度ブログにまとめて投稿するかといったらしないです。
そこで、Twitterの投稿をAPIで取得して自動でWordPressに投稿すれば、週単位や数日単位の自分ログができるのではないかと考えました。

## アプリの概要
TwitterのAPIを使って、Pythonでデータを取得します。それをWordPressのxml-rpcのインターフェースでPythonから投稿します。PythonはXserverにファイルを置いて、Cronで実行します。

## ツール
TwitterAPI
Python
Xserver


## 流れ

- TwitterのAPIトークンを取得
- Pythonでツイートを取得するプログラムを作成
- WordPressにPythonから自動投稿するプログラムを作成
- XserverにPythonをインストール
- Twitterデータを取得するプログラムとWordPressに投稿するプログラムを合体
- Xserverでcronで動かす

## 方法

既にきれいにまとめていただいた記事が多くあり、それの劣化版を作成してもしょうがないので参照しつつコメントさせていただく形で説明させていただきます。

### TwitterのAPIトークンを取得

Twitterのトークンは結構手間がかかります。Twitter　Developerというサイトで申請して待ってから使えるようになります。申請して他をやって待つのがかも
https://www.itti.jp/web-direction/how-to-apply-for-twitter-api/


### ツイートを取得するプログラムを作成

トークンが発行できたら面白いところです。tweetyみたいなライブラリを使う方法もありますが、この記事が神すぎます。非常にプログラムもきれい。

https://qiita.com/kyohei_ai/items/243b6f98a31433d2faaf

### WordPressにPythonから自動投稿するプログラムを作成

これも面白いところです。WordPressは自動で投稿する方法として２つありますが、この記事のように昔からあるxml-rpcを使います。

https://np-sys.com/general/python%E3%81%A7wordpress%E3%81%AB%E8%87%AA%E5%8B%95%E3%81%A7%E6%8A%95%E7%A8%BF%E3%81%99%E3%82%8B%EF%BC%88python-wordpress-xmlrpc%EF%BC%89/

### XserverにPythonをインストール

XserverにもともとあるPythonは権限の関係でpipできません。なので自分用のPythonを導入する必要があります。ついでにSSH接続できるようにもしておきます
Python
https://note.com/coeeff/n/neab8acfde97e
SSH
https://qiita.com/NP_Systems/items/5277827a9ba7805d0811

そしたら、あとはwitterデータを取得するプログラムとWordPressに投稿するプログラムを合体させます。

## Xserverでcronで動かす

XserverではCronの設定が簡単にできます。結果も自動でメール配信してくれるので重宝します。
https://www.xserver.ne.jp/manual/man_program_cron.php


### できるようになったこと

Twitterデータが自動で投稿できるようになりました。


https://np-sys.com/diary/
AWS Glueの概要ついてまとめ

#はじめに
DWHとかデータレイクとか扱うお仕事でGlueを使うことになったので勉強もかねてまとめ。
※実装とかには触れないので、概念とかこんなもんか～を知りたい方向けです

##Glueとは
>データの分類、クリーニング、加工を優れたコスト効果で容易に行い、さまざまなデータストア間およびデータストリーム間でデータを確実に移動するための、完全マネージド型ETL (Extract/Transform/Load、抽出/変換/ロード) サービス
※参照：https://docs.aws.amazon.com/ja_jp/glue/latest/dg/what-is-glue.html

例えば、IFされるJSONデータをDBに入れたいんだけど、そのままの形式ではDBに入れられないからDBに入れるように加工してあげてロードまでやっちゃおうね、というイメージ。（ETL読んで字の如くではあるが）
S3、DynamoDB、Redshift、RDS等と連携可能で、用途としては、データウェアハウス・データレイク構築に向いている。
##稼働イメージ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/664906/2cb88e22-7ed0-7519-cb88-ada90c3e8283.png)

####■図の用語について
・<b>データストア</b>：データを永続的に保存するリポジトリ（S3、RDBなど）
・<b>クローラ</b>：データストアに接続し、データカタログにメタデータテーブルを作成するプログラム
・<b>データカタログ</b>：テーブル定義、ジョブ定義などのメタデータが集約されたもの
・<b>ジョブ</b>：ETL作業のビジネスロジック。オンデマンド、スケジュール、イベントトリガーで実行可能。
・<b>データソース</b>：インプット（加工対象データ）
・<b>データターゲット</b>：アウトプット（データのロード先）

クローラって、データカタログって、結局何なの、、、というのが初見での感想 ~~（技術系公式ドキュメント読むとだいたいこうなる）~~
先ほどの例で考えてみると、JSONを加工する用のジョブのスクリプトだったり、加工したあとにアウトプットになるDBの情報（テーブル、カラム、型など）だったり、要するに処理に必要な情報をため込んでいる箱のようなものかなと。で、クローラは、そのDBのテーブル情報を作ってくれる担当というイメージ。
なんとなく、わかった気がする、、、！

#まとめ
Glueの基礎の基礎くらいは認識できた気がしています。
実装部分については、まだ触っていないのでよくわからないですが、また知識が増えたら投稿しようかなあと思います。
Swift Package Manager (SwiftPM) を使ってみよう　~導入編~

Xcode11からiOSアプリ開発にも使えるようになり、先日リリースされたXcode12ではかなり使いやすくなったSwiftPackageManager（以下、SwiftPM）について、プロジェクトへの導入方法とSwiftPMへ自作ライブリを作成方法のうち、この記事は導入方法になります。

↓作成方法はこちら
* [Swift Package Manager (SwiftPM) を使ってみよう　~自作ライブラリ作成編~](https://qiita.com/gurensouen/items/6abe6482effc4afaa7dd)


##SwiftPMとは
* Apple製のパッケージ管理ツール
* 「CocoaPods」や「Carthage」のようなもの
* [SwiftPM ドキュメント（英語）](https://swift.org/package-manager/)
* [SwiftPM Github](https://github.com/apple/swift-package-manager)


##ライブラリ導入方法　

###導入環境
* Xcode12

###パッケージの追加
[ PROJECT ] → [ Swift Packages ] → [ + ]
![スクリーンショット 2020-10-05 11.04.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246668/4c46dc86-84a5-f51b-d77c-c67d00c5af8f.png)

[ 導入したいライブラリのURLを入力 ] → [ Next ]
※「導入したいライブラリ名　SwiftPM」などで検索すれば、導入したいライブラリのURLはわかると思います。
![スクリーンショット 2020-10-05 11.17.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246668/e70eb5bd-dcec-78a3-6c3e-d5a4ce3bfdea.png)

[ バージョン指定（今回は「Version」で行ってます）] →　[ Next ]
![スクリーンショット 2020-10-05 11.33.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246668/e04f59ee-2b54-13a1-c6af-41d5385a38b2.png)
バージョン指定方法は、それぞれ下記のようになっています。

| タイプ | 内容 |
|:-----------:|:------------|
| Version     | 特定のバージョンまたはバージョンの範囲を指定する| 
| Branch      | ブランチ名を指定する|
| Commit      | コミットのIDを指定する|

また、「Version」では更にオプションが指定できます。

|タイプ | 内容 | 例 | 例の意味 |
|:-----------:|:------------|:------------|:------------|
|Up to Next Major | 指定バージョン以上かつ次のメジャーバージョンより小さい | 1.0.0 < 2.0.0 | 1.0.0以上かつ2.0.0より小さい |
|Up to Next Minor | 指定バージョン以上かつ次のマイナーバージョンより小さい | 1.0.0 < 1.3.0 | 1.0.0以上かつ1.3.0より小さい |
|Range | 指定バージョン以上かつ指定バージョンより小さい | 1.0.0 < 1.5.0 | 1.0.0以上かつ1.5.0より小さい |
|Exact | 特定のバージョンを指定する | 1.0.0 | 1.0.0 |

[ 「Add to Target」にて追加先を確認 ] → [ Finish ]
![スクリーンショット 2020-10-07 15.11.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246668/55f3851e-1531-48c1-e267-04e907b83f7b.png)

プロジェクトに追加されていることを確認
![スクリーンショット 2020-10-07 15.12.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246668/a10f2e7c-9c1c-c490-86b5-4ffd0e47b21b.png)


以上が、SwiftPMでのライブラリ導入方法になります。
呼び出し方は、他のライブラリ同様

```Swift:ViewController.swift
//
//  ViewController.swift
//  SwiftPMTest
//
//  Created by Isami Odagiri on 2020/10/03.
//

import UIKit
import Nuke

```
で、使用できます。

###参考
- https://qiita.com/hironytic/items/09a4c16857b409c17d2c
- https://qiita.com/_tid_/items/c26fcd1b95eaed2dedb2
iOS14でタブバーが消えたまま戻らなくなる現象に遭遇した

# Overview
画面遷移の度に `hidesBottomBarWhenPushed = true` すると `popToRootViewController()` した時にtabBarが戻らなくなりました。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135304/a5af73e4-59d1-1261-3797-68b703df6cb1.gif" width="50%">

iOS13では発生しなかったため、iOS14のバグと思われます。
※ [Developer Forumsにも上がっていました](https://developer.apple.com/forums/thread/660750)

# 雑に再現コード
<details><summary>長いので折りたたみ</summary><div>

```swift:FirstViewController.swift
final class FirstViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        title = "First"
    }
}

extension FirstViewController {
    @IBAction func next(_ sender: Any?) {
        guard let vc = storyboard?.instantiateViewController(identifier: "second") else { return }
        vc.hidesBottomBarWhenPushed = true
        navigationController?.pushViewController(vc, animated: true)
    }
}
```

```swift:SecondViewController.swift
final class SecondViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        title = "Second"
    }
}

extension SecondViewController {
    @IBAction func next(_ sender: Any?) {
        guard let vc = storyboard?.instantiateViewController(identifier: "last") else { return }
        vc.hidesBottomBarWhenPushed = true
        navigationController?.pushViewController(vc, animated: true)
    }
}
```

```swift:LastViewController.swift
final class LastViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        title = "Last"
    }
}

extension LastViewController {
    @IBAction func popToRoot(_ sender: Any?) {
        navigationController?.popToRootViewController(animated: true)
    }
}
```

</div></details>

# 対応策
↑のコードの場合であれば`SecondViewController`の`vc.hidesBottomBarWhenPushed = true`を消してしまえば`LastViewController`からの`popToRootViewController`でタブバーが戻ってくるようになります。
ただし、複雑な画面遷移だと思わぬ副作用が発生するリスクもあるので、バグ修正されるのを待った方がいいのかも😅
巨大な aar を分割し、ビルド時に復元する

## こんなときに

* Android アプリ開発で、aar 形式で提供されるライブラリーを使用しているが、aar ファイルが巨大すぎてそのまま commit & push すると GitHub に怒られるとき

## どうする

* aar ファイルを分割した状態で Git にコミットし、gradle でアプリをビルドする時に自動的に元の aar ファイルが復元される様にする

## くわしく

普通に aar ファイルをライブラリーとしてインポートすると、build.gradle ファイルは以下の様になってるはずです。

```gradle
configurations.maybeCreate("default")
artifacts.add("default", file('foo.aar'))
```

これを、以下の様に変更します。(ファイル名 `foo.aar` は適宜調整のこと)

```gradle
plugins {
    id "base"
}

task archiveAar(type: Zip) {
    group = "Build"
    description = "Creates the aar archive."
    archiveFileName = "foo.aar"
    destinationDirectory = project.projectDir
    inputs.files {
        fileTree(".") {
            include "foo.aar.*"
        }
    }
    inputs.files.each {
        from zipTree(it)
    }
}

configurations.maybeCreate("default")
artifacts.add("default", archiveAar.archiveFile)
```

さらに、aar ファイルを一旦 unzip し、出てきたファイル群を適当な複数の部分集合に分割したあと、それぞれを zip ファイルとして圧縮し直します。
圧縮後のファイル名は `include "foo.aar.*"` のところにマッチする様に `foo.aar.1`, `foo.aar.2`, ... とかそんな感じにしておきます。
元の aar ファイル内のディレクトリー構成が新しい zip ファイル内でも保たれる様に気を付けてください。
最後に、分割後のファイルと build.gradle を Git にコミットして完了です。(GitHub に push した時に怒られない様にするには、分割 zip 後の各ファイルが 50 MB 未満となる様にすべきです。)

あとは普通にアプリをビルドすれば OK です。
(初回ビルド時のみ、まだ aar ファイルが復元されてないためにビルドが失敗することがあります。その場合は先に `gradle archiveAar` を単体で実行すると aar ファイルが生成されます)

----

筆者環境は Gradle バージョン 6.3 です。他のバージョンの Gradle では結果が異なる可能性があります。
3. Percentage of users by age group

In this article, I check the percentage of users by age group.
※If you have a data, you don’t have to read contents1.

#Contents
[1. Creation of simulation data](#1-creation-of-simulation-data)
[2. Bar and pie charts](#2-bar-and-pie-charts)

#1. Creation of simulation data
```R:
> age <- rpois(1000, lambda=30)
> age <- aggregate(age, list(age), length)
> age10 <- age %>% filter(Group.1>9 & Group.1<20)
> age20 <- age %>% filter(Group.1>19 & Group.1<30)
> age30 <- age %>% filter(Group.1>29 & Group.1<40)
> age40 <- age %>% filter(Group.1>39 & Group.1<50)
> age50 <- age %>% filter(Group.1>49)
> Data <- c(sum(age10$x), sum(age20$x), sum(age30$x),
+             sum(age40$x), sum(age50$x))
> Data <- data.frame(c(10, 20, 30, 40, 50), Data)
> names(Data) <- c("age.classification", "number.of.users")
> Data
  age.classification number.of.users
1                 10              14
2                 20             436
3                 30             486
4                 40              64
5                 50               0
```

#2. Bar and pie charts
```R:
> library(ggplot2)
> p1 <- ggplot(data=Data, aes(x=age.classification))+
+   geom_bar(aes(y=number.of.users), size=0.9, stat='identity')+
+   labs(title="Number of users by age")+
+   ylab("number of users")
> library(ggrepel)
> Data$per <- round(Data$number.of.users/sum(Data$number.of.users)*100,1)
> Data$per <- paste0(Data$age.classification, "\n",Data$per, "%")
> p2 <- Data %>%
+   ggplot(aes(x=0, y=number.of.users, fill=factor(number.of.users)))+
+   geom_col()+
+   coord_polar("y")+
+   geom_text_repel(aes(label = per), position = position_stack(vjust = 0.5))+
+   theme_void()+
+   theme(legend.position="none")
> gridExtra::grid.arrange(p1, p2)
```
>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/775500/eb3e3dcc-92ab-9f21-ed67-b561e550c567.png)
【Vagrant+Vbox】ゲストOS側のゲストアディション(VboxGuestAdditions)のバージョンをホストOSに合わせてアップデートさせる。

メモとして残します。

ゲスト側のVboxゲストアディションが（GuestAdditions）ホストと比べ古かったため、
VagrantのプラグインでVagrantUp時に自動アップデート（ホストに合わせる）ようにしました。

#やり方
```shell
#ホスト側で実行
vagrant plugin install vagrant-vbguest


#あとはvagrant up
#または 起動しているなら↓
#vagrant reload --provision
```

以上。
Heroku + WordpressでS3を使用する

# 概要
WordpressをHerokuで運用する際、Herokuは定期的にビルドを行っているため、アップロードした画像が消えてしまう現象が発生します。

> herokuのリポジトリがdynoという単位で管理されており、Freeプランだと一定時間経過後にdynoが再起動される仕様になっているから。 - [【Rails6】herokuで投稿した画像が表示されない](https://tea-programming.blogspot.com/2020/03/rails6heroku_24.html)

そこでAWSの**「S3」**というサービスを用いることで画像が消える現象を回避します。Wordpressのプラグインを用いてアップロードする画像の格納先をS3に設定することで、外部に画像を保存します。

# S3を使用するための準備をする
まず、下記の記事に沿ってWordpressでS3を使用する準備を行います。

[WordPressの画像データをS3に保存する](https://hacknote.jp/archives/43897/)


# S3のアクセス権限の設定

S3のブロックパブリックアクセスは下記のように設定します。
![WS000022.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469694/c0a78513-7fc2-db1a-e4ed-183e1205a1c6.jpeg)
この設定によって、私の環境で次の二つを達成することを確認しております。

- WordPressからの画像アップロード
- ポートフォリオサイトからの画像の表示

参考：[Amazon S3 パブリックアクセスブロックの使用](https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/dev/access-control-block-public-access.html)

バケットポリシーの設定は次のようにしています。

```:バケットポリシー
{
    "Version": "2008-10-17",
    "Statement": [
        {
            "Sid": "AllowPublicRead",
            "Effect": "Allow",
            "Principal": {
                "AWS": "*"
            },
            "Action": "s3:GetObject",
            "Resource": "<リソース名>/*"
        }
    ]
}
```

参考：

-  [WordPress S3 Tutorial: How to Connect WordPress to Amazon S3 Bucket](https://www.codeinwp.com/blog/wordpress-s3-guide/)
- [Amazon S3 コンソールを使用して、バケットの ACL でパブリックアクセスを有効にしました。誰でもバケットにアクセスが可能ですか ?](https://aws.amazon.com/jp/premiumsupport/knowledge-center/s3-public-access-acl/)

# ローカル環境でS3へつなぐ際にエラーが発生する

Wordpressのローカル環境からS3へアクセスする際にエラーが発生することがありますので、次の記事に沿って対処します。

[WordpressからS3につなごうとして"There was an error attempting to get the region of the bucket"が発生した](https://qiita.com/kyabetsuda/items/c24f89a0cd53057bc265)


# GDをComposerに追加する

WordpressでS3を使用するためにはGD（画像ファイルの操作ライブラリ)の使用が必要です。HerokuにはデフォルトでGDがインストールされてないため、Composerで使えるように設定する必要があります。

参考：[Image Processing and GD](https://www.php.net/manual/en/book.image.php)

まず、composer.jsonに下記のように追記します。

``` composer.json
{
    "require": {
        "ext-gd": "*"
    }
}
```
作ったファイルはwordpressのルートディレクトリに配置します。続いて下記のコマンドを実行します。
 
```shell
$ composer install
```

終了後、composer.lockがcomposer.jsonと同じディレクトリに作成されていればOKです。後はHerokuへのデプロイ時にHerokuが自動的にライブラリをインストールします。

参考：[Heroku PHP Support](https://devcenter.heroku.com/articles/php-support#activation)
Kubernetes meetup オンプレ?クラウド?事例共有会に参加しました

## 開催日程
* 2020年10月08日（木）

## 場所
* オンライン

## 主催
* 株式会社カカクコム

## 申し込み
* https://techplay.jp/event/792629

## 費用
* 無料


## セッション - コンテナセキュリティとAdmissionWebhookによるデプロイ制限
### 会社紹介
* 有名サービス
    * 価格.com, 食べログ...
* 管理サーバ台数
    * 物理サーバ：何百台
    * 仮想サーバ：何千台

### 部署紹介
* 事業部
    * サービス開発
* インフラアーキテクト
    * 物理サーバ、仮想サーバ、OS,ミドルウェア
    * AS, DCネットワーク、自社CDN

### Kubernetes導入背景
* 開発エンジニアでのコンテナ利用事例増加(開発環境)
* 省コストで運用可能
* オンペレミスで運用しやすい

### システム構成
1. webサイトへアクセス
2. LoadBalanceによりいずれかのWorker NodeへL4分散
3. host HeaderによりIngressに接続したserviceへ振分け
4. Serviceに繋がるPodへルーティング

### 監視構成
* Prometheusでリソース(Worker Node)情報を取得して、Grafanaで可視化
* fluentdとElasticsearchでPodのログ収集して、Kibanaで可視化

### 各部署の作業範囲
* 開発エンジニア
    * Namespace配下でのアプリケーションデプロイ
    * アプリケーション監視
* インフラ担当者
    * ロードバランス
    * workerとIngress
    * 運用と監視システム

----

## セッション - マネージドKubernetesの強みとオンプレでの考慮点

### Kubernetesの構成要素
* Kubernetes Core
    * Kubernetesのコアコンポーネント
* Cloud Controller Manager
    * クラウド基盤と連携するためのコンポーネント
* Ingress Controller
    * L7 Load Balancing を提供するコンポーネント
* CSI Driver
    * ストレージ基盤と連携するためのコンポーネント
* Authentication Module
    * 認証機能を提供するコンポーネント
* その他

### Kubernetes Core
* Kubernetes本体のソースコード自体は基本的には同じ
* プラグインを利用してその他のコンポーネントと繋がれる

### Ingress Controller
* 以下の三つの方法がある
    * Podを利用したIngress
    * 外部のLBを利用したIngress(VM-based)
    * 外部のLBを利用したIngress(Container-native)


## 感想
* 今回の勉強会はKubernetesの基本知識の紹介ではなく、発表者の開発経験よりKubernetesの使い方と自分のシステムと結合方法が紹介される
* 大きいサービスやシステムに対して、Kubernetesを使って便利になる
【2020年10月】Retrofitで Multipart アップロードする時に参考になる記事まとめ

# 情報が揃っている記事がなかったので、ここに整理します。

## android - Retrofit(2.0 beta2) Multipart file upload doesn't work - Stack Overflow
https://stackoverflow.com/questions/33473213/retrofit2-0-beta2-multipart-file-upload-doesnt-work
@Multipartが動かない時は↓これを使いましょう↓

## Retrofit2でMultipartPOST - Qiita
https://qiita.com/satsukies/items/822db4f68094dad4951d
良記事！RequestBody.createが廃止になったので、その部分は↓を参考にしましょう

## okhttp3 - RequestBody.create(contentType、content)非推奨
http://www.366service.com/jp/qa/de8d3f15061dd674fda31b1c81356662

## AndroidでのBitmap/JPEG/byte配列の相互変換 - Qiita
https://qiita.com/aymikmts/items/7139fa6c4da3b57cb4fc
アップロード時に色々変換する時に参考にしましょう

## Androidでmultipartで画像とテキストを同時送信 - Qiita
https://qiita.com/hisakioomae/items/9588e41ead50bd62f186
RxJAVAを使ってる方はこれがわかりやすいかも！
【フロント・ネイティブエンジニア必見】マイクロインタラクションの参考になるサイト7選

# マイクロインタラクションの参考になる情報サイトまとめ
UX改善に欠かせないマイクロインタラクション
フロントエンド・ネイティブアプリエンジニアはこのような細部へのこだわりにワクワクすること間違いなし！
どんな実装があるのか、参考になる情報をまとめます。

## まずは書籍紹介
![picture978-4-87311-659-4.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138063/478bbcd2-862e-5b9b-0bb4-fc439befb0cd.gif)

[O'Reilly Japan - マイクロインタラクション](https://www.oreilly.co.jp/books/9784873116594/)

これは結構読むのが大変でした！
書籍をいきなり買うのはちょっと。。。という方は以下のサイトを厳選しましたので、さらっとみてからの購入をお勧めします

## サイト紹介

### マイクロインタラクションを感覚的に理解できるサイト
[マイクロインタラクションとは？注意すべきポイントや事例を徹底解説！ | Web Design Trends](https://webdesign-trends.net/entry/7583)

[マイクロインタラクションを考慮すべき４つの理由 | UX MILK](https://uxmilk.jp/75363)

[UIにマイクロインタラクションを！ より良いUXのための７つの秘訣 | UX MILK](https://uxmilk.jp/3553)

[より良いUIのためのマイクロインタラクション入門｜Blog｜Goodpatch グッドパッチ](https://goodpatch.com/blog/ui-micro-interaction/)

[小さな動きで大きな効果！マイクロインタラクションを使って優れたUXを実現する | Web Design Trends](https://webdesign-trends.net/entry/5883)

これらのサイトをざっと眺めれば、1５分程度でどのようなものがマイクロインタラクションかわかります。
見てるだけで楽しいのでぜひ眺めてみましょう！

### 効果検証はどうするのか！
[マイクロインタラクションの効果を数値化する｜鈴木慎吾 / TSUMIKI INC.](https://note.tsumikiinc.com/n/na0dd9ee70ea0)
ただ綺麗で楽しいだけじゃビジネス上意味はありません。
数字で効果を把握して、ビジネスに貢献するにはどうすればいいのか参考になります！

### デザイナーはどうやってつくるのか！
[マイクロインタラクションを活かしたコンセプトデザインの作成 @Adobe MAX Japan 2019｜鈴木慎吾 / TSUMIKI INC.](https://note.tsumikiinc.com/n/nd24ddb19d5fa)
デザイナーの方がどのように設計するのか、動画で多くのサンプルが見れます。
工程を把握することでデザイナーの方とのコミュニケーションがスムーズになること間違いなし！

## 最後に
読んでくださったみなさんが感動したUX・UIもぜひコメントで紹介してください！
よろしくおねがいします！！
2. Correlation

In this article, I check the correlation between sales and the number of visiting customers.
※If you have a data, you don't have to read contents1

#Contents
[1. Creation of simulation data](#1-creation-of-simulation-data)
[2. Visualization](#2-visualization)
[3. Correlation](#3-correlation)

#1. Creation of simulation data
I use [the data used here](https://qiita.com/Tatsuki-Oike/items/60d27a1d2912498173fd). Moreover, I add data to examine the relationship between two variables. Of course, You can check the relationship between multiple variables with almost the same code)

```R:
> head(Data)
        time sales
1 2020-03-01     7
2 2020-03-02     4
3 2020-03-03    17
4 2020-03-04     2
5 2020-03-05     9
6 2020-03-06     9
> Data$number.of.customers <- rnbinom(nrow(Data), mu = 7, 0.8)
> head(Data)
        time sales number.of.customers
1 2020-03-01     7                   1
2 2020-03-02     4                  18
3 2020-03-03    17                   2
4 2020-03-04     2                   1
5 2020-03-05     9                   2
6 2020-03-06     9                  43
```

#2. Visualization

```
> library(ggplot2)
> Data$time <- as.POSIXct(Data$time)
> ggplot(data=Data, aes(x=time))+
+   geom_line(aes(y=scale(sales), colour="black"), size=0.9, show.legend = T)+
+   geom_line(aes(y=scale(number.of.customers), colour="blue"), size=0.9, show.legend = T)+
+   labs(title="Comparison")+
+   ylab("sals/number.of.customers")+
+   scale_x_datetime(date_labels="%m/%d")+
+   scale_colour_manual(name='Legend',guide='legend' ,
+                       values = c("black"="black", "blue"= "blue"),
+                       labels=c('sales', 'number.of.customers'))
```

>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/775500/5ecaed02-216f-bccf-f852-b4208827b13e.png)


#3. Correlation

```
> library(corrplot)
> library(gplots)
> corrplot.mixed(corr=cor(Data[,c(2,3)]), upper="ellipse")
```
>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/775500/af26853f-619e-4ff6-38e6-841dd4d697ad.png)
before, after 擬似要素に画像を入れる。

下記の例は、ボタンに画像を入れたやつ。

```
                &__button{
                    position: relative;
                    width: 185px;
                    height: 34px;
                    padding: 5px 35px 5px 20px;
                    background-color: #0086D3;
                    color: white;
                    font-weight: bold;
                    &:after{
                        content: '';
                        display: inline-block;
                        position: absolute;
                        top: 15px;
                        right: 8px;
                        width: 13px;
                        height: 9px;
                        background-image: url(画像パス);
                        background-size: contain;
                        vertical-align: middle;
                    }
                }
```
WordpressからS3につなごうとして"There was an error attempting to get the region of the bucket"が発生した

# 概要
ローカル環境でWordpressを構築し、そこからS3へつなごうとした際にタイトルのエラーが発生しました。

>Error Getting Bucket Region —There was an error attempting to get the region of the bucket <バケット名>: Error executing "GetBucketLocation" on "<バケットのURL>?location"; AWS HTTP error: cURL error 60: (see https://curl.haxx.se/libcurl/c/libcurl-errors.html)

# 原因
内容はCURLでS3へつなぐ際にコード60のエラーが発生しているというものです。コード60は次のようになっています。

> CURLE_PEER_FAILED_VERIFICATION (60)
The remote server's SSL certificate or SSH md5 fingerprint was deemed not OK. This error code has been unified with CURLE_SSL_CACERT since 7.62.0. Its previous value was 51. - [libcurl error codes](https://curl.haxx.se/libcurl/c/libcurl-errors.html)

これだけでは少しわかりづらいですが、調べていると次のような記述を発見しました。
> OSにバンドルされているルート証明書などが古いので証明書の検証ができない様子。 - [curl: (60) SSL certificate problem, verify that the CA cert is OK](https://www.softel.co.jp/blogs/tech/archives/5880)

私の解釈ですが、**つなぎ先サーバのSSL証明書とつなぎ元端末のSSL証明書を検証した際、つなぎ元端末のSSL証明書が存在しないor古いために発生するエラーと考えられます。**こちらは次の対策をすることで解決しました。

# 対処法
まず、次のサイトより最新の証明書(cacert.pem）をダウンロードします。

[CA certificates extracted from Mozilla](https://curl.haxx.se/docs/caextract.html)

次に作成したwordpressプロジェクトのconf/phpフォルダ配下にphp.ini.hbsというファイルがありますので、そのファイルの一番下に次のコードを追加します。

```ini:php.ini.hbs
[curl]
curl.cainfo = "<ダウンロードしたcacert.pemのパス>"
```

Wordpressプロジェクトを再起動し、WP Offload Media Liteの設定画面でS3のバケットを選択すると接続ができるようになっているはずです。


参考：
[curl: (60) SSL certificate problem: unable to get local issuer certificate](https://stackoverflow.com/questions/24611640/curl-60-ssl-certificate-problem-unable-to-get-local-issuer-certificate)
[cURL error 60: SSL certificate problem: certificate has expired](https://stackoverflow.com/questions/62107431/curl-error-60-ssl-certificate-problem-certificate-has-expired)
クラスの関係をひと目で確認　PhpStormクラス図

![Something went wrong]()
私は仕事でPHP・Laravelを使用していますが、古くからある大規模システムなど、
ベリーファットなコントローラや無数のメソッドがあったり、追うのが大変なことがあります。
そのときにPhpStormの機能、UMLクラス図作成を使用すると便利です。

#どんな図？
継承元のクラスが青い実線で表示され、破線は依存関係（use 宣言）を示しています。
各クラスごとのメソッドをpublic, protectedに分けて表示してくれます。
![Screen Shot 2020-10-02 at 21.11.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/429030/4894818c-25c9-6966-ef08-1af3aed99f3a.png)

>2次元の図で表現することは、その情報を記憶しやすくする効果があります。人間の頭はイメージのほうが覚えやすいため、「形」で表現してあると、「2つのクラスの上に描かれていたスーパークラスがあったけど名前は何だっけ」というように、イメージの位置関係とあわせて内容が記憶しやすくなります。

>平澤 章. オブジェクト指向でなぜつくるのか 第2版 (Japanese Edition) (Kindle Locations 3425-3429). Kindle Edition. 

# HOW
まず、UMLプラグインが入っているか確認しましょう。
![Screen Shot 2020-10-02 at 22.24.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/429030/62298054-4277-96d9-3a77-7ddd52fceebe.png)

参照したいクラスを右クリックし、Diagrams > Show Diagramsを選択すると生成されます！
![Screen Shot 2020-10-02 at 21.56.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/429030/503b74d9-78a6-98a6-13dd-78c04601405e.png)

## 公式ページ
https://pleiades.io/help/phpstorm/class-diagram.html
AWS CloudWatchEventsの時間指定をCDKでラクにする。

CloudWatchEventsってUTCでしか動かないじゃないですか。
いつもそれを忘れて時間指定失敗するので、CDKでJST→UTCに変換することにしたんですよ。

# CDKでCloudWatchEventsを定義する

取り敢えずCloudWatchEventsの定義のとこだけ。
これをよしなにStepFunctionsとかと組み合わせるなり何なりする。

```Python
# バッチスケジュールをJSTで定義する（cron式で * にする所は空でよい）
props['schedule'] = {
    'minute': 40,
    'hour': 9,
    'week_day': 'MON-FRI'
}

# JSTをUTCに変換する
if props['schedule'].get('hour') is not None:
    props['schedule']['hour'] = props['schedule']['hour'] - 9
    if props['schedule']['hour'] < 0:
        props['schedule']['hour'] += 24
        if props['schedule'].get('day') is not None:
            props['schedule']['day'] = props['schedule']['day'] - 1
        
# JST 月初の朝9時までに動作する場合は、月末っぽい日付で動作させてLambda等で判定する
if props['schedule'].get('day') == 0:
    props['schedule']['day'] = '28-31'

# props['schedule']の中身をstrに変換する
for key in props['schedule'].keys():
    props['schedule'][key] = str(props['schedule'][key])
    
# Cloud Watch Events
Rule = events.Rule(
    app, f"Batch-{id}",
    schedule=events.Schedule.cron(**props['schedule'])
)
```

# 月初の9:00より前（UTC月末）の判定Lambda

今がJSTの月初（1日）かどうかだけ判定してTrueかFalseが返る。
StepFunctionsに組み込むならこれの返り値を判定して次に流すか終わるかすればよいし、単純な処理ならこのLambda内にて`if result:`で続けて処理してしまってもよいかと思います。

```Python
import datetime
import calendar


def lambda_handler(event, context):
    print('===Start Lambda===')
    print(event)
    
    dt_now = datetime.datetime.now()
    monthrange = calendar.monthrange(dt_now.year, dt_now.month)[1]
    
    result = dt_now.day == monthrange
    
    print(result)
    
    return result
```

※printは動作確認のためだけに書いてるので要らなければ消してよい。


# おわり

何かもっといい方法とかご存知の賢者様はご指摘いただけると嬉しいです。
TypeLoadExceptionとの遭遇と対処

# 問題の概要
AdstirSDKを更新したら、`TypeLoadException`エラーがでた。

# 原因(予想)
MigratePackages の実行中に動かなくなり、Unityを強制終了しちゃった。

# 詳細(手順)
1 : AdstirSDK の UnityPackageをimport（All Import）
2 : GoogleVersionHandler にて更新が確認されたので、全てApply
<img width="300" alt="GoogleVersionHandler.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/275803/2e810e3c-cc59-b446-04e7-a6ce82130b3d.png">

3 : PackageManagerResolver にて更新が確認されたので `GamePackageRegistry By Google` を選んで AddSelectedRegistries
<img width="300" alt="PackageManagerResolver.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/275803/5a610ee1-30ce-ec8b-1a0a-4684bf2e55e8.png">

4 : MigratePackages にて更新が確認されたので、全てApply
<img width="300" alt="MigratePackages.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/275803/a9fe2380-3ae9-0b24-b2e3-fda5600f951c.png">
5 : 「手順4」Apply後の読み込みが2時間近く終わらなかったので、Unityを強制終了
6 : Unity再起動
7 : Unity起動時に`TypeLoadException: Could not resolve type with token 01000036`のエラーログが複数出るようになった。
　（Clearでエラーログは消えるが、不安）

# 対応
明らかに怪しいのは「詳細手順4」なので、下記のような対応を行った。
1 : 詳細手順1〜3を行う
2 : 詳細手順4が自動で表示されるので Canncel -> 現状をGitにPush
3 : MenuからAssets/ExternalDependencyManager/PackageManagerResolver/MigratePackagesを選択
4 : MigratePackages にて更新が確認されたので、全てApply
5 : 数分で処理が完了 -> `TypeLoadException: Could not resolve type with token 01000036` のエラーが出る
　（おそらく、Migrateの途中でエラーが出ただけ）
6 : Unity再起動 -> 起動時にエラーが出現しなくなる

# まとめ
UnityPackageのImport作業途中で落ちたり、落としたりして異常が発生した場合は
作業を区切って少しずつ進めると良いかもしれませんね。