OmniAICreator/Qiita-1.07M huggingface dataset:
Lightsailインスタンスのスナップショット管理

#概要
Lightsailインスタンスのスナップショット管理の自動化について検討してみる。検討する機能は２つ。

1. Lightsailインスタンスのスナップショットを取得する
2. Lightsailインスタンスのスナップショットを削除する

いずれも設定したスケジュールに従って自動実行する。これにより、何世代かのスナップショットを残しつつ、無尽蔵にたまらないよう古いものはガーベージされる。

#構成
CloudWatch EventsとLambdaの組み合わせで実現する。スナップショット作成用、スナップショット削除用でそれぞれCloudWatch EventのルールとLambdaファンクションを作成する。

#実装
まずはLambdaファンクションを2つ作成する。
##スナップショット作成
```lambda_function.py
# -*- coding: utf-8 -*-
import boto3
import os
import datetime

client = boto3.client('lightsail')

#Lightsailのインスタンス名。Lambdaファンクションの環境変数から受け取る
name = os.environ['instancename']

def lambda_handler(event, context):

    #スナップショットファイル名に付加するタイムスタンプ
    timestamp = datetime.datetime.now().strftime('%Y%m%d-%H%M%S')

    try:
        #スナップショットの作成
        response = client.create_instance_snapshot(
            instanceSnapshotName = name + '-' + timestamp,
            instanceName = name
        )
    except Exception as e:
        print(e)
        raise e
```
Lightsailのインスタンス名はLambdaファンクションの環境変数としてセットする。

##スナップショット削除
```lambda_function.py
# -*- coding: utf-8 -*-
import boto3
import os
import datetime

client = boto3.client('lightsail')

#Lightsailのインスタンス名。Lambdaファンクションの環境変数から受け取る
name = os.environ['instancename']

def lambda_handler(event, context):

    #Lightsailのスナップショットのリストを取得
    response = client.get_instance_snapshots()

    #インスタンス名でフィルタ
    filterdList = filter(lambda x: x['fromInstanceName'] == name, response['instanceSnapshots'])

    #作成時刻でソート
    sortedList = sorted(filterdList, key=lambda x:x['createdAt'])

    #削除対象が存在する場合
    if len(sortedList) > 0:
        try:
            #最も古いスナップショットを削除
            response = client.delete_instance_snapshot(
                instanceSnapshotName = sortedList[0]['name']
            )
        except Exception as e:
            print(e)
            raise e
```
この例では一番古いスナップショットを問答無用で削除する。「n世代は確実に残す」という考慮をしたい場合は、作成時刻の新しい順でソートしてn+1番目以降を削除する、といったロジックにする必要がありそう。

##CloudWatch Events
CloudWatch Eventsのルールを２つ作成する。「イベントソース」は「スケジュール」を選択し、任意のスケジュールを設定。ターゲットとしてさきほど作成したLambdaファンクションを指定。その他のオプションはデフォルトのままでOK。
phpでスクライピングをやってみた part2

#始めに
[前回の続き](https://qiita.com/triple4649/items/722553d222b2c4f8a168)です

#あれこれやってうまくいきました

まずは、うまくいったソースと結果を示します

```sample.php
<?php
$dom = new DOMDocument();
$dom->loadHTML(file_get_contents('https://finance.yahoo.co.jp/'));
$target=array_filter(
    iterator_to_array($dom->getElementsByTagName('a')),
    function($a){return $a->getAttribute('data-ylk')==='slk:yoso;pos:1';}); 
array_walk($target, function($value, $key){echo $value->nodeValue;});

?>
```
出力結果
```
[買い] Ｈａｍｅｅ 本田隆一郎
```
#なぜうまくいかなかったか？

- `DOMDocument::load('https://finance.yahoo.co.jp/');`　は非推奨のようだった
- `load` は厳格なxmlファイルに用いるべき 厳格ではないhtmlソースには`loadHtml`を用いるべきだった
エラーの情報を取得するmessageとwith_traceback

# Python 3.6.3 でエラーの情報を取得する際に`.message`が使えなかった。

2015年にQiitaにまとめられた記事でpythonの勉強をしていて、エラーの情報を取得する回に

```[example.py]
try:
    a = 10 / 0
    print("{0}".format(a))
except ZeroDivisionError as e:
    print("message:{0}".format(e.message))
```
と処理する際に

```
Traceback (most recent call last):
  File "py3.division_by_zero_info.py", line 9, in <module>
    print("message:{0}".format(e.message))
AttributeError: 'ZeroDivisionError' object has no attribute 'message'
```
とAttributeErrorが出てうまく取得できなかった。


# `dir()`でエラーの持つアトリビュートが調べられる
色々調べまわっていると、`dir()`でオブジェクトの持つアトリビュートの一覧を確認できることを発見して早速試すと、

```[dir.py]
try:
  a = 10 / 0
  print("{0}".format(a))
except Exception as e:
  print(dir(e))
```
以下、結果

```
['__cause__', '__class__', '__context__', '__delattr__', '__dict__', '__dir__', 
'__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', 
'__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', 
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setstate__', 
'__sizeof__', '__str__', '__subclasshook__', '__suppress_context__', '__traceback__', 
'args', 'with_traceback']
```
バーっと出てきた。`args`は問題なさそう。`message`は見当たらない。

気になるのでバージョンを下げて（2.7.14)、もう一度`dir()`を試す。

```
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__',
 '__getitem__', '__getslice__', '__hash__', '__init__', '__new__', '__reduce__', 
'__reduce_ex__', '__repr__', '__setattr__',
'__setstate__', '__sizeof__', '__str__', '__subclasshook__', '__unicode__', 
'args', 'message']
```

`message` 発見ーーーー。

# `message`で出力する
2.7.14のまま`message`で出力してみる。

```[message.py]
try:
  a = 10 / 0
  print("{0}".format(a))
except Exception as e:
  print("message:{0}".format(e.message))
```
以下、結果

```
message:integer division or modulo by zero
```
ちゃんと取得できた！

# `with_traceback`で出力する
3.6.3に戻して`with_traceback`で出力する。
`with_traceback`を使う場合は`sys`をimportしてスタックトレース（処理を順番に格納すること？）の情報を`exec_info()`で取得した上で行う。

```[with_traceback.py]
import sys
try:
  a = 10 / 0
  print("{0}".format(a))
except Exception as e:
  tb = sys.exc_info()[2]
  print("message:{0}".format(e.with_traceback(tb)))
```
以下、結果

```
message:division by zero
```

無事に出力できた。
情報の内容も少し異なっているし、基底になっているクラスの違いもあるようで（内容が異なっているのかはわかってない）、そういうのも関係しているんでしょうか・・・


## お世話になりました。

