OmniAICreator/Qiita-1.07M huggingface dataset:
CodeBuild内のgradleからでIAM Roleを使ってS3にアクセスする

CodeBuildでJavaのコードをビルドする際、S3をmavenリポジトリとして使用することにしました。

その際設定でけっこう詰まったので記事にしてみました。

## credentialsで設定する

[gradleのドキュメント](https://docs.gradle.org/current/userguide/repository_types.html#example_declaring_a_s3_backed_maven_and_ivy_repository_using_iam)には次のように書かれています。

```gradle:build.gradle
repositories {
    maven {
        url "s3://myCompanyBucket/maven2"
        credentials(AwsCredentials) {
            accessKey "someKey"
            secretKey "someSecret"
            // optional
            sessionToken "someSTSToken"
        }
    }
}
```

今回はCodeBuildにassumeされたIAM RoleからaccessKey, secretKey, sessionTokenを取得するので、次のようなコードになります。

```gradle:build.gradle
import com.amazonaws.auth.AWSCredentialsProviderChain
import com.amazonaws.auth.EC2ContainerCredentialsProviderWrapper
import com.amazonaws.auth.AWSSessionCredentials

...

repositories {
    maven {
        url "s3://sample-maven-repository/repository"
        credentials(AwsCredentials) {
            def credentials = new AWSCredentialsProviderChain(
                new EC2ContainerCredentialsProviderWrapper()
            ).getCredentials()
            accessKey credentials.getAWSAccessKeyId()
            secretKey credentials.getAWSSecretKey()
            if (credentials instanceof AWSSessionCredentials) { 
                sessionToken credentials.sessionToken
            }
        }
    }
}
```

## authenticationで指定するとエラーになる
一方、gradleのドキュメントには下記のような指定方法も記載してあります。

```gradle:build.gradle
repositories {
    maven {
        url "s3://myCompanyBucket/maven2"
        authentication {
           awsIm(AwsImAuthentication) // load from EC2 role or env var
        }
    }
}
```

しかし、上記だとビルドはエラーとなります。
エラーログを見た所、`InstanceProfileCredentialsProvider`が`http://169.254.169.254/latest/meta-data/iam/security-credentials/`にアクセスしており、そこでエラーが発生し、全体の処理が終了しているようです。
GDBの「gcore」について (コア解析)

gdb について調べていると、 gcoreというコマンドを見つけました。

gcore は実行中のプロセスの core を生成する gdb のコマンドです。
通常、 core ファイルはプログラムが異常終了したときにカーネルによって生成されますが、
gdb の gcore コマンドを使えば実行中のプロセスを終了させることなく core ファイルを生成できます。 

gcore コマンドは次のように使います。

# 実行例

``` bash
# gdb
(gdb) attach PID
(gdb) gcore core
(gdb) detach
```

まず attach コマンドで PID を指定して実行中のプロセスにアタッチします。次に、 gcore コマンドで core ファイルを生成します。このとき、任意のファイル名を指定できます。core の生成が終わったらデタッチします。

gdb によってアタッチされたプロセスは gdb による制御下に入り、実行が停止します。 step, next, continue, detach などのコマンドで意図的に実行を再開しない限り、プログラムは完全に停止しています。gcore コマンドのメリットはプログラムの停止時間を最小限に抑えて、デバッグできるところにあります。

たとえば、実行中のサーバプロセスをデバッグしたい場合、ローカル変数などの各種のインスペクションを行うために gdb で長時間アタッチしてその間、サービスを止めてしまうのはできるだけ避けたいところです。このようなとき、 gcore コマンドを使えば、 core を生成したのちにただちにデタッチできるので、サービスの停止時間を最小限に抑えることができます。

# コアファイルデバッグ

``` bash
# BackTrace
(gdb) bt

# 関数指定
(gdb) frame 0

# 変数表示
(gdb) p var

# ソースプログラムを表示
(gdb) list

# ステップアウト実行
(gdb) next

# ステップイン実行
(gdb) step
```

# その他

gdb のパッケージには gdb_gcore.sh というスクリプトが含まれており、attatch, gcore, detatch をバッチで実行します。手作業でこれらのコマンドを実行するよりもこのスクリプトを使ったほうがいいでしょう。Linuxディストリビューションによっては gcore というコマンド名で /usr/bin などにインストールされているものもあるようです。

# まとめ
gdb の gcore コマンドについて紹介しました。実行中のプロセスをできるだけ停止させずにデバッグしたいというときに役立つのではないかと思います。
Juggling Motion in PowerApps #2

##Previous [Post](https://qiita.com/h-nagao/items/0fc22b2b9e1723570d4f)
In my previous post, I have explained simplified motion modeling, and core equation of juggling ball.
(Projectile with Air Resistance)
Next, I will show the Circular motion in PowerApps and how we determine the parameters.

##Circular motion
Equations for circular motion, which represents handling of ball, are simply given by
<img width="911" alt="circular.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/202779/61519fa8-d7a5-02ac-df9f-822b188fca9d.png">
where *T* is half of time period, which represents quickness of handling.
Although *{X2,Y2}* are arbitrary parameter, you can choose any *r*, *X1* is termination point determined by Equation of Projectile with Air Resistance.

##How determine each parameters?
As I have mentioned in previous post, each parameters are basically arbitrary.
But when it implemented into PowerApps, there are some restriction due to finite canvas size.

<img width="923" alt="const.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/202779/3915c781-8b7f-f588-c2a5-e1409ed5aa2e.png">

You can numerically solve the equation determining termination point *X1* using [Wolfram Alpha](https://www.wolframalpha.com/).

```Wolfram
NSolve[ v0/k * (1+g/(k*v0))*(1-Exp(-1 * k * t))==g/k*t,t]
```
For example, if we set (v0,k,g)=(800,0.8,500), termination time t_* is estimated as
<img width="629" alt="wolfram.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/202779/c7b9eaa9-9e95-5c80-0440-e9e1ca33ab64.png">

Also, termination point *X1* is obtained by substituting t_* into Equation of X(t).
Additional Remarks; in context of PowerApps, t_* is Duration property of Timer control.

Under these constraints, you should fine-tuning parameters to make juggling motion expected.
Let's try!!

##Acknowledge
I would like to thank [@that_API_guy](https://twitter.com/that_API_guy?s=09) for giving chance to join to Juggling Challenge in PowerApps.
Also, [@RajYRaman](https://twitter.com/RajYRaman?s=17), he suggests me to blog bit in detail.
ARDUINO で気圧と温度をSPIバスで読む

# ArduinoMicro でSPIバスを使う
## はじめに
- 今回は
 - Arduinoを使っていろいろなセンサの値を読んで使いたいので練習。
 - 昔購入した STmicroelectronics 社のLPS331AP (pressure/temperature sensor)があったので、これを使う
 - 必要なプロセスをできるだけ理解しながら行いたい
 - SPI (serial Peripheral Interface)を利用する（初利用！！） 

### (多分)一般的な作業工程
- センサーの仕様書をもってきて、何をどれくらい読めるかを確認する
- ピン配置を整理して、接続を考える
- センサーの設定、データの読み込みを実装する
- データの読み方をbrush up する。（今回はできていない）

## ピン配置

### 仕様書を入手

- 使用しているのは、LPS331APです。秋月電子のページ（[ここ](http://akizukidenshi.com/catalog/faq/goodsfaq.aspx?goods=M-06679)　）に何とメーカーのDataSheet と Design Tip "How to interpret the LPS331AP pressure and temperature readings"があり、これをじっくり読むことが大切。と言いながら、自分は読みませんでした。^^;)
- 入手: 私はマルチパーツ館の大気圧センサ・モジュール MLPS331-MOD なるもので、某雑誌の別売り[部品セット](https://www.marutsu.co.jp/pc/i/232224/)に含まれていたもので、古いもののようですが、まだ買えるようです。([ここ](https://strawberry-linux.com/catalog/items?code=12113)などで)
 - 24bit の圧力値と16bit の温度をレジスタに持ち、値をI2CやSPIで読むことができます。
 
### SPI (Serial Peripheral Interface) について

- SPIについてのざっくりとした流れの理解
 - Master と Slave がいる。Master はクロックは流す。CLK
 - Master　がCS(chip select）ピンをLOWにすると読みか書き込みの信号を送受信し、終わったらHIGHに戻す。CSでなくSS(slave select)とも呼ぶらしい。
 - Masterからslave のレジスタにデータを書くには、CSをLOWにしたのち、書き込み用の通信線でデータ通信してレジスタ値と値を送る。
 - MasterがSlaveのレジスタ値を読むには、CSをLOWにしたのち、読むための通信線(MISO)を利用して最初に１byte 書き込み、それから、目的のslaveのレジスタ値を読む。
 
- 最低限の通信は CLK(clock), CS(chip select)、MISO(master in slave out)、MOSI(master out slave in)の４線になる。

　- WikiPediaより：![image.png](https://qiita-image-store.s3.amazonaws.com/0/294040/18d84737-05be-5b34-5b4e-36b73a210a8a.png) 
　- 今回はまずこの４つの線をつないで読み書きの動作確認を行った。


### ArduinoMicroについて

- はまったその１：<SPI.h> で使えるSPIはICSPのピンであった。ここでCLK, MISO, MOSIが用意されている。
- はまったその２：CSに使えるGPIOピンが、プログラム上で指定するピンの番号とどのような関係にあるかわからなかった。結局D2のピンの番号が2, D11は11で良いと分かった。
- その他3.3Vに注意。
以上から、いかのようなにピンを接続させた。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/294040/53eb8f91-30ab-ed0b-798b-b3993093b73f.png)

実装については、先ほどのSPI通信をそのまま。センサーのレジスタ値にデータを書くには、

```
void spi_write(byte reg, byte val)
{
  digitalWrite(CS_PIN, LOW);
  SPI.transfer(reg);
  SPI.transfer(val);
  digitalWrite(CS_PIN, HIGH);
}
```

データを読むには

```
byte spi_read(byte reg)
{
  byte ret = 0;

  digitalWrite(CS_PIN, LOW);
  SPI.transfer(reg | REG_RW);
  ret = SPI.transfer(0);
  digitalWrite(CS_PIN, HIGH);
  return ret;
}
```

とすればよい。初期化はSPIの設定でbaudrate を指定する。ここでは1MHzにしている。
また、CSに使用するピンを出力設定にする。Arduinoのsetup()の中では、この後で必要な設定をレジスタ値に書き込む。

```
  SPI.begin();
  SPI.setBitOrder(MSBFIRST);
  SPI.setClockDivider(SPI_CLOCK_DIV4); // 8MHz/8 = 1MHz; (max 10MHz)
  pinMode(CS_PIN, OUTPUT);// Chip select pin
```

とりあえず、今回はこれで動いた。
スケッチをアップロードしてリンクを貼ろうとした方法が分からん。
整理したら、githubにuploadするとかしてみたいな。

### 参考にしたページ

いろいろ参考にさせていただきました。

- Arduino のページ([SPI](https://www.arduino.cc/en/Reference/SPI)や[例](https://www.arduino.cc/en/Tutorial/BarometricPressureSensor) )
- [電子回路の実験](http://kosakai.world.coocan.jp/LPS331AP.html)
- [Arduinoの部屋](https://n.mtng.org/ele/arduino/tutorial018.html)
- [掲示板](https://teratail.com/questions/21077)

多謝
インストーラ いくつか

Windows アプリケーションをバッチファイルでインストールしている某システムがダサ過ぎるので、マイグレーションに伴いいくつかインストーラを検証。
#7-Zip Extra
[https://sevenzip.osdn.jp](https://sevenzip.osdn.jp)
バイナリ結合でインストーラが作成できる。
が、セットアップアプリケーションは何かしら作らなければならない。
バグっぽい不具合があってやめた。ファイルサイズか、ファイル数が要因か。
エラーメッセージも"Unsupported Method"なんて表示されるだけで、不親切。
#Visual Studio 2017 Installer Projects
[https://marketplace.visualstudio.com/items?itemName=VisualStudioClient.MicrosoftVisualStudio2017InstallerProjects](https://marketplace.visualstudio.com/items?itemName=VisualStudioClient.MicrosoftVisualStudio2017InstallerProjects)
GUIがとても使いやすい。
圧縮率もデバッグで速度優先、リリースでは圧縮率優先と変えたりできる。
GUIが充実している分、大量のファイルを厳密に管理するのには向かなそう(プロジェクトファイルの中身も複雑)。
システム(Windows ディレクトリ)上の一部のアクセス権限の高いファイルが上書きできないのと、
作成・管理するのにVSが必要なので仕方なく却下。
.NETアプリケーションのインストーラには良さそう。
#InstallAware RAD Studio Edition
[https://www.installaware.com](https://www.installaware.com)
RAD StudioからGetItでダウンロードできる。Communityでも使用可。
かなり本格的。機能が多すぎてハードルが高く感じるけど、
InstallShieldのようなしっかりしたインストーラが作れそう。
開発者みんなが使ってくれるならいいけど、取っつきにくいのとGUIが英語という点で敬遠されそうなので却下。
使いこなせればいいソフトだとは思う。日本ではあまり流行っていない雰囲気。
#NSIS
[http://nsis.sourceforge.net](http://nsis.sourceforge.net)
It Really Whips Llama's XXX...
簡単。何度か大幅(？)なバージョンアップがあるようだけど、公式ドキュメントがそこそこ充実していてわかりやすい。
変数を使うスクリプトやWindows APIをラップしたような関数がちょっと冗長に感じるけど、
スクリプトだけでオプション付きのインストーラが作れる。
圧縮メソッドも指定できるので、LZMAにすれば圧縮率も申し分ない。
開発環境も軽量(インストーラは1.64MB)でスクリプトもアスキーファイルなので大量のファイルも管理しやすいと思う。
アンインストーラは削除対象ファイルやレジストリへの登録を自分で記述する必要があり、
コントロールパネルから削除するタイプのアンイストーラを作るには、ちょっと面倒かも。
#その他
[WiX Toolset](http://wixtoolset.org)も良さそう。
ただXMLでの記述は手間だし、WixEditを使うとInstallAware並みに高機能になってしまうので、みんなが使ってくれるかは悩ましいところ。
PTSをVTFで利用する（DDSを使った16bitイメージの保存）

どたばたして書けてなかったTipsを順次上げていきたいと思います。
githubにサンプルも上げたのですがgithubサーバがおかしいのでリンクは後程・・・。

# 渋谷駅のポイントクラウドデータをリアルタイム表示したい
少し前ですが、[渋谷駅のポイントクラウドデータ](https://3dcel.com/)が公開されました。
Unityユーザが反応し、すぐにリアルタイム表示をしていたのでTouchDesignerでもできないかな、と試してみました。
結果、DDS形式に変換することでうまく行ったのでそのプロセスを公開します。

# PTS形式とは
渋谷駅のデータはPTS形式で保存されています。
ちゃんとした規格のページが見つかりませんでしたが、[フォーラム](http://www.derivative.ca/forum/viewtopic.php?f=4&t=5857)を見る限りPTS形式は要するに**スペース区切りのUTF8のテーブルデータ**のようです。
LiDAR（測域センサ）のデータの保存によく使われているようです。
そしてどうやら**最初の3列がXYZ**で、**最後の3列がRGB**のようです。
『なるほど、ようするにテキストデータか』ということでatomで開いたところ、かなり時間がかかる上にエラーが・・・。
よく見るとファイルサイズが2GB近くあります。
行数＝頂点数として200万オーバー。確実に普通のモデルとしては読み込めないサイズです。
が、テクスチャに焼いてVTFとして表示すればリアルタイム表示は不可能ではないサイズでした。
また、上記の仕様以外に**一番上の行に総行数＝総頂点数を書く**というルールがあるようでした。

# DDS形式とは
VTFで利用する場合、16bitのfloatのフルカラー画像で保存することが大前提になります。そして色々人に聞いてみたところ、DDSを利用することにしました。
[DirectDraw Surface](https://en.wikipedia.org/wiki/DirectDraw_Surface)とはDirectXで利用可能な画像フォーマットです。
TouchDesignerではJPGやPNGと同様に簡単にMovie File Out TOP、 Movie File In TOPから保存、読み込みが可能です。

# chan形式とは
PTSを直接TouchDesignerで読み込めれば楽なのですがTouchDesignerはPTS形式に対応していません。
なので変換が必要になります。
TouchDesignerで簡単にテキストベースのデータを読み込む形、それはchan形式です。
chanは**スペース区切りのUTF8のテーブルデータ**です。
つまり、PTSとの違いは**一番上の行の総頂点数**と**ファイル形式名称**だけです。
試しにフォーラムに上がっていたStanford BunnyのPTSデータを

* 一番上の行を削除し、
* ファイル形式名称を.chanにリネーム

したところ、File In CHOPで.chanファイルとして値が読み込めました。

# PTSからchan形式に変換
ここまで来たらもう一息です。2GBのテキストデータはTouchDesignerではまともに読めなかったため、X、Y、Z、R、G、Bの各チャンネルのデータに分離して保存しなおすPythonを書きました。
一番最初の行の削除だけAtomで行って再度保存し、PythonのPandasを使って配列を分割しました。

```python:split.py

import pandas as pd

df = pd.read_csv('ShibuyaUnderground.chan', header=None, sep=' ')
df.to_csv('shibuya_x.chan', header=False, index=False, columns=[0], sep = ' ')
df.to_csv('shibuya_y.chan', header=False, index=False, columns=[1], sep = ' ')
df.to_csv('shibuya_z.chan', header=False, index=False, columns=[2], sep = ' ')
df.to_csv('shibuya_r.chan', header=False, index=False, columns=[4], sep = ' ')
df.to_csv('shibuya_g.chan', header=False, index=False, columns=[5], sep = ' ')
df.to_csv('shibuya_b.chan', header=False, index=False, columns=[6], sep = ' ')

```
この6つの.chanファイルをTouchDesignerを使って2枚のDDSにします。

# chan形式をDDS形式に変換
短ければパッチのみでTOP化することが可能だと思うんですが、200万行のデータはCHOP上で少しいじるだけでTouchDesignerがフリーズしてしまいます。
そこで直接CHOPをTOPに変換するShaderを書きました。

```glsl:image.frag
uniform samplerBuffer buffer_r, buffer_g, buffer_b;
uniform vec2 uBufferSize;
out vec4 fragColor;

void main()
{
	int count = int(vUV.x * uBufferSize.x) + int(int(uBufferSize.y * vUV.y) * uBufferSize.x);
	vec4 color = vec4(texelFetch(buffer_r, count).r,texelFetch(buffer_g, count).r, texelFetch(buffer_b, count).r,  1.0);
    fragColor = TDOutputSwizzle(color);
}
```
そして出来上がった画像をMovie File Out TOPを使ってDDSで保存します。

# ビジュアライズ
あとはこれをVTFで画像表示するだけ！
<img width="2032" alt="スクリーンショット 2018-10-22 23.38.41.png" src="https://qiita-image-store.s3.amazonaws.com/0/152718/3f2de63b-7a33-1668-20ef-a7d23c7e666a.png">
C言語で分布数え上げソート

# 分布数え上げソートとは
比較を行わなずに、データを整列する方法

#### 手順
以下、10点満点のテストを例にして説明

- 9人の学生の点数は次の通り：次の表を配列$a$とする

| 学生 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
|:---:|:--:|:--:|:--:|:--:|:--:|:--:|:--:|:--:|:--:|
| 点数 | 5 | 7 | 0 | 2 | 4 | 10 | 3 | 1 | 3 |

- 上表をもとに、度数分布表を作成：各点数の学生が何人いるか

|度数分布表| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|| 1 | 1 | 1 | 2 | 1 | 1 | 0 | 1 | 0 | 0 | 1 |

- 累積度数分布表を作成：0点からその点数までに何人の学生がいるか

|累積度数分布表| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|| 1 | 2 | 3 | 5 | 6 | 7 | 7 | 8 | 8 | 8 | 9 |

- 配列$a$の末尾から走査し、ソート済み配列を作成する：累積数=格納場所
  1. 配列$a$の末尾=8番の学生の点数は3点
  - 累積度数分布表の3を見る$\to$5
  - 作業用配列（配列$a$と同サイズ）の前から5番目に8番の学生のデータを格納
  - 累積度数分布表の3の値を1減らす（$5\to 4$）
  - 続いて、7番の学生の点数は1点
  - 累積度数分布表の1を見る$\to$2
  - 作業用配列の前から2番目に7番の学生のデータを格納
  - 累積度数分布表の1の値を1減らす（$2\to 1$）

|作業用配列| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
|:-------:|:--:|:--:|:--:|:--:|:--:|:--:|:--:|:--:|:--:|
|         |  |  |  |  | 3 | |  |  |  |

|作業用配列| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
|:-------:|:--:|:--:|:--:|:--:|:--:|:--:|:--:|:--:|:--:|
|         |  | 1 |  |  | 3 | |  |  |  |

  - 繰り返して最終的に次のような配列ができる

|作業用配列| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
|:-------:|:--:|:--:|:--:|:--:|:--:|:--:|:--:|:--:|:--:|
|         | 0 | 1 | 2 | 3 | 3 | 4 | 5 | 7 | 10 |

# サンプルコード
int型の配列を、分布数え上げソートを用いて整列するプログラム


```c:distribution_counting.c
#include<stdio.h>

/* 分布数え上げソート */
void distribution_counting (int array[], int array_size, int data_size) {
  int i, j;
  int count[data_size]; // 度数分布表用の配列
  int work[array_size]; // 作業用配列

  for (j = 0; j < data_size; j++) { count[j] = 0; }   // 分布表初期化
  for (i = 0; i < array_size; i++ ) { count[array[i]]++; }   // 度数分布表作成
  for (j = 1; j < data_size; j++) { count[j] += count[j-1]; }   // 累積度数分布表にする
  for (i = array_size -1; i >= 0; i--) {
    work[count[array[i]]-1] = array[i];   // 度数分布表に従って並び替え
    count[array[i]]--;   // 分布表更新
  }
  for (i = 0; i < array_size; i++) { array[i] = work[i]; }  // 作業用配列からコピー
}

int main (void) {
  int array[10] = { 2, 1, 8, 5, 4, 7, 9, 0, 6, 3 };
  int i;

  printf("Before sort: ");
  for (i = 0; i < 10; i++) { printf("%d ", array[i]); }
  printf("\n");

  distribution_counting(array, 10, 10);

  printf("After sort: ");
  for (i = 0; i < 10; i++) { printf("%d ", array[i]); }
  printf("\n");

  return 0;
}
```

実行結果

```
Before sort: 2 1 8 5 4 7 9 0 6 3
After sort: 0 1 2 3 4 5 6 7 8 9
```

# 性能
- ソート対象のキーの範囲が既知でないといけない
- 作業領域が必要
  - 分布表用の配列、コピー用の配列
- データの比較を行わないので高速
pgpool-IIの使い方を考える

## 環境情報
- 仮想環境：VirtualBox 5.2.18
- OS：CentOS 7.5
- pgpool-II 3.7.5-1pgdg.rhel7 (yum インストール)
- PostgreSQL 10.5-1PGDG.rhel7 (yum インストール)


## はじめに
pgpool-IIに興味があったものの、これまで職場で触る機会が無かったので、使い方を考えてみることにしました。

構築に当たって必要になる知識は上記環境情報記載のソフトウェアに加えてbashスクリプトとなります。

各ソフトウェアについてはそれぞれのマニュアルを見つつ構築を進めて行くことになります。

また、bashスクリプトについてはpgpool-II向けにフェイルオーバー、フェイルバックの処理を記載することになるのですが、こちらはマニュアルだけでは不十分で、どういう動きをさせたいのかを考えながら処理を書く必要があるようです。

pgpool-IIを使用するにあたってこの辺りは自由度が高いところのようなので、正直なところこの記事で正しい使い方が出来ているのか否か分かりません。とりあえず動くことは確認できましたが、職場で使うことがあればそのときは本家SRAとサポート契約結びたいところです。

このページでは全般的な構成イメージを説明します。
構築手順については当ページにリンクを記します。

## 構築手順
### PostgreSQL環境構築

[PostgreSQL環境構築](https://qiita.com/sankaku/items/9f266aaa2c745dd9fa38)

### pgpool-II環境構築

[pgpool-II環境構築](https://qiita.com/sankaku/items/0e293de1e51acbcb772a)

### 【前提】CentOS検証環境初期設定

[【前提】CentOS検証環境初期設定](https://qiita.com/sankaku/items/073683cfe674cb73d5de)

当検証を実施するに当たって実施したOSの基本的設定内容です。
pgpool-IIをインストールするために必須というわけではないですが、参考までに記載しておきます。

### 【蛇足】レプリケーションでバックアップ
[【蛇足】レプリケーションでバックアップ](https://qiita.com/sankaku/items/899648b1e57da149a77a)


## 検証構成
### pgpool-IIノード：3台
master/slaveモードを使用します。

クォーラム（定足数）の挙動を確認するため、複数かつ奇数で最小の3台とします。

### PostgreSQLノード：4台
レプリケーション構成でmaster1台、残り3台をslaveとします。

master故障時の代替master用に1台を想定しています。また、残り2台のslaveは代替masterが昇格した際に上位masterを代替masterに切り替えます⇒「上位master切替処理」。
slaveの「上位master切替処理」は複数台に対応させたので、その動作を確認するため、masterは1台ではなく代替含めた2台にしました。


正常な状態のイメージは以下のようになります。
![構成イメージ.jpg](https://qiita-image-store.s3.amazonaws.com/0/197060/26c79b00-d849-9fdc-4d10-070cc7b27f60.jpeg)


監視パケットはそれぞれ以下のように送出されます。

| 監視経路 | 監視方法 |
|:-----|:-----|
| pgpool\-IIからGW (Virtual BoxのHost) | ping |
| pgpool\-II間 | watchdog |
| pgpool\-IIからPostgreSQL | psql |


![監視パケットイメージ.jpg](https://qiita-image-store.s3.amazonaws.com/0/197060/59bbb3d4-8204-37c5-8166-1f72d5546d39.jpeg)


## pgpool-IIフェイルオーバー/フェイルバックイメージ
**Google Slidesで表示します。**
#### [フェイルオーバー](https://docs.google.com/presentation/d/1B8EdwXWu04orh6naSbHG-4rGnNDqrIHx-LJjafa5OLk/present?token=AC4w5VhiDY7UjzEgYe1C1R8x8neUWXzpLg%3A1540385817016&includes_info_params=1#slide=id.g43a75f42ab_0_6)

#### [フェイルバック](https://docs.google.com/presentation/d/1EqYQKb2gWhQ2H9ugj1wE30EX8Uljpf9p2jC1msEpk40/present?token=AC4w5VjncVxelMrILBJE-W55s97n2ZMBsA%3A1540386097578&includes_info_params=1#slide=id.g4294969042_2_52)

## PostgreSQLフェイルオーバー/フェイルバックイメージ
**Google Slidesで表示します。**
#### [フェイルオーバー](https://docs.google.com/presentation/d/1YIOHgRWA_0Jm_JISXLKRq8w0Pm6Rk7aEba7oApE99xo/present?token=AC4w5VgCXZms6zP9R3td_N-jlnhaaU07yA%3A1540386614933&includes_info_params=1#slide=id.g43aa9f8720_0_0)

#### [フェイルバック](https://docs.google.com/presentation/d/1CKPSOWEpB539v9zkPtUdf6y9LQqUTRktLmUWF2HdlUQ/present?token=AC4w5VhciSkZnyjrA8FDJvHO3dOQk1Yuig%3A1540386081200&includes_info_params=1#slide=id.g42988ebf22_1_44)
【Mac】よく使うけど忘れがちなショートカットキー

# Google Chrome
| ショートカットキー | 内容 |
|:-----------------:|:------------------:|
| ⌘-n | 新しいウィンドウを開く |
| ⌘-t | 新しいタブを開く |
| ⌘-option-←| 前のタブに切り替える |
| ⌘-option-→| 次のタブが切り替える |
| ⌘-w | 現在のタブを閉じる |
| ⌘-Shift-w | 現在のウィンドウを閉じる |
| ⌘-[ | ブラウザバック |
| ⌘-m | Chrome を最小化 |
| ⌘-q | Chrome を閉じる |
| ⌘-r | ページをリロード |
| ⌘-- | ページを縮小 |
| ⌘-+ | ページを拡大 |
| ⌘-Shift-f | ページを最大化・最大化終了 |
| ⌘-option-i | デベロッパーツールを開く |

# Mac
| ショートカットキー | 内容 |
|:-----------------:|:------------------:|
| ⌘-w | ウィンドウを閉じる |
| ⌘-q | アプリケーションを閉じる　 |
| ctrl-↔ | デスクトップを移動 |
| ⌘-tab | 起動中のアプリを確認 |
Apache2のhttpsと､Softetherの443番通信を両立したい

Apache2でのWebサーバーをLet's EncryptでSSL化したところ､SoftEther VPN Serverで443番を使った通信が､当然ながら通らなくなってしまいました｡

SoftEther自体は443を使わなくても通信ができるのですが､とあるクライアント側のネットワークが443以外使えないということもあり､なんとか443を使ったVPNと､HTTPSを両立させようと､必死になって調べてみましたが､大半が｢OpenVPNとSSLHつかって分離!｣とかそういう感じで､一切Apache2+SoftEtherの両立に関する情報がありませんでした｡

いろいろと調べたり､友人に相談したりした結果､うまく行ったので､やり方を書いておきます｡

## 環境
Debian 9 Stretch
Apacheバージョン:2.4.25
SoftEtherVPNインストール済み

## 1. SoftEther VPN Serverで443のListenを止める
![image.png](https://qiita-image-store.s3.amazonaws.com/0/300863/48263f8a-add4-5d68-7fde-9ec12019f9bc.png)

443はApacheに明け渡してしまい､SoftEtherからは443を止めてしまいましょう

## 2. ApacheにproxyのMODを読ませる
```shell
sudo /usr/sbin/a2enmod proxy
```

## 3. Apacheにバーチャルホストの設定をする

/etc/apache2/sites-available/ に､適当に名前をつけてconfファイルを置きます｡
ここではvpn.confとします｡

```conf:vpn.conf

<VirtualHost *:443>
    ServerName vpn.example.com # 適当にサブドメインかなんかでやっちゃいましょう
    ProxyPreserveHost On
    ProxyPass / vpn.example.com:5555 timeout=3600 # 5555番に転送
</VirtualHost>
```

これで設定は完了です｡

```
sudo systemctl restart apache2
```
で再起動

## 4. 確認
![image.png](https://qiita-image-store.s3.amazonaws.com/0/300863/6a94b33e-9ab4-e5be-1881-41fda945dd8b.png)

実際に繋いでみると､サーバー側では443を止めていても､クライアントからは443でつながっていることがわかります｡

実際セキュリティがどうなのかはわかりませんが､Apache2でのHTTPS接続と､443番を使わざるを得ない状況でのSoftEtherVPN Serverの両立ができました｡

もし同じことで悩んでいる方に役立てば嬉しいです｡
pgpoolでレプリケーションができていない場合の対処法

#前提
・Linux(CentOS7)を用いてPostgreSQLを2台構築
・pgpoolのレプリケーションモードで2台を同じ状態にしている。

#事象
2号機にしか書き込みがされていない状態が発覚

・サービスは上がっている
・特にレプリケーション失敗のログは出ていない。
・1号機のOSが再起動した(他チームが勝手に実施)
・pgpool_statusがdown up の状態

#対処法
##最初はDB不整合を疑った
1号機に再起動が掛かっている最中に2号機へ更新があったため
１，２号機でDBに差異が生じた。
それによって2号機にしか書き込みが行かなくなってしまったと仮定
⇒2号機のDBを1号機にリストアするも、事象改善せず。

##pgpool_statusを直そう
1号機は復旧しているにもかかわらず、pgpool_statusがdownとなっているのが
原因ではと仮定。
pgpoolの起動コマンドに-Dのオプションを追記
※このオプションをつけると、pgpool_statusを消して作り直す動きをする。

###pgpoolの起動コマンドの見方
といかsystemdの仕様だが、
systemctl cat [サービス名]で表示されるExecStartが起動コマンドである。

今回でいえば

ExecStart=/usr/bin/pgpool -f /etc/pgpool-II/pgpool.conf $OPTS

となる。


###systemdのシステムファイルの更新
単純に/usr/lib/systemd/system/pgpool.serviceを更新するだけではNGとなる。

こんなメッセージがでてくる。
Warning: pgpool.service changed on disk. Run 'systemctl daemon-reload' to reload units.

つまり
systemctl daemon-reload
を叩けと

こうすることで更新が走り、編集した内容でsystemdがよしなりやってくれる。


そうすると・・・

/var/log/pgpool/pgpool_status　が
up
up

の表記に！！！！

これで直りましたー
Ansible 2.7でyum + with_itemsを使うと出る警告の直し方


# 警告の内容

Ansible 2.7でyumモジュールを使っていたところ、以下の警告が出ました。

```
[DEPRECATION WARNING]: Invoking "yum" only once while using a loop via
squash_actions is deprecated. Instead of using a loop to supply multiple items
and specifying `name: {{ item }}`, please use `name: ['git', 'gcc']` and remove
 the loop. This feature will be removed in version 2.11. Deprecation warnings
can be disabled by setting deprecation_warnings=False in ansible.cfg.
```

要はループを使うなと言うわけですが、squash_actionsって何か知らなかったので調べてみました。

# squash_actionsとは

[ANSIBLE_SQUASH_ACTIONS](https://docs.ansible.com/ansible/2.7/reference_appendices/config.html#envvar-ANSIBLE_SQUASH_ACTIONS)に以下のように記載されています。

ざっくり言うと、with\_によるループを使っているときに、リストで渡すように最適化する機能です。

> Ansible can optimise actions that call modules that support list parameters when using with\_ looping. Instead of calling the module once for each item, the module is called once with the full list.The default value for this setting is only for certain package managers, but it can be used for any module.Currently, this is only supported for modules that have a name or pkg parameter, and only when the item is the only thing being passed to the parameter.

具体的には、以下のように書かれているときに、
yumモジュールを2回実行するのではなく、`['git', 'gcc']`のように自動的にリストにして、1回で実行してくれます。便利ですね。

```yaml
- yum: name={{ item }}
  with_items:
    - git
    - gcc
```

[DEFAULT_SQUASH_ACTIONS](https://docs.ansible.com/ansible/2.7/reference_appendices/config.html#default-squash-actions)によれば、yumの他に、apt、homebrewなどパッケージマネージャがデフォルトで定義されています。

# 修正方法

[Ansible 2.7 Porting Guide](https://docs.ansible.com/ansible/devel/porting_guides/porting_guide_2.7.html#using-a-loop-on-a-package-module-via-squash-actions)や[yum](https://docs.ansible.com/ansible/latest/modules/yum_module.html)に書かれているように、以下のようにします。

```yaml
- yum:
    name: "{{ packages }}"
    state: present
  vars:
    packages:
      - git
      - gcc
```

また、yumモジュールに関しては、以下のようにも書けます。こちらの方がシンプルですね。

```yaml
- yum:
    name:
      - git
      - gcc
```
クラウド・コンピューティングの定義

クラウド・コンピューティングとは、ざっくりとしか理解できていなかったのですが、NIST(National Insutitute of Standards andTechnology)が定義しているので書き留めておきます。

**「クラウド・コンピューティングとは、構成の設定および再配置が可能なコンピューティングリソースがユーザーから共有可能な状態で配備され、そのリソースに対してユーザーが望む時（On-demand）にストレスなくネットワークアクセスできるリソースモデル」**

①オンデマンドセルフサービス
ユーザーごとに独立した管理画面が提供され、クラウド提供者側のオペレーションが介在することなく、ユーザー自らが設定することができる。

②幅広いネットワークアクセス
携帯電話、PC、シンクライアントPCなど、様々な形態のデバイスからネットワーク経由でアクセスできる。

③リソースのプーリング
クラウドのコンピューティングリソースはマルチテナントモデルで提供される。
物理的なデータ配置場所に依存しない機能を持ち、ユーザーはロケーションについて正確な場所を知ることができない。

④迅速な伸縮性
リソースの調達がユーザーにより簡単にでき、内容によっては自動スケールアウト/スケールインができる。

⑤測定されたサービス
リソースの使用状況の可視化や自動コントロールができる。

そうですね現在の例えばAWSのクラウドを見てみると、ユーザーが自由に個別の管理画面を使って好きなタイミングで仮想マシン、ストレージ、CPU、メモリ、ネットワークなどのリソースを簡単に組み立てられるようになっています。

これらの定義はクラウドサービスプロバイダの成長と共に今後も変化していくと思われます。
C言語でマージソート

# マージソートとは
分割統治法に基づくアルゴリズム

#### 手順
1. 与えられた配列（長さ$n$）を$n/2$の部分配列に分割
2. 2つの部分配列をそれぞれマージソート
3. 得られた二つのソート済み部分配列を統合

![qiita-sort-5.png](https://qiita-image-store.s3.amazonaws.com/0/299208/99fa8de6-01e2-c83f-aa1f-f68bd82aac8f.png)


#### 基本的な考え方
- 整列済みの2つの配列を併合する
- 2つの配列の先頭を見て、小さいほうを取り出す
- 配列の併合を再帰的に実行

![qiita-sort-6.png](https://qiita-image-store.s3.amazonaws.com/0/299208/960549d8-5db9-fb37-4af2-f67ccd8d7e06.png)


# サンプルコード
int型の配列を、マージソートを用いて整列するプログラム

```c:merge_sort.c
#include<stdio.h>

/* マージソート */
void merge_sort (int array[], int left, int right) {
  int i, j, k, mid;
  int work[10];  // 作業用配列
  if (left < right) {
    mid = (left + right)/2; // 真ん中
    merge_sort(array, left, mid);  // 左を整列
    merge_sort(array, mid+1, right);  // 右を整列
    for (i = mid; i >= left; i--) { work[i] = array[i]; } // 左半分
    for (j = mid+1; j <= right; j++) {
      work[right-(j-(mid+1))] = array[j]; // 右半分を逆順
    }
    i = left; j = right;
    for (k = left; k <= right; k++) {
      if (work[i] < work[j]) { array[k] = work[i++]; }
      else                   { array[k] = work[j--]; }
    }
  }
}

int main (void) {
  int array[10] = { 2, 1, 8, 5, 4, 7, 9, 0, 6, 3 };
  int i;

  printf("Before sort: ");
  for (i = 0; i < 10; i++) { printf("%d ", array[i]); }
  printf("\n");

  merge_sort(array, 0, 9);

  printf("After sort: ");
  for (i = 0; i < 10; i++) { printf("%d ", array[i]); }
  printf("\n");

  return 0;
}
```

実行結果

```
Before sort: 2 1 8 5 4 7 9 0 6 3
After sort: 0 1 2 3 4 5 6 7 8 9
```

# 性能
- 比較回数$O(n\log{n})$で実用的
- 作業領域が必要
- 安定ソート
- 性能は、入力のデータの並び方に影響されない
ssh　WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
The fingerprint for the ECDSA key sent by the remote host is
*******************************************
Please contact your system administrator.
Add correct host key in /home/ebara/.ssh/known_hosts to get rid of this message.
Offending ECDSA key in /home/ebara/.ssh/known_hosts:27
ECDSA host key for ***.***.***.*** has changed and you have requested strict checking.
Host key verification failed.



vi ~/.ssh/known_hosts
該当行を削除。
Atomでpythonしてたらエラーが出る Please fix pylama path or install latest version. 

###Atomでpythonしてたらこんなエラーができました。

`Please fix pylama path or install latest version. `

何か文字を打ったりすると都度、このメッセージが画面右上にポップアップが行事されて非常にうっとおしい。


どうやら「pylama」に問題があるらしい。
直す　か　最新版にして！　と怒られています。


##背景
私、実は先日からAtomを使い始めたばかりでして、利用しているpythonの入門書に記載していた通りに色々設定を進めていました。


[前提知識の確認]
Atom:テキストエディタ。windowsでいうメモ帳。ただしAtomはプログラムを書くために作られたもの。プログラムを書く際に役立つ便利な機能がたくさんある。

python:プログラミング言語の1つ。とても簡潔に作られているらしい。シンプルイズベストの考えで作られた言語とのこと。

linter:構文チェック機能。プログラムを書いているとどうしても間違えることがある。この機能があるとプログラムの構文が間違っていれば教えてくれる。Wordでいうスペルチェック機能に該当する。



Atomではそういった便利機能をパッケージとして自分が必要なもの選んでインストールすることができる。
そこで私は書籍にかいてあった「linter-python」というパッケージをインストールした。
するとAtomがこう言う。「linter-python使いたいならlinterも入れないとだめだよ！(意訳)」

そこで私は言われるがままにインストールをした。(インストールボタンが表示されているので、簡単にパッケージをインストールできる。)


linter使いたいなら○○を入れないとだめだよ！と、次から次へとパッケージをインストールさせようとするAtom。
その時の私は言われるがままにどんなものかもわからないまま、インストールボタンを押していった。

ー
ーー
ーーー
そして、今日。最初に書いたエラーが出るようになってしまったのです。


##pylamaとは？
とりあえずパッケージをインストール画面で`pylama`で検索すると、トップに`linter-pylama`が表示されます。

恐らくエラーが言っていたのはこれのことだと思われました。

※10/23諸事情により画像削除

とりあえずインストール。


##でも解決しない。次のエラーがでてくる
`Installing “linter-pylama@0.10.1” failed.Hide output…
events.js:183`
 `throw er; // Unhandled 'error' event`
      ^

`Error: ENOENT: no such file or directory, open 'C:\Users\XXX\.atom\packages\linter-pylama\node_modul`


インストールできていないらしい。
その後何度も試しましたが、変化はありませんでした。


##ググった　同じエラー出た人がいた
どうしようもないので、ググりました。

すると同じエラーが出た人がGitHubで質問をしていました！
(https://github.com/AtomLinter/linter-pylama/issues/78)

去年の質問ということもあり、バージョンの違いはありましたが非常に似ている状況です。

中には私も！俺も！と似たようなトラブルにあった人たちが集まっています。(笑)

コメントを見ていると、どうやら`linter-python`と`linter-pylama`は非常に似ていて、競合する可能性が高いから、どちらか1つだけにしたら良いらしい。

(でもAtomが両方入れるように勧めてきたんだけどな…)


##結論(?)
結果的に余計なパッケージをアンインストールしました。
これで私の場合はエラーが表示されなくなりました。

細かく言うと、一旦`linter-python`と`linter-pylama`を含めた自分で後入れしたすべてのパッケージをアンインストール。
次に`linter-python`のみを再インストールしました。


これによってエラーはなくなりました。

そのため根本的な原因ははっきりとしていません。


今回はとりあえず再インストールしておこうの考えでうまくいったというところです。

本当はどのパッケージが原因なのかはっきりとさせたかったですが‥。
(検証という意味では1つのパッケージをアンインストールごとに改善があったかを確認するべきでした。)



ただ個人的には恐らくですが私の場合も紹介したGitHubのコメントと同じで例の2つのパッケージが競合していたのではないかなと思います。
(エンジニアとしてはこれではだめですね。)

何か間違ている点などがあればコメントよろしくお願いします。


今度エラーが起きた時はしっかりと状況確認をしたいと思います。


参考になれば幸いです。
ハッカソンで使える！フロント環境爆速構築手順

# 概要
ハッカソンではとりあえず見せることが重要です。Done is Better than Perfectです。
以前ハッカソンに参加した時に、この手順はまとめといたほうがいいなと思ったので、手順を紹介します。
必要なものは下記の2つ。
- GitHub アカウント
- Netlify アカウント

## 留意点
- 公開まで無料で行くことを目標としています。使用するサービスのうち有料のオプションについては触れません
- この環境はあくまでフロントのみの環境です。DBが必要、サーバーサイドで動かすものが必要な場合、firebaseやHerokuなどの使用を検討してください

# 1. リポジトリ作成
GitHubリポジトリを用意します。無料アカウントであれば公開されたリポジトリしか作れないので、その点は注意してください。
リポジトリを作ったら、共同作業する人をCollaboratorsに追加し、次のステップへ進みます

# 2. Netlify プロジェクト作成
Netlifyとは、無料で静的なサイトをホスティングするサービスです。
GitHubと連携し、特定のブランチにマージされたらその中身をデプロイする、ということが可能です。今回はこの機能を使っていきます。

## プロジェクト作成
プロジェクトを作成します。
New site form Gitをクリック
<img width="1243" alt="スクリーンショット 2018-10-22 12.32.39.png" src="https://qiita-image-store.s3.amazonaws.com/0/140260/1d7d2ea3-5596-2d2c-ddca-1004915b4ddc.png">

Continuous DeploymentでGitHubを選択し、Only select repositoriesから1.で作ったリポジトリを登録、Installボタンをクリック
<img width="725" alt="スクリーンショット 2018-10-22 12.34.59.png" src="https://qiita-image-store.s3.amazonaws.com/0/140260/2fcc4ca6-066c-580c-c609-9411261a06dc.png">

Deploy Settingを設定します。ここでは
- どのコマンドを叩くか
- どのディレクトリを公開するのか
- どのブランチを使うのか
などを設定できます。

そのプロジェクトやフレームワークに合わせたコマンド、ディレクトリを設定してください。

これだけでホスティング完了です。お疲れ様でした。


# 備考、Netlifyの設定について
Netlifyは通常、例えば`/.dist/`フォルダなどの**ルート直下にあるディレクトリの公開を行います。**
実体験ですが、僕は構成をミスって

```
/ios/xcodeのプロジェクト
/nuxt/nuxt.jsで作ったプロジェクト
```

という意味不明なリポジトリ構成にしてしまったことがあります。なぜリポジトリわけなかったのかいまだに謎です。
しかもそれをすでにチームメンバーに伝えてしまったため、今更ディレクトリ根っこから変えます..と言えませんでした。

Netlifyでは`netlify.toml`という設定ファイルをリポジトリルートに起き、細かい設定を記述することができます。
以下は実際に使った設定です

```
[Settings]
ID = "NetlifyプロジェクトのID"

[build]
base    = "nuxt/"
publish = "nuxt/dist/"
command = "npm run generate"
```

`base`: Netlifyが動作する根っこ
`publish`: 実際に公開するディレクトリ
`command`: 叩いてほしいコマンド

もっと細かい設定ができるみたいですが、最低限これだけ使えてれば公開は可能です。
https://www.netlify.com/docs/netlify-toml-reference/
IEのインターネットオプションの信頼済みサイトにサイトを登録するbat

IEのインターネットオプションの信頼済みサイトにサイトを登録するbatを作成する。

ex)
```
@echo off
set RegRoot=HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\Domains
reg add "%RegRoot%\Exanple1.co.jp\www" /v https /t REG_DWORD /d 2 /f
reg add "%RegRoot%\Exanple2.co.jp\www" /v https /t REG_DWORD /d 2 /f

pause
```
【iOS開発メモ】AVFoundationでキャプチャデバイスの検出

AVCaptureDevice.DescoverySessionクラスを使用してiPhoneで使用可能なキャプチャデバイスを検出します。

## 使用した端末
iPhone SE（iOS 11）

## コード

```swift
import UIKit
import AVFoundation

class ViewController: UIViewController {

    var device = AVCaptureDevice.DiscoverySession(
        deviceTypes: [
            AVCaptureDevice.DeviceType.builtInWideAngleCamera,
            AVCaptureDevice.DeviceType.builtInMicrophone,
            AVCaptureDevice.DeviceType.builtInDualCamera,
            AVCaptureDevice.DeviceType.builtInTelephotoCamera,
            AVCaptureDevice.DeviceType.builtInTrueDepthCamera
        ],
        mediaType: AVMediaType.video,
        position: AVCaptureDevice.Position.unspecified
    )

    override func viewDidLoad() {
        super.viewDidLoad()
        print(type(of: device.devices), device.devices)
    }
}
```

型推論があるのでAVCaptureDevice.DeviceTypeなどは省略可能です。
mediaTypeを変えてやればマイクなどのデバイスの検出も可能。

## 出力（見やすく編集してます）

```
Array<AVCaptureDevice> 
[<AVCaptureFigVideoDevice: 0x10160d8e0 [Back Camera][com.apple.avfoundation.avcapturedevice.built-in_video:0]>,
 <AVCaptureFigVideoDevice: 0x1016134d0 [Front Camera][com.apple.avfoundation.avcapturedevice.built-in_video:1]>]
```

これでAVCaptureDvice型のオブジェクトが取得できる。
Google Earth EngineのPython APIを使おう - その２：アセットの読み書き

# はじめに

[前回](https://qiita.com/marchen/items/f86335216cae6dba6637)環境構築を行ったので、まずは基本のデータの読み書きに挑戦してみます。Earth Engineでは自分のデータのことを「アセット」と呼ぶようです。

# アセットの読み込み

## 既存のアセットの読み込み
Earth Engineにはすぐに使える様々なアセットが用意されています。このような既存のアセットを読み込むにはアセットのIDを知る必要があります。ここでは例としてJAXAが公開している「ALOS DSM: Global 30m」を読み込んでみます。まずは検索窓に「elevation Japan」と入力してアセットを検索し、ALOS DSM: Global 30m横のImportリンクをクリックしてインポートします。

<img width="667" alt="elevation Japanの検索" src="https://qiita-image-store.s3.amazonaws.com/0/92399/5b1ef58e-9731-0ce7-45a5-a8fbbb69ba0d.png">

アセットIDはアセット横の‣マークをクリックすると、`id`のところに表示されます。
この場合は`JAXA/ALOS/AW3D30_V1_1`がアセットIDになります。

<img width="690" alt="アセットIDの表示" src="https://qiita-image-store.s3.amazonaws.com/0/92399/d5ee8410-7b59-c869-5068-2eda02611959.png">

アセットIDがわかったので以下の例のようにアセットを読み込むことができます。

```python
import ee
ee.Initialize()
alos_dem = ee.Image("JAXA/ALOS/AW3D30_V1_1")
```

## ベクターデータのアップロードと読み込み
今のところ、ベクターデータ（なぜかEarth Engine上での表記はTable）のアップロードはShapefileで行う必要があるようです。Code EditorからShapefileをアップロードするときには.shp、.dbf、.shxのファイルを同時にアップロードする必要があるようです。ファイル名に複数のピリオドが入っていると最初のピリオド以降を拡張子と判断するらしく、「変な拡張子のファイルをアップロードするでない」と怒られるので注意です。他にも.cpg、.prjなども同時にアップロードできるようです。

Shapefileの仕様のため、列名の最大長は10文字になります。Geodatabaseなどから変換するときには、長い列名はあらかじめわかりやすい列名に変更しておくとよさそうです。

アップロードしたデータを読み込むには`ee.FeatureCollection`を使います。

```python
import ee
ee.Initialize()
vector_data = ee.FeatureCollection("users/{USERNAME}/{ASSET_NAME}")
```

`{USER_NAME}`は最初に指定したEarth Engine上のユーザー名、`{ASSET_NAME}`はアセット名です。アセットがフォルダに入っている場合には

```python
vector_data = ee.FeatureCollection(
    "users/{USER_NAME}/{FOLDER_NAME}/{ASSET_NAME}"
)
```

です。

## ラスターデータのアップロードと読み込み
今のところ、アップロードできるデータはGeoTiffとTFRecord+JSON（なんだそれ？）だそうです。サイズは最大10GBまで（使いたいデータが10GB以上あるんだけど、どうしようかな）。

データの読み込みには既存のアセットと同様に`ee.Image`を使います。

```python
image = ee.Image("users/{USER_NAME}/{FOLDER_NAME}/{ASSET_NAME}")
```

# アセットの書き出し

## Earth Engine上のアセットへの書き出し
アセットをEarth Engine上のアセットとして書き出すには`ee.batch`モジュールを使います。まずは書き出しタスクを作成し、それからタスクを実行、という二段階処理です。例として「ALOS DSM: Global 30m」の東京駅近辺をアセットとして書き出してみます。

```python
# ライブラリ初期化。
import ee
ee.Initialize()

# ALOS DEMの読み込み。
alos_dem = ee.Image("JAXA/ALOS/AW3D30_V1_1")

# 書き出し範囲を作成。
region = [
    [139.767, 35.681], [139.767, 35.691],
    [139.777, 35.691], [139.777, 35.681]
]

# アセット書き出しのタスクを作成。
# scaleは解像度(m)。指定しないとオリジナルの値が使われる。
export_task = ee.batch.Export.image.toAsset(
    image = alos_dem, description = "ALOS DEM Exporting Test",
    assetId = "users/{USER_NAME}/TEST_ALOS_DEM", scale = 1,
    region = region
)

# 書き出し実行。
ee.batch.data.startProcessing(export_task.id, export_task.config)
```

`{USER_NAME}`は作成したユーザー名に読み替えてください。イメージの書き出し範囲は[チュートリアル](https://developers.google.com/earth-engine/exporting#to-asset)にあるee.Geometry.Rectangleを使う方法だと`TypeError: Object of type Geometry is not JSON serializable`というエラーが発生したので、リストで書き出し範囲を指定してあります。これがPython 3を使っているからなのか、Python 2でも同じなのかはわかりません。

スクリプトを実行するとWeb上のCode EditorのTasksタブに書き出しタスクが追加され、しばらく待っているとアセット一覧に`TEST_ALOS_DEM`というイメージが追加されるはずです。

[参考ページ](https://stackoverflow.com/questions/50912548/how-to-export-results-using-python-in-google-earth-engine)

## Google Driveに保存

つづく？
【Rails5】投稿記事を検索する機能をのせたので覚えがき/form_tag

Railsでscaffoldを使い、投稿アプリを作成しました。
その中で検索窓を実装し、タイトルから検索するフォームを実装しました。
https://qiita.com/budougumi0617/items/d98fc15adea4dab438e7
この変更を参考にしましたが、覚え書きメモとして記載

【前提】
scaffold名は「review」です。
review モデル
reviewsコントローラー
review/index.htmlに投稿フォームをのせております。

reviews/indexビュー
コントローラー
モデル
ルート
に記述。


```index.html.erb
<%= form_tag reviews_path, :method => 'get' do %> 

  <p>
    <%= text_field_tag :search, params[:search] %>
    <%= submit_tag "レビューを検索する", :name => nil %>
  </p>
<% end %>
```
**メモ1: review_pathのところはモデル名に変更**

```review.rb
  def self.search(search) 
    if search
     Review.where(['gametitle LIKE ?', "%#{search}%"])
    else
     Review.all
    end
  end
```
**メモ2＆疑問**
self.でクラスメソッドとしている。
が、同じものをモデル内には書かずにコントローラーに書いたらなぜかエラーになる。
クラスメソッドにする理由はよくわかっていない。。

【ワンポイント】
ちなみにここで、
Review.where('gametitle LIKE ? OR title LIKE ?', "%#{search}%", "%#{search}%")
とすると、複数のカラムを検索対象にすることも可能でした。

```reviews_controller.rb
  def index
    @reviews = Review.search(params[:search])
  end
```



```route.rb
  resources :reviews do
    collection do
      get 'search' => 'reviews#search'
    end
  end

```

メモ3：
collection do とは、
resourcesの中にルーティングを追加する動きっぽい。
Windowsで強化学習フレームワークGoogle_Dopamineを使う

WindowsでGoogle_Dopamineを使うまで。詰まったところとか、備忘録としてまとめる。

1.環境
・window8.1
・anaconda(-python3.5)

2.構築手順
(1)必要なものをインストールする(公式を参考に進める. https://github.com/google/dopamine)
   $ pip install absl-py atari-py gin-config gym opencv-python tensorflow
![image.png](https://qiita-image-store.s3.amazonaws.com/0/268002/384478c9-3711-f459-9b03-bbfa134676e1.png)
atari-pyがビルドできなくてインストールエラー。
   ↓を入れて再トライ。

```
$conda install -y cmake
$conda install -y zlib
```

まだできない。

どうやらwindows用のatariがあるっぽい?

```
$pip install --no-index -f https://github.com/Kojoley/atari-py/releases atari_py
```

参考URL：https://stackoverflow.com/questions/42605769/openai-gym-atari-on-windows?rq=1
         https://github.com/openai/atari-py
         http://daruma3940.hatenablog.com/entry/2017/08/13/030344

無事インストールできたっぽい。

(2)動作を確認する
公式からダウンロード。
```
$git clone https://github.com/google/dopamine.git
```
これが動けばとりあえずインストールは成功しているらしいが,,,

```
$cd dopamine
$python tests/atari_init_test.py
```

エラーでました。No Such File or Directoryみたいなのが書いてある。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/268002/7dff2f29-528f-7524-e306-2c12878f308b.png)

いろいろ調べてたら、
dopamine\tests\atari_init_test.pyのsetUpを以下のように変更。

```python:atari_init_test.py
def setUp(self):
    FLAGS( [ '--gin_files' ] )
    FLAGS.gin_files = ['dopamine/agents/dqn/configs/dqn.gin']
    FLAGS.base_dir = os.path.join(
        'C:/workspace/git/dopamine/tmp/dopamine_tests',
         datetime.datetime.utcnow().strftime('hogehoge'))
    FLAGS.agent_name = 'dqn'
    # `num_iterations` set to zero to prevent runner execution.
    FLAGS.gin_bindings = [
        'Runner.num_iterations=0',
        'WrappedReplayBuffer.replay_capacity = 100'  # To prevent OOM.
    ]
    FLAGS.alsologtostderr = True
```

あと、フォルダへのアクセスエラーも出て他ので、\dopamine\tmp\dopamine_tests\hogehogeを追加して、
作業フォルダへのパスも追加したらできた。
参考URL：https://stackoverflow.com/questions/52086240/dopamine-memory-error-and-attribute-error-in-rainbow-agent-test-py
　　https://github.com/google/dopamine/issues/13
GitLabでプッシュしたらSlackにメッセージを飛ばす

# 【経緯】
GitLabでファイルコミットした時に一々Slackでメッセージ入力して送信するのがめんどい。
調べたらGitLabとSlackの機能で簡単に対応出来そうだったので、やってみました。
自分の手順ではアプリを作成してますが、単純に特定のチャンネルに通知を飛ばしたいだけならアプリを作成する必要はなさそうです。
（参考にさせて頂いた方達のように、Incoming WebHooksを使用すればもっと簡単に通知出来そう）
ただし自分の場合は同じアプリを使用して、別々のWebhook URLを作成して、別々のSlackのチャンネルに通知を飛ばしたかったのでアプリ自作することで実現しています。
個人で使っているGitLabのバージョンは8.9.6です。

#【Slack APIの設定】
1. [Slack API](https://api.slack.com/)にアクセス
2. 「Incoming webhooks」のリンクを押下して、「Create your Slack app」を押下
3. 下記の画面で作成するアプリの名前、Webhooksを利用したいワークスペースを選択して「Create App」を押下<br>
![image.png](https://qiita-image-store.s3.amazonaws.com/0/249041/dd17c834-9326-df23-d382-6d9797408d6d.png)<br>
4. 「Basic Information」の「Display Information」でアプリ名、アプリの説明、アプリアイコン、背景色が設定できるので任意で変更<br>
![8.PNG](https://qiita-image-store.s3.amazonaws.com/0/249041/98575999-5b7a-6f29-7698-7ff27dfa248e.png)
5. 「Incoming Webhooks」を「On」にして、「Add New Webhook to WorkSpace」を押下<br>
![6.PNG](https://qiita-image-store.s3.amazonaws.com/0/249041/eae4391a-a850-a409-51a1-0cdf5ef6d217.png)<br>
![7.PNG](https://qiita-image-store.s3.amazonaws.com/0/249041/41f53b7a-8122-2f74-a112-cedf79ceb023.png)<br>
6. 連携したいワークスペース、投稿先のチャンネルを確認してOKなら「許可する」を押下
7. 「Webhook URL」の一覧に指定したWebhook URLが作成されていることを確認

#【GitLabの設定】
1. リポジトリの画面右にある歯車マークから「Service」を選択
![1.png](https://qiita-image-store.s3.amazonaws.com/0/249041/b2cce047-933c-1cda-654d-d8721907ecb8.png)<br>
2. サービスの一覧から「Slack」を選択
![2.PNG](https://qiita-image-store.s3.amazonaws.com/0/249041/f72438f9-0504-9f71-e3db-bc677b980c78.png)<br>
3. 任意のイベントを設定して「Active」にチェックを入れる
![3.PNG](https://qiita-image-store.s3.amazonaws.com/0/249041/b1c01200-10aa-2f9f-c009-cf64517b87bf.png)<br>
4. 「Webhook」の入力欄にSlack APIの設定で作成したWebhook URLを入力
5. 「Save Changes」を押下して設定を保存
6. 保存完了すると出てくる「Test settings」を押下してメッセージが飛んでくれば成功

# 【課題点】
当然なんですが「Push events」をフックしているので、ローカルリポジトリだろうとmasterだろうと関係なく通知が飛んできます。
頻度が少ないリポジトリや人数が少ないリポジトリなら問題ないと思いますが、大人数だったり頻繁に更新あったりするリポジトリには向かなそうです。
また、Slackの無料ユーザーだとワークスペースに追加できるアプリが10個までのようなので、他の人と今共有のワークスペースだったりアプリ数上限にひっかかっている（もしくはひっかかりそうな）ワークスペースには苦しいかも。
Git hookとIncoming Webhooksを使えば何とかなる要件だと思うので、アプリ数を圧迫したくない場合はそちらで対応。

# 【参考】
・https://qiita.com/M4e/items/c26d938e73830b0ba6b9
・https://qiita.com/txmy/items/975ef6e05842970fada0
・https://qiita.com/yuukiw00w/items/94e4495fc593cfbda45c
findとxargsでsleepしながらファイル移動する

大量のファイルを扱う際に、サーバー負荷を減らすためにsleepでウェイトしながら移動させたい時なんかに。

```
find ./src/*.zip -print -exec sleep 0.5 \; | xargs -n1 -I%% mv -v %% ./dest/
```

findのexecでsleepを入れつつ、xargsでは標準出力から受け取った結果を`-n1`の指定で1行ずつ`%%` をプレースホルダとしてmvコマンドで移動する。
Xcode で Breakpoint を一括で削除する方法

1. 左のペインに Breakpoint Navigator を表示
2. Workspace 右クリックして「Delete Breakpoints」選択
3. これですべての Breakpoint が消える

![image.png](https://qiita-image-store.s3.amazonaws.com/0/8292/6a61a14d-e239-61d7-8715-9220bcca869f.png)
finally節の中にreturnを書いてはいけない

例外が握りつぶされる事件が発生したので備忘録として残しておきます。。~~ドキュメント軽くさらった感じだと書いてなかった...?~~[^1]

#### 10/23 追記

@links_2_3_4 さんから情報をいただきました。下記ページに記載があります。
[8. 複合文 (compound statement) — Python 3.7.1 ドキュメント](https://docs.python.org/ja/3/reference/compound_stmts.html#the-try-statement)

> finally 節で return 文あるいは break 文を実行した場合は、保存された例外は破棄されます

以下のような書き方をすると例外が握り潰されます。

```python3:python3
def hoge():
    try:
        raise Exception("例外発生")

    except Exception as e:
        print("hoge内で例外発生")
        raise e

    finally:
        # 処理
        return "返り値"

def fuga():
    try:
        res = hoge()
    except Exception as e:
        print(f"fugaで例外検知: {str(e)}")

if __name__=="__main__":
    fuga()
```

```plain:実行結果
hoge内で例外発生
```

本来は単に外に書くか、`else`節内に書くべきだったのですよね。。なんか自分血迷ってたみたいです[^2]。

```python3:python3
def hoge():
    try:
        raise Exception("例外発生")

    except Exception as e:
        print("hoge内で例外発生")
        raise e

    finally:
        # 処理
        pass

    return "返り値"

def fuga():
    try:
        res = hoge()
    except Exception as e:
        print(f"fugaで例外検知: {str(e)}")

if __name__=="__main__":
    fuga()
```

```plain:実行結果
hoge内で例外発生
fugaで例外検知: 例外発生
```

「例外が無視されてる?!?」と思ったら今一度`return`の位置を確認するといいのかもしれません。
それにしてもこれは気づかないよなぁ...暗黙に握りつぶすぐらいなら文法エラーにしてほしいと個人的には思いました()

読んでいただきありがとうございます。いろいろご指摘くださると幸いです。m(_ _)m

[^1]: 私のググラビリティは低いです。悪しからず。
[^2]: `finally`を使用していたのは`splite3`のカーソルみたいに閉じる処理が必要なものがあったからです。本当は例として挙げているコード中に含めるべきかとは思いましたが冗長かと思い省略しました。
Eclipseにてantを使用する方法

 Eclipseを起動し、メニューバーから下記を選択
 ウィンドウ → ビューの表示 → その他 → [Ant]のディレクトリ → Antを選択

Antのビューが表示されるので
そのビューの中に使用したいXMLファイルパッケージエクスプローラーからドラッグ&ドロップ
ダブルクリックにて実行が可能になる
PHPでは関数内に関数を書けるしグローバル関数になる

ちょっと何言ってるのかわからない。


# 関数内関数

```php:PHP
function foo(){
	echo 'foo';
	function bar(){
		echo 'bar';
	}
}

foo(); // foo
bar(); // bar ← ！？
```

マジかよ。

実はしっかり[マニュアル](http://php.net/manual/ja/functions.user-defined.php)にも書かれている仕様です。

仕様ではあるのですが、つい先日までこの文法を知らなかったので、初めて見たとき面食らいました。
そもそもPHPで関数内に関数を書くという発想がなかったからということもありますが、普通はこれ関数内に閉じこもるでしょう。

```js:JavaScript
function foo(){
	console.log('foo');
	function bar(){
		console.log('bar');
	}
}

foo(); // foo
bar(); // bar is not defined
```

一手加えるだけで[クロージャ](https://qiita.com/shuuuuun/items/7ddf77573f1169e61b51)になるやつだ。

ではPHPではクロージャができないのかというともちろんできます。

```php:PHP
function foo(){
	echo 'foo';
	return function(){
		echo 'bar';
	}
}

$foo = foo(); // foo
$foo(); // bar
```

関数内の関数をreturnすることで、クロージャとして使えるようになります。
外側の値を使うには[useが必要](https://qiita.com/tricogimmick/items/3e344486658e3cfbd407)でJavaScriptより少しだけ面倒ですが。

でも私がこれを書くことになったとしたら、たぶんこう書きます。

```php:PHP
class foo{
	public function __construct(){
		echo 'foo';
	}
	public function bar(){
		echo 'bar';
	}
}
$foo = new foo(); // foo
$foo->bar(); // bar
```

クラスのなかったJavaScriptでクロージャが発展したのはわからないでもないですが、[PHPにクロージャがあって](https://wiki.php.net/rfc/closures)何が嬉しいのか、未だによくわかりません。
そもそもPHPのクロージャって[Closureクラス](http://php.net/manual/ja/class.closure.php)ですし。
クロージャがなければこれができなかった！みたいなのって何かあるんですかね？

まあ無名関数はarray_mapとかで時々使うんですが、[マニュアル](http://php.net/manual/ja/functions.anonymous.php)には『無名関数はクロージャとも呼ばれ』とか書いてあるんだけど別物だよね？？？

```php:無名関数
$foo = function(){
	echo 'foo';
};

$foo(); // foo
```


# 関数内変数

これは当然グローバル展開されません。

```php
function foo(){
	$bar = 1;
}

foo();
echo $bar; // Undefined variable: bar
```

変数は見えないのに関数は外に出る。
なぜなのか。

…はて、そういえば変数以外はどうなるんだ？


# 関数内クラス

```php
function declareClass(int $id){
	if($id===1){
		class HOGE{
			public function __construct(){echo '$idは1';}
		}
	}else{
		class HOGE{
			public function __construct(){echo '$idは1以外';}
		}
	}
}

declareClass(1);
new HOGE(); // $idは1

declareClass(2); // 1ファイル内で書くとCannot declare classになる
new HOGE(); // $idは1以外
```

クラスもグローバルになるようです。
つまり、これを使えばDIできるというわけですね(できない)。


# 関数内インターフェイス、トレイト

```php
function foo(int $id){
	if($id===1){
		interface HOGE{
			const bar = 1;
		}
		trait FUGA{
			public function baz(){
				return 1;
			}
		}
	}else{
		interface HOGE{
			const bar = 2;
		}
		trait FUGA{
			public function baz(){
				return 2;
			}
		}
	}
}

foo(2);

class HOGE2 implements HOGE{
	use FUGA;
}
$a = new HOGE2();
echo $a::bar, $a->baz(); // 2,2
```

`foo(1)`としたら`$a::bar`も`$a->baz()`も1になります。
traitやinterfaceもグローバルに展開されるようです。

つまり、関数の中身は基本的にグローバルなんだけど、変数だけわざわざ関数外から見えないようにされているだけ、ということのようです。
なんだか元々関数に抱いていたイメージと全く逆なかんじの実装になっていました。
顔写真に泣きぼくろをつけるサイトを作りました（jsの顔認識ライブラリ「clmtrackr」の使い方）

# 目次

- 1. 作ったWebアプリの紹介
- 2. JaveScriptの顔認識ライブラリ「clmtrackr」の紹介・使い方

# 1. 作ったWebアプリの紹介

泣きぼくろのある子がすごく好きです。
篠崎愛さんとか。

このサイトは、可愛い子を見たときに思う「もしこの子に泣きぼくろがあったらさらに可愛いのにな…」という気持ちを叶えるために作りました。

http://tear.laineus.com

（[GitHub](https://github.com/laineus/tear)）

![Screenshot from 2018-10-20 23-54-26.png](https://qiita-image-store.s3.amazonaws.com/0/151137/81ff360c-f0ca-3b77-b478-9ca133cac62a.png)

↑こんな感じです。
顔認識の精度が結構シビアで、かなりしっかり写った顔写真でないとなかなか認識してくれません…。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">泣きぼくろある女の子が好きなあまり、顔写真に泣きぼくろをつけるだけのサイトを作りました。<a href="https://t.co/RjQbixIRNL">https://t.co/RjQbixIRNL</a><br><br>証明写真並にはっきり顔が写ってないと認識されないかもしれません。</p>&mdash; らいね (@Laineus) <a href="https://twitter.com/Laineus/status/1054333416127242241?ref_src=twsrc%5Etfw">2018年10月22日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

↑よければRTください！

# 2. JaveScriptの顔認識ライブラリ「clmtrackr」の紹介・使い方

[clmtrackr](https://github.com/auduno/clmtrackr)

Canvasに描画された画像から顔を認識してくれるライブラリです。

うまく認識されると、最終的に下図のポイントに対応する座標を取得できます。

![68747470733a2f2f617564756e6f2e6769746875622e696f2f636c6d747261636b722f6578616d706c65732f6d656469612f666163656d6f64656c5f6e756d626572696e675f6e65775f736d616c6c2e706e67.png](https://qiita-image-store.s3.amazonaws.com/0/151137/e81de342-a82f-3ee6-54cc-425586a3b769.png)

今回作ったサイトでいうと、23と1（28と13）の間の座標を計算して、そこにそれっぽい円を描画しています。

## 使い方

npmやyarnで使う場合、clmtrackrをインストールします。

```bash
$ yarn add clmtrackr
```

ソースを落としてきてhtml内で直接読み込んでもokです。

インスタンス化してinit()を実行します。

```js
const ctrack = new clm.tracker({ stopOnConvergence: true })
ctrack.init()
```

`stopOnConvergence`をtrueにすると、顔の検出に成功したときにtrackingを自動でstopしてくれます。

`start()`でtrackingを開始します。
第一引数には対象のcanvasエレメントを渡しましょう。

```js
const canvas = document.getElementById('canvas')
tracker.start(canvas)
```

track開始後は、`getCurrentPosition()`関数で冒頭で記述した顔の座標情報を取得できます。
この関数の結果は、stopされるまで随時更新されていきます。

```js
tracker.getCurrentPosition()
```

検出できていなければfalseが返ってきます。
開始3秒後くらいから検出できる感じです。

また、トラッキングに成功したとき、失敗したときに下記のイベントが発火します。

```js
document.addEventListener('clmtrackrConverged', () => console.log('Converged'))
document.addEventListener('clmtrackrLost', () => console.log('Lost'))
```


うまく検出できない場合、どっちのイベントも発火せずtrackingし続けるようです。
また、Convergedにならなくても、ある程度正しい顔の座標が取れている場合などもありました。

（※ Lostとみなすしきい値はインスタンス化する際にオプションで設定できます。）

今回実装したサイトではLostとかConvergedとかガン無視して、実行後nフレームたったら`tracker.getCurrentPosition()`をチェックして判定する、という実装にしてしまいました。

### 注意

webpackでproductionビルドすると、下記の問題が発生しました。
https://github.com/auduno/clmtrackr/issues/132

なんとなくwebpackやめてparcelにしたら直ったので、webpackでの解決策は存じません。

# おわりに

僕がこのサイトを作って学んだことは、Parcelがとても便利だということと、泣きぼくろは目尻から輪郭に向かって40%進んだ位置に、顔の横幅に対して0.6%の大きさで配置するとベストだということです。

# 引用

画像素材
https://www.pakutaso.com/20180312064post-15433.html
設定したエイリアスを確認するコマンド

`.zshrc`などに設定した`alias`をコマンドで確認する方法

## aliasを設定

`.zshrc`

```
alias hoge="echo hoge"
```

## aliasを確認する

```
$ alias
```

以下のように出力される

```
hoge='echo hoge'
```