OmniAICreator/Qiita-1.07M huggingface dataset:
VoltDB 8.2リリース。古いデータを自動で削除するTTL機能を試してみました

# VoltDB 8.2リリース(2018年7月12日)

2018年7月12日にVoltDB 8.2がリリースされていました。

[この記事](https://qiita.com/mkyz08/items/1a1f8c9ce7f91293a5b1)で既にインストールして触っているのですが、改めて変更内容を確認したいと思います。

* 古いデータを自動で削除するTTL機能
* VoltDBコマンドラインで、ファイルからユーザ名とパスワードを読み取ることができる
* ファイルのエクスポート時にクラスタ全体で一意のファイル名を作成するオプションの追加
* スナップショットのリストア時のパフォーマンス向上
* sqlcmdユーティリティは、DESCRIBE テーブル名ディレクティブをサポート
* セキュリティ強化
* その他の改善

この内、興味がもったTTL機能について実際に使用してみたいと思います。


# 古いデータを自動で削除するTTL機能

「time to live」（TTL）機能は、個々のテーブルに対して、データの有効期限を定義することができます。有効期限（TTL値）を過ぎると、そのテーブルのレコードが自動的に削除されます。

## スキーマ定義

sqlcmdコマンドからテーブルを作成します。
CREATED_TIMESTAMPカラムがTTLを判断するデータとなります。レコード作成時に現在の日時が自動で入ります。なお、CREATED_TIMESTAMPカラムにはインデックスを作成しておく必要があります。
「USING TTL」にてTTLを定義しており、CREATED_TIMESTAMPカラムを見て、1分経過後に削除するようにしています。
クラスタ構成の場合はいずれか1台のサーバで実行します。
NOT NULL制約があればINTEGER、BIGINT、またはTIMESTAMPの列をTTL列として利用できます。


```sql
# sqlcmd
SQL Command :: localhost:21212
1> CREATE TABLE TEST_DATA_TTL (
  2>    NAME varchar(50) NOT NULL,
  3>    DATA smallint,
  4>    CREATED_TIMESTAMP TIMESTAMP DEFAULT NOW NOT NULL,
  5>    UNIQUE (NAME),
  6>    PRIMARY KEY (NAME)
  7> ) USING TTL 1 MINUTES ON COLUMN CREATED_TIMESTAMP;
Command succeeded.
> PARTITION TABLE TEST_DATA_TTL ON COLUMN NAME;
Command succeeded.
> CREATE INDEX TEST_DATA_TTL_IDX ON TEST_DATA_TTL ( CREATED_TIMESTAMP );
Command succeeded.
```

テストデータをインサートします。

```sql
> insert into test_data_ttl(name, data) values('test001', 1);
```

検索してみると、以下のように作成されていました。

```sql
> select *, now() as now from test_data_ttl;
NAME     DATA  CREATED_TIMESTAMP           NOW                        
-------- ----- --------------------------- ---------------------------
test001      1 2018-08-26 04:18:14.139000  2018-08-26 04:19:12.912000 

(Returned 1 rows in 0.01s)
```

1分経過後に同じSQLを実行すると0件となり、レコードが自動で削除されたことを確認できます。

```sql
> select *, now() as now from test_data_ttl;
NAME  DATA  CREATED_TIMESTAMP  NOW 
----- ----- ------------------ ----

(Returned 0 rows in 0.00s)
```


##　Statisticsシステムプロシージャ

Statisticsシステムプロシージャにて、テーブルごとに削除されたレコード数などTTLの処理に関する情報を表示することができます。

```sql
> exec @Statistics TTL TEST_DATA_TTL;
TIMESTAMP      TABLE_NAME     ROWS_DELETED  ROWS_DELETED_LAST_ROUND  ROWS_REMAINING  LAST_DELETE_TIMESTAMP      
-------------- -------------- ------------- ------------------------ --------------- ---------------------------
 1535258021467 TEST_DATA_TTL              2                        0               0 2018-08-26 04:33:41.120000 

```


## 注意点

色々と注意点もあるので、もう少し利用するユースケースに合わせて検証してみないと使うかどうかは判断できないです。

* TTL用のカラムがテーブルに存在していない場合は新たにカラムを追加し、インデックスも必要となるためメモリサイジングへ影響します。
* TTLは、パーティション表で使用すると効果的ですが、レプリケートテーブルではパフォーマンスへの影響があるため好ましくありません。
* 高負荷になったり、大量の挿入があるとTTL処理が遅れる可能性があります。
* データベースレプリケーション（DR）を使用すると、TTLトランザクションがDRバイナリログの50MB制限を超える可能性があります。 この場合、警告が発行され、TTL処理が中断されます。
Macバックアップ自動化 〜ポストTime Capsule〜

## やったこと
- 自動バックアップ構築(今回はローカル)

参考：[TimeCapsuleが生産終了になったので、Wifiルーター + ネットワークHDD（NAS）に移行しました - give IT a try](https://blog.jnito.com/entry/2018/05/01/054235)

## 重要テーマ
- TimeCapsuleが生産終了
- セキュリティ面やWifi規格のサポートを考慮すると今後別手段が必要
 
## ポイント
- バックアップはまめにとる必要があるが面倒

　自動化前提(Time Mahine利用)


- 有線キライ


- 安全性を増すため複数バックアップ

　クラウド(メイン) ＋ ローカル(保険)　-> クラウドは次回に
 
## 構成
 ハードを探し出すとキリがないのでブログを参考に

![スクリーンショット 2018-08-27 0.08.43.png](https://256interns.storage.googleapis.com/images/images/000/000/831/normal/%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%83%E3%83%88_2018-08-27_0.08.43.png?1535370529)



 - HG8045Q(ONU)

 - ASUSの[RT-AC68U](https://www.amazon.co.jp/gp/product/B00GJIEYBI/ref=oh_aui_detailpage_o04_s00?ie=UTF8&psc=1)(ルーター)

 - テキトーな[HDD](https://www.amazon.co.jp/DATA-%E5%A4%96%E4%BB%98%E3%81%91%E3%83%8F%E3%83%BC%E3%83%89%E3%83%87%E3%82%A3%E3%82%B9%E3%82%AF-%E3%83%86%E3%83%AC%E3%83%93%E9%8C%B2%E7%94%BB-%E5%9C%9F%E6%97%A5%E3%82%B5%E3%83%9D%E3%83%BC%E3%83%88-EX-HD2CZ/dp/B06Y4584PL/ref=sr_1_1?s=computers&ie=UTF8&qid=1535295204&sr=1-1&keywords=EX-HD2CZ)（今回はIOdataに）


ONUはNURO契約時のデフォルト。nuro光ケーブルが繋がる

ルーターでWi-Fiを飛ばす。ASUSは狙い撃ちで電波をとばせるそう

HDDはルーターに繋ぐ事でUSB記録装置が無線で使える

> あとから気づいたのですが、RT-AC68Uは普通の外付けHDDをUSB接続するだけでTimeMachine対応のNASを構築できるみたいです。

との事できちんとブログを参考に手頃なHDDに♪
ここも探し出すとキリがないので^^;

## セットアップ
- ルーターにファンネルを取り付け♪
- マニュアルに沿ってWifiを接続
- ファームウェアを更新して最新のOSに対応させる⇐重要

そして速度チェーック


### は、速い💦

![スクリーンショット 2018-08-27 20.28.57.png](https://256interns.storage.googleapis.com/images/images/000/000/832/normal/%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%83%E3%83%88_2018-08-27_20.28.57.png?1535370557)


HUAWEIのONUでもそこそこ早かったけど、
ASUSの５Gに繋いだらこんな顕著な結果に💦
無線でコレはなかなかなのでは。

- Time Machineの設定(ルーター側)

ブラウザでルーターの設定画面にいくと
Time Machineのメニューがあり非常にわかり易い💡

![スクリーンショット 2018-08-27 0.38.43.png](https://256interns.storage.googleapis.com/images/images/000/000/833/normal/%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%83%E3%83%88_2018-08-27_0.38.43.png?1535370585)



GUIでポチポチHDDを選択するだけで簡単にルーター側の設定が完了

![スクリーンショット 2018-08-25 16.53.33.png](https://256interns.storage.googleapis.com/images/images/000/000/834/normal/%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%83%E3%83%88_2018-08-25_16.53.33.png?1535370608)



- Time Machineの設定(mac側)

"Time Machine環境設定"でASUSサーバーをディスクに選択し
ルーターで設定したユーザとパスを入力すれば設定完了

![スクリーンショット 2018-08-27 0.17.58.png](https://256interns.storage.googleapis.com/images/images/000/000/835/normal/%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%83%E3%83%88_2018-08-27_0.17.58.png?1535370628)



## バックアップしてみた
初回は200GB以下で、10時間程かかったが、
二回目以降は数分でバックアップが取れていた（勿論自動で）👍


## まとめ
Time Machineで自動化＆無線でバックアップ環境が整ってTime Capsuleの代替に良さそう。
ASUSのルーターの性能が思いの外良く、ひとまずバックアップを取るだけなら問題なさそう。次回はコレで復元をしてみる

ルーター、HDD合わせて２万くらいで手頃。セットアップも簡単で１０〜２０分で済み手軽。このルーターは他にも色々クラウド機能等があるようなのでいろいろ弄ってみると面白いかもしれない。

ただ今回RT-AC68Uがアマゾンで注文してから珍しく２０日もかかったので、品薄なのかも。ASUSの新しいモデルの方が入手し易いかもしれない。
eclipseのメモリを増やしたい

## 経緯
デフォルトではメモリの割り当てが少ないので、増やす。

## `eclipse.ini`を編集。

```ini:eclipse.ini
-startup
plugins/org.eclipse.equinox.launcher_1.4.0.v20161219-1356.jar
--launcher.library
plugins/org.eclipse.equinox.launcher.win32.win32.x86_64_1.1.551.v20171108-1834
-product
org.eclipse.epp.package.php.product
-showsplash
org.eclipse.epp.package.common
--launcher.defaultAction
openFile
--launcher.defaultAction
openFile
--launcher.appendVmargs
-vmargs
-Dosgi.requiredJavaVersion=1.8
-Dosgi.instance.area.default=@user.home/eclipse-workspace
-XX:+UseG1GC
-XX:+UseStringDeduplication
--add-modules=ALL-SYSTEM
-Dosgi.requiredJavaVersion=1.8
-Xms256m  ★ココと
-Xmx1024m ★ココ
--add-modules=ALL-SYSTEM
-Xverify:none
-javaagent:plugins/jp.sourceforge.mergedoc.pleiades/pleiades.jar
```

* **-Xms**：起動時のヒープサイズ
* **-Xmx**：最大ヒープサイズ


この二つの値を大きくする。でも大きくしすぎると起動しなくなっちゃう模様。


## おわり
参考：[[Java開発]eclipse.iniファイルのメモリ設定 | KENスクールブログ](https://www.kenschool.jp/blog/?p=2322)
Amazon EC2 セキュリティグループ

##1.セキュリティグループとは？##
・Amazon EC2 インスタンスに適用可能なAWS標準のファイアウォール機能であり、EC2インスタンスへのアクセスを"許可"したり、トラフィックを"制御"することができます。



##2.注意点##

- インバウンド：未設定の場合通信は全て遮断し、許可した通信のみを通過させます。
＊デフォルトですべて拒否
- アウトバウンド：自動的にデフォルトのセキュリティグループが適用されます。
＊デフォルトですべて許可

EC2インスタンス起動時にセキュリティグループを指定しなかった場合、インスタンスは自動的にこのデフォルトのセキュリティグループで起動されてしまうので必ず、設定は確認するようにしましょう。

参考：[セキュリティグループのルールのリファレンス](https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/security-group-rules-reference.html)

- 重複した制限は緩い方が優先される。許可されたインバウンドに対する応答（戻りのトラヒック）はアクトバウンドで制限があっても、通過することができる。


##3.設定方法##
AWS EC2インスタンス一覧の画面を開き、左メニューにある「セキュリティグループ」より、作成や編集をすることができます。
![スクリーンショット 2018-08-28 21.37.21.png](https://qiita-image-store.s3.amazonaws.com/0/280929/31f35504-4649-5196-4fe5-e91bfd6c7fa4.png)



##4.セキュリティを高める##
・必要なポートだけを開放する。
・SSHやRDPなどサーバ管理を行うプロトコルは指定IPアドレスのみからのアクセスを許可する。



##5.NACL##

- セキュリティグループは、EC2ごとにファイヤーウォールを設定する、ステートフル。
-  NACLは、サブネットごとにファイヤーウォールを設定する、ステートレス。

なので、NACLはインバウンドもアウトバウンドも許可/拒否する設定をしなければいけない。
![スクリーンショット 2019-02-10 12.17.47.png](https://qiita-image-store.s3.amazonaws.com/0/280929/09dbb6f6-8ba5-995c-d746-c7629908370f.png)

NACLとセキュリティグループはどちらが優先されるのか？
![スクリーンショット 2021-03-29 18.38.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/91574f52-c773-be2b-f0c9-ba77d56007db.png)
この図の通り、例えば外部からの通信がある場合、セキュリティグループで許可されていても、NACLで拒否されていれば通信できないこととなる。
Asteriskのパーミッション設定

Asteriskは今までrootで起動していましたが、専用のユーザ名で起動する方法を調べてみました。

## ユーザを追加

```bash
# useradd asteriskpbx
# passwd asteriskpbx
```

## ユーザをグループwheelに追加
```bash
# usermod -aG wheel asteriskpbx
```
たぶん特に必要はない。
ユーザasteriskpbxでsudoできることを確認する。
できないときは`# visudo`を確認する。

## asterisk.confでユーザ名、グループ名を設定
```/etc/asterisk/asterisk.conf
[options]
runuser = asteriskpbx
rungroup = asteriskpbx
```

## 所有権、パーミッションを設定

asterisk.confの[directories]コンテキストに出てくるディレクトリに設定すればいいです。

```bash
# chown -R asteriskpbx:asteriskpbx /var/lib/asterisk
# chown -R asteriskpbx:asteriskpbx /var/log/asterisk
# chown -R asteriskpbx:asteriskpbx /var/spool/asterisk
# chown -R asteriskpbx:asteriskpbx /var/run/asterisk
# chown -R asteriskpbx:asteriskpbx /etc/asterisk
# chown -R asteriskpbx:asteriskpbx /usr/lib/asterisk

# chmod -R u=rwX,g=rX,o= /var/lib/asterisk 
# chmod -R u=rwX,g=rX,o= /var/log/asterisk 
# chmod -R u=rwX,g=rX,o= /var/spool/asterisk 
# chmod -R u=rwX,g=rX,o= /var/run/asterisk
# chmod -R u=rwX,g=rX,o= /etc/asterisk
# chmod -R u=rwX,g=rX,o= /usr/lib/asterisk
```

あとで設定ファイルなどを編集後に再読込して読んでないと思われるときは、多分パーミッションが原因なので、確認してもう一度パーミッションの設定をします。

##サービス（再）起動、ユーザ名が正しいことを確認
コンソールに入るとき（`asterisk -r`）はrootでもかまわない。

```bash
$ sudo systemctl start asterisk

$ sudo asterisk -rvvvvv
Asterisk 13.22.0, Copyright (C) 1999 - 2014, Digium, Inc. and others.
Created by Mark Spencer <markster@digium.com>
Asterisk comes with ABSOLUTELY NO WARRANTY; type 'core show warranty' for details.
This is free software, with components licensed under the GNU General Public
License version 2 and other licenses; you are welcome to redistribute it under
certain conditions. Type 'core show license' for details.
=========================================================================
Running as user 'asteriskpbx'
Running under group 'asteriskpbx'
Connected to Asterisk 13.22.0 currently running on rpi (pid = 5616)
rpi*CLI> 
```

ユーザ名、グループ名はAsterisk: The Definitive Guide, 4th Editionの例に従ってasteriskpbx:asteriskpbxとしています。
DAHDIはインストールしていないので省略しています。

環境
Vultr 東京リージョン Centos 7 x64
CentOS Linux release 7.5.1804 (Core)
Raspberry Pi 3B + Raspbian
Asterisk 13.22.0
GAE/goで外部APIを使った際にハマったところ

# はじめに
Goで書いたbotをGAEで運用しようとした際、通信部分(外部APIへのリクエスト)で地味にハマったため簡単にまとめていこうと思います。

## 実行環境
ローカル：Go v1.10.1
GAE：Go v1.10

# Google App Engine(GAE)とは
[Google App Engine(GAE)とは?](https://cloud.google.com/appengine/docs/whatisgoogleappengine?hl=ja)
> Google App Engine は、Google のインフラの上でアプリケーションを作り、実行できるようにする PaaS （ Platform as a Service : サービスとしてのプラットフォーム）です。App Engine アプリケーションは、作るのもメンテナンスするのも簡単で、トラフィックやデータストレージのニーズの増減にあわせてスケーリングするのも簡単です。App Engine を使えば、自分でメンテナンスしなければならないサーバーはなくなります。単純にアプリケーションをアップロードすれば、それだけで実行できます。

Googleが提供しているクラウドサーバーです。

# 外部APIを扱う
通常Getリクエストを行う場合は`http.get(url)`を行えばよいが、GAEで行う場合は`Context`を使うことを配慮しなければなりません。

## ローカルで実行する場合

```main.go
func main() {
	http.HandleFunc("/", handler)
	http.ListenAndServe(":8080", nil)
}

func handler(w http.ResponseWriter, r *http.Request) {
	response, err := http.Get(url)
	if err != nil {
		log.Println(err)
	}
	if response != nil {
		defer response.Body.Close()
	}

	body, err := ioutil.ReadAll(response.Body)
	if err != nil {
		log.Println(err)
	}

	fmt.Println(body)
}
```

## GAEの場合
```main.go
func main() {
	http.HandleFunc("/", handler)
	appengine.Main()
}

func handler(w http.ResponseWriter, r *http.Request) {
	context := appengine.NewContext(r)
	httpClient := urlfetch.Client(context)

	response, err := httpClient.Get(url)
	if err != nil {
		log.Println(err)
	}
	if response != nil {
		defer response.Body.Close()
	}

	body, err := ioutil.ReadAll(response.Body)
	if err != nil {
		log.Println(err)
	}

	fmt.Println(body)
}
```

# ハマったポイント
ローカルで実行する場合は`http.Get(url)`でよかったが、GAEで行う場合は`appengine.NewContext(*http.Request)`でcontextを作成し、`urlfetch.Client(context)`のように`urlfetch`を利用してリクエストを行わなければならなかった。

# まとめ
GAEの場合は通常と異なり、GAEのContextを作成し、urlfetchを用いてリクエストを行うことが必要になります。

```.go
func handler(w http.ResponseWriter, r *http.Request) {
    context := appengine.NewContext(r)
    httpClient := urlfetch.Client(context)

	response, err := httpClient.Get(url)
	if err != nil {
		log.Println(err)
	}
	if response != nil {
		defer response.Body.Close()
	}
}
```
# 参考
[The urlfetch package](https://cloud.google.com/appengine/docs/standard/go/urlfetch/reference)
[goでのhttpの書き方あれこれ](https://ema-hiro.hatenablog.com/entry/2017/10/03/030248)
サーバーサイドレンダリングできないモジュールの扱い方

## はじめに

[Svelte](https://svelte.technology/) 版 [Next.js](https://github.com/zeit/next.js/) の [Sapper](https://sapper.svelte.technology/) というフレームワークで画面を作っていたのですが、そこで [Handsontable](https://handsontable.com/) を使おうとして詰まったので対応方法をメモ書きとして残しておきます。

Sapper に限らず、Next.js、Nuxt.js など最近のフレームワークでは、デフォルトでサーバーサイドレンダリングが有効になっています。ところが、そこで使いたいモジュールの多くは、window や document などブラウザ特有のオブジェクトに依存しているため、そのまま import してサーバーサイドレンダリングを行うと実行時エラーで落ちてしまいます。

無理矢理に window や document を定義して回避することも考えられますが、その手の処理はブラウザの種類を判定することが目的だったりする場合も多く、サーバーサイドで動けばいいという発想には難があります。

ここでは、Sapper での対応方法を説明しますが、手法自体はサーバーサイドレンダリングを行う場合に共通した考え方ではないかと思います。

## 対応方針

ブラウザ特有のオブジェクトに依存するモジュールは、サーバーサイドレンダリング完了後に動的にロードして表示すればいい。

## 具体的な対処法

コンポーネントの初期化時に動的 import 関数を使い、モジュールを動的ロードします。ここでは Svelte の oncreate でロードしていますが、React であれば componentDidMount で同じことができます。

~~注意が必要なのは、oncreate を async にする場合には、onupdate や ondestroy も async にしなければならないという点です。合わせないとインスタンス初期化前に後続の onupdate が呼び出され this.instance が undefined の状態で実行されてしまいます。~~

2018/9/1 追記 当初うまくいっていたように見えたのですが、どうもうまく動作していないので、現時点では下記は間違いかもしれません。地道に Promise を重ねるしかないのか……

```html
<div ref:elem></div>

<script>
export default {
  async oncreate() {
    const Handsontable = await import('hansontable');
    this.instance = new Handsontable(this.refs.elem, this.get());
  },
  async onupdate({changed, current, previous}) {
    this.instance.updateSettings(current);
  },
  async ondestroy() {
    this.instance.destroy();
  }
}
</script>
```

## 謝辞

実のところ、この記事は[Andrew Smith さんのブログ](https://www.donielsmith.com/blog/2018/05/19/dynamic-imports-in-sapper/)のアイデアをまるパクリして書かれています。externals も webpack.IgnorePlugin もうまくいかず途方にくれていたので、非常に助かりました。
AWSのCloudFormation周りの用語をまとめてみた

# はじめに

英語を単純に発音しただけのカタカナ語だと意味は分かりづらい。AWSのドキュメントやAWSコンソールは親しみやすく日本語にしてくれてはいるんだろうけど、まだ英語の方が意味が取りやすい。

というわけで、AWSのCloudFormation周りの用語を自分なりにまとめてみました。

# CloudFormation周りの用語

## スタック

CloudFormationテンプレート1枚で構成されるサービス群。
インフラリソースをひとまとめにしたもの。

CloudFormationコンソールのトップにテンプレート単位で登録され、コンソール上では定義パラメータの確認や動いているインスタンス、ネットワークIDなどが確認できる。

CloudFormationテンプレートを修正することで、後から削除、変更などができる。
ChefからのDevOpsをサポートしたAWSのサービスOpsworksでも同様の意味で使われているようです。

### ロールバック

スタックをコンソール上で削除したときや構築が途中で失敗したときに全てのインフラサービスを削除してくれる機能。

サクッと環境作ってテストして、ネットワークごと削除。といったことが可能になる。
S3やECSレポジトリなど、ファイルを含んでいると削除できないリソースについては、削除が失敗する。

### Delete Policy

ロールバックによって、リソースが削除されないようにするオプション。

Cloudformationテンプレート内に記述して、リソースごとに設定が可能。本番環境などで誤ってスタックが削除された場合などにデータベースサーバーだけはそのまま残しておく、みたいなことに使うみたい。

## Cloudformationテンプレート

EC2インスタンスやS3バケット、IAM、VPCネットワークの設定などAWSの全てのサービスをコードで定義したymlまたはjsonファイル。

サービスごとの各種パラメータはここで設定。
S3バケットにアップしてCloudformation コンソールで構築する。

AWSのサービスはパラメータが多すぎるので、基本構成だけでも1000行は軽く超えることになる。
パラメータ設定に不備があるとスタック構築中にエラー→ロールバックという悲しいことになるので、Codeデザイナーなどに流し込んで部分的に試しながら作成するのがいいと思います。時間は不可逆です。

## パラメータ

各種AWSサービスの設定で使われる値
 
- VPCへのSSHアクセスのIP制限
- インスタンスタイプの設定
- CPU数、メモリ
- SNS通知先のメールアドレス

など

これらの値をGUIでインフラ構築時に設定する形にしておくことで、同じ構成を設定を変えて構築するなど、汎用的に使えるようになります。
ネストされたテンプレートへのパラメータの受け渡しを行うことでより汎用的で見通しの良いテンプレート管理ができるようになるといいですね！

## CloudFormationデザイナー

AWSサービスのアイコンをドラッグ&ドロップで配置していくことによって、スタックを作成できます。
S3に配置したCloudformationテンプレートからスタックを作成して、簡単なネットワーク図を作成することもできます。

あくまでテンプレート1枚ごとなので、ネストしたテンプレート構成の場合はネットワーク図出力として使えなかったり、逆にネストしたテンプレート構成に書き出せないのがもどかしいところ。
既存のインフラ構成をスタックにすることもできるようです。

## ネスト（ネストされたテンプレート）

長くなりがちなテンプレートを分割して管理できる。

複数のテンプレートを1枚の親テンプレートから呼び出して、サービス同士を組み合わせたインフラ構成を構築できるようにしておくこと。
ネストされたテンプレート間では、それぞれのサービスに依存した状態で構築を行うので、構築の順序とパラメータの受け渡しが重要になる。

分割のコツとしては、プラベート/パブリック含むVPCネットワーク系とルーター周りを1つのテンプレートとして、そのほかをサービスとして依存しない最小単位のサービス群でテンプレート化。親テンプレートからVPC、EC2やS3、データベース、デプロイ周りの順にネストされたテンプレートを呼び出していく構成がいいかと思います。

## パイプライン

継続的デプロイを行うためのサービス構成

例: 
Codepipeline + CodeCommit + CodeBuild + CodeDeploy

GitHubやAWS謹製CodeCommitなどのコードリポジトリに開発者からプッシュされたことを検知して、自動的にテストを行い、デプロイされるという一連の流れ

SNSやLambdaを連携して、Slackなどへの通知を行うようにするとチームのみんなに喜ばれる

## マルチAZ（マルチAZ構成）

複数のアベイラビリティーゾーンに渡って展開するサービス構成のこと。

基本的には同じサービスを冗長化しておかないと意味がない。複数台構成になるので料金は倍。
AWSのデータセンターが物理的破壊されてもサービスが存続できる、必要があるかはサービス次第。

## アベイラビリティーゾーン（AZ）

AWSのデータセンターがある物理的な地区分けのこと。
ap-northeast-1bは罠

## リージョン

アベイラビリティゾーンの上位にある地域枠
東京、大阪、シンガポール、ソウルなどがある

# CloudFormationあるある

- cloudfrontと間違えて検索して一向に望みの結果が出てこない
- ネストされた最後のテンプレートの検証に軽く30分はロスト
- 自由入力パラメータを設定しすぎてある程度知識がないと構築出来ない
- Googleで関連キーワードを調べまくっても結局わからなくてAWS語で書かれた公式ドキュメントを読む
Dockerコンテナ上のWebサービスにスマホからアクセスする（Windows）

DockerでWebサービス等を開発する際、PC内のDockerコンテナへスマホからアクセスしたいことがあります。
ですが、そのままDockerのIPアドレスにアクセスしても繋がりません。スマホが繋がっているLANとDockerコンテナが動いているネットワークが別々だからです。
そこで、PC上でポートフォワード（ポート転送）をかけてネットワーク間の橋渡しをしてやれば、スマホからDockerコンテナにアクセスできるようになります。

Windowsでは、netshコマンドでポートフォワードを設定できます。
また、拙作のGUIツールも紹介したいと思います。

## netshコマンド

これはWindows標準のコマンドのようですので、たぶんどのPCにもインストールされています。コマンドプロンプト等から使います。

転送設定の確認
`> netsh interface portproxy show v4tov4`

転送設定の追加（要管理者権限）
`> netsh interface portproxy add v4tov4 listenport={fromPort} listenaddr={fromAddr} connectport={toPort} connectaddr={toAddr}`

転送設定の削除（要管理者権限）
`> netsh interface portproxy delete v4tov4 listenport={port} listenaddr={addr}`

設定の追加・削除には管理者権限が必要ですので、コマンドプロンプトを管理者権限で起動しておくのを忘れないようにしましょう。

また、デフォルトの状態では、パケットフィルタでポートが閉じていますので、ポートを開放する必要があります。（順番はどっちが先でも大丈夫です）
参考：[Windows10 - ファイアウォール - 特定のポート番号の通信を許可](https://pc-karuma.net/windows-10-firewall-open-port/)

## portproxyというGUIツール

ですがこのnetshコマンド、パラメータは多いしサブコマンドも長くて覚えにくいです。
コマンドプロンプトを管理者権限で起動しておくのも忘れがちです。
さらに、netshコマンドを打つ前にPCのIPアドレスを調べておく必要もあり、手順が長い。
ポート転送を設定するためのツールとしては、正直使いにくいと思います。

それで、netshのGUIラッパーを作りました。
[portproxy](https://github.com/tyam/portproxy)

<img width="441" alt="portproxy.png" src="https://qiita-image-store.s3.amazonaws.com/0/50996/3daa600e-1754-2144-8a76-a3d1d14f26ec.png">

- 必要なときに管理者権限を要求します。あらかじめ管理者権限で起動しておく必要はありません
- IPアドレスを入力する際にPCのアドレスを候補として表示します。あらかじめ調べておく必要はありません

Electron性なので少し重いです。
netshコマンドを使う場合と同様、パケットフィルタのポートを開放しておく必要があります。

## まとめ

コンテナ内に作ったサービスをスマホで確認したいシーンは多くあると思います。
アクセス方法は、整理してみれば難しいことはありませんし、GUIツールも出来て気軽に試せるようにもなりました。
どんどん使っていってはいかがでしょうか。
なんちゃってStateではなく、なんちゃってStrategyパターン Factoryを添えて

# 概要のような何か
仕事でStateパターンを実装したのでQiitaに残しておきます。
使用言語はJava8でしたが、大抵の言語で似たように実装できるはずです。

# 2019年12月25日追記と修正
一年ぶりに見返してみたら、StateとStrategyの区別がちゃんとついていないことに気付いてしまいました

ステートマシンについて学習すると、なんでStateパターンという名前が付いているのかすんなり理解できるようになったので、
以下の記事で当時の自分が「なんちゃって」と軽く考えて付けていたサンプルの命名がかなりふさわしくないことに気づいてしまいました
Stateパターンを名乗るなら各Stateオブジェクトが状態遷移後のStateオブジェクトを返すようにすべきでした

**以下の記事の本題の内容は以前の記事のStateを全てStrategyに変換して作成しました。以前のものも一応残しておきます**

# 本題
Strategyパターンを使う場合、各処理を表すStrategyオブジェクトと、どのStrategyを生成するかを決定するオブジェクトが必要です。
何を生成するか決める処理は、Factoryに置きました。


```java
// Strategyのインターフェイス
public interface Strategy{
  void doSomething();
}
// Strategyの実装1
public class StrategyImpl1 implements implements Strategy {
  public void doSomething(){
    System.out.println("Strategy1固有の処理をいっぱい");
  }
}
// Strategyの実装2
public class StrategyImpl2 implements implements Strategy {
  public void doSomething(){
    System.out.println("Strategy2固有の処理をいっぱい");
  }
}
```

Strategyを用意しただけではあまり意味はないです。

```java
// このコードが書けていったい何の得があるのだろうか
Strategy strategy1 = new StrategyImpl1();
Strategy strategy2 = new StrategyImpl2();
```

実際は各処理を管理する条件分岐処理を行うクラスも必要です。

```java
public class Factory{
    // Staticでいいと思うよ
    public Strategy create(SomeCondition sc){
        if (sc.something1) {
            // 実際はオブジェクト生成にも二手間くらい掛けるよ
            return new StateImpl1();
        } else if(sc.something2) {
            return new StateImpl2();
        }
    }
}
```

よって、呼び出し側は次のように書けます。

```java
Factory factory = new Factory();

for(SomeCondition sc: List<SomeCondition> scs) {
  Strategy strategy = factory.create(sc);
  strategy.doSomething();
}
```

この例だけだとswitch文で十分なので、あまり意味がないどころか無駄に複雑にしているだけなのですが、
条件分岐が嫌に複雑で、判定した結果行う微妙に異なる処理がいっぱいある、みたいなときはかなり見通しがよくなります(なりました)

クラスファイルがたくさん増えるのは難ですが、
人間は一度にあまり多くのことや複雑なことは考えられないので、各クラスに分割して一度に理解しなければいけない量を減らしているわけです。

# 旧本題

Stateパターンを使う場合、各状態を表すStateオブジェクトと、どのStateを生成するかを決定するオブジェクトが必要です。
何を生成するか決める処理は、Factoryに置きました。


```java
// Stateのインターフェイス
public interface State{
  void doSomething();
}
// Stateの実装1
public class StateImpl1 implements implements State {
  public void doSomething(){
    System.out.println("State１固有の処理をいっぱい");
  }
}
// Stateの実装2
public class StateImpl2 implements implements State {
  public void doSomething(){
    System.out.println("State２固有の処理をいっぱい");
  }
}
```

Stateを用意しただけではあまり意味はないです。

```java
// このコードが書けていったい何の得があるのだろうか
State state = new StateImpl1();
State state = new StateImpl2();
```

実際は状態を管理する条件分岐処理を行うクラスも必要です。

```java
public class Factory{
    // Staticでいいと思うよ
    public State create(SomeCondition sc){
        if (sc.something1) {
            // 実際はオブジェクト生成にも二手間くらい掛けるよ
            return new StateImpl1();
        } else if(sc.something2) {
            return new StateImpl2();
        }
    }
}
```

よって、呼び出し側は次のように書けます。


```java
Factory factory = new Factory();

for(SomeCondition sc: List<SomeCondition> scs) {
  State state = factory.create(sc);
  state.doSomething();
}
```
PowerShellでWindows Serviceを起動する。

# やりたいこと
Windowsで、サービス（Windows Service）をたくさん起動していると、だんだん動作が重くなってきます。
そこで、普段はサービスを停止しておき、必要な機会に手動で起動するようにします。

# 作るもの
Redmineの稼働に必要な4つのサービスをまとめて起動するスクリプトを作成します。

# 設計
1. PowerShellでRedmineのサービスを起動するスクリプトを作成します。
2. そのスクリプトをキックするbatファイル(Windows Batch File)を作成します。
3. 「Redmineを使いたい」と思ったとき、batファイルを手動で実行し、Redmineを起動します。

# ソースコード
## サービス起動スクリプト
```powershell:StartService_Redmine.ps1
### RedmineのServiceを全て起動する ###

# Redmineの稼働に必要なサービスの名前を配列で用意します。
$services = @("redmineApache","redmineMySQL","redmineThin1","redmineThin2")

# 上記サービスのうち、停止しているサービスを起動します。
foreach($service In Get-Service $services | Where-Object {$_.status -eq "stopped"}){
    Start-Service $service
}
# 現在のサービスの稼働状況をコンソール出力します。
# サービスの状態が全て「running」になっていれば、サービスの起動が成功しています。
echo "`r`n<<<  Redmine Service Status  >>>"
Get-Service $services | Format-Table -Property DisplayName, Status
```
## スクリプトをキックするbatファイル
```terminal:StartService_Redmine.bat
powershell -ExecutionPolicy RemoteSigned -File C:\Tool\StartService_Redmine.ps1
pause
```
# 使い方
１. 上記の2ファイルを以下のように配置します。

```text
C:
└─Tool
    StartService_Redmine.ps1
    StartService_Redmine.bat
```
２. batファイルを管理者権限で実行します。
３. Redmineのサービスが起動されます。既にサービスが起動している場合は、何も起きません。

# 実行結果
```text

C:\Tool>powershell -ExecutionPolicy RemoteSigned -File C:\Tool\StartService_Redmine.ps1

<<<  Redmine Service Status  >>>

DisplayName                        Status
-----------                        ------
redmineApache                     Running
redmineMySQL                      Running
redmineThin1 (managed by WinServ) Running
redmineThin2 (managed by WinServ) Running

C:\Tool>pause
続行するには何かキーを押してください . . .
```
JMeterでJSONレスポンスを自動で整形する

# はじめに
JSON形式のHTTPレスポンスをJMeterで受信した！整形されていなくて見ずらい！！
JMeterでJSONのフォーマットってできないの？できるよね？

プラグイン入れたらできました。


# JMeter Plugins Managerの導入
まず、このJMeter Plugins Managerをインストールします。
これで、JMeterプラグインの管理が楽になります。

導入手順は以前こちらに記載したので、参考にしてみてください。
https://qiita.com/segur/items/66257aad638806b2f27a


# JSON Pluginsの導入

JMeterを起動して、**JMeter Plugins Manager**を開きます。

![06_success.PNG](https://qiita-image-store.s3.amazonaws.com/0/221845/2a7cfc05-f2c5-13d4-e4d4-eb7b486a0b47.png)

**JMeter Plugins Manager**が開けたら、**Available Plugins**タブをクリックし、検索欄に**json**と入力します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/221845/482b5471-8882-7693-625c-ba4baad7f534.png)

**JSON Plugins**というのが表示されるので、チェックボックスをONにします。すると、インストールが始まります。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/221845/c8b278f5-db24-1060-573c-ee9e537f37e7.png)

下にある**Review Changes**にログが表示されたら、右下の**Apply Changes and Restar JMeter**をクリックします。
すると、JMeterが再起動します。再起動ができたら、プラグインの導入は完了です。


# JSON Format Post Processorの設定

それでは、実際にJSONレスポンスの整形を試してみます。
今回は、リクエスト先としてJSONPlaceholderを使わせていただきました。

- リクエスト先URL: https://jsonplaceholder.typicode.com/posts
- 公式サイト: [JSONPlaceholder](https://jsonplaceholder.typicode.com/)


JSONレスポンスを返す**HTTPリクエスト**で右クリックし、**追加**→**後処理**→**jp@gc - JSON Format Post Processr**とクリックします。

![07_json.PNG](https://qiita-image-store.s3.amazonaws.com/0/221845/c7960024-596e-809f-a244-77668caac1b4.png)

すると、**HTTPリクエスト**配下に**jp@gc - JSON Format Post Processr**が追加されます。
この状態で、HTTP通信を行います。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/221845/8a1a7046-3892-4af6-1293-b6349a636b78.png)

**結果をツリーで表示**の**応答データ**が整形されました！


# さいごに
JSONが整形されることで、視認性がよくなり、テストがはかどりますね。


# 追記2019/02/03
ご紹介した **jp@gc - JSON Format Post Processr** には、日本語が文字化けするとうバグがありましたので、追記します。

また、私のPCでは未確認ですが、数値の桁数が大きい場合、10桁程度に切り捨てられて表示されるようです。
こちらは、気づきにくいバグですので、ご注意ください。
RSSの設定が思ったより手間取った

今回やるのは、RSSの設定です。

終わってみると、なんでこんなのスッとできなかったのだろうかと思います。


RSSの設定のしかたは大きく３つです。


1. xmlを書く 
2. Feedburnerでサイトを登録する
3. サイトにlinkタグを追記を修正する

## xmlを書く 

外部から見えるところにxmlを置きます。
名前は適当でいいと思います。
僕はrss.xmlっていうふうにつけました。

フォーマットはこんな感じのところを参考にしました。

[RSS 2.0タグリファレンス](http://www.openspc2.org/RSS/200/index.html)

## feedburnerでサイトを登録する

自分のサイトをFeedBurnerに登録します。

[feedburner](https://feedburner.google.com/fb/a/myfeeds)


## サイトにlinkタグを追記する

```html
  <link rel="alternate" type="application/rss+xml" title="2.0" href="rss.xml">
```
hrefのリンクを見にいったときにブラウザ越しに中身を見ることができれば、OKです。



## うまくいかないとき

* xmlの権限がおかしいかも
* フォーマットがちゃんと書けていないかも
    * feedburnerからどこが間違っているかしてきされるので、修正はしやすいと思います。


## 思ったこと

こうやって、WEBサーバを自分で一からやってブログをつくるのは、はじめてなのでいろいろと学べて、なんだか幸せだなー、と思う僕でした。
SAN(Subject Alternative Name) のオレオレ証明書

## はじめに
Nginx を ForwardProxy として使えないか(これは結果ダメだった)から作ったやつ。
1つの SSL 証明書で複数の FQDN に対応する証明書を作ってみる。

## つくってみよう
まずは KEY ファイルを作ります

```bash
openssl genrsa -des3 -out server.key 2048
Generating RSA private key, 2048 bit long modulus
.................................................................................................+++
.......+++
e is 65537 (0x10001)
Enter pass phrase for server.key: <<パスワードを入力>>
Verifying - Enter pass phrase for server.key: <<パスワードを再入力>>
```

次に CSR ファイルを生成する

```bash
openssl req -new -key server.key -out server.csr
Enter pass phrase for server.key: <<↑で設定したパスワード>>
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:JP
State or Province Name (full name) []:Tokyo
Locality Name (eg, city) [Default City]:Minato-ku
Organization Name (eg, company) [Default Company Ltd]:Nittsu Information Systems Co., Ltd.
Organizational Unit Name (eg, section) []:
Common Name (eg, your name or your server's hostname) []: <<適当にサーバのIPアドレスとか>>
Email Address []:

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
```

key ファイルからパスワードを除去する

```bash
cp -p server.key server.key.org
openssl rsa -in server.key -out server.key
Enter pass phrase for server.key: <<↑で設定したパスワード>>
writing RSA key
```

SAN に設定する FQDN を書く

```bash:san.txt
# ファイル名は何でもいい
subjectAltName = DNS:hoge.com, DNS:fuga.com
```

証明書ファイルを生成する

```bash
openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt -extfile san.txt
Signature ok
subject=/C=JP/ST=Tokyo/L=Minato-ku/O=Nittsu Information Systems Co., Ltd./CN=xxx.xxx.xxx.xxx
Getting Private key
```

ちゃんとできたか確認
**X509v3 Subject Alternative Name** を確認する

```bash
openssl x509 -text -in server.crt -noout
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            ee:0a:7e:f7:14:78:e9:b0
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: C=JP, ST=Tokyo, L=Minato-ku, O=Nittsu Information Systems Co., Ltd., CN=xxx.xxx.xxx.xxx
        Validity
            Not Before: Aug 28 11:24:31 2018 GMT
            Not After : Aug 28 11:24:31 2019 GMT
        Subject: C=JP, ST=Tokyo, L=Minato-ku, O=Nittsu Information Systems Co., Ltd., CN=xxx.xxx.xxx.xxx
        Subject Public Key Info:

       ～ 省略 ～

        X509v3 extensions:
            X509v3 Subject Alternative Name: 
                DNS:hoge.com, DNS:fuga.com
```

いじょう。

## 仲間募集中
[弊社](https://www.nittsu-infosys.com/)ではエンジニアを募集中です。インフラからアプリ、ユーザサポートまで幅広く業務を行ってます。
https://www.nittsu-infosys.com/recruit/2019/index.html
素人に毛が生えた程度のエンジニアでもプルリクしてOSSに貢献できた話

OSSに貢献してみたい人の参考になれば嬉しいっす。

# なにをしたのか？
to_boolという、いろんな型をbool型に変換してくれる便利なgemがありまして、そこにメソッドのエイリアスとrspecの少量の書き直しをました。

https://github.com/bricker/to_bool/pull/2

# マージまでの経緯
## リポジトリーをフォーク

あとあとプルリク送るため、git cloneではなくフォークしました。
他のやり方でもプルリクできるようでしたら、知識不足っす。さーせん。

## 修正

修正 -> テスト を何度か実施。
そのあとREADME.mdやgem_specを直しました。

## プルリクエストを作る
フォーク元のリポジトリに修正したリポジトリをマージしてもらうようプルリクを立てました。
ここが一番緊張しました。世界に公開されて辱めを受けるような。でも鈍感力で乗り切る。

プルリクのコメントには、中学生レベルの拙い英語で

- 何をやったのか
- マージしてくれるとうれしいな
という内容を記載しました。

実際の英文はこんな感じ
>Thank you for nice gem.

>I added some features.

>added alias to_boolean
>added for symbol
>change spec method
>If you don't mind, could you merge this?

どうでしょうか。こっぱずかしい。

## フィードバックを待つ
プルリク出してから一週間ぐらい音沙汰がなくめちゃくちゃ不安でした。
悪いことしてるわけじゃないから不安になることないんですが、初めてだとしょうがないです。
気長に待つのも大事ですね。

## 1週間ぐらいたつとお返事が
開発者の方から一言「ありがとう」とだけもらえて無事マージされました。
自分の考えが認められたようなそんな気持ちでめちゃくちゃ嬉しかったです。

# やってみての感想
最初は、不安でしょうがなかったです。
自分なんかが書いたコードが採用されるのかと。
でもマージされると、「おれやるやん」という自信と社会貢献したような充実感に満たされて、いいもんです。
Processingで学ぶ関数

# はじめに
この記事は子供向けに作成しています。

## 必要な知識
・setupとdrawがわかる
・変数がわかる

## 関数とは？
「かんすう」と読みます。
英語では「Function（ファンクション）」と呼びます。
関数と聞くと何やら難しそうですが、なんてことはありません。少しずつ覚えていきましょう。

## 関数を使うメリット
簡単に言うとプログラムコードをまとめられます。
なんども同じようなプログラムコードを書く必要がなくなり、そして後からプログラムコードを読み直した時にもわかりやすく、プログラムコードの変更も簡単になります。
「関数がわからないとゲームが作れない！」ということはありませんが、関数がわかるとグンっとプログラミングスキルがUPします。

## こんな人に読んでもらいたい
・ゲームを作っているが、何か変更を加えるたびに修正が大変だと思っている。
・後からプログラムコードを読み直した時に、どこがなんの処理かわからなくなりやすい。

## 初めての関数
### まずはsetupとdraw
```Java
void setup(){
  size(600, 400);
}
void draw(){
  background(0);
}
```

### 人の顔の絵を描いてみます。
```Java
void setup(){
  size(600, 400);
}
void draw(){
  background(0);
  
  // 顔っぽい絵を描いていきます。
  noStroke();
  // 顔
  fill(255, 255, 255);
  rect(200, 100, 200, 150);

  // 左側の目
  fill(30, 30, 30);
  ellipse(250, 150, 10, 10);
  // 右側の目
  ellipse(350, 150, 10, 10);
}
```

<img width="712" alt="スクリーンショット 2018-08-28 20.18.37.png" src="https://qiita-image-store.s3.amazonaws.com/0/149597/17db6aba-0616-6a7e-35b0-de31d112aff7.png">


### 機能をまとめる

```Java
  // 顔っぽい絵を描いていきます。
  noStroke();
  // 顔
  fill(255, 255, 255);
  rect(200, 100, 200, 150);

  // 左側の目
  fill(30, 30, 30);
  ellipse(250, 150, 10, 10);
  // 右側の目
  ellipse(350, 150, 10, 10);
```
drawの中の、この部分のプログラムって「顔を描く」というプログラムですよね。
であれば、「顔を描く」という機能で、プログラムをまとめてしまいましょう。

```Java
void setup(){
  size(600, 400);
}
void draw(){
  background(0);
}
// ここが追加された！これが関数！
void kao(){
  // 顔っぽい絵を描いていきます。
  noStroke();
  // 顔
  fill(255, 255, 255);
  rect(200, 100, 200, 150);

  // 左側の目
  fill(30, 30, 30);
  ellipse(250, 150, 10, 10);
  // 右側の目
  ellipse(350, 150, 10, 10);
}
```

「**kao**」という関数を作りました。drawの中にいた、顔を描いていたプログラムコードをkao関数の中にお引越ししています。

### 関数を呼び出す
kao関数を作りましたが、ここまでは関数を作っただけです。作った関数は、呼び出して初めて機能します。drawの中で呼び出してみましょう。

```Java
void setup(){
  size(600, 400);
}
void draw(){
  background(0);
  // kao関数を呼び出す！変数ではないので、「()」をつけて呼び出すぞ！
  kao();
}
void kao(){
  // 顔っぽい絵を描いていきます。
  noStroke();
  // 顔
  fill(255, 255, 255);
  rect(200, 100, 200, 150);

  // 左側の目
  fill(30, 30, 30);
  ellipse(250, 150, 10, 10);
  // 右側の目
  ellipse(350, 150, 10, 10);
}
```

これでkao関数を呼び出すだけで、顔の表示ができるようになりました。

顔をどう描くかは、kao関数の中に全てまとまっているので、顔の表情を変えたかったらkao関数の中だけを修正すればよくなります。

##最後に
これはまだ関数の少しの機能しか紹介していません。まだまだ便利な機能がありますので、続きをまた書いていきます。
Google Ad Managerのターゲティング、Key Valueを設定し広告表示出し分けロジックを実装する

# google ad managerのターゲティングを使いこなす key value編
coffeescript 
rails

こんな環境で動的に広告を出したい人向けの記事です。

記事内容がそこそこ雑です、googleの公式ドキュメントもみましょう。。。。orz

## spep1. 広告ユニットを作成しましょう
左のタブから広告ユニットを選択、必要情報を適当に入力します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/69647/e5929dcf-f644-7112-047c-53f763867aee.png)


## spep2. key valueを作成しましょう
在庫の中にあるkey valueを選択します。

新しいキーを選択します

名前：keyになるものです、間違っても全角を入力しないように
表示名：google ad manager上で使う名前、日本語でもおkです、わかりやすい名前をつけましょう。


![image.png](https://qiita-image-store.s3.amazonaws.com/0/69647/9dadc470-14c0-8310-32b2-5f3dbf7012d9.png)


### 2種類のタイプ
![image.png](https://qiita-image-store.s3.amazonaws.com/0/69647/5ecd76e5-8c71-902e-d1cd-1fd55e1c51b4.png)

valueの種類が多い　＝＞　検索パラメータを条件に広告表示非表示したい場合、ユーザーがどんな検索キーワードを入力するかわからないためvalueの種類が多い

valueの種類が少ない　＝＞　プルダウン選択式やFood.categoryなど200種類以下の場合は少ないと判断し、

```
valueの種類が多い場合：広告申込情報を作成または在庫を確認するときにターゲットとする値を入力
valueの種類が少ない場合は：定義済みのターゲット値から選択
```

を選択してあげてください。

## spep3. タグを作成時に条件を指定key valueを設定します
タグタイプはデフォルトで大丈夫です。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/69647/bc6910c1-b751-bc92-d095-b105ee11e7d4.png)

次に出てくるタグオプション画面にてターゲット設定を追加を押してください。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/69647/44a59729-e932-6bb9-b9d7-6e6a4d9e582c.png)

すると上記のような画面が表示されるので、先ほど設定したseoを選択

![image.png](https://qiita-image-store.s3.amazonaws.com/0/69647/52643a76-bffb-125d-6b51-833a6c7e7b4e.png)

## spep4. 条件なしの場合とタグ生成結果が変わる

```
  googletag.cmd.push(function() {
    googletag.defineSlot('/2814744/hoge_test_24480803', [310, 30], 'div-gpt-ad-1871254430326-0').setTargeting('article_tag', ['seo']).addService(googletag.pubads());
    googletag.pubads().enableSingleRequest();
    googletag.enableServices();
  });
```

このなかのこの部分が追加されてます。

```
.setTargeting('article_tag', ['seo'])
```

### 【非常に注意：反映に20分ほどかかります！！！！】
これでかなりはまりました、お気をつけてください。


## spep5. この生成されたタグをcoffeescriptに変換
今回追加した、タグ部分以外を引数を渡すだけで実装できる感じにしました

```coffeescript:gam_push.js.coffee
$ ->
  window.gam_push = (ad_slot_id, size, div_gpt_ad_number) ->
    googletag = window.googletag or {}
    googletag.cmd = googletag.cmd or []
    googletag.cmd.push ->
      googletag.defineSlot(ad_slot_id, size, div_gpt_ad_number).setTargeting('article_tag', [ 'seo' ]).addService googletag.pubads()
      googletag.pubads().enableSingleRequest()
      googletag.pubads().setTargeting('article_tag', ['seo'])
      googletag.enableServices()
      return
    googletag.cmd.push ->
      googletag.display div_gpt_ad_number
      return
    return
```


### 無事表示できました
![image.png](https://qiita-image-store.s3.amazonaws.com/0/69647/0a99c66a-ac69-51e9-592e-cfcf3b200cda.png)

タグ部分を seo から hoge に変更すると、無事表示できないことが確認できました。

あとはこの記事タグ seoの部分を動的にrailsでデータごとに出し分けしてあげれば良いだけです。



## step6. key valueのタグ指定もメソッドに引数を渡すだけで良いように変更する

これから実装します。
Laravel Nova インストールメモ


いつもAdmin画面作成には悩んでましたが、オフィシャルなツールが出たことで一安心？です（有償ですが）。
[本家サイト](https://nova.laravel.com/docs/1.0/installation.html#installing-nova)に書いている通りなのですが、久しぶりのLaravel利用でわかりにくいところもあったので簡単にメモしておきます。

## まずは準備（Novaの入手）

残念ながら先にライセンスを購入しないと利用できないようです。。。
下記は主な手順。

* まず、登録が必須なようです。
* 登録すると、画面が利用できるようになります（カード決済のみのようです）。
* ライセンスはSERIESという概念で管理されるようで、恐らくメジャーバージョンアップの際はシリーズが変更されるのでしょう。
* 購入が完了するとReleasesメニューの[BUY LICENSE]が[DOWNLOAD]に変化するので、Nova(zip)をダウンロードします。
* ダウンロードしてzipを解凍します。
* 解凍したzipをnovaとリネームして利用したいLaravelのアプリケーションフォルダに入れます（appとかと同じ階層です）。

## Nava（狭義の）インストール

### composer.jsonの編集

ルートにあるcomposer.jsonを編集します。

>novaの中にもあるけど、それはいじりません。

```diff:composer.json
{
    "name": "laravel/laravel",
    "description": "The Laravel Framework.",
    "keywords": ["framework", "laravel"],
    "license": "MIT",
    "type": "project",
    "require": {
        "php": "^7.1.3",
        "fideloper/proxy": "^4.0",
        "laravel/framework": "5.6.*",
        "laravel/tinker": "^1.0",
+        "laravel/nova": "*"
    },
+    "repositories": [
+        {
+            "type": "path",
+            "url": "./nova"
+        }
+    ],
    "require-dev": {
        "filp/whoops": "^2.0",
        "fzaninotto/faker": "^1.4",
        "mockery/mockery": "^1.0",
        "nunomaduro/collision": "^2.0",
        "phpunit/phpunit": "^7.0"
    },
    ・
    ・
    割愛
```

### そしてcomposer update

composer updateします。

```bash
composer update
```

### artisanコマンドを実行

novaを（本当に）インストールして、利用するテーブル類をmigrateします。
標準ではUserが利用されるようなので消したりしてはいけません。

```bash
php artisan nova:install

php artisan migrate
```

## ユーザーの作成

標準では認証にUsersテーブルが利用されるので、Usersテーブルにユーザーを登録する必要があります。

>Userではいろいろ不都合があるので利用するモデルを変更する方法を調べないといけません。


### 認証機能の追加

ここではめんどいので、Auth画面を作成して登録してみます。

```bash
php artisan make:auth
```

Registerでユーザーを登録し、登録したユーザーでログインしてみます。

## メモ

細かな設定方法等は[こちら](https://qiita.com/shrft/items/3d05f57a631d95a925ba)等で紹介されているようです。

いろいろ試したいと思います。
コマンドラインの引数ではなくプログラムでglogの設定を行う方法

## 結論

`flag.Set`を使います。  
例えば、`stderrthreshold`で、ログレベルの閾値を設定したい場合は、以下のようになります。

```go
func main() {
    flag.Set("stderrthreshold", "INFO")
    flag.Parse()

    glog.Info("Hoge")
}
```

## 参照

https://godoc.org/github.com/golang/glog
init.vim を複数ファイルに分ける

例えば statusline.init.vim を init.vim から分割し

```
 nvim
    ├── init
    │   └── statusline.init.vim
    └── init.vim
```

のように置いた時、

init.vim に

```init.vim
runtime init/statusline.init.vim
```
と書けば読み込みます。

何百行もあった init.vim がこんなにすっきりに！

```init.vim
scriptencoding utf-8

runtime init/plugin/plug_install.init.vim                                                                
runtime init/plugin/plug_settings.init.vim                                                               
runtime init/main/main.init.vim                                                                          
runtime init/color/color.init.vim 
```

追記:2020/8/6
スクリプトローカルな変数や関数が共有できないという短所があります．

###参考
https://unix.stackexchange.com/questions/171132/can-vimrc-be-divided-into-multiple-files
シェルスクリプトでPythonのArgumentParserを使う

Pythonに慣れると、シェルスクリプトのgetoptがあまりに非力で泣きたくなってくるので、この部分だけ`ArgumentParser`のパワーを拝借する方法を考えてみました。


```bash
#!/bin/bash

args_source="$(mktemp -u)"
PROGNAME="$0" ARGS_SOURCE="${args_source}" python3 - "$@" <<'__EOF__' || exit $?
from argparse import ArgumentParser
from os import environ
p = ArgumentParser(prog=environ['PROGNAME'])
# コマンドラインのオプションを指定する。
p.add_argument('--arg1', '-a', help='argument 1')
p.add_argument('--switch2', '-s', action='store_true', help='switch 2')
p.add_argument('arg3', nargs='+', help='position-fixed arguments 3')
def py2bash(v):
    if type(v) is list:
        return '('+' '.join(map(py2bash, v))+')'
    elif type(v) is bool:
        return f'/bin/{repr(v).lower()}'
    else:
        return "$'"+''.join(f'\\{c:03o}' for c in str(v).encode())+"'"
a = p.parse_args()
with open(environ['ARGS_SOURCE'], 'x') as fp:
    for k, v in vars(a).items():
        if v is None: continue
        print(f'{k}={py2bash(v)}', file=fp)
__EOF__
test -e "${args_source}" || exit 0 # printing --help
source "${args_source}"
rm "${args_source}"

# 以降、Bashの処理
```

* リストで受け取るパラメータ（`nargs`が指定されているもの）は、Bashでもリスト変数として受け取れます。
* Bool値として受け取れるパラメータは、`'/bin/true'`または`'/bin/false'`という文字列でBash変数に渡されます。これでBashの`if`等の評価にそのまま渡せます。
* それ以外は`str()`で文字列に変換したうえで、Bash変数に渡します。8進表記でエスケープしているので、記号や日本語が混じっても大丈夫なはず。
* 省略されたパラメータはシェル変数が定義されないので、`test "${omittable:+x}" = 'x' && echo 'specified'`等で確認が可能。

## Python2.7でもやってみた

```bash
#!/bin/bash

args_source="$(mktemp -u)"
PROGNAME="$0" ARGS_SOURCE="${args_source}" python2.7 - "$@" <<'__EOF__' || exit $?
# -*- coding: utf-8 -*-
from __future__ import print_function
from argparse import ArgumentParser
from os import environ
from os.path import exists
p = ArgumentParser(prog=environ['PROGNAME'])
# コマンドラインのオプションを指定する。
p.add_argument('--arg1', '-a', help='argument 1')
p.add_argument('--switch2', '-s', action='store_true', help='switch 2')
p.add_argument('arg3', nargs='+', help='position-fixed arguments 3')
def py2bash(v):
    if type(v) is list:
        return '(%s)' % ' '.join(map(py2bash, v))
    elif type(v) is bool:
        return '/bin/%s' % repr(v).lower()
    else:
        return "$'%s'" % ''.join('\\%03o' % ord(c) for c in str(v))
a = p.parse_args()
args_source = environ['ARGS_SOURCE']
if exists(args_source):
    raise OSError("File exists: %s" % repr(args_source))
with open(args_source, 'w') as fp:
    for k, v in vars(a).items():
        if v is None: continue
        print('%s=%s' % (k, py2bash(v)), file=fp)
__EOF__
test -e "${args_source}" || exit 0 # printing --help
source "${args_source}"
rm "${args_source}"

# 以降、Bashの処理
```

使えない機能がいくつかあったので多少煩雑になりましたが、まだPython3.xよりも普及していると思われるPython2.7でもOKです。
next.config.jsのコールバック地獄を回避する

## 例えば
プラグインが増えてしまう度にコールバック地獄を見たくないですよね。

```javascript:next.config.js
const withA = require('a')
const withB = require('b')
const withC = require('c')
module.exports = withA(withB(withC({
  webpack(config, options) {
    return config
  }
})))
```
どんどん増えていきます…。
毎度プラグインが増える度にコールバックを書き直す必要があります。

## 解決策
reduceで解決します。

```javascript:next.config.js
const plugins = [
  require('a'),
  require('b'),
  require('c')
]

const webpackConf = {
  webpack(config, options) {
    return config
  }
}

module.exports = plugins.reduce((prev, current) => current(prev), webpackConf)
```

結構スッキリしました。
あとは、プラグイン追加の度に、`plugins`に追加していけばオッケーです。
`module.exports`以下は書き直す必要がありません。
Google 広告の新タグが発火するけど計測できないときの対処（発火順の制御）

Google 広告の新タグの移行時に、下記の問題が起こった。

- global site tag と event snippet を仕込んだ。
- 両方然るべきページで発火している
- だが、 CV が計測されない

原因は単純で、タグの発火順序の問題であった。
CV の計測をするのならば、**先に global site tag、その後に event snippet** という順番である必要がある。

それを、下記のスクショのように設定すれば、 CV の計測ができた。

<img width="697" alt="スクリーンショット 2018-08-28 19.24.29.png" src="https://qiita-image-store.s3.amazonaws.com/0/172474/df0e37d6-bf23-c3b0-78e6-170b62e7b17b.png">

お試しあれ
iTerm2のProfilesでsshpassとsshを併用しサーバに接続する方法

#前提
https://qiita.com/LowSE01/items/f4919fff8f51887a2690
sshpassはこちらの記事を参考にしbrewでインストールしました。

```
brew install http://git.io/sshpass.rb
```


#現象

通常のiTerm2から

```
sshpass -p パスワード ssh ユーザー名@接続先
```

上記のコマンドを実行するとサーバに接続できるが、Profilesに同じコマンドを保存し開いてみるとBroken Pipeが表示され接続できない。

#解決法

調べてみたところ、以下のサイトがヒットした。

https://www.jianshu.com/p/b62e8e81d877

```
/usr/local/bin/sshpass -p パスワード ssh ユーザー名@接続先
```

これならいける様子。試してみたところ接続が確認できた。
PythonからJenkinsのジョブを実行したい

# 経緯
最近ぼちぼち出張も増えてきて、出先で作業することも増えてきました。
出先ではノートPCを使って作業するのですが、手配したばかりで中は環境構築がなされていないすっからかんのPCです。
今後のためにがっつり環境を作ってもいいのですが、せっかく新品なのであまり環境を汚したくないですし、頑張ったところでまあスペックはたかが知れているようなものなので、なんとか普段使っているPCのリソースを使って重たい作業を回したいなあと考えていました。
そんな折、何をとち狂ったのかのか、「Jenkinsのジョブで実行ファイルを叩けば行けるんじゃない?ついでにFlaskでフロントを作ってWebアプリとして動かせるようにしてしまえ。」と思い立ってしまったのが事の始まりでした。
ということでなんか本来の使い方から外れているような気もしますが、タイトルの通りpython(Flask)からJenkinsのジョブを実行する環境を作ったので備忘録的に残しておきます。
# Jenkins環境 
サーバー環境はすでに用意してあるものとします。 まず、ユーザー名とAPIトークンをメモっておきます。 Jenkinsにログインしてユーザー名をクリックすると設定の中から確認できます。 
次にリモートから実行を受け付けられるようにjobを用意します。 
jobの種類は恐らくはなんでもいいのですが、今回は「フリースタイル・プロジェクトのビルド」で作ります。基本的には普通にジョブを作る時と一緒なので、リモートから実行するときに便利そうな設定だけ書いておきます。 
## ビルドのパラメーター化 
ビルドのスクリプトを書くときにパラメーターを使いたい場合に設定します。POSTリクエストを投げた際にここで設定した名前をキーとしてパラメータを取得できます。 
## ビルド・トリガ 
「リモートからビルド」にチェックを入れて認証トークンを設定します。 恐らくなんでもいいので任意のトークン名を入力します。 ここでJenkinsの画面に、「リモートからビルドするには次のURLを使用します～」のようなメッセージが出ていると思うので、ここにリクエストを投げればリモートからジョブを実行できます。 ビルドのパラメーター化でパラメーターを設定した場合は、「buildWithParameters?token」の方を使用します。「TOKEN_NAME」の部分には認証トークンが入ります。 ビルド Windowsバッチコマンドであれば`%`で囲ってあげるとビルドのパラメータを取得できます。 

~~~cmd 
SET PARAM = %param% 
APP.exe %PARAM% 
~~~ 

シェルスクリプトの場合は`$`でしたっけ?ここはJenkinsではなくバッチやシェルスクリプトの書き方に沿って書いてください。 
これでJenkins側の設定は終わりです。 
## pythonのスクリプト
次にpython側のスクリプトを作ります。今回はFlask経由で実行するので若干冗長です。実行だけでよければ`job`の関数の部分さえあれば十分です。 
`render_template`と`redirect`はWebアプリとして使いたいがためのお飾りです。 
使う環境は3系を使います。 

~~~python:job.py
from flask import Flask ,request,redirect,render_template 
import urllib3 


app = Flask(__name__) 


@app.route('/')
def index():
 return render_template('index.html') 

@app.route('/job') 
def job():
 param = request.args.get('param')
 url = 'JENKINS_URL/job/jobname/buildWithParameters?token=TOKEN_NAME&param='+param #&paramの部分はJenkinsのビルドのパラメーター化で設定したキーにしてください
 username = "username" #Jenskinsのユーザー名
 password = "password" #JenkinsのAPIトークン
 http = urllib3.PoolManager()
 headers = urllib3.util.make_headers(basic_auth=('%s:%s' % (username,password)))
 response = http.request('POST', url, headers=headers)
 return redirect('http://localhost:8080/') 


if __name__ == '__main__':
 app.debug = True
 app.run(host='0.0.0.0',port=8080) 
~~~ 

適当にhtmlも書きます。 
<p data-height="265" data-theme-id="0" data-slug-hash="KxVvgQ" data-default-tab="html,result" data-user="sashimimochi" data-pen-title="KxVvgQ" class="codepen">See the Pen <a href="https://codepen.io/sashimimochi/pen/KxVvgQ/">KxVvgQ</a> by Sashimimochi (<a href="https://codepen.io/sashimimochi">@sashimimochi</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

これで`localhost:8080`にアクセスして実行ボタンを押せばJenkinsが稼働しているサーバーのリソースを使って実行ファイルを動かせるようになりました。これで出先でもある程度作業ができるようになったかな。
セキュリティー等は考慮していないガバガバ構築なのでそのあたりは悪しからず。
Pythonで目玉焼きを作ってみた🍳

# 結論から🍳

```python:medama.py
def print_medama(overall_r, medama_r):
    diameter = 2 * overall_r + 1
    for x in range(diameter):
        for y in range(diameter):
            dist = ((x - overall_r)**2 + (y - overall_r)**2) ** 0.5

            if (overall_r-0.5 < dist < overall_r+0.5) or (dist < medama_r): 
                print("*", end="")
            else:
                print(" ", end="")
        print()

print_medama(8, 4)
```

を実行すると以下が表示される。それだけ。

```
      *****
    **     **
  **         **
  *           *
 *             *
 *    *****    *
*    *******    *
*    *******    *
*    *******    *
*    *******    *
*    *******    *
 *    *****    *
 *             *
  *           *
  **         **
    **     **
      *****
```



# 背景

[Pythonで卵焼き作ってみた。【Python】【入門】【資料】 - Qiita](https://qiita.com/Shion-Anegasaki/items/056c4d20b957d7e75811)の記事を見たときに、頭の中にこんな感じ(この記事)の記事なのかなって思ったから。それだけ。

~~ワンライナーで書ける猛者を見たい。~~
Xonsh のスクリプトで mecab-ipadic-neologd の辞書を更新し、前回との差分を出力する

オープンソースで公開されて継続的にメンテナンスされている辞書がある、というのを技術職以外の方と話すことがあります。
そうすると「どれくらいの頻度で更新されてるの？」とか「最近だと、どんな単語が追加されたの？」などといった質問をされて若干回答に窮するので、スクリプトを書いて差分を確認できるようにしてみました。

手元の環境は以下になります。

* Ubuntu 16.04 LTS
* Python 3.6.5 :: Anaconda, Inc.
* xonsh==0.6.9

最近使っている Xonsh で書いてみました。スクリプトは以下になります。
[update_neologd](https://github.com/nettle0010/update_neologd)

特定ファイル名は Python の記述で取得して、コピーや解凍はいつも通りのシェルコマンドで実行するという使い方が個人的には楽しかったです。（Python でも同じことはできますが）

```
NEOLOGD_PATH = os.environ.get('NEOLOGD_PATH')
p = Path(NEOLOGD_PATH + '/seed')
seed = list(p.glob('mecab-user-dict-seed.*.csv.xz'))[0]

DIFF_PATH = os.environ.get('DIFF_PATH')
cp @(str(seed)) @(DIFF_PATH + '/diff_from.csv.xz')
xz -dv @(DIFF_PATH + '/diff_from.csv.xz')
```

直近の更新を確認してみたところ、以下のようになりました。

```
delete 767
put 2653
edit 0
```

詳細を読むと以下のような感じでした。（抜粋。< が削除で > が追加）

```
< イェルクフェルバー
< イェルク・フェルバー
< イェルマーク
< イェレナ
< イエローキッド
< イエロー・キッド
< イゴールオジム
< イゴール・オジム
< イバラキケンドウサンジュウニゴウダイゴミワセン
< イマージュエンターテインメント
< イーゴリジューコフ
< イーゴリ・ジューコフ
< ウェスタ神殿
< ウォルターヴァンベイレンドンク
< ウガヤフキアエズ
< ウドムルトの首長

> イイジャンファクター
> イェベホイビェア
> イェベ・ホイビェア
> イェルクフェルバー
> イェルク・フェルバー
> イェルマーク
> イェレナ
> イエスプライムミニスター
> イエス・プライム・ミニスター
> イエローキッド
> イエロー・キッド
> イエンバイ
> イギリスの欧州連合離脱是非を問う国民投票
> イゴールオジム
> イゴール・オジム
> イタロケルト語派
> イタロ・ケルト語派
> イッタイデンドウニナニガオキタノカ
> イナリ
> イルダガデア
> イルダ・ガデア
> インガロンダキング
> インガ・ロンダ・キング
> インターナリン
> インナーウエア
> インプロバブルワールズ
> インプロバブル・ワールズ
> イーゴリジューコフ
> イーゴリ・ジューコフ
> イーストサイド名店街
> ウィザーディングワールド
> ウィザーディング・ワールド
> ウィネパングの戦い
> ウェスタ川越
> ウェストコーストポップ
> ウェストサイドストーリー
> ウェストサイド物語
> ウェストナイルウイルス
> ウェスト・サイド物語
> ウェディングバトルアウトな男たち
> ウェディング・バトルアウトな男たち
> ウェブユーエスビー
> ウェンディージム
> ウエスタングローバルエアラインズ
> ウエスタン・グローバル・エアラインズ
> ウエストバージニア
> ウエストヴァージニア州
> ウォルターデシルヴァ
> ウォーフロント
> ウガヤフキアエズ
> ウソ発見器
> ウドムルトの首長
```

単語だけ出力したので、品詞情報だけ変更になっているものもありそうですね。
今回スクリプト書いてみて、追加だけでなく削除も行って品質を向上させているのが判って良かったです。

aliases に設定しても良さそうですし、[@NEologdOfficial](https://twitter.com/NEologdOfficial) で更新のアナウンスがされた際などに実行して確認してみたいと思います。

### 参考になった記事
[Pythonistaに贈るXonshのススメ](https://vaaaaaanquish.hatenablog.com/entry/2017/11/30/175236)
AWSでRDSを立ててインターネットから接続したい時、ネットワークACLの追加も忘れずに

いやまあ知らなかっただけなんですが...。

## こんな感じで
RDSが存在するVPCのネットワークACLに

![image.png](https://qiita-image-store.s3.amazonaws.com/0/25416/34800676-c00c-c11f-0480-326ea14b6f64.png)

3306を追加しましょう。
AWSコンソールにてMFAログインができなくなった

# 背景
ある日突然、AWSにログインできなくなった！？
なんでだ。

<img width="418" alt="スクリーンショット 2018-08-28 14.55.30.png" src="https://qiita-image-store.s3.amazonaws.com/0/105662/c41c3283-ebd9-4b93-21c6-2adde76633d0.png">

MFAデバイスとパスコードはあっているのになあ。

# 対処方法
- MFAのトラブルシューティングをクリック
<img width="418" alt="スクリーンショット 2018-08-28 14.55.30.png" src="https://qiita-image-store.s3.amazonaws.com/0/105662/41051d9f-fb99-0021-e6d3-7fa2396d4898.png">

- MFAデバイス再同期をクリック
<img width="898" alt="スクリーンショット 2018-08-28 14.51.14.png" src="https://qiita-image-store.s3.amazonaws.com/0/105662/f121e41c-c3ec-f240-70a7-ca4fea3296c6.png">


- MFAデバイスのワンタイムパスワードを二連続で入れる。

一回入れて、30秒後ぐらい後で更新されたものを下の欄に入れる）
これでログインできました。


<img width="957" alt="スクリーンショット 2018-08-28 14.51.20.png" src="https://qiita-image-store.s3.amazonaws.com/0/105662/b3c07af6-8df2-cf00-9d34-4b58cde3732b.png">


# ログインしたあとは・・・
iamからMFAデバイスと再度同期しておきましょう。
でないと、また同じことが起きます。

# 原因
デバイスにはiphone使ってるんですが、どうやらデバイスの時計のずれで起きるみたいですね。
試してないですが。