OmniAICreator/Qiita-1.07M huggingface dataset:
Selenium Gridの環境を作ってみた

ラクス Advent Calender 2018の14日目です。
久しぶりにSeleniumGridを使って、Seleniumのテストコードを実行する環境周りを触る機会がありましたので、起動方法とかを書いていこうかと思います。

# SeleniumGridとは
* 複数のSeleniumの実行環境を管理し、並列にテストを実行できるツール
* 「Hub」と呼ばれるテストスクリプトを受け付けるサーバーと「Node」と呼ばれる実際にテストを実行する環境で構成されている

イメージとしては下記の通りです。
![キャプチャ1.png](https://qiita-image-store.s3.amazonaws.com/0/43709/8cd13278-aae2-78e1-4924-b99f6ae511b7.png)

# SeleniumGridの起動
## Selenium Grid(Hub)の起動
* 必要なソフトウェア
    * [Seleniumサイト](https://docs.seleniumhq.org/download/)から`selenium-server-standalone.jar` をインストール
    * JDKをインストール
* 起動方法
    * ```java -jar selenium-server-standalone.jar -role hub```

http://[Selenium Grid ServerのIPアドレス]:4444/grid/console にアクセスするとコンソール画面が表示されるようになる

![Grid_Console.png](https://qiita-image-store.s3.amazonaws.com/0/43709/2ea8f85e-d60d-450f-d42b-57167c9559ef.png)

## Selenium Grid(Node)の起動
* 必要なソフトウェア
    * `Hub`と同様に`selenium-server-standalone.jar`と`JDK`をインストール
    * テストで使用するブラウザ
    * 動かすブラウザの`WebDriver`をインストール(例としてGoogle Chromeは、[ここから](http://chromedriver.storage.googleapis.com/index.html))
* 起動方法
    * `java -Dwebdriver.chrome.driver=/path/to/chromedriver.exe -jar selenium-server-standalone.jar`

起動すると、Hubのコンソール画面に接続したNodeの情報が表示されるようになります。

![Grid_Console 2.png](https://qiita-image-store.s3.amazonaws.com/0/43709/6fd779f9-49c1-72cc-8b57-1c1085e2bb0f.png)

Nodeのマシンでテストコードを動かすためには、`RemoteWebDriver`を使う必要がありますが、そこは次回で。。

# まとめ
テストを実行する環境を別にすることで、環境依存で発生するエラーが起きにくいのと、テストする内容によってNodeマシンを追加・設定すれば良いだけなので管理も楽になると感じました。

次はテストを並行で実行できるようにSelenium Gridの設定周りを試してみようかと思います。
(Dockerとかを使ってNodeを増やして、テストにかかる時間を短縮とかも)
AVA + Puppeteer のサンプルレシピを元に ignoreHTTPSErrors を指定する

![ava/header\.png at master · avajs/ava · GitHub](https://github.com/avajs/ava/raw/master/media/header.png)

[GitHub \- avajs/ava: 🚀 Testing can be a drag\. AVA helps you get it done\.](https://github.com/avajs/ava)


なんかちょっとしたテストに[Puppeteer](https://pptr.dev/)使えるお手軽フレームワーク無いかなと思ってちょっとググってみたら[AVA](https://github.com/avajs)と言うのが良さそうだったのでさらにPuppeteerのレシピまであったのでちょっと使ってみた。

> Recipes
> 
> - [Testing web apps using Puppeteer](https://github.com/avajs/ava/blob/master/docs/recipes/puppeteer.md)





# helpers/withPage in recipe

なるほど話が早い

> The first step is setting up a helper to configure the environment:

```javascript:helpers/withPage.js
import puppeteer from 'puppeteer';

export default async function withPage(t, run) {
	const browser = await puppeteer.launch();
	const page = await browser.newPage();
	try {
		await run(t, page);
	} finally {
		await page.close();
		await browser.close();
	}
}
```

[ava/puppeteer\.md at master · avajs/ava · GitHub](https://github.com/avajs/ava/blob/master/docs/recipes/puppeteer.md)



# さっそくサーバー証明書に引っかかるの巻

ありがち、でも困る

```javascript:main.js
import test from 'ava';
import withPage from './helpers/withPage';

const url = `https://host/test`;

test('page title must be appear in "📓The Narrative"', withPage, async (t, page) => {
		await page.goto(url);
		t.is('🐥 VigilaNTe', await page.title());
	}
);
```

```shell
  ✖ page title must be appear in "📓 The Narrative" Rejected promise returned by test

  1 test failed

  page title must be appear in "📓 The Narrative"

  /path/to/node_modules/puppeteer/lib/FrameManager.js:107

  Rejected promise returned by test. Reason:

  Error {
    message: 'net::ERR_CERT_AUTHORITY_INVALID at https://host/test',
  }

  navigate (node_modules/puppeteer/lib/FrameManager.js:107:37)
  Frame.<anonymous> (node_modules/puppeteer/lib/helper.js:144:27)
  Page.goto (node_modules/puppeteer/lib/Page.js:624:49)
  Page.<anonymous> (node_modules/puppeteer/lib/helper.js:145:23)
  goto (test/main.js:7:16)
  Test.run (test/helpers/withPage.js:7:11)
```

# puppeteer.launch([options]) で対応

とりあえず[puppeteer\.launch](https://pptr.dev/#?product=Puppeteer&version=v1.11.0&show=api-puppeteerlaunchoptions)で対応してしまおう :sweat_smile: 



```javascript:helpers/withPage.js
import puppeteer from 'puppeteer';

export default async function withPage(t, run, puppeteer_launch_opts = {}) {
	const browser = await puppeteer.launch(puppeteer_launch_opts);
	const page = await browser.newPage();
	try {
		await run(t, page);
	} finally {
		await page.close();
		await browser.close();
	}
}
```

```javascript:main.js
import test from 'ava';
import withPage from './helpers/withPage';

const url = `https://host/test`;
const puppeteer_launch_opts =
{
	ignoreHTTPSErrors: true
};

test('page title must be appear in "📓The Narrative"', withPage, async (t, page) => {
		await page.goto(url);
		t.is('🐥 VigilaNTe', await page.title());
	}, puppeteer_launch_opts
);

```

```shell
  ✔ page title must be appear in "📓 The Narrative" (2.4s)

  1 test passed
```

以上 🐤:star2:
PHP備忘録ファイル操作について

```
<?php
 
$filename = './file_write.txt';
$comment = '';
 
print $_SERVER['REQUEST_METHOD'];
if ($_SERVER['REQUEST_METHOD'] === 'POST'){
 
    if (isset($_POST['comment']) === TRUE) {
        $comment = $_POST['comment'];
    }
 
    if (($fp = fopen($filename, 'r')) !== FALSE) {
        if (fwrite($fp, $comment) === FALSE) {
            print 'ファイル書き込み失敗:  ' . $filename;
        }
        fclose($fp);
    }
}
 
$data = array();
 
if (is_readable($filename) === TRUE) {
    if (($fp = fopen($filename, 'r')) !== FALSE) {
        while (($tmp = fgets($fp)) !== FALSE) {
            $data[] = htmlspecialchars($tmp, ENT_QUOTES, 'UTF-8');
        }
        fclose($fp);
    }
} else {
    $data[] = 'ファイルがありません';
}
 
?>
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>ファイル操作</title>
</head>
<body>
    <h1>ファイル操作</h1>
 
    <form method="post">
        <input type="text" name="comment">
        <input type="submit" name="submit" value="送信">
    </form>
 
    <p>以下に<?php print $filename; ?>の中身を表示</p>
<?php foreach ($data as $read) { ?>
    <p><?php print $read; ?></p>
<?php } ?>
</body>
</html>
```
###fopenのモード3種類
fopenとはこれからどういう処理をするのかという指示
・aモードappendの略ファイルポインタはつねにファイルの後ろから。
・wモードwriteの略ファイルポインタは常にファイルの先頭から。ファイル内容を削除してから書き込みます。ファイルが存在しない場合は作成します。
・rモードreadの略ファイルポインタは常にファイルの先頭から。ファイルが存在しない場合は作成します。

・$fpがファイルハンドル(id)の部分になる
```
if (($fp = fopen($filename, 'r')) !== FALSE) {
        if (fwrite($fp, $comment) === FALSE) {
            print 'ファイル書き込み失敗:  ' . $filename;
        }
```
fwriteで$fpに書き込んだものをさらに書き込む
fwriteで書き込みするときはaもしくはwの書き込みをしないとダメ

パーミッションはftpで使われてるもの
r→read
w→書き込み
x→実行
プロダクト横断のSREチームを組成したい話

こんにちは、 @mshibuya です。
[広告代理店オプト](https://www.opt.ne.jp/)で[広告効果計測ツール「ADPLAN」](https://www.adplan7.com/)のSREチームリーダーをやってます。

これまでプロダクト内に閉じたSREチームとして活動してきたのですが、今後の展開としてSREとしての活動を複数のプロダクトチームを横断する取り組みに変えていきたいという構想があり、その話をしたいと思います。

なおこの記事は[SRE Advent Calendar 2018](https://qiita.com/advent-calendar/2018/sre)14日目のエントリです。

# これまでのあらすじ

ADPLANというプロダクトにおいて、信頼性や緊急対応への課題感からプロダクト内のいちチームとして3人からなるSREチームを立ち上げて約１年、多くの運用改善をして喫緊の課題も少なくなってだいぶ落ち着いてきたかなー…くらいな現状です。

[SRE Lounge #5にて登壇した際の資料](https://qiita.com/mshibuya/items/5570ac551dbddbcb94b1)にSREチーム立ち上げの経緯がまとまっているので、あわせてどうぞ。

# モチベーション

現状プロダクト内SREチームとして業務に当たる中で、こんな課題感があります。

- オンコール(緊急対応)当番のローテーションがタイト
    - 現状3人のSREチームで一週間交代で当番を回しているのですが、わりと頻繁に回ってくるのであまり気が抜けないという声があります
- とはいえ実際に対応が必要となるような緊急事態は滅多に起きない
    - これはSREとしては実際に緊急対応の経験を積む機会が得られず、十分スキルを高められないことに繋がってしまいます
- 良いプラクティスや学ぶべき教訓がプロダクトチームを超えて生かされない
    - 現状では社内他プロダクトにおいてSRE的プラクティスを実践しているチームがないことも関係しています
- プロダクトチームごとに独立して緊急対応へ備えるのはリソースを浪費する
    - 「有事に対して備えなければいけない」というのは当然精神的リソースを消費するので、負担を一箇所にまとめられればだいぶ楽になりそうです
- プロダクトによっては2-3人規模のチームもあり、「専業のSREを置く」という動きも取りづらい
    - 「SRE的業務に人を部分アサインする」でうまくいくイメージも持てないので、「専業のSREが（他プロダクトを見つつ）部分的にそのプロダクトも見る」が解になるかなと…


# 構想内容

表題の通り、プロダクト横断でのSREチーム体制に変えようとしています。

- プロダクト内チームとしての「SRE専業チーム」を作るのではなく、プロダクト開発チームの一員としてSREメンバーが所属する形式に
    - 同じチーム内で日々一緒に業務することで、新規の機能開発などがもたらす信頼性に対するリスクを早期にキャッチし、適切に手を打てるようにする
    - 万一信頼性に大きな懸念が生じたような時に、開発チームメンバーが信頼性向上タスクに取り組むといったリソースの融通が可能に
- 加えて別のプロダクトにおいてもSREを立て、プロダクトチームとは別枠の横のつながりとして「組織横断SREチーム」を組成する
    - SREのマトリックス的な配置については[ヌーラボさんの取り組み](https://speakerdeck.com/nulabinc/sre-lounge-number-5?slide=31)を参考にしています
- モニタリングやアラート、オンコール対応といったSRE的分野についてベストプラクティスを確立し、プロダクトチームを超えて活かしたい！
    - わりと切実です。プロダクトが立ち上がるたびに運用体制をカスタムメイドするのもコストが掛かりすぎるので、型にはめたいですよね


# 乗り越えるべき壁

とはいえ、

- プロダクトによって技術スタックがまちまち
    - SREの本家Googleのように全社的に統一された運用基盤があるわけでもないので、一人のSREが知るべき内容はすごく多岐に渡ってしまいそう
- バックログをどう管理していくか
    - これまではSREチームとしてのバックログを持ちその中でタスクの優先度をつけていました。プロダクトとしてのバックログにSRE的タスクを積むことになるとして、ビジネス上求められる開発と信頼性向上のバランスをどう取っていけるかなと。。
- SREメンバーの評価はどうしよう…？
    - これまでは評価上のライン＝SREチームでしたが、今後はプロダクトチームが評価ラインになるのでそこにSREとしての成果をどうやって反映させるのがよいか

あたりが課題で、解決していく必要がありますね。

# まとめ

こう考えていくと、SREというプラクティスが対象にしているのは結局システムだけではなくて、人や組織・プロセスも視野に入れたエンジニアリング活動なんだなーという思いを新たにしています。

この取り組みは運用体制の構築事例としてきっと組織を超えて参考にしていただける内容になると思っているので、その後についてまたご報告できればと思っております。

最後までお読みくださりありがとうございました！
【もげぞうβ】atcoder beginner contest002をやる

# PeerCast プログラミング配信 Advent Calendar 2018 12/13

はい、もげぞうβです。
atcoder beginner contest002をやりました。

- A問題  


```cl
(defun abc002a ()
  (let ((x (read))
	    (y (read)))
    (if (>= x y)
	    (format t "~d~%" x)
	    (format t "~d~%" y))))
```

- B問題  

```cl
(defun abc002b ()
  (let ((w (read-line)))
    (loop for i across "aiueo"
	      do (setf w (remove i w))
    (format t "~a~%" w)))
```

- C問題  

```cl
(defun abc002c ()
  (let ((a (read)) (b (read)) (c (read))
	    (d (read)) (e (read)) (f (read)))
    (format t "~d~%" (/ (abs (- (* (- c a) (- f b)) (* (- e a) (- d b)))) 2.0))))
```

- D問題  
時間切れ
GCP の Cloud Shell(Beta) で Terraform が遊べる

#GCP の Cloud Shell(Beta) で Terraform が遊べる

HashiCorp のブログを見てたら、こんなのがありました。
[Kickstart Terraform on GCP with Google Cloud Shell](https://www.hashicorp.com/blog/kickstart-terraform-on-gcp-with-google-cloud-shell)

![Kickstart Terraform on GCP with Google Cloud Shell.png](https://qiita-image-store.s3.amazonaws.com/0/318450/a27f7f56-a352-79fe-4361-e950911663ba.png)

なんだか、Google Cloud Shell で Terraform が遊べる（？）ようになったとか書いてありますね（おおざっぱ）

## Google Cloud Shell を起動してみる

下の方に「OPEN IN GOOGLE CLOUD SHELL」という青いボタンがあるので、ポチっと押します。

![gcp_cloud_shell_001.png](https://qiita-image-store.s3.amazonaws.com/0/318450/8c2012c0-9ffe-8c9e-6d57-0826bdb89d44.png)

とりあえず、「続行」をクリックします。

![gcp_cloud_shell_002.png](https://qiita-image-store.s3.amazonaws.com/0/318450/4fff1fa1-0d59-0304-0566-5dfd44baee44.png)

Google Cloud Shell が立ち上がりました。

## プロジェクトの選択

既存のプロジェクトがあれば選択し、なければ作成します。

![gcp_cloud_shell_003.png](https://qiita-image-store.s3.amazonaws.com/0/318450/ba2d442b-d853-f456-3eb1-36ebf76f3bd0.png)

プロジェクトの確認画面がでるので、よければ、「プロジェクトの確認」をクリックします。

## チュートリアルをやってみよう

ここからは、Terraform のチュートリアルになります。

### サーバ起動

![gcp_cloud_shell_004.png](https://qiita-image-store.s3.amazonaws.com/0/318450/6d6c2a31-2d39-aba5-e896-9da55b0432b4.png)

赤丸の部分をクリックして、エンターを押していきます。

そうすると、アメリカにサーバが 1台立ち上がります（f1-micro）

まぁ、画面上に「main.tf」って書かれてる部分が tfファイルの内容になっていて、サーバのコンフィグが書かれていますので、その通りに立ち上がるだけです。

### サーバ変更

サーバが起動したら、「次へ」をクリックします。

![gcp_cloud_shell_005.png](https://qiita-image-store.s3.amazonaws.com/0/318450/9782bf12-8631-3fee-113a-660832a93cc7.png)

1.1個目の赤丸を押してエンターすると、何もしないでプランが実行されます。特に変更ないみたいな感じで出ると思います。

2.「main.tf」の「f1-micro」を「g1-small」に変えてから、2個目の赤丸をクリックエンターです（チュートリアル通りなのですが、課金発生するので注意！）

```
machine_type: "f1-micro" => "g1-small"
```

3.3つ目の赤丸をクリックしてエンターすると、変更がアプライされます。

4.アプライ内容を確認して、4つ目の赤丸を押しエンターすると、サーバが変更されます。

落としてから変更して、上げなおすので少し時間かかりますね。

終わったら、「次へ」をポチっとなします。

### サーバ破壊

最後はきれいにして終わりですね。

![gcp_cloud_shell_006.png](https://qiita-image-store.s3.amazonaws.com/0/318450/b2323901-416e-ec7e-8df1-5de444d440f2.png)

２つの赤丸をクリックして、エンターします。

これで、サーバがきれいさっぱりいなくなります。

## まとめ

Google Cloud Shell を使って、Terraform のチュートリアル的なものがあるのは面白いですね。専用のサーバを用意しなくても、Cloud Shell で Terraform を動かせるというのもいいところです。
Cloud Shell はインスタンスが立ち上がって動いてるらしいのですが、一応無料となっています。ベータ版の間だけかもしれませんが・・・
チュートリアル中にナチュラルに課金させるとか、ちょっとひどい部分もありますが、ちょっとやってみたいという時にいいかもしれませんね。
raspberry pi 1でtensorflow lite その9

#概要

raspberry pi 1でtensorflow liteやってみた。
tfliteファイルを作ってみた。
kerasモデルから作ってみた。
データセットは、fizzbuzz.

#環境

tensorflow 1.12


#kerasモデルを学習してセーブする。


```
import numpy as np
from tensorflow.contrib.keras.api.keras.models import Sequential
from tensorflow.contrib.keras.api.keras.layers import Dense, Activation
from tensorflow.contrib.keras.api.keras.models import Model

def binary_encode(i, num_digits):
    return np.array([i >> d & 1 for d in range(num_digits)])

def fizz_buzz_encode(i):
    if i % 15 == 0:
        return np.array([0, 0, 0, 1])
    elif i % 5  == 0:
        return np.array([0, 0, 1, 0])
    elif i % 3  == 0:
        return np.array([0, 1, 0, 0])
    else:
        return np.array([1, 0, 0, 0])

def fizz_buzz(i, prediction):
    return [str(i), "fizz", "buzz", "fizzbuzz"][prediction]

NUM_DIGITS = 7
trX = np.array([binary_encode(i, NUM_DIGITS) for i in range(1, 101)])
trY = np.array([fizz_buzz_encode(i) for i in range(1, 101)])
model = Sequential()
model.add(Dense(64, input_dim = 7))
model.add(Activation('tanh'))
model.add(Dense(4, input_dim = 64))
model.add(Activation('softmax'))
model.compile(loss = 'categorical_crossentropy', optimizer = 'adam', metrics = ['accuracy'])
model.fit(trX, trY, epochs = 3600, batch_size = 64)
model.save('fizzbuzz5.h5')
print ("save model")

```

#kerasファイルからtfliteファイルを作る。


```
import tensorflow as tf
import tensorflow.contrib.lite as lite

converter = lite.TFLiteConverter.from_keras_model_file("fizzbuzz5.h5")
tflite_model = converter.convert()
open("fizzbuzz.tflite", "wb").write(tflite_model)
print ("ok")

```

#tfliteファイルを検証する。


```
import numpy as np
import tensorflow as tf
import tensorflow.contrib.lite as lite

def binary_encode(i, num_digits):
    return np.array([i >> d & 1 for d in range(num_digits)])

def fizz_buzz_encode(i):
    if i % 15 == 0:
        return np.array([0, 0, 0, 1])
    elif i % 5  == 0:
        return np.array([0, 0, 1, 0])
    elif i % 3  == 0:
        return np.array([0, 1, 0, 0])
    else:
        return np.array([1, 0, 0, 0])

def fizz_buzz(i, prediction):
    return [str(i), "fizz", "buzz", "fizzbuzz"][prediction]

NUM_DIGITS = 7
trX = np.array([binary_encode(i, NUM_DIGITS) for i in range(1, 101)])
interpreter = lite.Interpreter(model_path = "fizzbuzz.tflite")
interpreter.allocate_tensors()
input_details = interpreter.get_input_details()
output_details = interpreter.get_output_details()
#print (input_details)
#print (output_details)
for i in range(1, 100):
  input_data = np.array([trX[i - 1]], dtype = np.float32)
  interpreter.set_tensor(input_details[0]['index'], input_data)
  interpreter.invoke()
  output_data = interpreter.get_tensor(output_details[0]['index'])
  print (fizz_buzz(i, np.argmax(output_data[0])))

```

以上。
コンソールで処理中にグルグルするやつをFirebase CLIから借用する

Firebase hostingに CLIからデプロイするときにコンソールでグルグルするやつ（スピナー？）がかっこいいから使わせてもらおうと思いました。

## 完成品

こんなのができます。

![dots.gif](https://qiita-image-store.s3.amazonaws.com/0/211332/b54cbc55-af8b-0d85-aebe-9e22097e745c.gif)

## 環境構築

Firebase CLI のjsソースをそのまんまぱくって、node上で動かしてみることにします。

[cli-color](https://www.npmjs.com/package/cli-color)というパッケージを使うので、npm installしておきます。

あとは適当に index.js みたいな、エントリポイントとなるファイルを作っておきます。

## Firebase CLIのソースを探る

[firebase-tools](https://github.com/firebase/firebase-tools)のソースを探していくと、[deploy/hosting/deploy.js](https://github.com/firebase/firebase-tools/blob/master/src/deploy/hosting/deploy.js) にお目当ての処理を見つけました。

ほんとうに必要なところだけを抜き出すと以下のような感じです。

```js
var clc = require("cli-color");

var SPINNER = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];

var spins = 0;
function _updateSpinner(newMessage) {
    process.stdout.write(clc.erase.line + clc.move.left(9999));
    process.stdout.write(clc.bold.cyan(SPINNER[spins % SPINNER.length] + "  ") + newMessage);
    spins++;
}
```

これを適当なメッセージで呼び出す

```js
setInterval(() => {
    _updateSpinner("ローディング中です");
}, 200);
```

まわる

![dots.gif](https://qiita-image-store.s3.amazonaws.com/0/211332/b54cbc55-af8b-0d85-aebe-9e22097e745c.gif)

## cli-spinners

firebase-toolsのパッケージ依存をたどっていくと、直接は使ってなさそうですが、 [cli-spinners](https://www.npmjs.com/package/cli-spinners)という魅力的な名前のパッケージを見つけました。

何かと思ったら、実体は `spinners.json` というJSONファイルだけっぽい。

しかしこのJSONファイル、見るだけで胸がトキメキます。

一部だけ抜粋

```json
{
	"dots": {
		"interval": 80,
		"frames": [
			"⠋",
			"⠙",
			"⠹",
			"⠸",
			"⠼",
			"⠴",
			"⠦",
			"⠧",
			"⠇",
			"⠏"
		]
	},
	"circle": {
		"interval": 100,
		"frames": [
			"◜",
			"◠",
			"◝",
			"◞",
			"◡",
			"◟"
		]
	},
	"bouncing": {
		"interval": 80,
		"frames": [
			"[    ]",
			"[   =]",
			"[  ==]",
			"[ ===]",
			"[====]",
			"[=== ]",
			"[==  ]",
			"[=   ]"
		]
	},
	"monkey": {
		"interval": 300,
		"frames": [
			"🙈 ",
			"🙈 ",
			"🙉 ",
			"🙊 "
		]
	},
	"clock": {
		"interval": 100,
		"frames": [
			"🕐 ",
			"🕑 ",
			"🕒 ",
			"🕓 ",
			"🕔 ",
			"🕕 ",
			"🕖 ",
			"🕗 ",
			"🕘 ",
			"🕙 ",
			"🕚 "
		]
	}
}
```

さきほどのをちょっといじって

```js
var clc = require("cli-color");
var spinners = require('cli-spinners');

var spins = 0;
function _updateSpinner(frames, newMessage) {
    process.stdout.write(clc.erase.line + clc.move.left(9999));
    process.stdout.write((frames[spins % frames.length] + "  ") + newMessage);
    spins++;
}

var spinner = spinners.monkey;

setInterval(() => {
    _updateSpinner(spinner.frames, "ローディング中です");
}, spinner.interval);
```

実演

![monkey.gif](https://qiita-image-store.s3.amazonaws.com/0/211332/d4cd667b-9a37-bfa7-afe0-77888f2dbebf.gif)

いいですね。

## あとがき

※ この記事は個人の見解であり、所属する組織を代表するものではありません。
USBテザリングって便利だね

# はじめに
皆さまお久し振りです！
[情報通信システム工学科アドベントカレンダー](https://qiita.com/advent-calendar/2018/ics2018)2回目の登場となりました、ほの(@hnk1031 )です。
前回は[女子大生っぽい記事](https://qiita.com/hnk1031/items/e791f31ffaaee8cf6ea7)を書いたわけですが、今回は最近ためになった「USBテザリング」について共有しようと思います:relaxed:

#テザリング使ってますか？
私は普段からMacbookを持ち歩いているのですが、最近は外でもFree WiFiが普及していたりして、どこでもネットに繋げる時代になりました。
しかし、ネットの接続環境が無くてもネットに繋ぎたいときってありますよね！？
そのような場合にはスマートフォンでテザリングするのが便利なんです:star2:

# テザリングとは
テザリングとは、**インターネットに接続しているスマートフォンを、モデム・Wi-Fiルーターのようなモデムとして利用し、パソコンやタブレットなどの外部機器をスマートフォン経由でインターネットに接続する通信方法**のことです。
一般的には、
・WiFiテザリング
・USBテザリング
・Bluetoothテザリング
があります。

Wifiテザリングには、対応機種の多さや複数台接続が可能といったメリットがある一方、**スマートフォンのバッテリー消費が早い**というデメリットがあります:sweat:

USBテザリングには、**通信速度はテザリングの中で最も速く、スマートフォンの充電が同時にできる**というメリットがあります！
ただし、物理的にケーブル接続するのが面倒だと感じる人もいるかもしれませんね:sweat_drops:

Bluetoothテザリングには、複数台接続が可能でスマートフォンのバッテリー消費が少ないというメリットがありますが、**通信速度が遅く、接続できる範囲が狭い**というデメリットがあります。

私は今までWiFiテザリングを使っていたのですが、スマホのバッテリー消耗が早いことが不便だと感じたので、今回は**USBテザリング**を使ってみることにしました！

# USBテザリング実践〜！
さて、ここで使用機器を紹介します。
ノートパソコン：MacbookPro (バージョン 10.14.1)
スマートフォン：HUAWEI P10 lite (Android 8.0.0)
USBケーブル：ダイソーで買ったやつ

スマートフォンのUSBテザリングをONにしてみます！
![48362576_2723873104504968_2977273348221829120_n.jpg](https://qiita-image-store.s3.amazonaws.com/0/317882/10ade6ef-1d18-4331-2b32-55f674a479b6.jpeg)
これで接続できるかと思ったのですが、Macbook側を確認すると認識されません。。
ここで[こんな記事](http://japan.tokyork.net/gadget/android/mac-android-tethering/)を見つけました↓
> MacでAndroidスマートフォンのUSBテザリングを利用するためには、事前に、Android端末とのテザリングを可能にするドライバをインストールしておく必要がある。

これは初耳です…
USBに繋げば接続できちゃうと思っていた自分が甘かったですね:innocent:
こうなったらドライバのインストールをしましょう。
[★インストールはこちら★](https://joshuawise.com/horndis)
一番上の最新版を選びます。
<img width="894" alt="スクリーンショット 2018-12-14 20.31.49.png" src="https://qiita-image-store.s3.amazonaws.com/0/317882/2790b564-3a4f-2a14-c87a-f3383633185f.png">
インストールが完了したので、もう一度USBテザリングに挑みます！
<img width="780" alt="スクリーンショット 2018-12-14 20.37.14.png" src="https://qiita-image-store.s3.amazonaws.com/0/317882/9075a50d-3a55-e43c-4e1b-76c1db1f2555.png">
一番上に表示されているのがUSBテザリングです！
ちゃんと接続済みになりました〜！！

# 終わりに
インストールしたドライバがどのような仕組みで作られているのか不透明なところではありますが、これでUSBテザリングができるようになりました！
AndroidスマートフォンにMacOSのテザリングをしようと考えている人は是非参考にしてくださいね:hugging:
dockerで ERROR: readlink /var/lib/docker/overlay2/l: invalid argument と表示された時の対処法

# 症状
いつものように `docker-compose up -d` としたところ下記のエラーが表示されてdockerが使えない。

`docker ERROR: readlink /var/lib/docker/overlay2/l: invalid argument`

# 対応
イメージファイルを削除するとOKっぽい。取りあえず下記のコマンドでローカルファイルの削除を試みる。

`docker-compose down --rmi local`

まだ調子悪かったので下記のコマンドでイメージファイルを全て削除

`docker-compose down --rmi all`

その後 `docker-compose up -d` で無事利用できるようになりました。

以上、ご参考まで。
Ubuntu でSSHホスト鍵を作り直す

# 概要
- 仮想マシンのコピーやテンプレートからのデプロイを行った時など、SSHホスト鍵を作り直したい時がある。

## 環境
- Ubuntu 16.04.5 LTS

# 手順
- まず消す

```shell-session:~/
# rm /etc/ssh/ssh_host_*key*
```

- dpkg-reconfigureを使うと楽に作れる。
    - デフォルトで生成されるのはRSA,DSA,ECDSA,ED25519の4種。

```shell-session:~/
# dpkg-reconfigure openssh-server
```

- 終わり。
backgroundでの状態(変数)を変更しcontent_scriptsでも使うChrome WebExtensionコード例

# 結論

両方で`chrome.storage.local`を使い、つど値を確認する。

`chrome.storage.local`はコールバックで動く。
プロミス化したければ
[chrome.storageを同期的に扱う(ES7 async/await) - Qiita](https://qiita.com/kururua/items/06c9eab514221da4111b)
のコードが参考になる。(試してませんがさすがにもうフラグは必要ないですよね)

# 動作検証環境

* Chrome 69

# 概要

アドオンのアイコンクリックやオプション画面の操作により、それぞれのページで動作するスクリプトの動作を変更したかった。

ただし、メッセージパッシング方式は複雑になる予感があったため、採用したくなかった。

なのでextensionのストレージ機能を使い、双方がこれを参照・書き換える方式にしてみた。

コード例はアイコンクリックで機能自体のオン・オフ(bool)が切り替わるとともに、各ページで実行されるcontent_scriptsでもその変更が観測できるような小さいサンプルである。


# 使用API

[chrome.storage - Google Chrome](https://developer.chrome.com/extensions/storage)

# 参考

[javascript - Remember state chrome extension - Stack Overflow](https://stackoverflow.com/questions/23339944/remember-state-chrome-extension)


# コード

```background.js

/**
 * 初回実行時の状態格納
 */
chrome.storage.local.get(['isRun'], (result) => {
  console.log('bg result', result)
  if (!result.hasOwnProperty('isRun')) {
    chrome.storage.local.set({'isRun': true })
  }
  changeIcon(result.isRun || true)
})

/**
 * アイコンをクリックで状態を反転
 */
browser.browserAction.onClicked.addListener(tab => {
  chrome.storage.local.get(['isRun'], (result) => {
    chrome.storage.local.set({'isRun': !result.isRun })
  })
})

/**
 * 現在の状態がわかるように、値が変わったらアイコンのオン・オフを切り替える
 */
chrome.storage.onChanged.addListener((changes, namespace) => {
  console.log('changes', changes)
  for (key in changes) {
    if (key == 'isRun') {
      changeIcon(changes['isRun'].newValue)
    }
  }
})

/**
 * アイコンの切り替え 
 */
function changeIcon(isRun) {
  if (isRun) {
    browser.browserAction.setTitle({title: 'Click Capture : ON'})
    browser.browserAction.setIcon({path: 'icon/switch.svg'})
  } else {
    browser.browserAction.setTitle({title: 'Click Capture : OFF'})
    browser.browserAction.setIcon({path: 'icon/switch-off.svg'})
  } 
}

// chromeのための初期化
browser.browserAction.setIcon({path: 'icon/switch.svg'})
```

```content_scripts.js
console.log('content start')
chrome.storage.local.get(['isRun'], (result) => {
    console.log('result', result)
})
console.log('content end')
```

# サンプル動画

![change.gif](https://qiita-image-store.s3.amazonaws.com/0/62354/540a37bf-31df-bb7e-90a6-a20a97bf2881.gif)
お知らせ: KaTeXにmhchemがやってくる

さて、2018年11月25日 8:52 JSTに新たにKaTeXにmergeされたpluginがある。mhchemだ。

https://github.com/KaTeX/KaTeX/pull/1436

mhchemというのは

`$\ce{CO2 + C -> 2 CO}$`

のように書くと

$\mathrm{CO}_{2} + \mathrm{C} \rightarrow 2\mathrm{CO}$

のように変換してくれる、化学徒の強い味方である。

`$\mathrm{CO}_{2} + \mathrm{C} \rightarrow 2\mathrm{CO}$`

と比べれば書きやすさは一目瞭然である(Qiitaでmhchemが使えないので頑張って再現した)

`\ce`と`\pu`が追加される。マニュアルは

https://mhchem.github.io/MathJax-mhchem/

にある。もっといろいろできることがわかる。

もともとMathJax向けに実装されていたのをKaTeX

現在KaTeXは`0.10.0`が最新だが、これには含まれていない(`0.10.0`が出たのが2018年10月29日 13:23 JSTだからそれはそう)。次のReleaseまで待てない人は

https://github.com/KaTeX/KaTeX/blob/master/contrib/mhchem/mhchem.js

を各自サーバーに置いて試すと良い(伝統と信頼のcdn.jsdelivr.netsさんから持ってこれないか画策したがうまくいかない)。

## 追記

そういえばKaTeX`0.10.1`で取り込まれましたので

```html
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.10.2/dist/contrib/mhchem.min.js" integrity="sha384-oa0lfxCGjaU1LdYckhq8LZcP+JTf8cyJXe69O6VE6UrShzWveT6KiCElJrck/stm" crossorigin="anonymous"></script>
```

を追記すればいいと思います。

# License

[CC BY 4.0](https://creativecommons.org/licenses/by/4.0/deed.ja)

<a href="https://commons.wikimedia.org/wiki/File:CC-BY_icon.svg#/media/File:CC-BY_icon.svg"><img src="https://upload.wikimedia.org/wikipedia/commons/thumb/1/16/CC-BY_icon.svg/1200px-CC-BY_icon.svg.png" alt="CC-BY icon.svg" width="88px"></a>
ROS(×FPGA)のネットワークを構築するためにLANケーブルを直繋ぎする

（この記事は「[ROSアドベントカレンダー Advent Calendar 2018](https://qiita.com/advent-calendar/2018/ros)」の14日目です）

# ルータなしでネットワークを構築
Wi-Fi機能はあるけど、PCと繋げるのにいちいち無線ルータを持っていくのは面倒くさい、Wi-Fiだと遅延が酷くてよくわからない、そもそもWi-Fi機能がないボードを使っている、といったことはないでしょうか。

私はZyboZ7-7020ボードを用いて、FPGA×ROSロボット開発を行なっていたのですが、Wi-Fiのデバイスドライバの導入がうまくいかず、LANポートを用いてPCとネットワークを構築していました。

あらかじめ設定しておけば、FPGAボードのLANポートとPCのLANポートを直接繋ぐだけで、

*  FPGA上でからPublishされている各トピックのデータをPCでSubscribeしてデバッグ
*  PCからFPGA上のUbuntuにsshでログインできる

と何かと便利でした。

LANポートの種類によっては、ストレートLANケーブル（普通のLANケーブル）でもできるみたいなので、クロスLANケーブルをお持ちでない方は、まずストレートケーブルでお試しください。

# ipアドレスの固定
### ボード
`sudo nano  /etc/network/interfaces`
を開いて

```text:/etc/network/interfaces
auto eth0
iface eth0 inet dhcp
```
の**dhcpをstaticに変更**します。

さらに

```text:/etc/network/interfaces
auto eth0
iface eth0 inet static
address 192.168.2.101
netmask 255.255.255.0
gateway 192.168.2.1
dns-nameservers 192.168.2.1
```

と追記してください。
`sudo /etc/init.d/networking restart`
でネットワークが再起動するので、
`ifconfig`
でaddressが192.168.2.101になっていることを確認できればOKです。

###PC
まず、`ifconfig`でLANポートの名前を確認します。eth0以外だったら（enp0s25等）以下のeth0はそれに置き換えてください。

ここからは先ほどと同様に、
`sudo nano  /etc/network/interfaces`
を開いて

```text:/etc/network/interfaces
auto eth0
iface eth0 inet dhcp
```
のdhcpをstaticに変更します。

さらに、

```text:/etc/network/interfaces
auto eth0
iface eth0 inet static
address 192.168.2.100
netmask 255.255.255.0
gateway 192.168.2.1
dns-nameservers 192.168.2.1
```

と追記してください。
`sudo /etc/init.d/networking restart`
でネットワークが再起動するので、
`ifconfig`
でaddressが192.168.2.100になっていることを確認できればこちらもOKです。

# ROSの設定
以下はボード側をマスターにする場合です。
(PC側をマスターにする場合は`ROS_MASTER_URI=http://192.168.2.100:11311`としてください)
###ボード
`nano ~/.bashrc`
を開き
以下のようにROS_MASTER_URIとROS_HOSTNAMEを書き換えます

```text:~/.bashrc
export ROS_MASTER_URI=http://192.168.2.101:11311
export ROS_HOSTNAME=192.168.2.101
```
`source ~/.bashrc`
でbashを読み込んで設定完了です。
###PC
`nano ~/.bashrc`
を開き
以下のようにROS_MASTER_URIとROS_HOSTNAMEを書き換えます

```text:~/.bashrc
export ROS_MASTER_URI=http://192.168.2.101:11311
export ROS_HOSTNAME=192.168.2.100
```
`source ~/.bashrc`

#接続
PCとボードを(クロス)LANケーブルで繋ぎます。
###PCからボードにssh接続する場合
PC側で
`ssh {ボードのユーザー名}@192.168.2.101`
###ROSの利用
MASTERに設定している方で`roscore`
あとはネットワークが構築されているので通常通りに使えます。

#Zyboで使っていた時に起きた不具合
##### ボードはカーネルによっては起動時のネットワークが安定しないことがあります。
起動時にネットワークが192.168.2.101にならない場合があるので、その場合はシリアル通信でボードにログインし、`sudo /etc/init.d/network restart`をしなければなりません。不便ですね...

##### 外部からネットワークアクセスがあると、そちらからのブート待機状態となるため、起動が遅くなる場合があります。
この場合は、シリアル通信でボードにログインし、Ctrl+Cなどでブート待機を強制スキップすることができます。もしくは、LANケーブルを抜いておくことによって回避できます。

######  ネットワークの利用には電力を消費するため、ボードが急に落ちることがあります。
電力が足りずに落ちてしまう場合、電力供給を見直す必要があります。

# 参考サイト
[Ubuntuのパソコン同士で通信する方法 - ノートにメモ書き](http://lablabkun.hatenablog.com/entry/2017/12/22/143913)
環境構築が無事終わったと思ったら、再び動かなくなった件

# はじめに
ちょっと前に環境構築で躓いた話を書いたのですが…
https://qiita.com/teco-tomari/items/2ff71a596925dc437140

あれから一週間経って再びvagrantがエラーを吐き始めました。
何とか復活はしたのですが、原因の特定にまでは至ってないので、対応方法のメモとして記述しておきます。

# 何が起こった？
- バグ修正しようと思い、意気揚々と vagrant upを実行
- 延々と起こる Warning: Remote connection disconnect. Retrying...に恐怖を覚える
- ようやく起動したと思い localにアクセスすると「このサイトにアクセスできません 接続が拒否されました。」

ハァン？なんでさ。
# 調査開始
## vs Nginx
とりあえずエラーを確認するぞと Nginxのエラーログを tail -fしてみる。

```
$ sudo tail -f /var/log/nginx/hoge.homestead.test-error.log
// 画面をリロードする
// 画面をリロードする
// 画面をリロードする
```
……何も表示されない……(´・ω・｀)
Nginx自体がおかしいんじゃないかと思いstatusを確認。

```
$ systemctl status nginx
● nginx.service - A high performance web server and a reverse proxy server
   Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled)
   Active: inactive (dead) since Wed 2018-12-12 11:53:21 JST; 10min ago
```
動いてないやんけ……(´・ω・｀)
という訳で Nginxを起動する。

```
$ sudo systemctl start nginx
$ systemctl status nginx
● nginx.service - A high performance web server and a reverse proxy server
   Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled)
   Active: active (running) since Wed 2018-12-12 12:06:12 JST; 44s ago
```
Nginxの起動も出来たし、もう一度画面をリロードしてみる。

**＼\ 502 Bad Gateway /／**
(；￣Д￣）ﾊﾞｯﾄｫ... ｹﾞｰﾄｳｪｨ...

## vs Bad Gateway
もう一度めげずにエラーを確認する。

```
$ sudo tail -f /var/log/nginx/hoge.homestead.test-error.log
2018/12/12 11:35:05 [crit] 5916#5916: *5 connect() to unix:/var/run/php/php7.2-fpm.sock failed (2: No such file or directory) while connecting to upstream, client: 192.168.10.1, server: hoge.homestead.test, request: "GET / HTTP/1.1", upstream: "fastcgi://unix:/var/run/php/php7.2-fpm.sock:", host: "hoge.homestead.test"
```
何かphp7.2でエラーが発生しているような事が書いてあるので今度は phpの状態を確認。

```
$ systemctl status php7.2-fpm.service
● php7.2-fpm.service - The PHP 7.2 FastCGI Process Manager
   Loaded: loaded (/lib/systemd/system/php7.2-fpm.service; enabled; vendor preset: enabled)
   Active: failed (Result: timeout) since Wed 2018-12-12 11:04:04 JST; 35min ago
```
こっちも何やらタイムアウトで起動に失敗してらっしゃる…
という訳でphp7.2も起動する。

```
$ sudo systemctl start php7.2-fpm.service
$ systemctl status php7.2-fpm.service 
● php7.2-fpm.service - The PHP 7.2 FastCGI Process Manager
   Loaded: loaded (/lib/systemd/system/php7.2-fpm.service; enabled; vendor preset: enabled)
   Active: active (running) since Wed 2018-12-12 11:40:15 JST; 6s ago
```
php7.2の起動が完了したので、もう一度画面をリロードしてみる。

## ローカル環境復活！
無事に画面が表示されました。

# 原因は不明
何故に vagrant up時に失敗したかは不明。
原因は調査中デス……
ansibleでimpdpの結果を頑張って取る

# 前提

どうしてもansibleでOracleDBにimpdpをしなくてはいけなくなった
ご存知の通りansibleにはOracleのモジュールが圧倒的に少ないため、泣く泣くwin_shellでimpdpコマンドを直接実行することになった

# 問題

なぜか結果が全く帰ってこない。
impdp自体は3分ぐらいで終わるのだが、winrmのタイムアウトをいくら設定しなおしても結果が帰ってこない
失敗にもならない

# どうしたか

しょうがないのでimpdpのログをtailすることに

```yml
  - name: execute impdp itself
    win_shell: "impdp system/manager directory={{ DIRECTORY_NAME }} dumpfile=dmp.dmp table_exists_action=append logfile=dmp.log"
    async: 20
    poll: 0

  - name: watch impdp log until it is over
    win_shell: "Get-Content -Path {{ DUMP_PATH }}\\dmp.log  -Tail 1"
    register: tail
    until: tail.stdout.find('正常に完了') != -1
    retries: 40
    delay: 30
```

# 各taskの解説

## impdp

```yaml
# 非同期にしたい処理
    async: # 任意の秒数
    poll: 0
```

で、fire and forget（非同期処理を一回発火させ、無視して次に進む）が実現できる
pollに1以上の値を入れるとその回数だけ結果をチェックするようになるが、
結果が「帰ってこない」というのが問題なのでチェックしても意味が無い

## tail

```yaml
# 何かの同期処理
    register: tail
    until: tail.stdout # 任意の判定
    retries: # 任意の回数
    delay: # 任意の秒数
```

で、同期処理によりその瞬間のステータスを好きな方法で取得できる
untilにregisterした変数のstdoutプロパティに対する判定を適当に書けばOK
untilの中身がtrueになった時点で成功になり、次の処理に向かうようになる

retriesはリトライする回数、delayはリトライ間隔を指定できる
今回は40 * 30 = 1200 (20分)ぐらいがマックスの時間になる
最後までuntilのプレディケートを満たさなかった場合はfailとなる

# 最後に

こんなのやらないほうがいい
冪等性ないし
【React】react-quillを使った空行が反映されない


6月からreactを用いたサービスを運営する会社にてインターンを始めたので、ログを残しておきます。

こちらのはてなブログでも書きましたが、Qiitaにも書いておきます！
https://hidelog.hatenablog.com/entry/2018/08/13/104719

# react-quillを使った空行が反映されない
react-quillを使って、htmlをデータベースに保存していたが空行が反映されないので原因を究明してみた。

1. 考えた経緯
2. 原因を模索
3. 解決方法



## 1.考えた経緯
以下のように思考した。

### 一旦chromeの検証ツールで見てみる

【正常な箇所】
``` html
<p><br></p>
```

【異常な箇所】
``` html
<p><span style="color: rgb(0, 0, 0); background-color: transparent;"></span></p>
```

## 原因を模索
考えられる原因を色々と試してみる。

- react-quillのバグ
- 保存する際に何かが原因で空行が変換されている。
- その他違う原因

### react-quillのバグ

 react-quill blank lineで検索
-> それらしい記事は見当たらない

### 保存する際に何かが原因で空行が変換されている。
-> 実際の症状を再現しようと試みるも、データベースには正常に保存されているため症状の再現が不可能。

### 一旦実際の症状を再現しようと色々と試みる
-> 原因がわかった


## 原因
空行を入れる際に空行の先頭にスペースを入れると
``` html
<p><span style="color: rgb(0, 0, 0); background-color: transparent;"></span></p>
```
このようになって保存されてしまうため。
スペースの分が認識されずにspanタグが入れられてしまうため保存する際の見た目では、空行が入るが出力すると空行が入らない。
OCI(Oracle Cloud Infrastructure)のComputeインスタンスで端末(PC等)へのX Window ssh転送が出来るように設定する。

OCI(Oracle Cloud Infrastructure)のComputeインスタンスで端末(PC等)にX転送が出来るように設定してみるやで。
環境は OCI で OEL 7.6(Oracle Enterprise Linux 7.6) の仮想マシンで試してみます。
# 1. ターミナルソフト(teraterm等)のX転送設定

まずターミナルソフト(teraterm等)のX転送設定を有効にします。
下記のような記事をご参照下さい。

 > TeratermとX Windowサーバでsshのx11フォワーディング機能を利用する
 > https://orebibou.com/2015/02/teraterm%E3%81%A7ssh%E3%81%AEx11%E3%83%95%E3%82%A9%E3%83%AF%E3%83%BC%E3%83%87%E3%82%A3%E3%83%B3%E3%82%B0%E6%A9%9F%E8%83%BD%E3%82%92%E5%88%A9%E7%94%A8%E3%81%99%E3%82%8B/

# 2. 端末(PC等)へのXサーバー(Xming等)導入と起動

端末(PC等)にXサーバー(Xming等)を導入して、起動しておきます。
下記のような記事をご参照下さい。

 > Xming環境構築
 > https://cell-innovation.nig.ac.jp/surfers/R_Xming.html

# 3. sshd_config の設定確認／変更／再起動

opcユーザーでログインして、sshd_config を編集します。

```shell
sudo vi /etc/ssh/sshd_config
```

「X11Forwarding yes」がセットされているのを確認します。

```shell
X11Forwarding yes
```

「AddressFamily  inet」を追記します。

```shell
AddressFamily  inet
```

上記設定については↓のbugzillaに情報があります。

 > ssh -X shows shows error: X11 forwarding request failed on channel 0
 > https://bugzilla.redhat.com/show_bug.cgi?id=1436097

sshdサービスを再起動します。

```shell
sudo service sshd restart
```

# 4. ライブラリ(xauth)とテスト用アプリ(xeyes)のインストール

ライブラリ(xauth)とテスト用アプリ(xeyes)をyumでインストールします。

```shell
sudo yum install xorg-x11-xauth
sudo yum install xeyes
```

# 5. DISPLAY環境変数の確認とxeyesの起動

一度ターミナルを落としてログインし直します。
その後DIAPLAY環境変数を確認です。上手く行っていれば、自動でセットされているはず。

```shell
env | grep -i display
DISPLAY=localhost:10.0
```

xeyesを起動してみます。

```shell
xeyes
```
![xeyes.jpg](https://qiita-image-store.s3.amazonaws.com/0/110066/9bd2961e-2ac9-7e8d-5a5e-dded1bed52f3.jpeg)
見事に起動！(｀･ω･)Ъ

# 6. AddressFamily inet の設定について
まずsshd_configに追記する「AddressFamily  inet」の動作ですが、
これはsshdの接続でIPv4を強制することを意味します。

 > sshdで「IPv4」「IPv6」のどちらかのプロトコルのみ接続させる方法
 > https://www.server-memo.net/server-setting/ssh/addressfamily.html

そして前述の bugzilla のコメントでは、システム全体でIPv6が無効化されているのにも関わらず、
getaddrinfo()システムコールでIPv6のアドレス解決が失敗していると言及されています。

 > To my understanding, it looks like a problem that `getaddrinfo()` is returning AF_INET6 addresses 
 > even though it is disabled "systemwide" (at least on Fedora as I tested). 

解決策として sshd_config に「AddressFamily inet」追記して、
明示的にIPv4を選択することがすることが提示されています。

 > You can resolve the problem by explicitly selecting ipv4 (not `any` as mentioned in the description):
 > AddressFamily  inet

bugzilla の中では、IPv6無効化時の getaddrinfo()システムコールの動作についての
意見も出されているようですが、特に対応はされていないようです。

ちなみに 2018年12月の時点では、OCI(Oracle Cloud Infrastructure) の
VCN(OCIの仮想ネットワーク)は IPv6 に対応されてない事が明記されています。

 > Oracle Cloud Infrastructure VCN - FAQ
 > https://cloud.oracle.com/ja_JP/bare-metal-network/vcn/faq
 > VCNはIPv6をサポートしていますか。
 > いいえ。現在、VCNはIPv6をサポートしていません。

# 7. まとめ
sshd_configへの「AddressFamily  inet」追記がハマりポイントですかね。
今回はOEL 7.6環境で検証してますが、RedHat7系やCentOS7系も
IPv6が無効化されている場合は同様なんかと？彡(ﾟ)(ﾟ)

# 8. (追記) 踏み台経由で xeyes を起動

下記のような構成の場合は……彡(ﾟ)(ﾟ)  
  
 > PC端末 → Public Compute(踏み台) → Private Compute(xeyes起動)  
  
踏み台 → Private Compute の SSH接続時に -Xオプションを追加します。  
  
```shell
(↓踏み台へのSSH接続後、Private Compute接続時に)
ssh -X xxxx.xxxx.oraclevcn.com
(↓Private Compute接続後に)
xeyes
```
Herokuで自分用のツールページ作ってみた

# 初めに

普段からExcelとかスプレッドシートでクエリ書き込んだり、必要なものはその場でツール作ったりしてたのですが、もう少しスマートにいけないものかと考えて、最近Herokuを入れました。
去年も一回やってみようとして失敗したのですが、Gitスキルも少し上がったし行けるかなーということで。

# Herokuからセットしようかな
https://qiita.com/nanananamememe/items/56752bd5b3a00537ee8f

最初はこっちを参照しました。
でも、普通に入れるだけならHerokuのやつコピペするだけでも行けたりする。

https://devcenter.heroku.com/articles/heroku-cli

<img width="740" alt="スクリーンショット 2018-12-14 11.46.53.png" src="https://qiita-image-store.s3.amazonaws.com/0/188095/41db75e5-9fa5-6827-0b51-942cd57bae71.png">

この後にheroku loginやら叩いて、ログインできれば下準備は完了。

# APP 追加しよう

<img width="1220" alt="スクリーンショット 2018-12-14 11.56.22.png" src="https://qiita-image-store.s3.amazonaws.com/0/188095/a12595bf-4cf4-be45-d947-84cdf3ddf4ca.png">

こういうやつが出てきたら[ New ]　=> [ Create new app ]でアプリを追加する。

<img width="653" alt="スクリーンショット 2018-12-14 11.59.03.png" src="https://qiita-image-store.s3.amazonaws.com/0/188095/4d5e139e-4827-8a23-f1c9-eed9474a6181.png">

Pipelineは今の所いらなさそうなので無視して、名前だけ入れる。
国家はUnited StatesかEuropeかの二択なのであしからず。

<img width="829" alt="スクリーンショット 2018-12-14 12.01.28.png" src="https://qiita-image-store.s3.amazonaws.com/0/188095/7867ead6-7fda-ea13-824f-7defdf7b2b4f.png">

こういうガイドラインが出るので付いていくだけで初期セットアップはほぼ終了。

# 設定しよう

最後に開発環境作り。

<img width="1223" alt="スクリーンショット 2018-12-14 13.00.14.png" src="https://qiita-image-store.s3.amazonaws.com/0/188095/20f76f22-de08-19bc-7e64-e4ecd8806b71.png">

アプリ設定画面のSettingsで

<img width="1224" alt="スクリーンショット 2018-12-14 13.00.26.png" src="https://qiita-image-store.s3.amazonaws.com/0/188095/2b4d115f-6c6e-cfce-b158-3a413a3a3964.png">

BuildpacksのところでAdd Buildpackを押せば

<img width="605" alt="スクリーンショット 2018-12-14 13.00.32.png" src="https://qiita-image-store.s3.amazonaws.com/0/188095/e05ce5b6-0c0e-0a0c-7de7-36add577f962.png">

こういうのが出るので好きな言語を選択してあげればおｋ
言語ごとにcomposer.jsonが居るとか、index.phpを入れないといけないとか
追加設定があったりするけど、そこはおまかせしまーす。

https://ayumu-my-functions.herokuapp.com/

![スクリーンショット 2018-12-14 13.05.21.png](https://qiita-image-store.s3.amazonaws.com/0/188095/6a1cfbf9-83ee-f403-9f83-f16e79f9ae8a.png)

で、設定してGit繋いであれこれしながら作ったのがこちらになります。
まだ機能は４つしかありません。
２番目と３番目は汎用だけど、１番目と４番目はめっちゃ個人的なやつです。
これから増える予定。増え過ぎたらレイアウト考えますか。

# 終わり

本来は画像分析の続きをやりたがったのですが、時間がなかったので今回は見送りに。
もう一つの方は今回業務で使ったHeadless周りになると思います。
ではまた後ほど。
170円でサクッとmicro:bitにしゃべらせる

![](https://qiita-image-store.s3.amazonaws.com/0/44523/2d8b201b-ba7f-2aaf-56f0-b0965f937064.jpeg)

# きっかけ

「micro:bitをしゃべらせたい」という先生の要望を受けてトライ。micro python の speech を使う方法もあるのですが、「英語のみ」「何言っているかよくわからない」という事で、ISD1820を使って録音した声を再生するようにしてみました。

# 用意するもの

- micro:bit本体
- ISD1820のボード（Amazonでなんと170円 https://www.amazon.co.jp/dp/B0175U5J08/ )
![71ypFLQ+2qL._SX522_.jpg](https://qiita-image-store.s3.amazonaws.com/0/44523/d7fd417f-9862-bdb0-0cd6-388257fe6c32.jpeg)
- ピン（メス）-ワニ口ケーブル　３本（自作）　
- 紙コップ

# 配線・工作

![Untitled.png](https://qiita-image-store.s3.amazonaws.com/0/44523/fe366bf3-785b-a790-57eb-2c779797c542.png)

- 付属のスピーカーがはんだ付けされていないのではんだ付けは必要です
- 付属のスピーカーだと音が小さいので、紙コップを拡声器代わりに使うと良く聞こえるようになります
- 「ピン（メス）-ワニ口ケーブル」は市販では見つけられませんでした。写真の物は自作しました。

# プログラム

触ろうとする（明るさが暗くなる）と「さわるな！」と叫ぶプログラムをつくってみます

https://makecode.microbit.org/_iHVTyAeu61L0

![microbit-画面コピー (9).png](https://qiita-image-store.s3.amazonaws.com/0/44523/b0b724b2-e34c-ac26-8714-02115e0c8ddf.png)


# 使い方

1.基板上のRECボタンをクリックし「触るな！」という声を録音
2.PLAYEボタンで音声を確認
3.手でmicro:bitを暗くすると「触るな！」と再生されればOKです。「10」という値は環境に合わせて調整してみてください。
Type が AWS_PROXY のときの IntegrationHttpMethod は常に POST

# tl; dr
CloudFormation の `AWS::ApiGateway::Method` で `Properties` の `Integration.Type` が `AWS_PROXY` のとき `Integration.IntegrationHttpMethod` は常に `POST` を指定する。

# 参考になる方の情報源

- https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#set-up-lambda-proxy-integration-using-cli

> Lambda 統合の場合、統合リクエストには POST の HTTP メソッドを使用する必要があります。

# 参考にならない方の情報源
- https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-properties-apitgateway-method-integration.html#cfn-apigateway-method-integration-integrationhttpmethod

> 統合の HTTP メソッドタイプ。
> 
> Required: Conditional。Type プロパティでは、MOCK を指定した場合、このプロパティはオプションです。 他のすべてのタイプでは、このプロパティを指定する必要があります。
> 
> Type: String

　これ、 Type が MOCK だったらオプショナルという話しかしてないのが酷いところで、 Type が `AWS_PROXY` (すなわち API Gateway の `Lambda プロキシ統合の使用` にチェックを入れている場合) のときは `POST` にしろという話です。
 
　これは、 API Gateway の、そのリソースへのメソッドとは関係のない概念です。

　そのリソースが `GET` で要求されようが `POST` の対象であろうが `PATCH` だろうが `DELETE` だろうが(略)　それを受けて AWS の Integration するためのつなぎとして `POST` の形が採用されているという話です。

　このあたり、日本語のドキュメントが読みづらい原因としては `Integration` を無理矢理 `統合` とあてているからです。そのくせプロキシはプロキシのままで翻訳されている。
Scalaでキャメルケースをスネークケースに変換する

ぐぐったコードが数字が入ったり大文字連続だったりのイレギュラーケースで壊滅状態だったので今さっきでっち上げてみた。

```scala:StringHelper.scala
object StringHelper {

  private val separatees = "[a-z](?=[A-Z])|[0-9](?=[a-zA-Z])|[A-Z](?=[A-Z][a-z])|[a-zA-Z](?=[0-9])".r

  def camel2Snake(s: String): String = separatees.replaceAllIn(s, _.group(0) + '_')
    .toLowerCase
}
```
PHP備忘録じゃんけん

```
<?php
$result = '';
$janken = '';
// $_POST['cho']が存在するか確認するのにissetを使う。$_POST['cho']を使いたいのであれば必ず必要
if(isset($_POST['cho']) === TRUE){
    // 自分の手と相手の手を考える相手の手は$comなのでjankenではない。自分の手はcho
    // 配列はここに置くべきではないので、4行目に置く
    $janken = array ('グー','チョキ','パー');
    // issetとセットで考えるのでこれを6行目に持ってくる自分の手であるので、$jankenではなく$choのなかに入れる
    $janken = htmlspecialchars($_POST['cho'], ENT_QUOTES, 'UTF-8');
}
// 勝負が始まってから動くようにしたいので以下は全て5行目の中に
$key = array_rand($janken);
if($janken === 'グー' && $com === 'チョキ'){
    $result = '勝ち';
} else if ($janken === 'グー' && $com === 'グー'){
    $result = 'あいこ';
} else if ($janken === 'グー' && $com === 'パー'){
    $result = '負け';
}
?>
<!DOCTYPE HTML>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>課題</title>
</head>
<body>
<form method ="POST">
    <h1>じゃんけん勝負</h1>
    <p>自分:</p><?php print $janken; ?>
    <p>相手:</p><?php print $janken[$key]; ?>
    <p>結果:</p><?php print $result; ?>
<!--php if ($cho === 'グー'){ print 'checked';} もしchoがグーであるなら、チェックボックスにチェックを表示させる-->
<!--これをすることにより直近で選んだものにチェックがされるので、連続でクリックするときに便利-->
    <input type="radio" name="cho" value="グー">グー
    <input type="radio" name="cho" value="チョキ">チョキ
    <input type="radio" name="cho" value="パー">パー
    <button type="submit">勝負！</button>
</form>
</body>
</html>
```
GitHub初心者になるためのGitHubメモ

#はじめに
この記事は SLP KBIT Advent Calendar 2018 の14日目の記事です。
[SLP KBIT Advent Calendar 2018](https://qiita.com/advent-calendar/2018/slp_kbit)


GitHubのアカウントを持っているだけのなので、自分が使い方を思い出すための備忘録。
Windowsからcommitできるようになることを目指す。
ついでに今回は自分がつかっているeclipseからの方法を探した。

## 事前準備
[GitHub](https://github.co.jp/)
[GitHub Desktop](https://desktop.github.com/)
[eclipse](http://mergedoc.osdn.jp/)


## Windowsから
GitHub Desktopを使う。
![スクリーンショット (49).png](https://qiita-image-store.s3.amazonaws.com/0/309110/a61ee294-a5aa-4328-5a3e-ced7a086e6af.png)

① open this repositoryを押す。
![スクリーンショット (51).png](https://qiita-image-store.s3.amazonaws.com/0/309110/5292f782-b498-8ea8-8b3d-dcdebfd0d86f.png)
②そこに、コードのファイルをおく。
![スクリーンショット (21).png](https://qiita-image-store.s3.amazonaws.com/0/309110/4fa31f7d-0cbb-209d-dcf8-d4dc18d068fd.png)
③Commit to masterを押す。
![スクリーンショット (22).png](https://qiita-image-store.s3.amazonaws.com/0/309110/c88d9a2c-2d48-43d2-e10c-54c1fb36187b.png)

④Fetch origin のPublish repositoryを押す。
![スクリーンショット (50).png](https://qiita-image-store.s3.amazonaws.com/0/309110/d24c3b92-6ae8-023d-ce4d-6c47cbe4cf12.png)

これでGitHub上で確認できる。
## eclipseから
①GitHub上でリポジトリを作成する。
②eclipseでプロジェクトを開く。
![スクリーンショット (31).png](https://qiita-image-store.s3.amazonaws.com/0/309110/6761d97d-41f3-4a73-ff93-017a6bf57191.png)
③右クリック→チーム→プロジェクトの共用
![スクリーンショット (40).png](https://qiita-image-store.s3.amazonaws.com/0/309110/e3659a6a-d08c-791b-980f-3c4727a0dddd.png)
④Gitを選択→プロジェクトの親フォルダー内のリポジトリーを使用または作成にチェックリポジトリーを作成を押し、完了。
![スクリーンショット (41).png](https://qiita-image-store.s3.amazonaws.com/0/309110/0734eadc-25d5-93b8-7287-740212960292.png)
⑤右クリック→チーム→コミット
![スクリーンショット (32).png](https://qiita-image-store.s3.amazonaws.com/0/309110/d3aea3ff-c1c1-50f7-5d7e-aec6b696beb0.png)
⑥ステージを変更して、コミットメッセージを入れて、コミット
![スクリーンショット (42).png](https://qiita-image-store.s3.amazonaws.com/0/309110/72b4d1b4-25bb-4be6-1002-1ecfc8303a13.png)
⑦右クリック→チーム→ブランチのプッシュ'マスター’
![スクリーンショット (43).png](https://qiita-image-store.s3.amazonaws.com/0/309110/d3f2b9c0-beac-e665-f33f-622e2049200a.png)
⑧URLにhttps://github.com/<ユーザ名>/<リポジトリ名>.git→ユーザ名とパスワードを入れ、次へ。
![スクリーンショット (44).png](https://qiita-image-store.s3.amazonaws.com/0/309110/d7d97298-c6b0-7fe6-15e6-f985549f657c.png)
⑨リモート・ブランチが存在し分岐されている場合は強制的にプッシュにチェック（これがないと拒否された）
![スクリーンショット (45).png](https://qiita-image-store.s3.amazonaws.com/0/309110/9b6e23bc-62b0-8785-eacb-dbc558b68561.png)
⑩次へを押し、完了。
⑪ユーザ名とパスワードを押しOK。

これでGitHub上で確認できる。
##  まとめ
git init,git add ,git commit などgitを使うには、覚えることが少々ある。
しかし今回は、それを使わなくてもGitHub上でコード管理ができるようになることを目指してみた。
やってみた感想としてはGitHub上でレポジトリの作り方を覚えるだけで使えるというのは便利だと感じた。
ブランチを分けたり、マージとか、競合とか覚えることはいろいろあるらしい。
これから慣れていきたい。

### 参考資料
 GitHub Desktopの使い方
 [いよいよ登場！初心者こそ知っておきたいGitHub Desktopの使い方](https://ferret-plus.com/8498)
[Git for Windows のインストールと動作確認メモ(1/2)](https://cartman0.hatenablog.com/entry/2018/09/17/Git_for_Windows_%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E3%81%A8%E5%8B%95%E4%BD%9C%E7%A2%BA%E8%AA%8D%E3%83%A1%E3%83%A2)

eclipseのGitHub
[[GitHub]初めてのGitHub「eclipse連携編」](https://www.marineroad.com/staff-blog/16236.html)
新しい擬似クラス :is() / :has() / :where() の仕様を調べてみた

[Selectors Level 4 (W3C Working Draft, 21 November 2018)](https://www.w3.org/TR/selectors-4/) の 4. Logical Combinations に載っている新しい疑似クラス `:is()` / `:has()` / `:where()` について調べてみました。

## :is()

以前の仕様では `:matches()` や `:any()` という名称でしたが、最新のドラフトでは `:is()` に変更されています。新しい疑似クラスといってもこの仕様自体は2011年ごろから草案に上がっていたようですね。なげー…。
（※ 試しに Gecko のソースコードをちょっと覗いてみたらちゃんとリネームしてましたね。→ https://github.com/mozilla/gecko-dev/commit/fbf94105b88ce3e809467b98958878327e6deac0 ）

### 特長
- `:is()` のカッコ内に複数のセレクターを指定し、それらのどれかにマッチする要素に対し、スタイルを当てる。
- `:is()` の詳細度は、カッコ内に入るセレクターのうち、詳細度が最も高いものと同じになる。


### サンプルコード
```css:sample1.css
:is(header, main, footer) > .wrapper {
  padding: 20px;
}
```

```css:sample2.css
/* 詳細度: 1, 0, 1 */
:is(.foo, #bar, ol) > a {
  margin-bottom: 20px;
}

/* 詳細度: 0, 2, 0 */
:is(.foo, [bar], ol) > .link {
  margin-bottom: 30px;
}
```

### ソース
https://www.w3.org/TR/selectors-4/#matches
https://developer.mozilla.org/en-US/docs/Web/CSS/:is

## :has()
これは面白いっすね！2018年2月の草案で初めて出てきた擬似クラスのようです。残念ながらまだどのブラウザも実装していないようなので、実際に試すことはできません。

### 特長
- `:has()` のカッコ内にあるセレクタにマッチする子要素を持つ**親要素**の方にスタイルを当てる
    - ※ ポイントは親要素の方にスタイルを当てるというところ！

### サンプルコード
```css:sample3.css
/* 子要素に見出しを持つ section 要素にスタイルを当てる */
section:has(h1, h2, h3, h4, h5) {
  border: 3px solid #ddd;
}

/* 直接の子要素に highlight クラスを持つものがある p 要素にスタイルを当てる */
p:has(> .highlight) {
  line-height: 1.4;
}
```

たとえば他にも、 active クラスを持っている li 要素を持つ ul 要素の背景を強調したいなど、いろいろと使いたくなる場面も出てくるのではないでしょうか。

### ソース
https://www.w3.org/TR/selectors-4/#relational
https://developer.mozilla.org/en-US/docs/Web/CSS/:has

## :where()
`:where()` は `:is()` と同じ機能を持っていますが、常に詳細度は持たないという点で異なっています。ドキュメントいわく、詳細度を低く保っておき、スタイルを上書きしやすくしたいときなどに便利だそうです。

### 特長

- `:where()` のカッコ内に複数のセレクターを指定し、それらのどれかにマッチする要素に対し、スタイルを当てる。
- `:where()` の詳細度は常に0。何も持たない。


### サンプルコード
```css:sample4.css
/* hover していない a 要素にスタイルを当てる */
a:where(:not(:hover)) {
  text-decoration: none;
}

section a {
  text-decoration: underline;
}
```
上記のサンプルにおいて、もし `a:not(:hover)` と書いた場合、詳細度は 0:1:1 です（擬似クラスはクラスセレクター／属性セレクターと同じ詳細度）。そのため、 `section a` の詳細度 0:0:2 に勝ってしまい、スタイルが当たりません。 `:where()` によってこういった事故を防ぐことができます。


### ソース
https://www.w3.org/TR/selectors-4/#zero-matches
https://developer.mozilla.org/en-US/docs/Web/CSS/:where
Nagiosが新ディスクを認識しない

## 概要
先日AWS上のサーバのディスクを総入れ替えしたときに
ハマったポイントをまとめてみた。

***
## Nagiosが新しいディスクを認識しない

AWSにて新しいディスクに入れ替えた。
するとNagiosのディスク監視でエラーが発生。

```
/dev/xvda1 no such file or directory
```

監視がCLITICALになったままになってるではないか。
おいおい、そりゃあないぜNagios先生よ。。。

***
### とりあえず原因を調査してみる
サーバに入ってディスクを確認してみた。

```
$ lsblk
NAME   MAJ:MIN RM   SIZE RO TYPE MOUNTPOINT
nvme0n      8:0    0  21.9T  0 disk
├─nvme0n   8:1    0 488.3M  0 part /
```

ん？ディスク名変わってんじゃん！
調べたらAWSの新世代ディスクはディスク名がnvme〜になる仕様らしい。

***
### Nagiosの設定を変更する
AWSの仕様と言われれば仕方あるまい。
ここは潔くNagiosの設定を変えようじゃあないか。


以下のNagios設定ファイルの**元ディスク名**(xvda1)を**新ディスク名**(nvme0n)に修正。

- Nagiosクライアント側
  - /etc/nagios/nrpe.cfg

- Nagiosサーバ側
  - /etc/nagios/nrpe.cfg
  - /etc/nagios/servers/[サーバ名].cfg
  - /etc/nagios/servers/servicegroup.cfg


Nagiosは再起動しないと設定が反映されないのでサービスを再起動する。

```
$ service nagios restart
```
#### 設定は以上！
私がハマったポイントをまとめてみました。
ディスク名が変更された場合はNagiosの設定も修正が必要なので要注意！