OmniAICreator/Qiita-1.07M huggingface dataset:
【Docker】Alpine Linuxにhubをインストールしようとしたら躓いたので、解決策を残す

## 困ったこと
git操作を行えるdocker imageを作ろうと思い、Alpine Linuxイメージにgit, hubをインストールしようとしていました。
gitのインストールはパッケージを使えば簡単ですが、pull requestを作るために必要なhubは、安定して使えるパッケージがないので、バイナリファイルをインストールして使おうとしました。

hubを入れてhubコマンドを実行すると`hub: not found`とエラーが出てしまいました。

```Dockerfile:Dockerfile
FROM alpine:latest
RUN apk update && apk add git bash wget
RUN wget https://github.com/github/hub/releases/download/v2.12.8/hub-linux-amd64-2.12.8.tgz && \
    tar xzf hub-linux-amd64-2.12.8.tgz && \
    mv hub-linux-amd64-2.12.8/bin/hub usr/local/bin/ && \
    rm hub-linux-amd64-2.12.8.tgz && \
    rm -r hub-linux-amd64-2.12.8
```

```sh
which -a hub
usr/local/bin/hub

hub
bin/sh: hub: not found
```

## 原因
（まだ理解が浅いのですが）Alpine Linuxではglibcではなく、musl-libcを使っているため、バイナリファイルをインストールして使おうとしたときに、うまく動いてくれないことがあるようです。

## 結論
以下3つの解決策があります。
### 1. パッケージが用意されているDebianやUbuntuを使う。
私はこのイメージを業務で使いたかったので、パッケージをインストールすれば使えるかつ、安定していそうな、この方法を選びました。 デメリットはAlpine Linuxイメージを使う場合よりもイメージが重たくなることです。

```Dockerfile:Dockerfile
FROM debian:latest
RUN apt update && apt install -y git hub
```

### 2. edgeバージョンのhubパッケージをインストールする。
edgeバージョンでしたらhubのパッケージがありますので、これをインストールして使用します。
https://pkgs.alpinelinux.org/packages?name=hub

※なお、edgeバージョンは開発中で安定していないため、本番環境には適しません。

```Dockerfile:Dockerfile
FROM alpine:latest
RUN echo "http://dl-cdn.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories
RUN apk update && apk add git hub bash
```
### 3.シンボリックリンクを張る。
`libc6-compat`というパッケージをインストールするとシンボリックリンクが張られ、hubコマンドを使えるようになりました。

```Dockerfile:Dockerfile
FROM alpine:latest
RUN apk update && apk add git bash wget libc6-compat
RUN wget https://github.com/github/hub/releases/download/v2.12.8/hub-linux-amd64-2.12.8.tgz && \
    tar xzf hub-linux-amd64-2.12.8.tgz && \
    mv hub-linux-amd64-2.12.8/bin/hub usr/local/bin/ && \
    rm hub-linux-amd64-2.12.8.tgz && \
    rm -r hub-linux-amd64-2.12.8
```

## まとめ
安定して動いて欲しい場合は、1の方法が良さそうです。
趣味など不安定でも良い場合は、2か3の方法で良いと思います。

