OmniAICreator/Qiita-1.07M huggingface dataset:
〇〇行のコードで業務効率化？Pythonでスクリプト書いたぞ

これは[ユアマイスター Advent Calendar 2018](https://qiita.com/advent-calendar/2018/yourmystar)の12日目の記事です。

##こんにちは

これはたった`〇〇行`のコードで、ある作業を日当たり`30min~1h`短縮に成功したのでお知らせします。

`ある作業`というのは厳密にお話しすることは出来ないのですが、ざっくりいうと対象のページにアクセスする、という事です。

##やりたい事

少し冒頭で書きましたが、
PCとSP(スマホ)から対象となるページにアクセスしたい、という事です。

これを手作業で1ページずつアクセスして…。
とやっていては、対象ページ数の増加に伴って作業時間数が増加する為、非常に非効率なやり方ですよね。
（とは言いつつ、それをこのスクリプトが作成される前は手作業でやっていたという事実。）

人間なので、アクセスし忘れた、というヒューマンエラーも考えられます。

これをスクリプトで`自動化しようぜ`という事です。

結果、冒頭にもあるように`30min~1h`短縮した、という訳です。

はい、では実際書いたスクリプトがこちらです。

##〇〇行のコード
```python:sample.py
import requests
from time import sleep
target_urls = [
    '/xxx/xxx/',
    '/yyy/yyy/',
    '/zzz/zzz/'
]
pc_header = {'User-Agent': 'hoge'}
sp_header = {'User-Agent': 'huga'}
for target_url in target_urls:
    target_url = 'http://hogehoge.jp' + target_url
    print(requests.get(target_url, headers = pc_header).text.find('hoge.pc.css'))
    print(requests.get(target_url, headers = sp_header).text.find('hoge.sp.css'))
    sleep(0.1)
```

これがタイトルにもあるように`〇〇行のコード`です。
〇〇にした理由としては、変数`target_urls`に入る値によって変わるので、いちおう〇〇としました。

実際、変数に何も入れていない状態、つまり雛形の状態であれば`11行`しか書いていないですし、これで`30min~1h`も作業時間を短縮できた事を考えると、いかに今までの作業時間が無駄だったのか、がよくわかりますよね。

###コード解説

非常に簡単なコードだとは思うんですが、いちおう何をしているのか、解説しますね。（普段PHP書いてるんで）

まず最初のこれ
- `import requests`
- `from time import sleep`

`requests`はHTTPリクエストをするライブラリ。
`time`は時刻に関する様々な関数を提供するモジュールで、今回は`sleep`メソッドしか使用しなかった為、import sleepをしてます。
sleepの役割としては、処理を一時的に止めます。

次に
`target_urls`
これはアクセス先のURL、主にディレクトリパスとファイル名が入ります。

次に
`pc_header = {'User-Agent': 'hoge'}`
`sp_header = {'User-Agent': 'huga'}`
これは[ユーザーエージェント](https://www.baka-ke.com/2012/01/08/what_is_useragent/)が入ります。（このスクリプト作成時にユーザーエージェントが何かを知る…！）
`User-Agent`をkeyとして、`hoge`の部分にはそれぞれのユーザーエージェントの情報を入れてあげれば良いです。

次に

```python
for target_url in target_urls:
    target_url = 'http://hogehoge.jp' + target_url
    print(requests.get(target_url, headers = pc_header).text.find('hoge.pc.css'))
    print(requests.get(target_url, headers = sp_header).text.find('hoge.sp.css'))
    sleep(0.1)
```
(一気にいきます)
先ほど指定した`target_urls`を`for文`で回します。
`target_url`はディレクトリパスとファイルパスを今回は入れているので、プロトコルとドメイン名を結合してURLとします。

その後、まずimportしたrequestsのgetメソッドを使用して対象のURLにGETリクエストでアクセスします。

アクセスした時に`text`を抽出して、[findメソッド](https://www.sejuku.net/blog/52207#find)でcssファイルを検索します。

その後`sleep`メソッドで一時的に処理を止める。これを繰り返し行います。

####疑問を解決

1. なんでfindメソッドでcssファイルを検索したんですか？

→これは[ユアマイスター株式会社](http://corp.yourmystar.jp/)の開発スタイルに依存しているのですが、私達はデバイス毎にファイルを分けて開発しています。アクセス先URLに必ず存在するPCとSPそれぞれのファイルを検索する事で、それぞれのデバイスのURLにアクセスした事になるからです。

2. なんでsleepしてるんですか？

→アクセスが集中する事によるタイムアウトを避ける為です。

##まとめ
もっと無駄を無くして、自動化できるものは自動化、掛けるべき部分に時間を掛ける。その為にはチーム間で密なコミュニケーション。

ユアマイスター株式会社では、アジャイルで開発を進めています。

[エンジニアじゃない"まかない担当"がアジャイルについて書いてみた](http://yourmystar-engineer.hatenablog.jp/entry/2018/11/14/080000)
こんな記事もあるのでぜひ読んで見て下さい。
【第0回】Hello, world【ModPE Script】

# ModPE Scriptとは？

ModPE Scriptとは、[Zhuowei Zhang](https://twitter.com/zhuowei)の開発したAndroidデバイス向けアプリケーション、[BlockLauncher](https://play.google.com/store/apps/details?id=net.zhuoweizhang.mcpelauncher)で利用可能なスクリプトである。
これは、Minecraft PEへのブロックやアイテムの追加は勿論のこと、一部システムへの干渉も可能であり、JavaScriptという比較的容易な言語で、しかも視覚的に扱えるため、プログラミング入門にはうってつけだと思っている。

さて、今後このModPE Scriptについての解説紛いの投稿を続けるわけだが、予め言っておく事がある。
それは何か、私が作業している環境について、だ。

何せMinecraft PEの更新が重なるにつれ、BlockLauncher側で正常に処理されない増え、最新の環境では満足に作れないと言っても過言ではないからである。
さて、そんな事を言う私の作業環境だが、以下を参照してほしい。

- Android 7.0
- Minecraft ver.0.14.1
- BlockLauncher ver.1.12.6

現在Minecraft PEを利用しているユーザーであれば、この環境がどれだけ古いかがわかるだろう。
エンド？
ありませんよ？
森の館？
知らない子ですね()
と、かなり古いバージョンを前提とした話を進めたいと思っている。

# Hello, world

さて、誰のせいか話が大きく外れたが、ModPE Scriptは先述のようにJavaScriptである。
JavaScriptが前提だから、言語の解説は触れない。
ってか触れたくない。

で、このModPE Scriptだが、私個人では以下のような解釈をしている。

1. 何かしらのイベントが発火する。
2. BlockLauncherがイベントを検知、登録された関数を呼び出す。
3. ModPE Script内の指定の関数が呼び出される。
4. やったぜ☆

正直こんな適当な解釈で十分だと思うし、実際これまで悩んだ事がない。
じゃあこんな解釈の上で早速プログラミングの入門オブ入門なHello, worldを作るわけだが、ぶっちゃけこいつも説明不要なレベル。
Web API環境では以下を読み込ませておけば十分Hello, worldになる。

```javascript:script.js
console.log("Hello, world");
```

ModPE Scriptも大概同じである。
強いて言えば関数が違うだけ。
以下がModPE ScriptでのHello, worldである。

```javascript:script.js
print("Hello, world");
```

これを読み込ませれば、Hello, worldと表示される。

# フック関数の使用

でもあれだけじゃイベント発火時の処理には使われない。
ModPE Scriptでは、先述のようにイベントが発火する度に関数が呼び出される。
Hello, worldの次の段階として、プレーヤーがワールドに入ったときに、チャット欄に出力されるように組み換えてみよう。

```javascript:script.js
function newLevel(hasLevel){
	clientMessage("Hello, world");
}
```

プレーヤーがワールドに入ったことを検知する関数は`newLevel`である。
引数にはBoolean型の`hasLevel`が渡される。
この引数の`hasLevel`だが、何者なのか知らない。
ってかぶっちゃけ使わない。
だから書かない人がほとんど。

続いて、チャット欄に出力する関数だが、こちらは`clientMessage`である。
実行すれば画面左上に白い文字が表示される。

フック関数という概念が、Web API環境でのJavaScriptとの大きな違いだと思う。
ってかそれ以外の違いがいまいちわかんない。

# 最後に

ModPE ScriptはES5ベースにES6を混合した仕様のようで、アロー関数は使える、`let`/`const`は使えるが、`class`は使えない、`for`/`while`内で`const`を使用すると値が変えられないなど、実際にプログラマーしてる人達には理解に苦しむ仕様になっている。
まぁこの程度は序の口で、もっと面白い仕様ではあるので、今後もこの辺含めた話をしていければなと思っている。
java se 8 programmer Ⅰ メモ

#java.lang.StringBuilder
StringBuilderクラスの引数なしコンストラクタを呼び出してインスタンス化すると、初期値16のバッファを持つchar型の配列が生成される。
なので初期値は空文字。なぜかnullだと思ってしまった。。。StringBuilder型の変数を宣言しただけならもちろんnull。
ズバトク毎日くじを引くスクリプトを書いた

さわでぃさんの記事を参考にしました。↓
https://qiita.com/sawadybomb/items/b8a7b08a3907e0cb8b35

スクリプトと同じフォルダに'chromedriver.exe'を置いてください。

```python:yahoo_every_kuji.py
from selenium import webdriver
from time import sleep

home = 'https://login.yahoo.co.jp/config/login?.src=kuji&card_cushion_skip=1&.done=https://toku.yahoo.co.jp/everyday/lot'
driver = webdriver.Chrome('./chromedriver.exe')
driver.get(home)

id = driver.find_element_by_name('login')
id.send_keys('your_login_id')
btn_id = driver.find_element_by_name('btnNext')
btn_id.click()

sleep(1)

pw = driver.find_element_by_name('passwd')
pw.send_keys('your_password')
btn_pwd = driver.find_element_by_name('btnSubmit')
btn_pwd.click()

try:
    # くじボタンがある場合の処理
    btn_kuji = driver.find_element_by_id('btnLot')
    btn_kuji.click()
    sleep(3)
    driver.close()
except:
    # くじボタンがない場合の処理
    driver.close()
```
【インフラ】AWSでのシステム監視


# はじめに
はじめまして、株式会社ワンズパワーでエンジニアをしている@Nakayaです。

今回は、AWSを使ったシステムで監視をしたい場合に、
色々な監視パターンがありますが一例をご紹介したいと思います。

## 概要説明
#### まずは概要図
<img width="691" alt="1.png" src="https://qiita-image-store.s3.amazonaws.com/0/325477/a0fd480b-22e6-c2fb-7ad8-55cca23ccc48.png">

### 処理の流れ
①<span>　</span> EC2インスタンス等の監視対象から、リソースやログをCloudWatchに送信
②-1 CloudWatchに格納されたリソース情報をCloudWatchアラームが定期的に監視
②-2  リソースの使用率が事前に設定したしきい値に達したらLambdaを実行
③<span>　 </span>   ログにエラーが出力されたらLambdaを実行
④<span>　 </span>   Lambdaスクリプト内でSNS Topicを指定してメール送信処理を実行

## 登場人物の紹介
### CloudWatchAgent
EC2ではデフォルトでCPU使用率等はCloudWatchに送信しているが、メモリやディスクの使用率を監視したい場合はCloudWatchAgentが必要になる。

### CloudWatch
CloudWatchではリソース情報をメトリクスとして格納し、ログをCloudWatch Logsに格納する。

### CloudWatchアラーム
監視対象のメトリクスのしきい値と、しきい値に達した時のアクションを設定できる。
今回の場合はアクションをLambdaの実行にしている。
(直接メール送信もできるが、Lambdaを経由しておくとアラームを全て停止する等の制御が楽になる。)

### Lambda
サーバレスでスクリプトを実行できる。
今回はリソースがしきい値に達した時に通知をするLambdaスクリプトと、ログを監視し、エラーが含まれていたらアラート通知を行うスクリプトの用意を想定。

### SNS
いわゆるメッセージングサービス。
E-MailやSMS、あるいはLambda等のトピックを設定し、トピックにメールアドレスや電話番号、あるいはLambdaのARN等のサブスクリプションを紐づけることで指定した通知先にメッセージを送信することができる。

# 最後に
システム監視のパターンは色々ありますが、今回は簡単で、かつやりたい監視は大体できる方式を概要レベルで記載してみましたがいかがでしょうか。
実際はLambdaのスクリプトの部分がミソなので、今後そういった所もご紹介できたらと思います。

ありがとうございました。
Gitのログや差分表示を快適にするdenite-gitdiff

みなさんGitの操作どうしていますか？
CUIでやる人GUIでやる人Vim内でやる人、様々かと思います。
私は、CLIもしくは、[vim-fugitive](https://github.com/tpope/vim-fugitive)、Gitログ確認は、[agit.vim](https://github.com/cohama/agit.vim)利用しています。
[denite-git](https://github.com/neoclide/denite-git)を利用しようと思っていますが、まだ使いこなせてないです。


## 作ろうと思った経緯
現在のブランチって、指定ブランチと比べてどのファイル変更したんだっけ？
このコミットって、どのマージブランチだったっけ？
このマージコミットってどういうコミットがあったんだろ？
って気軽に確認したいことが多々ありました。
GitHubなどであれば、検索すればよいのですが、わざわざ開くの面倒なので、
いつも過ごしているVimから確認できるようにした方が圧倒的に便利です。

上記を解決するために、[denite.nvim](https://github.com/Shougo/denite.nvim)の拡張プラグイン
[denite-gitdiff](https://github.com/deresmos/denite-gitdiff)
を作ってみました！


よく使いそうな操作を紹介します。

## gitdiff_file
現在のブランチと指定ブランチとの差分ファイル一覧を表示させます。
差分のファイル一覧が出た状態で、差分をみたいファイルに対して、`openvdiff`アクションなどを実行すると、
差分が表示されます。（vim-fugitiveプラグイン依存）
下写真は、[Neovim](https://github.com/neovim/neovim)の`master`ブランチと`v0.3.1`タグを比較し、
どのファイルが変更されたっけ？を表したものです。
![gitdiff_file-demo](https://qiita-image-store.s3.amazonaws.com/0/243612/a6f394a8-d79f-dfa2-1c34-7941e8e2c1fd.png "gitdiff_file-demo")



## gitdiff_log
現在のブランチと指定ブランチとの差分の、コミットログを表示させます。（GitHubのPRのコミットログみたいなやつです）
ターゲットを指定しなかった場合は、現在ブランチのログを表示します。

下記のようなコマンドで、現在開いているファイルだけのコミットログの表示もできます。

```vimscript
:Denite gitdiff_log::::`expand('%:p')`
```

コロン多すぎになっちゃった



## branch_log アクション
このコミットってどのマージブランチだったんだろ？っていうときに使います。
そのブランチコミットログ一覧を表示させます。（GitHubのPRのコミットログ＋マージコミットって感じです）
例えば、下記PRを例にしてみます。
https://github.com/neovim/neovim/pull/9322

![gitdiff_branchlog-demo](https://qiita-image-store.s3.amazonaws.com/0/243612/0618e925-e6a4-5e8b-e713-53106616a141.gif "gitdiff_branchlog-demo")



## merge_log アクション
このマージコミットってどんなコミットログだったんだろ？ってときに利用します。


## さいごに
今後、非同期処理に切り替えてみようかなと思っています。
細かい部分の修正とかとか機能追加とかとかやっていきます。
ぜひぜひ使ってみてください。Windowsで動作確認していないので、動くかわからないです。（すんません。。。
Vim内でのGit生活をより良いものにしてきたいですね！
AWSでドメイン取得してServerlessでAmazon API Gatewayにカスタムドメインを設定する方法

Nuxt.jsで作成したSSRなサービスをServerlessでAmazon API Gawaway(AWS Lambda)デプロイする際に、独自ドメインを設定する方法です。

デプロイするソースはGitHubにアップしているものを利用します。
https://github.com/kai-kou/nuxt-serverless/tree/feature/no-use-s3


基本的には下記を参考に設定をすすめました。

Serverless(node.js)で独自ドメインSSLの適用方法 - Qiita
https://qiita.com/koshilife/items/bb7edb12f0285a241294


## ドメインの取得

下記を参考にドメインを取得します。```.com``` ドメインだと千数百円/年で取得が可能です。

Amazon Route53 でドメインを取得する - Qiita
https://qiita.com/NaokiIshimura/items/89e104dd2d8dd950780e


httpsを利用するのにSSL/TLS証明書が必要になりますので、下記を参考に証明書を取得します。この際、**リージョンは```us-east-1``` で取得します。**```ap-northeast-1``` で取得しても、Serverlessで設定する際に```us-east-1``` をみにいくので、証明書がみつからないとエラーになります。

Certificate Manager (ACM) がDNSの検証をサポートしました ｜ DevelopersIO
https://dev.classmethod.jp/cloud/aws/certificate-manager-dns-validation-support/

## serverless.ymlの設定

```custom.customDomain``` でドメインの設定をします。

```yaml:serverless.yml_一部抜粋
service: [サービス名]

provider:
  name: aws
  stage: ${opt:stage, 'dev'}
  region: ap-northeast-1
  runtime: nodejs8.10
  package:
    exclude:
      - src/**
      - .vscode/**
      - package.json
      - package-lock.json
      - tsconfig.json
      - tslint.json
      - yarn.lock
    include:
      - serverless.yml

  environment:
    NODE_ENV: production

custom:
  customDomain:
    domainName: "${self:provider.stage}.[ドメイン名]"
    stage: ${opt:stage, 'dev'}
    certificateName: "*.[ドメイン名]"
    createRoute53Record: true
  apigwBinary:
    types:
      - '*/*'

functions:
  nuxt-renderer:
    handler: handler.render
    memorySize: 512
    timeout: 30
    events:
      - http:
          path: /
          method: ANY
          cors: true
      - http:
          path: /{proxy+}
          method: ANY
          cors: true

plugins:
  - serverless-apigw-binary
  - serverless-domain-manager
```

## デプロイする

Serverlessのプラグインserverless-domain-managerを利用しますので、インストールしてから```serverless create_domain``` でドメインの設定をしてから```serverless deploy``` します。
```serverless create_domain``` 後、数十分待つと設定が完了してアクセスできるようになりました。

```sh
> npm install serverless-domain-manager --save-dev
> npm run build
> serverless create_domain

Serverless: 'dev.xxxxx.com' was created/updated. New domains may take up to 40 minutes to be initialized.

> serverless deploy
```

Amazon API Gatewayの「カスタムドメイン名」で確認すると設定がされていることが確認できました。

<img width="928" alt="API_Gateway.png" src="https://qiita-image-store.s3.amazonaws.com/0/48549/df3cc34d-b871-02a2-b660-d185f151ee1e.png">


やったぜ。


## 注意点

Amazon API Gatewayでデプロイして、そのまま利用する場合、エンドポイントのURLが```https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/dev/``` となり```dev``` が含まれるため、Nuxt.jsでベースURLの設定をする必要がありますが、カスタムドメインを利用する場合は不要になります。
なので、ベースURLを変更する必要があります。


## 参考

Serverless(node.js)で独自ドメインSSLの適用方法 - Qiita
https://qiita.com/koshilife/items/bb7edb12f0285a241294

Amazon Route53 でドメインを取得する - Qiita
https://qiita.com/NaokiIshimura/items/89e104dd2d8dd950780e

Certificate Manager (ACM) がDNSの検証をサポートしました ｜ DevelopersIO
https://dev.classmethod.jp/cloud/aws/certificate-manager-dns-validation-support/
IoTのポストを作ってみた

<h3>概要</h3>
ポストに郵便物が届いたら、ケータイに通知が届くIoTシステムを考えました。

<h3>材料</h3>
・3軸加速度（ジャイロ）センサモジュール　KXR94-2050
・Raspberry Pi Model 3B
・ジャンパーケーブル
・ブレッドボード
・Arduino
・USBケーブル
・電源など、他
<h3>大まかな概要図</h3>
次のような流れで、作っていきます。
![iotポスト概要図.png](https://qiita-image-store.s3.amazonaws.com/0/252280/bcdaf7a9-ee96-ff50-5329-befb9b9bc7b9.png)

<h3>接続</h3>
このようにブレッドボードとラズパイ、Arduinoを接続しました！
![無題のプレゼンテーション (2).png](https://qiita-image-store.s3.amazonaws.com/0/252280/dc665f2c-f5f0-3d27-bfcf-c7817e36d596.png)

仕様書を見ながらジャイロセンサーをArduinoに接続し、ArduinoはUSBでラズパイに接続しています。
<h3>IoTポストの仕組み</h3>
ポストの開閉部分にジャイロセンサをつけ、ポスト開口部の「開閉動作があった時に動く方向軸」の角度が変わったらものが届いたという判断をします。開口部が動く方向軸以外の動きは必要ない情報なので、取得していません。

Arduinoとジャイロセンサーで傾きの値を取得し、USBシリアル通信でラズパイのPythonへデータを送ります。Pythonでは、得た傾きの値を元に、ポストに動きがあったかどうかを検知しています。
<h3>動画</h3>
<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">ジャイロセンサーを利用した、IoTポストの動画です！<a href="https://t.co/0SeMlgThnN">https://t.co/0SeMlgThnN</a></p>&mdash; 高町咲衣⭐︎(さき) (@takamachi1saki) <a href="https://twitter.com/takamachi1saki/status/1072361132491489280?ref_src=twsrc%5Etfw">2018年12月11日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


<h3>ソースコード</h3>
<h4>Arduinoスケッチ</h4>

```c#
#include <SoftwareSerial.h>

void setup() {
  Serial.begin(9600);
}

void loop() {
  long x;
  x = 0 ;
  x = analogRead(A3) ;
  Serial.print(x);
  delay(200);
}
```
<h4>Python</h4>

```python
import serial
import time
import smtplib
from email.mime.text import MIMEText
from email.utils import formatdate

FROM_ADDRESS = '通知を出すメールアドレス（Gmail）'
MY_PASSWORD = 'パスワード（Gmailのパスワード）'
TO_ADDRESS = '通知を受けるメールアドレス'
BCC = ''
SUBJECT = 'POST!'
BODY = 'Got a Post!!'

def main():
   i = 0
   x_a = 0
   x_dif = 0

  con = serial.Serial('/dev/ttyACM0', 9600) 
  #ラズパイで、コマンド「dmesg」でデバイスファイルの名前を調べましょう。
  #Arduino UNOならこのままでいいです。

   time.sleep(2)
  print con.portstr
while 1:
    str=con.read(3)
    x = str.decode()
    if(x > x_a):
      x_dif = int(x) - int(x_a)
    else:
      x_dif = int(x_a) - int(x)

    if(x_dif > 100):
      if(i != 0):
          print("POST")
          to_addr = TO_ADDRESS
          subject = SUBJECT
          body = BODY

          msg = create_message(FROM_ADDRESS, to_addr, BCC, subject, body)
          send(FROM_ADDRESS, to_addr, msg)

          flg = True
          time.sleep(30)

      else:
        i = 1

    x_a = x

def create_message(from_addr, to_addr, bcc_addrs, subject, body):
  msg = MIMEText(body)
  msg['Subject'] = subject
  msg['From'] = from_addr
  msg['To'] = to_addr
  msg['Bcc'] = bcc_addrs
  msg['Date'] = formatdate()
  return msg

def send(from_addr, to_addrs, msg):
  smtpobj = smtplib.SMTP('smtp.gmail.com', 587)
  smtpobj.ehlo()
  smtpobj.starttls()
  smtpobj.ehlo()
  smtpobj.login(FROM_ADDRESS, MY_PASSWORD)
  smtpobj.sendmail(from_addr, to_addrs, msg.as_string())
  smtpobj.close()

if __name__ == '__main__':
  main()
```

<h3>つまずきやすいポイント</h3>
実現したいことに対してどんなセンサーを使用するのかが、IoTを考える上で重要なポイントです。
色々試してみて、今回は惜しくも向かなかったのが感圧センサー。指で押したりした時の圧力は測れるのですが、紙程度の重さではセンサーの数値が誤差程度しか動かなかったので、使用しませんでした。
<h3>感想</h3>
この方法で、郵便物が届いたことを確実に通知できました！
Project:CoCue【序】ー アイドルのいる生活を送るために

はぁ…今日はライブが無い日か……あぁ、・ちゃん（・・・・・・・・・というアイドルグループのとても可愛いイケメン美少女）に会いたい。
毎日・ちゃんと話す事ができたらどんなに幸せなことでしょう。
寂しい一人暮らしの僕が毎日話しているのなんて、冴えない同僚達とGoogleHomeくらいなもんですよ！

……ん？GoogleHome……？
GoogleHomeが・ちゃんの声で返事してくれたら最高じゃない…？
よーし、おじちゃん、GoogleHomeアプリ作っちゃうぞ〜っ！

なお、これより当プロジェクトを『Poject: CoCue』と呼称する。 


## 準備するもの
###  GoogleHome
国内発売開始時にその場のノリと勢いで購入したGoogleHomeですが、自宅の家電の。

###  音声データ
ライブの予約をするともらえるランダム録音から、ちょうど良い部分をカットしました。

###  ・ちゃんへの熱い想いと愛
そもそもの根幹とも言える・ちゃんへの想いと愛がもっとも重要になります。

### Actions on Google
[Actions on Google](https://developers.google.com/actions/)
- Actions on Googleについて触れる？
なんかGoogleHomeのアプリケーションを作るならほぼコレ一択っぽい。

### Firebase: Cloud Functions
[Cloud Functions](https://firebase.google.com/docs/functions/?hl=ja)
なんかすごい

### Firebase: Cloud Storage
[Cloud Storage](https://cloud.google.com/storage/?hl=ja)
使いたいのが音声データくらいなので、ストレージはなんでもよかったのですが、
せっかくだしGoogleのサービス縛りで構成するかとか変なこだわりで選びました。

## 開発
コード書いたり、設定したりがんばるっ




## 後日談
訪れた・ちゃんとの甘酸っぱい生活？
。。。には、まだまだ程遠いようだ。


### 問題点
- ・ちゃん（てんちゃん）が『10チャン』と認識されてしまう問題
- 対話モードとして使用するには、常にアプリケーションを立ち上げた状態にする必要がある
- アプリケーションを立ち上げた状態だとデフォルトの機能が使えない
- デフォルトの機能だと『OK, Google』のトリガーが必須になってしまうしデフォルト音声が邪魔
- デバッグで喉が渇く

### 今回のまとめ
スマートスピーカーの重要なポイントってトリガーだよなぁ
RaspberryPi + Julius（オープンソースの汎用大語彙連続音声認識エンジン）で柔軟に開発するのもありかな。。。


> 僕と君が繋がりつづける、そんな日がくること願ってる
>  ー ・・・・・・・・・ 『サテライト』より
Scalaの中置記法まとめ

「中置構文」と記されることもある。
具体例は下のサンプルコードの通り。

# まとめ

1. 引数1つの関数の場合、 `.` と `()` を省略して二項演算子として記述可能
1. 更に、名前の最後の文字が `:` の場合、右結合となり、左右の項の位置が入れ替わる
1. 2つの型パラメータを持つジェネリックな型は中置記法で書くことができる[^1]

[^1]: [Scala変態技法最速マスター - kmizuの日記](http://kmizu.hatenablog.com/entry/20100203/1265192486)より引用。型エイリアスを使うケースが多そう

```Scala:典型例
5 + 3 // 5.+(3)
1 :: List(2, 3) // List(2, 3).::(1) = List(1, 2, 3)
Command ~> Id // ~>[Command, Id]
```

# 参考

- [Scala覚え書き(構文編) - koba-e964の日記](http://koba-e964.hatenablog.com/entry/2015/04/05/181409)
- [Scalazの"~>"ってなに？(Scalaの中置記法について) - Qiita](https://qiita.com/poly_soft/items/066568a6b023871e1559)
- [Scalaの記号みたいな奴らなんなの - Qiita](https://qiita.com/harry0000/items/113b5ddbe64a2835a6e2)

# 脚注
RSpecでログイン処理をDRYに書きたい

# 動機

よくRailsで`before_action :authenticate!`みたいなコードを書いて、それをRSpecでテストしたいときがあります。
これをDRYに書くのは結構難しい。

# 問題

普通にべた書きするとだいたいこうなります。

```ruby
describe 'My API' do
  context 'when user is logging in' do
    let(:user) { create(:user) }
    before { allow_any_instance_of(ApplicationController).to receive(:current_user) { user }
    # API Spec...
  end
  
  context 'when user is not logging in' do
    # Specs for user logout...
  end
end

# これを各Specにコピペする…
```

つらいのは以下の2点です。

## contextが増える

ユーザーがログインしているのがほぼ必須なAPIを実装している場合でも、ユーザーがログインしていない場合の挙動をテストしようと思うとユーザーがログアウトしているケースのためのcontextを増やさなくてはならない。

## コピペが増える

ログアウト時のcontextは各Spec間で共有できないので、コピペするしかない。

# 解決策

RSpecの`when_first_matching_example_defined`とshared_contextの組み合わせで劇的に改善します。
まずはコードを掲載します。解説は続きますが、RSpecに多少詳しくないと何を言っているかわからないかも…

## コード

```ruby:spec/rails_helper.rb
RSpec.configure do |config|
  config.when_first_matching_example_defined(:require_login) do
    require 'support/login'
  end
end
```

```ruby:spec/support/login.rb
def login_as(user)
  allow_any_instance_of(ApplicationController).to receive(:current_user).and_return(user)
end

RSpec.shared_context 'when login required' do
  let(:user) { create(:user) }
  before do
    login_as(user)
  end

  context 'when current_user is nil' do
    before do
      allow_any_instance_of(ApplicationController).to receive(:current_user).and_return(nil)
    end

    it 'depends on your spec' do
      # actual spec goes here...
    end
  end
end

RSpec.configure do |config|
  config.include_context 'when login required', :require_login
end

```

## 解説

`rails_helper.rb`から見ていきます。
`when_first_matching_example_defined`はexampleを実行していって引数のタグを最初に発見した際にブロックを実行してくれるようなものです。
ここでは`:require_login`というタグを発見すると`support/login.rb`を`require`するようになっています。
`support/login.rb`内では、最下部で`include_context`を行っています。ここで第2引数を`:require_login`と、先程`when_first_matching_example_defined`で設定したものと同じシンボルを指定します。第1引数は任意の文字列ですが、こちらも次に指定する文字列と同じにします。
`RSpec.shared_context 'when login required' do`という行はshared_contextを定義しています。ここで引数の文字列を先程指定した文字列と同じにすることで、`:require_login`のタグを与えたすべてのexampleにshared_context内のcontextが挿入されます。
shared_context内を見てみると、まずユーザーのログイン処理に相当することを行った上で、ログアウト時に相当するcontextを別に作って`current_user`が`nil`を返すようにしています。さらにexampleもここに書けるため、ログアウト時のテストケースをここに集約することができます。
また、ここで注目すべきは`user`がログインの対象であるため、各exampleで`user`を定義することでログインするユーザーの属性をコントロールできます。

## メリット

* タグをつけるだけでユーザーがログインしている状態が自動的に作られる
* ログアウト時の挙動に関するexampleを一箇所で定義できる
* contextの不必要な増加が起きない
* RSpecの黒魔術を使いこなしている感があって楽しい😎

# まとめ

上のコードをコピペすればだいたい動くはずです。

# 補足

`:require_login`とか、名前がイケてないけど誰かもっといい命名あったら教えてください…
値が一致した行をコピーして最終行に追加するマクロ

#### 概要
・検索値と一致した行をコピーし、結果シートの表の最終行に追加します。
※ 一致する行が、複数でかつ連続にソートされていない場合は、上から一番最初に一致して連続している範囲が対象となります。

【例】

## 元データ（コピー元）
![image.png](https://qiita-image-store.s3.amazonaws.com/0/289724/f818b46b-157e-fbc6-49cb-916727dbf7db.png)


## 検索値
![image.png](https://qiita-image-store.s3.amazonaws.com/0/289724/5247c59d-24f9-f8e0-1ca5-2cbbb255333c.png)


## 出力結果
![image.png](https://qiita-image-store.s3.amazonaws.com/0/289724/321c0361-2274-53bf-538e-4968fd9a4964.png)





【実装例】

```vb
Sub 条件に一致した行を最終行に追加()
'
' 検索値と一致した行を結果シートにコピーする
'

'画面の再描画/自動計算を停止
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual


' 元データがあるシート
Dim masterSheet As Worksheet
' 検索値があるシート
Dim targetSheet As Worksheet
' 結果を出力するシート
Dim outputSheet As Worksheet


Set masterSheet = Worksheets(1)
Set targetSheet = Worksheets(2)
Set outputSheet = Worksheets(3)

' 検索値の最終行を取得
Dim row As Integer
row = targetSheet.Cells(targetSheet.Rows.Count, 1).End(xlUp).row

' 出力行数
Dim cnt As Integer: cnt = 2


For i = 2 To row
    ' 検索結果のセル
    Dim foundCell As Range
    ' 検索値のセル
    Dim searchCell As Range
    
    ' コピーする対象
    Dim copyRange As Range
    

    
    Set searchCell = targetSheet.Cells(i, 1)
    ' 検索値が空白ならスキップ
    If Not searchCell = "" Then
        ' 検索結果取得
        Set foundCell = masterSheet.Range("A:A").Find(searchCell, Lookat:=xlWhole, SearchOrDer:=xlByColumns)
        
        ' 検索結果が得られなかった場合スキップ
        If Not foundCell Is Nothing Then
            
            ' コピー範囲の行カウンタ
            Dim rowCnt As Long
            rowCnt = 1
            ' 検索結果の行番号
            Dim foundRow As Long
            foundRow = foundCell.row
            
            ' コピーする行の範囲を設定（次の行が同じまでループして行の範囲を設定）
            Do While foundCell.Value = masterSheet.Cells(foundRow + rowCnt, 1).Value
                rowCnt = rowCnt + 1
            Loop
            
            
            ' 対象行をコピー
            Set copyRange = masterSheet.Range(masterSheet.Cells(foundRow, 2), masterSheet.Cells(foundRow + rowCnt - 1, 16))
        Else
            ' 検索値が得られなかった場合は、検索値をコピー
            Set copyRange = searchCell

        End If
        
        ' 結果シートの最終行の次に貼付け
        Dim outputEndRow As Integer
        outputEndRow = outputSheet.Cells(outputSheet.Rows.Count, 2).End(xlUp).Offset(1, 0).row - 1
        
        If (outputEndRow = 3) Then
            outputEndRow = outputEndRow + 1
        End If
        

        ' outputSheet.Range(2, outputRow).PasteSpecial (xlPasteAll)
         copyRange.Copy (outputSheet.Cells(outputEndRow, 2))
         
         outputSheet.Cells(outputEndRow + copyRange.Rows.Count, 2).Value = "XXX"
                  
    End If


Next


      
    
'画面の再描画/自動計算を再開
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
    
    
    
End Sub






```
Ubuntu 18.04 LTS, 英語キーボードやMozcの設定の初心者備忘録

# Mozc のインストールや設定

https://sicklylife.jp/ubuntu/1804/mozc_ut2.html
を参考に、インストールしました。

# 英語キーボードの設定

```
設定 -> 地域と言語 -> 入力ソース を 英語(US) -> 日本語(Mozc) にした
```

# alt + grave(`) で Mozc に切り替え

```
sudo apt-get install dconf-editor
```
で、dconf エディタをインストールしました。

```
アクティビティより dconf エディターを起動
org > gnome > desktop > wm > keybindings
['<Super>Above_Tab','<Alt>Above_Tab'] を ['disabled'] に変更
```
として、「alt + grave でアプリなどが切り替わる」のを無くしました。

```
設定 -> デバイス -> キーボード -> 次の入力ソースへ切り替える
を、「Alt + `」に設定する。
```

# 参考にさせて頂いた URL 

https://sicklylife.jp/ubuntu/1804/mozc_ut2.html

https://qiita.com/oicawa/items/7582a0aa865b866ffde1

https://www.nekochango.com/entry/linux/ubuntu/fcitx
外に出ている自分から会社にいる隣席の人にお願い事がある

皆様夜な夜なこんばんわ。
@HiromiSakuraiことひろみちゃんです。
![17773_411555162247680_1855825762_n.jpg](https://qiita-image-store.s3.amazonaws.com/0/312673/b4496909-8689-3b37-83ef-b47d3a1f7a58.jpeg)

[Seeed UG Advent Calendar 2018](https://qiita.com/advent-calendar/2018/seeed)の12日目空いてたので頂きました。

私の事を知ってる方であればご存知でしょうが知名度はまだまだ低いのでご紹介します。
[co-worksのTibbo-Pi](https://tibbo-pi.co-works.co.jp/)
こんなデバイス作って売ってる会社にいます。

[Groveのセンサ](https://tibbo-pi.co-works.co.jp/news/new_item_universal_4pin_connector/)を繋ぐことが出来るブロックを作ってセンサが少ないTibbo-PiのラインナップをSeeed社の力を借りて充実させようという乗っかりプロジェクトから生まれた一品です。

![tpbit02.png](https://qiita-image-store.s3.amazonaws.com/0/312673/c41e72a9-11dd-2e36-359b-e57f201ce2ee.png)

ありがとうSeeed様。後は個々のセンサの対応してくだけ。俺あんまやらないけど誰かがやってくれるはず。

とりあえず今日の時点で対応終わってるリストが届いたのでなんかやってみようかと思って手出した。
↓リスト
・Grove:心拍センサ
・Grove:スライドボリューム
・Grove:火炎センサ
・Grove:ラインファインダ v1.1
・Grove:赤外線反射センサ v1.2
・Grove:タッチセンサ
・Grove:赤外線測距センサ v1.2
・Grove:レコーダー v3.0
・Grove:ボリューム(パネルタイプ)

うーん、あんまり例が無さそうなとこ使ってみたいというマイノリティ思想がうずく。
じゃあこれで！
[Grove:レコーダー v3.0](http://wiki.seeedstudio.com/Grove-Recorder_v3.0/)
![cover.jpg](https://qiita-image-store.s3.amazonaws.com/0/312673/f49e8b24-6302-fe7b-95cb-17a02155e45a.jpeg)

マイクとスピーカーがついてて83秒間録音・再生が出来る。音量調整もできる。
ふむふむ。

これはアレをもっと和やかにできるかも！！

アレとは、仕事上外出や出張が多いんですが、いつも電話出来る環境にいるわけでもなく、メッセンジャーやメールで連絡を取る事を余儀なくされるんです。
ただ、メッセンジャーやメールって通知は届くんでしょうけど、職場で音出してる人も少なく送っても気付かれない場合が多いですよね？
そこで自分の机に置いてあるTibbo-Piに標準で付いてるブザーを鳴らしてるんです。

**Tibbo-Pi「ビー！ビー！」**
**隣席の人(うるせぇ＆うぜぇ＆お前の仕事なんか知らん)**

多分こんな事思ってると思うんです。
そこでこのレコーダーの出番です。
自分の声でお願いしたら少し和やかにお願い事ができるかなと。

Tibbo-Piと言えばNode-REDですが、チュートリアルに使い方や自分みたいなめんどくさい人用のサンプルソースが置いてあります。
[レコーダーのチュートリアル](https://tibbo-pi.co-works.co.jp/tutorial/grove_recorder_v3_0/)
ここからソースコピーしてNode-REDのメニューから読み込み選んでペースト。
![1a05a953ecb8f3c28a313731d3cf5a81.png](https://qiita-image-store.s3.amazonaws.com/0/312673/b160c2fc-7c23-73b4-c053-0ec7bcf7657e.png)
![ff1c624ef3d8ce5567e7b1e3828bd1c1.png](https://qiita-image-store.s3.amazonaws.com/0/312673/e7b59407-e215-6b30-4de4-8601e4161694.png)
**なんて簡単なっ・・・（宣伝）**

![P_20181211_184914.jpg](https://qiita-image-store.s3.amazonaws.com/0/312673/a6bc822c-c069-8937-6efd-c74e38ee8b39.jpeg)
Tibbo-Piとレコーダーはこんな感じで接続。
**ブロック刺してコネクタ繋ぐだけっ！Groveのセンサの相性抜群！（宣伝）**

ほんとはここでNode-REDの説明したかったんだけど、スクショ撮るの忘れて帰ってきちゃったんで絵で説明。筆ペンがすぐそこにあったんでそれで書いた。
![WIN_20181212_03_50_42_Pro.jpg](https://qiita-image-store.s3.amazonaws.com/0/312673/2e60ba69-e05a-c839-9e42-fac31aad435f.jpeg)

絵で描くとしょぼいけど、この基本構成は良く使います。
Node-REDってやっぱりNode-REDと相性いいんですよ！（当たり前）
ほかにもクラウドサービスがいっぱいあるけど、いつもと同じ感覚で使えるNode-REDの使いやすさは異常・・・！
[声再生動画（youtube）](https://youtu.be/qf3CtzCWycU)
![koe.png](https://qiita-image-store.s3.amazonaws.com/0/312673/f050a04c-c827-043f-05e3-99952dacf08d.png)

**Tibbo-Pi「お願いがあります」**
**隣席の人(え？なになに？何頼まれてあげようかなぁ♪キュン♪)**

これで和やかになる事間違いなし。
lighttpdを起動するときに渡した環境変数をCGIから利用する

シェルスクリプトでWebアプリケーションいけますよっていっても、実際にこんな感じで開発するといいみたいなプラクティスが古いまま（ローカルにApacheいれたりとか、まあ別にそれでもいいんだけど）なので、試してみたことを書き残しておこうと思います。

タイトルなんのこっちゃって感じですが、

```sh
HOGE=aaaa lighttpd -D -f lighttpd.conf
```

みたいな感じで渡した環境変数`HOGE`を、CGIスクリプト内で使用するためのlighttpdの設定についてです。
`API_KEY=xxxxxxxx rails s` みたいな感じの、現代的なWeb開発環境だとだいたいあるアレです。（語彙）

サンプルコードはこちら: https://github.com/miminashi/lighttpd_env_example

# lighttpd.conf の設定

- `mod_setenv`を有効化する
- `setenv.add-environment`に、CGIに渡したい環境変数を追加する

```lighttpd.conf
server.modules += ( "mod_setenv" )
setenv.add-environment = ( "HOGE" => env.HOGE )
```

# CGIのスクリプトの例

- 普通に環境変数`HOGE`を使用できるようになっています

```sh
#!/bin/sh

printf 'Content-Type: text/plain; charset=UTF-8\r\n\r\n'
printf 'HOGE: %s\r\n' ${HOGE}
```

# 実行

```shell-session
$ brew install lighttpd
$ HOGE=helloworld lighttpd -D -f lighttpd.conf
```

# 動作確認

- 当然ですが別のTerminalを開きます
- 当然ですがブラウザから確認してもOK

```shell-session
$ curl http://localhost:3000/cgi-bin/hello.cgi
HOGE: helloworld
```

# まとめ

- lighttpdで環境変数ひとつずつ指定するしかないのか・・・？
- 参考: https://stackoverflow.com/questions/28818130/lighttpd-not-making-global-environment-variables-availble-to-executables
RTMPに対して性能テストを行ってみる


## 概要
業務でRTMPを使ったアプリケーションを運用しています。
このアプリケーションに対して、性能テストを行うことになりました。
対応した内容をまとめていきます。

### ツール選定
当初はJMeterへプラグインを導入し実施する計画だったが、試験が上手くできませんでした。
そこで、Flazrを試したところ概ね動作を見せたため今回設定に至りました。

### Flazrの導入

`brew` でインストールすることができなかったので、パッケージはこちらのサイトから入手します。

```
https://sourceforge.net/projects/flazr/files/flazr/
```
※実行にはjavaが必要なので、ない場合はインストールが必要です。

### Flazrの実行
Flazrの実行はダウンロードしたflazrディレクトリに潜り、下記形式のコマンドを実行します。

```bash
./client.sh -version [クライアントバージョン] -load [接続数] -threads [スレッド数] -host [IP] -port [ポート番号] -app [アプリケーション名] [ストリーム名]
```

### 実践
では実際にアプリケーションを用意して、Flazrを使ってみます。
アプリケーションは[nginxで動画配信(RTMP)サーバーを構築して、OBSの映像ソースとして取り込む
](https://qiita.com/danna_P/items/b6cae10313b2eb9b076a)のやり方を参考に、`nginx`に`RTMP`モジュールを追加する形で対応します。

準備が終わったらOBSを使って配信します。
![スクリーンショット 2018-12-12 2.40.50.png](https://qiita-image-store.s3.amazonaws.com/0/39671/bca61a70-0495-2e6f-df03-a86909860775.png "スクリーンショット 2018-12-12 2.40.50.png")

これで準備は整いました。
では実際に負荷をかけていきます。

今回は100プロセスほど実行します。
実行すると下記のように、ターミナルに実行結果が流れ、コネクト状態になります

```bash
$ ./client.sh -version 00000000 -load 100 -threads 15 -host 192.168.33.99 -port 1935 -app live test
```

![トリム.mov.gif](https://qiita-image-store.s3.amazonaws.com/0/39671/3b55ff1c-1277-af51-ca90-8610ce99cb90.gif "トリム.mov.gif")

この状態で監視ツール(Mackerel)を見ると、負荷がかかっていることが確認できるかと思います。

![スクリーンショット 2018-12-12 2.43.53.png](https://qiita-image-store.s3.amazonaws.com/0/39671/70b55c2a-d0c2-13c9-cb7f-eb8a8a25b5f1.png "スクリーンショット 2018-12-12 2.43.53.png")

## まとめ
このようにFlazrを使うことで、RTMPに対して負荷試験を行うことができるようになります。

以上、最後まで読んでいただきありがとうございました。

## 参考
* *[nginxで動画配信(RTMP)サーバーを構築して、OBSの映像ソースとして取り込む
](https://qiita.com/danna_P/items/b6cae10313b2eb9b076a)*
N個上の階層に移動するコマンドを自作した話

## `cd ..` って打つのが面倒

一つ上の階層に行くという、日常的に行う操作のために5文字もタイプしなければいけないのは無駄な感じがしませんか？
特に `.` が打ちづらくて、手がホームポジションからズレてしまいます。
また、3つ上の階層に行くとなると、 `cd ../../..` と、更にタイプ数が増えてしまい、より面倒さが増します。


## 上の階層に移動するためのコマンド

というわけで関数を自作しました。

### Setup

以下のスクリプトを `.bashrc` や `.zshrc` に書いておくと使えます。

```shell
function up () {
    if [ $# -eq 0 ] ; then
        cd ..
    else
        for ((i=0; i < $1; i++))
        do
            cd ..
        done
    fi
}
```


### Usage

```sh
up     # cd .. と同じ
up 3   # cd ../../.. と同じ
```


### 説明

- 引数が指定されていなければ `cd ..` を行う
- 引数が指定されていれば、その値の回数だけ `cd ..` を行う

というだけの関数です。


## まとめ

僕がこの関数を使い始めてから、もうすぐ2年ほど経ちます。
`cd ..` が `up` という二文字だけで実現できることで、こんなにも楽になるとは思いませんでした。
ただ、特に使うのは `up` だけなので、 `alias up='cd ..'` でもいいかもしれません。
しかし、普段学んでいる技術を使って、自分の生活を楽にするのはとても楽しいです。
みなさんも、楽するためのコマンドなどを作って、使い倒しましょう！
centos7【centos7.6 && Virtualbox5.2.22のGuestAdditionsのインストールでこける】

###環境
Virtualbox: 5.2.22
Guest OS: centos7.6(kernel:3.10.0-957.1.3.el7)
Host OS: centos7.5


###現象
2018/12/12現在、kernelのupdateをかけてからguestadditionsをインストールしようとしたらエラーした。
画面サイズがディスプレイいっぱいにならなかったり、ホストとの共有ディレクトリやクリップボード共有も無効となる。

###エラーの内容
GuestAdditionsのインストール途中でエラーメッセージを確認しろというメッセージが出てインストールができない。
※dkms,make,gcc,bzip2,gcc-c++,kernel-headers,kernel-devel,perlはインストール済み
※kernel-headersとkernelのバージョンも一致していることを確認済み

```
$ cat /var/log/vboxadd-install.log

chcon: can't apply partial context to unlabeled file '/opt/VBoxGuestAdditions-5.2.22/src/vboxguest-5.2.22/build_in_tmp'
chcon: can't apply partial context to unlabeled file '/opt/VBoxGuestAdditions-5.2.22/other/mount.vboxsf'
chcon: can't apply partial context to unlabeled file '/var/lib/VBoxGuestAdditions/lib/libGL.so.1'

$ cat /var/log/vboxadd-setup.log

Building the main Guest Additions module.
Building the shared folder support module.
Building the graphics driver module.
Error building the module.  Build output follows.
make V=1 CONFIG_MODULE_SIG= -C /lib/modules/3.10.0-957.1.3.el7.x86_64/build SUBDIRS=/tmp/vbox.0 SRCROOT=/tmp/vbox.0 -j2 modules
make[1]: warning: -jN forced in submake: disabling jobserver mode.
test -e include/generated/autoconf.h -a -e include/config/auto.conf || (                \
echo >&2;                                                       \
echo >&2 "  ERROR: Kernel configuration is invalid.";           \
echo >&2 "         include/generated/autoconf.h or include/config/auto.conf are missing.";\
echo >&2 "         Run 'make oldconfig && make prepare' on kernel src to fix it.";      \
echo >&2 ;                                                      \
（以下略）


```


エラーのメッセージは以下URLと同じ現象
https://www.centos.org/forums/viewtopic.php?t=69013&p=289780


###解決策
上記URLによると、残念ながら次のvirtualboxのバージョンアップ(5.2.23)まで待つか、どうしてもcentos7.6でやるならvirtualbox以外の仮想化ツールを使うしかなさそう。

###参考
2018/12/12現在、以下からvirtualbox 5.2.23のTestbuildsは入手可能。
https://www.virtualbox.org/wiki/Testbuilds
VirtualboxのticketにはTestbuildsでcentos7.6で成功したとの書き込みもあるよう。
https://www.virtualbox.org/ticket/18093
redis-clusterのfailover挙動

# 背景
- redis clusterのfailoverには過半数のmasterの投票が必要らしい
- 実際に確認してみた

# 初期状態
![スクリーンショット 2018-12-12 2.08.53.png](https://qiita-image-store.s3.amazonaws.com/0/89548/aa445561-9d6a-5bc0-eea7-cc53f3ed0a04.png)
- 3 master, 3 slave
- redis 4.0.9

# slaveを1台破壊
## こうすると
![スクリーンショット 2018-12-12 2.09.02.png](https://qiita-image-store.s3.amazonaws.com/0/89548/2d0e746f-9cc7-df20-74ff-ed106f2fe6d0.png)

## こうなる
![スクリーンショット 2018-12-12 2.09.11.png](https://qiita-image-store.s3.amazonaws.com/0/89548/14d8f159-a0d2-e912-fd9c-805d7161d046.png)

slave1こわれるだけ。masterには影響なし


# masterを1台破壊
## こうすると
![スクリーンショット 2018-12-12 2.09.20.png](https://qiita-image-store.s3.amazonaws.com/0/89548/5235c157-27a3-1819-6ed5-cb9b1053b983.png)


## こうなる
![スクリーンショット 2018-12-12 2.09.34.png](https://qiita-image-store.s3.amazonaws.com/0/89548/d71c9554-d79b-a064-60fa-02909b2e12ad.png)

replicationされてるslaveが昇格.1minくらいタイムラグあり



# master2台を順次破壊する
## こうすると
![スクリーンショット 2018-12-12 2.14.31.png](https://qiita-image-store.s3.amazonaws.com/0/89548/bbea7839-d5be-adba-9742-5e7433de1fd7.png)


## こうなる
![スクリーンショット 2018-12-12 2.14.43.png](https://qiita-image-store.s3.amazonaws.com/0/89548/24b95c18-a8fc-56c6-dfa1-a7ac2ad75980.png)

replicationされてるslaveが昇格.1minくらいタイムラグあり



# master2台を同時に破壊
## こうすると
![スクリーンショット 2018-12-12 2.15.54.png](https://qiita-image-store.s3.amazonaws.com/0/89548/4b88d44e-2244-e231-f59e-3ff1298dcf56.png)

## こうなる
![スクリーンショット 2018-12-12 2.16.07.png](https://qiita-image-store.s3.amazonaws.com/0/89548/f752a432-df8f-92b5-aa81-f6c37f778591.png)


## failoverが発生しない理由
- slaveの昇格ルール
    - 全masterの過半数の投票が必要
- 1台ずつ壊れたとき
    - 1台目壊れたとき
        - 投票権を持っているmasterは2台。(master2, master3)
        - 全master3台中、過半数の投票によりfailoverが発生
    - 2台目も同様
- 2台同時に壊れたとき
    - 投票権を持っているmasterは1台。(master3)
    - 投票数は過半数に達しないので、failover発生せず
- 公式: https://redis.io/topics/cluster-spec#availability


# 同じ系統のmaster-slaveを破壊
## こうすると
![スクリーンショット 2018-12-12 2.18.44.png](https://qiita-image-store.s3.amazonaws.com/0/89548/02781aa9-4599-6981-c89f-5ec19dcf1482.png)

## こうなる
![スクリーンショット 2018-12-12 2.18.56.png](https://qiita-image-store.s3.amazonaws.com/0/89548/174327dd-d981-ad71-0297-bfa7b6bcf6e3.png)


# 結論
以下の場合にアプリに影響あり。
- 同じ系統のmaster, slaveが死ぬ
- masterが2台以下の状態で、masterが死ぬ
Azure Monitor for containersが晴れてGAしました!

今年の9月 Microsoft Ignite(Orlando, USA)において、Azure Monitorのリブランディング（ブランド再構築）を発表させて頂きました。その発表の中の1つが「Azure Monitor for containers（別名 : container insights）」です。Azure Kubernetes Service（AKS）をすでにご利用されている方なら、AzureポータルのAKSの［概要］ページに［Monitor コンテナー］というタイルが置かれていることをご存知かと思います。これがAzure Monitor for containersです。
![overview.png](https://qiita-image-store.s3.amazonaws.com/0/321495/3ee8f039-69ba-bd3a-cd28-947c33e41c2d.png)

元々、Microsoftにはコンテナ監視の製品が存在しておらず、2年前、コンテナ監視が今後、重要になることを社内で訴求し、Log Analytics Container Monitor Solutionを立ち上げ、去年GA(General Availability : 一般提供開始)させて頂きました。この製品は、Docker コンテナを中心とした監視ツールです。その後、コンテナ技術が普及し始め、Kubernetesなどのオーケストレーションやワークロードなどを中心に監視するツールの必然性が出てきました。
### Azure（クラウド）上での監視ツールへの考察 
オーケストレーションを中心とした監視ツールを考察していく上で「ただ単にコンテナの監視ツールではなく、クラウド（Azure）上での監視ツールを」と考えるようになりました。そこで検討したのが次のポイントです。
•	Azureと言う広範囲な場所にAKSなどのサービス群を発見し、簡単に監視できること。
•	監視されていないAKSはあるのか？
•	クラウドサービスの傍らに監視がないといけない。監視ツールを探す手間が面倒。
•	簡単に問題が発見でき、監視ツールを覚える必要のないユーザー体験（UX）が必要。
•	監視ツールの管理や監視をしなくても良く、手間いらずで、自動的にメンテナンスやアップグレードをしてくれる。つまり、監視ツールにでなく、自社のビジネス向上だけに人件費をかけることが出来る。
### 考察の末に出来たオーケストレーションを中心としたAzureコンテナ監視
今年5月 //build conference（Seattle, USA）にて、Azure Monitor for containers（プリビュー）を発表させて頂きました。Azure Monitor for containersには次の新しい試みがあります。
AKSを作成する際、同時にコンテナーの監視を有効化できる (Azureポータル、CLI、Terraformなど) 。
![onboard.png](https://qiita-image-store.s3.amazonaws.com/0/321495/1923ba67-f994-c7e6-5014-e0e232cec3b8.png)
AKSの［概要］ページに［Monitor コンテナー］パネルがあり、クリック１つでコンテナ、ノードなどを含めたKubernetesクラスター全体が把握できる。
![clusterandcontroller.png](https://qiita-image-store.s3.amazonaws.com/0/321495/b38b8b00-a780-1f38-5d75-2fa85fd77d96.png)
Azureサブスクリプションやリソースグループに関係なく、Azure上のAKSを一覧表示し、そのクラスターの健康状態が一望できる。また、監視されていなければ、それも提示し、簡単に監視を追加できる。
![multicluster.png](https://qiita-image-store.s3.amazonaws.com/0/321495/074cca54-25ee-f160-60c5-c8371de0c743.png)
このようにAzure Monitor for containersでは、クラウドサービス（AKS）と一体となった監視を提供することが出来ました。さらに、コントローラーやコンテナビューにて、リミットやリクエストもお見せすることにより、スケールの見通しやコストを意識したデプロイメントのお手伝いが出来るようにいたしました。ライブログ機能により、デプロイしたコンテナをリアルタイムでログ監視することもできます。(Observability)
![livelogs.png](https://qiita-image-store.s3.amazonaws.com/0/321495/b7713e8b-f8be-107a-5279-5ef329440d15.png)
まだ、この記事では、紹介しきれない監視機能が他にもたくさんあります。製品を使ってみてください。詳細は、下記の参考文献をご覧ください。
### GA(一般提供開始)、そして、、、
12月11日 KubeCon（Seattle, USA）を機に、Azure Monitor for containersをGAさせて頂きました。GAしたからと言って、開発が終了したわけではありません。まだ、これからだと思っています。特にマイクロサービスや分散トレーシング（Open tracing）について、より深くかかわっていく予定です。製品に関してのコメントやリクエストがあれば、ぜひお知らせください。随時、受け付けております。

**原田慶子 - Azure Monitor and Analytics - Senior Program Manager**

#### 参考文献：
•	Azure監視ブログ: https://azure.microsoft.com/en-us/blog/new-full-stack-monitoring-capabilities-in-azure-monitor/ 
•	Azure Monitor for containers 一般提供開始ブログ: https://azure.microsoft.com/en-us/blog/azure-monitor-for-containers-now-generally-available/ 
•	製品説明書：https://docs.microsoft.com/ja-jp/azure/azure-monitor/insights/container-insights-overview 
•	ケーススタディ: https://customers.microsoft.com/en-us/story/hafslund-nett-power-and-utilities-azure
•	フォーラム: https://techcommunity.microsoft.com/t5/Azure-Monitor/bd-p/AzureMonitor (label “container insights”)
Google公式Flutter用WebViewプラグインを一通り使ってみた

# はじめに
この記事は[Flutter Advent Calendar 2018](https://qiita.com/advent-calendar/2018/flutter)の11日目分です。

すぐに枠が埋まってしまっていたのでFlutter Advent Calendarに参加する予定はなかったのですが、前回の「[Google公式Flutter用Google Mapsプラグインを一通り使ってみた](https://qiita.com/aoinakanishi/items/25f2526fc7c1fe8350c6)」に引き続き、11日枠が投稿されずに空いていたので急遽この記事を書くことにしました！

今回も先日のFlutter Live 2018で合わせて提供が開始されたWebViewです。

# Google公式Flutter用WebViewプラグインがついに公開

Flutterユーザーならみなさんご存知かと思いますがFlutter上でWebViewを使う公式プラグインは存在しませんでした。

ところが先日「[Flutterウィークリー #37](https://qiita.com/aoinakanishi/items/d2d6f6fd21b3ba287715)」でもお伝えしたとおり、Googleから公式のWebViewプラグインが公開されました。現在はデベロッパープレビューという形で提供されていますが、誰でも利用することが出来ます。

# パッケージ

https://pub.dartlang.org/packages/webview_flutter

# webview_flutterのGithubリポジトリ

https://github.com/flutter/plugins/tree/master/packages/webview_flutter

# iOS用設定
ios/Runner/Info.plistを開いて以下を追記します

```xml
    <key>io.flutter.embedded_views_preview</key>
    <string>YES</string>
```

# dependencyにwebview_flutterを追加

```yaml
dependencies:
  flutter:
    sdk: flutter

  # The following adds the Cupertino Icons font to your application.
  # Use with the CupertinoIcons class for iOS style icons.
  cupertino_icons: ^0.1.2
  webview_flutter: ^0.1.0+1

dev_dependencies:
  flutter_test:
    sdk: flutter
```

# パッケージの宣言

```dart
import 'package:webview_flutter/webview_flutter.dart';
```

# WebView表示用コード

```dart
      body: WebView(
        initialUrl: 'https://flutter.io',\
      ),
```

# スクリーンショット

## Android
<img width="428" alt="Screen Shot 2018-12-12 at 00.45.24.png" src="https://qiita-image-store.s3.amazonaws.com/0/129712/77ac1de6-1bbc-94ac-80bf-d2bf90378c1f.png">

## iOS
<img width="487" alt="Screen Shot 2018-12-12 at 00.45.32.png" src="https://qiita-image-store.s3.amazonaws.com/0/129712/54a93666-f98d-06fd-d00a-62245b10b1a6.png">

# JavaScriptを有効にする

```dart
      body: WebView(
        initialUrl: 'https://flutter.io',
        javaScriptMode: JavaScriptMode.unrestricted,
      ),
```


|値|状態|
|:---|:---|
|JavaScriptMode.disabled|無効|
|JavaScriptMode.unrestricted|有効|

# WebViewクリエイト時のイベントを取得

```dart
      body: WebView(
        initialUrl: 'https://flutter.io',
        javaScriptMode: JavaScriptMode.unrestricted,
        onWebViewCreated: (WebViewController webViewController) {
          print("Created!");
        },
      ),
```

# WebViewControllerで出来ること

|メソッド名|引数|説明|
|:--|:--:|:--|
|loadUrl|string|URLを渡して遷移|
|canGoBack|-|前のページに戻れるか|
|canGoForward|-|先のページに進めるか|
|goBack|-|戻る|
|goForward|-|進む|

# まとめ

先日調査したGoogle Mapsにも増してまだまだ何も出来ない印象です。基本的な動作、ページの表示、戻る、進む、JavaScriptの有効化、無効化の操作が出来るだけで他の設定変更やHTTPヘッダの操作、エラーハンドリング、などなど、WebViewを使って独自の機能を実装することは現状できないと考えたほうが良さそうです。

プラグインのソースを追いかけていくと`updateSettings`というメソッドがあったので、いろいろと変更できるかと思いましたが、`jsMode` というパラメーターを受け取って処理できる以外は

> throw new IllegalArgumentException("Unknown WebView setting: " + key);

というエラーを返すだけでした。唯一受け取ることが可能な`jsMode`も先のjavaScriptModeでOn/Offを切り替えられるのと同じことが出来るようになっていました。

WebViewもアプリ内でよく使う機能のひとつなので、公式プラグインが出たのはFlutterを業務で利用できない理由が一つ減ったということで、今後のアップデートに期待したいですね。

# この記事のソースコード

https://github.com/aoinakanishi/flutter-webview-example
広告の「直接的と間接的な効果」は「ストライカーとアシスト」の関係

# はじめに

Adventカレンダー「エンジニアのためのWebマーケティング」の11日目です。
サクッと読める記事を目標に。異論・ツッコミ大歓迎。
できるだけ専門用語を使わないように気をつけます。

「サクッと」と言っている割に、結構ダラダラ長いので短くまとめるのをもっと意識して・・・

それでは参りましょう

# 突然ですが

みなさんは直接的な効果を及ぼす広告というと何を思い浮かべますか？

いちばん有名なものは**「リスティング広告」**と言われています。
これは消費者が能動的に購入を意識した時は、目的の物を自身で検索して購入する傾向が高く、その際に出てくる広告が「リスティング広告」が圧倒的に高いためです。

例えば、
「スマブラ switch」と検索したユーザーは、先日発売した「大乱闘スマッシュブラザーズ SPECIAL」を買う可能性が高く、そのワードで検索した時に出るリスティング広告に**Amazonや楽天**の広告を出すと消費者が買う可能性が高いことを示しています。

## リスティングは「刈り取り」が得意

ということは、リスティング広告は**購入欲求が高いユーザーを刈り取るのが得意（＝コンバージョンさせるのが得意）**ということになります。

サッカーで言い換えるなら、**優秀な「ストライカー」**です。


## ディスプレイ広告は「育成」が得意

対するディスプレイ広告などの「ネットサーフィン」の途中に出てくるような広告は**購入欲求がまだ低いユーザーを育成するのが得意（＝コンバージョン予備軍に持っていくのが得意）**ということになります。

サッカーで言い換えるなら、**優秀な「アシストプレイヤー」**です



# Webサイトで購入がされた時、それは誰のおかげ？

**コンバージョンが発生した時に、その立役者は一体誰なのでしょうか？**

今までサッカーで例えたので、引き続き例えてみましょう。

これはつまり、
**「サッカーで得点が入ったら、シュートを決めた選手のおかげなのでしょうか？」**
という質問と同じような意味になります。

YesでもありNoでもありますね。

確かに、シュートをした選手がいないと得点は入りませんが、「シュートができる状態まで持っていった選手」も貢献していることは理解できるかと思います。

## 広告も同じ

ということは、刈り取りをしたリスティングも優秀ではありますが、**「ユーザーに検索させる意欲まで引き上げた他の広告」**も優秀であることがわかります。

広告を運用していると、リスティングのコンバージョン（＝直接効果）ばかりに目が行きがちになりますが、ディスプレイ広告などの**間接効果**にもぜひ、目を向けてみてください。

正しい広告効果の評価は、**コンバージョンに至ったユーザーが最初からどんな道のりを辿ってきたか**を正確に把握し判断することから始めます。

# 結論

広告の評価はサッカーと同じで、
**得点を決めた人とその人にパスを回した人の療法を評価するべし！**

# どうでもいい話

自分が昔好きだったサッカー選手は、ゴールキーパーの[川口選手](https://ja.wikipedia.org/wiki/%E5%B7%9D%E5%8F%A3%E8%83%BD%E6%B4%BB)でした。

# おわりに

明日は、「流入チャンネルが持つ意味」について解説します
12-12 std::audioはクロスプラットフォームオーディオAPIの基盤となるか

https://adventar.org/calendars/3353 の12日目エントリーです。

11/20, 11/21の2日間にわたってロンドンでAudio Developers Conference 2018というイベントが行われ、わたしもそれに参加してきました。ADC自体は正直JUCEの開発元ROLIがJUCEのために開催しているカンファレンスと評価するのが妥当な感じでしたが、その中でC++で標準オーディオAPI仕様を策定しよう、というセッションがJetBrainsの開発者によって行われました。

前回議論したことですが、クロスプラットフォーム・オーディオライブラリの機能要件は、地味に増えていることがあります。とは言っても、その中には「技術標準」として考慮すべき事項とそうでない事項があります。たとえばWindowsでwinmmに加えてwasapiをサポートするとか、ASIOをサポートする（あるいはしない）というのは、特定プラットフォームの実装面での要件です。こういう問題は標準APIの議論の範疇にはありません。

逆に、入出力チャンネルについて、ステレオまでだけではなく5.1chや7.1ch、3Dオーディオなども考慮した多チャンネルをサポートしなければならない、といった要件は、プラットフォームを問わずに発生する新しい要件であり、標準化において考慮すべき事項です。

多チャンネルのオーディオバッファをinterleaved（単一の配列＝バッファにフレーム単位でチャンネルごとに順番にデータを入れる方式 = `frame1 (ch1, ch2), frame2 (ch1, ch2), ...`）で取得したりdeinterleaveしたり（interleavedなバッファをフレームからチャンネル単位のバッファに分解してチャンネルごとにまとめる方式 = `ch1 (frame1, frame2, ...）, ch2 (frame1, frame2, ...), ...`に変換）といったAPIも用意して、一般的な要求に応えたいようです。

std::audioについては、セッション中はデモが行われましたが、現時点でまだリポジトリすら公開されておらず、デモが行われたセッションの録画も公開されておらず（他のセッションはほとんど[公開されている](https://www.youtube.com/playlist?list=PLe2skUvADfhtnpEe-6t8N963ziOwqIRi1)のですが）、外部の人間が実装をテストできると言える状況とはまだ言えなそうです。既存のクロスプラットフォーム・オーディオライブラリがたくさんあるのに何で新しいものを作ろうとするの?という質問も出ましたが、これから意見募集するかも?みたいな雰囲気でした。個人的な印象としては、「こんなのがあったらいいんじゃないか」という思いつきで構想を出してセッション案も出してしゃべったけど、まだ勇み足で、相談したり意見を受け容れたりする準備は何も整っていないのかな?という感じでした。

わたしがstd::audio構想について根本的に疑問があるとしたら、既存の標準化作業の成果を使うのではダメなのか?というところです。特にオーディオの最適レート取得をどうするかとか、16ビット整数とfloatのどちらをデフォルトにするかとか、まだ決まっていない部分などがあるといいますが、Web Audio APIのような先例はすでにあるので、基本的な部分の議論がまた繰り返しになるだけなのではないか、と思います。Web Audio APIは無駄に高度な機能を抱え込みすぎたきらいもあるので（firefoxの[Audio Data API仕様](https://wiki.mozilla.org/Audio_Data_API)を振り返ってみましょう）、全部をフォローする必要は全く無いと思いますが、参考にする部分は少なからずあることでしょう。

ちなみにWeb Audio APIのオーディオ実装を抜き出してクロスプラットフォームのオーディオライブラリにしちゃえばいいんじゃないか?と思った人もいるかもしれません。ハイ、あります。Chromiumのソースのforkだそうです。

https://github.com/LabSound/LabSound

ちょうど前回紹介したブログにFirefoxのオーディオ実装であるcucebを抜き出して使ったらどうか?みたいな話が載っていましたが、そのChromium版のようなものだと思えばよさそうです。個人的にはこの辺が現状では妥当な落としどころなんじゃないかなと思っています。ただ、C++のソリューションでは、Cで書かれたportaudioやlibsoundioのように言語の壁を越えて使われることは、ほとんど無いでしょう。

ちなみにcucebについて「何で単独で使えるようにモジュール分けてないんだよ」という内容になっている前述の記事について、[hacker newsでは](https://news.ycombinator.com/item?id=8727312)「ちゃんとモジュールはわかれている」「そうなのか。何か本文の内容も信じられなくなってきたな」みたいなコメントが続いていて、眉に唾をつけながら読んだほうがいいのかなとも思います。

標準化には段階がいくつかあり、（詳しいことは忘れてしまいましたが）さまざまな委員会レビューを経て承認される必要があり、標準化が実現するまでは早くても2022年あるいは2023年までかかるのではないかという感じでした（登壇者は2022年頃ではないかと説明し、聴衆の一部が2023年まではかかるはずだというコメントを出していました）。それくらいのタイムフレームで見ておくとよさそうです。
slackのスラッシュコマンドでチームスピリットの勤怠打刻を行う

[リバネス](https://lne.st)の勤怠管理は[Teamspirit](https://www.teamspirit.co.jp/)を使って行われています。スタッフの勤務状況を記録する為に必要な要素は揃っています。
一方で、勤怠打刻は当然手動で行う必要があります。手段としては
- 出社時、オフィスエントランスにある[非接触ICカードリーダーにSuica等をかざして打刻](http://teamspirit.clouds-spice.com/)
- Salesforceのモバイルアプリから打刻：[参照](https://qiita.com/geeorgey/items/e25daaf97ed2f9721c6c)
といった、２パターンを用意していますが、ここにもう一つ打刻手段を追加してみました。
slackはリバネススタッフが恐らく一番使っているコミュニケーションハブとなっています。だったら、その中でできちゃったほうが楽だよねというのが発想の原点です。
## 勤怠打刻のためのslack appを作る
では、その実現方法はどうすればよいだろうと考えたとき、過去に[botkit](https://github.com/howdyai/botkit)を使ってちょっとしたbotを作ったことがあったので、それで良いかなとも思ったのですが、botkitで設置するbotで実現しようとすると、チャンネル上にbotがinviteされている必要があり、面倒でした。slackのどこのチャンネルからでも勤怠打刻がしたい！という熱意に応えるには、[slackのスラッシュコマンド](https://get.slack.help/hc/ja/articles/201259356-%E7%B5%84%E3%81%BF%E8%BE%BC%E3%81%BF%E3%81%AE%E3%82%B9%E3%83%A9%E3%83%83%E3%82%B7%E3%83%A5%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89)を使うしかありません。
これを設置することで、 /ts と打ち込めば勤怠打刻ができる。そんな状態を作ります。
では、そのスラッシュコマンドを使うには何が必要かというと[slack app](https://api.slack.com/)です。botkitを使ってbotを設置するにはbotを生成すればよかったのですが、アプリはもう少しできることが拡張されています。
- スラッシュコマンド
- インタラクティブコンポーネント
- webhook
みたいなものが使えるようになります。

## 開発環境
参考にしたのはこちらです
[Slack のコマンドを使って TeamSpirit に打刻する](https://ja.ngs.io/2018/02/14/ts-dakoku/)
元はGoで書かれているのですが、著者はGoが分かりません。そのために
- node.js
- botkit:slack純正chatbotフレームワーク
- express:slackからのコマンドのやり取りをするためにWebサーバが必要になる
- mongodb:各種データの保存先
- heroku：上述のサービスを可動させるための基盤

という環境に移植しました。

## 細かい設定等はGithubへ
[geeorgey/ts-dakoku-node-express](https://github.com/geeorgey/ts-dakoku-node-express)
デプロイボタンから、herokuにデプロイすればすぐに使えると思います。
一つApexクラスを設置しているので、そちらのSalesforce本番環境へのデプロイも必要ですが、クラス・テストクラスも揃っているのでコピペで使えます。

## ハマったところ
このアプリの肝は、slackのOAuth情報とSalesforceのOAuth情報をmongodbに保持して使うという部分です。それぞれバラバラな情報は見かけるのですが、両者ともに実現するのに苦戦しました。
Salesforceに関しては恐らくセキュリティの都合上、セッションの持続時間が短めに設定されているはずです。slackから利用する場合にいちいちセッション貼り直すのは面倒なので、mongodbに入れたデータを元にして、再度アクセストークンを生成しています。[参照情報](https://developer.salesforce.com/docs/atlas.ja-jp.api_rest.meta/api_rest/intro_understanding_refresh_token_oauth.htm)
また、node.jsは非同期処理が成されます。しかし著者はそのような言語を使ったことがありませんでした。mongodbに問い合わせた結果を使って次の処理を行うには、Promiseというやり方が必要になるのです。理解するのに時間を要しました…

## なぜこれが必要だったのか
実はこんなことを書いているのですが
[共有・意識喚起のslackと、実行催促のsalesforce chatterという使い分け](https://geeorgey.com/archives/3560) 弊社リバネスでは、長らくSalesforce chatterを放置し続けてきたという事情もあり、chatterからのアクションが行動に繋がりませんでした。現状で実効性が一番高いのはslackからのアクションであろうということから開発されています。

## 今後の展開
基本的なやり方については把握が出来ました。スラッシュコマンドを使った処理も追加しやすいように設計されています。(server.jsにエンドポイントを追加し、modules/ にエンドポイントの処理を書き、modules/response.js にインタラクティブコンポーネントから入ってくる処理を書けば良い)
リバネスでは、データの蓄積はSalesforce上に成されています。適切なタイミングでトリガーを設置し、slackに通知するということはこれまでも出来たのですが、通知のあとの処理は結局Salesforceの画面を開いて行う必要があったのです。slackアプリ上から処理が実現できれば、Salesforce→slackへ通知→通知を受けた画面でインタラクティブコンポーネント(つまり、ボタンですね)を表示してボタンを押せば処理完了という流れが出来ます。
例えば、月末の請求処理を一例にすると
- リバネスでは、毎月25日及び末日のお昼12時にSalesforceアプリのジョブが走るようになっていて、slackに未請求商談及び担当者へのメンション付きメッセージが投下されます
- そのメッセージを見た担当者が、付帯情報を見た上で請求書の発行というインタラクティブコンポーネントボタンを押せば請求処理が完了する
- ここは実装中なので将来的な話になりますが、ボタンからのアクションがSalesforce側のApexへ@HTTPGetで渡り、請求処理を受け取ったSalesforce側で書類の発送・メール送信等が実行される
といったイメージです。
必要なアクションをSalesforce上のデータを起点として発行し、slackで該当者へ通知。該当者は通知を受けた画面でそのまま処理を実行できる。便利じゃないですか？
BotkitでSlackの書式付きメッセージに反応させる

## 環境

`"botkit": "^0.6.13",`

## Botkit-Slackの基本

Botkitで指定メッセージに反応させるには、`bot.hears`に反応させるワードを書いている。

```javascript
// 反応ワードの設定
bot.hears(['hello world'], 'ambient', (bot, message) => {
  console.log(message.text); // botが反応したらログ出力
});
```

これでbotを起動させて、Slackで「hello world」と発言すると、botがメッセージに反応して発言内容がログ出力されるはず。

## メッセージに書式付きがあると...
メッセージにSlackの書式を付けられてしまうと、botが反応しなくなるパターンがある。

たとえばこんな書式付きメッセージ
<img width="325" alt="スクリーンショット 2018-12-12 0.39.49.png" src="https://qiita-image-store.s3.amazonaws.com/0/52227/08f7c541-d46f-f925-7a5e-e1d918e7f621.png">
画像だと分かりにくいが、Slackからメッセージをコピペするとこんな書式になる。

`*hello* world`

helloがboldになっただけだが、botkitの`hears`は書式も含めて判定してしまうため、`bot.hears(['hello world']`では反応しなくなる。

じゃあ`bot.hears(['*hello* world']`とすると、正規表現エラーになりBotは動かない。
（当たり前だが）

## 解決方法
書式付きメッセージに反応するよう`hears`の正規表現で書式をエスケープさせるよう書く必要がある。

```javascript
// *hello* worldに反応させる
bot.hears(['\\*hello\\* world'], 'ambient', (bot, message) => {
  console.log(message.text); // botが反応したらログ出力
});
```

これでBotkitが`*hello* world`に反応するようになる。

`match`でメッセージをパラメータ化する場合は、こんな感じで書く。

```javascript
// *hello* no*1* に反応させる
bot.hears(['\\*hello\\* no\\*(.*)\\*'], 'ambient', (bot, message) => {
  console.log(`message.match[1]:${message.match[1]}`);
  console.log(message.text); // botが反応したらログ出力
});
```

## 備考
正規表現は以下のサイトでマッチするかテスト可能
https://regex101.com/

## 参考サイト
- https://github.com/howdyai/botkit/issues/1404
- [メッセージの書式設定](https://get.slack.help/hc/ja/articles/202288908-%E3%83%A1%E3%83%83%E3%82%BB%E3%83%BC%E3%82%B8%E3%81%AE%E6%9B%B8%E5%BC%8F%E8%A8%AD%E5%AE%9A)