OmniAICreator/Qiita-1.07M huggingface dataset:
【Unity】Screen.safeAreaとiOSステータスバーの罠（？）

# Unityで取得できる Screen.safeAreaには罠（？）がある

罠に遭遇したのは、以下の条件

- 4.7インチiPhone(iPhone6/7など)
- Unity2017.4.35, 2018.4.15
- iOS10

|OS|Screen.safeArea.h|Screen.height|ステータスバー高さ|
|---|---|---|---|
|iOS12|1294|1334|40|
|iOS10|1334|1334|40|

- iOS11以降だとsafeAreaのRectは正しくステータスバーを避けてくれるが、iOS10だと重なってしまう

# 原因

- そもそもsafeAreaの導入がiOS11から
- Screen.safeAreaは単純にsafeAreaInsetsをOS判定して取得しているだけだと思われる
    - iOS10以下はエラーにならないようにしているだけ?

# 解決策

- OSを取得して分岐するしかなさそう
 - iOS10以下ならiPhoneX系統は存在しないから、ステータスバーは 20 x scale で固定…？
    - scaleを取得するにも結局plugin書かないとなので、topLayoutGuide、bottomLayoutGuideあたりを使うのが良さそう

# 参考

- [iPhoneXでのAutoLayoutをきれいに書くための試行錯誤](https://qiita.com/risuke/items/bb5735f0e8f3bc8306db)
- [【Unity】これ以上iOSのSafeAreaで消耗したくない人のため『Unity-SafeAreaCanvas』](https://qiita.com/nkjzm/items/e395e6da9ca46963dba9)


# 余談

- この記事を検証するにあたってシミュレーターで実行しようとして色々色々罠にハマった…
- 警告に従って、Graphics APIsにGLES3を「追加」すると、シミュレーターでのアプリ起動時に `UnityInitApplicationGraphics` で停止してしまう
- 正解は、「追加」ではなく入れ替え（Metalは削除）
- が、ES3に入れ替えたバージョンでiOS13の検証はできたが、iOS10のシミュレーターで実行しようとすると再び`UnityInitApplicationGraphics` で停止
- 未検証だが、ES2にするべきなのかもしれない
プログラミング・フォロを組み立てる

#プログラミング・フォロ
micro:bitを内蔵して６本足で自律して歩き回ることの出来る [プログラミング・フォロ](https://www.switch-science.com/catalog/5482/)を組み立てて動かしてみました。

##組み立て
プラモデルなので、ニッパで切り出してカッターでバリを取って、説明書を見ながら組み立てるだけ。
出来上がるとこんな感じに。
![image1_2.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576327/9d48689e-66dc-3add-900a-66608d579f9c.jpeg)
胴の部分にモーターとギアボックスがあり、頭の部分に電池Boxとモータードライバと赤外線センサーとスピーカーがある。
横にあるのがmicro:bitで、フォロの顔の部分にはまるようになっている。
腕はあるけどモーターでは動かないのはちょっと残念。

##プログラミング
micro:bitへのプログラミングは[MakeCode](https://makecode.microbit.org/)を使う。
今回は Raspberry Pi 4 上でMakeCodeを使ってみた。
![2020-01-31-232702_1007x584_scrot.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576327/ac8d9af1-7775-ff82-ad28-783aa84807a3.png)


プログラミング・フォロのHPにあるように、顔の部分に来るLEDを光らせるサンプルをMakeCode上で作り、ファイルをダウンロードする。ダウンロードしたファイルは ~/Downloads ディレクトリに xxx.hex というファイル名でダウンロードされる。
![2020-01-31-232824_640x465_scrot.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576327/ca979909-8062-d910-e881-4704462b5f9f.png)

Raspberry Pi にmicro:bitをUSBで接続すると、micro:bitが自動でマウントされるので、ダウンロードしたファイルをmicro:bitのディレクトリにコピーする。コピーが終わると micro:bit がアンマウントされ、自動で再起動がかかり、すぐに作ったプログラムが実行され、顔が表示される。
micro:bitをRaspberry Piからはずし、フォロにセットしてスイッチを入れるとちゃんと顔が表示された。

ちゃんとプログラミングして動くことがわかったので、次は探索プログラムをダウンロードしてmicro:bit上へコピーして、フォロにセットする。
フォロの電源を入れると前へ歩き出し、壁の近くまで行くと少しバックして回転してまた前に歩き始めた。
ちゃんと赤外線センサーも反応してるし、前後の移動も回転も動いてくれた。
![move_folo.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576327/d6f05f17-edea-8c63-1105-3a2876d60a64.gif)
リモートデスクトップのタスクバーが重なってしまう問題解消法

##リモートデスクトップのタスクバーが重なってしまう問題解消法

リモートデスクトップをした際に接続元のタスクバーが
接続先タスクバーの上に表示されてしまうことがたまにある。
原因分からないが、鬱陶しい。


####解決策は、接続元で「エクスプローラー」プロセスの再起動を行うことで解消する。

解消手順

+ タスクマネージャー起動
* プロセスタブ→「エクスプローラー」プロセスを右クリック→再起動

このような細かいことは気にしない人が多い。
自分はフルスクリーンじゃないとだめな派です。
Github Actions Secrets API を使って Go で Secrets を更新する

# Github Actions API が公開され、 Secrets を API 経由で更新できるようになりました

Github Actions で利用する Secrets はこれまで手作業で更新する必要がありました。
たくさんのレポジトリを管理していてそれぞれに Actions を仕込むときに更新がとても大変でした。

そんな中、 Github Actions API が公開(2020/1/27)され、 Secrets の更新が API 経由で行えるようになりました :tada:

[Secrets | Github Developer Guide](https://developer.github.com/v3/actions/secrets/)

# Secrets API の概要

Secrets は秘密鍵、公開鍵を用いて暗号化しているのですが、 Github Actions では libsodium を使って実現しているようです。

- [jedisct1/libsodium - Github](https://github.com/jedisct1/libsodium)
- [Introduction - Libsodium documentation](https://libsodium.gitbook.io/doc/)

![github_secrets-100.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14657/3ebe41e6-02f8-75b6-b034-8bf69da9aa2c.jpeg)

- 暗号化に使う公開鍵を Github Actions API を使って取得します。
- key_id と key が取得できます。 (libsodium で Secrets を暗号化するための公開鍵です)
    - key は base64 でエンコードされているのでデコードしてバイナリに戻します。
- 公開鍵を用いて Secrets を暗号化します。
- Github Actions API を使って Secrets 名と暗号化された Secrets を送信します。
- Github Actions で用いるときに秘密鍵で復号化して Secrets を利用しているものと思われます。

# Go で API を叩いてみます

Go には google/go-github という Github API のライブラリが存在します。

[google/go-github - Github](https://github.com/google/go-github)

ただ、 2020/1/31 現在、まだこのライブラリでは Github Actions API をサポートしてない模様です。
調べてみると、既にサポート PR が出ていたので試してみました。

```go.mod
replace github.com/google/go-github/v29 => github.com/martinssipenko/go-github/v29 v29.0.3-0.20200130054045-bbe3d535861d
```

```go
func UpdateSecret(owner, repo, name, secret string) error {
	// Github Client を用意
	sts := oauth2.StaticTokenSource(
		&oauth2.Token{AccessToken: os.Getenv("GITHUB_TOKEN")},
	)
	oc := oauth2.NewClient(context.Background(), sts)
	cli := github.NewClient(oc)

	// 公開鍵を取得
	pubKey, _, err := cli.Actions.GetPublicKey(context.Background(), owner, repo)
	if err != nil {
		fmt.Println("error GetPublicKey:", err.Error())
		return err
	}
	pkBase64 := pubKey.GetKey()
	pk := make([]byte, 32)
	_, err = base64.StdEncoding.Decode(pk, []byte(pkBase64))
	if err != nil {
		fmt.Println("base64 decode error:", pkBase64, err.Error())
		return err
	}

	// sodium で暗号化を施す
	encSec := sodium.Bytes(secret).SealedBox(sodium.BoxPublicKey{Bytes: pk})
	encSecBase64 := base64.StdEncoding.EncodeToString(encSec)

	// Secret を更新
	es := &github.EncryptedSecret{
		Name:           name,
		KeyID:          *pubKey.KeyID,
		EncryptedValue: encSecBase64,
	}
	_, err = cli.Actions.CreateOrUpdateSecret(context.Background(), owner, repo, es)
	if err != nil {
		fmt.Println("failed to update secret", err.Error())
		return err
	}
	return nil
}
```

これで無事 Secret を API 経由で更新できました :tada:
GROUP BYやサブクエリを使わずに店ごとの一番高い商品を取得する

DrupalというWebフレームワークのクエリビルダーでこのような処理が行われていて個人的に目からウロコだったので共有します。

たとえばこんなテーブルがあったとして、店（`shop_id`）ごとの一番値段(`price`)高い商品を取得したい。

| shop_id | item_name | price |
|-------|-------|-------|
|1|pencil|200|
|1|eraser|180|
|2|t-shirt|1900|
|2|skirt|1500|
|3|table|20000|
|3|chair|10000|

(テーブル名は`shops`テーブルとします)
値段が欲しいだけだったら

```sql
SELECT shop_id, MAX(price) FROM shops
GROUP BY shop_id
```
で以下のような結果になります

| shop_id |price |
|-------|-------|
|1|200|
|2|1900|
|3|20000|

が、ここで商品名(`item_name`)も同時に取得しようとすると、標準SQLではエラーになります。

ネットを検索してみたところサブクエリを使う方法もあるようですが、今回紹介する方法では、`LEFTJOIN`と`WHERE`だけで取得します。

```sql

SELECT shop_id, item_name, price FROM shops
LEFT JOIN shops AS shops2 ON shops.shop_id = shops2.shop_id AND shops.price < shops2.price
WHERE shops2.price = NULL
```
たったこれだけのクエリで店ごとの一番高い商品が取得できます。

| shop_id | item_name | price |
|-------|-------|-------|
|1|pencil|200|
|2|t-shirt|1900|
|3|table|20000|

このクエリで何をしてるのかというと、まず

```sql

LEFT JOIN shops AS shops2 ON shops.shop_id = shops2.shop_id 
```
で全く同じテーブルを`shop_id`を基準として右に連結しています。

この状態でクエリを実行すると

| shop_id | item_name | price | shop_id | item_name | price |
|-------|-------|-------|-------|-------|-------|
|1|pencil|200|1|pencil|200|
|1|pencil|200|1|eraser|180|
|1|eraser|180|1|pencil|200|
|1|eraser|180|1|eraser|180|
|2|t-shirt|1900|2|t-shirt|1900|
|2|t-shirt|1900|2|skirt|1500|
|2|skirt|1500|2|t-shirt|1900|
|2|skirt|1500|2|skirt|1500|
|3|table|20000|3|table|20000|
|3|table|20000|3|chair|10000|
|3|chair|10000|3|table|20000|
|3|chair|10000|3|chair|10000|

となりますが、

```sql
AND shops.price < shops2.price
```

であらかじめ右の価格が大きい場合しか連結しないようにしてるので、`LEFT JOIN` の結果は以下のようになります。

| shop_id | item_name | price | shop_id | item_name | price |
|-------|-------|-------|-------|-------|-------|
|1|pencil|200|NULL|NULL|NULL|
|1|eraser|180|1|pencil|200|
|2|t-shirt|1900|NULL|NULL|NULL|
|2|skirt|1500|2|t-shirt|1900|
|3|table|20000|NULL|NULL|NULL|
|3|chair|10000|3|table|20000|

店で一番高い商品の右側だけが`NULL`になるので、

```sql

WHERE shops2.price = NULL
```
で絞り込めば完了です。

| shop_id | item_name | price |
|-------|-------|-------|
|1|pencil|200|
|2|t-shirt|1900|
|3|table|20000|
Microsoft Graph APIでSharepointのサイトIDを調べる方法

Graph APIでSharepointのサイトIDを取得する方法がわからずハマったので備忘録として残しておきます。


# Sharepoint サイトIDとは

GraphAPIでSharepointのサイト内の情報を見る際に必要なIDです。

```
contoso.sharepoint.com,2C712604-1370-44E7-A1F5-426573FDA80A,2D2244C3-251A-49EA-93A8-39E1C3A060FE
```

>サイトは、次の値の複合 ID である一意の識別子によってアドレス指定されます。
>
>- サイト コレクションのホスト名 (contoso.sharepoint.com)
>- サイト コレクションの一意 ID (GUID)
>- サイトの一意 ID (GUID)

参考：https://docs.microsoft.com/ja-jp/graph/api/site-get?view=graph-rest-1.0&tabs=http


# サイトIDの調べかた

APIをたたくだけですが、GraphエクスプローラーというGraphAPI専用のAPIクライアントがあるので、これを使います

【Graphエクスプローラー】
https://developer.microsoft.com/ja-jp/graph/graph-explorer

サンプルも結構あるので、リファレンスがわからん！という場合はサンプルから探した方が早いかもしれません



## ルートからの相対パスで検索

```
https://graph.microsoft.com/v1.0/sites/root:/{path}
```

→https://{tenant}.sharepoint.comにアクセスしたときのサブサイトのみが取得できる？



## キーワードで検索

ルートからの相対パスで検索にてヒットしない場合はキーワードで検索するのが早いです。

```
https://graph.microsoft.com/v1.0/sites?search=contoso
```




# 最後に

キーワードでの検索を知るまでサイトが全然出てこなくてかなり無駄な時間を過ごしてしまいました。
Microsoftのリファレンスの読みづらさはどうにかならないもんか。。。
Ubuntu環境でのMySQLアンインストールについて 

#Ubuntu環境でのMySQLアンインストールについて 
突如以下のエラーでmysqlにログインできなくなってしまった。
色々と試したが結果ダメだったので、特にデータもなかったので、アンインストールを決意。


```
root@ip-10-0-0-31:/var/run/mysqld# mysql -u root -p
Enter password:
ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (111)
```


###Ubuntu環境で完全にアンインストールする方法

以下のコマンドを順に実行する。

```
sudo apt-get remove --purge mysql-server* mysql-common
sudo apt-get autoremove --purge
sudo rm -r /etc/mysql
sudo rm -r /var/lib/mysql
```
【MySQL】はじめてのクエリチューニング vol.1  インデックス作成のメリット・デメリット

インデックス作成のメリット・デメリットについて記します
![mysql.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/322577/1eead5d0-764e-6172-e7c0-521330dfd9ce.jpeg)

## 目次

1. メリット

2. デメリット 

3. インデックス作成の目安

# メリット

### 1.検索（SELECT）が速くなる

特定の行を高速で検索する事が出来ます

JOINの結合条件、WHERE、ORDER BYで指定されているカラムのカーディナリティが高い（値の種類が多い）場合に力を発揮

プライマリーキー（一意キー）の場合は最も効果的

環境によリますが、カーディナリティが高いカラムを指定してインデックスを作成し100000件のデータに検索をかけた場合、処理速度が95%ほど改善されたりします

クエリチューニングに欠かせない複合インデックスについては別記事で
https://qiita.com/okasir4444/items/4024b8152832443fae64

# デメリット

### 1.検索以外の処理が遅くなる

更新・削除・挿入の処理が遅くなります

更新（UPDATE）・・インデックス変更のためのオーバーヘッドが加わる（更新対象カラムが含まれるインデックスのみ）

削除（DELETE）・・インデックス変更のためのオーバーヘッドが加わる（全てのインデックスが対象）

挿入（INSERT）・・更新・削除とちがい、WHERE句の処理もないのでインデックスの恩恵が受けられない&インデックス変更のためのオーバーヘッドが加わる（全てのインデックスが対象）

### 2.データベースの容量を圧迫する

もともとのテーブル以外にインデックスを作成するのでデータ量はおのずと増えてしまう

# インデックス作成の目安
以下が大まかな目安

・絞り込んだ結果のレコード数が全体の5%以下

・レコード数が１万件以上

**メリット・デメリットを意識して、効率のよいインデックスを最小限作成することが大事です**
Xcode Frameworkをマルチプラットフォーム対応する方法

[Neumorphismic](https://qiita.com/MasasaM_shi/items/4b86622bd95fd48deb76)というライブラリを作ったときに悩んだのでメモ。

# 動機
SwiftUIのライブラリなのでマルチプラットフォーム対応させたかった。ちなみに同じSwiftUIとはいえ、`Gesture`系なんかは特にプラットフォームによって使えたり使えなかったりするので`#if os()`は割と多用した。
Swift自体のライブラリならSwiftPMだけで作るべきな気もしますが、よくわかってません。

# やりかた
① `File` -> `New` -> `Target` -> `iOS`(なんでも良いですが) -> `Framework`でとりあえずiOS用のFrameworkを作る
② `Build Settings` -> `Architecture` -> `Supported Platforms`で`Other`を選び、追加したいプラットフォームを追加する。今回はAppleのプラットフォーム全てをカバーしたので以下の通り。
<img width="121" alt="Screen Shot 2020-01-31 at 23.23.31 copy.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186526/c972f633-d04b-6737-20d2-763c221fcd50.png">
`iphoneos`だし`appletvos`だし地味に面白い。
③ `Build Settings` -> `Architecture` -> `Deployment`に追加したOSのサポートするバージョンを書く欄が増えてるので、そこにも記入。今回は以下の通り
<img width="391" alt="Screen Shot 2020-01-31 at 23.26.47 copy.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186526/96ac8b57-961c-e018-0f40-6a28f0cb9148.png">
【PostgreSQL】テーブルのインデックスが壊れた話

# はじめに
サーバーリプレース作業(Windows Server 2008R2 + Oracle 11g → Windows Server 2016 + PostgreSQL 9.6) を一昨年から準備してきまして、全国25箇所を昨年の9月から順次展開中です。

展開して稼働しているところで、インデックスが壊れて更新が出来なくなる現象がありました。
幸い重要度が高くないテーブルだったためユーザー被害は少なかったのですが、重要度が高いテーブルだったら大問題になっていたかと思うとゾッとしました。
データベースを活用したアプリケーションの開発を15年近くしていますが、インデックスが壊れるというのは初めての体験でしたね。

# 仕様
SQLServer側でレプリケーションツールを一定間隔(10分など)で起動し、PostgreSQLのレプリケーション用テーブルを読み込みレプリケーションをしています。
PostgreSQLのレプリケーションテーブルには自動採番のID列があり、インデックスもID列のみになっています。
SQLServerでレプリケーションしたら、PostgreSQLのレプリケーション用テーブルの該当するID列のデータを削除します。

# 障害
レプリケーションがされなくなり、レプリケーション用テーブルの件数が溜まる一方になりました。

## 内容
レプリケーション用テーブルの先頭10件分がSQLServerにレプリケーションされているか確認したところ、正常にレプリケーションが出来ていました。レプリケーションツールの不具合か何かでPostgreSQL側の該当するID列のデータ削除が行われなくなったと推測しました。
データ削除が行われないと同じレプリケーションデータを繰り返す(100件単位)ことになり、SQLServer側では一意制約違反エラーが続くことになる。

# 原因
レプリケーション用テーブルのインデックスの一部が壊れた。

PostgreSQLログには下記が出力されていた。

```
[2020-08-04 15:06:10 JST]   9248[1]   ERROR:  could not truncate file "base/16384/114413907" to 59 blocks: Permission denied
[2020-08-04 15:06:10 JST]   9248[2]   CONTEXT:  automatic vacuum of table "replicate_que"
```

DB接続ツールにて該当するID列のデータを削除しようとDELETE句を実行したのですが削除されません。そこでSELECT句に変更してみると抽出されてきません。しかし、抽出条件を除いて全件SELECTすると該当するID列が抽出されてきます。
ID列以外の更新日時列を抽出条件に指定してSELECTしてみると抽出が出来ます。また、更新日時の1時間分くらいのID列で抽出が出来ず、それ以外の更新日時ならID列で抽出が出来ます。

# 対応
SQLServerにレプリケーションされているデータを確認し、レプリケーション用テーブルを更新日時を抽出条件にしてDELETE句を実行して、正常にレプリケーションがされる状態まで行います。

REINDEXコマンドを使用して、インデックスを再構築する。

## REINDEXによるテーブルロック
上長からREINDEXはテーブルをロックするということで、テーブルをロックしないでインデックスの再構築を行う方法を調査しました。
※PostgreSQL 12では、REINDEXにCONCURRENTLYオプションが追加されたため、下記SQLのようにする必要はありません。

```sql:テーブルロックしないインデックスの再構築
create unique index concurrently pk_replicate_que_new on replicate_que(que_id);

alter table replicate_que drop constraint pk_replicate_que;
alter index pk_replicate_que_new rename to pk_replicate_que;
alter table replicate_que add primary key using index pk_replicate_que;
```

ただ今回のレプリケーションテーブル(replicate_que)を100万件登録してもREINDEXによるインデックスの再構築は2秒以内でした。通常のレプリケーションテーブルの滞在するデータは多くても1万件程度なので、REINDEXによるインデックスの再構築によるテーブルロックはほとんど無視してもいい処理時間 数ミリ以下となります。

結局、テーブルロックしないインデックスの再構築の方法はやめて、REINDEXによるインデックスの再構築のままで対応することになりました。

# 最後に
頻繁に登録・削除が行われるため、インデックスの断片化は高くなるようなので随時監視はしている。しかし高いからといって必ずしも壊れる訳ではない。AUTOVACUUMが稼動すると断片化も下がったりもします。

※インデックスの断片化によりパフォーマンスが悪くなることはあってもインデックスが破損するという記事は見当たりませんでした。

再度発生した時にはバックアップ後にREINDEXコマンドを仕掛けるように検討しようと思います。

```sql:インデックスの断片化の監視
SELECT objectname,ROUND(CAST(app.leaf_fragmentation AS NUMERIC),2)
FROM (
SELECT *, quote_ident(schemaname) || '.' || quote_ident(indexrelname) AS objectname
FROM pg_stat_user_indexes WHERE idx_scan > 100000
) AS t, pgstatindex(objectname::regclass) AS app
WHERE app.leaf_fragmentation <> 'NaN'
ORDER BY round DESC, objectname
```
※pgstatindexを使用するためには、pgstattupleモジュールが必要です。

[2018年度WG3活動報告書 性能トラブル調査編](https://pgecons-sec-tech.github.io/tech-report/html_wg3_performance/wg3_performance.html#30aaf0b03eb9fc31b9982ea109c9d184)

【2020/08/14追記】
1日1回の夜中2:00のバックアップ後にREINDEXコマンドを仕掛けるようにして、3ヶ月経って再度発生しました。それまで数週間〜最長2ヶ月内に1回は発生していたので、抑止効果はありました。
PostgreSQLログに壊れた場合に痕跡が残るので、これを監視してREINDEXコマンド自動的にするような仕組みを作成していく予定です。
ボールをまっすぐ飛ばすための条件

TensorFlowJSのPosenetやCoCoSSDなどを駆使して、ゴルフのAIコーチを作成中です。

今はまだコーチの頭脳を作成中。ゴルフスイングとゴルフゲーム、ゴルフクラブ・ゴルフコースを全て数値化し、個性を見極めてアドバイスしてくれるAIコーチを育成しようと思っています。ここまでにいろいろ技術実践したことは、過去投稿をご覧になってください。

##100名のスイングデータから法則を見出す
およそ１ケ月かけて、TensorFlowJSのPosenetと独自モデルを使って、100名のトッププロの、後方からのアドレスからフィニッシュまでのスイングをデータ化しました。およそ[こんな](https://qiita.com/Chishiki/items/49aa295fec3b3184e046)感じで作った独自モデルを使って、スロー動画を解析しました。

30秒のスローモーションでフレームレートは30fps。1名あたり15部位を約1,000レコードを生成しています。ここから統計理論を駆使して、法則を見出そうとしています。トッププロのスイングを覚えて法則を把握することが、AIコーチ育成の最初の段階と考えています。
![スクリーンショット 2020-01-31 23.01.35.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/74852/8ddf0ef9-4060-0a2a-f5fa-c1fd0b9b7e96.jpeg)


##ひとつ発見！
まず注目してみたのは、後方から見た前傾角度。腰から頭の線を結び、3時の方向を0度として、アドレスからフィニッシュまでの全員の角度を算出し、グラフ化してみました。
![スクリーンショット 2020-01-31 22.41.27.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/74852/3115a2f8-8d78-cd9e-2af4-c0359bbfd0ab.jpeg)

縦軸：角度、横軸：スイング経過時間
![スクリーンショット 2020-01-31 22.44.41.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/74852/ad53a074-97fe-7830-fdb9-ca13ff4914bf.jpeg)
（＊検知能力によって、多少位置ブレが生じています。）

代表としてD・ジョンソンの遷移グラフを載せましたが、100名ともおよそ似たグラフとなります。注目すべきは、一番前傾角度が小さくなる（前傾が深くなる）所。上記グラフで言うと、480コマ目あたり。

さて、その瞬間はスイングで言うとどの姿勢の状態だと思いますか？

答えは、「インパクトの直前」です。100名全員ではありませんが、およそ９０％以上のトッププロは、インパクトの直前で、一番体が沈む、です。そして、全員がアドレスの前傾角度よりもインパクト前後の前傾角度の方が小さい（前傾が深い）です。

まっすぐ遠くへ飛ばそうと力が入る時は、そうなるんですかね。100名のデータを眺めて、最初に発見した法則です。

##ひとりに絞ってデータを取り続けると・・
これをひとりに絞ってデータを取り蓄積すると、良い時・悪い時に、少しの体の動きの違いが分かるのでは、と思ったりしています。

##このデータを使って分析したい方、データを取って欲しいプロゴルファーの方、自分の理論が正しいかをデータで確認したいレッスンプロの方
ご連絡をお待ちしています！

・データ分析したい方
　莫大なデータから統計や傾向理論を駆使・確立出来る方からのアイデアを募っています。

・プロゴルファーの方
　一緒に、あなたのスイングを基準とした、独自のスイング法則・ゴルフ理論を作りましょう！

・レッスンプロの方
　ご自分の理論が正しいか、の検証が出来ます。また当方で確立した理論に口添えして頂きたいです。
SwiftPMでライブラリを作るときにフォルダ構成に悩んだのでメモ

[Neumorphismic](https://qiita.com/MasasaM_shi/items/4b86622bd95fd48deb76)というライブラリにを作ったのですが、フォルダ構成がわからず適当にやった結果一度作り直したのでメモっときます。

参考にしたライブラリ: [Kingfisher](https://github.com/onevcat/Kingfisher)

# やりかた
① ライブラリ本体のXcode Projectを作る
② Demo用のProjectを作る
③ Xcode Workspaceを作ってその中に2つのProjectを放り込む
④ `info.plist`や`Preview Provider`などのPathを修正する
⑤ `Build Phases`->`Copy Bundle Resource`から`info.plist`を削除
⑥ `General`の`identify`を設定し直す
⑦ 後は`Package.swift`をルート階層に持ってくるなど適当に

# ついでに
[Neumorphismic](https://github.com/mcasashi-aso/Neumorphismic/)も一部回収したので是非みてくださると嬉しいです。
Chocolateyでwsl-ubuntu-1804をインストール

会社のポリシーなどで、Windows Storeが使えない場合、WSLを手動でダウンロードしてインストール
することになります。

次のURLがそのやり方：
[https://docs.microsoft.com/en-us/windows/wsl/install-manual](https://docs.microsoft.com/en-us/windows/wsl/install-manual)

これでもいいのですが、Chocolateyでやってみたらどうなるかと試してみたら、思いのほか深みにはまって苦戦したので、参考まで。


# 事前準備
## Windows Subsystem for Linuxを有効化する
「コントロールパネル>すべてのコントロールパネル>プログラムと機能」を開きます。
左側にある「Windowsの機能の有効化または無効化」メニューをクリック。
「Windowsの機能」ダイアログが開くので、ここを下にスクロールしていき、
「Windows Subsystem for Linux」チェックボックスをON。


# Chocolateyをインストール
## Chocolateyのインストールの参考URL

[https://chocolatey.org/install](https://chocolatey.org/install)

## インストール
PowerShellを管理者で開いて次のコマンドでchocolateyをインストール。

``` PowerShell:
Set-ExecutionPolicy Bypass -Scope Process -Force; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))
```

# Chocolateyでubuntuのインストール
途中Yes/Noを聞かれるので、"Yes"で答える。

``` PowerShell:
choco install wsl-ubuntu-1804
```


# ubuntuインストールフォルダに自分自身をフルアクセスでアクセス許可をつける
エクスプローラで「```C:\programdata\chocolatey\lib\wsl-ubuntu-1804```」フォルダを右クリックして、「プロパティ」を表示します。
「セキュリティ」タブ「編集(E)...」ボタンをクリック。
「アクセス許可」ダイアログが表示されるので、「追加(D)...」ボタンをクリック。
「ユーザまたはグループの選択」ダイアログが表示されるので、「選択するオブジェクト名を入力してください(E):」テキストエリアに、現在利用しているWindowsの自分自身のユーザIDを入力して、「名前の確認(C)」ボタンをクリック。
「OK」ボタンで戻る。
「アクセス許可(P)」で「フルコントロール」チェックボックスをON。
あとは「OK」ボタンで戻っていく。

<b><font color="red">※思いのほかはまったところ：
このフォルダにアクセス許可をつけるのがすごく大事。これをしておかないと、インストール後にwsl(bash)プロンプトを起動するとエラーで起動できないです。
PowerShellプロンプト(もしくは、コマンドプロンプト)を管理者で起動して、そこでwsl(もしくはbash)を起動すれば、起動しますので、おそらくこのフォルダに書き込みをしにくためだと思われます。
Administratorsにフルアクセスのチェックがついているので、自分自身のユーザIDがAdministratorsに参加していればOKかと思ったが、ダメみたいです。自分自身を設定したらうまくいきました。
</font></b>


# wsl(もしくはbash)プロンプトを開き、sudo用一般ユーザを作る
PowerShellプロンプトで、wsl(もしくはbash)を入力して「Enter」キーを押下します。

```PowerShell:
PS> wsl
```

rootでプロンプトが開きますので、ユーザを追加、sudoグループに追加します。

```bash:
root@mypc:~# adduser myuser
root@mypc:~# gpasswd -a myuser sudo
```

Uid/Gidが恐らくどちらも10進数の1000で作られるはずです。

# wslコマンドやbashコマンドを叩いた時のデフォルトユーザを上記で追加したユーザにします
ubuntuをインストールした先のフォルダにubuntu1804.exeがありますので、これを利用してデフォルトユーザを指定します。
これをしておかないと、wslやbashプロンプトを起動すると毎回rootで起動してしまいます。

```PowerShell:
PS C:\programdata\chocolatey\lib\wsl-ubuntu-1804\tools\unzipped> ./ubuntu1804 config --default-user myuser
```

## もし、このubuntu1804.exe config --default-userコマンドがエラーで失敗した場合
レジストリを先のUid/Gid(1000/1000)で登録します。

```
コンピューター\HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Lxss
```

```
DefaultGid REG_DWORD 1000(10進数)
DefaultUid REG_DWORD 1000(10進数)
```

# wsl(もしくは、bash)プロンプトを起動
Windowsキー+Rキーで「ファイル名を指定して実行」ダイアログを表示し、"wsl(もしくは、bash)"と入力して「Enter」キーを押下します。
すると、wsl(もしくは、bash)プロンプトが、先の一般ユーザ(myuser)で起動します。
基本情報技術者　テクノロジ系　第8章 システム開発技術③



# オブジェクト指向

データと処理をひとまとまりにして考えます。

## オブジェクト指向の概念

### オブジェクト
データとメソッドをまとめたもの

### メソッド
処理
### カプセル化
オブジェクト化(データとメソッドをまとめる)すること
### 情報隠蔽
メソッドのみデータにアクセスできるようにすること
### クラス
オブジェクトの型
### インスタンス
クラスより出来上がったもの

## クラス間の関係

### 1.集約-分解関係
全体と部分の関係

### 2.凡化-特化関係
親子の上下関係
### 3.スーパークラス、親クラス、基底クラス
2.の上位クラス
### 4.サブクラス、小クラス、派生クラス
2.の下位クラス
### 5.インヘリタンス
上位クラスが下位クラスを引き継ぐこと
### 6.ポリモルフィズム,多様性
メソッド同じでもオブジェクトごとに異なる動作を行うこと。

## インヘリタンス(継承)
上位から下位へクラスを引き継ぐため
差分プログラミングするだけで、内容を多様化できる。

## オーバーライド(上書き)とポリモルフィズム
インヘリタンスの際に、上位の内容で修正した内容でやりたい場合
下位でオーバーライド(上書き)を行う。

またメソッド(処理)が同じでも
元のクラスが違う場合
結果が異なるのをポリモルフィズムといいます。

例: 計算
計算メソッド呼び出しで

掛け算クラス
割り算クラスだとそれぞれ結果が異なります。

## UML
オブジェクト指向による、システム分析・設計に用いる図法です。

### ユースケース図
ユーザーから見て、システムがどのように機能するかを表す図です。

### クラス図
クラス間の関係を表す図です。

### シーケンス図
オブジェクト(インスタンス)間のやりとりを時系列で表す図です。
JavaScript: Math.random() でランダムな数値を作る

Math.random() を使うと、0以上、1未満のランダム値を生成する。つまり、0.1とか、0.9とか。
Math.random() * 3 とすると、0から2までのランダム値、例えば1.4とかにすることができる。
小数点以下がいらない場合、Math.floorで囲んであげる。
Math.floor(Math.random() * 3) という感じ。
Cloud Build で docker-compose を使う

プロジェクト作成済みで Cloud SDK でログインしてる前提。

### docker-compose のイメージを GCR に push 
```
$ git clone git@github.com:GoogleCloudPlatform/cloud-builders-community.git 
```
```
$ cd cloud-builders-community/docker-compose/
```
```
$ gcloud builds submit --project <PROJECT_ID> --config=./cloudbuild.yaml
```

### cloudbuild.yaml で使う
``` cloudbuild.yaml
steps:
  - id: docker-compose-up
    name: gcr.io/$PROJECT_ID/docker-compose
    args: [
      'up',
      '-d'
    ]
```
Amazonの注文メールから正規表現で商品リンクを抜き出す

ZapierでAmazonの注文メールから商品リンクを抜き出したいケースがあった。正規表現を使って商品リンクだけ抜き出したかったが、Python Regular Expression というPython特有の正規表現だったので苦戦したのでメモ。

## 作成した正規表現
```
(https?://www\.amazon\.co\.jp/gp/r\.html\?[\w.-?/%&=:]+_TE_item_image)
```
注文メールのHTML本文には`https://www.amazon.co.jp/gp/r.html?`で始まるURLが複数ある。そこで最後に`_TE_item_image`が付いているURLだけ抽出してやればOKだった。

##正規表現を作成する方法
うまく想定したパターンがマッチしなかったり、正規表現ジェネレータなどでもうまくいかないときはVSCodeなどのエディターの検索機能で1個ずつ必要な正規表現を追加していき、マッチ範囲が伸びていくのを確認しながら作成するのがおすすめ。
<img width="1195" alt="スクリーンショット 2020-03-20 15.32.16.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242610/9cd98a53-5d84-a6a0-5115-f76957678b19.png">

正規表現検索モードである`.*`をオンにし、`<td class="name"([\s\w=":(]*)`のように`[]*`に正規表現を増やしていく。気になるのは`-`の後に`>`を持ってくるとマッチしないことだ。ハイフンは特に正規表現での特殊な意味はなかったと思うのだが、詳しい方がいたら教えて欲しく。

```

<td class="name"([\s\w></.?&%=":(,);-]*)> ([\w\W]*) </a> <br /> ([\W\w]*) <br /> 販売
```

##基本的な正規表現

```
\   直後の文字をエスケープ。ただし[]の中ではこれをかかなくても.や？はエスケープされるよう
.   任意の一文字
?   直前の文字もしくはグループが0個か1個。つまりhttpでもマッチするようs?とする
()  グループ。これでくくれば1文字として扱われる。(aaa)?は何もないか、aaaになる。
[]　呼び方不明。この角括弧に含まれるいずれか１文字にマッチ
\w  [0-9A-Za-z_] と同じ意味。半角英数字とアンダーバーにマッチ
*   直前の文字が 0回以上 繰り返す場合にマッチ
+   直前の文字が １回以上 繰り返す場合にマッチ
```

[Zapierの公式ヘルプ](https://zapier.com/help/create/format/find-text-with-regex-in-zaps)によると Extract Pattern でテキストを抽出するには`()`で囲んでやらねばならない。
> In order to have this step return text in its output, you must include a capture group in your regex.

実際のリンク先で最終的にリダイレクトされる商品URLは途中の`&T=C&U=`以降にクエリーとして付与されている（ただし`http://`でSSL化されていない）ようだったので、更に Extract URL の処理をかませて欲しいURLを抽出した。

##参考リンク
- https://developers.google.com/edu/python/regular-expressions
- https://www.ipentec.com/document/regularexpression-url-detect
セグメント木を使って配列からn番目に小さい数をO(logN)で取得する

# この記事は何？
数字の追加や削除が行われる集合から高速にk番目に小さい数を得る手法としてセグメント木の利用が考えられる。最初この解説がうまく理解できなかったのでdumpする。

# 前提となる知識
セグメント木を用いたRSQ。以下がとても分かりやすい。RMQの解説だが、考え方は95%くらいMinでもSumでも一緒。
https://www.creativ.xyz/segment-tree-entrance-999/

RSQ自身はk番目に小さい値を取得ことを目的とするデータ構造ではないが、RSQを用いることでこれが高速に実現できる。

# 解きたい問題
[ARC033C:データ構造](https://arc033.contest.atcoder.jp/tasks/arc033_3)

- 数の集合 S に対する以下のクエリを処理してください。
    - タイプ 1 ： `S に数 X を追加する。`
    - タイプ 2 ： `S に含まれる数のうち X 番目に小さい数を答え、その数を S から削除する。`
- 制約: 1 <= N, <= 200,000
- ポイント1: Sに同じ数は追加されない

# ポイント
Nが比較的小さな値であること。
この制約は、$len(N)$のセグメントツリーを作る際のメモリ制約と初期化に際してO(N)が必ずかかってしまう制約のためである。

#  セグメントツリー RSQ の二分探索
例として $[2, 3, 5, 7]$の中から3番目に小さい数字を得ることを考える。

まず、セグメントツリーに各数字の$index$を$1$として値をセットする。（図の四角内)
クエリRSQ $[0, i)$ を考えると、箱の下にある値のようになる。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30938/1d57ff71-2f0d-c3d1-40f4-14ac35e57e1a.png" width=50%>

これをみるとクエリ$[0,i)$ = kとなる最初の(最左の)iが、得たい値(k番目に小さい数)であることが分かる。

最左のクエリ$[0,i)$ = kを満たす$i$が得られれば、iのindexがそのまま得たい値であることは自明である。
以降ではこの手法を考える。

# 手法1： クエリを2分探索で実行し、最左のkを求める O(log^2 N)
まず、ARC033の解説でも述べられている手法が考えられる。

RSQにかかる計算量は高々O(logN)であることを利用し、クエリ[0,N)から始めクエリ[0,mid)のように二分探索を行っていき、最左のインデックスを得ることが現実的である。

この手法ではRSQの計算量$O(logN)$に対して二分探索の計算量$O(logN)$がかかるため、全体として$O(log^2N)$となる。

```Python
def segmentTreeBisectLeft(segTreeTarget: segmentTreeSum, x):
    lo, hi = 0, st.lenOriginalList
    while lo < hi:
        mid = (lo+hi)//2
        if segTreeTarget.query(0, mid + 1) < x: lo = mid + 1 # ここでRSQ[0,mid)のクエリ
        else: hi = mid
    return lo
```


# 手法2： セグメント木を2分探索で掘り、最左のkを求める O(log N)
ここでセグメントツリーの木構造を使ってノードn配下で管理している最小のxを探索するfind(x, n)を考える。
次に先ほどの入力例を用いて、3番目に小さい数を知りたいとした場合の動作を示し、それぞれの動作を述べる。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30938/082e9a6b-c966-8f88-1ffb-66774a5d97c2.png" width=50%>

- 1: 入力はルートノード0に対して行う(find(3, 0)
- 2: 左ノード1にfind(3, 1)を渡す
- 3: ノードは受け取ったxよりも自分の値が小さい場合、ノードの値を差し引き、親に返す。例では、x=3から自身の2を引いた1をノード0に返す。これは、x番目に小さい数を求めたいのに、自分の配下にはx-aのノードしか管理していないのであれば、自分の配下に求めたいノードは存在しないからである。
- 4: ルートノード0は左のノード1から1が帰ってきたので、その値を用いて右のノード2に対してfind(1, 2)を送る。
- 5. ノード2は左のノード5にfind(1,5)を送る。
- 6. ノード5は左のノード11にfind(1, 11)を送る。この葉には値が存在しないため、Noneを返す。
- 7. ノード5は左のノード11にfind(1, 12)を送る。
- 8: この葉はxと一致する。これにより、index = 5をreturnする。
これにより、この関数はk番目に小さい値が5であることを求められた。

```Python
def findNthValueSub(self, x, nodeId):
    """
    [2, 3, 5, 7] = [0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0]
    とマッピングされているセグメント木においてx番目に小さい値を得るための関数
    """
    # ここから先は葉ではないノードへの処理
    if self.dat[nodeId] < x: # このノードが要求されているよりも小さい値しか持たないとき
        return (None, x - self.dat[nodeId])
    if nodeId >= self.lenTreeList - 1: # nodeIfがノードのときは
        return (True, nodeId - (self.lenTreeList - 1)) # そのindex番号を返す
    resLeft = self.findNthValueSub(x, 2 * nodeId + 1) # 左側の探索を行う
    if resLeft[0] != None: # もし、値が入っているならそれを返す
        return (True, resLeft[1])
    resRight = self.findNthValueSub(resLeft[1], 2 * nodeId + 2) #右側の探索を行う
    return resRight
```

# 詳細な説明
https://www.slideshare.net/chokudai/arc033
https://ei1333.hateblo.jp/entry/2017/12/14/000000

# 全体のソースコード
https://github.com/recuraki/PythonJunkTest/blob/master/atcoder/lib/treeSegment/segmentTreeSum.py
Google API 復習 ①地図の表示

 今回ポートフォリオとして、非常時の避難先を登録するアプリケーションを作成し、以下4種類のGoogle APIを使用しました。

-Google Maps Javascript API
-Geocoding API
-Elevation API
-Distance Matrix API

かなりボリュームがあるので、小出しにして、記事にしたいと思います。初めて投稿するので、間違っている箇所がありましたら、ご指摘いただけると幸いです。＊APIを使用する為の準備については、有益な記事が複数ありました。下記に参考記事を記載します。

それでは本題に入ります。
第１部は、**地図の表示**についてです。
スクロール１回で終わります（笑）

まずビューに地図を表示させるために、idをmapとし、styleタグで領域を設定します。

      <div id="map" style="height: 400px; width: 600px;></div>
JavaScriptにはhtmlの要素を操作できる、**DOM(Document Object Model)**という仕組みがあり、以下の記述でid、mapの領域に予約を入れ、前述のオプションを適用する事で、地図が表示できます。オプションについては、好みに合わせてカスタマイズする事が出来ます。*zoom:解像度 center:中心地点 mapTypeId:地図タイプ
    
      var getMap = (function() {                         
        var getMap = (function() {
          function codeAddress(address) {// 地図表示に関するオプション
          var mapOptions = {
            zoom: 16,
            center: { lat: 35.662, lng: 139.703 },
            mapTypeId: "roadmap"
          };// 地図を表示させるインスタンスを生成
          var map = new google.maps.Map(document.getElementById("map"), mapOptions);
          console.log(map); …続く

          )};
        )};
      )};
最後にconsole.logで出力する事で、このように渋谷周辺を表示する事が出来ました。
<img width="616" alt="スクリーンショット 2020-01-31 21.57.47.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510265/a9b9913e-aded-910e-dac3-af443a1f65c3.png">

[以下参考記事]
[Rails5でGoogleMapを表示してみるまで](https://qiita.com/tiara/items/4a1c98418917a0e74cbb
)
[Google Maps Javascript API Reference](https://developers.google.com/maps/documentation/javascript/tutorial?hl=ja)
[ドットインストール / Google Maps API入門（無料)](https://dotinstall.com/lessons/basic_google_maps_v2)
[Javascript初心者向け / DOMとは？](https://eng-entrance.com/what-is-dom)
background-imageの取り扱い一覧

HTML、CSSでdivを作成して、そのdivの背景にimageを入れたいときってありますよね。

でも、ぴったりサイズの画像だったら良いんですが、、、

大体の場合は全くぴったりじゃなくて、表示させてい部分そこじゃないよ！ アップ過ぎるよ！ ズームインしすぎだよ！って時の方が多いですよね。。

例えば、この画像。

![pets-4415649_640.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/161691/26a03869-eadc-54bf-1c32-e0a83b3ab93f.jpeg)
[pixabay](https://pixabay.com/ja/photos/%E3%83%9A%E3%83%83%E3%83%88-%E7%8A%AC-%E3%82%B3%E3%83%BC%E3%82%AE%E3%83%BC-%E3%81%8B%E3%82%8F%E3%81%84%E3%81%84-4415649/)

小さいdivの背景にしてしまうと、、、

![pets-4415649_1920.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/161691/08af4eef-b948-dedb-5c73-835328d7f891.jpeg)


こんな感じになっちゃったり、、

いや、もふもふ度はわかるけども、、


そんな時にどうやったら、上手に背景画像として表示できるのかをまとめました。


##background-repeat

まず画像をリピートしたい時。もしくは、したくない時。

したくない時は

```CSS:
background-repeat: no-repeat;

```

したい時は

```css:

/* default設定。左右上下にリピート */
background-repeat: repeat;

/* 左右にリピート */
background-repeat: repeat-x;

/* 上下にリピート */
background-repeat: repeat-y;

```



##background-color


背景が透過の小さい画像をrepeatさせるときなどは、背景色も変えたいですよね。
そんな時は、background-colorも併用できちゃいます。

```CSS:

background-color: black;
background-image: url(backgroundimage.png);

```

これで、黒ベースの背景に、backgroundimage.pngという画像がrepeatされることになります。



##background-position

今度は、背景画像の表示開始位置を指定する時に使います。
単純に、right, center, topでの指定や、ピクセル、パーセンテージでの指定ができます。

```HTML:

//右下が表示開始位置
background-position: right bottom;

//表示される領域の左端から20%、上端から40%の位置が背景画像の表示開始位置
background-position: 20% 40%; 

//左上から20px、下に40pxの位置が表示開始位置
background-position: 20px 40px; 

```

##background-size

こちらは、自動的に画像のサイズを調整してくれる優れもの。
分かりやすかったbackground-sizeの記事。from はにはまんさん
https://haniwaman.com/background/

まとめると大きく3種類
- 要素が確実に覆われけど、画像の全体表示とは限らない『cover』
- 大きさが変わらない、ありのままを表示する『auto』
- 画像全体は表示させるが、要素を覆うとは限らない『contain』
- 背景の幅・高さをpxや%で指定する


まぁよく使うのは、下記。

```CSS:

background-size: cover;

```

ちなみにmin-height: 100vh;と記載すると、画面いっぱいの高さで表示してくれるみたい。


##background-attachment

たまにオシャレなWEBサイトで、背景画像を固定しているものとかありますよね。下にスクロールしていっても、背景は動かずそのまま、みたいな。

たかふみさんのDEMOサイト
https://takafumimegumi.com/demo/background-attachment/index.html
たかふみさんの解説
https://takafumimegumi.com/blog/background-attachment

オシャレかよ。

やり方は、単純に

```CSS:

background-attachment: fixed;

```
ってすれば良いみたい。





##「番外編」画像の上にグラデーションをかける


最後に、番外編で画像の上にグラデーションをかける技。


```

background: linear-gradient(to top, rgba(217, 175, 217, 0.7) 0%, rgba(151, 217, 225, 0.7) 100%), url(image.png);
```

グラデーションの詳しい掛け方
https://www.sejuku.net/blog/53162

グラデーションをかけるツール
https://www.indetail.co.jp/blog/css3-gradation/


とまぁこんな感じで、まとめ終了。
Vagrant 2.2.6 + Virtualbox 6.0.14からVagrant2.2.7  + Virtualbox 6.1.2にアップデートしたときのメモ

## 結論
* 起動にエラーが出た
* `vagrant plugin list`でインストールされているプラグインを確認
* `vagrant plugin install vagrant-vbguest`と`vagrant plugin install vagrant-disksize`を行い、プラグインを更新
* `vagrant up`で再起動。エラーが出た
* `vagrant destroy -f`で消す
* `vagrant up`で再起動。エラーが出た
* `vagrant destroy -f`の後にも`.vagrant`ファイルが残っていた。これを消す。
* `vagrant up`。立ち上がった。

## 備考

* OSはubuntu 18.4 LTS 20200130.1.0


[[Mac] Vagrant 2.2.6 と Virtualbox 6.1でうまくvagrant up ができなかった時の対処法](https://qiita.com/shuu1222/items/7a6d04172363be44025c)のような、
ファイルを書き換えるようなことはしなかった。
Djangoで複数のテンプレートをまとめて1つにしたい

# Djangoで複数のテンプレートをまとめたい

Django入門とかでよく出てくる{% extends 'hoge.html' %}だと１つしか継承できず、もっとパラメータの条件分岐で表示するテンプレを変えたい！って時に困ったので調査した。

# 結論

```
{% include 'hoge.html' %}
```
DjangoというよりテンプレエンジンのJinjaのやり方らしい
https://jinja.palletsprojects.com/en/2.10.x/templates/#include
Hello Qiita【初投稿】

#自己紹介
現職ではEC関連プロダクトの開発企画・サポートをしています。
PdMとかPjMといわれるような企画・開発から、ユーザーへの導入をサポートするテクニカルサポート的なことまで、幅広くやっています。

日常的にコーディングしていたのは社会人になって最初の数年だけで、現食でコードを書くのはマクロのメンテナンスくらいです。
会社という組織というなかで仕事をする文にはそれでも困らないのですが、実装ができる・理解できるというのはエンジニアと仕事をするうえで重要だと感じますし、**何より楽しい。**

ということで、コードを書く・何かをつくるということについて、少し前から学びなおしをはじめました。
自分なりに学んだことをまとめてはいたのですが、せっかくなのでQiitaに少しずつ投稿してアウトプットとしていきたいと思っています。

どうぞよろしくお願いします。
AnimationClip再生終了後に呼ばれるイベントを設定するスクリプト

ちょっとした動作確認の時などに用意してあるとちゃちゃっと設定できて便利なのですが、
いざ実装してみようとした所ちゃちゃっと終わらなかったので、備忘録として残しておきます。

## AnimationFinishedEventTrigger.cs
```
using UnityEngine;
using UnityEngine.Events;

[RequireComponent(typeof(Animation))]
public class AnimationFinishedEventTrigger : MonoBehaviour
{
    [SerializeField] private UnityEvent onFinished = null;
    Animation selfAnimation;

    private void Start()
    {
        selfAnimation = GetComponent<Animation>();

        var animationEvent = new AnimationEvent
        {
            functionName = "OnFinished",
            time = selfAnimation.clip.length
        };
        selfAnimation.clip.AddEvent(animationEvent);
    }

    public void OnFinished()
    {
        if (onFinished != null) onFinished.Invoke();
    }
}
```

## 使い方
上記のコンポーネントをAnimationが付いているGameObjectに追加して、
呼び出したいメソッドをインスペクタから設定するだけです。
※uGUIのButton等と同じ要領
![キャプチャ.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153804/089f23c5-fe7c-1344-1759-34a23e061501.jpeg)
【Android Studio】【Java】ボタンによる画面遷移

あくまでも自分用のmemoとして残しておきます。
#必要なファイル（全4つ）
・MainActivity.java
・activity_main.xml
・SubActivity.java
・activity_sub.xml 

#MainActivity.javaのソースコード
17~24行目を追加

<img width="936" alt="スクリーンショット 2020-01-31 21.56.09.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317272/9d50bffc-198a-9074-a1dd-e34af5dd13f5.png">

```
Button nextButton = findViewById(R.id.bt_next);
nextButton.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        Intent intent = new Intent(getApplication(),SubActivity.class);
        startActivity(intent);
    }
});
```
#SubActivity.javaのソースコード
16~22行目を追加

<img width="936" alt="スクリーンショット 2020-01-31 21.56.46.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317272/01893d41-21e3-537e-e06c-9ac4773320d2.png">

```
Button backButton = findViewById(R.id.bt_back);
backButton.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        finish();
    }
});
```

#activity.xml(デザインタブ)
画面右上のidに注意！

<img width="936" alt="スクリーンショット 2020-01-31 21.57.19.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317272/70a34239-d6cc-e514-f08f-eace22a590a9.png">


#activity_sub.xml(デザインタブ)
画面右上のidに注意！

<img width="936" alt="スクリーンショット 2020-01-31 21.57.29.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317272/665637c4-fd97-48e8-7a42-bf28130209d2.png">
Progateでの学びを断片的に落としていく【バリデーションの構築】

#バリデーションを構築していく
##バリデーションの文法
空のデータを制限する

```ruby:アプリ名/app/models/該当ファイル.rb
validates :カラム名,{presence: true}
```

文字数を制限する

```ruby:アプリ名/app/models/該当ファイル.rb
validates :カラム名,{length:{maximum: 制限したい文字数を半角で}}
```

列記することもできる

```ruby:アプリ名/app/models/該当ファイル.rb
validates :カラム名,{presence: true , length:{maximum: 制限したい文字数を半角で}}
```

##どこに記述するか
`アプリ名/app/models/該当ファイル.rb`。
Progate道場コースⅡまで進めて、modelディレクトリ内を触ったのはこれくらいじゃないか…。
今回は、投稿編集の類のバリデーションだったので、`app/models/post.rb`。
RubyでPaizaの問題を解く時役立ちそうなヒント(?)

#概要
プログラミング学習の一環としてPaizaのスキルチェックを利用しているなかで、よく使用するが忘れがちなコードのメモ。
どんどん追加していきます。

#Arrayクラス
###値をスペース区切りで出力する

```ruby:
puts array.join(" ")
```
参考:[【Ruby】配列の要素を半角スペース区切りで出力する](https://qiita.com/hirym/items/a44aad56b680fb4fccde "【Ruby】配列の要素を半角スペース区切りで出力する")

###配列の配列で、配列1つにつき1行で出力

```ruby
ary = [[1,2,3],[4,5,6],[7,8,9]]
ary.each do |i|
 puts i.join(" ")
end
```

#Hashクラス
###valueの値で降順にソートする

```ruby:
hash = hash.sort_by{|key,value| -value}
```

#値の操作
###数値から文字列を取得

```ruby:
数値.abs
```

参考: [Rubyで数値から絶対値を求める方法【初心者向け】](https://techacademy.jp/magazine/19246"Rubyで数値から絶対値を求める方法【初心者向け】")


###数値を文字列に変換

```ruby:
数値.to_s
```

###小数点以下の操作

```ruby:
数値.to_f #表示
```
```ruby:
数値.floor #切り捨て
```
```ruby:
数値.round #四捨五入
数値.round(1) #（）で桁数の指定。整数部分の四捨五入をする場合は負の数を指定する。
```
参考: [Rubyで数値の切り捨て・切り上げ・四捨五入する](https://uxmilk.jp/43388"Rubyで数値の切り捨て・切り上げ・四捨五入する")
Flask-SQLAlchemyでSQLiteを使用したときに外部キー制約を順守させる方法

　外部キー制約に反した時にエラーを吐くようにする方法を探していた。
　結論：~~(見当たら)ない。諦めてコード側で守る。~~
　　　　接続するたびにPRAGMA foreign_keysをONにする。コード参照。
　**@tiechel様ありがとうございます。**
#検証方法
###環境
　Python ~~3.7~~ 3.8
　Flask-SQLAlchemy ~~v2.4.1~~ v2.4.4
　
#失敗例
###2つのテーブルを作成する。

```Model.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///./tmp/test.db'
db = SQLAlchemy(app)

class Person(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(50), nullable=False)
    addresses = db.relationship('Address', backref='person', lazy=True)


class Address(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    email = db.Column(db.String(120), nullable=False)
    person_id = db.Column(db.Integer, db.ForeignKey('person.id'),
                                nullable=False)
```
　https://flask-sqlalchemy.palletsprojects.com/en/2.x/quickstart/
　https://flask-sqlalchemy.palletsprojects.com/en/2.x/models/ より

###出来上がるテーブル

```test.db
CREATE TABLE "person" (
	"id"	INTEGER NOT NULL,
	"name"	VARCHAR(50) NOT NULL,
	PRIMARY KEY("id")
);

CREATE TABLE "address" (
	"id"	INTEGER NOT NULL,
	"email"	VARCHAR(120) NOT NULL,
	"person_id"	INTEGER NOT NULL,
	PRIMARY KEY("id"),
	FOREIGN KEY("person_id") REFERENCES "person"("id")
);
```

###テストを行う

```test.py
import unittest

def testForeignKey(self):
    db.create_all()
    db.session.add(db.Address(id=0, email="aaa", person_id=111))
    db.session.commit()
    
    
if __name__ == '__main__':
    unittest.main()
```

　test.dbを覗いて新しいレコードが追加されていることを確認する。
　
#外部キー制約に反した時にエラーを吐くようにする方法
###Model.pyを更新する
```Model.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy

# ---------変更点---------
import sqlalchemy.engine
from sqlalchemy import event
# ---------変更点---------

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///./tmp/test.db'
db = SQLAlchemy(app)


# ---------変更点---------
@event.listens_for(sqlalchemy.engine.Engine, "connect")
def set_sqlite_pragma(dbapi_connection, connection_record):
    cursor = dbapi_connection.cursor()
    cursor.execute("PRAGMA foreign_keys = ON")
    cursor.close()
# ---------変更点---------

class Person(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(50), nullable=False)
    addresses = db.relationship('Address', backref='person', lazy=True)


class Address(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    email = db.Column(db.String(120), nullable=False)
    person_id = db.Column(db.Integer, db.ForeignKey('person.id'),
                                nullable=False)
```

同じようにテストを行うとFOREIGN KEY constraint failedを吐く。
set_sqlite_pragmaはデコレーター(@event.listens_for)で接続の度に勝手に実行されるので自分で呼び出す必要はありません。

###外部キーがデフォルトで有効になっていない理由
　SQLite v3.6.19まで外部キー制約が機能していなかったようです。
　https://www.sqlite.org/foreignkeys.html#fk_enable

###PRAGMAについて
　SQLiteに特殊な要求を行うコマンド。今回は外部キー制約をONにするために使用している。

　~~テストを変更させずにエラーを吐かせる方法をご存じの方がいらっしゃいましたらご教授ください。~~
　**@tiechel様、本当にありがとうございました。**
Firestoreのバックアップを手動で取ってみよう

こんばんは。PrAha Inc.のCEO兼エンジニアの[dowanna](https://twitter.com/dowanna6)です。

## Firestoreのバックアップを取りたい
Firestoreにバッチ更新をかましたり、マイグレーションしたいときがありますよね。
万が一データを吹き飛ばした時に備えて、基本的にはFirestoreAPIを叩く自動スクリプト等で定期的にバックアップを取っておくわけですが、時には緊急対応のため、手動バックアップを取得したいときがありますよね。

というわけで今日は手動バックアップの取り方をば。

## 手順
- GCP上にCloud storageバケットを作成する
- Cloud shell起動
- プロジェクトを選択
- FirestoreのバックアップをExport
- ロールバックするときはImport
- 注意点

### GCP上にCloud storageバケットを作成する
まずはGCPの[Cloud storage](https://cloud.google.com/storage/)へ。適当にバケットを作成し、バケットidを控えておきます


### Cloud shell起動
GCPコンソールの画面右上にこんなアイコンが見えるはずです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246648/a34d09a4-8ef1-4ac8-af23-70db6e7b2175.png)

左下の「Cloud shell」アイコンをタップして、シェルを起動しましょう

### プロジェクトを選択
起動したシェルにこんなコマンドを打ち込んでみましょう。

```
gcloud config get-value project
```

これで現在シェルに使われているプロジェクトが分かります。
今のFirebaseはプロジェクトを作成すると裏側でGCPのプロジェクトも作成しているため、FirebaseのprojectIdは、そのままGCPでも使えます。

もし別のprojectを選択する場合は、このコマンドで指定しましょう。

```
gcloud config set project [PROJECT_ID]
```


### FirestoreのバックアップをExport
さて、Firestoreのバックアップを取りましょう。

```
gcloud firestore export gs://[STORAGE_ID]/
```

storage-idには、先ほど控えたCloud storageのidを入力してください。
それ以降に何も指定しなければ、タイムスタンプを使ったディレクトリが作成されて、その配下にバックアップが保存されます。
何もオプションを与えなければ、これだけで全てのサブコレクションも含めてバックアップが取得されます。

これでFirestoreの手動バックアップ完了です。めちゃくちゃ簡単でしたね。

### ロールバックするときはImport

もし何かバッチ処理やマイグレーションにしくじった場合は、こんなコマンドでロールバックできます。

```
gcloud firestore import gs://[STORAGE_ID]/[BUCKET_ID]
gcloud firestore import gs://hogehoge-project-id/2020-01-31T07:12:30_55688 // 例えばこんな感じ
```

ロールバックも簡単ですね！Firestore有難い！

### 注意点
ただしFirestoreのバックアップにはいくつか注意点があります。

##### バックアップ時の状態が完全に再現されるわけではない
FirestoreのexportはDocIdを保持し、そのDocIdを使って、更新対象を探します。
同じDocIdを持つドキュメントはバックアップデータに上書きされます。

裏を返すとexport後に新規作成したDocは、バックアップデータをimportした場合も残り続けます。

つまり、バックアップ時の状態が再現されるわけではありません。
例えばバックアップ後にゴミデータを作ってしまった場合、そのゴミデータはimport後も残り続けます。
なのでバックアップを取得する前にFirestoreへの本番アクセスを遮断しておくなど、ゴミの発生を予防しておきましょう。

##### Indexはexportファイルに含まれない
exportファイルにはindexが含まれないので、importするFirestoreプロジェクトのindex状態に依存します。バックアップ後にindexを変更/削除した場合は注意が必要です。

##### exportファイルは読みにくい
直接読む事はほぼ無いかと思いますが、exportされたファイルはutf8-LEでエンコードされていたり、なぜかlatin-1でエンコードされているので、無邪気に開こうとすると文字化けします。

例えばvimなら、exportファイルを開いた後に

```
:set fenc?
```

でエンコードを確認したり、iconv等でエンコードを変更する一手間がかかります。（変換しても化けてる事があるけど...）

```
iconv -f UTF-16LE -t UTF-8 [filename] > [new-filename]
```

それを回避するための[npmパッケージ](https://www.npmjs.com/package/node-firestore-import-export)が用意されているので、読みやすい形式（jsonとか）を希望する場合は、使ってみても良いかも。

##### CollectionIdを指定しないとBigQueryで読み込めない
```
gcloud firestore export gs://[STORAGE_ID]/
```

こんな感じで全てのサブコレクションも含めてexportしたバックアップは、BigQueryで読み込めません。

```
gcloud firestore import gs://[BUCKET_NAME]/ --collection-ids=[COLLECTION_ID_1],[COLLECTION_ID_2]
```

--collection-idsフラグを使ってコレクションを指定する必要があるみたいです。


### Firestoreの公式ドキュメント
[こちら](https://firebase.google.com/docs/firestore/manage-data/export-import)
.bashrcを設定する方法

#.bashrcを作成する方法
ホームディレクトリで以下のコマンドを実行する。＊ホームディレクトリでないと実行できない
```touch ~/.bashrc
```
ホームディレクトリへ移動するには以下のコマンドを実行する。
```cd ~
```
.bashrcへの書き込み
echo "記載内容" > ファイル名

.bashrcでパスを通す
```export PATH=/Applications/MAMP/bin/php/php7.3.1/bin:$PATH 
```

通したパスを反映させる
```source ~/.bashrc```
Java(clear)

【clear】
ArrayListの要素をすべて削除する際に使用するメソッドである。
以下のようにして使用する。
変数名.clear();

Java（add）の回で使用したArrayList「array」を
clearメソッドで全ての要素を削除する。

    ArrayList<String> array = new ArrayList<String>();
    
    array.add("日本語");
    array.add("英語");
    array.add("フランス語");
    array.add("中国語");
    array.add("ドイツ語");

    System.out.println(array);
    
    [日本語, 英語, フランス語, 中国語, ドイツ語]

ArrayListの要素をすべてを削除する。

    array.clear();
    System.out.println(array);

リストの中を出力すると以下のようになる。

    []

要素の値がすべて削除されて何も表示されていない。
PostgreSQLで外部DBに接続する（postgres_fdw）

# はじめに

PostgreSQLでは、postgres_fdw を使うことで外部のDBにアクセスできます。
外部のDBはPostgreSQLだけでなく、MySQLやOracleなど違うDBMSでも可能です。
この記事では、同じローカルPostgreSQL内で、違うDBを参照してみます。

ちなみに、外部DBへの接続にはdblinkを使う方法もあります。
postgres_fdw はdblinkの後継機能となっており、postgres_fdw の方が記述し易く、かつ性能もよいです。

# 環境

- OS：Windows10
- PostgreSQL：10.8
- MySQL：8.0.19

# DB作成～データ登録

まず、PostgreSQLで2つのDBを作成し、それぞれテーブル作成とデータ登録も行います。

``` sql:test_local
CREATE DATABASE test_local;

\c test_local;

CREATE TABLE PERSON(
    name varchar(20),
    age integer
);

INSERT INTO PERSON VALUES ('佐藤一郎', 30);
```

``` sql:test_remote
CREATE DATABASE test_remote;

\c test_remote;

CREATE TABLE FRUIT(
    name varchar(20),
    price integer
);

INSERT INTO FRUIT VALUES ('林檎', 150);
```

## postgres_fdw のセットアップ

以下の流れでセットアップします。


``` sql
\c test_local;

-- 1. 拡張機能のインストール。初回のみ
CREATE EXTENSION IF NOT EXISTS postgres_fdw;

-- 2. 接続先の外部サーバオブジェクトを作成。ここではユーザとパスワードは設定しない
CREATE SERVER remote_server 
    FOREIGN DATA WRAPPER postgres_fdw
    OPTIONS (host 'localhost', port '5432', dbname 'test_remote');

-- 3. 外部サーバにアクセスするユーザとパスワードを指定
CREATE USER MAPPING
    FOR postgres SERVER remote_server
    OPTIONS (USER 'postgres', PASSWORD 'admin');

-- 4. 外部テーブル定義の設定
CREATE FOREIGN TABLE FRUIT(
    name varchar(20),
    price integer
) SERVER remote_server;
``` 

## select 実行

これで、test_local から test_remote の FRUIT テーブルが参照できます。

``` sql
\c test_local

-- test_remoteのテーブルを参照。外部DBを意識せずに書ける
 select * from Fruit;
```

## IMPORT FOREIGN SCHEMA でテーブル定義をインポート

以上で参照は可能ですが、`CREATE FOREIGN TABLE` でテーブル定義を書くのが面倒です。
Postgres9.5 からは `IMPORT FOREIGN SCHEMA` でテーブル定義を丸ごとインポートできるので、そちらを使いましょう。
スキーマ指定ですべてのテーブルをインポートしますが、`LIMIT TO` で対象のテーブル指定、`EXCEPT` で除外するテーブル指定が可能です。

``` sql
 IMPORT FOREIGN SCHEMA public
   LIMIT TO (FRUIT) -- 対象のテーブルだけインポート
   FROM SERVER remote_server INTO public;
```

# 外部テーブル定義の削除

外部テーブル定義を削除するときは、`DROP FOREIGN TABLE` を使えばよいです。
外部DBにあるテーブル自体は削除されません。テーブル自体を削除する場合は、外部DBにアクセスする必要があります。

``` sql:test_local
DROP FOREIGN TABLE FRUIT;
```

# 外部テーブル定義をすべて削除する

スキーマを指定してテーブル定義をインポートすることは出来ますが、スキーマ指定で削除する構文はありません。
一つ一つDROPするか、PL / pgSQLを使いましょう。

``` sql
-- すべてのスキーマの外部テーブル定義をDROP
do
$$
declare
  l_rec record;
begin
  for l_rec in (select foreign_table_schema, foreign_table_name 
                from information_schema.foreign_tables) loop
     execute format('drop foreign table %I.%I', l_rec.foreign_table_schema, l_rec.foreign_table_name);
  end loop;
end;
$$;
```

（参考：https://stackoverflow.com/questions/40728788/drop-foreign-schema-in-postgresql-using-a-foreign-data-wrapper）
AWSでhttpsする時

# 今回陥った事
1. 初めての証明書発行でつまづく
2. httpをhttpsにするためwordpressの設定を変更したらログインできなくなった
3. httpsに変更できた！しかしレイアウトが崩れている
4. ssl化したけど、安全じゃないって出てくる


# とても参考になったページズ
1. [Application Load Balancer 用の HTTPS リスナーを作成する](https://docs.aws.amazon.com/ja_jp/elasticloadbalancing/latest/application/create-https-listener.html)
2. [WordPressアドレスとサイトアドレスの違い・間違って変更した場合の対処法](https://www.nishi2002.com/4207.html)

3. [ELB + SSL + WordPressについて](https://norm-nois.com/blog/archives/3869)

4. [SSL化したのに、”このサイトへの接続は完全には保護されていません”と表示される場合](https://london3.jp/2017/08/site-ssl/)



上記のナンバリングに沿っているのそれを参照すれば解決する

#以下詳しい説明
## 1. 初めての証明書発行でつまづく
結論：ACMの証明書を使った

（ACMとはAWS内のhttps化サービス。無料）

以下日記
最初AWSでlet's encryptを用いた証明書発行を試みた。サーバへの導入は問題なく行うこと。しかし、ロードバランサの設定をhttpsにする時、リスナーの設定のやり方でこけてしまった。強強エンジニアに相談したところ「ACMでよくね？」と言われ導入（ACMの存在自体知らなかった。AWSは何でもありますね）。AWS触り始めて数週間の私でも感覚的に作成することができました。

## 2. httpをhttpsにするためwordpressの設定を変更したらログインできなくなった

おいおい付け足していく
Office365のメール受信スロットリングと対応案に含まれる罠

Qiitaに投稿し始めてもうすぐ2年。赴くままに書いているので、エンドユーザー向けの投稿もあれば、365管理者向けの投稿も雑多になっている。
そんな中で、意外な記事の閲覧数が多い。それがコレ。

[【備忘録】Office365のメール流量制限まとめ】](https://qiita.com/hisssa0102/items/fd58c1aac56733dc673b)

エンドユーザー向けでも365管理者向けでもなくて、すごくニッチな投稿だと思うけどコンスタントに増えてんだよな…。

というところで、受信制限と対応案についてまとめてみる。

#受信スロットリングとは

詳しくは上記の記事を見てほしいけど、ざっくり「あんまりメールきすぎてるからブロックするわ」という機能。

メールボックスごとに、1時間当たり3600のメッセージを超えると「上限を超えてっぞ」とメールを受信を遅らせるらしい。

通常の個人用メールアドレスで使ってる限りはこんなにメールくることはない（キッパリ）。

でも、社内システムのアラートメールを受けるメールアドレスとかだとこの閾値を超えてしまうケースもある。ということでそんなケースから対応案を考えたみる。
オンプレミスとか、固定のグローバルIP内にSMTPサーバーがあり、そこからアラートメールなどを送信するシナリオです。

#コネクタで回避できる？

社内のSMTPサーバーからのメールはOffice365ではない(=外部）ので、外部のメールサーバーの扱いでメールを受信してると、スロットリングの影響を受けてしまう。

これは「受信コネクタ」を作成して、「このIPからのメールは信頼してるから大丈夫」と登録しておくことで緩和することもできる。
Exchnage管理センター　-　メールフロー　-　コネクタ、から、「組織のメールサーバーからOffice365」で送信元IPアドレスを指定してやる。詳しいつくり方は割愛。

だがしかし、そこには罠がある。

#コネクタの罠

それは

- 受信コネクタをつかうと、外部テナントのメールですらコネクタの影響を受ける
- 受信コネクタを使うと、外部にもメールを送信できるけど、内部外部あわせて一切送信できないケースがある

という2つ。


###「外部テナントのメールですら、コネクタの影響を受ける」
受信コネクタを作成すると、コネクタに設定しているIPからOffice365を使っているすべてのドメイン宛のメールは、自社テナントを経由するようになってしまう。

そもそも受信コネクタなので社内向けのメールが中心のはず。なのでコネクタを作って社外にメール送るってことは本来少ないはず。ではあるけどまれにこういうケースがある場合は影響を受けてしまう。

コネクタ経由になってしまう社外当てのメールが、きちんと外に出ていくよう、トランスポートルールなどで検討する必要あり。

###「受信コネクタを使うと、外部にもメールを送信できるけど、内部外部あわせて一切送受信できないケースがある」

1つのメッセージの宛先に、複数のドメインを含むとアウト。

テナント外のドメイン＋テナント内のドメインでも、テナント内のドメイン＋テナント内のドメインでもダメ。どうしてもコネクタが必要なら、ドメインごとにメッセージを分けなきゃダメらしくい。

#コネクタを作るより、もっと簡単な回避策

受信するメールボックスを分割する。それだけ。
流量制限はメールボックスごとなので、メールボックスを分ければメールボックスごとの受信数は逆数で減る。

受信用メールボックスが1つで流量制限受けるなら2つ3つにする。一番シンプル。もっとも、アプリ側で対応必要になるケースもあるけど。

#まとめ

そもそも、受信の流量制限対応としては、SMTP送信・直接送信が本来の推奨構成。さらにこれらが選べないケースは外部のメール送信サービスを使うことを推奨されてる。
その3つが選べないような、超レアケースの対応案でしかない。

どうしても受信スロットリングへの対応が必要なほどメールを受ける場合は

- そもそも、受信スロットリングの影響受けるケースが少なく
- 要件的にシステム通知用のメールとかのはずで、そういったものは社内から社内宛のはずなので、先の2つの構成とか、メールボックスを複数持つことを優先的に考える

- それでもテナント外の宛先を含めたいし、メールボックスを分けることも難しいような超レアケースの場合は、受信コネクタではない別の方法か、十分に考慮

それこそ、ドメインごとにメッセージ分けるとか、アプリ側の作りこみとか。でも、メッセージ分けると流量制限の影響を受ける可能性が上がるというパラドックス。

そんなケースなら、いっそメール使わない方法を考えたほうが早いんじゃないだろうか。
安直にコネクタでいいじゃん、と考えないように注意しましょう。



#参考資料

Office 365 を使用してメールを送信するように多機能デバイスまたはアプリケーションをセット アップする方法
https://docs.microsoft.com/ja-jp/exchange/mail-flow-best-practices/how-to-set-up-a-multifunction-device-or-application-to-send-email-using-office-3

コネクタ設定における 3 つのポイント (送信元 : 組織のメール サーバー)
https://blogs.technet.microsoft.com/exchangeteamjp/2017/12/07/3points-of-inbound-connector/