OmniAICreator/Qiita-1.07M huggingface dataset:
とりあえず webpack を使ってみる

webpack 最低限、超入門。
細かい説明は抜きにして、とりあえず webpack を触ってみたいひと向け。
「webpack」で調べてみると説明が長い記事が多く、全体の流れを理解しにくかったので、短くまとめてみました。

# 1. そもそも webpack とは何か

js や css などを 1 つにまとめてくれるツール
→ 開発時にファイルを分割できる
→ 嬉しい

# 2. とりあえず動かす

## 2.1. インストール

webpack は Node.js のパッケージなので、Node.js を持っていない場合はインストール。
参考「[とりあえず Ubuntu で新しい Node.js, npm をインストール - Qiita](https://qiita.com/kerupani129/items/60ee8c8becc2fe9f0d28)」

以降は作業したいディレクトリでの操作。

```shell
npm init -y # package.json の作成。-y を付けると対話が出ない
npm install --save-dev webpack
npm install --save-dev webpack-cli # (webpack 3 以前では不要)
```

## 2.2. ファイル編集

作成された `package.json` の `"scripts"` を以下のように編集。

```json:package.json
...
  "scripts": {
    "build": "webpack"
  },
...
```

参考「[package.json | npm Documentation](https://docs.npmjs.com/files/package.json)」
参考「[npm package.json 日本語版 取扱説明書](http://liberty-technology.biz/PublicItems/npm/package.json.html)」

## 2.3. ファイル追加

実際のソースコードを追加。
(ここでは分かりやすいよう js ファイル 1 つ)

```html:dist/index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>だぁ！</title>
    <script src="./main.js"></script>
  </head>
  <body>
  </body>
</html>
```

```js:src/index.js
document.addEventListener("DOMContentLoaded", function() {
	document.write('わん♪');
	document.write('にゃー❤');
});
```

webpack の設定。

```js:webpack.config.js
module.exports = {
	entry: './src/index.js',
	output: {
		path: __dirname + '/dist',
		filename: 'main.js'
	}
};
```

参考「[Configuration - webpack](https://webpack.js.org/configuration/)」

## 2.4. ビルド

```shell
npm run build
```

webpack が実行され、`dist/main.js` ができます。

## 2.5. その他

あとはファイル分割したりすると嬉しい。
検索してサンプルのコードを探すと良い。 

- CommonJS `require` `module.exports` (`exports`)
- ES6 `import` `export`

# 3. webpack 4 を使う

環境によってインストールされるバージョンが異なる場合がありますが、webpack 4 ならより便利に使えます。
**※ Node 4 以下だと正しく動作しないので、古い場合は先に Node.js をバージョンアップ。**

参考「[次のリリースであるwebpack 4の主な変更点まとめ - 技術探し](http://abouthiroppy.hatenablog.jp/entry/2017/12/25/100004)」

## 3.1. ファイル編集

```json:package.json
...
  "scripts": {
    "dev": "webpack --mode development",
    "build": "webpack --mode production"
  },
...
```

## 3.2. ファイル削除

この記事のサンプルでは webpack 4 のゼロコンフィグ時のディレクトリ構成と同じにしているので、そのまま `webpack.config.js` を削除してもビルドできます。

## 3.3. ビルド

開発時とリリース時で簡単に分けることができます。

```shell:開発時
npm run dev
```

```shell:リリース時
npm run build
```

minify の有無やその他色々便利に切り替えてくれます。

# 4. おまけ


## 4.1. webpack のバージョンを調べる

```shell:npm&nbsp;5.1&nbsp;まで&nbsp;(それ以降でも使える)
$(npm bin)/webpack -v
```

```shell:npm&nbsp;5.2&nbsp;から
npx webpack -v
```

## 4.2. Babel の導入

webpack と Babel を同時に説明すると分かりにくい気がしたので、別記事にしました。

参考「[とりあえず webpack 4 で Babel 6 か 7 を導入する - Qiita](https://qiita.com/kerupani129/items/60282ed958d9fb0cd3f5)」

## 4.3. ディレクトリ構成

`src` に html なども含めたい場合にはサブディレクトリ `js`, `html` などを作るべきかも。

サブディレクトリを `webpack.config.js` で指定する際は `path.join`, `path.resolve`, `+` などで `__dirname` につなげる (`output.path` は相対パスで指定しない) 。
webpack 4 だとコマンドライン引数から色々設定できるようです。

## 4.4. `package.json`

本当は必須は `"name"` と `"version"` 。
ただし、webpack を使う分には `"scripts"` と `"devDependencies"` さえあれば動く。
(`"main": "index.js",` も不要)
CentOS 7 サーバ構築 目次

#はじめに
knutpb1205ではCentOS 7でLAMPサーバ構築とセキュリティ対策について記事を投稿します。最終目的はWordPress運用とします。
仮想環境VMwareでCentOSをminimalインストールし、必要なものを追加していくスタイルです。サーバソフトウェアはパッケージは更新が遅いので極力使わずソースファイルからコンパイルします。
仮想環境での実行結果のため、物理環境と結果が異なることがあります。ご了承ください。

#追記
CentOS 7が2018年5月にアップデートし1708から1804に変わりました。
「サーバ構築目次」は1708を対象にしているので、1804に新しくページを作成します。


#目次（リンク）
##1 CentOS 7 SSH接続のための設定
[CentOS 7 NIC ネットワークデバイス名の変更](https://qiita.com/knutpb1205/items/8789fc0e8105f2f0c2ef) （2018/2/25作成）
[CentOS 7 ネットワーク設定](https://qiita.com/knutpb1205/items/a15929a8c16c2faca323)　（2018/2/26作成）
[CentOS 7 NTPの変更](https://qiita.com/knutpb1205/items/f5f73b7d34c5a05c47a7)　（2018/2/25作成）
*この工程でSSH接続が可能になります。*

##2 初期設定
[CentOS 7 OSインストール後の初期設定](https://qiita.com/knutpb1205/items/747fe122ea9f237f71e2)　（2018/2/27作成）
[CentOS 7 Firewallの設定](https://qiita.com/knutpb1205/items/3a9fa22d43588092d6f0)　（2018/3/23作成）

##3 ソースファイルからのビルドのためのコンパイラインストール
[CentOS 7 gcc 8.13.0のソースファイルからのインストール](https://qiita.com/knutpb1205/items/fc6dbc15fbd052f7560a)　（2018/5/23作成）
[CentOS 7 cmake 3.11.4のソースファイルからのインストール](https://qiita.com/knutpb1205/items/ddd93b382ddce6e08eaa)　（2018/6/20作成）

##4 サーバソフトウェアのインストール
[CentOS 7 MySQL 5.7.22のソースファイルからのインストール](https://qiita.com/knutpb1205/items/85c3a56620b60c909e37)　（2018/4/30作成、2018/6/20更新）
[CentOS 7 Apache 2.4.33のソースファイルからのインストール](https://qiita.com/knutpb1205/items/a8e78449093435c7cb48)　（2018/3/30作成、2018/6/20更新）
[CentOS 7 PHP 7.2.5のソースファイルからのインストール](https://qiita.com/knutpb1205/items/c970e653466591fb2545)　（2018/6/20作成）

##5 通信の暗号化のインストール
[CentOS 7 OpenSSL 1.1.0hのソースファイルからのインストール](https://qiita.com/knutpb1205/items/995d878bf5ba294cfd0a) （2018/3/30作成、2018/6/20更新）
[CentOS 7 Let's Encrypt サーバ証明書の取得](https://qiita.com/knutpb1205/items/07068bf5c7ddd1a0fd35)　（2018/3/14作成、2018/6/20更新）

##6 HTTPの高速化 HTTP/2のインストール
[CentOS 7 ApacheのHTTP/2対応](https://qiita.com/knutpb1205/items/8923eb7c06761958f185)　（2018/3/16作成、2018/6/20更新）

##7 セキュリティ対策
[CentOS 7 Suricata 4.0.4のソースファイルからのインストール](https://qiita.com/knutpb1205/items/47f3e8f58b3d13458a3c)　（2018/3/19作成、2018/6/20更新）
[CentOS 7 ModSecurity 2.9.2のソースファイルからのインストール](https://qiita.com/knutpb1205/items/ac0ee1037472bf00e07c)　（2018/3/20作成、2018/6/20更新）
ModSecurity 3.0.0はインストール途中でエラーが発生しているため、思索中。

##8 WordPressのインストール
[CentOS 7 WordPressのインストール](https://qiita.com/knutpb1205/items/ce494316f3c5c863ebe2)　（2018/3/21作成）
cronとPythonとSeleniumとで決まった時間にラジオを聞く

家にいるときは朝からラジオを聞くことが多いので、目覚まし代わりにラジオを再生するようにしたいと思います。時間を指定してラジオをつけようと思うと数千円出して新しい機器を購入したりアプリを入れたりということが選択肢としてありますが、こちらの記事によるといろいろ苦労もあるようです。
→「[ラジオで爽やかに目覚めたい! だけなのに、けっこう大変だった話。ソニーの電球スピーカー&ラジオ](https://av.watch.impress.co.jp/docs/series/hinuma/1040547.html)」

そこで、自分の家にはUbuntuを入れている[インテルのNUC](https://www.intel.co.jp/content/www/jp/ja/products/boards-kits/nuc.html)があることを思い出し、cronを使ってradiko.jpからラジオを再生すればいいと考えました。

（以下はChromeを使うことを前提にしています。）

## Seleniumでradiko.jpにアクセス

こちらの記事のようにCUIからradiko.jpのコンテンツ操作する方法は結構あるようです。
→「[CUIなサーバーだけでradikoを聞きたい！](https://qiita.com/onokatio/items/86755bb3083e414f1a3a)」

ただradiko.jp内のリソースに直接触れる感じになるのが若干気が引けたというのと、より簡単な方法で実行したいという気持ちがあったので、UIテストのときに使われるSeleniumを用いてradiko.jpの再生ボタンを押すという方法を選択しました。

### Seleniumの準備

Seleniumはこちらを参考にしました。
→「[PythonでSeleniumを使ってスクレイピング (基礎)](https://qiita.com/kinpira/items/383b0fbee6bf229ea03d)」

#### ドライバ取得

上記の参考記事に従い、seleniumのインストールと使っているOSやブラウザのバージョンにあったドライバの取得をします。

https://www.seleniumhq.org/projects/webdriver/

e.g.

```bash
wget https://chromedriver.storage.googleapis.com/2.40/chromedriver_mac64.zip
unzip chromedriver_mac64.zipwget
```

#### Selenium インストール

```bash
pip install selenium
```

### Seleniumでラジオを再生

```python
#!/usr/bin/env python
# -*- coding: utf-8 -*-

from time import sleep

from selenium import webdriver
from selenium.webdriver.chrome.options import Options


class Radio(object):

    def __init__(self, driver_path, url, options=None):
        self.driver = webdriver.Chrome(driver_path, chrome_options=options)
        self.driver.get(url)

    def play_or_stop(self):
        self._play_button.click()

    def exit(self):
        self.driver.quit()

    @property
    def _play_button(self):
        return self.driver.find_element_by_class_name('btn--primary')

    def __enter__(self):
        self.play_or_stop()
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        self.exit()


def main():
    options = Options()
    options.add_argument('--headless')

    with Radio('/path/to/driver', 'http://radiko.jp/#!/live/TBS', options):
        sleep(360)


if __name__ == '__main__':
    main()

```

詳しい説明は省きますが、ポイントは再生画面の再生ボタンを特定して`click()`を実行していることです。また、スクリプトが終了した時点で`webdriver.Chrome`のオブジェクトが破棄され、ブラウザが閉じてしまうので`sleep(360)`として一時間ラジオが鳴っている状態にしています。`--headless`はChromeの画面を表示せずに実行するオプションで、後述する理由により追加しています。

実装: https://github.com/itkr/my-radio

## cronの設定

実行するPythonやドライバのパスに注意しながら普通にcronを設定します。cron自体の説明は省略します。

### Headless Chrome を使う理由

Ubuntuで実行した際、cronからだと`--headless`オプションを付けないとうまく起動してくれませんでした。また、Macではブラウザの表示はされましたが音が出ない場合がありました。(原因は追えていません)

### コンピューターを休止させておいきたい場合

ずっと動かしているコンピューターならいいのですが、スリープや休止状態にしている場合cronがうまく動かない場合があります。そこで`rtcwake`というコマンドで復帰する時間を操作できるようです。参考→「[【備忘録】毎日自動的に休止→起動する(CentOS 6.6)](http://yaochin.seesaa.net/article/414381643.html)」(Ubuntuでも使えました)

## 余談

タイトルは毎朝聞いている「伊集院光とらじおと」をちょっとだけ意識しました。
Raspberry Pi 3 でIPアドレスを固定して、外部からSSH接続できるようにする

Raspberry Pi に外出先からもアクセスしたいと思い、調べたところ、
外部からの接続を可能にするには、まずRaspberry PiのIPアドレスを固定にする必要がありました。

今回は、Raspberry Piに外部からの接続を可能にする下準備としてIPアドレスを固定する方法から、
ポートを開放して、外部からのアクセスを受け付けるところまで説明します。

##dhcpcd.conf を編集する

dhcpcd.confとファイルに固定したいIPなどの情報を記載します。
まずは、以下のコマンドたたいて、ファイルを開きます。

```sh
$ sudo nano /etc/dhcpcd.conf
```

末尾に以下の情報を追記します。
ちなみに、Buffalo無線ルータの場合の設定となりますので、
適宜、routersなどの値を編集してください。

| メーカー       |       デフォルトゲートウェイ | 
|:-----------------|------------------:|
| バッファロー    |            192.168.11.1 |
| ロジテック       |            192.168.2.1 |

```conf:/etc/dhcpcd.conf
interface wlan0
static ip_address=192.168.11.40/24
static routers=192.168.11.1
static domain_name_servers=192.168.11.1
```

##IPアドレスの確認

先ほどの設定が反映されているか確認するため、Raspberry Piを再起動します。

再起動し、ifconfigでIPアドレスを確認して、
dhcpcd.confで設定したとおり、
「192.168.11.40」となっていれば、設定がうまくいっています。

#外部からの接続

外部からアクセスできるようにポートを開放します。

今回、私は、SSH接続を外部からしたかったので、開放するポートは22番にしました。

バッファローでは、以下のように設定を登録します。

http://faq.buffalo.jp/app/answers/detail/a_id/15794

##グローバルIPアドレスの確認

外部から接続するので、グローバルIPアドレスを確認します。

こちらの、サイトで確認すると便利です。
https://www.cman.jp/network/support/go_access.cgi

Raspberry Piとは別のネットワークに繋がっているPCから、
以下のコマンドをたたいて、接続ができれば、設定完了です。
（xxxの部分にグローバルIPアドレスを入れます）

```sh
$ ssh user@xxx.xxx.xxx.xxx
```

これで、いつでもどこでもRaspberry Piにアクセスができるようになりました！！

**追記**
今回、繋ぎ方の説明としてコンパクトにまとめましたが、
実際に、運用する場合は、公開鍵認証などを設定して、
セキュリティを高めた上でご利用くださいmm
Springの「GUIDES」を解読する旅　Scheduling Tasks編　つっこみ大歓迎！

[Scheduling Tasks](https://spring.io/guides/gs/scheduling-tasks/)

このページを解読していきます。

環境
sts 3.8.4
stsを立ち上げて「File」->「New」->「Import Spring Getting started content」から対象のプロジェクトを検索。インポートして動作を確認している。


経緯
Spring bootを学習していたが、市販の書籍が頼りなく本家のドキュメントを読むことに。
全て英語なので四苦八苦しながら読んでいる。

Java　スキル
Oracle Java8 Silver程度

学習のための備忘録として書いています。
修正すべき点や補足などアドバイスがありましたらぜひともお願いいたします。

##コンポーネントの作成

```java:ScheduledTasks.java
package hello;

import java.text.SimpleDateFormat;
import java.util.Date;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component
public class ScheduledTasks {

    private static final Logger log = LoggerFactory.getLogger(ScheduledTasks.class);

    private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");

    @Scheduled(fixedRate = 5000)
    public void reportCurrentTime() {
        log.info("The time is now {}", dateFormat.format(new Date()));
    }
}
```

まずはこちらのコードから。
`@Component`とすることで次に作成するApplication.javaのMainクラスで使用することができるようになります。Mainクラスには`@SpringBootApplication`（`@ComponentScan`を含む）というアノテーションをつける必要があります。これにより同じパッケージ内のコンポーネントを自動的に探せるようになります。ここで作成するコンポーネントも使用できるようになります。

###ScheduledTasksメソッドを読み解く

このクラスでは５秒ごとにコンソールにログを表示する仕組みを作っています。
`private static final Logger log = LoggerFactory.getLogger(ScheduledTasks.class);`
でロガーを取得します。

LoggerFactoryとはLog4j の開発者が作ったロギングライブラリです。
`ScheduledTasks.class`のようにロガーを使うクラスのClassオブジェクトというものを引数に設定します。

これにより、デフォルトではlog.info( )でコンソールに表示できるようになります。

`@Scheduled(fixedRate = 5000)`というアノテーションをつけておけば定期的にそのメソッドが実行されることになります。ちなみに引数のあるメソッドにアノテーションをつけて場合例外が発生します。次に作るファイルで`@EnableScheduling`の指定をすることにより`@Scheduled`がついたメソッドが実行されます。


SimpleDateFormatやDateに関しては割愛します。

##Application.javaの作成

次にmainメソッドを持つ、application.javaのコードを見ていきます。

```java:Application.java
package hello;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;

@SpringBootApplication
@EnableScheduling
public class Application {

    public static void main(String[] args) throws Exception {
        SpringApplication.run(Application.class);
    }
}
```

###アノテーションの解説
このコードでは`@SpringBootApplication`のアノテーションがついています。こちらは`@Configuration`　`@EnableAutoConfiguration` `@EnableWebMvc`　`@ComponentScan`をセットで読み込みます。


`@ComponentScan`により先ほど作成したScheduledTasksクラスを探してくれます。`@EnableScheduling`をつけると`@Scheduled(fixedRate = 5000)`のアノテーションをつけたreportCurrentTime()メソッドが定期的に実行されるようになります。アノテーションは`@Scheduled(cron="")`を使うことでさらに複雑なスケジューリングも可能になるようです。

##実行
stsではプロジェクト名をクリックして再生ボタンを押せば自動的にコンパイルから実行まで行われます。

![screen.jpg](https://qiita-image-store.s3.amazonaws.com/0/240587/bc45fee7-5a75-1f02-f15a-730f3a90f4c1.jpeg)

コンソールに5秒ごとにログが追加されていきます。
CentOS 7 NTPの変更

# 動作確認環境
- 仮想環境 VMware Workstation Player 14.1.1
- OS Windows 10 Pro 64bit

#仮想環境
- OS CentOS 7.4 (1708) minimalインストール
- メモリ 2GB
- HDD 250GB

# 初回の時計合わせ
初回は手動で時計合わせを行う。以下のコマンドを実行する。
この状態では「ntpdate: コマンドが見つかりません」と表示されるので、[CentOS 7 OSインストール後の初期設定](https://qiita.com/knutpb1205/items/747fe122ea9f237f71e2)の「基本パッケージのインストール」の`yum -y groupinstall base`を実行してから行うと良い。

````
ntpdate ntp.nict.jp
````

# 自動のNTPサーバ修正
オリジナルの設定ファイルをバックアップする。

````
cp -a -p /etc/chrony.conf /etc/chrony.conf.org
````

設定ファイルを修正する。

````
vi /etc/chrony.conf
````

以下のように修正する。

```` /etc/chrony.conf
server ntp.nict.jp
server ntp.nict.jp
server ntp.nict.jp
````

自動で起動するように設定する。

````
systemctl enable chronyd
````

起動する。

````
systemctl start chronyd
````

# 動作確認
10分ほど経過したら動作を確認する。

````
chronyc sources -v
````

以下のような表示があれば成功。

````
^+ ntp-a3.nict.go.jp 1 6 77 59 +972us[ +972us] +/- 5667us
^- ntp-b2.nict.go.jp 1 6 77 61 +1423us[+1423us] +/- 3830us
^* ntp-a2.nict.go.jp 1 6 77 62 +269us[ +547us] +/- 4458us
````

---
[目次](https://qiita.com/knutpb1205/items/3ece0cab588afdb13f02)
Android の ConstraintLayout でウィジェットの中心にウィジェットを配置してみた件

# 方法

中央に配置されるウィジェットに４方向分の `layout_constraint*_to*Of="中央にウィジェットを配置するウィジェットの ID"` を指定することで[センタリング](https://developer.android.com/reference/android/support/constraint/ConstraintLayout.html#CenteringPositioning)を行います。

# サンプル

[ImageView](https://developer.android.com/reference/android/widget/ImageView.html) のセンターに [Button](https://developer.android.com/reference/android/widget/Button.html) を表示してみます。

## コード

``` sample.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.v7.widget.AppCompatImageView
        android:id="@+id/imageView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@mipmap/bg_pattern2_aozora" />

    <android.support.v7.widget.AppCompatButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="中央"
        app:layout_constraintBottom_toBottomOf="@id/imageView"
        app:layout_constraintEnd_toEndOf="@id/imageView"
        app:layout_constraintStart_toStartOf="@id/imageView"
        app:layout_constraintTop_toTopOf="@id/imageView" />
</android.support.constraint.ConstraintLayout>
```

## 結果

<img width="491" alt="スクリーンショット 2018-02-25 16.53.33.png" src="https://qiita-image-store.s3.amazonaws.com/0/6881/4017a2b6-0706-4bee-6fba-26b57efc7ed4.png">

# 関連記事

- https://qiita.com/84d010m08/items/9797205ee453345e2e8d
CentOS 7 NIC ネットワークデバイス名の変更

# 動作確認環境
- 仮想環境 VMware Workstation Player 14.1.1
- OS Windows 10 Pro 64bit

#仮想環境
- OS CentOS 7.4 (1708) minimalインストール
- メモリ 2GB
- HDD 250GB

# 変更方法
CentOS 7では標準でデバイス名が`ens33`になっている。
これを一般的な名称`eth0`に変更する。

**1 カーネル起動時の変更**
grubの編集

````
vi /etc/default/grub
````

`net.ifnames=0 biosdevname=0`を追記する。

````
GRUB_CMDLINE_LINUX="crashkernel=auto rd.lvm.lv=centos/root rd.lvm.lv=centos/swap rhgb quiet net.ifnames=0 biosdevname=0"
````

編集後、内容を反映するためにコマンドを実行する。

````
grub2-mkconfig -o /boot/grub2/grub.cfg
````
以下のような文が表示され、最後に`done`と表示されればよい。

````
Generating grub configuration file ...
Found linux image: /boot/vmlinuz-3.10.0-693.el7.x86_64
Found initrd image: /boot/initramfs-3.10.0-693.el7.x86_64.img
Found linux image: /boot/vmlinuz-0-rescue-9346d04a2bfa47d89e7523247656d127
Found initrd image: /boot/initramfs-0-rescue-9346d04a2bfa47d89e7523247656d127.img
done
````

**2 NICの設定ファイルの変更**
NICの設定ファイル名の名前を変更する。

````
mv /etc/sysconfig/network-scripts/ifcfg-ens33 /etc/sysconfig/network-scripts/ifcfg-eth0
````
ファイルを開き、`ens33`の部分を2箇所`eth0`に変更する。

````
vi /etc/sysconfig/network-scripts/ifcfg-eth0
````
**3 設定反映**
再起動するとNICのデバイス名が変更される。

````
shutdown -r now
````

#参考
[CentOS 7でNICのデバイス名を変更する | 俺的備忘録 〜なんかいろいろ〜](https://orebibou.com/2015/03/centos-7%E3%81%A7nic%E3%81%AE%E3%83%87%E3%83%90%E3%82%A4%E3%82%B9%E5%90%8D%E3%82%92%E5%A4%89%E6%9B%B4%E3%81%99%E3%82%8B/)

---
[目次](https://qiita.com/knutpb1205/items/3ece0cab588afdb13f02)
AWS EC2をLVSでロードバランスさせてみた

# はじめに
LVSでロードバランスをさせる方法を勉強する必要があって勉強してたのですが、勉強したからにはお試ししないとねってことで、AWSの無料枠使って最小構成ってぽい構成で構築してみました。

ELB使えって話もあるかもしれませんが、勉強だからねしょうがないね。

# 今回の構成
最小構成ってことでLB1台にアプリケーションサーバー2台の構成です。

# インスタンス
今回は全てEC2で作成します。
OSはなんとなくRHELです。

    $ less /etc/redhat-release
    Red Hat Enterprise Linux Server release 7.4 (Maipo)

3台とも全て同じ設定にしてます。

# LVSで振り分けるまでの手順
作成したインスタンス3台にそれぞれ役割を付けてあげてください。
Hostから役割が分かりにくいですが、名前とか付けれるので付けてあげると少し管理しやすいです。
それぞれの役割で行うことを以下に記載していきます。
といってもアプリケーションサーバーはやる事ほとんどないのですが。

## LBサーバーの手順
### LVSのインストール
    $ sudo yum install -y ipvsadm

yumからインストールすると古いこともありますが、今回はお試しなので気にしません。
注意として今回はKeepAlivedは使用しません。
お試しなので消えてもいいやっていうのと単純に面倒くさがっただけです。

### LBサーバーからIPV4の転送を許可して設定を反映
    $ sudo vi /etc/sysctl.conf
    net.ipv4.ip_forward = 1  (追加)
    $ sudo sysctl -p
    net.ipv4.ip_forward = 1

### LVSを有効化
    $ sudo systemctl start ipvsadm
    $ sudo systemctl enable ipvsadm
    Created symlink from /etc/systemd/system/multi-
    user.target.wants/ipvsadm.service to /usr/lib/systemd/system/ipvsadm.service.

### IPテーブルの確認
    $ sudo ipvsadm -l
    IP Virtual Server version 1.2.1 (size=4096)
    Prot LocalAddress:Port Scheduler Flags
      -> RemoteAddress:Port           Forward Weight ActiveConn InActConn

最初なので何も登録されていないはずです。
何か登録されていてリセットしたい場合は`sudo ipvsadm -C`でリセットしてあげてください。

### IPテーブルへの追加
    $ sudo ipvsadm -A -t <LB IP>:80
    $ sudo ipvsadm -a -t <LB IP>:80 -r <APP1 IP>:80 -m
    $ sudo ipvsadm -a -t <LB IP>:80 -r <APP2 IP>:80 -m

IPの部分には各サーバーのプライベートIPを記載してください。
プライベートIPはEC2ダッシュボードを見るか各サーバーで`ifconfig`したら分かります。

振り分けについては特に設定しなければラウンドロビンでやってくれるようです。

## アプリケーションサーバーの手順

### アプリケーションのインストール
    $ sudo yum install httpd
    $ sudo service httpd start

何か待ち受けてないといけないので`httpd`入れて待ち受けて貰います。
今回は振り分けが確認できれば良いので、アプリケーションとかいいながら何も中身は入れてません。

## 振り分け確認
LBサーバーで`curl http://127.0.0.1`をしてアプリケーションサーバーのアクセスログが交互に出力されてくれれば無事成功です。

## 最後に
今回の手順の場合はLBサーバーが外部からの待ち受けをしていないので外からのアクセスは出来ず、LBサーバースタートでの確認しか出来ません。
外部からの待ち受けについては特に記述が見つからなかったので、普通に待ち受けてあげればよさそうですが、設定を色々と追加しないとダメっぽい感じがします。
良くわかってないので、また勉強してきます。

あと、セキュリティグループきちんとしてないとアプリケーション側を直接見に行けてしまうので、portの設定ぐらいはやってあげた方が良いです。

## 不満
-lオプションで接続先一覧が見れるのですが、AWSの場合Hostが長すぎてPortが全く見えないのが困りものです。
tp-link TL-WR841N V13 に OpenWrt をインストールしてみた

はじめに
---
無線LANルータ [tp-link TL-WR841N](https://www.tp-link.com/jp/products/details/cat-9_TL-WR841N.html) は、2,000円前後で購入できるお手軽ルータです。
この機種はバージョンによってハードウェアが異なります。とりわけV13はそれ以前と比べ大幅に変更されました。開封後ルータの底面を見てはじめてどのバージョンかわかります。
今回 TL-WR841N V13用の [OpenWrt](https://openwrt.org/) をインストールしてみました。


参考
---
[OpenWrt - Techdata: TP-Link TL-WR841N v13](https://openwrt.org/toh/hwdata/tp-link/tp-link_tl-wr841n_v13)
[OpenWrt - TP-Link TL-WR841ND](https://wiki.openwrt.org/toh/tp-link/tl-wr841nd#tftp_recovery_via_bootloader_for_v8_v9_v10_v11_v12)

Ubuntuパソコン側の設定
---

OpenWrt のファームウェア・イメージファイルは、Ubuntuパソコンから TL-WR841N へ tftp で転送します。そのための環境を整備します。

1.Ubuntuパソコンに tftpサーバをインストールします。

```shell-session
$ lsb_release -a
No LSB modules are available.
Distributor ID:	UbuntuSoC
Description:	Ubuntu 17.10
Release:	17.10
Codename:	artful
$ sudo apt-get install tftpd-hpa
$ sudo systemctl restart tftpd-hpa
```
2.OpenWrt の tftp用ファームウェア・イメージファイルをダウンロードし、TL-WR841N へ転送できるようにします。

```shell-session
$ wget https://downloads.lede-project.org/snapshots/targets/ramips/mt76x8/openwrt-ramips-mt76x8-tl-wr841n-v13-squashfs-tftp-recovery.bin
$ sudo cp openwrt-ramips-mt76x8-tl-wr841n-v13-squashfs-tftp-recovery.bin /var/lib/tftpboot/tp_recovery.bin
```
3.LANポートのIPアドレスを 192.168.0.66 に変更します。

```shell-session
$ sudo ifconfig enp10s0 192.168.0.66
```

TL-WR841N 側の設定
---
1.Ubuntuパソコンと TL-WR841N をLANケーブルで接続します。その後RESETボタンを押したまま電源を入れます。6,7秒RESETボタンを押したままにすると、ファームウェアをダウンロードし、フラッシュROMへ書き込み後、再起動します。

2.OpenWrtの初期IPアドレスは 192.168.1.1 なので、UbuntuパソコンのLANポートIPアドレスを 192.168.1.100 に変更します。その後 ssh で接続します。

```shell-session
$ sudo ifconfig enp10s0 192.168.1.100
$ ping 192.168.1.1
PING 192.168.1.1 (192.168.1.1) 56(84) bytes of data.
64 bytes from 192.168.1.1: icmp_seq=1 ttl=64 time=0.363 ms
$ ssh root@192.168.1.1
The authenticity of host '192.168.1.1 (192.168.1.1)' can't be established.
RSA key fingerprint is SHA256:*******************************************.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.1.1' (RSA) to the list of known hosts.


BusyBox v1.27.2 () built-in shell (ash)

  _______                     ________        __
 |       |.-----.-----.-----.|  |  |  |.----.|  |_
 |   -   ||  _  |  -__|     ||  |  |  ||   _||   _|
 |_______||   __|_____|__|__||________||__|  |____|
          |__| W I R E L E S S   F R E E D O M
 -----------------------------------------------------
 OpenWrt SNAPSHOT, r6293-2805402f86
 -----------------------------------------------------
=== WARNING! =====================================
There is no root password defined on this device!
Use the "passwd" command to set up a new password
in order to prevent unauthorized SSH logins.
--------------------------------------------------
root@OpenWrt:~#
```

最後に
---
はやく [dd-wrt](https://www.dd-wrt.com/site/index) もサポートしてくれないかな(=^・^=)
vee-validateを使っていてハマったこと


## requiredのとき、値がfalseでもvalidateの結果が、trueになってしまう。

事象：お問い合わせフォームの「チェックボックス」

![スクリーンショット 2018-02-25 18.44.15.png](https://qiita-image-store.s3.amazonaws.com/0/92083/81fd8e81-4900-2e8f-fc0e-ee3acf7bcdc9.png "スクリーンショット 2018-02-25 18.44.15.png")

```
input(
	type="checkbox",
	data-vv-name="bool",
	v-validate="'required'",	
)
```


```

validator.validate('bool', true).then((result) => {
	console.log(result)
});
--> true

validator.validate('bool', false).then((result) => {
	console.log(result)
});
--> true

```

値がtrueでもfalseでもバリデーションが通ってしまう。

チェックボックスの正しい動作として、チェックがついていなければ、エラーになって欲しい。
でも、このままだとエラーにはならない。

調べました。
「vee-validate boolean」

解決したIssuesが出てきましたよ。
https://github.com/baianat/vee-validate/issues/484

あれ？修正してくれてますやん！
なんで動かないの？バージョンも最新にしたのに。。。

ソース見に行くか・・・
requiredルールのソース

https://github.com/baianat/vee-validate/blob/master/src/rules/required.js

```required.js

  // incase a field considers `false` as an empty value like checkboxes.
  if (value === false && invalidateFalse) {
    return false;
  }

```

ちゃんと用意してくれていました。
どうやら```invalidateFalse```の指定をしてあげればいいのですね^^

正しいチェックボックスの例

```
input(
	type="checkbox",
	data-vv-name="bool",
	v-validate="'required:invalidateFalse'",  // <-- ここ	
)
```

![スクリーンショット 2018-02-25 18.55.47.png](https://qiita-image-store.s3.amazonaws.com/0/92083/de23ccb1-b8da-c4b5-3622-b217c0f568d5.png "スクリーンショット 2018-02-25 18.55.47.png")


はい！正しく動いてくれました！

vee-validateのドキュメントはたまに古いことがあるので、あれ？ってなったらソース見に行くのがいいですね。
とても見やすいソースになっているので、すぐに原因を見つけることができると想いますよ。
[Concourse]01_最も単純なパイプライン

# 目的

[Concourse](http://concourse.ci/)が便利なので利用者もっと増えて欲しいなあと思っています。

けれども、Jenkinsおじさんをやっていた身からするとちょっと理解しづらい部分があるので、
`step-by-step`で説明できたらいいなということでシリーズ化して書いていこうと思います。

# Concourseってなんやねん

コンテナベースでCI/CDのパイプラインのツールです。
PivotalさんがメンテナンスしているOSSです。
CloudFoundryなどもこれを利用してCI/CDをしているらしいです。

# ちょっと前提

最初のセットアップとConcourse CIのCLIツールである
flyのセットアップまで完了していること。

# 最も単純なパイプラインの作成

単一のジョブを実行するパイプラインを記述します。

## パイプラインを記述する

もっとも単純なパイプラインとして以下を記述。

```yaml:01_sample.yaml
jobs:
  - name: job-sample
    plan:
      - task: task-sample
        config:
          platform: linux
          image_resource:
            type: docker-image
            source:
              repository: alpine
              tag: 3.7
          run: 
            path: /bin/sh
            args:
              - -c
              - -x
              - |
                uname -a
```

やっていることはシンプルで、

1. `alpine:3.7`のDockerイメージをpullする
2. 上記イメージの内部で`/bin/sh -c -x 'uname -a'` しているだけの内容になります。

## パイプラインの設定

記述したパイプラインをConcourse CIに設定します。

```bash:パイプラインの作成
$ fly -t home sp -p 01_pipeline_sample -c 01/01_pipeline_sample.yaml
apply configuration? [yN]: y
pipeline created!
you can view your pipeline here: http://concourse.web.ryoma0923.work/teams/main/pipelines/01_pipeline_sample

the pipeline is currently paused. to unpause, either:
  - run the unpause-pipeline command
  - click play next to the pipeline in the web ui
CA2115:concourse_sample 01013548$ fly -t home dp -p 01_pipeline
!!! this will remove all data for pipeline `01_pipeline`
```

# パイプライン(厳密にはパイプライン内のジョブ)の実行

Concourse CIの画面にアクセスすると、
`01_pipeline_sample`パイプライン
が作成されています。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/40692/30cd2274-f4b0-4e37-73ae-9f18f500b3bf.png)

パイプラインは作成したのみだと`Pause`されているため、実行できません。
これを解除するためにConcourse CIの画面から実行できるようにPauseを解除
(Unpause)します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/40692/6d406e41-2621-f1c4-2faa-80bb9f215273.png)

Unpauseしたいパイプラインの再生ボタン?をクリックすればPauseが解除されます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/40692/d428d7a5-b30d-aeb4-1c29-e9f821815a0b.png)

1. 実行したいパイプライン(`01_pipeline_sample`)をクリックします
2. 実行したいジョブ(`job-sample`)をクリックします

![image.png](https://qiita-image-store.s3.amazonaws.com/0/40692/fb4e8ee9-9f35-6bde-f220-a465edd3d241.png)

画面右上の`+`ボタンををクリックするとジョブが実行されます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/40692/2c784675-8909-8be5-994d-7dab975547ee.png)

指定したDockerのコンテナイメージ(`alpine:3.7`)がpullされ、
指定したコマンド(`uname -a`)が実行されていることがわかると思います。


# 参考
今回のコードは全て、
[Fufuhu/concourse_sample](https://github.com/Fufuhu/concourse_sample)
の`01`ディレクトリ配下にアップロードしてあります。
次回以降も同じリポジトリにアップロードする予定です。
MicroPython on ESP8266

# MicroPython on ESP8266

Amica製NodeMCUでMicroPythonを使ってみたので、使い方や躓いたところのメモ。

> ホスト環境
> OS: elementaryOS Loki

## GettingStart

### 事前準備
NodeMCUにはUSB TypeB端子が付属している。
これでホストと接続できるが、接続にはCP210xドライバ(cp210x.ko)が必要。
(中国製の偽物の場合、ch34xとかいうものが必要になるらしい)

Linuxなら(おそらく)既に入っているはずだが、必要なら、[ここ](https://jp.silabs.com/products/development-tools/software/usb-to-uart-bridge-vcp-drivers)で落とす。

### micropython書き込みのための準備

- micropythonのESP8266用ファームウェアをダウンロード
    - https://micropython.org/download の Firmware for ESP8266 boardsからダウンロードできる
    - ここでは、`esp8266-20171101-v1.9.3.bin`をダウンロードした
- 書き込み用のツール esptool をインストール
    - `sudo -H pip esptool.py`

### 書き込む

USBでNodeMCUとホストを接続したら、以下の手順でmicropythonを書き込む。

- dmesgでNodeMCUがどのデバイスファイルに割り当てられたか確認する(だいたい`/dev/ttyUSB0`とかになってる)
- まずはフラッシュの内容を消去  
  ```
  sudo esptool.py --port /dev/ttyUSB0 erase_flash
  ```
- 次に事前にダウンロードしたファームウェアをインストール  
  ```
  sudo esptool.py --port /dev/ttyUSB0 --baud 9600 write_flash --flash_size=detect -fm dio 0 esp8266-20171101-v1.9.3.bin
  ```

## 触ってみる

- NodeMCUのmicropython対話型実行環境に接続する  
  ` sudo screen -R NodeMCU /dev/ttyUSB0`
- Lチカしてみる。machineモジュールでGPIOなどを操作することが可能。  

> ピン2はオンボードのLED

```python
import machine
import time
pin = machine.Pin(2, machine.Pin.OUT)
for i in range(10):
  pin.value(0)
  time.sleep(0.1)
  pin.value(1)
  time.sleep(0.1)
```

## 自作モジュールを作ってみる

Lチカのモジュールを作ってみる。
`LED.py`というファイルを作成し、その中にLチカのプログラムを記述する。

```python
f = open('LED.py', 'w')
f.write("""
import machine
import time

class LED(object):
  def __init__(self,pinNum, direction):
    self.pin = machine.Pin( pinNum, direction)

  def Blink(self, repeatTime, sleepTime):
    for i in range(repeatTime):
      self.pin.value(0)
      time.sleep(sleepTime)
      self.pin.value(1)
      time.sleep(sleepTime)

  def Notice(self):
    self.Blink(3, 0.1)

  def Alert(self):
    self.Blink(3, 0.05)
""")
f.close()
```

## メインループの作成

micropythonにはboot.pyとmain.pyの２つの特別なファイルがある。
boot.py → main.pyという順に実行される。
Arduinoで言うところの`setup()`がboot.py。`loop()`がmain.py。

今回はmain.pyを記述していく。

##### ファイルシステム
```python
import os
os.listdir()
```
で中身を確認出来る。

```python
os.mkdir('hogehoge')
```
でディレクトリ作成。

```python
os.rmdir('hogehoge')
```
でディレクトリ削除

##### main.pyの編集

main.pyが既にある場合、Errno 13が出てアクセスできないので一度削除する。

```python
os.rmdir('main.py')
os.listdir()
```
出力結果：　`['boot.py', 'LED.py']`

あとはLED.pyのときと同じ。

```python
f = open('main.py', 'w')
f.write("""
import machine
from LED import LED
import time
 
timeLED = LED(2, machine.Pin.OUT)
hourCount = 1
minCount = 1
 
while True:
    if hourCount == (60 * 60):
        timeLED.Notice()
        hourCount = 1
        minCount = 1
    elif minCount == 60:
        timeLED.Alert()
        minCount = 1
    else:
        timeLED.Blink(1,0.1)
    
    hourCount += 1
    minCount += 1
    time.sleep(1)
         
""")
f.close()
```
このあと、Ctrl+Dでリセット。

次はWifiを使ってなんかするつもり。
それにしてももっと楽にファイルを作成する方法はないものか……
ichigojamで赤外線リモコン

以前から気になっていたのですが、I2Cのサポートがあるようなのでichigojamを作って[I2C赤外線リモコン](https://qiita.com/yamori813/items/74c060bdc84950bccfc8)を試してみました。

![写真（2018-02-26 14.42）.jpg](https://qiita-image-store.s3.amazonaws.com/0/104066/4861e1f5-3393-36bc-c76c-06fa6e700df5.jpeg)

基板はBASICを触ってた頃に買ったと思われる、SunhayatoのICB-89で作ってみました。この基板は今は製造されてなくて、最近は同じサイズの秋月の基板を主に使っています。

赤外線LEDのドライブは[電脳伝説さんの回路](https://vintagechips.wordpress.com/2014/11/18/3-3v%E5%AF%BE%E5%BF%9C%E8%B5%A4%E5%A4%96%E7%B7%9Aled%E9%A7%86%E5%8B%95%E5%9B%9E%E8%B7%AF%E6%B1%BA%E5%AE%9A%E7%89%88/)を使わせてもらいました。

5Pin -> SDA
27Pin -> SCL

表示はUSBのアナログテレビキャプチャユニット(OV511+SAA7111A)を使って[macam](http://webcam-osx.sourceforge.net/)でMacのディスプレイに表示してみました。余談ですがmacamのOV511サポートは自分が15年くらい前に書いたコードです。

![スクリーンショット（2018-02-27 10.15.08）.png](https://qiita-image-store.s3.amazonaws.com/0/104066/088db81f-e87d-eeca-65ff-a39a9a59773c.png)


I2Cで書き込まれるデータは#700にPOKEしたものですが、I2CWの引数は二つなので[信号タイプとデータ](https://qiita.com/yamori813/items/6b69f662dbc9248ca0c6)を分けています。実際のI2Cバスでの書き込み時は連続して送られます。

上の画面の信号はSONYのCDプレイヤーのPlayボタンで動作しました。

AppleRemoteのMENUボタンも送ってみた。

![スクリーンショット（2018-05-03 11.05.23）.png](https://qiita-image-store.s3.amazonaws.com/0/104066/3cedb5f8-338b-1ea0-00e1-4a1161d3cce2.png)

BASICを使ったのは40年ぶりくらいかもしれません。中学生の頃はBASICで書いたプログラムなんてと馬鹿にしていたところがありましたが、年とってちゃんと動けばどんな言語でも良いと思えるようになりました。
最近の気づいたこと　python 

・if文を一行で書くやつ参考演算子っていうらしい
https://qiita.com/howmuch515/items/bf6d21f603d9736fb4a5

(変数) = (条件がTrueのときの値) if (条件) else (条件がFalseのときの値)

indexingをサポートしているモジュールだけが、[1]とかインデックスを指定できるよ

・sortted関数について
sorted(utterable,key=None,reverse=False)
Keyはiterableをforしてそれぞれの中身でどっちを比較対象にするか指定するものか

Forでくるくる回した中味がリストならlambdaを使って、引数から中味を持ってきて戻せばいいって感じ
Numpyの学習メモ

# NumPyとは

pythonでベクトルや行列計算を高速に行うのに特化したライブラリ。

### ライブラリをインストール

```
$ pip3 install numpy 
Collecting numpy
  Downloading numpy-1.14.1-cp36-cp36m-macosx_10_6_intel.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl (4.7MB)
    100% |████████████████████████████████| 4.7MB 178kB/s 
Installing collected packages: numpy
Successfully installed numpy-1.14.1
```

### ライブラリをインポートする

```python
import numpy as np 
```

### ndarrayクラス

配列を高速に扱うためにndarrayクラスが用意されている

#### ndarrayクラスの生成

##### リストから生成（`np.array(リスト)`）

```py
np_array = np.array([1,2,3])
print(np_array)
print(type(np_array))
```
```
[1 2 3]
<class 'numpy.ndarray'>
```

##### 連続したndarrayクラスの生成

```py
np_array = np.arange(4)
print(np_array)
print(type(np_array))
```

```
[0 1 2 3]
<class 'numpy.ndarray'>
```

### 複製

ndarrayクラスは`copy()`で複製を作成できる  
複製されたものは元のオブジェクトの影響を受けにない

```py
import numpy as np

np_array = np.arange(4)
np_array_cp = np_array.copy()

np_array[0:3] = 1

print(np_array)
print(np_array_cp)
```

```
[1 1 1 3]
[0 1 2 3]
```

### ブールインデックス参照

- 真偽値のリストを生成する
- 真偽値のリストから該当する要素だけを取り出す

```
np_array = np.arange(4)
boolean_list = np_array % 2 == 0

print(boolean_list)
print(np_array[boolean_list])
```

### ユニバーサル関数

```
np_array = np.array([-3, -2, -1, 0, 3, 6, 9])

print(np_array)

#絶対値
np_array_abs = np.abs(np_array)
print(np_array_abs)

#eのべき乗
print(np.exp(np_array))

#平方根
print(np.sqrt(np_array_abs))
```

```
[-3 -2 -1  0  3  6  9]
[3 2 1 0 3 6 9]
[4.97870684e-02 1.35335283e-01 3.67879441e-01 1.00000000e+00
 2.00855369e+01 4.03428793e+02 8.10308393e+03]
[1.73205081 1.41421356 1.         0.         1.73205081 2.44948974
 3.        ]
```
AWSに構築したWebサイトへのHTTPアクセスをFastly経由で行えるようにする

![fastly.png](https://qiita-image-store.s3.amazonaws.com/0/141934/e58e868b-ef33-9d3f-0774-44cdaf305613.png)

# 今回やったこと

- AWSに構築したWebサイトへのHTTPアクセスをFastly経由で行えるようにする

# 記事の内容について

- DNSにはRoute53を利用します
- ドメインはRoute53に登録済みとします
- WebサイトへのアクセスはHTTPとします
- 解説はロードバランサ、Webサーバの構築が完了した状態からスタートします
- コンソールでの設定について必要な箇所のみ抜粋して記載してます

# Before/After

![fastly01-2.png](https://qiita-image-store.s3.amazonaws.com/0/141934/66bd4e9e-6dfe-4a19-1f80-8e57b3e7eefb.png)

# 環境設定


## Fastly

Originサーバ（コンテンツ取得元）の情報を登録します。

![fastly02.png](https://qiita-image-store.s3.amazonaws.com/0/141934/333e5c7e-115f-ba18-f40b-2dda6b7661b0.png)

`Domain`にはブラウザからアクセスする際のドメインを指定します。
ワイルドカードも利用できるようですが、今回はお試しのため「www.ドメイン名」で指定しました。

`Address`にはOriginサーバのIPアドレスorホスト名を指定します。
今回の構成ではロードバランサのDNS名を指定しました。

その他の設定項目もありますが、今回はHTTPS接続は利用しないため、設定は行いませんでした。

> 参考
> [Sign up and create your first service \- Basic setup \| Fastly Help Guides](https://docs.fastly.com/guides/basic-setup/sign-up-and-create-your-first-service)


## Route53

WebサイトへのアクセスをFastly経由にするため、CNAMEレコードを追加します。

![fastly03.png](https://qiita-image-store.s3.amazonaws.com/0/141934/fe0e7806-bb63-122a-534c-02f70d61eb01.png)

`CNAME`にはFastlyのホスト名を指定します。

> 参考
> [Adding CNAME records \- Basic setup \| Fastly Help Guides](https://docs.fastly.com/guides/basic-setup/adding-cname-records)

## アクセス確認

8.8.8.8(Google Public DNS)に対して問い合わせを行って、レスポンスがFastlyになってることを確認。

```shell-session
$ nslookup www.xxx.xxx 8.8.8.8

Server:		8.8.8.8
Address:	8.8.8.8#53

Non-authoritative answer:
www.xxx.xxx	canonical name = nonssl.global.fastly.net.
Name:	nonssl.global.fastly.net
Address: xxx.xxx.xxx.xxx
Name:	nonssl.global.fastly.net
Address: xxx.xxx.xxx.xxx
Name:	nonssl.global.fastly.net
Address: xxx.xxx.xxx.xxx
Name:	nonssl.global.fastly.net
Address: xxx.xxx.xxx.xxx
```

ブラウザでWebサイトにアクセスを行ってページが表示されることを確認。
（画像くらい配置しておくんだった。。。）

![fastly05.png](https://qiita-image-store.s3.amazonaws.com/0/141934/9f8141f5-cd58-6724-091c-e637dbc994a3.png)

Fastlyのダッシュボードでステータスを確認。

![fastly04.png](https://qiita-image-store.s3.amazonaws.com/0/141934/2db64785-e2b2-2507-1f06-ddf42a4cde74.png)
Error: Default Activity Not Found　が出てビルドが通らなかったけど解決した。

#Error: Default Activity Not Found　が出てビルドが通らなかったけど解決した。

![スクリーンショット 2018-02-12 23.53.48.png](https://qiita-image-store.s3.amazonaws.com/0/148394/4879a8b5-e5c6-b237-d611-ec4da0760b68.png)

Error: Default Activity Not Found　　が出て、ビルドができず、
うんともすんとも言わない状態でしたが、解決したのでメモ書き。

コードは何も書いておらず、他のプロジェクトは動くので最初の設定で何かしてしまったかな？と思ったところ、


「Add an Activity to Mobile」にて「Add No Activity」を選んでいました。
![スクリーンショット 2018-02-25 17.37.55.png](https://qiita-image-store.s3.amazonaws.com/0/148394/8c736169-d8e5-fbc0-2c0d-5a527794d032.png)

＿人人人人人人人人人人人人人＿
＞　本当にActivityがいない　＜
￣Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y￣


![スクリーンショット 2018-02-13 21.28.16.png](https://qiita-image-store.s3.amazonaws.com/0/148394/d37b78ad-8a23-8ceb-c089-d0eab0dcb008.png)


＿人人人人人人人人人人人人人＿
＞　本当にActivityがいない　＜
￣Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y￣


『Error: Default Activity Not Found』が出た時の対処法
https://qiita.com/konifar/items/92307f5dacec90e63d91
を読んで、AndroidManifestを書き直しました🙏


書き直したところ、無事動きました！よかった！
[メモ]fastifyのhttp injection機能

## http injection

https://github.com/fastify/fastify/blob/master/docs/Testing.md

* fastifyのinstanceを作成する。

```javascript:app.js
const app = require('fastify')();

app.get('/users/:id', (req, reply) => {
  reply.send({ id: 2, name: 'piyo' });
});

app.post('/users', (req, reply) => {
  reply
    .code(201)
    .send({ id: 3, name: 'hogehoge' });
});

module.exports = app;
```

* http injection機能を利用する際は、`inject`メソッドを使用する。

* サーバをlistenすることなく、テスト等を実行できる。

```javascript:test.js
const test = require('tape');
const app = require('./app');

test.onFinish(() => {
  app.close();
});

test('GET /users/:id', async t => {
  t.plan(3);

  try {
    // 第2引数にNodeスタイルのcallback関数を渡すこともできる。
    // 省略した場合は、Promiseが返却される。
    const res = await app.inject({
      method: 'GET',
      url: '/users/2'
    });

    // tests
    t.equal(res.statusCode, 200);
    t.equal(res.headers['content-type'], 'application/json');
    t.deepEqual(JSON.parse(res.payload), {
      id: 2, 
      name: 'piyo'
    });
  } catch (e) {
    t.fail(e.message);
  }
});

```

* リクエストボディを指定したい場合は、`payload`プロパティに値を設定する。

```javascript
test('POST /users', async t => {
  t.plan(4);

  try {
    const res = await app.inject({
      method: 'POST',
      url: '/users',
      payload: { name: 'hogehoge' }
    });
    const payload = JSON.parse(res.payload);

    t.equal(res.statusCode, 201);
    t.equal(res.headers['content-type'], 'application/json');  
    t.equal(payload.name, 'hogehoge');
    t.ok(payload.hasOwnProperty('id'));
  } catch (e) {
    t.fail(e.message);
  }
});
```
herokuでcloud９から簡単デプロイ



まずは、herokuをインストール（https://signup.heroku.com/identity）

```
cd
sudo vi .profile
```

次にiを入力することにより入力画面へ移ります 

```
PATH="/usr/local/heroku/bin:$PATH"
export PATH
```
記述が終わったら、「esc」キーを押してから「:wq」で保存します

```
 source ~/.profile
```

# heroku toolbeltのアップデート
```
 sudo wget -qO- https://toolbelt.heroku.com/install.sh | sh 
```

続いて、herokuにログインします。

```
cd ~/environment/アプリ名
heroku login
```

続いてrailsのgemfileでの設定

```
 group :production do
  gem 'rails_12factor'
end
```

インストール

```
bundle install
```


herokuの作成

```
git init
heroku create
```

urlにアクセスしてみましょう！


gitの設定

```
git add .
```

gitの変更をコミット

```
git commit -m "update for upload to heroku"
```


デプロイをする

```
git push heroku master
```

DBを作る

```
heroku run rake db:migrate
```
シェルスクリプトで日付をループしてPHPに引数として渡す

時々必要になるのですが、多分1ヶ月後ぐらいにまた必要になるのでメモしておきます。

# 前提条件
- MacOS High Sierra 10.13.3
- PHP7.1.7

# 今回のお題

PHPで書かれたバッチ集計プログラムがあるとします。
通常は、毎日集計するプログラムでcronで日次実行するように設定済み。トラブル時に再実行可能なように、引数をつけたら指定した日付でも実行可能になっている・・・というよくあるやつ。
この集計プログラムに1項目追加になって、集計値も半年くらい前から見たい＝半年分再実行とかいう話になったら、手動で一日ずつやるとかいう忍耐と根性を試されてるみたいな真似はしたくない。というか、しない。

# コード

実行されるPHPをdate_test.php,シェルスクリプトをdate_test.shとし、同じディレクトリ内に置いてあるとします。
サンプルなので、実行されるPHP側は、引数が受け取れたことをvar_dumpで確認するだけにしています。

```php:date_test.php
<?php
var_dump($argv);
```


```sh:date_test.sh

#!/bin/sh

if [ $# -ne 2 ]; then
    echo "引数は2つ指定して下さい"
    exit 1
fi

START=$1
END=$2

echo "start script"
TARGET=$START
while :
do
    echo $TARGET
    php ./date_test.php $TARGET

    if [ $TARGET = $END ] ; then
        echo "end script"
        break
    fi

    TARGET=`date -d "$TARGET 1day" "+%Y-%m-%d"`
done
```

最低限のチェックとして引数が2つないと実行しないというのをつけました。

# 実行

1つ目の引数が集計開始日、２つ目が集計終了日になるように指定

```
$ ./date_test.sh 2017-07-01 2018-01-31
```

結果は

```
start script
2017-07-01
array(2) {
  [0]=>
  string(15) "./date_test.php"
  [1]=>
  string(10) "2017-07-01"
}
・・・略・・・
2018-01-31
array(2) {
  [0]=>
  string(15) "./date_test.php"
  [1]=>
  string(10) "2018-01-31"
}
end script
```

になります。

PHP側は、$argvは1つ目がスクリプトの名前になるので、引数は2つ目以降に入ってくるのが注意点ですかね。
日付として正しいかとかのチェックは、PHP側でやるのでもよろし。

シェルスクリプトは途中でechoしてどこまで進んでるかわかるようにするのが個人的にはおすすめです。
あと無限ループを作るときは、いきなりphpを実行するとかはやめて、echoだけにしてお望みの期間がぐるっと回るか確認してあげるとよいかと思います。（被害が少なくて済みますしね・・・）
実行権限は適切に与えてあげてください。誰でも実行できるぜーというのをドキュメントルートに置くとかダメ絶対。（本当にあった怖いお話・・・）

シェルスクリプトについては、参考サイトに貼ったURLで大抵のことは見つかるのでオススメです。

# おまけ

Macで上記のような日付計算しようとしたら

```
usage: date [-jnRu] [-d dst] [-r seconds] [-t west] [-v[+|-]val[ymwdHMS]] ...
            [-f fmt date | [[[mm]dd]HH]MM[[cc]yy][.ss]] [+format]
```

とか言われたので、ちょっと調べて以下のbrewコマンドを実行しました

```
brew install coreutils
```

PATH通せってメッセージに出てたので、.bash_profileに

```
PATH="/usr/local/opt/coreutils/libexec/gnubin:$PATH"
```

どうやら、Macのdateコマンドは一般的なLinuxと違うらしい・・・
何で実行できないのか、しばらく悩んじゃったじゃないか

# 参考サイト

http://shellscript.sunone.me/while.html
Rustの"&"と"ref"の違い

# この記事は

なんかよくわからないなーと思っていた時に良いISSUEを見つけたので、備忘録としてまとめるものである。
cf: [borrow/ref: Not clear what's the difference between ref and & · Issue #390 · rust-lang/rust-by-example](https://github.com/rust-lang/rust-by-example/issues/390)

# "&"とは

公式？だと[ここ](https://rustbyexample.com/scope/borrow.html)あたり
参照のこと。リソースの所有権を借用することを意味する。
基本的に借用というコンテキストで語られることには"&"を利用する模様。

# "ref"とは

公式？の[ここ](http://rust-lang-ja.org/rust-by-example/scope/borrow/ref.html)によると
借用というよりも構造体やタプルのメンバーをデストラクトすることを想定している模様。

# "ref"と"&"で束縛してみる

```rust
fn main() {
    let x = 123;

    let x_ref_1 = &x;
    let ref x_ref_2 = &x;
    let &x_ref_3 = x;
    let ref x_ref_4 = x;
    
    assert_eq!(x, *x_ref_1); // x_ref_1 == &x なのでOK
    assert_eq!(x, *x_ref_2); // x_ref_2 == &&x なのでエラー
    assert_eq!(x, *x_ref_3); // &x_ref_3 と x での束縛がmissmatch typeエラー
    assert_eq!(x, *x_ref_4); // x_ref_4 == &x なのでOK
}
```
syntaxとしては、"&"は"*"と同様な扱い。
一方、"ref"は"mut"とかと同様な扱いといった感じ。
基本的に参照による束縛を行う時に使うが、"&"は右辺、"ref"は左辺で参照であることを示すときにそれぞれ用いる感じっぽい。

# "ref"と"&"でデストラクトしてみる

```rust
fn main() {
    let x = 3;
    let s1 = Some(&x);
    assert_eq!(s1.unwrap(), &x);
    
    let s2 = Some(x);
    assert_eq!(s2.unwrap(), x);
    
    match s1 {
        Some(y) => assert_eq!(y, &x),
        None => {},
    }
    match s1 {
        Some(&y) => assert_eq!(y, x),
        None => {},
    }
    match s1 {
        Some(ref y) => assert_eq!(y, &&x),
        None => {},
    }
    
    match s2 {
        Some(y) => assert_eq!(y, x),
        None => {},
    }
    /* エラー
    match s2 {
        Some(&y) => assert_eq!(y, &x),
        None => {},
    }*/
    match s2 {
        Some(ref y) => assert_eq!(y, &x),
        None => {},
    }
}
```
`match Option(&x) { Some(&y) => assert_eq!(y, x), ... }`
なるほどそりゃそうだ感ある。

# 結論

左辺にref、右辺に&とでも覚えておけばよい感。
今の所、refが完全に要らない子なんだが。。

所有権持ってる状態で、借用を起こさずに参照を取るためには"ref"を使うのかな。
もうちょっと書いてたら腹落ちしそう。
Smallchatを使ってSlack連携するホームページ

ホームページで、チャットを使って質問できる機能を見かけるので、普段使っているSlackと連携できないかなと思い調べてみました。
#Smallchatとは
* ホームページ上で、指定したSlackのチャンネルとチャットができる
* タグを埋め込むだけでOK

#Slackの準備
* [こちら](https://slack.com/intl/ja-jp)からアカウントとチームを準備してください

#Smallchatの準備
* 基本的に無料です。（有料コンテンツもあります）
* [こちら](https://small.chat/)にアクセスして、「Add to Slack」を押します。
<img width="1308" alt="スクリーンショット 2018-02-25 16.01.41.png" src="https://qiita-image-store.s3.amazonaws.com/0/203706/280bcad0-dcdc-d51e-393c-b62b7f2822d7.png">
* チームを洗濯してAutorizeを押します。
![スクリーンショット 2018-02-25 16.06.01.png](https://qiita-image-store.s3.amazonaws.com/0/203706/b18883ce-98e6-e799-efbd-59140568b136.png)
* チャット用のチャンネルを作成します。すると、dashboard画面が表示され、ホームページに埋め込むScriptが表示されます。
![スクリーンショット 2018-02-25 16.16.33.png](https://qiita-image-store.s3.amazonaws.com/0/203706/9760be9b-bf7c-8f2c-4a6a-f4c5dbcf73f1.png)
* これで準備完了です。

#ホームページにScriptを埋め込む
* 先ほど表示されたScriptをホームページのHTMLファイルに埋め込みます。すると...
<img width="1435" alt="スクリーンショット 2018-02-25 16.22.07.png" src="https://qiita-image-store.s3.amazonaws.com/0/203706/cecceddd-0592-a0b1-40e6-19b6eb203983.png">
* 右下にアイコンが表示されます! このアイコンを押すと、
<img width="319" alt="スクリーンショット 2018-02-25 16.24.14.png" src="https://qiita-image-store.s3.amazonaws.com/0/203706/1a4edce1-7cbb-fc24-ef4b-1d6e287fd2e5.png">
* チャットができる画面が現れます。こちらにメッセージを入力すると、先ほど作成したチャンネルにメッセージが飛びます。
![スクリーンショット 2018-02-25 16.26.41.png](https://qiita-image-store.s3.amazonaws.com/0/203706/56edcfe4-b6ea-da8f-982c-39d4678cd11c.png)


#設定の変更
* Smallchatのdashboardから設定ができます。例えば、
  * アイコンの形
  * アイコンの色
  * タイトル文字変更
  * 入力フォームのデフォルト文字変更
* チャンネルの追加、自動応答の機能は有料コンテンツになります。（今回は試していません）

# 感想
簡単に自分のホームページにチャット機能を埋め込むことができて感動しました!有料コンテンツの自動応答の機能も便利そうですね！
TypeScript のトランスパイルを babel に任せる

## モチベーション

TypeScript でも babel-preset-env などの babel エコシステムにのりたい。

## やり方

babel 7 から TypeScript のパースも出来るようになったのでそれで行う。

`@babel/preset-typescript` をインストールして .babelrc に設定する。

```:sh
yarn add -D @babel/preset-typescript
```

```:.babelrc
{
  "presets": [
    "@babel/preset-typescript"
  ]
}
```

以上

## 落とし穴

実はこれだけだと型がおかしい場合などにコンパイルエラーが起きない。
開発中はエディタなり IDE なりでエラーが出せるとは思うが、型があるのに型エラーが出ないのは何のための型なのかわからない。
なのでテストなりトランスパイルの前にコンパイルが通るかチェックする必要がある。

```:package.json
{
  "scripts": {
    "test:compile": "tsc --noEmit"
  }
}
```

エディタなどに支援されているがために気づかず怖いことになってしまいそう (๑•́‧̫•̀๑)
「CloudMapper」を試してみた

AWSで環境構築してみたものの、自分が設計した通りの構成図になっているか不安だったので、ちょうどそこにcloudmapperなるものがオープンソース化されたということなので、試してみました。
ここに記載されている内容は主に
https://github.com/duo-labs/cloudmapper/blob/master/README.md
を参考にしています

## 環境
macOS High Sierra ver10.13.3
python3のインストール済み

# cloudmapperのインストール
```
$ git clone https://github.com/duo-labs/cloudmapper.git
$ cd $_
```

# 必要なツール等をインストール
```
$ brew install autoconf automake libtool jq
```

# python環境での実行なのでvirtualenvを使用
```
$ pip3 install --upgrade pip
$ pip3 install virtualenv
#### 以下、cloudmapperディレクトリ配下で実行
$ virtualenv venv
$ source venv/bin/activate
$ pip3 install -r requirements.txt
```
これでとりあえずは起動できるところまできました

# demoファイルで実行してみる
```
$ python cloudmapper.py prepare --config config.json.demo --account demo
$ python cloudmapper.py serve
```
ブラウザで確認 http://127.0.0.1:8000/

![FireShot Capture 15 - Duo CloudMapper - http___localhost_8000_.png](https://qiita-image-store.s3.amazonaws.com/0/107164/ff43766e-df11-1d65-a7c6-d7c84c057129.png)

表示されたら動作としてはOKです

ではいよいよ、自分で構築したAWS環境のネットワーク図を作成します

# configファイルの作成
```
$ cp config.json.demo config.json
```

```json:config.json

{  "accounts":
    [
        {"id": "123456789012", "name": "aws_cloudmapper", "default": true}
    ],
    "cidrs":
    {
        "1.1.1.1/32": {"name": "SF Office"},
        "2.2.2.2/28": {"name": "NY Office"}
    }
}
```
nameの部分のみを適当に変えます





# cloudmapper専用のポリシーを作成
cloudmapperが対象のAWSアカウントにアクセスが可能な状態にする必要があります

AWSコンソールから「IAM」→「ポリシー」→「ポリシーの作成」に移動します

ポリシーの作成画面でJSONを選択して以下の内容で作成します
ポリシー名はcloudmapper-readonlyにしました（好きな命名にしてください）

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Resource": "*",
            "Action": [
                "ec2:DescribeRegions",
                "ec2:DescribeAvailabilityZones",
                "ec2:DescribeVpcs",
                "ec2:DescribeSubnets",
                "ec2:DescribeSecurityGroups",
                "ec2:DescribeVpcPeeringConnections",
                "ec2:DescribeInstances",
                "ec2:DescribeNetworkInterfaces",
                "rds:DescribeDBInstances",
                "elasticloadbalancing:DescribeLoadBalancers"
            ]
        }
    ]
}
```

# IAMユーザーの作成
上記で作成したcloudmapper-readonly権限をもったIAMユーザーを作成します。
発行されたアクセスキーIDとシークレットキーは次のステップで使用するので、保管しておいてください

# ~/.aws/configの設定

```sh:~/.aws/config
[profile cloudmapper]
output = json
region = ap-northeast-1
```


# ~/.aws/credentialsの設定
先ほど作成したIAMユーザーのkeyを設定

```sh:~/.aws/credentials
[cloudmapper]
aws_access_key_id = ****************
aws_secret_access_key = *******************************
```

これでcloudmapperがAWSにアクセス可能となります

# ネットワーク構成図を作成
さて、いよいよ自分で構築したAWS環境の構成図を作成したと思います

githubからインストールしたcloudmapperディレクトリに移動します。そしてAWSから構築した環境の情報を取得します。

```
$ cd ~/cloudmapper
$ source venv/bin/activate
(venv) $ ./collect_data.sh --account aws_cloudmapper --profile cloudmapper
```

無事取得されたら```aws_cloudmapper```ディレクトリが作成されます

そしていよいよネットワーク構成図を出力します

```
(venv) $ python cloudmapper.py prepare --account aws_cloudmapper
$ python cloudmapper.py serve
```

ブラウザで確認 http://127.0.0.1:8000/

表示されたら成功です。

簡単ではありますが、以上となります。
Windows10にLinux環境標準装備

元々ウインドウズ派で、ソフト開発なんかもウインドウズで開発するつもりであったが、知らぬまに開発舞台のスタンダードは、macになっていててさすがに未熟なわたしでは抵抗もできずマックノートを購入して、こちらのブログ等はmacで作ってます。
しかしながら、ウインドウズノートは使い続けている状況で、休日はノートを２台持ち歩いている状況。
要は、ウインドウズパソコン内でリナックス環境を作るのは非常に困難なためです。

そこで、期待したいのが、ウインドウズ１０にリナックス環境が標準装備されることです。<a href="https://forest.watch.impress.co.jp/docs/news/1069839.html">参考サイト</a><br>
Ubuntu ウブントゥと読みます。
しかし、まだまだ未完成との情報もありすぐに飛びつくはまずいようです。
まあ、環境はそんなに気にせずプログラムをどんどん書きたい派なのでこの企画に期待したいです。頑張って下さい、マイクロソフトさん。

<a href="http://www.freestyle-life.site:3000/posts/">マイサイト</a><br>
不確実性に備えるバッファの計画

# バッファの種類

バッファには2つの種類がある。

- フューチャーバッファ(機能バッファ)
- スケジュールバッファ

## フューチャーバッファ
機能として持たせておくバッファ。
例えるなら、37個の買い物リストがあるうち、買わなくてもいい優先度の低いリスト

## スケジュールバッファ
スケジュールとして持たせておくバッファ
例えるなら、空港に行くときに事前に1時間余裕を持って家を出るなど

# 見積もりの単位

理想時間でもストーリーポイントでも、規模が図れるものであればなんでもいい

# 見積もりに不確実性を反映させる

以下の2つの見積もりを利用する。

- 平均ケース(50%見積もり)
- 最悪ケース(90%見積もり)

例:6つのユーザーストーリーに対するプロジェクト全体のスケジュールバッファの算出

|ユーザーストーリー|平均ケース|最悪ケース|(最悪-平均)の2乗|
|:------------|-------:|:------:|-------------:|
| ストーリー１　　　　　　　　　|5       |13      |64            |
| ストーリー2　　　　　　　　　|1       |3       |4            |
| ストーリー3　　　　　　　　　|3       |5       |4            |
| ストーリー4　　　　　　　　　|5       |8       |9            |
| ストーリー5　　　　　　　　　|2       |5       |9            |
| ストーリー6　　　　　　　　　|1       |1       |0            |
|縦列の合計     |17      |35      |90           |

この場合、90に注目する。
90の平方根である9.4の小数点を丸めた値、9をバッファとし、平均ケースに足すことで
17+9がバッファを見込んだ数値となる。

# 最後に

バッファは水増しではない。
車の車間距離のようなものなので、バッファについて聞かれたら公明正大に答えよう。