OmniAICreator/Qiita-1.07M huggingface dataset:
今からWindowsで初心者にとってベストなPython開発環境を構築する手順メモ

# はじめに
最近、自分のWindowsでのPython開発環境をリニューアルしたのでそのときの手順をメモしておく。
Pythonのインストールからプロジェクトを作るまでをまとめました。
OSはWindows10です。多分7や8でも問題ないはず。

※（2018/4/15追記）
MacOS10.13.3でもほぼ同じような感じで環境構築できました。

※（2018/7/5追記）
ここでの「初心者にとってベスト」とは、pyenvとかコンテナとかでバージョン管理すのは考えないということを意味します。つまり、単にPythonの文法や面白さを学ぶにあたってそこらへんで躓いたり苦手意識が付くのが勿体無い気がするので、そこは飛ばしていますということになります。

# Anacondaインストール
Anacondaとは、Python自体の他にSciPyやNumPyなどのデータサイエンス系の必要パッケージもまとめられたパッケージのこと。
Pythonを始める人はそういうモチベーションの人が多いと思うし、今はその気持ちが無くても、あとからデータサイエンスやりたいってなったときに、Windowsの場合は後から追加するのが結構だるいらしいので、最初のタイミングでいれてしまう方がいい。（少し容量が増えますが）
以下公式サイトからAnacondaをダウンロードする。自分の場合は64bitなので、64bitを選択。今からPythonを始める場合は3系を推奨。
https://www.anaconda.com/download/#windows

![image.png](https://qiita-image-store.s3.amazonaws.com/0/221948/0dd836d0-44b3-5170-2f70-5dfab74107e3.png)

ダウンロードが完了したら、インストーラを起動する。
基本的にNextやAcceptなどを選択して進んでいけばOKだが、以下の環境変数の設定に関するチェックボックスはつけておこう。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/221948/46bb6241-f743-08af-6f4f-04a2e5afea50.png)

# Pycharmインストール
PycharmとはPythonの統合開発環境(IDE)であり、OS限らずPython開発でIDE使うなら実質ほぼこれ一択的な存在。
以下公式サイトからコミュニティ版Pycharm（無料）をダウンロードする。
https://www.jetbrains.com/pycharm/download/#section=windows

![image.png](https://qiita-image-store.s3.amazonaws.com/0/221948/be3e4c62-34a2-6381-675b-bfd9ca55d8d6.png)

ダウンロードが完了したら、インストーラを起動する。
こちらも基本的にNextボタンをポチポチしておけばOKだが、以下のチェックボックスにチェックすることをお勧めする。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/221948/6ce8eabb-fda1-d4f6-08e7-0ae782d7e5a5.png)

# Pycharm起動してプロジェクト作るまで
インストール完了したPycharmを起動すると、UIをIntelliJかDarculaで選択できる。（後で変更可）要は白か黒。なんか、黒がかっこいいので黒を選択。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/221948/18a9ba39-8b33-8095-2d09-28b6376cd822.png)

"Create New Project"ボタンを押下し、プロジェクトを作成する。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/221948/dd10288b-b1f7-af92-f4ce-2183fc175911.png)

プロジェクト情報を埋めていく。
プロジェクト名は今回は"sample"とする。
"Project interpreter:New Virtualenv environment"の項目を開き、"Base Interpreter"がさきほどインストールしたAnacondaになっていることを確認できたら成功。

"Create"ボタンを押下し、プロジェクトの作成が完了。

後はディレクトリやファイルなどを作ってPythonプログラミングの世界の始まりである。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/221948/d548ffbb-cfd0-e78f-b0af-a2fd09510c54.png)


# （参考）Pycharmを使いやすくする初期設定
以下サイトが分かりやすくてちょうどよい情報量でした。
http://akiyoko.hatenablog.jp/entry/2017/03/10/082912
Azure Active Directory B2Cでマルチテナントサンプルを動かしてみた(1)

# 概要