[Python基礎講座\(11 例外\) \- Qiita](https://qiita.com/Usek/items/53527feba2adcb386aa8)
[Pythonの組み込み例外の木構造を見てみる \- Qiita](https://qiita.com/amedama/items/aa840a0a98f720cfc4ca)
[オブジェクトのアトリビュートの一覧を取得す](http://www.lifewithpython.com/2014/02/python-get-list-of-attirbutes-of-object.html)
[5\. 組み込み例外 — Python 3\.6\.3 ドキュメント](https://docs.python.jp/3/library/exceptions.html)
[29\.1\. sys — システムパラメータと関数 — Python 3\.6\.3 ドキュメント](https://docs.python.jp/3/library/sys.html)
スマート植木鉢Parrot PotとAPIの紹介

[Nextremer Advent Calendar 2017](https://qiita.com/advent-calendar/2017/nextremer) 15日目の記事です

こんにちは、Nextremer園芸部です。Nextremer東京オフィスでは、11月よりIoT植木鉢[Parrot Pot](https://www.parrot.com/jp/gadeningu/parrot-pot#parrot-pot)を使ってホウセンカズラを育てています。今回はparrot potとAPIの使い方を書きます。

## 何ができる？

* 植木鉢内のセンサーで生育環境のデータを計測
    * 土壌湿度
    * 照度
    * 気温
    * 肥料レベル
* スマホアプリで状態を管理、日、週、月、年単位でグラフが見られる
* 土壌湿度が閾値まで下がると自動で水やり可能
* Bluetoothでスマホと同期した際、植木鉢内のメモリに保存されているデータがクラウドにアップロードされる
    * python、raspberry pi、AndroidでAPIが利用可能。CSVをdumpしてくれる

## 初期設定

1. 植木鉢の上層部を開けて単３電池４本を挿入
2. 鉢の中に腐葉土を入れ、育てたい植物を植える
3. iPhone, AndroidでFlower Powerをダウンロード
4. 植物DBから自分の育てる植物を選択、Bluetoothで同期
5. 育成開始


## APIの使い方(python)

①
[Parrot Flower Power for Developer](http://developer.parrot.com/docs/FlowerPower/#flower-power-cloud-api)からアクセスキーとシークレットキーを取得します。

②
Flower Power APIをgit clone

※APIは2系で書かれているので、3系で使いたい方はApiCloud.pyとCSVDump.pyのprint文が使われている箇所を書き直す必要があります

③
main.pyにアクセスキー、シークレットキー、ログインネームとパスワードを入力します。

```
username = 'YOUR_USERNAME'
password = 'YOUR_PASSWORD'

client_id = 'CLIENT_ID'
client_secret = 'CLIENT_SECRET'
```

これでmain.pyを実行

```
Loggin successful!
Dump Parrot pot 9d0c.csv
 From: 2017-11-28 17:35:57
 To:   2017-12-05 17:35:57
```

取得する期間は、main.pyの中の
```
dumpAllFlowerPower(api, since, until)
```
のsinceとuntilに日付を入力することで変更可能。
vimをはじめて3ヶ月の僕が初心者に紹介するvimコマンド

# 最初に
いざ、まとめてみると、めっちゃ多くなったので、個人的に最低限必要な便利コマンドをまとめておきます．(とか言いつつ、バカみたいに多い．．．．．)

# vimにはモードがあるのはご存じ？
- ノーマルモード
- インサートモード
- ビジュアルモード
- コマンドモード

**ノーマルモードがモードの軸になっています．**
Escを押せば、ノーマルモードに戻ります.
(迷ったら、連打ダダダダダダ．．．．)

以下、`:`が書いているやつがコマンドモードです．
例 `:noh` 検索でハイライトしてるやつを消す．(nohlsearch)

あと、ノーマルモードでの移動が`hjkl`でできるのが、面白いですよね．
なれてしまうと、キー移動が面倒になってきますよ（笑）

# コマンド一覧
## ノーマルモード
### モード変更
おすすめは`o`ですね．行末にいなくても改行できるのが神

|cmd|function
|:--:|:--
|`i`  |インサートモードへ
|`o`  |下に行を追加して、インサートモードへ
|`v`  |ビジュアルモードへ
|`C-v`|ビジュアルモード矩形

### 移動
`C-u``C-d`は意外と便利で、長文の移動は流石に`hjkl`ではキツいっす．

|cmd|function
|:--:|:--
|`gg` |最初の行に移動
|`G`  |最後の行に移動
|`C-u`|1ページ上に移動
|`C-d`|1ページ下に移動
|`0`  |行頭に移動
|`$`  |行末に移動
|`zz` |現在のカーソル位置を中心に持ってくる
|`w`  |1ワード後ろに移動(ワード先頭)
|`e`  |1ワード後ろに移動(ワード末尾)
|`b`  |1ワード前に移動(ワード先頭)
|`b`  |1ワード前に移動(ワード末尾)


### 編集
`C-r`がredoなんですね.あと、数字の増減がコマンドで出来るなんて、あと、vimrcの記述で数字だけじゃなくて、文字も増減できるんですよ．(a->b->c...)

|cmd|function
|:--:|:--
|`u`  |1つ前に戻る (undo)
|`C-r`|1つ先に進む (redo)
|`x`  |カーソル位置の文字を削除
|`dd` |1行削除
|`yy` |1行コピー (yank)
|`p`  |コピーしたやつをペースト (paste)
|`C-a`|数字をインクリメント
|`C-x`|数字をデクリメント

###　検索・置き換え
ここは''で囲まれたやつは変更できる

|cmd|function
|:--:|:--
|`r '1word'`            |カーソル一の1文字を'1word'に置き換え
|`/'word'`              |'word'で検索してハイライト
|`:%s/'before'/'after'/`|'before'から'after'に置き換え

###　その他
|cmd|function
|:--:|:--
|`:w` |上書き (write)
|`:q` |終了 (quite)
|`:q!`|上書きせずに強制終了


## インサートモード
コレはMakefileくらいでしか使わないですけど

|cmd|function
|:--:|:--
|`C-v + tab`|vimrcの設定でtabきーがスペースになっちゃた時にtabを打つ方法

# 最後に
本当は便利コマンドはもっといっぱいあって、奥が深いんですよね．
個人的にワード単位での処理ができるのが面白いんですんが、
それはまた別の記事で(書くとは言っていない．)
Ionic3でNative pluginのgoogle-maps使用時、公式ドキュメント通りに実装しても地図が表示されない問題を修正

[公式ドキュメント](https://ionicframework.com/docs/native/google-maps/)にしたがって実装しても地図が表示されない問題が起きました。

[cordova-plugin-googlemaps](https://github.com/mapsplugin/cordova-plugin-googlemaps)自体のバージョンが2.1.1にバージョンが上がっている関係なのでしょうか？リリースノートを見ていないので何とも言えないですね。(Ionicの公式ドキュメント上では2.0.0想定のようです。)

以下に対応した内容を公式ドキュメントとの差異のみで記述しておきます。

## 前提
作業環境:

```
@ionic/cli-utils  : 1.19.0
ionic (Ionic CLI) : 3.19.0
cordova (Cordova CLI) : 7.1.0
@ionic/app-scripts : 3.1.5
Cordova Platforms  : android 6.3.0 ios 4.5.4
Ionic Framework    : ionic-angular 3.9.2
Node  : v8.9.1
npm   : 5.5.1
OS    : macOS High Sierra
Xcode : Xcode 9.2 Build version 9C40b
```

## 対応内容
-1. `Platform` プラグインをインポート。

```home.ts
import { Platform } from 'ionic-angular';
```

-2. コンストラクターに `platform` の記述を追加。そのため `ionViewDidLoad` から `loadMap()` メソッドを削除しておく。

```home.ts
  constructor(public platform: Platform) {
    platform.ready().then(()=>{
      this.loadMap();
    })
  }
```

-3. `loadMap()` メソッドを以下のように変更。(このメソッドのみ変更差分だけでなく、全文記述しました。手抜きです。すみません。)

```
  loadMap() {
    let element: HTMLElement = document.getElementById('map_canvas');
    let mapOptions: GoogleMapOptions = {
      camera: {
        target: {
          lat: 43.0741904,
          lng: -89.3809802
        },
        zoom: 18,
        tilt: 30
      }
    };
    let map: GoogleMap = GoogleMaps.create(element, mapOptions);

    // Wait the MAP_READY before using any methods.
    map.one(GoogleMapsEvent.MAP_READY)
    .then(() => {
      console.log('Map is ready!');

      // Now you can use all methods safely.
      map.addMarker({
        title: 'Ionic',
        icon: 'blue',
        animation: 'DROP',
        position: {
          lat: 43.0741904,
          lng: -89.3809802
        }
      })
      .then(marker => {
        marker.on(GoogleMapsEvent.MARKER_CLICK).subscribe(() => {
          alert('clicked');
        });
      });
    });
  }
```

以上により、　 `$ ionic cordova run android --devise --prod` 等で実行すると地図がしっかりと表示されます。ネイティブプラグインなので、例にもれずブラウザでの動作確認は出来ませんのでご注意を。

## 参考:
https://github.com/mapsplugin/cordova-plugin-googlemaps/issues/1873

## 補足
公式ドキュメントにhtml側の記述が記載されていませんが、以下の通り記述することで問題なく表示されます。

```
<ion-content>
  <div style="height: 100%;" id="map_canvas"></div>
</ion-content>
```
new Date() のスタブを作る

### 概要

JavaScriptのユニットテストを実行する場合、`Date.now()` や `new Date()` をスタブ化して指定した値を返すようにしたい場合がある。
`Date.now()` は単にメソッドを置き換えれば良いだけだが、`new Date()` のスタブは一見迷ってしまうのでここに記録しておく。

### TL;DR

```js
var OriginalDate = Date;
Date = function () { return new OriginalDate(2017, 0, 1); };
Date.prototype = OriginalDate.prototype;
```

### 説明

- `Date = function () { return new OriginalDate(2017, 0, 1); };` でコンストラクタを置き換える
- さらにprototypeもコピーすることで、 `(new Date()) instanceof Date` されてもtrueを返せる
- `Date.now()`, `Date.UTC()`, `Date.parse()` には対応していないので必要に応じて追加する
nginxを利用したAlfresco用プロキシサーバの設定

# SharePointサーバを443ポートで利用したい

[前回の記事](https://qiita.com/whale_shark/items/07bbb5db006aa3dc0f95)でAlfrescoサーバをインストールした。

SSL経由出ないとOfficeを経由した、SharePointのサービスが利用できない。

標準で提供されているTomcatの8443ポートを利用する方法もある。
この方法は美しくないので、Alfrescoサーバの手前にnginxを配置してポートフォワードさせる。

# 手順

基本的には、Alfresco公式の[ドキュメント](http://docs.alfresco.com/community/tasks/configure-ssl-prod.html)にしたがうが、Alfrescoのドキュメントでは、httpdを利用しAJPで接続している。

今回は、nginxを利用しAJPではなくポートフォワードで解決する。

## nginxのインストール

この人の記事を参考。

https://qiita.com/MuuKojima/items/afc0ad8309ba9c5ed5ee

## Alfrescoの設定

global-config.properties に以下の設定をそれぞれ追加・変更する。

```bash:alfresco_install_dir/tomcat/shared/classes/alfresco-global.properties(変更)
alfresco.context=alfresco
alfresco.host=<ホスト名>
alfresco.port=443
alfresco.protocol=https
share.context=share
share.host=<ホスト名>
share.port=443
share.protocol=https
```
```bash:alfresco_install_dir/tomcat/shared/classes/alfresco-global.properties(追加)
opencmis.context.override=true
opencmis.context.value=
opencmis.servletpath.override=true
opencmis.servletpath.value=
opencmis.server.override=true
opencmis.server.value=https://<ホスト名>
aos.baseUrlOverwrite=https://<ホスト名>/alfresco/aos
```

## nginxの設定

nginx側のポートフォワードの設定を行う。
デフォルトはhttpからhttpsに変更する。

```bash:/etc/nginx/conf.d/default.conf
server {
    listen       80;
    server_name  <ホスト名>;

    return 301 https://$host$request_uri;
 #以下デフォルト値
```

httpsの設定

```bash:/etc/nginx/conf.d/https.conf
server {
     listen 443 ssl;
     server_name 192.168.9.200;
     proxy_set_header X-Real-IP $remote_addr;
     proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
     proxy_set_header Host $http_host;
     proxy_redirect off;
     proxy_max_temp_file_size 0;
     ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
     ssl_prefer_server_ciphers on;
     ssl_ciphers ECDHE+RSAGCM:ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:!aNULL!eNull:!EXPORT:!DES:!3DES:!MD5:!DSS;
     ssl_certificate      <証明書>;
     ssl_certificate_key  <鍵>;

     location / {
        proxy_pass https://192.168.9.200:8443;
     }
}
```

証明書と鍵はopensslとかでとりあえず作成したものを設定しておく。

後日、証明書の作り方も記事にします。

## サービスの再起動

```bash:alfrescoの再起動
# systemctl stop alfresco
# cd <alfresco_install_dir>
# ./alfresco.sh status
tomcat already running
postgresql already running
# ./alfresco.sh stop
# systemctl start alfresco
```

*なぜかサービスを上手に停止できません。そのため時間かかります…誰か教えて*

```bash:nginxの再起動
# systemctl stop nginx.service
# systemctl start nginx.service
```
echoでyaagを使う

いろいろ省略して以下の部分のコードだけあればechoで[yaag](https://github.com/betacraft/yaag)が使える。
公式のREADMEにサンプルコードがまだないのでコントリビューションできるチャンスかも。

```go
package main

import (
	"github.com/betacraft/yaag/echo"
	"github.com/betacraft/yaag/yaag"

	// ...(省略)...
)

func main() {
	yaag.Init(&yaag.Config{On: true, DocTitle: "API", DocPath: "docs/apidoc.html"})

	server := echo.New()
	server.Use(middleware.Yaag())

	// ...(省略)...
}
```
ピクトグラムを作ろう

「[たのしいインフォグラフィック入門](https://www.amazon.co.jp/%E3%81%9F%E3%81%AE%E3%81%97%E3%81%84-%E3%82%A4%E3%83%B3%E3%83%95%E3%82%A9%E3%82%B0%E3%83%A9%E3%83%95%E3%82%A3%E3%83%83%E3%82%AF%E5%85%A5%E9%96%80-%E6%AB%BB%E7%94%B0-%E6%BD%A4/dp/4861008530/ref=tmm_pap_swatch_0?_encoding=UTF8&qid=1513248063&sr=8-2)」を読んだ。

インフォグラフィック制作のためのステップとして、

1. ピクトグラム（基礎体力作り）
2. 図解（基礎体力作り）
3. インフォグラフィック
  
という構成になっている。

今回はそのうち、ピクトグラムについてのインサイトを書いてみる。

## 「ピクトグラム」とは
言葉の代わりになったり、言葉を補うグラフィックのこと。

- 言葉で説明するスペースが足りない
- じっくり説明する時間がない
- 言語が通じない

等の課題を解決するために使用される。

## 利用シーン
 - 公共の場（標識とか）
 - プレゼン資料
 - 製品パッケージ・取扱説明書
 - デバイス操作画面やwebサイトなどのインターフェイス
 - 動画
 - アート

などなど...

## 製作フロー
解析作業とデザイン作業に分かれる。

  1. 利用目的の確認（解析作業）
  2. 対象の理解（解析作業）
  3. ラフスケッチ（デザイン作業）
  4. 清書（デザイン作業）
  5. 調整（デザイン作業）


## 実践[WIP]
※このセクション、あとで追記するかも
### **①利用目的の確認**

- **写真やイラストではなく、なぜピクトグラムなのか？**
  - 何箇所かで使い回すため？
  - スペース的な問題？
  - バリエーションを作る工数がかからないから？
  - 具体的なイメージを持たせたくない・対象を抽象化したい？

- **どこで使うのか？**
  - 屋外？
      - 遠くからでも識別できるように気をつける
  - 屋内？
  - 紙媒体？
      - 利用者が限定されるため、ターゲットに合わせてオリジナルのものを作る機会が多い
  - 画面ごし？
      - 利用シーンにおいて考えうる一番小さいサイズで制作する（潰れる可能性を考慮）

- **誰に向けて？**
  - できるだけ多くの人に向けて（汎用的）
  - 年齢・性別・嗜好で絞り込み（特徴的）

- **何を？（伝えたい情報は何か）**
  - ルール：「xxしてはいけません」、「xxを守ってください」
      - 制限速度・喫煙禁止など
  - 機能：「xxするにはこれです」
      - 音楽機器の「早送り」・エレベーターの開閉など
  - 状態:「現在xxです」
      - 電池の残量・音量など
  - 場所「ここはxxです」、「xxはあそこです」
      - 非常口、トイレ、駐車場など
  - 区別：「これはxxです」
      - オリンピック競技種目の区別・ゴミの分別など

### **②対象の理解**
**キーワードの抽出を行う**
例えば、「マリー・アントワネット」を意味するピクトグラムを作る場合には、「マリー・アントワネット」と聞いて思いつくキーワードを挙げていく。
「フランス・ヴェルサイユ・ドレス・仮面舞踏会・浪費・(パン・お菓子)・革命」など...（括弧内は事実と異なる部分があるので一応囲んでおきました）

### **③ラフスケッチ**
抽出したキーワードをもとに、思い浮かぶモチーフをスケッチする。
キーワードからモチーフが浮かばない時は、キーワードからさらに連想する言葉を挙げていく。
例えば「ヴェルサイユ」であれば、「バラ」「宮殿」などなど。

ラフスケッチの最大の目的は、表現の可能性を洗い出すことなので、紙と鉛筆など、アナログツールで進めると良い。

<img src="https://qiita-image-store.s3.amazonaws.com/0/74592/37bb992a-35fb-1946-887e-0bdf1b803654.jpeg" width=350px>
なんかこんなのを色々描き出して行って、この後モチーフ同士を組み合わせたり、足し引きして「マリー・アントワネット」に近付けていくイメージ。

### **④清書・⑤調整**
周囲の人にラフスケッチを見てもらいながら意見を募り、清書するものを選んだら、デジタルツールで清書していく。
最後に、実際の利用イメージに合わせてテイストを調整したら完成。


## まとめ
今回まとめた手法は、ピクトグラムを作る時だけでなく、アイコンや挿絵を選ぶ時などにも活かせそうです。
他にも色々載っていたので、ご興味ある方はぜひ一読することをオススメします => [たのしいインフォグラフィック入門](https://www.amazon.co.jp/%E3%81%9F%E3%81%AE%E3%81%97%E3%81%84-%E3%82%A4%E3%83%B3%E3%83%95%E3%82%A9%E3%82%B0%E3%83%A9%E3%83%95%E3%82%A3%E3%83%83%E3%82%AF%E5%85%A5%E9%96%80-%E6%AB%BB%E7%94%B0-%E6%BD%A4/dp/4861008530/ref=tmm_pap_swatch_0?_encoding=UTF8&qid=1513248063&sr=8-2)

## [PR] 仲間を探しています！
アトラエで一緒に、世界中を魅了するサービスづくりに挑戦したい仲間を募集中です！
https://www.green-japan.com/company/172?job_offer_id=10594
あると便利なwindowsのbatファイル

別に無くても問題ないですが、あると便利なbatファイルです。
検索するとすぐ出てきますけど、メモも兼ねて。

## VPN接続・切断

VPNに接続する際に、いちいち設定からポチポチ開くのも面倒なので、下記コマンドを実行するbat作っておけば便利です。

```bat

@echo off
rasdial.exe VPN user pass
```

ユーザとパスワードを指定する場合は、

```bat

@echo off
rasdial.exe VPN * * 
```

こうしておけばOKです。

また、いろいろと問題があるので、ユーザとパスワードは毎回指定したほうが無難ですね。

VPNの切断はこんな感じです。

```bat

@echo off
rasdial.exe VPN /DISCONNECT
```


接続と切断をセットでbatを作成しておくと少し手間が省けます。ちっちゃいストレスから解放されます。

## リモートデスクトップ接続

あるとものすごく便利です。
仕事柄いろんなところにアクセスするので。。。。


```bat

@echo off
Set SERVER=XXX.XXX.XXX.XXX
Set USERNAME=user
Set PASSWORD=pass
 
Cmdkey /generic:TERMSRV/%SERVER% /user:%USERNAME% /pass:%PASSWORD%
Start mstsc /v:%SERVER%
Timeout 2
Cmdkey /delete:TERMSRV/%SERVER%
```

これも、パスワードなどが丸見えなので、

```bat

@echo off
Set SERVER=XXX.XXX.XXX.XXX
Set /P USERNAME="ユーザ："
Set /P PASSWORD="パスワード："
 
Cmdkey /generic:TERMSRV/%SERVER% /user:%USERNAME% /pass:%PASSWORD%
Start mstsc /v:%SERVER%
Timeout 2
Cmdkey /delete:TERMSRV/%SERVER%
```

「/P」で設定して入力できるようにしてしまえばいいんではないかと思います。

## まとめ
書いていて思いましたが、接続系ばっかですね。。。
その辺を自分が面倒と感じていることが改めてわかりました。

まだまだちょっとしたストレスを解消できるものがあると思うので見つかれば追加していきます。
マイクロサービスざっくり

# Reference
<img width="200" alt="2017-11-27 14 03 25" src="https://www.oreilly.co.jp/books/images/picture_large978-4-87311-760-7.jpeg">  
https://www.oreilly.co.jp/books/9784873117607/

--- 
# 目次
- **1章 マイクロサービス**  
- **2章 進化的アーキテクト**  
- **3章 サービスのモデル化方法**  
- **4章 統合**  
- **5章 モノリスの分割**  
- **6章 デプロイ**  
- **7章 テスト**  
- **8章 監視**  
- **9章 セキュリティ**  
- **10章 コンウェイの法則とシステム設計**  
- **11章 大規模なマイクロサービス**  
- **12章 まとめ**  

---

# まずは

---

# マイクロサービスとは
**協調して動作する小規模で自律的なサービス**

# Golden Role
**「他には何も変更せずに、単独でサービスの変更やデプロイを行えるか。」**

---

# メリット
####技術異質性
サービスごとに異なる技術を使う決断ができる。
また影響範囲が狭いため、その決断を迅速に行う事ができる。  
#### 回復性
単一障害点を回避し、障害に応じて機能低下させるシステムを構築可能。
マイクロサービス(分散システム)特有の障害も存在することを理解しなければならない。  
#### スケーリング
サービス単位でのスケジューリングが可能なので、モノリシックサービスに対して効率的にスケーリングが可能。
#### デプロイ容易性
変更の影響範囲を小さくすることができるため、迅速にデプロイが可能。
問題が生じた場合は、問題の原因である個別のサービスを迅速に特定、ロールバックを実現。  
#### 組織面の一致
アーキテクチャを組織により良く一致させることができ、1つのコードベースで作業する人数を最小化し、チームの大きさ、生産性を最適化する。  
#### 合成可能性
分散システムとSOAの主な利点の1つは、機能を再利用する機会を広げること。
目的に対して様々な方法で機能を利用可能。  
#### 交換可能にするための最適化
サービスが小さければ、サービスの置き換え、削除に対する障壁が小さくなる。
レガシーシステムを残しにくい。  

--- 
# 大切なこと
---
# 成功のためには
マイクロサービスは様々な分野の技術や方法論を組み合わせることで成り立っています。

- SOA(サービス指向アーキテクチャ)
- DDD(ドメイン駆動設計)
- CI・CD(継続的インテーグレーション・デリバリ)
- インフラ仮想化
- 自動化
- アジャイル開発プロセス
- などなど

**これらの総合的に実践することで初めて本領を発揮します。**

---
# 最低限必要な標準ルール
- 各マイクロサービスと、システム全体の状態を監視するための仕組みやルール。
 
- マイクロサービスがAPIを公開するための標準技術やルール。

- あるマイクロサービスの障害がシステム全体に波及しないようにするための仕組みやルール。

---
# サービスの分け方、繋ぎ方
---

# 基本的な考え方  
**凝集性**: 変更する理由が同じものは集める、変更する理由が違うものは分ける  

**疎結合**: 連携するサービスに関して必要最低限のことだけしか把握しない。  

--- 

# 境界づけられたコンテキスト
「[Domain-Driven Design](https://domainlanguage.com/ddd/reference/)」で述べられている概念。
[わかりやすかった記事(日本語)](http://little-hands.hatenablog.com/entry/2017/11/28/bouded-context-concept)

# データは境界を決定する第二条件であるべき
大事なのは「何を行うか」
そして「そのためにはどんなデータが必要か」と考える
同じデータだからとまとめると凝集性が逆に下がってしまう。

--- 

# 繋ぎ方
## **共有データベース**
DBは事実上、脆弱な大規模API
いかなる代償を払ってでも避けるべき

## **同期通信、非同期通信**
- リクエスト/レスポンス  
リクエストを発行し、レスポンスを待つ
- イベントベース  
イベントを通知するだけ

#### オーケストレーションとコレオグラフィー
あるサービスとその下流となる複数のサービスによってひとつの処理が構成される場合の制御方法

- **オーケストレーション**  
基点となるサービスが下流サービスをリクエスト/レスポンスでフロー制御  
基点となるサービスが神サービスになりがち
- **コレオグラフィー**  
基点となるサービスがイベントベースでイベントを発行し、下流サービスがそれを受信して個々に処理を行う  
**コレオグラフィによる連携を模索すべき**

## **コード共有**
よく言うDRYは危険
全てのサービスに渡るDRYには寛大になるべき
コードの重複 << サービス間の結合

---

# DBの分割
外部キーやトランザクションを失う  
CAP定理ってやつ、整合性／可用性／分断耐性  
一般的にはAPシステムを選択する  
整合性が取れていない状態を表現するドメインの概念(例 処理中の注文など)を導入  
分散トランザクション

---

# 後半
- デプロイ
- テスト
- 監視
- セキュリティ
- コンウェイの法則とシステム設計
- 大規模なマイクロサービス

---

# 最後に
あくまで手段。
SOA、DDDのためのマイクロサービス。
決して銀の弾丸ではない。
課題レポート：【アルゴリズム】本を管理するアプリをつくってみよう！

課題

 ``` 
def input_book_info
  book = {}
  puts "本の名前を入力してください："
  book[:name] = gets.chomp
  puts "本の値段を入力してください："
  book[:price] = gets.to_i
  puts "出版社を入力してください："
  book[:company] = gets.chomp
  books << book
end

def show_book_info(books)
  unless books.empty?
    books.each do |book|
      put "番号:[#{index}], 本の名前: #{book[:name]}"
      index += 1
    end

    puts "詳細を見る本の番号を入力してください："
    input = gets.to_i
    book = books[input]

    puts "本の名前: #{book[:name]}\t|値段: #{book[:price]} 円\t|出版社: #{book[:company]}"
  else
    puts "本が登録されていません。"
end

def end_program
  puts "ご利用ありがとうございました"
  exit
end


books = []

while true do
  puts "登録された本の数：#{books.length}"
  puts "[0]:本の情報を入力する"
  puts "[1]:本の名前を一覧表示する"
  puts "[2]:プログラムを終了する"
  input = gets

  if input == 0
    input_book_info(books)
  elsif input == 1
    show_book_info(books)
  else
    end_program
  end
end
 ``` 
まず、エラー表示によりend抜けを推測、unlessに対するend抜けは素早く発見できたが、その後エラー表示がなくなるので困った。プログラムは一応走るが、[0]:本の情報を入力する　[1]:本の名前を一覧表示する　がelse扱いになっているので、input以下に間違いがあると当初推測していたが、gets.to_iの単純な記述不足であった。その後リタイアしてしまったが…
以下　def show_book_infoのindex = 0の定義づけの抜け、1行目の引数の記述不足、他、じっくり眺めればわかる問題だった。要注意。

解答

 ```
def input_book_info(books)
  book = {}
  puts "本の名前を入力してください："
  book[:name] = gets.chomp
  puts "本の値段を入力してください："
  book[:price] = gets.to_i
  puts "出版社を入力してください："
  book[:company] = gets.chomp
  books << book
end

def show_book_info(books)
  unless books.empty?
    index = 0
    books.each do |book|
      puts "番号:[#{index}], 本の名前: #{book[:name]}"
      index += 1
    end

    puts "詳細を見る本の番号を入力してください："
    input = gets.to_i
    book = books[input]

    puts "本の名前: #{book[:name]}\t|値段: #{book[:price]} 円\t|出版社: #{book[:company]}"
  else
    puts "本が登録されていません。"
  end
end

def end_program
  puts "ご利用ありがとうございました"
  exit
end


books = []

while true do
  puts "登録された本の数：#{books.length}"
  puts "[0]:本の情報を入力する"
  puts "[1]:本の名前を一覧表示する"
  puts "[2]:プログラムを終了する"
  input = gets.to_i

  if input == 0
    input_book_info(books)
  elsif input == 1
    show_book_info(books)
  else
    end_program
  end
end

 ```
Android Studio いろいろ

# 設定編
## 複数プロジェクトを別ウィンドウで開く
他のプロジェクトを参考にしながら、コーディングしたい時にこの設定にしておくと便利。
デフォルトだと他のプロジェクトを開くと、現在開いているプロジェクトが閉じられてしまいます。

設定方法
Preferences（Macのショートカットは「⌘ + ,」）から、
Appearance & Behavior -> System Settingsを開く

Project Openingの項目を
"Open project in new window" にすればOK
![image.png](https://qiita-image-store.s3.amazonaws.com/0/132583/ce2a4e8a-de0b-275c-e19c-fea89da85922.png)


# ショートカット編
経験則で書いているので、きちんと理解したい人はこちらをどうぞ
https://developer.android.com/studio/intro/keyboard-shortcuts.html

## Search Everywhere
Shift2回押し

## パス検索
プロジェクト内の文字列検索の時に使用しています
⌘ + Shift + f

## 定義元へジャンプ（定義元から参照先へジャンプ）
⌘ + b

## 開いているファイルのパスをコピー
⌘ + Shift + c

## コードフォーマット
⌘ + alt + l

## ドキュメントを表示
Ctrl + Space
Swapメモリ使用量が高いプロセスの特定

###まえがき
監視システムでサーバのSwapメモリの使用量を長期間監視していた際に、
徐々に右肩上がりに使用量が増加していることに気づきました。
対処方法を検討するため、まず調査から始めましたが、
監視システムでの監視対象がサーバ全体でのSwapメモリであり、
どのプロセスがメモリを食っているのかを判別できませんでした。

そこでLinux上からすぐに特定プロセスのSwapメモリの使用量を
確認するコマンドを作成しました。

備忘録で置いておきます。
時間ができた際に各コマンドの内容等を追記していきます。

OS環境はRedhat Enterprise Linux 7です。

###コマンド

```Linux:コマンド
grep Swap /proc/[1-9]*/smaps | grep -v '\W0 kB' | tr -s ' ' | cut -d ' ' -f -2 | sort -t ' ' -k2 -n | tr -d ' ' | tail -10
```

これで全ての起動プロセスのうち、
Swapメモリが高いプロセスTOP10を出すようにしています。
複数のFirebase Realtime Databaseに接続したい

# Vue.jsで複数Firebaseに接続したい
簡単なメモ

firebaseモジュールと、それぞれのconfig情報をimportする。

```main.js
import * as firebase from 'firebase'
import {FirebaseConfig} from './firebase-config'
import {secondaryFirebaseConfig} from './firebase-config-second'
```

あ、ちなみにconfig.jsはこんな感じ

```firebase-config.js
export const firebaseConfig = {
  apiKey: 'your_apiKey',
  authDomain: 'your_authDomain',
  databaseURL: 'your_databaseURL',
  projectId: 'your_projectId',
  storageBucket: 'your_storageBucket',
  messagingSenderId: 'your_messagingSenderId',
}
```

そして、それぞれをinitializeする

```main.js
var first = firebase.initializeApp(firebaseConfig)
var secondary = firebase.initializeApp(secondaryFirebaseConfig, 'secondary')
```

[ドキュメント](https://firebase.google.com/docs/web/setup?hl=ja#initialize_multiple_apps)によると、ここでの `'secondary'` はapp.nameを設定しているみたい

```hoge.js
// Initialize the default app
firebase.initializeApp(defaultAppConfig);

// Initialize another app with a different config
var otherApp = firebase.initializeApp(otherAppConfig, "other");

console.log(firebase.app().name);  // "[DEFAULT]"
console.log(otherApp.name);        // "other"
```
S3トリガーでLambdaを使うときの、イベント抜けに対する一つの解法

これは[初老丸Advent Calendar 2017](https://qiita.com/advent-calendar/2017/syoroumaru/)の15日目の記事です。

# S3トリガーのLambda
皆さんLambda使ってますか？Lambdaいいですよね！
特にS3をトリガーに使うと、外部からの処理開始の契機はS3にファイル置くだけだし、どんどん置いていったら適当に並列にLambdaが呼ばれてスケールするしで性能のことも何も考えなくていいので最高です(たぶん)。

ただ、ちょっと注意点もあります。それは、「S3のイベント発火はたまに抜けが出る」という問題です。公式ドキュメントのどこに書いてあるかは探しきれてませんが、実際結構抜けます。

# 例
ここでは例として以下のようなアーキテクチャを考えます。

- 適当なバケットを作って、そこにファイルが置かれたらLambdaが起動する
- 起動したLambdaはそのファイルを処理する
- 処理が終わったらそのファイルを同じバケット内の「bak」というフォルダに移動させる

これ、しばらく動かしてみたら分かりますが、結構bakに移動しないで残ってるファイルが出てくるんですね。これがS3のイベント抜け(と私は呼んでる)です。これは困りました。

# 解法1：SQSを併せて使って処理を開始し、S3のイベント発火に頼らない
一つの解決案として、[cloudpackさんのWhitePaper](https://cloudpack.jp/whitepaper/serverless.html)では、「SQSにファイル名を同時に書き込み、時間起動したLambdaでpollして処理する」というアーキテクチャを挙げられています。

ここでは別解として、S3とLambdaだけで解決する方法を考えてみます。

# 解法2：S3を別のLambdaで見張る
要はS3にいつまでも処理されずに残っているファイルがあるのが問題なわけですから、それを見張っておいて抜けたイベントを再度無理矢理起こしてやればいいわけです。

処理としては

- 時間起動するLambdaを使う
- S3を見て、一定時間以上残っているファイルを一度bakフォルダに移す
- bakフォルダからそのファイルを戻す

でいけるはずです。
以下がサンプルコードになります。

```python:python
# coding=utf-8
import boto3
import os
import re
from datetime import tzinfo, timedelta, datetime

BUCKET_NAME = '対象バケット名'

ZERO = timedelta(0)

class UTC(tzinfo):
  def utcoffset(self, dt):
    return ZERO
  def tzname(self, dt):
    return "UTC"
  def dst(self, dt):
    return ZERO

s3 = boto3.resource('s3');
s3c = boto3.client('s3', region_name='リージョン名')
bucket = s3.Bucket(BUCKET_NAME);

time_threshold = timedelta(minutes=5) # 5分以上残っているものを対象にする

for object in bucket.objects.all():
  if not re.findall(r'^bak/', object.key, flags=re.I):
        key = object.key
        gap = datetime.now(UTC()) - object.last_modified
        if gap > time_threshold:
            res = s3c.copy_object(Bucket = BUCKET_NAME, Key = 'back/'+key+'.bak',CopySource = {'Bucket': BUCKET_NAME,'Key': key})
            res = s3c.copy_object(Bucket = BUCKET_NAME, Key = key,CopySource = {'Bucket': BUCKET_NAME,'Key': 'back/'+key+'.bak'})
```

とりあえずこいつを5分おきにでも動かしておくことで、イベント抜けはなくなりました。最大でも5分の遅延でちゃんと処理されていました。

# 利点
S3とLambdaだけで完結しているのでSQSまで使うのに比べて導入が楽(全体のアーキテクチャをいじらず後付けでいける)のは楽ちんです。
また、S3イベントから呼ばれるLambdaも、処理に失敗したら最後のファイル移動をしないで終了してしまえば5分後にはこいつがイベントを再発火してくれてリトライがかかるので、エラーハンドリングで手を抜けます(それがいいかどうかは別のお話ですが)。

# 注意点
bakフォルダ以下にファイルがたまってくると動作は遅くなってきますので、S3のアーカイブ機能で適当に消してやるなり、そもそもの処理済みファイルの移動先を別のバケットにしてやる等で適宜解決する必要があります。
また、copy_objectが成功するのを前提にしてるので、万一「bakに動かすのは成功したけど、戻すのに失敗した」時はどうにもなりません。そのあたりはご自身でエラーハンドリングを書き足してください。

ファイルを移動しないでもTAGを書き足すとかでもイベントを発火できないかなーと思ったりもしましたが試してませんのでごめんなさい。
画像の外部URLからbase64を取得する

# three.jsをいじっていたら

three.js の [TextureLoader](https://threejs.org/docs/#api/loaders/TextureLoader) にある `load ( url, onLoad, onProgress, onError )` に外部URLを直接入れてもCORSに関するエラーが出てきてしまいました。

```js

var url = 'https://example.com/image.png';
(new TextureLoader()).load(url, (texture) => {
  // texture は three.js の Texture
  // https://threejs.org/docs/#api/textures/Texture
});

```


# サーバ側から叩けば問題ない

CORSについて理解ができていなかった私は (今もまだわかっていない)　サーバ側からリクエストすれば回避できるということを知りませんでした。
というわけで [express](https://www.npmjs.com/package/express) を使ってサーバを立ててしまいましょう。
`TextureLoader.load` の `url` や `<img>` タグの `src` にはbase64を指定できるので、今回はbase64を使っています。

```:ディレクトリツリー

main
├── server
│   └── index.js
└── src
    └── index.html

```

```js:server/index.js

const express = require('express')

let defaultPort = 8000

let app = express()
let server = app.listen(process.env.PORT || defaultPort, () => {
    console.log('start server listening', process.env.PORT || defaultPort)
    console.log('http://localhost:' + (process.env.PORT || defaultPort))
})
app.use(express.static(__dirname + './../src'))

// GETリクエストで画像の外部URLを受取り、base64を返す
app.get('/url2base64', function(req, res) {
    const url = decodeURIComponent(req.query.url);
    request.get(url, function(error, response, body) {
        if (!error && response.statusCode == 200) {
            data = "data:" + response.headers["content-type"] + ";base64," + new Buffer(body).toString('base64');
            res.send(data);
        } else {
            // 画像がなかったら透過gifを返しておく
            res.send("data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEHAAEALAAAAAABAAEAAAICTAEAOw==");
        }
    });
});

```


```html:src/index.html

<img src="" alt="">
<script>
    var url = "https://www.google.co.jp/images/nav_logo242.png";
    var xhr = new XMLHttpRequest();
    xhr.open('GET', './url2base64?url=' + encodeURIComponent(url));
    xhr.addEventListener("load", function(e) {
        document.getElementsByTagName('img')[0].src = xhr.responseText;
    });
    xhr.send(null);
</script>

```

あとは `main` ディレクトリ配下で

```shell

npm install express
node server

```

とすれば [http://localhost:8000/index.html](http://localhost:8000/index.html) にて、指定したURLの画像が表示されるはずです。
デベロッパーツールで `<img>` タグの `src` を見てみるとbase64で指定されていることがわかると思います。
Go言語のHTTPサーバのテスト事始め

この記事は、[Go2 Advent Calendar 2017](https://qiita.com/advent-calendar/2017/go2)の15日目の記事です。

# 最初に
Go言語のHTTPサーバに対してテストを実装する方法を簡単にですがご紹介したいと思います。
今回はサーバ側の実装として[echo](https://github.com/labstack/echo)を利用していますが、他のフレームワークを利用していても同様にテストすることが可能です。

今回のテスト対象のHTTPサーバは以下の通りです。

```go
package main

import (
    "net/http"

    "github.com/labstack/echo"
)

const helloMessage = "Hello, World!"

func main() {
    router := NewRouter()

    router.Start(":8080")
}

func NewRouter() *echo.Echo {
    e := echo.New()

    e.GET("/hello", helloHandler)

    return e
}

func helloHandler(c echo.Context) error {
    return c.String(http.StatusOK, helloMessage)
}
```

# HTTPリクエストをシミュレートしてテスト
HandlerFuncに対して[`ServeHTTP(w ResponseWriter, r *Request)`](https://golang.org/pkg/net/http/#HandlerFunc.ServeHTTP)を使うことで実際にサーバを立ち上げずにリクエストをシミュレートすることが可能です。
[httptest.NewRequest(method, target string, body io.Reader)](https://golang.org/pkg/net/http/httptest/#NewRequest)でクライアント側をシミュレートし、[httptest.NewRecorder()](https://golang.org/pkg/net/http/httptest/#NewRecorder)で生成するレコーダーでレスポンスを記録することが可能です。

```go
package main

import (
    "net/http"
    "net/http/httptest"
    "testing"

    "github.com/stretchr/testify/assert"
)

func TestHelloHandler(t *testing.T) {
    router := NewRouter()

    req := httptest.NewRequest("GET", "/hello", nil)
    rec := httptest.NewRecorder()

    router.ServeHTTP(rec, req)

    assert.Equal(t, http.StatusOK, rec.Code)
    assert.Equal(t, helloMessage, rec.Body.String())
}
```

# 実際にHTTPリクエストを飛ばしてテスト (E2E test)
サーバ部分を[`httptest.NewServer(handler http.Handler)`](https://golang.org/pkg/net/http/httptest/#NewServer)で[`httptest.Server`](https://golang.org/pkg/net/http/httptest/#Server)に置き換えてテストを行います。
`httptest.Server`はテスト時に、`net.Listen("tcp", "127.0.0.1:0")`でloopbackの空いている適当なポートをListenしてくれます。
尚、Listenしたいポートを固定化したい場合は`go test -httptest.serve=127.0.0.1:8000`と実行することで固定化することも可能です。


```go
package main

import (
    "io/ioutil"
    "net/http"
    "net/http/httptest"
    "testing"

    "github.com/stretchr/testify/assert"
)

client := new(http.Client)

func TestRouter(t *testing.T) {
    router := NewRouter()
    testServer := httptest.NewServer(router)
    defer testServer.Close()

    req, _ := http.NewRequest("GET", testServer.URL+"/hello", nil)

    resp, _ := client.Do(req)
    respBody, _ := ioutil.ReadAll(resp.Body)

    assert.Equal(t, http.StatusOK, resp.StatusCode)
    assert.Equal(t, helloMessage, string(respBody))
}
```

`httptest.Server`をHTTPSサーバとして立ち上げてテストしたいときは、`httptest.NewTLSServer(router)`とすることでHTTPSサーバとして立ち上げることができます。

# 最後に
今回は`echo`ベースのサーバに対してテストを行いましたが、`gin`や`goji`等のフレームワークでも同様にテストすることが可能です。
それでは、良いテストライフを！
Nagios を日本語化してRPMビルドする

# Nagios　を日本語化してRPMビルドする

## 環境

- macOS High Sierra 10.13.2
- docker 17.09.1-ce, build 19e2cf6
− Nagios 4.3.4

## 作業場所作成

作業するディレクトリを用意します。

```bash
sudo mkdir -p /tmp/rpmbuild/SOURCES /tmp/rpmbuild/SPEC
sudo chmod a+w /tmp/rpmbuild
```

## Docker

Dockerを利用できる環境を用意してください。
また、こちらのコンテナをpullしておきます。

[auchida/mock\-rpmbuilder \- Docker Hub](https://hub.docker.com/r/auchida/mock-rpmbuilder/)

```bash
sudo docker pull auchida/mock-rpmbuilder
```

## 日本語翻訳ファイルの用意

こちらで配布されているのでありがたく使わせて頂きます。

[Nagios 4\.x \| ももーい鯖覚書](https://www.momo-i.org/chapter5/nagios/4.x.html)

```bash
cd /tmp/rpmbuild/SOURCES
curl -L -O http://ftp.momo-i.org/pub/security/nagios/patches/nagios-jp-4.3.4.patch.gz
```

## SOURCEとSPECファイルの用意

Nagiosは配布されているソースにSPECファイルが用意されているので、それに追記して使用します。

[Nagios Core \- Browse /nagios\-4\.x/nagios\-4\.3\.4 at SourceForge\.net](https://sourceforge.net/projects/nagios/files/nagios-4.x/nagios-4.3.4/)

```bash
/tmp/rpmbuild/SOURCES
curl -L -O https://downloads.sourceforge.net/project/nagios/nagios-4.x/nagios-4.3.4/nagios-4.3.4.tar.gz
tar zxvf nagios-4.3.4.tar.gz
cp nagios-4.3.4/nagios.spec ../SPECS/nagios-4.3.4-2-jp.spec
```

SPECファイルを編集します。

```bash
vim /tmp/rpmbuild/SPECS/nagios-4.3.4-2-jp.spec
```

``` diff
--- nagios.spec            2017-12-14 20:26:58.000000000 +0900
+++ nagios-4.3.4-2-jp.spec 2017-12-14 21:13:17.000000000 +0900
@@ -22,13 +22,14 @@
 Summary: Open Source host, service and network monitoring program
 Name: nagios
 Version: 4.3.4
-Release: 2%{?dist}
+Release: 2%{?dist}.jp
 License: GPL
 Group: Applications/System
 URL: https://www.nagios.org/
 Packager: Daniel Wittenberg <dwittenberg2008@gmail.com>
 Vendor: Nagios Enterprises (https://www.nagios.org)
-Source0: http://dl.sf.net/nagios/nagios-%{version}.tar.gz
+Source0: https://downloads.sourceforge.net/project/nagios/nagios-4.x/nagios-%{version}/nagios-%{version}.tar.gz
+Patch0: http://ftp.momo-i.org/pub/security/nagios/patches/nagios-jp-%{version}.patch.gz
 BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root
 BuildRequires: gd-devel > 1.8
 BuildRequires: zlib-devel
@@ -73,6 +74,7 @@

 %prep
 %setup
+%patch0 -p1

 # /usr/local/nagios is hardcoded in many places
 %{__perl} -pi.orig -e 's|/usr/local/nagios/var/rw|%{_localstatedir}/nagios/rw|g;' contrib/eventhandlers/submit_check_result
```

## ビルド

今回はCentOS７（RHEL７）用にビルドします。完了すると、 /tmp/rpmbuild/output 内にRPMが生成されています。

```bash
sudo docker run -e MOCK_CONFIG=epel-7-x86_64 -e MOCK_TARGET=SPECS -v /tmp/rpmbuild:/rpmbuild --privileged=true -i auchida/mock-rpmbuilder:latest
ls -l /tmp/rpmbuild/output
```

## あとがき

ビルドまでしか確認していないです。
SPECファイルのchangelogに追記するべきなんだろうけど、してないです...

## 参考

[Nagios 4\.2\.4 の日本語RPMを docker \+ mock環境 で作ってみたよ！ : 元うなぎ屋](https://snickerjp.blogspot.jp/2017/02/nagios424-with-docker-mock-build.html)
ネットワークACLを使用してVPC外へのトラフィックを遮断する

# 概要
AWS利用だと本番サーバのAMIからサクッと検証環境を構築して検証することがありますが、設定ミスや漏れにより意図しないトラフックを本番に流してしまう恐れがあり案外危険な作業だと感じていました。
そこでネットワークACLを使用してVPC外へのトラフィックを遮断できる状態を作り、その中で安全に検証をすることにしました。
ということで、今回はネットワークACL設定について投稿いたします。


# やりたかったこと
- 意図しないトラフィックをネットワーク外に出さない
- DynamoDBへのアクセスを遮断したい
- 検証環境設定にミスや漏れがあってもトラブルを起こさない
- 知らないところで外部通信しているものを見つけたい
- 検証環境を皆安全に使ってもらいたい




# VPCとネットワークACL設定内容
- 東京リージョンのzone-bとcをsubnet-bとcで設定
- inboundは制限しない
- outboundはvpc外に出ないように設定にする
- 設定値は以下のとおり

|セグメント|CIDER|NetworkALC<br>(inbound)|NetworkALC<br>(outbound)|
|:--|:--|:--|:--|
|vpc |10.0.0.0/16 |0.0.0.0/0 allow<br>0.0.0.0/0 deny |0.0.0.0/0 allow<br>0.0.0.0/0 deny|
|subnet-b |10.0.0.0/24 |0.0.0.0/0 allow<br>0.0.0.0/0 deny |10.0.0.0/16 allow<br>10.0.1.0/24 allow<br>0.0.0.0/0 deny |
|subnet-c |10.0.1.0/24 |0.0.0.0/0 allow<br>0.0.0.0/0 deny |10.0.0.0/16 allow<br>10.0.0.0/24 allow<br>0.0.0.0/0 deny|


# 構成図
![aws-vpc.PNG](https://qiita-image-store.s3.amazonaws.com/0/146154/743d14fd-9d9d-689b-6b20-fe32f2709cf3.png)



- ネットワークALCを意識しないでVPCを構築するとvpcのネットワークALCをそのままsubnetに使ってしまうので、subnet用には新規作成する必要があります。
- 以下の様にsubnetのネットワークALCは1つにまとめることも可能です。

|セグメント|CIDER|NetworkALC<br>(inbound)|NetworkALC<br>(outbound)|
|:--|:--|:--|:--|
|subnet-b<br>subnet-c |10.0.0.0/24<br>10.0.1.0/24 |0.0.0.0/0 allow<br>0.0.0.0/0 deny |10.0.0.0/16 allow<br>10.0.0.0/24 allow<br>10.0.1.0/24 allow<br>0.0.0.0/0 |


この設定が基本になります。この後は検証に必要なoutboundを開けて検証を実施していきます。


# ネットワークACL使用時の注意点
- セキュリティグループと混合してしまわないようにしっかり理解することが大事です。
- 1つのネットワークALCで指定できるルール数は20（上限緩和で最大40）まで。
- 追加のルールを処理するためのワークロードが増えるため、ネットワークのパフォーマンスに影響することがあります。 
このあたりは気にしながら使うようにしたいです。


(参考)
http://docs.aws.amazon.com/ja_jp/AmazonVPC/latest/UserGuide/VPC_ACLs.html
http://docs.aws.amazon.com/ja_jp/general/latest/gr/aws_service_limits.html#limits_vpc


# さいごに
ざっくりとした説明でわかりにくかったかもしれませんが、
安全な環境で開発することは、結果的に安全なサービスにつながると思っています。
少しても参考にして頂ければ幸いです！　　横地秀
AWSのWorkSpaces内でキーボードが反応しない (Karabinerが原因でした...)

## 症状

PC: MacbookPro Sierra (10.12.6)

社内のAWS WorkSpacesに入って、いつものようにキーボードを叩いてみると、反応しない。

他のアカウントでもダメ...
外部キーボードでもダメ...
他の人は打てる。
自分だけダメ...

3ヶ月ぐらい、放置していましたが...
ふとKarabiner-Elementsを入れた記憶が...


「WorkSpaces karabiner」で検索してみると
https://github.com/tekezo/Karabiner-Elements/issues/203
いくらか同じように苦しんでいる人が...

### 対処
Karabinerを仕方なく Unisntall して解決


### uninstall方法 (Misc > Uninstall Karabiner-Elements)
![スクリーンショット 2017-12-14 19.14.25.png](https://qiita-image-store.s3.amazonaws.com/0/125781/e2e7e335-d188-eb83-0050-f22c1556cfd4.png)
Apollo-androidのレスポンスキャッシュを使ってみる

# Apollo-android

GraphQLのAndroid用クライアントライブラリであるApollo-androidの導入手順を書こうかと思ったのですが、
[こちらの方の記事](https://qiita.com/ssoejima/items/0ae0cb97aabfcac11c6a)がとても詳しいので、今回はApollo-androidでCacheの利用する際の手順について書きます。

今回のソースは、下記になります。Kotlin1.2.0で書いています。
https://github.com/moto2011/apollo-android-sample

## Cache

Apollo-androidの導入自体は上の記事を参考に行って下さい。
以降は、導入自体は完了している前提となります。

レスポンスのキャッシュは以下の3つがあるようです。今回は`HTTP Response Cache`を利用してみます。

1. HTTP Response Cache
1. Normalized Disk Cache
1. Normalized InMemory

### 1. dependencies追加

公式のREADMEの通りです。Cacheを利用する場合dependenciesに以下を追記します。

``` build.gradle
dependencies {
    implementation 'com.apollographql.apollo:apollo-http-cache:0.4.3'
}
```

### 2. ApolloClientの作成

公式のREADMEでは`.httpCache(new HttpCache(cacheStore))`となっていますが、
`HttpCache`はcacheStoreを引数にとるコンストラクタがないとかエラーが出たので、`ApolloHttpCache `の方を使いました。

``` MainActivity.kt
// Cache
val size = 1024L * 1024L
val cacheStore = DiskLruHttpCacheStore(cacheDir, size)

// Build the Apollo Client
apolloClient = ApolloClient.builder()
        .serverUrl("https://api.github.com/graphql")
        .httpCache(ApolloHttpCache(cacheStore)) // HttpCacheではなくApolloHttpCache
        .okHttpClient(client)
        .build()
```

### 3. HttpCachePolicyの設定

以下のの4つがあるようですが、今回は`CACHE_FIRST`（キャッシュがあればそれを使い、キャッシュがなければ通信）を指定して有効期限も設定します。

1. CACHE_ONLY
1. NETWORK_ONLY
1. CACHE_FIRST
1. NETWORK_FIRST

``` MainActivity.kt
apolloClient.query(ViewerQuery())
        .httpCachePolicy(HttpCachePolicy.CACHE_FIRST.expireAfter(20, TimeUnit.MINUTES)) // ポリシーの設定
        .enqueue(object : ApolloCall.Callback<ViewerQuery.Data>() {
            override fun onResponse(response: Response<ViewerQuery.Data>) {
                c.resume((response.data() as ViewerQuery.Data).viewer.login)
            }

            override fun onFailure(e: ApolloException) {
                c.resume("Error!!")
                e.printStackTrace()
            }
        })
```

### 4. 動作確認

画面中央のボタンタップで、githubのユーザ名を表示するだけのアプリです。

まず通信出来る状態でボタンをタップするとユーザ名が表示されます。
そのあとタスクキルなどして機内モード等でオフライン状態にしたのちに再度アプリを起動・ボタンをタップすると
前回通信時のレスポンスキャッシュがあるため下記の通り、ユーザ名が表示されます。

<img src="https://qiita-image-store.s3.amazonaws.com/0/6290/54261c44-5369-2096-3ba5-2472cc5d4a12.png" width=40%>

## 終わりに

今回、この記事を書くにあたってはじめてGraphQLを触りました。
正直、今回のようなアプリだとその良さを体感するまでには至っていないため、
もう少し使ってみて中身のある記事を投稿します。。
Ansibleで試す仮想サーバ環境でSplunk管理

#はじめに
Advent Calendar14日目を担当します。Tossy773です。
今回はvSphere仮想環境上でSplunkインフラを構築する際にAnsibleを活用できそうなTIPSを中心に試してみました。

Splunkは物理サーバにベアメタルで構築することもできますが、仮想環境上に構築することで仮想環境基盤での様々な運用上のメリットを得られます。VMware仮想化環境では先日のAdvent Calendarでも紹介されていたようにansibleで自動化可能ですので、煩雑な処理を標準化して誰でもミスなく実施することが容易になります。

#今回のお題
##Splunk VMのsnapshotを取得しSplunkをバージョンアップする
SplunkのアップグレードはCLIでできるのですが若干煩雑です。バージョンアップ後に想定外の状態が発生した場合に備えて簡単にバージョンアップ前の状態に戻したい場合があります。
そこで、仮想基盤でSplunk VMのSnapshotを取得したあとに、バージョンアップを実施しコマンドを毎回実行するのではなくansibleを活用してみます。

#実現イメージ
![図1.png](https://qiita-image-store.s3.amazonaws.com/0/215274/7cff6cf3-49f6-e9c5-24ca-bb019fe80a8d.png)


##splunk-versionup.yaml
```---
- hosts: localhost
  tasks:
   - name: take a snapshot
     vmware_guest_snapshot:
       hostname: 192.168.1.10
       username: administrator@vsphere.local
       password: password
       datacenter: mydatacenter
       folder: vsphere/Splunk7/VM
       name: Splunk7
       uuid: 423bbd4c-8483-7077-408e-cf6ae60eec8e
       state: present
       snapshot_name: snap1
       description: snap1_created_by_ansible
     delegate_to: localhost
 
   - name: wait take snapshot wait
     wait_for: timeout=2
 
   - name: poweron os
     vmware_guest:
       hostname: 192.168.1.10
       username: administrator@vsphere.local
       password: password
       datacenter: mydatacenter
       folder: vsphere/Splunk7/VM
       name: Splunk7
       uuid: 423bbd4c-8483-7077-408e-cf6ae60eec8e
       state: poweredon
     delegate_to: localhost
 
- hosts: 192.168.1.2
  tasks:
   - name: versionup splunk
     copy: src=/tmp/splunk-7.0.1-2b5b15c4ee89-linux-2.6-x86_64.rpm
           dest=/tmp/splunk-7.0.1-2b5b15c4ee89-linux-2.6-x86_64.rpm
   - name: splunk stop
     shell: "/opt/splunk/bin/splunk stop"
 
   - name: upgrade splunk
     shell: "rpm -U /tmp/splunk-7.0.1-2b5b15c4ee89-linux-2.6-x86_64.rpm"
   - name: start
     shell: "/opt/splunk/bin/splunk start --accept-license --answer-yes --no-prompt"
```

#まとめ
今回はわかりやすさを優先し、シンプルな構成でのご紹介でしたが、応用すれば大人数用のトレーニング環境構築などへも流用できたり、さらに複雑な構成、導入への対応も可能になると思います。

先日、参加したコミュニティイベントではSplunkをコンテナ上で稼働させるという発表もありました。
日本国内での仮想化インフラの流れもどこかでコンテナ中心に変わっていくかもしれませんね。
Ansible ContainerとSplunk連携も今後試してみようかとおもいます。
最後までお読みいただきありがとうございました。
Database Cloud Service をIP Networkに接続してみた。

OracleCloudのDBCSがIPNetworkに対応したようなので試してみました。
# 前提
・IP Networkは作成済み。
・VPNaaSで社内ローカル環境とVPN接続済み。
・リージョンは「APAC Commercial5 (ap5)」を使用。

IPNetwork：10.195.30.0/24
社内ローカル：192.168.11.0/24

DBCSをIPNetworkに接続することが目的になります。
バックアップやその他パラメータは考慮していません。
**そして自分は本職DBAではありません**


# DBCS起動

Service画面でRegionを「No Preference」から「AP005_Z11」に変更してください。
IP Networkの画面が出てくるので、接続するネットワークを選択します。


![DBCS1.png](https://qiita-image-store.s3.amazonaws.com/0/161282/15937f59-7fda-4927-8841-8970f1380c4f.png)
*DatabaseTypeがRACの時はIPNetworkが出てきません。*　　

---
管理パスワード、SSH公開鍵、タイムゾーン、IP Reservationを設定。
バックアップ設定は今回省略しています。
![DBCS2.png](https://qiita-image-store.s3.amazonaws.com/0/161282/f8597db1-c5ab-08f8-3f31-6c225799cc48.png)

---
各設定を確認します。IP Networkが含まれることも忘れずに。

![DBCS3.png](https://qiita-image-store.s3.amazonaws.com/0/161282/10bd1dbc-a273-b62d-21ae-35a3f0738e99.png)

---
起動が完了するまで30分ほど掛かります。

![DBCS4.png](https://qiita-image-store.s3.amazonaws.com/0/161282/aa680a37-0ca6-f1f3-803a-cd5113c5e32f.png)

---

割り当てられたプライベートIPはCompute Classicのインスタンスから確認可能です。
![DBCS6.png](https://qiita-image-store.s3.amazonaws.com/0/161282/552c6175-763d-0232-3686-a9d08b379f5c.png)

---
完了したら右側のメニューからアクセス・ルールを選択。
社内のローカルIPから22番と1521番のアクセスを許可します。
![DBCS7.png](https://qiita-image-store.s3.amazonaws.com/0/161282/be96a782-58ea-b8ab-6506-1712e69ab65e.png)

---
ローカルのPCからSQL*Plus接続確認をします。
Service Overviewの接続文字列のdemo001はプライベートIPに置き換えています。
![DBCS8.png](https://qiita-image-store.s3.amazonaws.com/0/161282/6bb4c806-ae18-5555-71c7-3a533385d000.png)

---

# 気になったこと
プライベートIPは勝手に割り当てられます。任意に設定することはできませんでした。
任意に決める方法があればおしえてください。

アクセスルールがTCPとUDPのみでICMPが無いので、Pingは打てませんでした。

---

これまでDBCSとVPN接続する時はCorenteを使ってGRE接続していたので
設計と設定が楽になりますね。VPNaaSならコストも抑えられるのもメリットかなと。
CSSをプログラム風に解釈したらアレルギーが治ってきた話

#前置き
去年まではデザイン崩れが発生すると
「助けてデザイナーの人！」
だったのが、今では検証ツール開いて要素に適用されているstyleからなんとなく原因特定→修正まで出来るようになったので、そのコツの話。

それまでは周りの人にどうやったらCSSとか分かるようになるのか聞いてみるも
「世間のサイトとかを検証ツールとかで開いて、パラメータ変えてコネコネすればそのうち分かるよ。」
みたい事をアドバイスされ…
すぐに挫折orz

CSSへの興味や勉強モチベーションが低いと、ハードルが相当高いと感じた。
見た目も一般的なプログラム言語とは全く違うので、精神的に抵抗がかなりある。

裏ではこんな感じのプログラムが実行されているような感じ！
というイメージが持てれば、Webはあんまり触った事ないけどプログラムの基礎なら分かる、という人にはかなりとっつきやすくなるのでは、と思った。

以下自分流解釈。

##HTML
『「ブラウザ」というアプリ』で画面を表現するための言語。
HTMLファイルの中で大きな区切りはheadとbodyで、C言語やJava的に言えば、headはheaderファイル、bodyはcファイルやjavaファイルに相当するものを記述するイメージ。

```html
<html>
  <head></head>  <!-- →  xxx.hに書いてるもの -->
  <body></body>  <!-- →  xxx.c とか xxx.javaに書いてるもの、ここが表示領域 -->
</html>
```
bodyに記述したものが、画面に(ブラウザに)表示される。

##タグ(要素)
大きさとか色とかもろもろのプロパティ(パラメータ)を持ったクラス。
divとかspanを記述する事は、divクラスのオブジェクトを生成するようなイメージ。

```html
<html>
  <head></head>
  <body>
    <div></div> <!-- divタグ -->
    <span></span> <!-- spanタグ -->
  </body>
</html>
```


これらは
new Div();
new Span();
みたいなイメージで、このコンストラクタはアウトプット(画面への表示)までセットでついてくる感じ。

##ブロックとインライン
なんで改行されんだー！幅指定が効かねー！うがああぁぁぁあ！ヽ(#｀皿´)ノ
ってなるときは、だいたいこのブロックとインラインのせい。
こいつらは何者かというと、要素が重ならないように画面上へ配置するために、要素へ設定されているタイプみたいなもの。
全部の要素が画面上の位置(0,0)で全て重なっていて、全ての要素に位置座標を記述しないといけないのは大変。
(もちろん全部の要素に位置座標を指定する事も出来る)

**ブロック**
要素が重ならないように、前の要素の下へ下へと配置される。

**インライン**
要素が重ならないように、基本は前の要素の右へ右へと配置される。
ブラウザの横幅的に入りきらなくなると、改行されるイメージ。



divはブロックの概念を持ったクラスで、spanはインラインの概念を持ったクラス、というイメージ。

下記のような記述をすると

```html
<div>div</div>
<div>div</div>
<div>div</div>

<span>span</span>
<span>span</span>
<span>span</span>
```

こんな感じに表示される

![divとspan.png](https://qiita-image-store.s3.amazonaws.com/0/106608/baae7a45-3a45-d536-a542-9f67fe02f0ac.png)


なので下記のようなdiv要素は
```html
<div>test</div>
```

コード的に解釈すると

```java
class Div{
  public string value;

  public Div(string value){
    this.value = value;

    // その他ブロック要素的な初期パラメータを設定する処理
    // ~
    // ~

    // 描画処理
    this.viewBlock();
  }

  private void viewBlock(){
    // this.paramをブロック要素的に表示する処理
  }

};
```
こんな感じのクラスがあって

```java
new Div("test");
```
こんな感じで引数に「test」という文字を渡してるイメージ。

##CSS(style)は要素のプロパティをいじるやつ
サイズを変えたい、色を変えたい、影をつけたい、といった要素(divとかspanとか)の見た目に関するプロパティを記述出来るのがCSS。

なので下記のようなdiv要素は

```html
<div style="width:100px;color:#000000;">test</div>
```

コード的に解釈すると

```java
class Style{
  public int width;
  public int height;
  public string color;
  // …
  // 他にもborderとかbackgrand-colorとかいろんなプロパティを持ってる

  public Style(string[] argStyle){
    // argStyleをkey - value形式にして、keyに対応するプロパティに
    // valueを設定していく処理
  }
};

class Div{
  public string param;
  private Style style;

  public Div(string arg , string[] argStyle){
    this.param = arg;
    this.style = new Style(argStyle);
    // その他ブロック要素的な初期パラメータを設定する処理
    this.viewBlock();
  }

  public void viewBlock(){
    // this.styleの情報を元にして
    // this.paramをブロック要素的に表示する処理
  }
};
```

こんな感じのクラスがあって

```
new Div("test","width:100px;color:#000000;");
```

こんな感じで引数に「test」という表示用文字と、「width:100px;color:#000000;」というレイアウト用文字を渡してるイメージ。

styleの部分は、phpの連想配列的な方がイメージしやすいかも。

#終わりに
だいたいこんな感じのニュアンスがピンとくるようになれば、
・ブロックでも次のブロック要素を右の方へ表示したい！
・要素を重ねたい！
みたいに、よく一般的なサイトで行われているような処理も、どのプロパティをいじればいいのか検討がつくようになるし、自分で調べて解決出来るようになるはず。