## 参照
[Problem with the linux binaries on Alpine #1818](https://github.com/github/hub/issues/1818)
[Alpine Linux で適当なバイナリを持ってきて動かす備忘録](https://www.labohyt.net/blog/server/post-3272/)
[glibc がリンクされた binary を alpine 上で動かしたい](https://qiita.com/skame/items/12d12fef0902d162279e#_reference-dca814c90b2c9b30e932)
Rails6が立ち上がらない！Node.js, webpacker, yarnのインストール 【開発日記】薬価検索アプリno.5-2 

##出来上がりのサイト
薬価検索アプリmedipraはこちらです
→　[見に行ってみる](https://www.medipra.net)

##2020/04/12更新
ブログの方に移動しました
→　[こちら](https://sugainote.com/rails6-start-up/)



###前回の内容はこちら。
[【開発日記】薬価検索アプリno.5 〜Railsでアプリケーションの雛形作成、mySQLエラー、GitHubの設定まで〜](https://qiita.com/pharma_tech3/items/0d6f14e889a40dffee3b)

###開発背景などはこちら
[【開発日記】薬価検索アプリno.1 〜開発概要→企画〜](https://qiita.com/pharma_tech3/items/51c9a670c605098bc3bf)



##現在の進捗状況
1.必要な機能の洗い出し
2.必要な画面設計
3.データベース設計
4.Railsでアプリケーションの雛形作成 ⬅︎今ココ
5.大きな機能から順に実装　
6.テストコードを書いて動作を担保する
7.リファクタリングして整理する
8.デプロイ



#rails sしてみたら...
前回、 `rails new` してアプリケーションの雛形を作りました。
そのまま勢いでrails sしたのですが...

```terminal
=> Booting Puma
=> Rails 6.0.0 application starting in development 
=> Run `rails server --help` for more startup options
RAILS_ENV=development environment is not defined in config/webpacker.yml, falling back to production environment
Exiting
Traceback (most recent call last):
	68: from bin/rails:4:in `<main>'

#中略

2: from /Users/user/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/webpacker-4.0.7/lib/webpacker/configuration.rb:84:in `data'
	 1: from /Users/user/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/webpacker-4.0.7/lib/webpacker/configuration.rb:87:in `load'
/Users/user/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/webpacker-4.0.7/lib/webpacker/configuration.rb:91:in `rescue in load': Webpacker configuration file not found /Users/user/projects/medipra/config/webpacker.yml. Please run rails webpacker:install Error: No such file or directory @ rb_sysopen - /Users/user/projects/medipra/config/webpacker.yml (RuntimeError)
```

と、エラーが出てしまいました。

#Rails6からの変更点
完全に僕の勉強不足なのですが、
**Rails6から標準でwebpackを利用する** ようになっています。

エラー文に `rails webpacker:install` を実行しろとあるのでやってみます。


## Node.js, webpacker, yarnのインストール


```terminal
$ rails webpacker:install

=>
sh: node: command not found
sh: nodejs: command not found
Node.js not installed. Please download and install Node.js https://nodejs.org/en/download/
```

今度はnode.jsを入れろと言われてしまいました。

Homebrewを使ってインストールします。


```terminal
$ brew install node
```

Node.jsがインストールできたら次のコマンドで確認しましょう

```terminal
$ node -v
=>v12.12.0
```

ちゃんとインストールされたことが確認できました。

ではもう一回webpackerをインストールします。

```terminal
$ rails webpacker:install
=>Yarn not installed. Please download and install Yarn from https://yarnpkg.com/lang/en/docs/install/
```

今度はyarnがないと叱られてしまいました。


調べてみるとｙａｒｎはNode.jsの環境で使うパッケージマネージャー。Rubyで言う所のbundlerのようなものでしょうか。

またhomebrewを使ってインストールします。

```terminal
$ brew install yarn
```

完了したら、確認してみます。

```terminal
$ yarn -v
=> 1.19.1
```
ではもう一回webpackerをば。

```terminal
$ rails webpacker:install
```

こんなのが出れば完了です！
[![Image from Gyazo](https://i.gyazo.com/7e864435a00a7830c7ae62da4852dec6.png)](https://gyazo.com/7e864435a00a7830c7ae62da4852dec6)


これでrails s入れたらおなじみの画面が表示されました。

めでたしめでたし。



#まとめ・所感
新しく出たRails6を使いたいがばかりに見切り発車してしまいましたが、大きな仕様変更を確認していなかった自分の勉強不足ですね。

こちらの雑誌にもしっかり掲載されていました。
しっかり勉強します！
amazonへのリンク（アフィリエイトではないです）
https://www.amazon.co.jp/gp/product/4297108690/ref=ppx_yo_dt_b_asin_title_o00_s00?ie=UTF8&psc=1


最後までお付き合いいただきありがとうございました。
Rails3.2で404ページを使う

きっかけは、削除したIDを探したときに表示される「ActiveRecord::RecordNotFound」がかっこ悪いから。

# 各コントローラーで対処
[findよりfind_by_idでActiveRecord::RecordNotFoundを回避する](https://pumpkin.hatenablog.jp/entry/20090920/1253416605)を参考にして

```ruby:hoge_controller.rb
#@hoge = Hoge.find(params[:id])
@hoge = Hoge.find_by_id(params[:id])
```
`find_by_id`で、見つからなければnilになる

```ruby:hoge_controller.rb
@hoge = Hoge.find_by_id(params[:id])

if @hoge 
 (あったときのアクション)
else
 render :template => '/common/error_404'
end
```
動いたけど、これを全部でやるのはめんどくさい。

# ActionControllerで対処
[Rails3で404エラー画面作成](http://keep-up-with-tech.blogspot.com/2013/09/rails3404.html)
ひとまとめにできるので、こっちに切り替えた

renderに変数を渡したい。
参考：[render先に変数が上手く渡らないときに確認すること](https://qiita.com/bambis13s/items/015f5bf921eb820ef652)

```ruby:application_controller.rb
#rescue_from ActionController::UnknownAction, :with => :error_404
rescue_from ActiveRecord::RecordNotFound, :with => :error_404

def error_404(exception = nil)
  @ex = exception
  render :template => '/common/error_404', ex: @ex, :status => 404 
end
```
`ActionController::UnknownAction`で存在しないアクションが引っかからないのでコメントアウトした。
参考：[uninitialized constant ActionController::UnknownAction (NameError) when starting the web server](https://stackoverflow.com/questions/28545520/uninitialized-constant-actioncontrollerunknownaction-nameerror-when-starting)

```ruby:error_404.html.erb
<%- if @ex %>
<p><%= @ex %></p>
<%- end %>

<%- if params[:id] %>
	<p>すまん、「ID：<%= params[:id] %>」は見つからんかった</p>　
	<%= image_tag("cat.jpg")%>
<%- else %>
	<p>そんなページはありゃーせんのじゃー</p>
	<%= image_tag("dog.jpg")%>
<%- end %>
```
エラーの「ActionNotFound」「RecordNotFound」を記述したいけど、取り出し方がわからなかった。
Rubyでバブルソートを表現してみよう

ryoです。三日坊主してると思いました？自分も思ってました。
unityのアプリを作ってたのですが、自分で理解できなくて、アウトプット出来ないんです。すみません。
バブルソートというものを勉強したのでRailsで表現できるように挑戦しようと思います。

## この記事を見て身につくこと
・バブルソートの意味がわかる
・Rubyでバブルソートを表現できる


##　目次
- そもそもバブルソートって何？
- バブルソートのルールと手順
- 完成コード
- 各行のコード解説
- その他のソートの種類
- 実は・・・

## そもそもバブルソートって何？

**バブルソート**とは、ソートアルゴリズムの一つです。
**ソートアルゴリズム**とは、データを整列するための方法みたいものです。ソートというのが整列という意味なので、そのままです。

ではバブルソートとは、どうやってデータを整列していくものかについて見ていきます。

## バブルソートの手順、ルール

- 先頭の要素'A'と隣り合う次の要素'B'の値を比較する
- 要素'A'が要素'B'より大きいなら、要素'A'と要素'B'の値を交換する
- 先頭の要素を'B'に移し、要素'B'と隣り合う要素'C'の値を比較/交換する
- 先頭の要素を'C','D','E'...と移動しながら比較/交換をリストの終端まで繰り返す
- 最も大きい値を持つ要素がリストの終端へ浮かびあがる
- リストの終端には最も大きな値が入っているので、リストの終端の位置をずらして(要素数をひとつ減らして)
- 上記手順を繰り返す

[ここの手順を引用させてもらいましたイメージ図もこちらにあります。](https://www.codereading.com/algo_and_ds/algo/bubble_sort.html)


## 完成コード

```ruby:test.rb
def bubblesort(int)

  datas = int.chars.map(&:to_i)

  datas.length.times do |data|
    (datas.length - (data + 1)).times do |array|
        if datas[array] > datas[array + 1]
            datas[array],datas[array + 1] = datas[array + 1],datas[array]
        end
        puts datas.join
    end
  end
end

puts "整列させる数値を入力してください"

bubblesort(gets.chomp)
```

出力結果

```
整列させる数値を入力してください
94783 #入力
49783
47983
47893
47839
47839
47839
47389
47389
43789
34789

```

## 各行のコード解説

def内は呼び出されるまで動かないので一旦下から読み始めます。

まずは数値を入力してもらいます。

```ruby:test.rb
puts "整列させる数値を入力してください"
bubblesort(gets.chomp)
```

入力した数値をbubblesort内に持っていって色々します。

```ruby:test.rb
def bubblesort(int)
```

入力されたものをcharsで１文字ずつに分割してmapで数値に変更します

```ruby:test.rb
  datas = int.chars.map(&:to_i)
```

文字の数だけ繰り返す記述です。

```ruby:test.rb
  datas.length.times do |data|
```


１文字ずつ処理するための記述です。２文字目、３文字目になるにつれて右側の数値が確定していくので、
確定した文字分処理を減らします。

```ruby:test.rb
    (datas.length - (data + 1)).times do |array|
```

```
整列させる数値を入力してください
94783 #入力
49783
47983
47893
47839　＃この時点で一番右は確定しているから比較する必要がなくなる。
```


現在の要素と、次の要素を比較して現在の要素が大きいか確認します。

```ruby:test.rb
        if datas[array] > datas[array + 1]
```

大きかった時は、要素を入れ替えます。

```ruby:test.rb
            datas[array],datas[array + 1] = datas[array + 1],datas[array]
```

```
整列させる数値を入力してください
94783 #入力
49783 #９と４を比べて、９の方が大きいから入れ替えている
```


ばらけさせてる数字を連結させます。処理の動きがわかりやすいようにtimes内に入れてますが
結果だけを知りたい場合はもっと下のendに下記記述を移動すれば結果だけ出るようになります。

```ruby:test.rb
        puts datas.join
```

## その他のソートの種類

- バケットソート（ビンソート）
- 基数ソート
- ヒープソート
- マージソート（併合ソート）
- クイックソート
等、色々あります。

## 実は・・
今回は動きがわかりやすいように
コードを紹介しましたが、ソートは各言語で簡単にできるようになっているんです。

rubyの場合sortというものがあるので、下記でソートは完了してしまいます。便利ですね。

```ruby:test.rb

def bubblesort(int)
  datas = int.chars.map(&:to_i)
  datas.sort!
  puts datas.join
end

puts "整列させる数値を入力してください"

bubblesort(gets.chomp)
```

出力結果

```
整列させる数値を入力してください
956217329 #入力
122356799
```


だから、普段はあんまり意識する必要ないけど、バブルソートってどんなんだろう？って思った時に思い出してあげてください。お疲れ様でした。
Golangでベクトル演算を高速化しようとしてみた話

# はじめに

Goでスライスのベクトル演算などを書いてたときに、今までは

```go
for i := 0; i<len(slice); i++ {...}
```

のように素直にfor文で全要素にアクセスしてました。  

もっと速い演算方法は無いかと考えていたところ、

```go
for i := 0; i<cpus; i++ {
    go func{...}
}
```

のようにcpuコア数に合わせてsliceを分割し、goroutineで並行処理する方法を思いつきました。

ということで、実際に速度の検証をしてみました。


# 結論から言うと...

~~むしろ遅くなりました。~~  

__2019/11/01追記__  


要素数10万以上では、goroutineを使用したほうが速くなりました。（環境によります。）  

検証コードはスライスに数字を代入しているだけなので、演算時間が逆転する要素数が多くなっています。   しかし、べき乗や平方根を求めるなどの重い処理をする場合、goroutineの旨みが増すことが予想できます。

以下は検証のコードなので、興味のある方は見て頂けると幸いです。

# 環境
- MacBook Pro 2019
- macOS Catalina
- 2.4 GHz Quad-Core Intel Core i5
- Go 1.13.1

# 検証

## 素直にfor文

```go
func main() {
	n := 100000000
	is := make([]int, n)
	fmt.Println("==START==")

	start := time.Now()
	for i := 0; i < n; i++ {
		func(i int) { is[i] = i }(i)
	}
	end := time.Now()

	fmt.Println("==END==")
	fmt.Println(end.Sub(start))
}
```

```terminal
$ go run main.go
==START==
==END==
309.95595ms
```

1億回で310msでした。


## cpu数に合わせて並行処理

```go
func main() {
	fmt.Printf("Number of cpus: %v\n", runtime.NumCPU())
	wg := &sync.WaitGroup{}
	cpus := runtime.NumCPU()
	n := 100000000
	is := make([]int, n)
	fmt.Println("==START==")

	start := time.Now()
	jMax := n / cpus
	for i := 0; i < cpus; i++ {
		wg.Add(1)
		go func(i int) {
			defer wg.Done()
			/* 遅いコード
			   for j := 0; j < n/cpus; j++ {
			       is[i*n/cpus+j] = i*n/cpus + j
			   }
			*/
			offset := i * jMax
			for j := 0; j < jMax; j++ {
				is[offset+j] = offset + j
			}
		}(i)
	}
	wg.Wait()
	end := time.Now()

	fmt.Println("==END==")
	fmt.Println(end.Sub(start))
}
```

```terminal
$ go run main.go
Number of cpus: 8
==START==
==END==
88.946429ms
```

1億回を8個のgoroutineで処理して、89msでした。  
要素数が多い場合、goroutineを使用したほうがかなり速いです。

## cgoで実行

```go
/*
void vec(long *is, long n){
    for (int i=0; i<n; i++) {
        is[i] = i;
    }
}
*/
import "C"

func main() {
	fmt.Println("==START==")

	n := 100000000
	is := make([]int, n)

	start := time.Now()
	C.vec((*C.long)(unsafe.Pointer(&is[0])), (C.long)(n))
	end := time.Now()
	time.Sleep(time.Second)

	fmt.Println("==END==")
	fmt.Println(end.Sub(start))
}
```

```terminal
$ go run main.go
==START==
==END==
271.969568ms
```
cgoはそこそこの結果に終わりました。

- メモリセーフでない
- コードが読みづらくなる

ことを考慮すると、よっぽどの理由がない限りgoroutineを使うのがよいと思います。

> ちなみにpyhtonでも実行してみました。
>
> ```python
> import time
> import numpy as np
> 
> print("==START==")
> start = time.time()
> iarr = np.arange(100000000)
> duration = time.time() - start
> print("==END==")
> 
> print(str(duration*1000) + "ms")
> ```
> 
> ```terminal
> python main.py
> ==START==
> ==END==
> 304.9652576446533ms
> ```
> 書きやすさと速度を考えると、numpyは偉大ですね。

## 要素数を増減して検証
演算回数を1万回、10万回、100億回に変えて実行してみます。

| 演算回数 	|   生go  	| goroutine 	|   cgo   	|
|:------:	|:-------:	|:---------:	|:-------:	|
|   1万  	| 0.035ms 	|  0.087ms  	| 0.038ms 	|
|  10万  	|  0.43ms 	|   0.34ms  	|  0.39ms 	|
|   1億  	|  309ms  	|    89ms   	|  272ms  	|
|  100億 	|   47s   	|    38s    	|   43s  	|

演算回数10万回以上ではgoroutineが速くなりました。  

cgoは演算回数が増えると生goよりも速くなりました。シングルコアの環境であれば、cgoを使うのも有効かもしれません。

 
# おわりに

冒頭にも書きましたが、演算数が増えたり、内容が重くなったりするとgoroutineの効果が大きく出ると思います。 

信号処理をgoで書いてるので、機会があればQiitaにも投稿しようと思います。
コンテナ上からbastion経由でRDSに接続する

#はじめに
Docker container上で動くPythonからAWSのRDSインスタンスに接続したくなりました。

VPCのプライベートサブネットにRDSを配置しているために直接接続することができないため、
パブリックサブネットにEC2インスタンスを立ててBastion（踏み台）として機能させます。
というのが以前までのベストプラクティス？のようでした（[注記](#注記)参照）。

今回も上記方法で接続してみました。

#前提
AWS RDSインスタンスが構築されていること。
bastionとして機能させるEC2インスタンスが立ち上がっていること。
RDSのセキュリティグループでEC2(bastion)からの接続が許可されていること（[参考ページ](https://dev.classmethod.jp/cloud/aws/rds-portforward/#toc-2)）。
EC2(bastion)のセキュリティグループでSSH接続が許可されていること。

検証環境
Windows10 Pro
Docker for Windows 2.1.0.3
RDSインスタンス：MySQL 5.7

#Bastion側の設定

###SSH接続をタイムアウトしないようにする(サーバ側設定)

sshdの設定ファイルを変更します。
`sudo vi /etc/ssh/sshd_config`


変更前

```configuration:sshd_config
#ClientAliveInterval 0
```

変更後

```config:sshd_config
ClientAliveInterval 30
```

今回はローカルフォワーディングを実現したいので、
特に他に変更することなく接続することができます。
GatewayPorts の設定も不要です。

（リモートフォワーディングとの違いについて図解が分かりやすいです→[参考サイト](https://hrkworks.com/it/windows-tips/openssh/)）

###変更を反映させる

sshdを再起動しておきます。
`sudo systemctl restart sshd`


#コンテナ側の設定

###とりあえずDockerfile

Dockerfileはこのように作りました。

```dockerfile:Dockerfile
FROM python:3.7.3
ENV DEBIAN_FRONTEND=noninteractive

RUN apt-get update \
    && apt-get -y install --no-install-recommends apt-utils dialog 2>&1 \
    && apt-get -y install mysql-client \
    && apt-get autoremove -y \
    && apt-get clean -y \
    && rm -rf /var/lib/apt/lists/*

COPY .ssh/* /root/.ssh/
RUN chmod 600 /root/.ssh/*
RUN echo "ServerAliveInterval 15" >> /etc/ssh/ssh_config

ENV DEBIAN_FRONTEND=
```

以下の部分ではEC2インスタンスにSSHで接続するためのキーファイルを.sshに配置し、
パーミッションを適正値に設定するよう記述しています。

```dockerfile:Dockerfile
COPY .ssh/rsa_id /root/.ssh/rsa_id
RUN chmod 600 /root/.ssh/rsa_id
```




###SSH接続をタイムアウトしないようにする(クライアント側設定)

また、SSH接続をタイムアウトさせないように、
クライアント側でも設定ファイルに記述を追加しておきます。

```dockerfile:Dockerfile
RUN echo "ServerAliveInterval 15" >> /etc/ssh/ssh_config
```


#接続
コンテナでsshクライアントを立ち上げます。
このとき、ポートフォワーディングを設定するオプションとRDSのエンドポイントを入力します。

`docker container exec -it [コンテナ名] ssh -L 3306:[RDSのエンドポイント]:3306 ec2-user@[EC2のパブリックIPアドレス] -i /root/.ssh/id_rsa`

MySQLクライアントでリモートのRDSに接続できるか確かめます。

`docker container exec -it [コンテナ名] mysql -u [mysqlのユーザ名] -p -h 127.0.0.1:3306`


#注記

SSMによるポートフォワーディング
参考：[AWS Systems Manager のポートフォワーディング機能がリリースされました](http://blog.serverworks.co.jp/tech/2019/09/11/ssm-portfowarding/)

ご指摘などありましたら大変ありがたいです！

###参考サイト
[RDSにSSHポートフォワーディングを利用して接続してみた](https://dev.classmethod.jp/cloud/aws/rds-portforward/)
[SSHポートフォワード：OpenSSH の -L と -R オプションの動作を図解](https://hrkworks.com/it/windows-tips/openssh/)
macbookの時計が数秒ずれてていつまでもたってもなおらかったんだけど謎QAサイトのコマンドでなおった


https://kotaeta.com/72343792

```
16:22:16 tkrmbp:~% sudo sntp -sS pool.ntp.org
Password:
sntp 4.2.8p10@1.3728-o Tue Mar 21 14:36:42 UTC 2017 (136.200.1~4588)
kod_init_kod_db(): Cannot open KoD db file /var/db/ntp-kod: No such file or directory
2019-10-31 16:22:20.674264 (-0900) +2.506353 +/- 1.708850 pool.ntp.org 162.159.200.1 s3 no-leap
16:22:23 tkrmbp:~% sudo touch /var/db/ntp-kod
16:22:48 tkrmbp:~% sudo chmod 666 /var/db/ntp-kod
16:23:01 tkrmbp:~% sudo sntp -sS pool.ntp.org
sntp 4.2.8p10@1.3728-o Tue Mar 21 14:36:42 UTC 2017 (136.200.1~4588)
2019-10-31 16:23:04.279347 (-0900) +0.000932 +/- 0.038549 pool.ntp.org 162.159.200.1 s3 no-leap
16:23:04 tkrmbp:~%
```
fluentdのプラグインをgemでインストール

gemでのfluentdプラグインのインストール方法を確認しました。

S3へ出力するプラグインを試してみます。

Ruby、gemはインストール済みとします。

（rbenvの環境下で試したので、以下の例ではgem installを一般権限で実行してます。場合によってはsudoが必要です）

# fluentdインストール

```
$ gem install -N fluentd
$ fluentd --version
fluentd 1.7.4
```

シンプルな設定ファイルとして以下のファイルを作成します。

```sample.conf
<source>
  @type tail
  path input.txt
  pos_file input.pos
  tag test
  <parse>
    @type none
  </parse>
</source>
<match test>
  @type s3
  s3_bucket xxx
  path fluentd-sample-log
  <buffer>
    chunk_limit_records 1
  </buffer>
</match>
```

`@type s3`でoutputプラグインとしてs3を指定しています。s3プラグインはあとでインストールします。

`s3_bucket xxx`のところは自分の試せるバケット名を指定します。

`chunk_limit_records`の設定は、バッファリングの容量を1レコードのみにして実質バッファリングせずに入力されたらすぐに出力することを指示するものです。

入力のファイルを作っておきます。

```
$ touch input.txt
```

fluentdを起動してみます。

```
$ fluentd -c sample.conf
```

`Unknown output plugin 's3'. Run 'gem search -rd fluent-plugin' to find plugins"`
というエラーが表示されてしまいます。

# プラグインインストール

プラグインをインストールします。

```
$ gem install fluent-plugin-s3
$ fluentd -c sample.conf
```

別のターミナルで以下のようにすると、

```
$ echo hello >> input.txt
```

S3のバケットの中身を見ると、データが保存されているのが確認できます。`chunk_limit_records 1`なので、1ファイルに1レコードのみが含まれます。

```
$ aws s3 ls s3://xxx/
2019-10-29 12:08:36         71 fluentd-sample-log20191029_0.gz
$ aws s3 cp s3://xxx/fluentd-sample-log20191029_1.gz - | gunzip
2019-10-29T12:08:34+09:00       test    {"message":"hello"}
```

# 結論

fluentdインストール時に含まれるfluent-gemの役割がわからなかった。普通のgemでもできてしまった。fluentdで使われるRubyとgemコマンドのRubyが一致していれば、どちらでも問題ないということでしょうか。
MATLABの機械学習で脳波を識別　その２

# はじめに
この記事は、前回の記事「[MATLABの機械学習で脳波を識別　その１](https://qiita.com/aoimidori/items/17274ded0e55e07bbd53)」の続きとなる内容です。前回の内容を読んでいる前提で話が進みますので、まだ読んでいない方は先に[その１](https://qiita.com/aoimidori/items/17274ded0e55e07bbd53)から見ておいてください。

# やりたいこと（おさらい）

・手の運動中の脳波4パターン（以下の①～④）を学習させる
　　①右手を前方に動かす運動
　　②右手を後方に動かす運動
　　③左手を前方に動かす運動
　　④左手を後方に動かす運動
・学習したアルゴリズムを使って、運動イメージ中の脳波が①～④のどれか判別させる

# 分類アルゴリズムの学習

前回は学習データ（ClassifyMat）および評価データ（VerifyMat）の作成まで終わったので、今回は実際に学習の方を進めていきます。
学習には、MATLABの中にある[分類学習器アプリ](https://jp.mathworks.com/help/stats/train-classification-models-in-classification-learner-app.html)を使用しました。MATLAB画面上部の「アプリ」タブから探せます。

アプリを開くと「新規セッション」のボタンがあるので、そちらから学習データを選択します。
実際の画面は下記です。変数としてClassifyMatを選択し、応答がLabel、予測子がLabel以外の7つの特徴量になっていることを確認します。
<img width="563" alt="NewSession.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521542/3a8d6b46-01a6-5608-239c-fbec9e116a6d.png">

データの選択、設定ができたら「セッションの開始」ボタンを押します。

<img width="972" alt="ClassificationLearner1.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521542/1a8379e1-0a66-7a0d-df01-ecb6f172bd0f.png">

すると、早速上のような画面が表示されると思います。
次に、色々とモデルやパラメータを選んでいく必要があるわけですが、今回はざっくりと、機械学習がどれぐらい使えるのかを見たいので、「すべてのクイック学習」→「学習」の順にクリックして、おおまかな傾向を見たいと思います。

<img width="973" alt="ClassificationLearner2.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521542/1542c139-ac06-ce07-bd51-caa66d791f5f.png">

すると、上のような結果が出ると思います。左側に手法がいくつか並んでいて、それぞれ精度が表示されていると思いますが、「細かいKNN」の精度が1番高くなっているので（混同行列の結果も悪くなさそうです）、今回はシンプルにこれを使っていきたいと思います。

学習済みのモデルを使って、評価データを分類させるには、モデルをエクスポートしなければならないようです。アプリの右上「エクスポート」のボタンから、「モデルのエクスポート」を行います。
<img width="500" alt="ModelExport.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521542/edac4f1b-94b3-967a-efe3-20ee17a65826.png">

そうすると、MATLABのワークスペースに、上記で作成したtrainedModelが置かれるので、これを使って評価データを予測します。コードは下記。

```matlab
YPredicted = trainedModel.predictFcn(VerifyMat(:,1:7));
```

また、評価データの真のクラスと、trainedModelによって予測されたクラスの混同行列を作ります。コードと結果は下記の通り。

```matlab
Y = mat2cell(table2array(VerifyMat(:,end)),height(VerifyMat));
confusionchart(cellstr(Y{1,1}),YPredicted);
```

<img width="495" alt="ConfusionMatrix.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521542/4cc30eb0-f0d0-1067-3f9c-493fba3743ba.png">

RightForwardに正しく分類できたものが全体の6割強という感じでした。

# 考察

今回、えいやで機械学習を試してみましたが、あまり深く作りこみをしていなくてもある程度の精度は得られたかなと思います（とはいえ実用化には程遠いレベルですが）。アプリ上でモデルの比較ができたので、結構サクサクと作業が進みました。

また、混合行列を見てみると、RightForwardに近い運動ほど誤分類も多くなる（右手の前方運動と後方運動は識別が難しい、右手の前方運動と左手の後方運動は識別が容易）というのは、一つ面白い結果だったなと思います。

最後に、これは手持ちのデータではどうしようもないですが、運動イメージ中の脳波を使って学習もできれば、より精度が良くなるかもしれません。

# おわりに

今後、この手持ちのデータを使って、自分のできる範囲で分類の精度をあげていくには
　・データ前処理のブラッシュアップ
　・特徴量エンジニアリング
　・最適なモデルの策定
　・ハイパーパラメータの最適化
などなど、色々とやれることがあると思います。

精度をあげていく処理については、また機会があれば試してみたいと思います。
スマホアプリ開発初心者 flutterでの iOS / Android デュアル開発備忘録

iOS, Androidデュアル開発でたまたま巡り合ったflutterについての備忘録。まだまだflutterは開発途上の感じがして万人受けはきついようだ。

・flutter そのものはGoogleが開発している。今後もしばらくはエンハンスが期待できそう。
・Android Studio にプラグインはあるが、レイアウト編集、GUIツールが内包されていない（2019年10月現在）。他、Visual Studio Code でも対応ができるようだ（自身は未検証）。
・Dart言語のみ
・日本語資料が少ない＝日本では開発者が少ない、オープンソースのライブラリもほとんど見かけない（英語資料も他の設計ツールに比べると相対的にまだまだ少ない）
・各OSに依存する処理は結局別々に対応しなければならない
・初心者には（私も）インストール＆環境設定(下記参考資料参照)、レイアウトも考慮したコードの記述方法全般でハードルが高く、あまり浸透しない理由の一つであろう。

#flutterの特徴
・Layout.xmlが存在しない：Widgetの概念の組み合わせ、Dartコード内で完結、React NativeのJSXのような記述も無い
・私見では単純コードでもRun/Buildに時間がかかる傾向（Android Studioでflutterプラグイン対応した場合）
・ブラウザベースでのGUI開発ツールが公開されているが、個人運営（リスクといえばリスク）、大枠レイアウトしか定義でき内容で実用性は疑問　https://flutterstudio.app/
ハイレベルである程度のソースコードがリアルタイムで自動生成されるので、それをコピペで活用はできる
※Android Studio に同じような機能で実用性に耐えられる機能が内包されれば、flutterがかなり広まる気がする。
flutterもAndroid StudioもGoogleなので、今後のGoogleに期待。

現時点では初心者があまり深入りしない方が良さそうだが、
特にGUIレイアウト編集ツールがAndroid Studio に統合されたら有力な化け物になる可能性が高い。iOSの開発をGoogleが手助けしてGoogleとしてメリットがあるかというとそこは？なので、個人的には直ちに大掛かりなエンハンスは期待していない。

#参考記事
ツールのダウンロード先：https://flutter.dev
特性など：https://qiita.com/kappaLab/items/d6939c249ebb45d142e6
インストール方法(macの場合、2019年10月現在最新環境でも動作確認)：https://qiita.com/akatsukaha/items/3b8a5a6d94a3cdb1e047
GUIでSouce Code生成のお助けツール（flutter studio）について：
https://qiita.com/hiraokusky/items/2292150722b17ef4fe21
https://medium.com/@pmutisya/flutter-studio-version-2-41cce10fcf3d
【Javascript】▼IE表示が　出来ない　Javascriptが　現れた！

[注意！IE11で使えない最新JavaScritコード（ES6）](https://blog.capilano-fw.com/?p=1273)
↑IEで動かないjavascriptたち一覧

自分が実際に苦しめられた輩は下の4匹。
御三家より一匹多い。

（ネタはないのに備忘録下書きがたまっているので消化してるだけです）


##Jqueryの表示							
参考：[IEの互換モードを無視して標準モードで動かす](https://qiita.com/kawaz/items/1b64defd2997feb3f924)
詳しくは上記URL参照。
初期設定で互換表示をさせないように下記のタグをHTMLに設置。
お世話になる頻度は高めかと。
				
```
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />	
```					
							
##Object.assignの補完							
参考：[Object.assignの代わりになるもの](https://github.com/getsentry/sentry-javascript/issues/1477)
IEに対応していないjavascriptの一つ。

「Object.assign　IE」と検索すると、一番最初にヒットするのは[こちら](https://cpoint-lab.co.jp/article/201804/2450/)ですが、
記載されているタグを挿入したら無限ループ？　か何かが起こってうまく動きませんでした。
なので下記のスクリプトを設置。					
					
```
<script src="https://cdn.polyfill.io/v2/polyfill.min.js"></script>
```
一種のライブラリのようですので、オフラインだと絶賛動きません。

							
##Promiseの補完							
参考：[Promiseのpolyfill(IE11お前もか!)](https://qiita.com/zERobYTezERo/items/ac458c4cf2a8f2f6c3dd)
IEに対応していないjavascriptの略。
こちらもオフラインだと動かないです。

```
<script src="https://www.promisejs.org/polyfills/promise-6.1.0.min.js"></script>
```
			
##Fetchの補完							
参考：[fetchが定義されていませんとかのエラーはpolyfillかCDNで対処しよう](https://hubarifront.hatenablog.com/entry/2019/02/22/165900)
IEに対応していない略。
こちらは唯一オフラインで動きます。
ソースをドロップドロップ。					
					
```

<script src="https://cdnjs.cloudflare.com/ajax/libs/fetch/2.0.4/fetch.min.js"></script>
```
TypeScriptでprettier付きNode.jsのプロジェクトを作る際の手順


- プログラミング言語 TypeScript
- コードフォーマッタ prettier

がセットアップされたNode.jsプロジェクトを作る手順の健忘禄。

最近、Prettierの[公式](https://prettier.io/docs/en/precommit.html)が、 `pretty-quick` を使うようになったので修正。

配布されている[Node.js](https://nodejs.org/ja/)のインストーラーやnvmなどでNode.jsはインストール済みの前提。あとgitignoreやソースフォルダも作成。

```sh

mkdir myproject
cd myproject
npm init
echo node_modules >> .gitignore
echo dist >> .gitignore
mkdir src
```

ここまででプロジェクト作成。

次にTypeScriptとPrettierと各種定義やコミット時に自動フォーマットするためのライブラリなどをインストール。

```sh
npm i --save-dev typescript @types/node
```

次にtsconfig.json を作成。

```sh
npx tsc --init
```

tsconfig.json にコードのフォルダの指定と、出力先フォルダを作成。compilerOptionsの項目にて、

```
    "outDir": "./dist",                        /* Redirect output structure to the directory. */
```

を元のコメントアウトしているものと置き換え。コンパイル元のコードの設定を末尾に設定。

```
  }
 }
```

↓

```
  },
 "include": [
   "src/**/*"
 ]
}
```

次に。package.jsonに各種便利スクリプトを設定、mainとscriptの項目を書き換え。

```
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
```

↓

```
  "main": "src/index.ts",
  "scripts": {
    "start": "node dist/index.js",
    "build": "node_modules/.bin/tsc"
  },
```

Prettier の設定は好みで。自分は文字列は常にシングルクオーテーションにしたいのでこの設定で。

```
echo "singleQuote: true" >> .prettierrc
```

あとはコードを作成。

```sh
echo "console.log('Hello TS');" > src/index.ts
```

実行してみる。

```
npm run build && npm start
```

実行してみて、

```
Hello TS
```

と表示と表示されれば完了。

```
git init
git add .
git commit -am "First Commit"
```
Git に足して、あとは prettier 関連のインストールをする。

```
npm install --save-dev prettier husky 
npx husky-init
npm install --save-dev pretty-quick
npx husky set .husky/pre-commit "npx pretty-quick --staged"
```

src/index.ts を編集して

```
git commit -am "Test prettier"
```

これで

```
sifue@DESKTOP-LKSCKRS:~/workspace/serval-bolt$ git commit -am "Test prettier"
🔍  Finding changed files since git revision 466d18d.
🎯  Found 2 changed files.
✅  Everything is awesome!
```

のように表示されればちゃんと動いている。これをプッシュしてフォーマットされれば完成。では楽しいTypeScriptライフを！
Python3+CleanArchitecture

# はじめに
[Python](https://www.udemy.com/course/python-beginner/) 学習のアウトプットとして、Python3 + CleanArchitectureのサンプルプログラムをコーディングしました。[Injector](https://github.com/alecthomas/injector) を使って、DIP（依存関係逆転の原則）を満たすようにしています。というか今の所それだけですmm
 
- (※) クリーンアーキテクチャ関連の理解に関しては、以下を参考にしています
  - [クリーンアーキテクチャの右下の図@nrslibさん](https://nrslib.com/clean-flow-of-control/)
  - [Clean Architecture　達人に学ぶソフトウェアの構造と設計](https://www.amazon.co.jp/Clean-Architecture-%E9%81%94%E4%BA%BA%E3%81%AB%E5%AD%A6%E3%81%B6%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2%E3%81%AE%E6%A7%8B%E9%80%A0%E3%81%A8%E8%A8%AD%E8%A8%88-%E3%82%A2%E3%82%B9%E3%82%AD%E3%83%BC%E3%83%89%E3%83%AF%E3%83%B3%E3%82%B4-%EF%BC%B2%EF%BD%8F%EF%BD%82%EF%BD%85%EF%BD%92%EF%BD%94-%EF%BC%A3%EF%BC%8E%EF%BC%AD%EF%BD%81%EF%BD%92%EF%BD%94%EF%BD%89%EF%BD%8E-ebook/dp/B07FSBHS2V) ...途中まで読みました...

# 環境&構成
- Python 3.7.4
- [sample app (source code)](https://github.com/pureone-tcy/clean-architecture-python/tree/master/app)

```
.
├── main.py
├── interfaces
│   ├── controller.py  
│   └── console.py
├── usecase  
│   └── restaurant.py
└── domain
    └── message.py
```

# 処理フロー
クリーンアーキテクチャの図と、シーケンス図の色を合わせています。

<img width="400px" src="https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.amazonaws.com%2F0%2F293368%2F7ce1fb10-504e-16e0-8930-278b8a7f942d.jpeg?ixlib=rb-1.2.2&auto=compress%2Cformat&gif-q=60&s=eb579755ad2125de277a8f23e46d3a2f" />
<img width="800px" src="http://www.plantuml.com/plantuml/png/fP7Dhjem58JtVegZP0CBfAhjeaG84GYj8b5HeRBeqYIdrAfZM_w1ylQr1MbpiK6wkbavFZEVFUE5iLHRrt5oa7yWszUmeHVK6UGRTlnbbzmX0Vyfhs8DKrHOw2WJa7-QBgjgJL2quAtawg-5HVsJDWXbIvLVcvxqHIEA2BL3OwdJVhcImch9EMh8FVbZ-U4ENIh5MKCjamAMpZ21ni3ESVntn3ScVZyvOMzmHGr2Nhqltqq_HyfwkqCb3RDINs0s0temLjF6mdpUUzwOrcSqakE3WEj0KvePV93l1t8kpsH8p3gleaSSjJAyoZZxpmp_C9cdAov0Eq68JyTEr69IH99EJumgBO09Pacq7yJ3Lc-wuPQNzBKKKDKlPxF9f1ycu64wbAVl6rIHzpNHGb4jFcyg7Jrwd08QZG7ozJf8XefjANhKR7PYU1xThEFihkH1ov7oDe2XvZlgZWdAOUkiSfOiKBIkuty1"/ >

- `RestaurantUseCase`は、抽象的な`IORepository`に依存する
- `RestaurantController`のコンストラクタで、DI定義のから、`RestaurantUseCase`の実装を取得する

# ポイント

- 抽象クラスの`IORepository`と、それを継承した`Console`のDIのバインド設定を定義する  
- `RestaurantController`のコンストラクタで、上記の設定でDIされた`RestaurantUseCase`を保持する

```python
class DIMoudule(Module):
    def configure(self, binder):
        binder.bind(repository.IORepository, to=console.Console)


class RestaurantController:
    def __init__(self):
        self.usecase = Injector([DIMoudule()]).get(
            restaurant.RestaurantUseCase)

    def run(self):
        self.usecase.run()
```

- `RestaurantUseCase`のコンストラクタで、DIされた`IORepository`の実装を保持する  
  （上記の`DIMoudule`の設定だと、`Console`がDIされる）

```python
class RestaurantUseCase:
    @inject
    def __init__(self, c: repository.IORepository):
        self.console = c

    def run(self):
        self.console.start)
```

## 終わりに
- 今回の実装だと、`UseCase`の抽象(=`UseCaseInputPort`)が存在しない
  - 参考：[クリーンアーキテクチャの右下の図@nrslibさん](https://nrslib.com/clean-flow-of-control/)
- `Controller`のコンストラクタで、`Injector`から、DIバインド済みの`UseCase`を取得するようになっています
[Unity] partialを使ってコンフィグを分けてみる



`※あくまで個人的にこう使うと便利かもレベルです。`
（partialって何？ってのはここでは省きます。簡単に言えばクラスの定義を複数ファイルにまたいで行うことができるもの。）
##ゲーム内のコンフィグをまとめてみる
Unityでゲームを作る上でファイルのパスやステータスなどの定数、PlayerPrefsのkeyなどの定数を定める静的クラスを作ると思います。
例えば、ファイルのパス、敵のステータス、PlayerPrefsのKeyをまとめた`Configクラス`を作ったとします。
####Config.cs

```c#:Config.cs
public static class Config
{
    public static class Path
    {
        public const string Prefabs = "Prefabs/";
        public const string BGM = "Audio/BGM/";
        public const string SE = "Audio/SE/";
    }

    public static class Enemy
    {
        public const int HP = 10;
        public const int Power = 5;
        public const float Speed = 2.5f;
    }

    public static class Key
    {
        public const string SaveData = "SaveData";
    }
}

```

現状はまだ内部に3つのクラスしかないのでまだゴチャゴチャしていないのですが、これが制作が進むにつれてプレイヤーのステータスであったり、タグの名前、ファイルの名前などのクラスをどんどん追加していくと可読性も下がりますし何よりどれがどこにあるのかが分からなくなってきます。
そんな時に`partial`を使ってファイルを分けます。
例として今回は上のConfigクラスをpartialクラスにして大きく2つのファイルに分けてみます。
大まかな分けかたの基準として今回は`アプリの設定（Path、Key）`と`ゲームの設定（Enemy）`として、新たに`AppSetting`と`GameSetting`のファイルを作り、分けてみます。
####AppSetting.cs

```c#:AppSetting.cs
public static partial class Config
{
    public static class Path
    {
        public const string Prefabs = "Prefabs/";
        public const string BGM = "Audio/BGM/";
        public const string SE = "Audio/SE/";
    }

    public static class Key
    {
        public const string SaveData = "SaveData";
    }
}

```

####GameSetting.cs

```c#:GameSetting.cs
public static partial class Config
{
     public static class Enemy
    {
        public const int HP = 10;
        public const int Power = 5;
        public const float Speed = 2.5f;
    }
}

```

※ファイル名とクラス名が一致しませんがstaticかつpartialクラスであるため問題ありません。
こうすることで同じクラスに属してかつファイルを分けることができます。
UE4 Android Pipeline State Object (PSO)  検証 

## はじめに
- UE4 初回起動時のカクカク対策
 - その一つの原因が　Android はシェーダーコンパイルを実行時にするためです。
 - それを解決するUE4の仕組みが UE4 Android Pipeline State Object (PSO) です

## Device Profile を設定する

-psocache -logPSO

## 開発環境
- Visual Studio 2017 professional
- UE4.22

## PROJECT SETTING
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/143480/1e500bb0-a40c-7a40-e92e-534d13fb670a.png)
 - Share Material Shader Code
 - Shaed Material Native Libraries
 - にチェックを入れます。

## 日本語だと Device Profile の設定ができない
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/143480/9735b251-1b04-d04b-8296-24707339f03e.png)


## Device Profile を設定する

 - Window => DeveloperTool => Device Profile を開く
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/143480/1db568a3-478e-fbdb-157a-1fa67d793392.png)

 - Android の 横の ... をクリックします

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/143480/2f949ba9-69c6-38b9-9fa3-452e15998128.png)

 - Console => Renderring の横の + ボタンを押す

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/143480/cf89d639-460f-a25d-eb18-2bca329acd97.png)

 - Android, Android-ETC1, en-US にチェックを入れる


## 参考

https://docs.unrealengine.com/en-US/Engine/Rendering/PSOCaching/index.html
bashで否定先読みを使いたいときの回避策


## やりたいこと
bashのif文で、文字列の最初にドットが含まれない正規表現を条件式として使いたかった。
ファイルのリストから隠しファイル (ドットファイル) を除外したかったからである。

カレントディレクトリの状況↓

```bash
ls
```
> `.DS_Store`
> `myfile.txt`

## ハマったところ
bashでは前方一致はできるが、否定先読み (前方一致の否定) は使えない[^1]

**前方一致：**

```bash
file_name=$(ls)
if [[ $file_name =~ ^(\.).*$ ]];then echo $file_name; fi;
```
> `.DS_Store`

**否定先読み：**

```bash
if [[ $file_name =~ ^(?!(/.)).*$ ]];then echo $file_name; fi;
```
> `bash: !: event not found`

## 解決案
elseを使う方法もあるが、if内で処理を行わないので冗長になってしまう。
そこで、まずif文の条件式を前方一致にしておき、その条件式全体を`!`で否定することで、擬似的に否定先読みを行った。

**否定先読みの回避策：**

```bash
if [[ ! $file_name =~ ^\..*$ ]];then echo $file_name; fi;
```
> `myfile.txt`

[^1]: [Bashで正規表現をやろうとしたら 否定先読み(Negative Lookahead) が出来なくてハマった話 ｜ Developers.IO](https://dev.classmethod.jp/etc/bash-regex-negative-lookahead/)
[ Android ] [ HTTP ] サーバから取得した値に関するメモ

サーバクライアント通信3の記事
（https://qiita.com/QiitaD/items/79228417a68c51090a4e）
で紹介した非同期処理プログラムを用いて、
サーバから取得した値に応じて処理を変えるプログラムを実装していた。
しかし、取得した値がswitch文などで分岐できなかった。
そこで、発生した問題の解決方法を2つ見つけたので記す。


##取得した値をStringBuilderに格納するプログラム
###解決法①
サーバ側のプログラムは以下の通りである。
クライアントはサーバから整数字0～2のうちの一字を取得できる。

~~~
 public class HelloWorld extends HttpServlet {
    public void doGet(HttpServletRequest request,
                      HttpServletResponse response)
                      throws IOException, ServletException {

    Random random = new Random();
    int randomNumber = random.nextInt(3);
    String stringRandomNumber = String.valueOf(randomNumber);

    PrintWriter out = response.getWriter();
    out.println(stringRandomNumber);
    out.close();
    }
}
~~~

クライアント側で
サーバから取得した整数字をStringBuilderに格納するプログラムは
以下のとおりである。(Logは確認用)

~~~
            //HTTP接続処理・・・
InputStream is = connection.getInputStream();
while (true) {
    byte[] line = new byte[1024];
    int size = is.read(line);
    if (size <= 0) break;
    src.append(new String(line, "utf-8"));
    Log.d("src.length", String.valueOf(src.length()));
            }
~~~

このプログラムを実行して、Logを確認すると
「src.length : 1024」
と表示された。

1024ということは

~~~
byte[] line = new byte[1024]
~~~

が関係していそうだ。
サーバからは１字しか取得していないので、残りはスペースだろうと予測。
そこでtrim()をつかってスペースを除去してみた。
具体的にはsrc.appendを以下のコードに変更してみた。

~~~
    src.append(new String(line, "utf-8").trim());
~~~

このプログラムを実行して、Logを確認すると
「src.length : 1」
と表示された。
やはりスペースが入っていたようだ。
私の記事を参考にして実装頂いた方には、
上記の点を注意していただきたい。

###解決法②
また該当プログラムを
BufferedReaderを用いたものに変更しても成功した。
以下がそのコードである。

~~~
            Reader reader = new InputStreamReader(is);
            BufferedReader bufferedReader = new BufferedReader(reader);
            try {
                String line;
                while ((line = bufferedReader.readLine())!=null){
                    src.append(line);
                }
            } finally {
                bufferedReader.close();
            }
~~~

このコードならtrim()を使う必要はない。

##まとめ
サーバから値を取得する際に使う
Readerクラスについては、まだまだ曖昧な部分が多い。
より深く理解したとき、そのことについて触れた記事を書きたいと思う。
以上。
word2vecで慎重+勇者の類似語を計算してみたら、案外妥当だった感

#はじめに
もう何番煎じになるかわかりませんが、djangoとword2vecを使用して単語をN次元のベクトル化して、コサイン類似度で最も類似している単語を探してくくるウェブページを作り、PythonAnywhereで公開しました。

[類似語探索用ページのURL](https://kamuy.pythonanywhere.com/stats/nlp)

# 使い方
・テキストボックスに単語を+や-で結合して入力し、類語抽出を押すだけ。
※PythonAnywhereのプランがBeginner Freeなので、すっごい重いです。

# 使用例
せっかく作ったので、慎重+勇者を試してみよう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/237112/2844e4cb-c020-320a-51ec-28f1c7b7b1aa.png)

うん。それほど間違ってはいないかな。（錯乱）

強い+勇者では・・・
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/237112/c89cb28d-22b2-a205-bd87-31c958ec4efd.png)

もしかして、勇者という単語自体が悪い単語なのでは！？
かくなる上は、正義を足してみようか・・・。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/237112/ef557458-bd3f-f733-13e0-de4f80e1281f.png)

駄目だ。正義が勇者に負けた・・・。
英雄で試してみるか・・・。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/237112/05bb4f39-9a72-3cdb-677f-9d1184eac5c3.png)

おお、大分まともに！

#結論
勇者はろくでもない。（暴論）
あてにするなら英雄のほうがいい。

#今回使わせて頂いたモデル
[word2vecの学習済み日本語モデルを公開します](http://aial.shiroyagi.co.jp/2017/02/japanese-word2vec-model-builder/)
YAMAHA RTX1210でIKEv2 VPN接続の設定をして全く理解できなかった


# わけが分からない単語について
IKEv2 VPN接続について調べてるとよく見る単語。だけどRTXの資料にはほとんど出てこない。

## ポリシーベース（動的ルーティング）、ルートベース（動的ルーティング）
よくわからない。RTXの資料にはこの単語が出てこない。RTXには関係ないの？RTXは対応してるの？

[発売を来週に控えたヤマハの最新VPNルータ、「RTX1210」の気になる最終仕様は？ (RTX1210とMicrosoft AzureをVPNで結ぶ設定を解説)](https://cloud.watch.impress.co.jp/docs/event/677029.html)

> 森田氏はまず注意点として、Microsoft Azureのサイト間VPN接続には2種類あることを説明した。IPsecのIKEv1によるポリシーベースVPNの「静的ルーティング」と、IPsecのIKEv2によるルートベースVPNの「動的ルーティング」だ。動的ルーティングは複数セグメント接続も可能だが、IKEv2対応機種が限られるとして、「RTX1210（RTX1200以降）なら大丈夫」と説明した。

どっちにも対応してるらしい。が設定例をみてもそれがルートベースなのかポリシーベースなのか判断がつかない。IKEv2を選んだらそれがルートベースになるってこと？

ポリシーベースのVPNをサポートしていないと言っているルータもある。

[ポリシーベースの VPN を使用したパロアルトネットワークとファイアウォール間の VPN のプロキシ ID](https://knowledgebase.paloaltonetworks.com/KCSArticleDetail?id=kA10g000000ClW8CAK&lang=ja&refURL=http%3A%2F%2Fknowledgebase.paloaltonetworks.com%2FKCSArticleDetail
)

>パロアルトネットワークファイアウォールは、ポリシーベースの vpn をサポートしていません。



##トラフィックセレクタ プロキシID
よくわからない。お互い関係ありそう。

* [Tips & Tricks: VPN プロキシ IDを使用する理由](https://live.paloaltonetworks.com/t5/%E3%83%8A%E3%83%AC%E3%83%83%E3%82%B8%E3%83%89%E3%82%AD%E3%83%A5%E3%83%A1%E3%83%B3%E3%83%88/Tips-amp-Tricks-VPN-%E3%83%97%E3%83%AD%E3%82%AD%E3%82%B7-ID%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%99%E3%82%8B%E7%90%86%E7%94%B1/ta-p/227841)

* [ポリシーベースの VPN を使用したパロアルトネットワークとファイアウォール間の VPN のプロキシ ID](https://knowledgebase.paloaltonetworks.com/KCSArticleDetail?id=kA10g000000ClW8CAK&lang=ja&refURL=http%3A%2F%2Fknowledgebase.paloaltonetworks.com%2FKCSArticleDetail)

RTXではトラフィックセレクタについてこの資料で言及されている
[IKEv2](http://www.rtpro.yamaha.co.jp/RT/docs/ipsec/ike2.html)

>メッセージ交換で使用されるTS (トラフィックセレクタ) ペイロードに関して、イニシエータとして動作する場合は、常にIPv4/IPv6すべてのアドレス、プロトコル番号、ポート番号を許可する>内容を送信します。またレスポンダとして動作する場合は、常に提案されたTSペイロードを受理し>ます。
>なお、TSは既存のルーティング処理に影響を与えません。ルーティングの結果、トンネル経路へ向けられたパケットに対してTSは適用されます。

何言ってるかわからない。

##トンネルモード
[IPsec の設定](http://www.rtpro.yamaha.co.jp/RT/manual/rt-common/ipsec/ipsec_chapter.html)
> IPsec による通信には、大きく分けてトンネルモードとトランスポートモードの 2 種類があります。
トンネルモードは IPsec による VPN(Virtual Private Network) を利用するためのモードです。ルーターがセキュリティ・ゲートウェイとなり、LAN 上に流れる IP パケットデータを暗号化して対向のセキュリティ．ゲートウェイとの間でやりとりします。ルーターが IPsec に必要な処理をすべて行うので、LAN 上の始点や終点となるホストには特別な設定を必要としません。
トンネルモードを用いる場合は、トンネルインタフェースという仮想的なインタフェースを定義し、処理すべき IP パケットがトンネルインタフェースに流れるように経路を設定します。個々のトンネルインタフェースはトンネルインタフェース番号で管理されます。設定のためにトンネル番号を切替えるにはtunnel select コマンドを使用します。トンネルインタフェースを使用するか使用しないかは、それぞれtunnel enable、tunnel disable コマンドを使用します。

拠点間VPNがトンネルモード？

# 結局
わからなさすぎる。でもつながったよ。
TeX の表中の脚注を表の直下につける

**この記事を読むとできるようになること**
`TeXで，表中につけた脚注をページ下ではなく表のすぐ下に書ける`

- 環境
    - macOS mojave 10.14.6
    - TeXshop 4.44

TeXで表を書いていたら，こんな感じに表中に脚注をつけたくなりました．
<img width="302" alt="スクリーンショット 2019-10-31 15.05.04.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/403437/c66bfd65-fdb3-f819-0021-311e51200afe.png">


これを出力したくて，以下のように書いてみました．

```TeX:table_sample.tex
¥begin{table}[h]
¥begin{center}
¥caption{member list}
¥label{tab:menber}
¥begin{tabular}{ccc}¥hline
Name &age &nicname¥¥¥hline¥hline
Satoshi &34¥footnote{Emikoさんに聞いた} &doraemon¥¥
Taro    &24¥footnote{Takeshi君に聞いた} &Tarorian¥¥
Shinichi &21 &Conan¥¥
Jiro    &30 &Ramen¥¥¥hline
¥end{tabular}
¥end{center}
¥end{table}
```

これをタイプセットしてみると… あれれ〜？
<img width="302" alt="スクリーンショット 2019-10-31 15.20.53.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/403437/92331040-7837-0085-d38f-ae79962113c5.png">


脚注が出力されません．

Table.1 のように脚注をつけるには，`threeparttable` パッケージを使うとよいです．

```Tex:table_sample2.tex

%プリアンブルに以下を記述
¥usepackage{threeparttable}
%...(省略)...

¥begin{center}
¥begin{threeparttable}[h]
¥caption{member list}
¥label{tab:menber}
¥begin{tabular}{ccc}¥hline
Name &age &nickname¥¥¥hline¥hline
Satoshi &34¥tnote{a} &doraemon¥¥
Taro    &24¥tnote{b} &Tarorian¥¥
Shinichi &21 &Conan¥¥
Jiro    &30 &Ramen¥¥¥hline
¥end{tabular}
¥begin{tablenotes}
¥item[a] Emikoさんに聞いた.
¥item[b] Tekeshi君に聞いた.
¥end{tablenotes}
¥end{threeparttable}
¥end{center}
```

表中の脚注をつけたいところに ```\tnote{a}``` などと書きます．
```\tnote{1}``` とか，```\tnote{*}``` でも大丈夫です．

脚注の中身は ```¥begin{tablenotes}``` 以下に書きます．
ここも，```\item[1]``` とかでも大丈夫です．


普通の脚注 ```\footnote``` と違うのは，
```\tnote``` と ```\item``` がリンクしていないことです（したがって，ハイパーリンク機能を使っていても適用されません）．
AmazonAWSLambdaでRuby使ってpostgresにアクセスする時にIgnoring pg-XX because its extensions are not built. Try: gem pristine pg と出た時の対処法

lambdaでRubyを使ってPostgresにアクセスする際に以下のようなエラーが出る場合があります。

```
Ignoring pg-1.1.4 because its extensions are not built. Try: gem pristine pg --version 1.1.4
```
それをどのように解決したかを記載します。

###結論
pgやnokogiriなど、c言語のライブラリを使用しているものをrequireする際は
linux環境（redhat系）でbundle installを行ったvendorフォルダをlambda上にアップロードする。

###原因
lambdaがc言語のライブラリを参照する際にライブラリのパスが分からない。

###解決方法
dockerでAmazonLinuxの仮想環境を作成し、そこでbundle installを実行します。

####前提
- GemfileでRubyの開発環境が作れる
- Dockerがインストールしてある

####通常のlambdaでRuby動かすための環境構築
- Gemfileを作成

```
    source "https://rubygems.org"

    gem "aws-sdk"
    gem "pg"
```
- lambda上で動作するRubyファイルを作成

```
require 'aws-sdk'
require 'pg'
def lambda_handler(event:, context:)
    host = String("hogehoge")
    db   = String("postgres")
    user = String("hoge")
    pass = String("geho")
    port = String("5432")
    PG::Connection.new(:host => host, :user => user, :dbname => database, :port => port, :password => password)
    { statusCode: 200, body: JSON.generate('Hello from Lambda. powerd by Ruby!!')
end 
```
- Gemifileが配置されているディレクトリで`bundle install --path vendor/bundle`実行
- Zipしてアップロード

####ハマったこと
以下のようなエラーが出る

```
Ignoring pg-1.1.4 because its extensions are not built. Try: gem pristine pg --version 1.1.4
```

####解決方法
参考にしたgitリポジトリ
https://github.com/stevenringo/lambda-ruby-pg-nokogiri

- dockerでvendorを作る仮想環境を呼び出す
ホストマシン上でGemfileを作った上で、そのフォルダ上で以下を実行し仮想環境に入る

```
 docker run -v `pwd`:/var/task -it  stevenringo/lambda-ruby2.5-postgresql10 /bin/sh
```
- 実行環境作成に必要な環境を整備する

```
bundle config --local build.pg --with-pg-config=/usr/pgsql-10/bin/pg_config
bundle config --local silence_root_warning true
bundle install --path vendor/bundle --clean
mkdir -p /var/task/lib
cp -a /usr/pgsql-10/lib/*.so.* /var/task/lib/
```
※途中の`mkdir -p /var/task/lib`と`cp -a /usr/pgsql-10/lib/*.so.* /var/task/lib/`も省略せずに行ってください。
これを怠るとZIPアップロード後に

```
"errorMessage": "libpq.so.5: cannot open shared object file: No such file or directory - /var/task/vendor/bundle/ruby/2.5.0/gems/pg-1.1.4/lib/pg_ext.so"
```

と表示されます。

- zipで固める。

`exit`で仮想環境から抜けて、zipで固めます。この時、libフォルダも合わせて固めます。

```
zip -r hello_world.zip hello_world.rb vendor lib
```

- ファイルをアップロードする

これで当初のエラーは出なくなるはず。

### 検索用キーワード
gem
Ruby
postgres
pg
lambda
libpq
pristine
エラー
ラムダ
railsをバージョン指定してインストールする方法

- インスール済みのrailsのバージョンを確認

```
$ gem list rails

*** LOCAL GEMS ***

rails (6.0.0)
rails-dom-testing (2.0.3)
rails-html-sanitizer (1.3.0)
sprockets-rails (3.2.1)
```

- 今回はrails5.2.3をインストールしたい

```
$ gem install -v 5.2.3 rails
```

- 上記を実行後、再び確認すると追加されている

```
$ gem list rails

*** LOCAL GEMS ***

rails (6.0.0,5.2.3)
rails-dom-testing (2.0.3)
rails-html-sanitizer (1.3.0)
sprockets-rails (3.2.1)
```

- 最期に新しくプロジェクトを作る時はバージョンを指定してあげる

```
$ rails _5.2.3_ new first_app
```

- 参考

    - [Railsチュートリアルでrails newするときはバージョンを指定しよう](https://qiita.com/jnchito/items/f3bde6e46afbeba8cb82)

    - [Railsのバージョンを指定してinstallする方法](https://qiita.com/tanakayo/items/7b85261924eca1a5a3d6)
AutoML Visionを使って知識ゼロからAPIで画像認識



クラウドを用いた画像認識は[先行記事](https://qiita.com/pyru89kwmr/items/c723bb4456443bcaafa2)の通りにやったら普通に出来たのであんまり書くことないかも

代わりにEdgeでやった記事を書こうと思います
※こちらも執筆中
[AutoML VsionとTPUを用いて知識ゼロからEdge(Raspberry Pi)でゴミの画像認識](https://qiita.com/XM03/items/98bf047725fbf43bc0f3)
色々やってたら環境ぶち壊れたり苦労が多々あったのでその過程もまとめられたら良いです


# 筆者について
C, C++, JAVA, python, chainerなどは触った事があるが
ラズパイ, GCP, APIに関しては全くの無知識
普段はwindowsを使っているのでUbuntuの環境構築から始まります

# 環境
Ubuntu 18.04.2 LTS（ノーパ）
Raspbian（Raspberry Pi 3 Model B+）
Coral accelerator EDGE TPU

# やること
GCP、AutoML Vision のAPIを使ってクラウドを通してゴミの画像認識@Ubuntu
AutoML VisionのEdge機能を使ってラズパイでローカルなゴミの画像認識@Rasbian
ハードウェアまで含めたゴミの分別システムの構築（Qiitaには画像認識以外に関しては投稿しない予定）（自動分別ゴミ箱的な）

# やったこと
gcloudを使って、AutoMLをターミナルから実行できる環境構築
モデルの学習など（GCP繋げばマウスでできる）
pythonからAutoMLの実行
Ubuntu ＋ USBカメラでAutoMLのリアルタイム実行
Ubuntu ＋ USBカメラで画像データの収集プログラムの作成＆実行
ラズパイ　＋　USBカメラで画像データの収集プログラムの作成＆実行


# 参考（コピペ元）
ほぼ自分用の備忘録なのでコピペが多いのは許してください
[pyenv と pyenv-virtualenv をインストールする](https://qiita.com/shigechioyo/items/198211e84f8e0e9a5c18)

imwrite
https://note.nkmk.me/python-opencv-imread-imwrite/

AutoML API
https://qiita.com/pyru89kwmr/items/c723bb4456443bcaafa2

ラズパイをjupyterサーバーにする
http://irukanobox.blogspot.com/2018/02/raspberry-pijupyter-notebook.html
https://qiita.com/shimaken/items/b411de87b00c051e6697

ラズパイのSSHをON
https://s2jp.com/2014/01/raspberry-pi-ssh/

windows10でラズパイにSSH接続
https://www.onebizlife.com/windows10-ssh-client-1980

# memo
opencv のインストール
これ以外でやってみたけどエラーでてきた
version 3.1.0
anacondaで

```
$ conda install -c https://conda.binstar.org/menpo opencv3
```
時間がずれているとエラーになる
https://qiita.com/yuji38kwmt/items/b3fe316f6c000235aab5

ラズパイの初期パスワードは
raspberry
ラズパイのSSH有効コマンド

```
sudo raspi-config
```
から



wgetでエラーが出る

```
ERROR: The certificate of ‘dl.google.com’ is not trusted.
```
https://blog.dreamhive.co.jp/mkoba/?p=5741


edgeでautoML
https://www.apps-gcp.com/automl-vision-edge/
r

# pyenvのインストール
AutoMLに必要なgoogle cloudモジュールがpython2系でしか動かないみたいなのでまずはpyenvを入れます
こちらを見たほうが正確
[pyenv と pyenv-virtualenv をインストールする](https://qiita.com/shigechioyo/items/198211e84f8e0e9a5c18)

pyenvのインストール

```
git clone https://github.com/pyenv/pyenv.git ~/.pyenv

echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.profile
echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.profile
echo -e 'if command -v pyenv 1>/dev/null 2>&1; then\n  eval "$(pyenv init -)"\n

source ~/.profile
```
このまま

```
pyenv install 3.6.3
```
などとしてもエラーが出てしまうので

```
sudo groupadd developer
sudo gpasswd --add USERNAME developer
sudo visudo
Defaults exempt_group="developer"
```

pythonのインストール

```
pyenv install 3.6.3
```
ついでにpyenv-virtualenvもインストール

```
//github.com/pyenv/pyenv-virtualenv.git $(pyenv root)/plugins/pyenv-virtualenv
echo 'eval "$(pyenv virtualenv-init -)"' >> ~/.profile
source ~/.profile
pyenv virtualenv 3.6.3 myenv
```
確認してみます

```
pyenv versions
* system (set by /home/user/.pyenv/version)
  3.6.3
  3.6.3/envs/myenv
  myenv
```
それでもpython -Vが変わらないときはこのコマンドでいけました

```
eval "$(pyenv init -)"
```
https://akamist.com/blog/archives/2610

# AutoML VisonのAPIをやってみる

素直にこの通りにやった行けました
https://qiita.com/pyru89kwmr/items/c723bb4456443bcaafa2
Blawn言語の実装をいじって遊んでみた感想


# はじめに

単なる個人の感想です。

# 1.ブロック

文の連続を単なるvectorで表しているみたいだけど、個人的にはブロックとしてまとまって管理できるようにしたほうが良い気がしている。

例えば、ブロックの中にブロックがある入れ子構造のとき、変数のスコープをブロック単位で管理する言語は多いと思う。
そんな時には、ブロック単位で管理できるメリットは大きいと思う（個人の感想です）。

# 2.文と式

ここでは、文とは「値を返さないもの」、式とは「値を返すもの」ぐらいのふわっとした意味で使っています。

言語の文法を定義するとき、文と式はきちんと区別したほうが良いと思う。

特に問題になりやすいのが、if。
ifが文なのか式なのかによって、コンパイラが吐き出すコードは変わってくる。

```x = if m < n (1) else (2)```

みたいなコードがあったとする（言語は適当）。

このとき、ifが文（値を返さない）だったとすると、このコードは文法エラーになるべき（ifをコンパイルしたコードが値を返さないはずなので、コンパイルした結果がおかしくなる）。

なので、言語の文法を考える時には、式なのか文なのかはきちんと区別したほうが良い（個人の感想です）。

## とはいえ

ifが式だと面白いので（個人の感想ry）、Blawnのifを式（値を返す）にしてみた↓。

[https://github.com/JunSuzukiJapan/Blawn](https://github.com/JunSuzukiJapan/Blawn)


```if.blawn
function lt(m, n)
  return if m < n
  (
    1
  ) else
  (
    0
  )

x = lt(5, 7)
print(int_to_str(x))
```

上記のようなコードがコンパイルできます。

具体的にどんなコードを吐き出すかというとphiを使っていて下記のようなコードになります。

```if.ll
// （略）
define i8 @main() {
entry:
  %0 = call i64 @lt.2(i64 5, i64 7)
  %x = alloca i64
  store i64 %0, i64* %x
  %1 = load i64, i64* %x
  %2 = load i64, i64* %x
  %3 = call %struct.String* @int_to_str(i64 %2)
  call void @print(%struct.String* %3)
  ret i8 0
}

declare void @lt()

define i64 @lt.2(i64 %m, i64 %n) {
entry:
  %0 = alloca i64
  store i64 %m, i64* %0
  %1 = alloca i64
  store i64 %n, i64* %1
  %2 = load i64, i64* %0
  %3 = load i64, i64* %1
  %4 = icmp slt i64 %2, %3
  br i1 %4, label %"then of if expr", label %"else of if_expr"

"then of if expr":                                ; preds = %entry
  br label %"merge of if_expr"

"else of if_expr":                                ; preds = %entry
  br label %"merge of if_expr"

"merge of if_expr":                               ; preds = %"else of if_expr", %"then of if expr"
  %condtmp = phi i64 [ 1, %"then of if expr" ], [ 0, %"else of if_expr" ]
  ret i64 %condtmp
}

```

> 参考：
> [LLVMのphiとは](https://qiita.com/JunSuzukiJapan/items/faf2ac94df0ebca43064)
MacのterminalからAIXに接続してviをやるとXTERM-256COLOR: Unknown terminal typeと言われるとき

こんな感じで変な出力になるとき。

```
x@server:x> $ vi a.txt
XTERM-256COLOR: Unknown terminal type
 [Hit return to continue] 

[Using open mode]
"a.txt" 60 lines, 4826 characters 

                                                                  Data type                     Column 
``` 

下記をコピペして実行するだけで直ります。

```
export TERM=xterm
```
css の配置で回り込みを防ぐ方法(clearfix)

#cssの配置の回り込みを防ぐぐ方法(clearfix)

方法を解説してあるサイトです

http://creator.aainc.co.jp/archives/4721

cssによって回り込みを防ぐ方法です
clear属性とdisplay属性でブロック表示、content属性で挿入する要素を使用します

この方法以外にも使用目的として正確ではないですがoverflow属性でもできるそうです

cssを使わない方法はdivを挿入するやり方もあります