[Azure Active Directoryを使ってみた](https://qiita.com/hydrangeas/items/10868000ea607eaf36a5)の続き。

[Developing an Azure AD B2C multi-tenant application](https://blogs.msdn.microsoft.com/mrochon/2017/07/27/developing-an-azure-ad-b2c-multi-tenant-application/)を見つけて、よしよし動かしてやろうと思った次第。

結論から言えば、「[multi-tenant applications](https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-devhowto-multi-tenant-overview)にAADのマルチテナントの例があるけど、AAD B2Cでマルチテナントなんてイケてないから、[This demo Application](https://b2cmultitenant.azurewebsites.net)ではB2Cテナント1つでやるぜ。ソースは[こっち](https://github.com/mrochon/b2cmultitenantapp)ね。」（ひどい意訳）ってこと。

# 動け・・！

READMEもないし、**b2cmultitenantapp.onmicrosoft.com** だけソリューション内でgrepかけたら出てくるわ・・。って感じだったので、どこを書き換えのか、のメモを置いておきます。

## clone

まずはcloneしておきます。
https://github.com/mrochon/b2cmultitenantapp

## とりあえず起動

そのままで起動するし、動きます。パスワードとか色々ハードコーティングされてますしね！

## サインアップ

Web.configを書き換えます。下記画像のように**アプリケーションID** を`ida:ClientId`に、アプリID URIのドメイン部分（xx.onmicrosoft.comの形式）を`ida:Tenant`にそれぞれ転記。ついでに応答URLポートを44393にしておくと、後々楽です（きっと）。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/7886/23f22bd4-b5c6-52e9-1c85-1810438d7446.png)

次に、サインアップ・サインインポリシーを設定しないと、**404エラーが出てしまう**ので、設定します。ここ、思わぬ時間をロスしてしまうので注意。**B2CMultiTenant/App_Start/Startup.Auth.cs** の **SignUpInPolicyId** を書き換えます。**ProfilePolicyId**、**ResetPwdPolicyId** も近くにあるので、書き換えておくと、後々楽になります（たぶん）。

Azureポータルでいうところの、下記部分。**B2C_1_** 大事！

![image.png](https://qiita-image-store.s3.amazonaws.com/0/7886/8d68ff80-fa88-fb19-4b6e-65c146027d47.png)

## 雑感

割と簡単で安心した。
そのあと、リダイレクトされてからコケるんだけど、そこはまた次に頑張ります・・。

以上
cakephp3 csv出力

cakephp3 でcsv出力をします。
プラグインを使用して簡単に作成します。

公式
[https://qiita.com/shigejun/items/0c2a8110422ffd0e119d](https://qiita.com/shigejun/items/0c2a8110422ffd0e119d)

### インストールする

```
composer require friendsofcake/cakephp-csvview:~3.0
```

### プログラム修正

```config/bootstrap.php
Plugin::load('CsvView');
```

### 使用する
単純に$data配列をcsv出力する例です。
ヘッダーを付けたりフッターを付けたりなどもできるので、
それは公式を参考にしてください。

```php
public function export()
{
    $data = [
        ['a', 'b', 'c'],
        [1, 2, 3],
        ['you', 'and', 'me'],
    ];
    $_serialize = 'data';

    $this->viewBuilder()->className('CsvView.Csv');
    $this->set(compact('data', '_serialize'));
}
```
1分でできるGithubの2段階認証の設定

他の記事を見ていてgithub初心者なので全然わからない。
UIが変わるので他の記事を見てもふむ...という感じだった。ので、記事を書いて見ました。

# はじめに現象
2段階認証を設定して初めてpushしようとしたら下記のようなエラーがでた。

```shell
 $ git push -u origin master
remote: Invalid username or password.
fatal: Authentication failed for 'https://github.com/_repo_.git/'
 $ git push origin master
Username for 'https://github.com': _USERNAME_
Password for 'https://4geru@github.com': ****
remote: Invalid username or password.
fatal: Authentication failed for 'https://github.com/_USERNAME_/_repo_.git/'
```

# 解決法
手順は以下の通りです。
1. Tokenの発行
2. ~/.netrcの記述

## 1. Tokenの発行
Github > SettingsからPersonal settingsのDeveloper settingsを選択
<img width="150" alt="スクリーンショット 2018-04-03 5.11.53.png" src="https://qiita-image-store.s3.amazonaws.com/0/64677/59c2b37c-bff7-466a-ea44-f235a726c226.png">
[Personal access tokens](https://github.com/settings/tokens)からGenerate new tokenでtokenを作成します。
<img width="700" alt="スクリーンショット 2018-04-03 5.12.28.png" src="https://qiita-image-store.s3.amazonaws.com/0/64677/6f4d12c2-a74e-0127-1c34-e108f5a2d672.png">

token生成時に必要なのは、Token descriptionとSelect Scopeです。
操作できるscopeは、repositoryに関する操作だけで十分だと思います。
<img width="600" alt="スクリーンショット 2018-04-03 5.12.40.png" src="https://qiita-image-store.s3.amazonaws.com/0/64677/e295cb65-3073-fbc0-d323-4e225300847c.png">

`生成されるTokenは必ずコピーしてください。`忘れた場合は再度生成することができます。

## 2. ~/.netrcの記述

~/.netrcをtouchで生成し、中に設定を記述していきます。

```shell
$ touch ~/.netrc
```

お好みのエディタで、~/.netrcの設定を書いてください。

```~/.netrc
machine github.com
login [あなたのGitHubのID]
password [1のtoken]
```

# 参考URL
[Githubを二段階認証にして、弾かれた時にする一番ラクな対策](https://qiita.com/Asuforce/items/c2fa32e78d0d6fcf015d)
[[Git][GitHub]GitHubにPushする際に認証失敗する](http://wada811.blogspot.com/2014/05/failed-to-push-to-github-over-https.html)
[Github 登録時の二段階認証](https://qiita.com/non0311/items/a67a7e7c5599c7ace0c4)
[GitHubで二段階認証に変更する](https://qiita.com/katsukii/items/9773e9cfea7d929fcf9c)
数年ぶりにWindowsを使って入れたアプリとか

数年ぶりに業務でWindows触ってます。
導入して良かったアプリとかをメモしました。

## 環境
Windows 10

## エディター編

### IntelliJ IDEA
最高におすすめなIDE
エディタはいろいろ使ってみたけど結局これに落ち着きました。

[統合開発環境はどれを使えば善いか？（独断と偏見の遥か彼方） - Qiita](https://qiita.com/GeneralD/items/19affd5beba88517a708)
[IntelliJ IDEA: The Java IDE for Professional Developers by JetBrains](https://www.jetbrains.com/idea/)

### Vim
GitのCommitコメントとか細かい作業はvimで

[Vim — KaoriYa](https://www.kaoriya.net/software/vim/)

## ブラウザ
### Google Chrome
説明不要のブラウザ。

[Chrome ブラウザ](https://www.google.co.jp/chrome/index.html)

### Google Chrome Canary
開発段階の機能がほぼ毎日更新されるChrome。

[Chrome Canary ブラウザ](https://www.google.co.jp/chrome/browser/canary.html)

## 黒い画面系

### Chocolatey

Windows用ソフトウェアのパッケージ管理ツール、MacでいうHomebrew。
ソフトウェアの更新&インストールを管理することができます。

下記のようにxml形式のファイルに設定を書いて一括でインストールすることも。

```
<?xml version="1.0"?>
<packages>
    <package id="GoogleChrome"/>
    <package id="Firefox"/>
    <package id="dropbox"/>
    <package id="ConEmu"/>
    <package id="nyagos"/>
    <package id="git"/>
    <package id="slack"/>
    <package id="skitch"/>
    <package id="winmerge-jp"/>
    <package id="vim"/>
</packages> 
```

[Chocolatey - The package manager for Windows](https://chocolatey.org/)

### ComEmu
コンソールエミュレータ。
タブが使えて背景が透明にできるしフォントが綺麗で嬉しい。

[ConEmu - Handy Windows Terminal](https://conemu.github.io/)

### nyagos
UNIX風コマンドラインシェル。
しばらくnyagosとGit Bashを行ったり来たりしてます。

[GitHub - zetamatta/nyagos: NYAGOS - The hybrid UNIXLike Commandline Shell for Windows](https://github.com/zetamatta/nyagos)

### nodist
Node.jsのバージョンを管理できるツール。
Windows用のnvmやnodebrew的なもの。
ディレクトリごとにNode.jsのバージョン指定もできたりmatchコマンドが便利！

[GitHub - marcelklehr/nodist: [LOOKING FOR A MAINTAINER :) ] Natural node.js and npm version manager for windows.](https://github.com/marcelklehr/nodist)

### Git
バージョン管理のスタンダード
Chocolateyで入れました、操作はコマンド派です。

[Git](https://git-scm.com/)

## 便利系

### Skitch
画像にサクッとコメントや矢印を追加できるアプリ。

[Skitch | Evernote](https://evernote.com/intl/jp/products/skitch)

### Pocket
あとで読む系サービス。
PCで気になった記事を、帰りにスマホで見るとか出来て便利。

[Pocket](https://getpocket.com/)

### Slack
チャットツール。
外部連携の多さとbot導入の手軽さが素敵。
いろいろ試した結果Slackオススメです。

[人々の働き方を変える、次世代のビジネスコラボレーション ツール | Slack](https://slack.com/intl/ja-jp)

### Simplenote
シンプルなクラウドメモ帳。
ちょっとしたメモを取る時に使います。
アカウントが同期できるのでスマホからも編集できて手軽。

[Simplenote](https://simplenote.com/)

### Cacher
GistBoxが終了してCacherに。
Gistに簡単にアクセスできるアプリ。
スニペットを手軽に登録したり、Gistが格段に使いやすくなります。

[Cacher](https://www.cacher.io/)

StackEdit
高機能マークダウンエディタ。
ガッツリ議事録やドキュメントを書く時に使います。
UML図も書ける。

[StackEdit – In-browser Markdown editor](https://stackedit.io/)

### Wox
ランチャーアプリ
Macのalfred的なやつです。

[Wox](http://www.wox.one/)

### QTTabBar
エクスプローラーをタブ化できるアプリ

[QTTabBar - QuizoApps](http://qttabbar-ja.wikidot.com/)

### Clibo
クリップボードを拡張できるアプリ。
10個前にコピーしたテキストを呼び出したりできるので作業効率が上がります。
定型文も登録できる。

[クリップボード履歴・定型文などの管理 Clibor | amuns:code](https://www.amunsnet.com/soft.html)

### KeySwap
キーボードの割当を変更できるアプリ。
CapsLockは使わないのでCtrlに変更してます。

[KeySwap for XPの詳細情報 : Vector ソフトを探す！](http://www.vector.co.jp/soft/winnt/util/se228667.html)

### WinMerge
ファイルやフォルダの比較ができてマージもできるやつ。

[WinMerge 日本語版](http://www.geocities.co.jp/SiliconValley-SanJose/8165/winmerge.html)


## おわり
他にもこれ便利だよってのがあれば教えて下さい！
Moby client 備忘録 1

golangでdockerを操作した時のメモです

#環境
Manjaro Linux
go version go1.9.4 linux/amd64
dep

#読み込むパッケージ

```golang:main.go
import (
	"github.com/moby/moby/client"
	"github.com/docker/go-connections/nat"
	"github.com/docker/docker/api/types"
	"github.com/docker/docker/api/types/container"
	"github.com/docker/docker/api/types/network"
	"context"
	"net/http"
	"fmt"
)
```

#dockerのイメージリストを取得(ローカル)
とりあえずイメージ一覧を取得してきます

```golang:main.go
func main() {
	ctx := context.Background()
	cl, _ := client.NewEnvClient()

	list, _ := cl.ImageList(ctx, types.ImageListOptions{All: true})
	

	fmt.Println(list)
}
```
これをdockerをインストールされているpcで動かすとリストを取得することができます

#dockerのイメージリストを取得(リモート)

```golang:main.go
func main() {
	ctx := context.Background()
	tr := &http.Transport{}
	image, _ := client.NewClient("http://<IPアドレス>:<ポート>", client.DefaultVersion, &http.Client{Transport: tr}, map[string]string{})

	list, _ := cl.ImageList(ctx, types.ImageListOptions{All: true})

	fmt.Println(list)
}
```

NewEnvClientでいい感じにしたかったんですが...[GoDoc](https://godoc.org/github.com/docker/docker/client)見てもいまいちわからなかったのでNewClientを採用.
ただコード見た感じNewClientもNewClient結局同じものを読んでいるみたいなのでこのままにしておきます.
ちなみにdocker clientのデフォルトのポートは2375みたいです.

#まとめ
dockerの[Remote API](https://docs.docker.com/develop/sdk/)は2375のポートをデフォルトで使っているみたいなので基本から何もいじってなければ多分大丈夫だと思います

参考
https://godoc.org/github.com/docker/docker/client
https://docs.docker.com/develop/sdk/
バギング

## アンサンブル学習

突然kaggleにはまったので、はやりの手法をメモ。とりあえず特徴量抽出(t-SNEとか)とアンサンブル学習(stacking,bugging,boosting)を頑張ればいいっぽい。アンサンブル学習とは複数のモデルを組み合わせて多数決なり平均をとるなりで予測を返す手法。buggingは並列、boostingは直列、stackingは両方なイメージ。

## buggingのscikit-learnによる実装

``` python:bugging.py
from sklearn.ensemble import BaggingClassifier
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import train_test_split
from sklearn.datasets import load_breast_cancer

bagging = BaggingClassifier(KNeighborsClassifier(),max_samples=0.5,max_features=0.5,n_estimators=12)

cancer = load_breast_cancer()
X_train, X_test, y_train, y_test = train_test_split(
    cancer.data, cancer.target, stratify = cancer.target, random_state=36)

clf = bagging
clf.fit(X_train,y_train)
print('train: ',clf.score(X_train,y_train))
print('test: ',clf.score(X_test,y_test))

```

簡単に言うと、データと特徴量を復元抽出して複数のモデルを訓練し、それらのモデルを集約して予測を返している。モデルの種類、抽出するデータの割合、抽出する特徴量の割合、作成するモデルの数を指定できる。

## 参考
http://scikit-learn.org/stable/modules/generated/sklearn.ensemble.BaggingClassifier.html
Railsでform_tagを利用する際のclassの反映の仕方

#状況
まず、状況として、Railsを利用してformを作成する時に、どうしてもcssを反映させたかったのでclassを使って反映させる必要がありました。
しかし、ドキュメントをみて試行錯誤してもうまくいきませんでした。結果的にある記事を参考にさせていただいた結果うまくいきました。

##環境
Rails 5
slimを使用

##具体例
```
 = form_tag XXXXX_path do 
   = text_field_tag :name, class: 'index__form--text-feild'
```

これだとなぜか、textfieldの中にvalueとしてclassが入ってしまい、結果的に

```
<input type="text" name="name" id="name" value="{:class=>index__form--feild}">
```

となってしまいます。

##解決策
そこで、valueを一旦空白で用意する事でこれを解決します。具体的に示すと、

```
 = form_tag XXXXX_path do 
   = text_field_tag :name, '', class: 'index__form--text-feild'
```

とすることで

```
<input type="text" name="name" id="name" value="" class="index__form--text-feild">
```

となります。

##結論
valueが絶対に用意されてしまうので、そこを空白の形で用意してあげるとうまくそれ以降のオプションが反映されるみたいです。

##参考文献
こちらの記事を参考にさせていただきました。ありがとうございました。
http://mikamisan.hatenablog.com/entry/2016/02/29/214930
Eclipseでlombokが動かない(getter/setterが生成されない)場合の対応方法について

## 状況

PCを新しくしたらEclipseでlombokが動かない（getter/setterが生成されない）のでその時の自分メモ書き。
（EclipseのINIファイルを自分で直接追記する方法でもいけるっぽいけどダウンロード作業まで同じだし手数はそれほど変わらないから確実な方で）

## 環境

OS　:　Windows10
対象:　Eclipse Version: Oxygen.2 Release (4.7.2)

## 対応手順

### 手順１　以下のページよりJarファイルをダウンロード

https://projectlombok.org/download
![g1.png](https://qiita-image-store.s3.amazonaws.com/0/230829/ae4f4aa9-c066-646f-a642-bc46ba409b8c.png)
### 手順２　コマンドプロンプトからJarファイルを実行

```
> java -jar lombok.jar
```
### 手順３　lombokの画面からEclipseのExeファイルを選択して、QuickInstallを選択

![g1.png](https://qiita-image-store.s3.amazonaws.com/0/230829/ab2e7eaf-812e-3a37-c16c-4dee32caa407.png)

### 手順４　Eclipseを起動して、「Eclipseについて」を開きlombokがあることを確認
※ INIファイルにも自動で追記されている

![g1.png](https://qiita-image-store.s3.amazonaws.com/0/230829/111ddc4a-3b5a-0be1-9c89-6658e741d708.png)
[Haskell] 純粋関数型言語と圏論：序論

# 純粋関数型言語って何？
引数が同じであれば、結果もまた同じになるという意味での「関数」を第一級オブジェクトとしたプログラミング言語のことです。
例えばオブジェクト指向プログラミング(C#)であれば、

``` C#
class Hoge{
  private int fuga;

  public Hoge(int a){
    fuga = a;
  }

  public int Add(int b){
    fuga = fuga + b;
    return b;
  }
}
```

このような実装がよく見られますね。
しかし、この実装はインスタンスを生成した後、Add関数を呼ぶ度にローカル変数fugaの値が変わっていき、Add関数が返す値が変わってしまいます。このようなことを純粋関数型言語では許していません。

では、どのように純粋関数型言語(Haskell)で書くかというと、こうなります。

``` haskell
add :: Int -> Int -> Int
add a b = a + b
```
まぁ、この関数自体は、C＃などの所謂オブジェクト指向プログラミング言語でも表現できるわけなのですが、味噌になるのは、こういった書き方を”強制”する、ということなのです。

純粋関数型プログラミング言語は、このHaskellのように構文が他の言語と大きく違うものが多く、とっつきにくいため、JavaやC＃といった現在最もよく使われているC言語由来のオブジェクト指向プログラミング言語からは移行しにくいと思います。

では、この純粋関数型言語がなぜ、もてはやされているのか？
そういう疑問を持つのは必然だと思います。

# 何故、関数型プログラミング言語が良いのか？
これに関して、私は2点挙げられると思います。

1. テストコードが書きやすいこと
1. 数学の公理系というバグの（多分）[^1]ない世界に持ち込めること

この2点です。

1に関しては、上記2つのコードを見ると分かっていただけると思うのですが、
C＃のコードは、テストを1回する毎にインスタンスを作り直さなければならないことが分かるかと思います。(勿論、そうじゃない書き方があることは分かっています。しかし、DBやファイルなどのデータやハードウェアを扱う際には、このようなコードが往々にして現れるのをご存じなはずです。)

2に関してはどういうことか？
以下に説明します。

## 公理系ってなんだ？

公理系とは数学において、数学を論ずるに際して、最も基本的な仮定のことです。
もう少し正確に表すと、その学問を考えるのに必要な前提条件の集まりです。
ユークリッド幾何学で言えば、

「平面上で直線外の1点を通って、この直線と交わらない直線がただ1本存在する。」（ユークリッド原論：第5公準の別解釈）

といったものがこれにあたります。
小中高と私達はこのユークリッド幾何学に基づいた幾何学(図形の勉強)を習っていたわけです。[^2]

わかりづらければ、中高の物理でよく書かれていた”なお摩擦は考えないものとする”的なものだと思ってくれると良いと思います。
プログラミングの世界に適用するならば、

"long型で表現できる整数より大きな数は存在しないものとする。"
"丸め誤差は考えないものとする"

などが当たりますかね(笑)[^3]

## 純粋型関数言語に適用される数学の世界:圏論
では、どのような数学の公理系が純粋型関数型関数言語に適用されているのかというと、初めからちょこちょこと出てきている”圏論”という数学の論理の公理系です。これは関数型言語が生まれた頃から意識されて作られたのか、それとも数学の論理に似ていたからそちらに寄せていっているのかはわかりませんが[^4]、新しい"純粋"関数型言語においては、確実に"圏論"を意識されていることと思います。

この記事を見て下さった方は是非、一緒に圏論と関数型プログラミングの世界へ旅をするのに付き合ってくださると幸いです。

# これからのロードマップ

1. [Haskell]純粋関数型言語と圏論：序論 ← この記事
1. 【予定】[Haskell]純粋関数型言語と圏論：集合の写像

# 参考文献
* Steve Awodey -訳: 前原和寿- 2015/09/25 - 圏論 原著第2版 - 共立出版
* Bryan O'Sullivan・John Goerzen・Don Stewart - 訳: 山下信夫・伊藤勝利 - 2009/10/26 - Real World Haskell ー実戦で学ぶ関数型言語プログラミング

[^1]: 多分というのは、注釈2のような事があったのです。数学が絶対ではないということですね。
[^2]: ユークリッド幾何学は現代の初等教育(小中高の教育)の基礎になっていますが、もともとユークリッド原論という論文を基にしていましたが、ヒルベルトという数学者によって矛盾があることが証明されています。
[^3]: 数学の世界からプログラミングの世界を見た時、これらの事象は、集合論によって包括して説明することができます。
[^4]: 少なくともHaskellに関しては、圏論を意識した設定を行っているようです。
Cloud SQL binarylogの閲覧方法

ある事情からbinarylogを見る必要がありました。
Cloud SQLを初めて使ったということも、MySQL力が足りないこともあり、すごく苦労しました。
結論から言うと、cloud_sql_proxyを使ってポートフォワードし、mysql-serverパッケージに含まれる、mysqlbinlogを使って閲覧しました。
他に良い方法があれば教えて下さい。

## 前提条件

* Cloud SQLには、MySqLを選択していること
* インスタンスの設定で、`バイナリログを有効`にしていること
* gcloudのサービスアカウントを持っていること
* Cloud SQLのrootアカウントを持っていること
* ローカルPCはubuntu(その他のPCは読み変えればいけると思います。)

## gcloudへログイン

gcloudコマンドを使って、プロジェクトにログインします。

```bash
gcloud autn login
gcloud config set project < project name >
```

## cloud_sql_proxyをインストール

[マニュアル](https://cloud.google.com/sql/docs/mysql/connect-admin-proxy?hl=ja)を参考に、`cloud_sql_proxy`をインストールします。
私は、すでにパスが通っている`gcloud`コマンドと同じ場所に配置しました。

```bash
wget https://dl.google.com/cloudsql/cloud_sql_proxy.linux.amd64 -O cloud_sql_proxy
sudo chmod +x cloud_sql_proxy
```

## cloud_sql_proxyで接続してみる

ポート番号はローカルPCで空いているポートを使います。

```bash
cloud_sql_proxy -instances=<インスタンス名>=tcp:3300
```

<インスタンス名>は、インスタンス接続名をそのまま使いました。

![Screenshot from 2018-04-03 00-40-55.png](https://qiita-image-store.s3.amazonaws.com/0/52547/1cad0b75-8570-af76-e492-54b33de5c96c.png)

すると、mysqlコマンドがローカルで使えるようになります。

```bash
mysql -u root -p --host 127.0.0.1 --port 3300
Enter password: 
```

ログファイル名を取得します。

```bash
mysql> SHOW BINARY LOGS;
+------------------+-----------+
| Log_name         | File_size |
+------------------+-----------+
| xxxxx-bin.000001 | 104857880 |
| xxxxx-bin.000002 |  98579596 |
+------------------+-----------+
2 rows in set (0.01 sec)
```

## mysqlbinlogでログを閲覧する

mysql-serverをインストールします。
serverとしては使いませんが、閲覧するために必要です。

```bash
sudo apt install mysql-server
```

ポートフォワードされたポートをmysqlbinlogに指定すると、閲覧/検索できます。

```bash
mysqlbinlog --read-from-remote-server -u root -p --host=127.0.0.1 --port 3300 xxxxx-bin.000002 --start-datetime="2018-04-01 00:00:00" --stop-datetime="2018-04-01 23:59:59" > foo.log
```
2分で思い出すjavascriptの非同期処理/Promise/Async・Await

自分は主にはRubyのサーバーサイドエンジニアなのですが、とはいえスタートアップということもあり時々Node.jsでの開発ややReact.jsを書くことがあります。
でその度に

1 久しぶりに見たjavascriptの非同期処理の書き方を見る
↓
2 あれ？thenとかPromiseとかなんやったかなー？忘れたもう一回ちゃんと復習(**かなり時間かかる**)
↓
3 [しっかり解説されている記事](https://qiita.com/kiyodori/items/da434d169755cbb20447)を見て、あーなるほど思い出したとなる
↓
4 時間が経つ
↓
1に戻る

を繰り返しているので2の時間を削減すべく、暫く見ると思い出すメモコードを書きました。
ちなみにじっくり理解したい方は3の記事が非常におすすめです！
このコードも3の記事を参考にさせていただいております。ありがとうございます。

以下はコードです。

```js
// Normal callback
// 関数を引数として渡して実行する
// ネストすると所謂コールバック地獄が起きる
function func_with_callback(callback) {
  let [data, err] = ['data', null] // 実際はここは何かの非同期処理 成功時
  // let [data, err] = [null, 'error'] // 失敗時
  callback(data, err)
}

func_with_callback(function(data, err){
  if(data){
    console.log(data)
  } else{
    console.log(err)
  }
})

/***
Promise
callback地獄にならないための書き方
呼び出され関数はPromiseオブジェクトを返す
Promiseは3つの状態
 * Pending 未実行/実行中
 * Fulfilled 処理成功時
 * Rejected 処理失敗
を持っており、
Promiseは非同期処理の結果をcallback関数の引数ではなく
成功時 resolve(args) ⇨ onFulfilled(args)関数が実行
失敗時 reject(args) ⇨ onRejected(args)関数が実行
されることで処理の結果を戻す。
resolve時は then
reject時は catch
に渡される関数に処理結果が引数として渡される

Promiseを使うことで
foo_func()
.then(baz_func)
.then(baz_func)
.catch(err)
のように書けてコールバックを回避できる
***/


function func_with_promise(){
  return new Promise(function(resolve, reject){ // => status: Pending 作られた時点ではPending
    let [data, err] = ['data', null] // 実際はここは何かの非同期処理 成功時
    // let [data, err] = [null, 'error'] // 失敗時
    if(data){
      resolve(data) // => status:Fulfilled onFulfilledが呼ばれる
    } else {
      reject(err)  // => status:Rejected onRejectedが呼ばれる
    }
  })
}

func_with_promise()
  .then(function onFulfilled(data){ // onFulfilled
    console.log(data)
  })
  .catch(function onRejected(err){ // onRejected
    console.log(err)
  })


/***
Async/await
asyncで定義した関数は呼び出し時にPromiseを返す。
関数内で
値をreturnするとresolve
エラーが起きたらrejectする
***/

async function func_with_async(){
  let [data, err] = ['data', null] // 実際はここは何かの非同期処理 成功時
  return data　// 値をreturnした場合はresolve(data)
  // let [data, err] = [null, 'error']
  // if (err) throw err // エラーが起きた場合はreject(err)
}

// async functionもPromiseを返すのでthenでチェーン出来る
func_with_async().then(function(data){
  console.log(data)
}).catch(function(err){
  console.log(err)
})

// async functionの中ではawait出来る
async function await_func(){
  try {
    res = await func_with_async() // awaitはasync関数内でしか使えない
    console.log(res)
  } catch(err){
    console.log(err)
  }
}
await_func()
```

半分は自分用ですが、同じような境遇の方の役に立つか、フロントエンドの詳しい方から何かあればご指摘いただけるとうれしいです。
[RHEL7]rootパスワード忘れの救い方法

ある日、久しぶりに、以前構築したRHEL7の仮想マシンにログインしようとしたら。。。

あれ？
Passwordは何番だっけ。。。

色々試したら所、やはり時間経ちすぎて、忘れてしまった。
と焦ろうとしたところ、emergencyモードに入れば、rootパスワードなんかリセットできると思い出した。まだ大丈夫じゃない？と不安しながら、
早速emergencyモードでPassword解除しようとする。

-----
①grub起動メニューで「e」を入力し、編集モードに入る
![1.png](https://qiita-image-store.s3.amazonaws.com/0/245015/53dfea0b-427e-63d3-eddf-9db3ad73ab5a.png)
②「rhgb quiet」を削除し、代わりに「single」を入力して、「Ctrl + X」でgrub起動！
![2.png](https://qiita-image-store.s3.amazonaws.com/0/245015/5514513f-c310-d18a-132c-386a8f6de114.png)
③しかし、失敗になった。rootのパスワードが求められた（RHEL7のせい！？）
![3.png](https://qiita-image-store.s3.amazonaws.com/0/245015/703517ed-6c80-64ed-db4b-5c141cccb043.png)

------------------
どうしようとgoogle先生に聞いた所、RHEL7前の時代はemergencyモードで修正できたが、RHEL7からは下記手順でできるんだ。

①「single」の代わりに「rw init=/bin/bash」（※意味調査待ち）で修正できるそうだ。
![4.png](https://qiita-image-store.s3.amazonaws.com/0/245015/a7a1ab43-3ed9-68e7-acdc-cc3eaa671213.png)
②早速試したら、やった！Passwordリセットできたぜ！！！
![5.png](https://qiita-image-store.s3.amazonaws.com/0/245015/072070cb-ffe6-4cce-13c9-20b853c86fb1.png)
③Password変更後、「# exec /sbin/reboot」でOSリブートして、OS正常に戻った。
Pryにdeleteコマンドを定義して要らないbinding.pryを消しながら快適デバッグしたい

# binding.pryのあるある
[pry](https://github.com/pry/pry)と[pry-byebug](https://github.com/deivid-rodriguez/pry-byebug)を使ってbinding.pryでデバッグするというのはめちゃくちゃ便利でRubyの開発には欠かせないものですが、
「もうここは止まらなくていいのに止まった。。。。要らないところ一つずつ消すの面倒くさい（泣）」
という経験があるのはぼくだけでは無いかと思います。

要らないところは消しながら進めれば良いのですが、残念ながらそういうコマンドは用意されていません。

そこで今回は独自にdeleteというコマンドを定義して削除する方法を考えました。

.pryrcに以下を追記します。
コードがかなり複雑なんですが

```rb
class Pry
  @delete_history = {}
  class << self
    attr_accessor :delete_history
  end
end

default_command_set = Pry::CommandSet.new do
  command "delete", "delete current binding.pry from file" do
    file_name, current_line =
    Pry::Command::Edit::FileAndLineLocator.from_binding(_pry_.current_binding)
    Pry.delete_history[file_name] ||= 0

    lines = IO.readlines(file_name).map.with_index(1) do |line, index|
      if line.match?(/binding.pry(\s)?/) && index <= (current_line - (1 + Pry.delete_history[file_name]))
        print("#{file_name}:#{index} deleted\n")
        Pry.delete_history[file_name] += 1
        line.gsub!(/binding.pry(\s)?/, "")
        line.match?(/\A[[:space:]]*\z/) ? nil : line
      else
        line
      end
    end

    File.open(file_name, 'w') do |file|
      file.puts lines.compact
    end
  end
end

Pry.config.commands.import default_command_set
```

これである程度は削除できます。

```
    44:   binding.pry
 => 45:   RECORD_KEYS = [
    46:     "user",
    47:     "user_name",
    48:     "text",
    49:     "ts",
    50:     "datetime"

[1] pry(TimeSheetWriter)> delete
"44:   binding.pry\n delete!!"
```

なぜある程度かというと一度削除するとそのファイルが全体として1行ずれてしまうためです。
で単純に上から削除していく場合はいいのですが、順番を前後して削除しているパターンなどは対応しきれていません。
惜しいところまで来ているので後もう一歩のところです。
もう少しいい感じにできたら更に更新したものをアップしようと思います。
Splunkで東京の駐輪場を可視化してみる

#本当は楽しいSplunk Vol.1

##なぜやるのか
社内外で日本語のSplunkの記事が少ない、Splunkサーチコマンド良くわからないまま挫折した、Splunk怖いorz...という声を良く耳にしたので、簡単にできるところから解説してみたいと思います。

##お題
誰の為に役立つか分かりませんが、東京都が公開している、緯度経度付きの駐輪場一覧リストをSplunkでゴニョゴニョしてみます。

##今回使うSplunkコマンド
- [inputlookup](http://docs.splunk.com/Documentation/Splunk/7.0.3/SearchReference/Inputlookup)
- [top](http://docs.splunk.com/Documentation/Splunk/7.0.3/SearchReference/Top)
- [chart](http://docs.splunk.com/Documentation/Splunk/7.0.3/SearchReference/Chart)
- [geostats](http://docs.splunk.com/Documentation/Splunk/7.0.3/SearchReference/Geostats)

##今回使うデータ
http://www.seisyounen-chian.metro.tokyo.jp/kotsu/churinjou.csv
(ヘッダを英語に加工＆UTF-8で保存し直しておきましょう)

##Lookupの手順
Lookupとは自分でデータセットをCSVでアップロードして、Splunk上で利用できるようにすることです

1.まずはSettings > Lookups
![splunk_search.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26354/0e8769f3-99f0-5ce7-3a04-d0831d9871a9.jpeg)


2.Lookup table files(CSVはUTF-8で！)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/26354/b563c618-f05b-7ae4-52a6-c10f4784b80b.png)

3.CSV選んで名前を付けてSave
今回は「churinjou_rev1.csv」という名前でアップロードしてみました
![image.png](https://qiita-image-store.s3.amazonaws.com/0/26354/5a21e852-d01a-b450-6e31-54d6f74bf6c5.png)

## それではサクッと呼び出してみましょう
Search画面にコマンドを叩き込んでみてください(inputlookupのサーチの場合は期間は特に気にしなくて大丈夫です)

```
|inputlookup churinjou_rev1.csv
```
![image.png](https://qiita-image-store.s3.amazonaws.com/0/26354/05fa54d9-fc3b-38c8-aa53-21ec8e766198.png)

##どこの区が駐輪場多いのか(チャリンコ天国)
結果は・・・**足立区最強**

```
|inputlookup churinjou_rev1.csv | top ward
```
![image.png](https://qiita-image-store.s3.amazonaws.com/0/26354/9b87897f-f441-521e-885e-ad71dc0fc1ee.png)

##区別の駐輪場数と平均収容台数を出してみましょう
```
|inputlookup churinjou_rev1.csv | chart count avg(capacity) as avgCapacity by ward | sort -avgCapacity
```
![image.png](https://qiita-image-store.s3.amazonaws.com/0/26354/eb50b15f-3363-2766-f19c-a174fc9d2e8e.png)

##地図に駐輪場の数をプロットしてみましょう
今回は標準のMAPよりちょっとカッコよく見える、Custom Cluster MAPをインストールして使ってみましょう
https://splunkbase.splunk.com/app/3122/

```
|inputlookup churinjou_rev1.csv | geostats latfield=latitude longfield=longitude maxzoomlevel=14 count
```
![image.png](https://qiita-image-store.s3.amazonaws.com/0/26354/54af7f6b-0dc0-b95b-7e4c-ff60952dcc79.png)


実に美しい・・・光り輝く駐輪場たち。ピンクの元気玉みたいなのが足立区らへんです。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/26354/9248e5a5-7ed7-ecf3-7476-ea0d30cc343e.png)

maxzoomlevelでズーム14~とかにしておくとかなり詳細な場所にズームできて捗りますよ！
【swift】二次元配列をソートする

swiftで二次元配列をソートする方法を考えました。
学籍番号1~10番までの生徒が、100点満点のテストを受けたとします。
二次元配列を「twoDimArray」とし、[学籍番号(1~10)、点数]とします。
点数をランダムに割り当て、高得点順にソートします。

```swift

var twoDimArray = [[Int]]()

        for _ in 0 ..< 10{
            twoDimArray.append([])
        }
//学籍番号1~10のそれぞれの生徒に、点数をランダムに割り当てる
        for i in 0 ..< 10{
            twoDimArray[i] = [i + 1,Int(arc4random_uniform(100))]
        }
//学籍番号順にprintする
        for i in 0 ..< 10{
            let a = String(twoDimArray[i][0])
            let b = String(twoDimArray[i][1])
            print(a + "：" + b + "点")
        }
//高得点順にソートする
        print("高得点順にソート")
        twoDimArray.sort{$0[1] > $1[1]}
//ソート結果をprintする
        for i in 0 ..< 10{
            let a = String(twoDimArray[i][0])
            let b = String(twoDimArray[i][1])
            print(a + "：" + b + "点")
        }
```
print結果は、以下のようになります。
1：10点
2：51点
3：92点
4：34点
5：4点
6：44点
7：82点
8：5点
9：49点
10：88点
高得点順にソート
3：92点
10：88点
7：82点
2：51点
9：49点
6：44点
4：34点
1：10点
8：5点
5：4点
ReactDOM.createPortalを使ってモーダルを作る

## Portals
React16で導入された概念で、子コンポーネントを親要素のDOM階層の外にレンダリングすることが可能になる。モーダルを作成する際に利用することで、ルート要素の直下にモーダルを置かなくても、子要素の中で通常のコンポーネントと同様に扱うことができる。

## ソースコード
https://bitbucket.org/ayatas/portal-modal/

## モーダルのコンポーネント作成

```React:modal.js
import React from 'react';
import ReactDOM from 'react-dom';

import PropTypes from 'prop-types';

class Modal extends React.Component {
  constructor(props) {
    super(props);
    this.rootEl = document.getElementById('root');
  }
  render() {
    return(
      ReactDOM.createPortal(
        <div
          style={{
            position: 'fixed',
            width: '100%',
            height: '100%',
            backgroundColor: 'rgba(0, 0, 0, 0.5)',
            display: 'flex',
            justifyContent: 'center',
            alignItems: 'center',
            top: 0,
            left: 0,
          }}
        >
          <div
            style={{
              position: 'fixed',
              width: '50%',
              height: '50%',
              backgroundColor: 'white',
            }}
          >
            <button onClick={this.props.onClose}>Close</button>
          </div>
        </div>,
      this.rootEl)
    );
  }
}

Modal.protoTypes = {
  onClose: PropTypes.func,
}

export default Modal;
```

- ```this.rootEl = document.getElementById('root');```でルートのDOM要素を取得。
- ```ReactDOM.createPortal```で取得したルート要素の直下に、モーダルを描画する。

## 使い方

```React:sample.js
import React from 'react';
import ReactDOM from 'react-dom';

import Modal from './modal';

class Sample extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      isModalShown: false,
    };
  }
  render() {
    return(
      <div>
        <button onClick={() => { this.setState({ isModalShown: true }) }}>Click to show modal.</button>
        {this.state.isModalShown &&
          <Modal onClose={() => { this.setState({ isModalShown: false }) }} />
        }
      </div>
    );
  }
}

export default Sample;
```
- 本来このようにModalコンポーネントを配置すると、DOMノード上でSampleの下に配置されてしまうが、createPortalを利用しているので、ルート要素の直下にModalコンポーネントが配置される。
- またコンポーネントとしては通常の子コンポーネントと同様にpropsなどを渡すことができる。
- モーダルの開閉は親要素のstateを操作することで行う。
sympyで超基本の微分方程式を解いてみよう

こんにちは森の生活者、ガマ仙人です。
現在この記事は限定公開にしてます。
qiita初めてなので、怖くて怖くて公開できません。
で、Sympyを昨日から勉強してます。
Maximaでできることはだいたいできるようですね。
今日は簡単な微分方程式を解いてみたいと思います。
超簡単な例題でやってみましたが
あら、不思議、あっけなく解けてしましました。
やるなあSympy!
で、とりあえずメモしておきます。


#自由落下運動における高さと加速度の関係

```python:test1.py
h = Symbol('h') #高さ
t = Symbol('t') #時間
g = Symbol('g') #重力加速度

#微分方程式を定義するーー時間ごとの高さを2階微分したものはマイナスの重力加速度である
before =  Eq(h(t).diff(t,2), -g)

#微分方程式を解いてみよう
after =dsolve(before,h(t))

#結果を表示してみる
display(before,after)

```
結果

```math
\frac{d^{2}}{d t^{2}}  h{\left (t \right )} = - g
```
```math
h{\left (t \right )} = C_{1} + C_{2} t - \frac{g t^{2}}{2}
```

というわけで解けてますね

#単振動の微分方程式
```python:test2.py
x = Symbol('x') #振動の位置
w = Symbol('ω') #角速度
t = Symbol('t') #時間

#微分方程式を定義するーーなんと表現していいかわからんので式をそのまま書くよ
before = Eq(x(t).diff(t,2), -w**2*x(t))

#微分方程式を解いてみよう
after =dsolve(before,x(t))

#結果を表示してみる
display(before,after)

```
結果

```math
\frac{d^{2}}{d t^{2}}  x{\left (t \right )} = - ω^{2} x{\left (t \right )}
```
```math
x{\left (t \right )} = C_{1} e^{- i t ω} + C_{2} e^{i t ω}
```
これも解けましたね

#y′ = ay の基本形
```python:test3.py
x=Symbol('x')           
y=Symbol('y') 
a=Symbol('a') 

eq = Eq(y(x).diff(x), a*y(x))
display(eq, dsolve(eq, y(x)))
```
```math
\frac{d}{d x} y{\left (x \right )} = a y{\left (x \right )}
```
```math
y{\left (x \right )} = C_{1} e^{a x}
```
#ロジスティック方程式の基本形
```python:test4.py
x=Symbol('x')           
y=Symbol('y') 
a=Symbol('a') 
b=Symbol('b') 

eq = Eq(y(x).diff(x), (a-b*y(x))*y(x))
display(eq, dsolve(eq, y(x)))
```
```math
\frac{d}{d x} y{\left (x \right )} = \left(a - b y{\left (x \right )}\right) y{\left (x \right )}
```
```math
y{\left (x \right )} = \frac{a e^{a \left(C_{1} + x\right)}}{b \left(e^{a \left(C_{1} + x\right)} - 1\right)}
```

#補足
ちなみに、言う必要もないかもしれまんが
上記のサンプル動かす前に
次のことやっておいてくださいね。
数式が綺麗に出力されますから、気持ちがいいです。

```python:
from sympy import *
from sympy.interactive import printing
printing.init_printing(use_latex=True)
```
モブプロを体験しました

[バリュース株式会社](https://valus.co.jp/)さんの勉強会に声をかけていただいたので行ってきました。
本家の記事は[こちら](https://www.wantedly.com/companies/valus/post_articles/113543)です！

#モブプロって？
最初は聞いてもわからなかったのですが、ざっとまとめるとこういうことらしいです。

・ モブプログラミングの略
・ 複数人で同時にプログラミングする
・ 一人がドライバとしてプログラムを書く。これは一定時間で交代していく。
・ その他の人は実装について考えてあーだこーだ言う

#モブプロ実践
##目的
kotlin触ってみよう！

##目標
Serverless Framework　+ kotlinでAPIを作る

##環境
・ 人数は社員の方を含めて10名程度で、kotlin経験者はほとんどいない。
・ 私はkotlinを日常業務で書く、Serverless Framework知らない

半分以上初対面の人同士ではじまったのでおっかなびっくりすすむ。
→バリュースさんがピザとアルコールを用意してくれたおかげでだんだんと皆饒舌に

#体験してみて
楽しかった！

##良かったこと
・ 皆が一通りドライバ(コードを書く役)をやるので手持ち無沙汰な人がいない
・ あーだこうだ言うのが楽しい
・ みんなでわいわいやっているので間違えてもフランクに否定してもらえる
 (みんな手探りでトライ&エラーの繰り返しなので全然悪い気がしない)
・ みんなで一個の問題をクリアしていくと一体感が生まれる(アルコール成分も関係しているかもしれない)

##課題
・ Serverless Frameworkの開発環境を整える時間が多く、目的のkotlinを体験するところまでが長かった
・ 人数が多かったのでドライバの人が誰の意見を採用するか迷うケースが多々あった
・ ワイワイ出来たとはいえ、発言の多い人、少ない人の差はあった

##次にやるなら
・ 目的に対して多く時間を割けるように環境設定をすませておけたら良かったかも
→今回に関してはkotlinを触ることが目的だったのでServerless Frameworkの開発環境設定を済ませておくなど(Serverless Frameworkも面白かったけども)
・ もっとプログラミングに参加できるように1ドライバに対しての人数を分けるなど
→10名程度人数がいるなら2チームに別れてもいいかもしれない

#終わり
いつもの勉強会は登壇者の情報を受け取ってどう使うかを考える事が多いんですが、モブプロは体験型の勉強会なので参加している感がとても強くて良かったです。
自分が書いているコードにツッコミが入ったりして、より実際のプログラミングに近いところで新しい発見がありました。
HerokuでRailsアプリをデプロイする際にハマった点

##**前置き**

herokuでRailsを環境にデプロイする際に、個人的にハマった点をいくつかメモしておきます。

##**デプロイ後にページを表示しても情報が反映されない**
```
$ heroku run rake db:migrate
```
大体の原因はこれらしい

##**assets配下のファイルが反映されない**

```
$ git push heroku master
```
上記のデプロイ前にこれを行う

```
$ rake assets:precompile RAILS_ENV=production
```
cssやjsを修正した際は必ず行うようにしましょう。

##**Special thanks to**
* [RailsアプリをHerokuにデプロイする手順メモ] (https://qiita.com/EntreGulss/items/8186938683f929a0dae2)
Cloudflareが1.1.1.1で超高性能DNS始めたし、いっちょ俺のパソコンもDNS over HTTPSしてみる

# Cloudflareが1.1.1.1で超高性能DNS始めたし、いっちょ俺のパソコンもDNS over HTTPSしてみる

はいど〜も！バーチャルYoutuberのおのかちおです！
先日、Cloudflareが 1.1.1.1:53 でパブリックDNSを始めたことが話題になってますよね。Googleが8.8.8.8でやってるあれと同じです。

![k.png](https://qiita-image-store.s3.amazonaws.com/0/154157/9b498681-c9b9-5adc-39e4-bd87c946f78e.png)

しかもこれ、超速いんですよね。自分の手元からだと、8.8.8.8の10倍速い。

![k1.jpg](https://qiita-image-store.s3.amazonaws.com/0/154157/01afb9ed-5f4b-bf37-33ec-d5f0b2b125a1.jpeg)


# 1.1.1.1の主な特徴

- ログを保管しない。破棄する。
- IPv6 対応
- DNSSEC の対応
- DNS over HTTPS の対応
- DNS over SSL の対応
- …

# IPアドレス

1.1.1.1
1.0.0.1
2606:4700:4700::1111
2606:4700:4700::1001

覚えやすくていいですね。

# DNS over HTTPS

DNS over HTTPSは、DNS要求をSSLで暗号化できるものです。また、通信するポートが443なため、80と443以外のポートで外に出れない環境などでも使用することができます。

Cloudflareが、手軽にDNS over HTTPSを使えるバイナリを提供しています。

https://developers.cloudflare.com/argo-tunnel/downloads/

```
$ wget https://bin.equinox.io/c/VdrWdbjqyF/cloudflared-stable-linux-amd64.tgz
$ tar xvf cloudflared-stable-linux-amd64.tgz
$ sudo mv ./cloudflared /usr/bin/
```

このcloudflaredは、元々Cloudflareとwebサービスをつなげる機能がメインですが、今回はそれを使いません。今回はproxy-dnsという機能を使用します。

proxy-dnsは、cloudflaredが127.0.0.1:53で起動します。
そこにリクエストが来ると1.1.1.1で動くHTTPSなDNSサーバーに問い合わせをし、帰ってきます。
つまりは、DNSとDNS over HTTPSの変換器的な役割ですね。
さらに、このcloudflaredは内部にキャッシュを持っているため、2回目からの問い合わせは高速になります。

さっそく起動しましょう。

```
$ sudo cloudflared proxy-dns

INFO[0000] Adding DNS upstream                           url="https://cloudflare-dns.com/.well-known/dns-query"
INFO[0000] Starting metrics server                       addr="127.0.0.1:49312"
INFO[0000] Starting DNS over HTTPS proxy server          addr="dns://localhost:53"
```

これで、ローカルの53でdns解決ができます。ためしてみましょう。

```
$ dig google.com @127.0.0.1

; <<>> DiG 9.12.1 <<>> google.com @127.0.0.1
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 1493
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1536
;; QUESTION SECTION:
;google.com.                    IN      A

;; ANSWER SECTION:
google.com.             152     IN      A       216.58.214.14

;; Query time: 131 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: 月  4月 02 23:34:56 JST 2018
;; MSG SIZE  rcvd: 65

```

自分の実験だと、8.8.8.8が40ms、1.1.1.1が4msなので、そこそこ遅いですね。
ただ、外部DNSが使えない社内や学内から使いたいときにはとても便利だと思います。

# サービスにする

毎回コマンドを入れていたらきりがないので、systemd用のserviceファイルを作りましょう。

```ini:/etc/systemd/system/proxydns.service
[Unit]
Description=Proxy dns server over https
Before=network.target

[Service]
Type=simple
ExecStart=/usr/bin/cloudflared proxy-dns

[Install]
WantedBy=multi-user.target
```

起動させましょう。

```
$ sudo systemctl start proxydns.service
$ sudo systemctl enable proxydns.service #自動起動させたい場合のみ
```

あとは、NetworkManagerでDNS設定に書き足したり、systemd-resolvedで使うなり、自由に設定しましょう。

# さいごに

DoH (DNS over HTTPS)を使うことで、一定の環境下でも外部DNSに接続することができます。
> ちなみに、dns-cryptという汎用的なDoHデーモンなどを使うことで、1.1.1.1を含む様々なDoHサーバーを使うこともできます。

これから利用者が増えるに従って速度も落ちるかもしれません。今後に期待したいところです。

参考: https://developers.cloudflare.com/1.1.1.1/dns-over-https/cloudflared-proxy/
`dep ensure -vendor-only=true` の使い所

# TL;DR
docker buildの高速化。
`Gopkg.toml`と`Gopkg.lock`に変更がない場合はキャッシュが利用されてビルドの時間を短縮できる。

```Dockerfile
FROM golang:1.10

WORKDIR /go/src/github.com/munisystem/test
COPY Gopkg.toml Gopkg.lock ./
RUN dep ensure -v -vendor-only=true

COPY . .
RUN dep ensure -v
RUN go build
```

# 解説

`docker build`の`COPY`及び`ADD`のレイヤでキャッシュが効くか否かは対象のfileのhash値によって決まる。

例えばRailsアプリケーションのDockerfileでは以下のような記述が多く見受けられる。

```Dockerfile
FROM ruby:2.5.0

COPY Gemfile Gemfile.lock ./
RUN bundle install

COPY . .

```

こういったDockerfileを書くことにより、コードベースに変更を加えても`Gemfile`と`Gemfile.lock`に変更がない限りbundle installをスキップすることが出来る。

ではGolangのパッケージ管理ツールであるdepではどうだろうか。
`dep　ensure`は`Gopkg.toml` `Gopkg.lock`の他にGoのコードから依存を解決しようとするため、カレントに対象となるファイルがない場合は実行に失敗してしまう。

`-vendor-only=true`をビルドの引数として与えると、Goのコードは一切参照せずに`Gopkg.lock`から依存を引っ張ってきてくれる。
これを利用して`dep ensure`による大量の依存関係のダウンロードにキャッシュを効かせるのが今回のアプローチ。
WindowsのWSLにOpenAI gymとchainerrlをインストールした時のメモ

# はじめに
この記事はWSL (Windows Subsystem for Linux) 上にOpenAIのgym(強化学習フレームワーク)の実行環境を構築した時のメモです。

インストールしたもの

- python3.6
- pip
- 強化学習で使いそうなライブラリ
- VcXsrv(XServerクライアント)

この記事には以下の内容は含まれません。

- WSLはインストール済みであることが前提です。
- 強化学習の説明はしませんので、別の記事をご参照ください。

# インストールするもの
## Linux側
WSL(ubuntu)のデフォルトはpython3.5が入っているので、Python3.6とpipを使えるようにする。
[このページ](https://blog.smallsec.ca/2017/09/07/installing-python3-6-on-wsl/)を参考にapt-getでインストールする。

```sh
sudo add-apt-repository ppa:jonathonf/python-3.6
sudo apt install python3.6 python3-pip
sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.5 1
sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.6 2
```

`python3 -V`でpython3.6が有効になっていればOK。


今回は仮想環境とかは作らずにWSL上に環境を作っていく。
pipでさしあたって使いそうなものをインストール。

```sh
pip3 install --user numpy tensorflow keras chainer chainerrl gym jupyter scipy
```

## Windows側
XServerクライアントが必要になります。
Xmingが有名ですが、[こちら](https://qiita.com/fukuramikake/items/283b817c16725af79a28)でVcXsrvが勧められていたのでVcXsrvをインストールしてみました。

ダウンロード：[SourceForge](https://sourceforge.net/projects/vcxsrv/)
インストール方法など：[WindowsでリモートのLinuxのGUIアプリを表示させる－Xサーバ VcXsrv](http://vogel.at.webry.info/201612/article_3.html)

インストールは特に難しいことはなく、インストーラを起動してボタンをクリックしていくだけ。
インストール後はデスクトップにあるXLaunchというのを起動して、タスクバーに"X"マークのロゴが出ればOK。

一応、ロゴをマウスオーバーしてディスプレイのポートが0.0であることを確認しておく。
("ホスト名:0.0 - 0 clients"となっているはず。)

WSL側の設定は.bashrcに以下の二行を追加。localhostの後ろの0.0はロゴのマウスオーバーで確認した値にしておく。
二行目は"failed to load driver: swrast　wsl"というエラーメッセージを消すために入れているが、なくても動く。

```sh
export DISPLAY=localhost:0.0
export "LIBGL_ALWAYS_INDIRECT=1"
```

.bashrc変更後は`source ~/.bashrc`するか、再起動する。


OpenGymのGUIが動くように以下をインストール。

```sh
sudo apt-get install python3.6-gdbm python-opengl
```

# 実際に試してみる
## 簡易確認
以下の内容でファイルを作ってコマンドラインから実行。テストなので、ランダムに行動させています。

*最後の一行を入れないと終了時にエラーが出るみたいです。（2018/4/2時点）*

```python
import gym
env = gym.make('CartPole-v0')
observation = env.reset()
for _ in range(100):
  env.render()
  action = env.action_space.sample()
  observation, reward, done, info = env.step(action)
env.close()
```

自動でXwindowが最前面に来ないこともあるので、タスクバーを見ていないと見落とすかも。

## jupyter + chainerrl
jupyterを起動すれば、ChainerRLの[クイックスタート](https://github.com/chainer/chainerrl/blob/master/examples/quickstart/quickstart.ipynb)も実行できる。

jupyterは`jupyter notebook`で起動して、Windows側のブラウザから表示されたURLにアクセスすればOK.
git diffからのvimで変更行数が少ないファイルの順番にソートして無駄ファイルをコミット対象から外す

リリース前にテーブル・ストアド・VIEWの変更差分を洗い出したいときってありますよね。
開発環境でガンガン更新した後、さてリリースしようと思ったものの、「うわっ、私の変更、多すぎ・・・！？」ってなったとき、スクリプト化して本番と見比べるってのが常道であり王道であります。

というわけで、データベースの大量のストアドやテーブルなどの差分を見る作業を効率よくしたい。
見たいのは変更分が多いものであり、検証用DB名などが混ざっているだけの変更はノイズでしかない。
また、空行などが変更分として数えられているものも除外したい。

#### 前提
 * gitで一度でもスクリプト化したものを扱ったことがある
 * ストアドなどのSQLServerオブジェクトをスクリプト化する手順が確立している。
 * vimでファイルエディットが出来る

まずはdiffを取得。各ファイルでどのくらいの差分があるのかを検証したいので、空白・空行抜きの行数情報だけをファイルとして出力。

```bash:git-bash
git diff --stat-width=800 -w --ignore-blank-lines > diff.patch
```

出力されたファイルは、

```bash
ファイル名 | 変更行数 +-
```
と言うような形式になってると思うので、パイプ後の数値の順番に並び替えしたい。
vimを開き、行数の降順で並び替え。
あとで行数検索するので、ここは降順でも昇順でも、ていうか何もしなくても構わないです。

```vim:vim
%sort! /[^|]*\|/
```

まず、変更差分が０行のものを全検索。

```vim:vim
|\s\+0$
```

0行以外の行を削除。これで変更差分がないものが抽出出来る。

```vim:vim
v//d
```

sqlファイル名を抽出

```vim:vim
\/\w\+\.sql
```

あとはファイルをこねこねとエディットして(vimなら楽勝ですよね)、

```bash:git-bash
git checkout ファイル名1.sql
git checkout ファイル名2.sql
git checkout ファイル名3.sql
…
```

これをgit bashに一括で流す。
git checkout のファイル名複数記載は出来ないみたいなので、一つ一つやってます。

これで、変更差分のあるSQLファイルだけを抽出出来ました。
iOSでFirebase DynamicLinksを導入するのに知っておきたいこと

# Firebase DynamicLinksについて

Firebase DynamicLinksはiOS, Android, Webへのリンクの共有を簡単にしてくれる便利な機能です。この記事ではiOSでFirebase DynamicLinksを実装する上で知っておくべき内容についてご説明します。

## minimumAppVersion

「この値より古いバージョンがインストールされていた場合は、App Storeに遷移してアップデートを促す」**という仕様ではありません。**

minimumAppVersionの値に関わらず、DynamicLinksに対応済みのバージョンがインストール済みならアプリは起動してしまうので注意してください。ドキュメントにもあるように、このバージョンより古いアプリでDynamicLinkを受け取ってしまった場合の処理は**自分で記述する必要があります**。

#### 使いどころ

例えばアプリのアップデートによりDynamicLinks経由で起動できる画面が増えた場合に、minimumAppVersionを上げることが考えられます。これにより、古いバージョンのアプリは、自分の知らない仕様のURLが受信されたことを検知できます。

#### minimumAppVersionよりも古いバージョンでDynamicLinkを受け取ってしまった場合

正しく対応する場合は、

1. そのURLを一旦ローカルに保存する
2. ユーザをApp Storeへ誘導する
3. アップデートされたら保存したURLを読み出して対応する

と言った実装が必要になります。実装が大変であれば、読み捨てるという割り切りも良いかもしれません。

## 新規インストールからDeepLinkが取得できない場合

### 自己診断ツール

まず自己診断ツールを使って設定に誤りがないか確認し、エラーになっているようならコンソールログの表示内容を参考に修正します。

```swift
DynamicLinks.performDiagnostics(completion: nil)
```

ダイナミック リンクのデバッグ  |  Firebase https://firebase.google.com/docs/dynamic-links/debug?hl=ja

### 自己診断ツールは"no errors found"なのにリンクが取得できない場合

自己診断ツールでは問題ないのに、AppDelegateの`application(_ app:open:options:)`が毎回`"dlscheme://google/link/?dismiss=1&is_weak_match=1"`になってしまいディープリンクが取得できないことがあります。

まずはSDKが最新であることを確認してください。本機能については何度かバグ修正が行われています。

私の場合、APIの許可設定に問題がありました。Google APIs Consoleより設定を変更することで解決されました。

1. Google APIs Consoleにアクセスする。
2. 「ライブラリ」→「Firebase Dynamic Links API」でAPIが有効になっていることを確認する。
3. 「認証情報」からFirebaseの当該プロジェクトに対応しているAPIキーを探し、アプリケーションの制限の設定に問題がないかを確認する。

## `DynamicLinks`型のメソッドの意味がよくわからない

```swift
func handleUniversalLink(_ url: URL, completion: @escaping DynamicLinkUniversalLinkHandler) -> Bool
```
ショートURLをロングURLに戻します。

```swift
func shouldHandleDynamicLink(fromCustomSchemeURL url: URL) -> Bool
```
DynamicLinksによるインストール後の起動後にAppDelegateの`application(_ app:open:options:)`が呼ばれますが、そこで渡される`url`がDynamicLinksによるものかどうかを判定します。
これが`true`なら`dynamicLink(fromCustomSchemeURL:)`によって`DynamicLink`型に変換できます。

## 画像があるならSocial Meta Tagを使うべき

オプションですが、未インストールユーザがDynamicLinkを踏んだ時に見えるプレビューページがリッチになるので、画像が表示できるアプリは使用すると良いと思います。

ソーシャル メタデータでリンク プレビューを生成する  |  Firebase https://firebase.google.com/docs/dynamic-links/link-previews?hl=ja

## Androidとの違い

- Androidにはプレビューページがなく、未インストールユーザは直接Google Playに飛ばされます。
- AndroidはDynamicLinkで指定された最小バージョンよりも古いバージョンがインストールされている場合はGoogle Playに飛ばされます。

## 共有アプリごとに付与するパラメータを切り替えたい

計測目的など、シェア先によってURLのオプションを変更したいケースがあると思います。ユーザがActivity Viewを選んだ際にシェアする内容を同期で渡す必要があるのですが、ショートURLの生成は非同期で行われるため困ることになります。

- 非同期を無理やり同期に変換する。
- ユーザがシェアを押す前に全パターンのURLを生成しておく。

といった解決策がありそうですが、私は前者の同期で変換するパターンで対応しました。次の手順になります。

1. 同期に変換する場合は、`UIActivityItemProvider`を継承した型を作成し、`UIActivityItemProvider#item`をオーバーライドします。
2. GCDを使って`item`が呼ばれたら同期でショートURLを返すように実装します。

シェアの際に`item`が呼ばれるスレッドはメインスレッドではないので、単純にsemaphoreを使って止めるようにしました。ただしこの場合、シェア先を選択した後少し画面が固まることになります。他に良い実装方法があれば教えていただきたいです。

## まとめ

ハマりどころはありますが、OSまたぎのURL共有を解決するのは手間ですので、こういったサービスに頼るのは良いと思います。
Slackで不要になった昔のファイルを削除する

## TL;DR

* Slack のストレージ容量が一杯になる前に不要になったファイルを削除したい
* ほぼ個人的なメモなので、後で書き直す可能性あり
* やっつけで書いているので、使用等は当然自己責任で

> :bulb: 単純に API 叩いてるだけなので、中身を読んで改造してご活用ください

## 動作

1. files.list の API を叩いて全ファイル数の当りをつける (その後、３秒程休憩)
2. ５秒毎に files.list の各ページの API を叩いて削除対象を探す
3. ４秒毎に、見つかった対象のファイルIDを元に files.delete の API を叩く

> * 削除対象の条件としては LIMIT_DAYS 以上経過したファイル  
>     * チャンネルだとか、ユーザーだとかは見てないので、必要に応じて入れること
> * 短い時間で API を叩き過ぎないように一応ウェイトを入れている

## コード

```python
#!/usr/bin/python3
import requests
import sys
from time import sleep
from datetime import datetime

# Need Legacy Token
TOKEN = '(Slack のレガシートークン)'
LIMIT_DAYS = 30

# ------------------------------------------------------------------------------
# API からページ番号指定でファイル一覧を取得する
# ------------------------------------------------------------------------------
def getFilesFromApi(page):
    url = 'https://slack.com/api/files.list?token={0}&pretty=1&page={1}'.format(TOKEN, page)
    response = requests.get(url)
    data = response.json()
    return data

target_ids = []

# ------------------------------------------------------------------------------
# 対象ファイルを探して対象に追加
# ------------------------------------------------------------------------------
def appendTargetFrom(data):
    now_date = datetime.now()
    files = data['files']
    for file in files:
        target_date = datetime.fromtimestamp(int(file['timestamp']))
        days = (now_date - target_date).days
        if days > LIMIT_DAYS:
            target_ids.append(file['id'])

data = getFilesFromApi(1)
total_pages = data['paging']['pages']
sleep(3)

for page in range(1, total_pages + 1):
    print('検索用API呼び出し中... {0}/{1}'.format(page, total_pages))
    sleep(5)
    appendTargetFrom(getFilesFromApi(page))

# ------------------------------------------------------------------------------
# 指定 ID のファイルを削除
# ------------------------------------------------------------------------------
def deleteFileBy(id):
    url = 'https://slack.com/api/files.delete?token={0}&file={1}&pretty=1'.format(TOKEN, id)
    response = requests.post(url)
    data = response.json()
    print('削除 id={0} ... {1}'.format(id, data['ok']))

print('削除するのは全部で {0} 個'.format(len(target_ids)))
for id in target_ids:
    sleep(4)
    deleteFileBy(id)
```
サーバにTomcatを降臨させアプリを起動させたい

自前のサーバにJavaで開発したwarファイルをデプロイして、アプリを起動させたい
環境の準備までやってみよう

# インストール手順
## 1. OSの確認
```bash:サーバ
$ uname -m
x86_64
$ cat /etc/centos-release
CentOS Linux release 7.1.1503 (Core)
```

## 2. wget
```bash:サーバ
$ su - root
$ sum install wget
```


## 3. JDK1.8 (Java8)
```bash:サーバ
$ wget --no-check-certificate --no-cookies --header "Cookie: oraclelicense=accept-securebackup-cookie" http://download.oracle.com/otn-pub/java/jdk/8u161-b12/2f38c3b165be4555a1fa6e98c45e0808/jdk-8u161-linux-x64.rpm
$ ll
合計 170080
-rw-r--r--. 1 root root 174157387 12月 21 04:10 jdk-8u161-linux-x64.rpm
$ sudo yum localinstall jdk-8u161-linux-x64.rpm
```
`http://...`から始まるURLは[Java SE Development Kit 8 Downloads](http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html)のページ各ファイルのURL
上記ページにて「Accept License Agreement 」のラジオボタンにチェックする
ダウンロードしたいファイルを右クリック、「リンクのアドレスをコピー」でURLを取得できる

```bash:サーバ
$ java -version
java version "1.8.0_161"
Java(TM) SE Runtime Environment (build 1.8.0_161-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.161-b12, mixed mode)
```

### yumだとOpenJDKになっちゃう

今回はOracleをいれたいから`yum`はしない
[CentOS6にjdk-1.8.0をインストールした話](http://d.hatena.ne.jp/nojikaba/20151018/1445157700)

### 3. Tomcat
[Apache Tomcat](http://tomcat.apache.org/)
今回はTomcat8.5を入れる。
Coreをダウンロードするのが一般的かと。

```bash:サーバ
$ useradd -s /sbin/nologin tomcat   # Tomcatユーザの追加
$ wget http://ftp.jaist.ac.jp/pub/apache/tomcat/tomcat-8/v8.5.29/bin/apache-tomcat-8.5.29.tar.gz
$ tar -xvzf apache-tomcat-8.5.29.tar.gz
$ ll
drwxr-xr-x. 9 root root      4096  3月 22 22:24 apache-tomcat-8.5.29
-rw-r--r--. 1 root root   9532698  3月  5 22:50 apache-tomcat-8.5.29.tar.gz
$ mv apache-tomcat-8.5.29 /usr/local/tomcat
```
この後ポートの設定やデプロイが必要となるが今回はここまで

## :pray:参考

先人に感謝

### OS確認

[今更聞けない！LinuxのOSやバージョンの確認方法](https://eng-entrance.com/linux-os-version)
[Linuxが32ビット版か64ビット版かの確認](http://d.hatena.ne.jp/tech_memo/20110224/1298527712)

### wgetとは？

[wgetでこういう時はこうする!!](https://qiita.com/hirohiro77/items/b774908436ec032df719)
[curlとWgetの比較 | POSTD](https://postd.cc/curl-vs-wget/)
[wgetとcurlの違い - usmysaの開発メモ](http://usmysa.hatenablog.com/entry/2016/05/24/223311)

### JDK

[CentOS6.xにOracleのJDK8をインストールする](https://qiita.com/Sa2/items/8ba501294df745be8c78)
[[CentOS7]Oracle Java8をインストール](http://zero-config.com/centos/install-java8.html)
[Linuxでjdkをwgetする方法](https://qiita.com/hajimeni/items/67d9e9b0d169bf68d1c9)

### Tomcat

[CentOSにJDK、Tomcatをyumでインストールしてしまったものを最新にするとき](https://qiita.com/yoh-nak/items/a93d2564ccf574065970)
[CentOSにTomcatをインストールする](https://qiita.com/yukihigasi/items/f477e021cd909bfcde3e)
[CentOS7にTomcat8を構築する方法](https://qiita.com/LowSE01/items/2c735f22d220f53a6b2f)
[Apache Tomcat 8 を CentOS 7 にインストールする手順](https://weblabo.oscasierra.net/installing-tomcat8-centos7-1/)

### yum rpmの違い

[【初心者にもわかる】rpmとyumの違いと使い分け一通り](https://eng-entrance.com/linux-package-rpm-yum-def)
SinatraでJSONを受け取る方法

SinatraでJSONを受け取る方法。

結論： [Rack::PostBodyContentTypeParser](https://github.com/rack/rack-contrib/blob/master/lib/rack/contrib/post_body_content_type_parser.rb) を使う。

## やり方

### `rack-contrib`をインストールする

```ruby:Gemfile
gem 'rack-contrib'
```

or 

```shell-session
$ gem install rack-contrib
```

### `Rack::PostBodyContentTypeParser`を有効にする

```app.rb
require 'sinatra'
require 'rack/contrib'

use Rack::PostBodyContentTypeParser

post '/hoge' do
  params[:foo]
end
```

## 動作確認

```shell-session
$ curl -X POST -H 'Content-Type: application/json' -d '{"foo": "bar"}' http://localhost:4567/hoge

bar
```

ただし、リクエストの`Content-Type`は`application/json`である必要があるので注意。