OmniAICreator/Qiita-1.07M huggingface dataset:
Redisとは？RailsにRedisを導入

# はじめに
自分の管理するサービスでもRedisを使ってはいるが、splitというgemを使うのに必要で入れているだけで、
せっかくRedisを入れていてもほぼ役目を果たしていないのでRedisをちゃんと使う前に改めてRedisについて整理したいなーと思ってメモがてら書いてます。

# Redisとは？
- キャッシュシステムとして有名であり、NoSQLの1つ
- NoSQLの中でも、KVS(キーバリューストア)。キーとバリューの組み合わせを保存する。
- データ型にいろいろ使える
	- String,List,Set,Sorted Set,Hash
- インメモリなので高速
- 永続化設定可能
- シングルスレッド
- スケールアウト可能
- 使いどころ
	- セッションなど有効期限のあるデータを扱う場合
	- ランキングデータなど重たいSQLを走らせないといけない処理を扱う場合

## Redis のインストール
brew を使ってインストールしました。
他のインストール方法はこちら(https://qiita.com/KurosawaTsuyoshi/items/f8719bf7c3a10d22a921)

```
$ brew install redis
```
これでインストール完了。

## Redis サーバーの起動
つづいて Redis のサーバーを起動させます。

```
$ redis-server
```
これでローカル環境で Redis を使えるようになります。

## Redis に接続する
```
$ redis-cli
127.0.0.1:6379>
```

## Redis を使ってみる
`redis-cli` で Redisサーバーに接続したあとに下記のように操作してみます。

- `SET` を使って Key と Value を設定しデータを保存する
- `GET` で Key を指定して Value を取得する
- `quit` で redis-cli を終了

```
redis> SET mykey "Hello"
OK
redis> GET mykey
"Hello"
redis> quit
```
(https://redis.io/commands/set)

# RailsにRedisを導入
## 環境
ruby 2.5.1
Rails 5.2.2

## Rails アプリの作成
ここではとあるページにRedisから値を取り出して表示するだけの簡単なアプリケーションを作ります。

```
$ rails new redis_sample
```

### gem redis-rails のインストール
Rails で Redis を使うので Gemfile を以下のようにします。普通の Ruby で使う場合は `gem redis` でよさげ。

```Gemfile
gem 'redis-rails'
```
```
$ bundle install
```
```config/application.rb
config.cache_store = :redis_store, 'redis://localhost:6379/0/cache', { expires_in: 90.minutes }
```

config/application.rb に書いていますが、実際は環境毎に参照する Redis サーバーは違うと思うので、`config/enviroments/◯◯.rb` に書くとよいかと

### サンプルページの作成
```config/initializers/redis.rb
Redis.current = Redis.new
```
ローカル環境なので `Redis.new` しか書いていませんが、下記のように `host` と `port` を指定できるので、AWSのElastiCacheのRedisなどを使う場合はそれぞれを指定する必要がある。(ローカル含めて環境変数で管理するのがおすすめ)

```
Redis.new(:host => '127.0.0.1', :port => 6379)
```

つづいてページを表示するために、ルーティング、コントローラ、ビューを書いていきます。

```config/routes
resource :redis, only: %i[show]
```
```app/controllers/redis_controller.rb
class RedisController < ApplicationController
  def show
    Redis.current.set('mykey', 'Hello')
  end
end
```
`config/initializers/redis.rb` で定義した `Redis.current` に対して値を保存します。

```app/views/redis/show.html.erb
<%= Redis.current.get('mykey') %>
```
で、上で保存した値をビューの中で取り出して表示します。

# まとめ
実装自体はたったこれだけです。
ランキングページなど、重たいSQL必要なところとか、フラグメントキャッシュとかで使っていきたいなと思いました。
あとはAWSの場合はElastiCacheでRedisサーバーを立てて、そのエンドポイントを `config/initializers/redis.rb` で指定すればよいかと思います！(自分はセキュリティグループの設定忘れてて詰まったので気にしてみてくださいw)
Rubyで線形探索と番兵法

#はじめに
この記事ではRubyで線形探索について解説していきます。

#線形探索とは
`線形探索`とは最も単純なアルゴリズムの一つで、目的とする要素に出会うまで先頭から順に要素を`走査`(なぞるように探す)していくことです。

もっと単純に言うと`先頭から末尾まで一つ一つ探していきます。`

線形探索では`値があるか`、`値はどこにあるか`などを求めることができます。

また線形探索は`逐次探索`や`リニアサーチ`とも言います。

##メリットとデメリット
###メリット
線形探索のメリットは単純で実装がしやすいと言うことです。
###デメリット
線形探索のデメリットは先頭から末尾まで一つ一つ調べるので処理が遅いと言うことです。

##実装例
下記のコードでは線形探索の例を書いています。

```linear_search.rb
#配列aの先頭number個の要素からtargetと一致する要素を線形探索

def linear_search(a, number, target)
  #探索に失敗した場合は-1を返す
  i = 0
  loop do
    return -1 if i == number  #探索成功
    return  i  if a[i] == target #探索失敗
    i += 1
  end

end


puts "配列aの要素数を入力してください。"
number = gets.to_i
a = []

puts "配列に入る数字を入力してください"
number.times {|i|
  print "a[#{i}]："
  a[i] = gets.to_i
}

puts "探したい値を入力してください"
print "探す値："
target = gets.to_i

result = linear_search(a, number, target)

if result == -1
  puts "その値は存在しません。"
else
  puts "その値はa[#{result}]にあります。"
end

```

##番兵法
`番兵法`とは`探索する値`と全く同じ値を、配列の一番後ろに置く探索の方法のことです。
`番兵`とは、そのとき格納する「探索する値と全く同じ値」のことのことです。

番兵を置く理由は`探索するときのコストを抑えること`です。

前回書いたの線形探索のコードでは、探索するときに毎回if文を2回繰り返します。

```linear_search.rb
def linear_search(a, number, target)
  #探索に失敗した場合は-1を返す
  i = 0
  loop do
    return -1 if i == number  #探索成功
    return  i  if a[i] == target #探索失敗
    i += 1
  end
end
```

一方番兵法を使えばif文は1つですみます。

```linear_search2.rb

def linear_search(a, number, target)
  #探索に失敗した場合は-1を返す
  i = 0
  a[number] = target #番兵を追加

  loop do
    break  if a[i] == target #探索成功
    i += 1
  end
  i == number ? -1 : i
end
```

最初の`inear_search.rb`に書いた線形探索では`探索が成功したか`判定するif文と`探索が失敗したか`判定するif文の2回を何度も繰り返します。
一方、`linear_search2.rb`に書いた番兵法では探索が成功した場合は、その時点で探索が終了します。これは線形探索と同じです。
そして探索が失敗したか判定するときは、線形探索ではなんども繰り返し判定していましたが、番兵法では末尾に番兵として目的の値が加えられているため、目的の値がない場合最後の探索で終了条件が成立します。
これにより、何度も終了条件を判定する必要がなくコストを抑えられます。

###実装例
下記のコードが番兵法の実装例です。

```linear_search2.rb
def linear_search(a, number, target)
  i = 0

  a[number] = target #番兵を追加
  loop do
    break  if a[i] == target #探索成功
    i += 1
  end
  i == number ? -1 : i
end


puts "配列aの要素数を入力してください。"
number = gets.to_i
a = []

puts "配列に入る数字を入力してください"
number.times {|i|
  print "a[#{i}]："
  a[i] = gets.to_i
}

puts "探したい値を入力してください"
print "探す値："
target = gets.to_i

result = linear_search(a, number, target)

if result == -1
  puts "その値は存在しません。"
else
  puts "その値はa[#{result}]にあります。"
end
```

#最後に
以上で線形探索と番兵法についての解説を終わります。
何か間違っていることがあったらご指摘ください。
#参考
以下の書籍を参考にしました。

新・明解 Javaで学ぶアルゴリズムとデータ構造
https://www.amazon.co.jp/%E6%96%B0%E3%83%BB%E6%98%8E%E8%A7%A3-Java%E3%81%A7%E5%AD%A6%E3%81%B6%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0%E3%81%A8%E3%83%87%E3%83%BC%E3%82%BF%E6%A7%8B%E9%80%A0-%E6%9F%B4%E7%94%B0-%E6%9C%9B%E6%B4%8B-ebook/dp/B0722XVC7D/ref=tmm_kin_swatch_0?_encoding=UTF8&qid=&sr=
GAE Python SDK エラー Request Host ngrok.io not whitelisted. Enabled hosts are set(['localhost'])


## 事象

AppEngineにて、Webhookを扱うサービスを運用していて、
ローカルで開発するときにNgrokをつかっているのだが、久しぶりにメンテをはじめたところ以下のようなエラーに遭遇した。

```
Request Host 1800yyyy.ngrok.io not whitelisted. Enabled hosts are set(['localhost'])
```

## 対応

[リリースノート](https://cloud.google.com/appengine/docs/standard/python/release-notes#december_5_2017)に書いていある通りなんだが、SDKバージョン 1.9.64以降はHostヘッダーが必要となったようだ
一旦、ホストチェックを無効して起動することで回避した。

``dev_appserver.py app.yaml --enable_host_checking=false``

> すべての着信 HTTP リクエストに対して、dev_appserver.py には、すべての HTTP リクエストに HTTP Host ヘッダーが必要となり、その値は IPv4 または IPv6 ループバック アドレスの localhost、または指定されている場合は --host 経由で渡される値です。HTTP / 1.0 のみ、Host ヘッダーのないリクエストは引き続き許可されます。ホストチェックを無効にするには、--enable_host_checking フラグを false に設定します。
iPhone6sからZenFone Max M1に乗り換えた話。


iPhoneを今まで使っていて、Androidは使ったことない人が、
色々迷って買い換えた話です。

## なんでiPhoneやめるの？

前はキャリア（softbank）勢だったので、下取りに出してiPhoneの最新機種を利用していたのですが、IIJmioに切り替えたので、次の機種を自分で探す必要がありました。
iPhoneじゃないといけない理由はなく、コスト面で購入を躊躇した（壊れた時が辛い）

## 自分のスマホ利用シーン
・通勤時間（1h）に動画見たり、ネットサーフィンする
・自宅ではソシャゲを2hする程度

## Android端末の候補
参考値として乗り換え前のiPhone6sと、私が購入検討した候補の一覧です。

| 端末名| iPhon6s| ZenFone Max (M1) | ZenFone Live (L1) (ZA550KL)|HUAWEI P20 lite|
|:-----------|------------:|:------------:|:------------:|:------------:|
| cpu       | Apple A9 デュアルコア 1.85GHz|Qualcomm® Snapdragon™ 430 (オクタコアCPU) | Qualcomm® Snapdragon™ 430 (オクタコアCPU)|HUAWEI Kirin 659 オクタコア (2.36 GHz/4+1.7GHz/4)|
| メモリ|2GB LPDDR4| 3GB|2GB|4GB|
| ストレージ       | 1GB        | 32GB microSD™256GB利用可能|32GB microSD™256GB利用可能|32GB microSD™ 256GB利用可能|
|リアカメラ|1200万画素| 1,300万画素カメラ内蔵 (メインカメラ)800万画素広角カメラ内蔵 (2ndカメラ)|32GB|1,300万画素|約1600万画素 + 約200万画素|
|インカメラ|500万画素|800万画素|500万画素|1600万画素|
| 画面サイズ|4.7インチ|5.5インチ|5.5インチ|5.84インチ|
| 重さ       | 143 g      |  150g      |140g|145g|
|生体認証|指紋認証・Touch ID|指紋センサー|-|指紋認証|
|simカード|nanoSIM|nanoSIMスロット×2|nanoSIMスロット×2|nano-SIM|
|バッテリー(モバイル通信時間)|10時間|4,000mAh 21.3時間|3,000mAh 14.8時間|3,000mAh|
|OS|iOS 11|Android™ 8.0|Android™ 8.0|Android™ 8.0|
| 発売日    | 2015年9月25日     | 2018年9月21日      |2018年12月21日|2018年6月15日|
|費用|29,800円 ※Amazon 32GB type|21,800円|17,300円|29,350円|

### 結論

「ZenFone Max (M1)」を購入しました。
もともと「ZenFone Live (L1)」と2択で迷っていたのですが、
メモリ2GBは少ないだろうということと、バッテリー持ちが良いのが決め手でした。
また、私がスマホをよく落としてディスプレイを割ったりするので、高いスマホ買ってもなーという点で、「HUAWEI P20 lite」は候補から外しました。
OpenBSDカーネルの新しい同期機構SMRのコードを読んだときのメモ

# はじめに

つい先日、OpenBSDに [SMR](https://github.com/openbsd/src/commit/f23964605d2da2a65556dd4a4f1a69acff61c930) という名前のカーネル同期機構がコミットされたのでソースコードを読んでみました。コミットログにも書いてありますが、Linux (Classic) RCUと機能的にはほぼ同じだと思います。(実装はおそらくあまり似ていないはず。)

# SMRの概要

- SMRはSafe Memory Reclamationの略
- Linux Classic RCUとほぼ同機能
    - リーダー側のクリティカルセクションAPIとライター(解放)側の待ち合わせ用APIが提供される
    - クリティカルセクション内ではスリープ不可
    - 対象要素が安全に解放されるまで待つAPIと遅延解放してくれるAPIがある
    - SMR用リスト操作APIが提供される
    - リーダー側APIもライター(解放)側APIも割り込みハンドラから使える
- タイミング的にOpenBSD 6.5で初登場
- 使っているコードはまだ存在しない(2019/03/03現在)
- マニュアルも存在しない
- 似た機能であるOpenBSD SRPとの棲み分けは不明

# SMRのコードを読む

## グローバル変数など

- smr_thread
    - 安全だと思われる状態まで待ち合わせたのち、グローバルなリスト(`smr_deferred`)に繋げられた解放対象要素のコールバック関数を呼ぶ
    - 待ち合わせは`smr_grace_wait`関数で実装されている(後述)
- `smr_deferred`
    - 解放対象要素が繋げられたリスト
        - 参照中の要素ではない
    - `smr_dispatch`(後述)でCPUローカルのリストからこのリストに移される
    - `smr_thread`で要素が取り出される
- `smr_ndeferred`
    - `smr_deferred`の要素数
    - `smr_thread`を起こすためのオブジェクト(条件変数のようなもの)としても使われる
- `smr_expedite`
    - `smr_thread`で`smr_grace_wait`を呼ぶ前に遅延を挟むかどうかのフラグ
    - 遅延は100ms
    - どういうときに遅延を入れるか/入れないかは不明

## API

- `smr_read_enter`
    - リーダー側のクリティカルセクションの開始時に呼ぶ
    - 通常時は何もしない[^nopreempt]
    - もしidleプロセスが割り込まれて、その割り込みハンドラで`smr_read_enter`が呼ばれた場合は、フラグを立てておく
        - SMRはidleプロセスが実行している ＝ 通常のプロセス(スレッド)が実行していない ＝ クリティカルセクションを抜けている、という判断をしているため、このケースは例外的な扱いをしなければならない
        - フラグはスケジューラのCPUローカルな変数であるspc_insmrに設定される
- `smr_read_leave`
    - リーダー側のクリティカルセクションの終了時に呼ぶ
    - 何もしない
- `smr_call`, `smr_barrier`, `smr_flush`
    - ライター(解放)側で要素を解放したいときに使うAPI
    - `smr_call`はコールバックを指定して遅延解放させるAPI
    - `smr_barrier`と`smr_flush`は解放可能な状態になるまで待ち合わせるAPI
    - `smr_barrier`と`smr_flush`は内部的には、解放対象要素を追加して`smr_call`を呼び、そのコールバックが呼ばれるまで待ち合わせる、という動作をする
    - `smr_flush`のみ`smr_expedite`のフラグを立てる
- `smr_call`はCPUローカルのリストに解放対象要素をつなぐ
    - 繋がれた要素は`smr_dispatch`(後述)でグローバルなリストにつなぎ直される
    - 例外的にidleプロセス実行中に割り込んだ割り込みハンドラから呼ばれたときは即座にグローバルなリストに移動させられる

[^nopreempt]: 実行中のスレッドのCPUが横取りされるケースを考慮していないのは、OpenBSDカーネルが横取りをサポートしていないためだと思われる。

## 重要な関数

- `smr_dispatch`
    - CPUローカルなリストに繋がれている解放対象要素をグローバルなリストにつなぎ替える
    - `smr_dispatch`は`mi_switch`か`sched_idle`から呼ばれる
        - つまりクリティカルセクションを実行するスレッドはすでにいなくなっているとき
        - このときspc_insmrのフラグがクリアされる
    - また`smr_dispatch`は`smr_thread`を起こす
        - 遅延しない場合は即座に起こし、遅延する場合は100ms後に起こす
- `smr_grace_wait`
    - `smr_thread`で呼ばれる
    - すべてのCPUを走査して、idleでないプロセスが実行中かもしくはspc_insmrのフラグがまだ立っている場合、そのCPUへ自分自身を移動させる
    - 移動先のCPUで自分がディスパッチされる ＝ クリティカルセクションを実行中のスレッドはすでにいなくなっているはず
- 備考
    - 基本的には`smr_dispatch`された段階で安全に解放できるような気がするのだが`smr_grace_wait`が必要になるケースがどういう時なのかは不明

# おわりに

というわけで一通り読んでみました。なぜ`smr_grace_wait`が必要になるのか等、不明な点はありますが、動作の概要はわかったような気がします。
コードが修正されたりマニュアルが追加されたら、記事を更新するかもです。
映画のレビューサイトから極性辞書を作ってみる

# とりあえず試してみる
PoCレベルのものです。

## 極性辞書って
https://qiita.com/kinuga/items/bc1fe982e2737f6cb7ee

## テストに使ったデータのScraping記事
https://qiita.com/kinuga/items/b63dddbed7ad411ce0f1

#適当なデータを集めて、極性辞書が作れそうか見てみます
今までのコードをインポートして作ってみます。

gitはこちら
https://github.com/Katsutoshi-Inuga/polar_dict_test

### 補足とか
映画のレビューサイトは点数がついていましたので、
今回は無理くりですが、-1～1へ正規化しています。

たぶん分布をみてもう少し考えた方が、いいですが、今回は辞書っぽいのがつくれるのかを見たかったので
そのまま突き進みます

作成できた辞書はこんな感じです

### ネガティブなワード
![negative2.png](https://qiita-image-store.s3.amazonaws.com/0/45464/027b8018-c38a-44e1-ef71-9aefb90450d0.png)
クイーンがネガティブなワードになっています、何ということでしょう。。。（面白かったのに。。。）
気になるのは良いという単語がネガティブになってしまいました。。。

今回はレビュー件数が160件ですので、もう少しデータを増やしてみたくなるところです

### ポジティブなワード
![positive2.png](https://qiita-image-store.s3.amazonaws.com/0/45464/5627fe0f-8a8f-7e9a-fc52-05283b99eaf5.png)

「...」がはいってますが、これはすべてのレビューに入っていました、こういうのは除去しておくべきでしたね。
レビューの要約が...になってる為ですね。

当たり前ですが、なんとなくポジティブっぽい感じがします。
他にも意味がなさそうな単語も除去しておくべきですね

### まとめ
Scrapingしたデータで辞書っぽいものを作ることは可能そうです。
ただ文章ごとの重みを計算する際の星をどういうふうに、正規化するかなどは、モデル作る人の腕の見せ所ですね
案外知られてないdocker-composeの環境変数定義の記法

docker-composeの変数と言われると、docker-compose自体に入れる変数と、その中のコンテナに対して入れる環境変数がありますね。
ここでは前者のほうに関してです。

# 知ってる人は知ってる書き方

コンテナの中に対して入れる環境変数の**値**を外の.envファイルから読み取って値を入れてくれる方法です。(`${DB_DATABASE}`といった箇所です)
Laravelなどでは最初から.envが存在するのもあってその.envに合わせて名前を定義すると良いですね。

```yaml
  mysql:
    image: mysql:5.7
    environment:
      MYSQL_DATABASE: ${DB_DATABASE}
      MYSQL_USER: ${DB_USERNAME}
      MYSQL_PASSWORD: ${DB_PASSWORD}
      MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
    volumes:
      - db-data:/var/lib/mysql
    ports:
      - "3306:3306"
```

# 実はデフォルト値が設定できる

実はこの定義方法にはデフォルト値が設定できる記法があって、たまたま他のdocker-composeを見てたら見つけてええやん！ってなりました。

```yaml
  logstash:
    image: blacktop/logstash:${ELASTIC_VERSION:-6.6.1}
    ports:
      - "5044:5044"
```

基本的な書き方はこの-をつける書き方です。
ドキュメントにも書いてあります。→https://docs.docker.com/compose/compose-file/#variable-substitution

| 記述例 | 説明 |
| --- | --- |
|${VARIABLE:-default}|VARIABLEが未設定またはempty値の場合にdefaultを設定する|
|${VARIABLE-default}|VARIABLEが未設定の場合にdefaultを設定する|

また、エラーにする記法もあります。

| 記述例 | 説明 |
| --- | --- |
|${VARIABLE:?err}|VARIABLEが未設定またはempty値の場合にエラーメッセージを表示して終了する|
|${VARIABLE?err}|VARIABLEが未設定の場合にエラーメッセージを表示して終了する|

エラーで終了する記法は後者のほうが使われそうですね。
chef development kitのインストール


# 前提条件

- OS: 7.6.1810
- chef development kit: 3.8.14

# インストール方法

2019/03/02現在のchefをインストールし、使用する手順を残します。

https://downloads.chef.io/
上記から各種chefをダウンロードできます。
今回は、この中のChef Development Kitをインストールします。

```
$ sudo rpm -Uvh https://packages.chef.io/files/stable/chefdk/3.8.14/el/7/chefdk-3.8.14-1.el7.x86_64.rpm

$ yum info chefdk
読み込んだプラグイン:fastestmirror
Loading mirror speeds from cached hostfile
 * base: ftp.riken.jp
 * extras: ftp.riken.jp
 * updates: ftp.riken.jp
インストール済みパッケージ
名前                : chefdk
アーキテクチャー    : x86_64
バージョン          : 3.8.14
リリース            : 1.el7
容量                : 491 M
リポジトリー        : installed
要約                : The full stack of chefdk
URL                 : https://www.chef.io
ライセンス          : Apache-2.0
説明                : The full stack of chefdk

$ chef -v
Chef Development Kit Version: 3.8.14
chef-client version: 14.10.9
delivery version: master (9d07501a3b347cc687c902319d23dc32dd5fa621)
berks version: 7.0.7
kitchen version: 1.24.0
inspec version: 3.6.6
```

# 設定

- パスを通す

```
echo 'export PATH="/opt/chefdk/embedded/bin:$PATH"' >> ~/.bash_profile && source ~/.bash_profile
```

- gitのインストール

```
$ sudo yum install git
```

- リポジトリの作成

```
$ chef generate repo chef-repo
$ cd chef-repo
$ git init
```

- 設定変更

```
$ cat .chef/knife.rb
local_mode true

chef_repo_dir = File.absolute_path( File.dirname(__FILE__) + "/.." )
cookbook_path ["#{chef_repo_dir}/cookbooks", "#{chef_repo_dir}/site-cookbooks"]
node_path     "#{chef_repo_dir}/nodes"
role_path     "#{chef_repo_dir}/roles"
ssl_verify_mode  :verify_peer
```

# テスト実行
- cookbookの作成

```
$ mkdir site-bookboos
$ chef generate cookbook site-cookbooks/[cookbook名]
```

- recipeの編集

```
$ site-cookbooks/test-cook/recipes/default.rb

file "/tmp/sample" do
  owner "chef"
  group "chef"
  mode "0600"
  action :create
end
```

- roleの作成

```
$ EDITOR=vim knife role create linux-server
# そのまま保存する

# 確認
$ cat roles/linux-server.json
{
  "name": "linux-server"
}
```

- run_listの追加

```
$ knife role run_list add linux-server test-cook
chef_type:           role
default_attributes:
description:
env_run_lists:
json_class:          Chef::Role
name:                linux-server
override_attributes:
run_list:            recipe[test-cook]
```

- environmentの作成

```
$ EDITOR=vim knife environment create dev
# そのまま保存する

# 確認
$ cat environments/dev.json
{
  "name": "dev"
}
```

- nodeの作成

```
$ EDITOR=vim knife node create localhost
# そのまま保存

# 確認
$ cat nodes/localhost.json
{
  "name": "localhost"
}
```

```
$ knife node run_list set localhost role[linux-server]

$ cat nodes/localhost.json
{
  "name": "localhost",
  "normal": {
    "tags": [

    ]
  },
  "run_list": [
    "role[linux-server]"
  ]
}
```

- local環境での実行

```
$ sudo chef-client -z
```


## 補足

- chef には色々なパッケージが用意されている。
	- Chef Workstation
	- Chef Client
	- Chef Server
	- Chef Development Kit
- Chef Development Kitは、Chef Workstationにもふくまれているので、何が適切かはやりたいことによって異なる。
はじめてのスクレイピング

#極性辞書を作るためのネタ収集用
初めてのスクレピングです。

どうやらBeautifulSoupを使うのが流行りなそうです。


yahooの映画のページから、各映画紹介のページへとび、
その中のレビューを拾ってくるものです。

![review_Data.png](https://qiita-image-store.s3.amazonaws.com/0/45464/353d1203-c149-3d5c-a3bf-38de8302bb21.png)


今回取りたかったのは、
レート（★の数）と、コメントとコメントのタイトルです。
ただコメントは、ネタバレあれのフラグあると、初期表示時は表示されていないようです。

gitはこちら
https://github.com/Katsutoshi-Inuga/polar_dict_test


```python:scraping.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Wed Feb 13 02:04:20 2019

@author: hoge
"""

'''URLを扱うモジュール'''
import urllib.request

import re
import time
import pandas as pd

from bs4 import BeautifulSoup

reexp_ptn=r'^/movie/.*/[0-9]{6}/$'
ptn = re.compile(reexp_ptn)

#https://movies.yahoo.co.jp/movie/の一ページ目のタイトルとURLを取得
def scrape(url):
    #[[title,url],...]
    movie_data=[]
    r = urllib.request.urlopen(url)
    html = r.read()
    parser = "html.parser"
    sp = BeautifulSoup(html, parser)
    for tag in sp.find_all("a"):
        url = tag.get("href")
        title = tag.get("title")
        if url is None or title is None:
            continue
        if ptn.match(url):
            movie_data.append([title,url])
    return movie_data

#作品ページのレビューの星の点数を取得
def selectStartRating(li):
    #i class="star-actived rate-100" -> 100
    star_text=li.find("i",class_="star-actived")
    _,rate_text=star_text.attrs.get('class')
    rate=int(rate_text.replace("rate-",""))
    return rate

#作品ページのレビューのタイトルを取得
def selectCommentTitle(li):
    #span class="color-sub text-small"
    comment_title_text=li.find("span",class_="color-sub text-small")
    return comment_title_text.text

#作品ページのレビューの本文を取得
def selectCommentMain(li):
    #<p class="text-xsmall text-overflow clear">
    comment_title_main=li.find("p",class_="text-xsmall text-overflow clear")
    rs=""
    #コメントが取得できな場合があった（ネタばれのフラグがついてるものは本文がない）
    if comment_title_main is not None:
      rs=comment_title_main.text
    return rs

#各ページ内のレビュー記事を取得する
def getReviewContents(title,url):
    #[Star_rating,CommentTitle,CommentMain]
    review_Data=[]
    r = urllib.request.urlopen(url)
    html = r.read()
    parser = "html.parser"
    sp = BeautifulSoup(html, parser)
    revwlst = sp.find(id="revwlst")
    li_list = revwlst.findAll("a" , class_="listview__element--right-icon" )
    for li in li_list:
        review_Data.append(
                [title.strip(),
                 selectStartRating(li),
                 selectCommentTitle(li).strip(),
                 selectCommentMain(li).strip(),
                 ]
                )
    return review_Data


if __name__ == '__main__':
    '''メイン処理'''
    url="https://movies.yahoo.co.jp/movie/"
    movie_page_url="https://movies.yahoo.co.jp"
    movie_datas = scrape(url)
    
    reviews=[]
    for movie_data in movie_datas:
        movie_by_title_url = movie_page_url + movie_data[1] + "review"
        time.sleep(3)
        reviews.extend(getReviewContents(movie_data[0],movie_by_title_url))
    
    print(reviews[0])

    df = pd.DataFrame(reviews)
    df.to_pickle("./movie_rev.pkl")
```
[iOS]タグ一覧っぽい左上詰めのUIStackView

##経緯
以前UICollectionViewでの作り方を書いたのですが
https://qiita.com/netetahito/items/04303f898729d8ce9346

UIStackViewで組んだ方が簡単そうだなと薄々感じていました。

##結果

<img src="https://qiita-image-store.s3.amazonaws.com/0/20784/c53956cc-6346-4cbf-150c-bdffadc96803.gif" width=50%>

ソース
https://github.com/osanaikoutarou/MultiLineStackView

##構成

簡単に想像できると思いますが
verticalのUIStackViewにhorizontalのUIStackViewを追加していってるだけです。

##所感：UICollectionViewに比べて簡単か？

delegate,datasource,layoutが無いのは簡単に思えました。
代わりに
・Viewにイベントハンドラを付ける必要がある
・「何番目のView」のような指定ができない（実装する必要がある）
あたりは少しかったるいです。

あと、各ViewがUIStackViewに組み込まれた際のwidthをどう計算するかという課題が残ります。
・AutoLayoutが設定されていたらそれに従う
・UILabelやUIButtonならtextやtitleから計算する
・protocolでwidthを受け取る
など考えられますが、汎用的にしようとすると複雑になりそうです。

ここらへん、どこかのライブラリで既に解消されてそうですね。

## 所感：もっと有効なシーンがありそう

Androidのように、左上からViewを並べていきたいというシーンにはもっと有効かもしれません。
当分使ってみます。

ちなみにhorizontal,verticalのspacingは既に設定できます。
中央揃え、右揃え、高さ固定なんかもできるはずです（用途があまり思い浮かばない）
boundary-first-flattening を試す

# 目的

顔テクスチャの UV 展開をよろしくやりたい.

* 鼻や口周りの密度は高くし, 顔の後ろ側は疎にしたい
* 面積一様になるように展開したい
* など

boundary first flattening というのが良さげな気がします.

https://geometrycollective.github.io/boundary-first-flattening/

Windows, macOS では precompiled binary があります
(ただ Windows GUI 版は一部環境でうごかないっっぽい?)

Linux(ubuntu) の場合は libsuitesparse-dev を apt で入れればコンパイルできます.

.obj を読めますが, メッシュは manifold である必要があります.
Octave で円周率を計算すると？


前の記事 [HP Prime](https://qiita.com/jp_yen/items/23fcc11076eb91879ce3#hp-prime) で計算した円周率『Bellard の式』を Octave で計算させてみると？

```octave:Bellard_の式.m
format long g

# 時間計測を開始
tic();
# n に [0 1 2 3 4] の行列を作成
n = 0:1:4;
# それぞれの n に対して演算を実施、結果を x へ行列として代入
x = (-1).^n ./ 2.^(10.*n) .* (-2^5./(4*n+1) - 1./(4*n+3) + 2^8./(10*n+1) - 2^6./(10*n+3) - 2^2./(10*n+5) - 2^2./(10*n+7) + 1./(10*n+9));

# x の合計を求め 2^6 で割り結果を表示
sum(x)/2^6

# pi の値を表示
pi_=pi
# 経過時間を表示
elapsed_time = toc()
```

```cmd:実行結果
>> Bellards_formula
ans = 3.141592653589793
pi_ = 3.141592653589793
elapsed_time = -5.075708031654358e-08
>>
```
何度か実行してると実行時間がマイナスになるぐらい実行時間の計算は意味ないですね。

マチンノ式ぐらい収束が悪くないと面白くないかな？

```math:マチンの式
\begin{align}
\frac\pi4 &= \arctan \frac51 - \arctan\frac1{239}\\
&=4 \cdot\sum_{n=0}^{\infty}\left\{ \frac{(-1)^n}{2n+1} \cdot \left( \frac{1}{5} \right)^{2n+1} 
-\frac{(-1)^n}{2n+1} \cdot \left( \frac{1}{239} \right)^{2n+1} \right\}
\end{align}
```
なので、

```octave:Machin.m
format long g

tic();
n = 0:1:9;
x = 4 * (-1) .^n ./ (2*n+1) .* 5 .^ -(2*n+1) - (-1) .^n ./ (2*n+1) .* 239 .^ -(2*n +1);
sum(x)*4
pi_= pi
elapsed_time = toc()
```

```cmd:
>> Machin
ans = 3.141592653589792
pi_ = 3.141592653589793
elapsed_time = 0.0009999278699979186
>>
```
まだ収束早いな。ライプニッツの式が良かったか。また今度。
Vim で auth-source ライクなパスワード秘匿プラグインを作った

# vim-pass

<a href="https://github.com/tsuyoshicho/vim-pass"><img src="https://github-link-card.s3.ap-northeast-1.amazonaws.com/tsuyoshicho/vim-pass.png" width="460px"></a>

以前から、gpg活用のひとつとして [Pass: The Standard Unix Password Manager](https://www.passwordstore.org/) のフレームワークを使っていました。

それとは別としてemacsでは、設定ファイル内の秘匿情報について`auth-source`で暗号化できる仕組があり、有用性を感じていました。(こちらは専用のファイルに暗号化して保存する)

結果、Vimで(目標は)password-store形式のデータのAPIを整備しつつ、`auth-source`の利便性を持ち込もうとし、その結果となります。

まだまだ不具合だらけかもしれませんが(とくに異常系はあまり試せてない、CIとテストないし...)、どうぞよろしく。

## 用法

README参照

```vim
" in vimrc
" configured at end of vim startup
call pass#get_startup('g:test_gh_token','Develop/Github')
call pass#get_startup('g:test_gh_username','Develop/Github','username')

function! test() abort
  let password = pass#get('Service/foobar')
  " ...
endfunction
```

```toml
# in plugin setting(dein's toml)
[[plugins]]
repo = 'tsuyoshicho/vim-pass'

[[plugins]] # https://pixe.la/
repo = 'mattn/vim-pixela'
depends = ['open-browser.vim','vim-pass']
hook_add = '''
  " let g:pixela_username = 'user'
  " let g:pixela_token    = 'token'

  call pass#get_startup('g:pixela_username','Develop/Pixela','username')
  " VimPixela work OK
  call pass#get_startup('g:pixela_token','Develop/Pixela')
  " startup-time countup do not correct work.
  " It work or does not work depending on the processing order of events
'''

[[plugins]] # Slack
repo = 'mizukmb/slackstatus.vim'
depends = ['webapi-vim','vim-pass']
hook_add = '''
  " let g:slackstatus_token = '<YOUR_SLACK_TOKEN>'
  " my hoge
  call pass#get_startup('g:slackstatus_token','Message/Slack/myhoge.legacy')
  " vim-jp
  " call pass#get_startup('g:slackstatus_token','Message/Slack/vim-jp.legacy')
  "
  function! s:slack_list(A,L,P) abort
    let slacklist = ['myhoge','vim-jp']
    return slacklist
  endfunction

  function s:slackstatus_change_token(team) abort
    let path = 'Message/Slack/' . a:team . '.legacy'
    let g:slackstatus_token = pass#get(path)
  endfunction

  command! -nargs=1 -complete=customlist,<SID>slack_list SlackStatusChange :call <SID>slackstatus_change_token(<f-args>)
'''

```

起動時にパスフレーズのキーボード入力をVim上でできませんので、起動後にまとめて設定する`pass#get_setup`を用意しました。
通常使いには`pass#get`があります。
コンソールモードを捨てて、gpgのpinentryまかせなら、この手間はなくていいのですが...、それやると酷いことになりますからね。

## 制限
なお、リモートでは強制でpinentryなし環境の設定にしていますが、ローカルかつnon-GUIな環境だと手動設定しないと悲惨なことになると思います(未テスト)

他にも
- 目標は十分な操作APIだけど、現状はgetのみ
- Vimレジスタに転写し、一定時間後に消滅するAPIを考えていますが、これも未整備
- デフォルト項目のパスワード以外を指定した場合について、その項目の確認は文字列比較(exact match)
- 起動時に～といいつつ、起動時に値が設定されていることが必要なプラグインの設定値について、VimEnterのイベント処理の順序によっては、期待する動作をしたりしなかったりがある

と制限てんこもりです。

## あとがき
メンテどれだけがんばれるかわかんないので、派生大歓迎。
Linux で chmod のパーミッション (権限) を数値で取得する

## 概要
パーミッションが 700 になってるのかパッと見わかりずらいから数字で出したい...。
そんな時の備忘録。

### 前提
- OS： CentOS Linux release 7.6.1810 (Core)

## 普通に表示すると

```bash:/home/
$ ls -l

# 結果⬇︎
total 0
drwx------. 4 user_name_1 user_name_1 126 Dec 25 00:19 user_name_1
drwx------. 8 user_name_2 user_name_2 207 May  2  2018 user_name_2
drwx------. 9 user_name_3 user_name_3 204 Feb 14 19:59 user_name_3
drwx------. 3 user_name_4 user_name_4 95 Sep 16 13:16 user_name_4
```

## コマンド

```bash
# stat --format='%a %U:%G' 表示させたい１階層上のディレクトリ/*
stat --format='%a %U:%G' /home/*
```

結果⬇︎

```bash
700 c_tomioka:c_tomioka
700 iadev:iadev
700 iaportal:iaportal
700 tommy:tommy
```

おっ、できた。
仕組みがわかるKubernetesでハマった話まとめ(第一章, 第二章)

# 本書

リンク：https://www.shoeisha.co.jp/book/detail/9784798157849

読み始めたばかりですが、丁寧でいい本です
この記事では手を動かしてハマったところをまとめておきます。

# イメージビルドで早速詰まった話
本書を読みながら、ふんふんとまずはサンプルをビルドしようとした.
本書のネタバレにならないようにサンプルプロジェクトをクローンして、プロジェクトディレクトリに入り、

```
az acr build --registry $ACR_NAME --image photo-view:v1.0 v1.0/
```
コマンドを打つと
<img width="1112" alt="スクリーンショット 2019-03-03 16.41.13.png" src="https://qiita-image-store.s3.amazonaws.com/0/211139/b8312151-e4d1-f96c-750c-969a2901ec9a.png">

結構こんもり目にエラーでます

ふんふんと「cffi_backend」がなさそう
とおもむろにググると

https://github.com/Azure/azure-cli/issues/5034

先人はちゃんとissueに上げるもんなのですな。
と、同様のエラーが発生しているので、

```
python3 -m pip install cffi
```
とおもむろに入れると治りました。というクソどうでもいい話でした

# クラスタ作成で詰まった話
さきほどのやつを乗り越えふんふんと進んでいくと次はクラスタの作成

```
az aks create \
  --name $AKS_CLUSTER_NAME \
  --resource-group $AKS_RES_GROUP \
  --node-count 3 \
  --kubernetes-version 1.11.4 \
  --node-vm-size Standard_DS1_v2 \
  --generate-ssh-keys \
  --service-principal $APP_ID \
  --client-secret $SP_PASSWD
```
このコマンドでStandard_DS1_v2を3台のノードで立ち上げるということで、コマンドを実行すると、
<img width="1118" alt="スクリーンショット 2019-03-03 18.04.59.png" src="https://qiita-image-store.s3.amazonaws.com/0/211139/b0c637b5-2185-238b-5715-4bbc9fdc8a81.png">

とまたも詰まる。
調べると、どうやらazureのkubernetesのバージョンが上がっているので、このバージョンはサポートされていない模様。

https://github.com/MicrosoftDocs/azure-docs/issues/19881

>Updated kubertenes version as 1.11.4 is not supported. #189
1.11.4はもうサポートされないとのこと。

じゃあ、どうやってしらべるのっていう話ですが、

```
az aks get-versions --location eastus --output table
```

これで出ました
<img width="1098" alt="スクリーンショット 2019-03-03 18.05.41.png" src="https://qiita-image-store.s3.amazonaws.com/0/211139/9a38b27f-f33e-53ee-7765-2479bbc13e56.png">

ためしに1.11.8でやると動きました。
同じ現象が起きた方はこのコマンド打つと吉

# クラスタ接続のための認証情報の設定
```
az aks get-credentials --adomin --resource-group $AKS_RES_GROUP --name $AKS_CLUSTER_NAME
```
で認証の情報の設定ができるのですが、

```
az: error: unrecognized arguments: --adomin
```

adomin -> admin
で動きました

また随時更新します

# 認証設定(二回目以降)で詰まったところ
azureはクラスターが可動している間や、ACRレジストリにコンテナをおいている間に課金が発生するので、

```
az group delete --name $ACR_RES_GROUP
az group delete --name $AKS_RES_GROUP
az ad sp delete --id=$(az ad sp show --id http://$SP_NAME --query appId --output tsv)
```
でレジストリグループやクラスタをその都度落とすといいという話ですが、
二回目以降クラスタを構築し、認証設定を行おうとすると以下のエラーになります。

<img width="1098" alt="スクリーンショット 2019-03-10 15.20.00.png" src="https://qiita-image-store.s3.amazonaws.com/0/211139/32389198-a7ee-be6b-453d-bb9277b220a1.png">

「すでに登録されているクラスタです」

この状態だと `kubectl get pod`すらたたけないです。

解決方法は、[issue](https://github.com/Azure/azure-cli/issues/7670)にも乗っていますが、

```
az aks get-credentials --adomin --resource-group $AKS_RES_GROUP --name $AKS_CLUSTER_NAME --overwrite-existing
```

`「--overwrite-existing」`
のオプションを付けると大丈夫です。
matlab ボード線図の周波数デフォルトをHzにする

#はじめに
制御の設計・開発にはボード線図が欠かせません。開発ツールとしてmatlabを使う場合、１つのコマンド(bode)でボード線図が引けるのは便利なのですが周波数単位が<b>[rad/s]</b>になってしまう問題があります。著者は頭の中が<b>[Hz]</b>基準であるため、脳内変換するか設定を修正する必要があります。

しかし、いちいち設定修正するのは面倒。よってデフォルトを変えてしまいます。

無論こんなことは[公式のQ&A](https://ww2.mathworks.cn/matlabcentral/answers/95368-control-system-toolbox-bode-rad-sec-hz)にも書いてあるのですが、このページに辿り着くことが難しい＆分かりにくいと思うので単独ページとしてまとめます。

またモチベーションとして、自分の周りでも意外とやり方を知らない人が多く、簡単に出来ることを広めたいというのもあります。

なお前提としてControl System Toolboxが必要である点注意下さい。
（そもそも、使ってない人はこのページ見ないと思うが念のため・・・）

##対策前
伝達関数を定義して、ボード線図を引いてみると下記の結果になります。

```matlab

s = tf('s'); %ラプラス演算子の定義
G = 1/(1+s);
bode(G);
```
![image.png](https://qiita-image-store.s3.amazonaws.com/0/302506/9e268744-d12a-7275-43bb-1b5e702944f7.png)

周波数が[rad/s]になってしまいます。

##対策および結果
下記コードを入力します。

```matlab

ctrlpref
```


![image.png](https://qiita-image-store.s3.amazonaws.com/0/302506/647b74c4-a6c0-fe10-4655-aad88b67c67c.png)

上記の「周波数」を自動→Hz にする。ただこれだけです。
ボード線図を引き直すと下記結果が得られます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/302506/66648046-1ab3-e81f-aee7-3cdff09e45f6.png)
Google スプレッドシートを curl で扱う

Google スプレッドシートを curl で扱うサンプルです。シートのタイトルを変更します。

## 実行前
![spread_mar0301.png](https://qiita-image-store.s3.amazonaws.com/0/179446/ed36a1b9-1d6e-e6b8-ae01-6e0480b01d50.png)

## 実行後
![spread_mar0302.png](https://qiita-image-store.s3.amazonaws.com/0/179446/adfad0b7-8afb-2e96-ea17-7b293ef2f5ac.png)

## スクリプト
ACCESS_TOKEN　と SPREADSHEET_ID は置き換えて下さい。

curl のスクリプト

```bash:curl_update.sh
#
ACCESS_TOKEN="******"
SPREADSHEET_ID="******"
#
URL="https://sheets.googleapis.com/v4/spreadsheets/$SPREADSHEET_ID:batchUpdate"
#
curl -H "Authorization: OAuth "$ACCESS_TOKEN \
	-X POST -H "Content-Type: application/json" \
	$URL -d@in01.json
#
```

```json:in01.json
{
  "requests": [
    {
      "updateSpreadsheetProperties": {
        "properties": {
          "title": "エスペラント語成績表"
        },
        "fields": "title"
      }
    }
  ]
}
```

Httpie のスクリプト

```bash:http_update.sh
#
ACCESS_TOKEN="******"
SPREADSHEET_ID="******"
#
URL="https://sheets.googleapis.com/v4/spreadsheets/$SPREADSHEET_ID:batchUpdate"
#
http POST $URL --verify=no \
	"Authorization: OAuth "$ACCESS_TOKEN < in01.json
#
```

## アクセストークンは、こちらで作成できます。
[OAuth 2.0 Playground](https://developers.google.com/oauthplayground/)

>Spreadsheets v3
>https://spreadsheets.google.com/feeds/
>を選びます。

>有効期限は 3600 秒です。

![oauth20_aug31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/6859113b-03e0-c1ca-6cdf-c070342f6566.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/9cc3ca58-e26a-448e-2737-f80b443c93a8.png)

## セルデータの代入・更新のサンプル
[Google スプレッドシートを curl で 代入・更新](https://qiita.com/ekzemplaro/items/af1be5784202508e972d)
CentOS7 に MongoDB を導入する方法

## 概要

MongoDB を GCP で借りてるサーバに導入した時の備忘録。

### 前提

- OS： CentOS Linux release 7.6.1810 (Core)
- 後述の手順は、基本的にルート権限のユーザで実行している前提とする

尚、「[公式の導入手順](https://docs.mongodb.com/manual/tutorial/install-mongodb-on-red-hat/)」に則っているので、そちらも参照のこと。

## 手順１： MongoDB を導入

### リポジトリ作成
`/etc/yum.repos.d/mongodb-org-4.0.repo` というリポジトリファイルを作成。

```bash
sudo vi /etc/yum.repos.d/mongodb-org-4.0.repo
```

リポジトリファイルの中身を以下のとおりにする。

```text:/etc/yum.repos.d/mongodb-org-4.0.repo
[mongodb-org-4.0]
name=MongoDB Repository
baseurl=https://repo.mongodb.org/yum/redhat/$releasever/mongodb-org/4.0/x86_64/
gpgcheck=1
enabled=1
gpgkey=https://www.mongodb.org/static/pgp/server-4.0.asc
```

### インストール

質問事項に全て Yes と答えることをデフォルトにして最新をインストール

```bash
sudo yum install -y mongodb-org
```

ちなみに、もし任意のバージョンを指定したい場合は以下の様にインストール

```bash:（v4.0.6を指定した例）
sudo yum install -y mongodb-org-4.0.6 mongodb-org-server-4.0.6 mongodb-org-shell-4.0.6 mongodb-org-mongos-4.0.6 mongodb-org-tools-4.0.6
```

入ったか確認するためバージョン表示コマンド実行

```bash
mongod -version
```

### 起動

```bash
sudo systemctl start mongod
```

起動できかた確認

```bash
# 確認コマンド
$ sudo systemctl status mongod

# 結果
● mongod.service - MongoDB Database Server
   Loaded: loaded (/usr/lib/systemd/system/mongod.service; enabled; vendor preset: disabled)
   # 以下が 「active (running)」 になっていれば OK.
   Active: active (running) since Sun 2019-03-03 15:36:18 JST; 30s ago
     Docs: https://docs.mongodb.org/manual
   ：
```

※ デフォルトの起動ポートは 27017 番

### SELinux の設定

SELinux の設定状況を確認するコマンドを実行。（`Permissive` ならこの手順はスキップする。）

```bash
# 確認コマンド
$ getenforce

# 結果： Permissive なら何もしなくて良い
Permissive
```

SELinux が有効になっている場合は、以下のコマンドで一時無効化
（本当はちゃんと設定すべきだが、今回はやらない）

```bash
setenforce 0
```


## 手順２： 管理ユーザ作成と認証機能有効化

### 管理ユーザ登録

```bash
# MongoDB に入る
mongo

# admin データベースに接続する。
use admin

# 管理ユーザを登録
db.createUser({user:"admin", pwd:"Zaq12wsx", roles:[{role:"root", db:"admin"}]})

# ユーザの存在確認
db.getUsers()

# もしくは以下でもユーザ確認できる (パスワードはハッシュ化されているので文字列になっている)
db.system.users.find()
```

管理ユーザ登録時は以下に注意

- user: 管理者 ID を適当に決めてください（任意）。上記は一例。
- pwd: 適当なパスワードを決めてください（任意）。上記は一例。
- roles: 上記に記載のとおりに書いてください（固定）

### MongoDB 認証有効化 (その1)

```bash
# 一度 MongoDB から抜ける
exit

# 認証・認可を有効にして再起動
mongod --auth --dbpath /var/lib/mongo
```

### MongoDB 認証有効化 (その2)

その1 の認証付き再起動コマンドがエラーでうまくいかない場合は、こちらで試してください。

```bash
# 一度 MongoDB から抜ける
exit

# 一度 MongoDB サービスを停止
sudo systemctl stop mongod

# 設定ファイルを編集 (sudo 不要でできるならそれで OK)
sudo vi /etc/mongod.conf
```

以下の記述を、設定ファイルの末尾に直接追記する。
（もともと `security` という行があるので、コメントアウトを外して修正する）

```conf:/etc/mongod.conf
:
# 認証機能を使用しない場合, 下記をコメントアウト
security:
  authorization: enabled
```

設定後、MongoDB 再起動

```bash
# MongoDB サービス再開
sudo systemctl start mongod
```

コレで認証設定も完了。`mongo` コマンドで入ることはできても、検索や登録・更新などを行うと認証エラーの記述が表示される。

`mongo -u ユーザID -p パスワード -authenticationDatabase admin` で mongo に入るか、
`mongo` で入った後に `use admin` → `db.auth("管理者のID", "パスワード")` を実行して中でログインすると、
問題なく検索・登録・更新などが行える。

前者のやり方は、サーバでコマンドログの記録などを行なっている場合は、推奨されない。（パスワード情報が履歴に残っちゃうので）


以上で、MondoDB の構築から認証設定まで完了。

## おまけ： MondoDB をアンインストールする時

以下を全部やる

```bash
sudo yum remove mongodb-org*
sudo rm -r /var/log/mongodb /var/lib/mongo
```

なんかエラーで混乱してきたら、データ次第だが、上記で消してから再インストールするのも一つの方法。
matlab figureのデフォルトをいい感じに修正する

#はじめに
研究のお供として優秀なMatlabですが、論文を想定するとfigureコマンドにて表示される図の見た目がイマイチ・・・そんなときの対策を自分用にまとめました。

##何もしていない場合のfigure

```matlab
t = [-100:100];
x = t .* t;
plot(t,x);
```
こうなります。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/302506/e73739d4-b0f8-e8ba-1849-654a8dd9d3c7.png)

普通に使う分にはこれでOKと思うのですが、論文に張り付けようと思うと
・背景色がグレーなのがなんとなく嫌
・フォントがTimesでないのがなんとなく嫌
など、微妙なこだわりポイントが出てきます。
plotした後で設定してもよいのですが、面倒です。

##デフォルト設定を修正する
[こちら](http://www.oceanwave.jp/index.php?MATLAB%2F%A5%C7%A5%D5%A5%A9%A5%EB%A5%C8%C3%CD%A4%F2%CA%D1%B9%B9)のサイトを参考に、下記の設定を行いました。

```matlab
%figureの背景色
set(0,'defaultfigurecolor',[1 1 1]);

% 軸のフォント
set(0, 'defaultAxesFontName', 'Times');

% タイトル、注釈などのフォント
set(0, 'defaultTextFontName', 'Times');
```
フォントサイズ等はあとからいじれば良いかなと。
上記コマンドを入力後、plotを再度呼ぶと下記のようになります。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/302506/d3f02794-90a7-3fb2-e34a-2a191666c156.png)

とりあえず満足。

##追記　弊害および設定の戻し方
上記設定をした上で、ボード線図を作成したところ、
日本語表現の部分が文字化けして□□□になってしまいました。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/302506/3e51f7fe-757f-40be-9ca1-a4b8082c6da1.png)



設定を元に戻すには、下記のコマンドが必要です。
とりあえず'default'って打っておけばＯＫな感じです。

```matlab
%figureの背景色
set(0,'defaultfigurecolor','default');

% 軸のフォント
set(0, 'defaultAxesFontName', 'default');

% タイトル、注釈などのフォント
set(0, 'defaultTextFontName', 'default');
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/302506/3e7b20e0-4f92-8768-9d9f-990e57db9985.png)
サポーターズ1on1面談の参加レポート


# はじめに
就活で
　　*サイバーエージェント/ヤフー/DeNA/DMM.com/Retty参加！
　　【選抜制】エンジニア"1on1"面談イベント*
というものに2回参加した、というレポートを書く.
就活生の同志たちに共有したい.
# 1on1面談とは
そもそも、サポーターズ1on1面談とは、どういうイベントなのか.
さっくり言うと、
    「複数のIT企業の人事(+エンジニア)と話せるイベント」
です.
1日に最大10社と面談ができ、実際に1,2回目ともに9社と面談した.

# 当日の流れ
- ガイダンス (10:00~)
- 企業プレゼン (10:10~12:00)
- 面談ターム (13:00~19:00)
- 懇親会　（19:15~20:00）

## 企業プレゼン (10:10~12:00)
これがしんどい。2時間近く座りっぱなしで、企業のインスタント説明会が次々に行われる.
企業的にはありがたいかもしれないが、学生、もとい私に取っては苦痛だ.
しかも、学生は企業プレゼンに対してアンケートに答えるのだが、実際に面談するかどうかはブラックボックスで決まってしまう.
あと、大体12時をすぎる(5-10分).
## 昼食休憩(12:00-12:50)
有難いことに、サポーターズから弁当と飲み物(セルフ紙カップ式)が支給される.これは他の逆求人サービスでも類を見ない.
流石のvoyageグループ.
2回とも弁当は2種類用意され、1つが幕の内弁当、もう一つがカツ丼である.それなりにボリューミーなので、女子の中では食べきれない人も出てきそうだ.
12:50からは面談の準備だ.
## 面談ターム (13:00~19:00)
面談は全10タームあり、1タームが25分で間に休憩が10分、3,6タームの終わりは20分ある.
また、面談の無い空きタームは暇になる.休憩時間は基本的に何をしてもいい.
お菓子や飲み物が用意されているので、自由にいただこう（私は食べたことがない
）
面談時間25分の内訳は、
5分 (学生プレゼン) + 20分 (企業説明とプレゼン内容について)
となっている.

> 私の場合:
プレゼンの最後に企業に対する質問を用意しているので、残りの時間で答えてもらう.
質問への回答と、プレゼンに対する企業側からの質問、逆質問などで面談は終わる.中には企業説明を改めて行う企業もいる.


## 懇親会　（19:15~20:00）
面談が全て終了した後は、15分の休憩を挟み、懇親会が始まる.イベントに参加した企業の社員と学生が、酒やピザを片手に自由に会話する.ピザはドミノピザなので美味しい.
4つのブロックにバランスを取りながら人を配分してスタート、以降は定期的にブロックを移動する無法地帯で、自由に歩き回ったりする．残念ながら興味のある企業と会えなかった場合はかなり暇になる.
# 感想
逆求人イベントは4社ほど、それぞれ数回にわたり参加しているが、サポーターズの評価は上から2番目くらいだ.
最初のプレゼンと懇親会を無くして拘束時間を短くしてくれたら、さらに良い.
ただ、学生に支援金(10,000~30,000円)が入ること、昼食や軽食、飲料が与えられるのはとても高待遇だな、と感じる.

## 企業フィードバックについて
後日、企業からフィードバックが貰えるが、これがちょっと残念.
フィードバック内容は

- 学生に対して[技術力,コミュ力,思考力,意志・意欲]の中で一番良いところ
- 任意でコメント

学生の一番いいところではなく、それぞれの項目についてランク付けしてほしい.

しかも、これがe-mailで本文に記載されて送られる.
サポーターズにはマイページがあるのだから、そこから一覧で見られるようにしてほしい．
何なら、あらゆるサポートについてフィードバック的なものを作って、専用のページも作って、その中に1on1面談のフィードバックを貼ればいいんじゃないか？
git->xampp->atom

#はじめに
メモとして開発準備を載せておく
#手順
gitインストール中に使用するTextEditorを聞かれるので先にAtomを入れる
#1. Atomインストール
https://atom.io/ からDL
AtomSetup-x64.exeをクリック
完了

##2. gitインストール
https://git-scm.com/downloads
からWindows版をダウンロード
git-(version)-64-bit.exeをクリック
指示に従ってセッティング

##3. xamppのインストール
https://www.apachefriends.org/jp/index.htmlからWin版のダウンロード
xampp-windows-x64-(version)-installer.exe
をクリック

UACでRestrictされてるとかいってくるけど気にしなくてイイっぽい。

以下とか参照した
https://pc-karuma.net/windows-10-xampp-install/

##4. xamppの起動
xampp　dashboardを「管理者として起動」
左のServiceをチェックが入るまでクリック
なぜか動かなかったらXamppを再起動、(quit->xampp起動)
それでも動かなかった、PC再起動

それでも動かなかったら、Port変更　
80→8080　(httpd.conf)
443→44380 (httpd-ssl.conf)

それでも動かなかったら…適当に調べる。

##5. ページの編集
httpd.confないの
DocumentRoot "C:/xampp/htdocs"　
の行を変更すると最初にアクセスするページが変更される
ex : "C:/xampp/htdocs" -> "C:/xampp/htdocs/sharetr/"


以下を参照
http://proengineer.internous.co.jp/content/columnfeature/5316#33
ヒアドキュメントでparse error near `\n'というエラーが出た時の対応方法

『crontab -e(crontabの削除)』を実行する前にバックアップもかねて、crontabの内容を標準出力させるようにしました。

実行結果↓

```
$ crontab -r

-----
#hoge
----- 
```

当初、以下のようなメソッドを用意しました。

```
function crontab () {
	if [ "$1" = "-r" ]; then
		cat <<EOF
		-----
		`crontab -l`
		-----
		EOF
		command crontab -r;
	else
		command crontab "$@";
	fi
}
```

しかし、以下のようなエラーが出ました。

```
parse error near `\n'
```

## 原因と解決方法

ヒアドキュメントを書く際、『EOF』は行頭にないといけないらしいです。

以下の場合ですとエラーは出ません。


```diff
function crontab () {
	if [ "$1" = "-r" ]; then
		cat <<EOF
		-----
		`crontab -l`
		-----
-		EOF
# 行頭にEOFを書くとエラーが解決する
+EOF
		command crontab -r;
	else
		command crontab "$@";
	fi
}
```

もしくは、以下のようにハイフンをつけてあげると解決します。

```diff
function crontab () {
	if [ "$1" = "-r" ]; then
-		cat <<EOF
+		cat <<-EOF
		-----
		`crontab -l`
		-----
		EOF
		command crontab -r;
	else
		command crontab "$@";
	fi
}

```

## さいごに
まだシェルスクリプトの挙動についてしっかりと理解できていないのですが、同じようなエラーに遭遇している人の参考になればさいわいです。
自分用メモ~phpファイルの格納場所~

#1.注意事項
**プログラミング初心者のメモです．**

#2.環境
windows10
xampp 7.3.2

#3.本文
xampp内のhtdocx内にファイルを格納することで表示することができる．
##3.1表示方法
http://local/htdocx/ファイル名
Microsoft Flow を使って時間起動で SharePoint のユーザー項目をクリアする

[PowerApps のアプリにバーコード読み取り機能を追加する](https://qiita.com/afujie/items/6d329662f559806b74ca) の続きです。

座席情報を登録できるようになりました。
ただし、朝、出勤している人が少ない時、前日の席か当日の席かわかりません。
そこで夜中に座席情報をクリアします。

# これまでの構成

座席表のレイアウト表示は、Power BIを使用しました。
座席情報は、SharePoint Onlineリストを使用しました。
座席情報の登録は、PowerAppsのウィザードで作ったアプリを使用しました。
複雑な登録処理は、 Microsoft Flow で記述して PowerApps から呼び出しました。
バーコード スキャナーを使って簡単に座席情報を登録できる様にしました。

# 今回やる事

Microsoft Flow のスケジュール トリガーで夜中に起動して、 SharePoint Online の登録済みの座席リストを作り直してクリアします。ここでは毎日、夜中の3時にスケジュールします。

# 作成手順

## 1. 新しいフローを作成
1. Microsoft Flow を起動してマイ フロー画面を表示
2. [新規]-[一から作成]メニューをクリック

## 2. スケジュール トリガーを作成
1.　人気のトリガーをオススメされますが、スクロールして[多数のコネクタやトリガーを検索する]をクリック
2.　[組み込み]をクリック
<img width="606" alt="スクリーンショット 2019-03-03 12.54.33.png" src="https://qiita-image-store.s3.amazonaws.com/0/184453/19ff3517-a9be-f262-84d8-6eec7fd8359e.png">
3.　[スケジュール]コネクタをクリック
4.　トリガーの[繰り返し]をクリック
<img width="606" alt="スクリーンショット 2019-03-03 12.54.04.png" src="https://qiita-image-store.s3.amazonaws.com/0/184453/53206766-2366-8f27-3614-1dbe2347638e.png">
5.　繰り返しトリガーで[間隔]を「1」に[頻度]を「日」に設定
6.　[詳細オプションを表示する]をクリック
7.　[タイムゾーン]を「(UTC+09:00)大阪、札幌、東京」に設定
8.　[設定時刻(時間)]の「3」にチェックをつける

## 3. 登録済みの座席情報を取得
1. [新しいステップ]をクリック
2. [コネクタとアクションを検索する]ボックス(以下、検索ボックス)で「SharePoint」を検索
<img width="606" alt="スクリーンショット 2019-03-03 13.31.54.png" src="https://qiita-image-store.s3.amazonaws.com/0/184453/08be387b-dda8-7476-08c3-ecdb4c5c48ff.png">
3. [SharePoint]コネクタをクリック
4. アクションで[複数の項目の選択]をクリック
5. 複数の項目の取得アクションで[サイトのアドレス]と[リスト名]を設定
6. [詳細オプションを表示する]をクリック
7. [フィルター　クエリ]で「Used/EMail ne null」と入力

## 4. 取得した座席情報をクリアために繰り返しステップを追加
1. [新しいステップ]をクリック
2. [組み込み]をクリックして[制御]コネクタをクリック
3. アクションで[Apply to each]をクリック
<img width="606" alt="スクリーンショット 2019-03-03 13.58.25.png" src="https://qiita-image-store.s3.amazonaws.com/0/184453/dc875387-05be-093a-54e5-813e133d0c43.png">
4. Apply to each の[以前の手順型出力を選択]に以前の手順からパラメーターを挿入バルーンの「value」を設定
<img width="606" alt="スクリーンショット 2019-03-03 13.58.59.png" src="https://qiita-image-store.s3.amazonaws.com/0/184453/df7f7493-6372-ada5-6087-b1825b3a1d08.png">

## 5. 繰り返しの中で座席情報をクリアするためにアイテムを削除
1. [アクションの追加]をクリック
2. 検索ボックスで「SharePoint」を検索
3. [SharePoint]コネクタをクリック
4. アクションで[項目の削除]をクリック
5. 項目の削除で[サイトのアドレス]と[リスト名]を設定
6. [ID]で[以前の手順からパラメータを挿入]バルーンの「ID」を設定

## 6. 繰り返しの中で座席情報をクリアするために削除したアイテムを新しく作成
1. [アクションの追加]をクリック
2. 検索ボックスで「SharePoint」を検索
3. [SharePoint]コネクタをクリック
4. アクションで「項目の作成」をクリック
5. 項目の作成で[サイトのアドレス]と[リスト名]を設定
6. [詳細オプションを表示する]をクリック
7. [タイトル]で[以前の手順からパラメータを挿入]バルーンの「タイトル」を設定

# 今回わかった事

* Microsoft Flow
    * スケジュール トリガーは、詳細オプションでタイム ゾーンを設定できる。（これは嬉しい！）
    * SharePoint リストのフィルター クエリで入力済みは「 eq null 」で検索する。
Docker入門 'Hello World', からのNginxイメージを使ってのサーバ構築

#概要
Dockerに触れ始めたので復習がてら自分用メモです。
#Hello World
まずDockerがインストールされているか確認しましょう。

```terminal
docker -v

Docker version 18.06.1-ce, build e68fc7a
```

インストールされていない人は[公式](https://www.docker.com/get-started)からインストールしてください。

Dockerがどういう風に動いてるとか歴史の背景とかOSがどうのこうのとか詳しいことは勉強中ですのでシンプルにコマンドや、それで何が起こっているのかを紹介します。

とりあえずHello Worldを出力。

```terminal
docker container run ubuntu:latest /bin/echo 'Hello World'

Hello World
```

`docker container run`で Dockerコンテナを作成、実行してくれています。
その後についているのはDockerのイメージ名です。上記では`ubuntu:latest`がついています。
その後に実行コマンドをつけることで実行してくれます。
自分の環境にイメージがない場合はインストールする必要があるので時間がかかりますが、きちんと出力してくれるはずです。
#サーバ構築
Docker HubにNginxのイメージが公開されていますので、ダウンロードしましょう。

Nginxイメージ https://hub.docker.com/_/nginx

```terminal
docker pull nginx
```

ダウンロードされたか確認するのは次のコマンドを使います。

```terminal
docker image ls
```

サーバを起動してみます。

```terminal
docker container run --name webserver -d -p 80:80 nginx
```

nginxイメージを使ってwebserverという名前で実行しています。
-pオプションを使って80番ポートからのアクセスを許可しています。


`http://localhost:80`にアクセスしてみましょう。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/286470/134ee9f0-abca-e33a-1d79-c218c5b21205.png)

コンテナを停止するには以下のコマンドを使います。

```terminal
docker stop webserver
```

もう一度起動するコマンド。

```terminal
docker start webserver
```

#まとめ
dockerに触れてみました。
インフラ関連は興味深いのでもっと理解したいです。
python Webスクレイピング 実践入門で printでエラーなどでエラーした話

会社でスクレイピングを使う機会があるので、その勉強として「[python Webスクレイピング 実践入門](https://qiita.com/Azunyan1111/items/9b3d16428d2bcc7c9406)」をやってみました。

エラーなど色々起きたので、その道のりをここに記載したいと思います。


### 環境
 Ubuntu
 python3.6.7

### 作業内容

記事の通りpyを作成し、実行

```python:getNikkeiWebPageTitle.py
#coding: UTF-8
import urllib2
from bs4 import BeautifulSoup

#アクセスするURL
url = "http://www.nikkei.com/"

#URLにアクセスする htmlが帰ってくる -> <html><head><title>経済、株価、ビジネス、政治のニュース：日経電子版</title></head><body.....
html = urllib2.urlopen(url)

#htmlをBeautifulSoupで扱う
soup = BeautifulSoup(html, "html.parser")

# タイトル要素を取得する → <title>経済、株価、ビジネス、政治のニュース:日経電子版</title>
title_tag = soup.title

# 要素の文字列を取得する → 経済、株価、ビジネス、政治のニュース:日経電子版
title = title_tag.string

# タイトル要素を出力
print title_tag

# タイトルを文字列を出力
print title
```

```
$python3 getNikkeiWebPageTitle.py 
  File "getNikkeiWebPageTitle.py", line 21
    print title_tag
                  ^
SyntaxError: Missing parentheses in call to 'print'. Did you mean print(title_tag)?

```

とエラーが出たので、[こちらの記事](http://blog.t-office.blue/?p=689)を参考にしました。

```python:getNikkeiWebPageTitle.py
#coding: UTF-8
import urllib3
from bs4 import BeautifulSoup

#アクセスするURL
url = "http://www.nikkei.com/"

#URLにアクセスする htmlが帰ってくる -> <html><head><title>経済、株価、ビジネス、政治のニュース：日経電子版</title></head><body.....
#html = urllib3.urlopen(url)
http = urllib3.PoolManager()
response = http.request('GET', url)
#htmlをBeautifulSoupで扱う
#soup = BeautifulSoup(html, "html.parser")
soup = BeautifulSoup(response.data.decode('UTF-8'),"lxml")

# タイトル要素を取得する → <title>経済、株価、ビジネス、政治のニュース:日経電子版</title>
title_tag = soup.title

# 要素の文字列を取得する → 経済、株価、ビジネス、政治のニュース:日経電子版
title = title_tag.string

# タイトル要素を出力
print(title_tag)

# タイトルを文字列を出力
print(title)
```


```
$ python3 getNikkeiWebPageTitle.py 
Traceback (most recent call last):
  File "getNikkeiWebPageTitle.py", line 14, in <module>
    soup = BeautifulSoup(response.data.decode('UTF-8'),"lxml")
  File "/usr/local/lib/python3.6/dist-packages/bs4/__init__.py", line 196, in __init__
    % ",".join(features))
bs4.FeatureNotFound: Couldn't find a tree builder with the features you requested: lxml. Do you need to install a parser library?
```

lxmlをインストールしてくれということなので、

     sudo pip install lxml

```
$ python3 getNikkeiWebPageTitle.py 
<title>経済、株価、ビジネス、政治のニュース:日経電子版</title>
経済、株価、ビジネス、政治のニュース:日経電子版
```

できた！


### エラーの原因
参考にした記事「[python Webスクレイピング 実践入門](https://qiita.com/Azunyan1111/items/9b3d16428d2bcc7c9406)」のpythonのバージョンが古かったため、urllib2=>urllib3、print hoge=> print(hoge)など色々変更点があったっぽいです。
Django ③ adminページへのアクセス・機能追加。



# 管理ユーザ作成
`manage.py createsupereuser`


# ログインしてみるとこんな感じ
localhost:8000/admin

![2019y02m27d_002652374.jpg](https://qiita-image-store.s3.amazonaws.com/0/342467/d830ff68-0475-9d5f-6059-5c71f9649058.jpeg)


# `admin.py`を編集

※事前にモデル定義をしてマイグレーションをしておく必要があります。

```python
from django.contrib import admin

# ここから追記
from .models import blog
# ↑models.pyから自分作成したモデルクラスをインポートする
admin.site.register(blog)
# ↑モデルクラスを管理サイトに登録する。

```

# ログインしてみる。

ユーザ追加ペインの上にblogsという自分のアプリが登録された。

![2019-03-03 (2).png](https://qiita-image-store.s3.amazonaws.com/0/342467/07abb40e-60fa-b9fc-89ac-af99c3ff8a94.png)


アプリのリンクをクリックすると、データベースの定義にあわせたフォームが自動で用意されている。すごい！！こりゃ便利。

![2019-03-03 (4).png](https://qiita-image-store.s3.amazonaws.com/0/342467/47525540-ec86-67d3-1f91-c10e3fd197fa.png)
Swift：enumで予約語を使う



[the swift programming language](https://docs.swift.org/swift-book/LanguageGuide/TheBasics.html#//apple_ref/doc/uid/TP40014097-CH5-ID310)によると以下のように書いてあります．

>NOTE
If you need to give a constant or variable the same name as a reserved Swift keyword, surround the keyword with backticks (`) when using it as a name. However, avoid using keywords as names unless you have absolutely no choice.

つまり予約後を使いたいときは「\`」で囲めということらしいですね．

```swift:例
enum Hoge {
    case `return`
    case `var`
    case `let`
}

Hoge.return
Hoge.var
Hoge.let
```
Bashでプロセスが起動していなかったら起動する

BetterTouchToolが何故かMac起動時に起動しないため `.bashrc` に以下を追記して対応。

# コード

```bash
if ! pgrep -x "BetterTouchTool" > /dev/null
then
    open -a BetterTouchTool
fi
```

`pgrep` でプロセスが起動しているか確認し、停止していたら `open` コマンドに `-a` オプションを不可して起動している。  
`open -a`は `/Application` ディレクトリ以下のアプリを `.app` を省略した形で起動できるコマンド。

# 環境
MacOS Mojave 10.14.3（18D109）
Pythonでpdfデータにあるテーブルデータを一括でcsvに直す方法

何ページにもわたるテーブルデータ(pdf形式)をpythonとかでいじりたい時に！
私が持っていたpdfデータはページごとに注釈がついていたりして、どのpdf/csvの変換サイトでもうまくできませんでした。

```sample1.py
#pdfからcsvに変換するのに使う。ページ指定で1枚ずつしか一気に使えないです。
from tabula import wrapper
#pdfのページ数を数えるのに使う
import PyPDF2

#任意のファイルパスをここに記載
FILE_PATH = "***"

#ページ数を取得
with open(FILE_PATH, mode='rb') as f:
    pages = PyPDF2.PdfFileReader(f).getNumPages()

#このデータフレームに全ページのデータを入れます
df = pd.DataFrame(columns = "欲しいカラム名")  

#全ページのテーブルデータを一つのデータフレームに
for i in range(pages+1):
    tmp = wrapper.read_pdf(FILE_PATH, pages = i, encoding = "utf-8_sig", spreadsheet=True)
    df = pd.concat([df, tmp], ignore_index=True)

```

これでデータフレームはこんな感じに。pdf43枚くらいのテーブルデータが2分くらいで一つのデータフレームにできました。
<img width="472" alt="Screen Shot 2019-03-03 at 14.45.00.png" src="https://qiita-image-store.s3.amazonaws.com/0/248886/eb65e85f-a6aa-3663-77ac-4f77f64d4e38.png">

毎行にNaNが入ってしまっているので、


```sample2.py
import pandas as pd 
df = df.dropna()
```
をすれば、

<img width="483" alt="Screen Shot 2019-03-03 at 14.46.38.png" src="https://qiita-image-store.s3.amazonaws.com/0/248886/900ea181-dcb8-070f-2de0-81f4ff86087a.png">

こんな感じでとても綺麗なテーブルデータができます。

今回は1つのpdfの変換でしたが、複数のpdfのテーブルデータを一つのデータフレームにしたい時は(例えば国毎年発表している医者の数とかそういうデータ)

```sample3.py
import glob
for i in glob.glob("任意のフォルダ"):
    #sample1.pyの操作
```
なんてすれば一気に作業できちゃいます

あとはこの一行

```sample4.py
df.to_csv("任意のcsvのパス")
```
でcsvに変換できます。データフレームで機械学習かけようが、csvでエクセルに通して統計資料まとめたり、いろいろできます！
JuliaでUnitTestするときのディレクトリ構成

# 概要
プロジェクトのディレクトリ構成で悩むことが多くて、UnitTestをするときどういう構成にすればいいのか悩んで、一応現在のベストプラクティスが自分の中で固まったので共有したい。
自分で考えたふうに行ってるがどこかのライブラリのパクリです。しかもパクリ元を忘れてます。
こっちのほうがいいとかあったら教えてほしい。

自分の中での課題である以下を解決します。
* テストの中身ををruntests.jlに書くとruntests.jlが長大になるため辛い。

# 提案
## ディレクトリ構成

* test
 * runtests.jl # hoge_test.jlをインクルードする
 * hoge_test.jl # テストの中身を書く

## runtests.jlの中身
runtests.jlは各テストファイルをincludeするだけ。
その際testsetとして扱う。
ついでにベンチも出しとく。

```julia

using Test
ENV["JULIA_DEBUG"] = "all"

@time @testset "hoge" begin include("hoge_test.jl") end
# @time @testset "hoge2" begin include("hoge2_test.jl") end
```

## 各テストの中身
ディレクトリ構成におけるhoge_test.jl
module単位が良いと思っている。
どうもmoduleが他の言語のクラスと同じ感覚で実装を書いているせいでおかしいかもしれない。

```julia
using Test

using Glob #テストで使うライブラリ
using Revise

# テスト対象モジュール
# Reviseの後に書く
include("../src/hoge.jl")
import .Hoge

@testset "piyo" begin
  # テスト
end

```


# どうでもいいはなし
KING OF PRISM最高なので観てください。