OmniAICreator/Qiita-1.07M huggingface dataset:
メモ: ndjbdns

* [CentOS7でndjbdnsを動かす - Qiita](http://qiita.com/tukiyo3/items/6994ab172b4da359cf93)の続き
* [N-DJBDNS](http://pjp.dgplug.org/ndjbdns/document.html#c16)
* [ndjbdns man](http://www.filewatcher.com/d/Fedora/i686/Applications/System/ndjbdns-1.05.4-9.fc15.i686.rpm.141073.html)

# MX優先順位設定

```bash:設定前
$ dig mx hoge.jp
(略)
;; ANSWER SECTION:
hoge.jp.		86400	IN	MX	0 a.mx.hoge.jp.
hoge.jp.		86400	IN	MX	0 b.mx.hoge.jp.
```

## 設定

```bash:
tinydns-edit data data.new add mx hoge.jp 5.6.7.8
tinydns-edit data data.new add mx hoge.jp 5.6.7.9
```

で作ってもいいけど書式を知っていれば以下のように書ける。

```diff:data
- @hoge.jp:5.6.7.8:a::86400
- @hoge.jp:5.6.7.9:b::86400
+ @hoge.jp:5.6.7.8:mx1.hoge.jp:10:86400
+ @hoge.jp:5.6.7.9:mx2.hoge.jp:100:86400
```

```bash:設定後
$ dig mx hoge.jp
(略)
;; ANSWER SECTION:
hoge.jp.		86400	IN	MX	10 mx1.hoge.jp.
hoge.jp.		86400	IN	MX	100 mx2.hoge.jp.
```

* 値が小さいほど優先度は高くなります
* [【ドメイン】MXレコードの優先値とは何ですか？ | よくある質問 | お名前.comヘルプセンター](http://help.onamae.com/app/answers/detail/a_id/7908)

# spf

`tinydns-`コマンドでtxtレコードのコマンドがないのでdataを直接編集。

```diff:data
+ 'hoge.jp:v=spf1 include\072spf1.hoge.jp ?all:86400
+ 'spf1.hoge.jp:v=spf1 ip4\0725.6.7.0/28 ?all:86400
```

# 逆引き

* [EZ-NET 特集： DNS サーバ djbdns のインストールと設定 - 逆引きの設定](http://network.station.ez-net.jp/special/djbdns/doc/3-6.asp)

逆引きとは`in-addr.arpa`形式。

```bash:例
.6.1.1.5.in-addr.arpa:5.1.1.6:ns1.hoge.jp:86400
.6.1.1.5.in-addr.arpa:5.1.1.6:web1.hoge.jp:86400
^6.1.1.5.in-addr.arpa:ns1.hoge.jp
```

## postfix側の設定

* [Postfix でメールリレーの設定 (SMTP クライアント + SMTP Auth) - maruko2 Note.](http://www.maruko2.com/mw/Postfix_%E3%81%A7%E3%83%A1%E3%83%BC%E3%83%AB%E3%83%AA%E3%83%AC%E3%83%BC%E3%81%AE%E8%A8%AD%E5%AE%9A_(SMTP_%E3%82%AF%E3%83%A9%E3%82%A4%E3%82%A2%E3%83%B3%E3%83%88_%2B_SMTP_Auth))

> relayhost = [mail2.example.com]
> relayhost = [mail.example.com]
> 下に書いたほうが優先される。
SQL Server Compact Editionのデータベースファイル(.sdf)を作る

Visual Studio 2013からはSQL Server Compact Editionはサポートされなくなりました。
公式には、「SQL Server 2012/2014 ExpressのLocalDBを使え」または「SQLiteを使え」ってことのようなのですが、そうはいってもいろいろ都合があってSQLCEを使いたい場合もありますよね。
そういう時はどうすればいいかというと、`System.Data.SqlServerCe.dll` アセンブリに含まれる `System.Data.SqlServerCe.SqlCeEngine`クラスのオブジェクトを生成して`CreateDatabase()`メソッドを呼べば、.sdfファイルが作られます。

PowerShellで書いた例が、[Jeremiah Clark's Blog](http://blogs.msdn.com/b/miah/archive/2011/08/08/powershell-and-sql-server-compact-4-0-a-happy-mix.aspx) にありましたのでまるっと参照します。

```ps1
$binpath = "C:\Program Files\Microsoft SQL Server Compact Edition\v4.0\Desktop\";
[Reflection.Assembly]::LoadFile("$binpath\System.Data.SqlServerCe.dll")
$connectionString = "Data Source='C:\temp\testDB.sdf';"

$engine = New-Object "System.Data.SqlServerCe.SqlCeEngine" $connectionString
$engine.CreateDatabase()
$engine.Dispose()

$connection = New-Object "System.Data.SqlServerCe.SqlCeConnection" $connectionString
$command = New-Object "System.Data.SqlServerCe.SqlCeCommand"
$command.CommandType = [System.Data.CommandType]"Text"
$command.Connection = $connection

$connection.Open()

$command.CommandText = "CREATE TABLE [Files] ([Id] int NOT NULL  IDENTITY (1,1), [Name] nvarchar(450) NOT NULL);"
$command.ExecuteNonQuery()        

$command.CommandText = "ALTER TABLE [Files] ADD CONSTRAINT [PK_Files] PRIMARY KEY ([Id]);"
$command.ExecuteNonQuery()

$command.CommandText = "CREATE UNIQUE INDEX [IX_Files_Value] ON [Files] ([Name] ASC);"
$command.ExecuteNonQuery()

$command.Dispose()
$connection.Close();
$connection.Dispose;
```
【AdobeCC】AdobeCCのアカウントの取得方法


##1.Adobe Creative Cloudにアクセスする
初めてAdobe Creative Cloudを使用するときの参考にしてください。

**「体験版を試す」**からアカウント情報の入力画面へ進みます。

![スクリーンショット 2014-11-25 22.53.24.png](https://qiita-image-store.s3.amazonaws.com/0/37178/6c026ae2-dc69-abad-0e7a-fe9f7e0d26f8.png "スクリーンショット 2014-11-25 22.53.24.png")

Adobe Creative Cloud
(http://www.adobe.com/jp/creativecloud.html)

##2.Creative Cloudメンバーシップ

必要事項を入力

![スクリーンショット 2014-11-25 23.47.43.png](https://qiita-image-store.s3.amazonaws.com/0/37178/2093b1a5-2899-a38f-921c-1229202b26f8.png "スクリーンショット 2014-11-25 23.47.43.png")

##3.登録完了

登録が正常に済めば、アカウント名が表示される。

![スクリーンショット 2014-11-26 9.09.51.png](https://qiita-image-store.s3.amazonaws.com/0/37178/1cb93141-6c57-12db-871e-2aa52023eaad.png "スクリーンショット 2014-11-26 9.09.51.png")

##4.電子メールを確認

Adobe先輩からメールが届きます。

![スクリーンショット 2014-11-26 9.25.39.png](https://qiita-image-store.s3.amazonaws.com/0/37178/841a7b10-90e0-f4de-2b1b-a00847aa2d4f.png "スクリーンショット 2014-11-26 9.25.39.png")
***
電子メールを確認する。
これ、忘れずにしておきましょう。

![スクリーンショット 2014-11-26 9.25.26.png](https://qiita-image-store.s3.amazonaws.com/0/37178/203f3dac-bb00-7907-0452-2e06fbc86e83.png "スクリーンショット 2014-11-26 9.25.26.png")

***
これでAdobe先輩の恩恵を受けられます。

![スクリーンショット 2014-11-26 9.26.02.png](https://qiita-image-store.s3.amazonaws.com/0/37178/5b4da7dd-eae4-7e67-dfd2-5a9a0271da5c.png "スクリーンショット 2014-11-26 9.26.02.png")


Enjoy your Creative Life!!
Android Studioで設定画面を作る

(Android Studio 0.8.14) PreferenceActivityが作れますが、中身がほとんどDeprecatedってなんとかならんのかい！

1. 専用のActivityを作る
1. PreferenceFragmentを作る
1. 動くようにしてやる

これでいってみます。

専用のActivityを作る
---

- appを右クリックして、New → Activity → Blank Activityを作る
 - （ここではSettingsActivityと名付けます）
- レイアウトを編集してFrameLayoutだけにする（コードは後で）
 - この1画面だけなので match_parentで、contextもここで指定しちゃいましょう

```xml:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/settings_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".SettingsActivity" />

```

PreferenceFragmentを作る
---
- appを右クリックして、New → Fragment → Fragment(Blank)を作る
 - （ここではSettingsFragmentと名付けます）
 - Create layout XML?、include fragment factory method?、include interface callbacks? のチェックを外す
- ソースを変更
 - 普通のFragmentみたいに再作成チェック（onCreateでsavedInstanceStateがNullか否か）しなくていいんだろか？

```java:
 public class SettingsFragment extends PreferenceFragment {
    public SettingsFragment() {
    }
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        addPreferencesFromResource(R.xml.preferences);
    }
}
```

- レイアウトを必要に応じて変更
 - [本家ガイド] (http://developer.android.com/design/patterns/settings.html)などを参考にしてください
 - とりあえずここではTextPreferenceを二つ作ったとします

動くようにしてやる
---

- FragmentにListenerを設定します

```java:settingsFragment
    @Override
    public void onResume() {
        super.onResume();
        getPreferenceManager().getSharedPreferences()
            .registerOnSharedPreferenceChangeListener(this);
    }
    @Override
    public void onPause() {
        super.onPause();
        getPreferenceManager().getSharedPreferences()
            .unregisterOnSharedPreferenceChangeListener(this);
    }
    @Override
    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
        if (key.equals(getString(R.string.preference_key1))) {
            EditTextPreference pref = (EditTextPreference) findPreference(key);
            pref.setSummary(pref.getText());
        } else if (key.equals(getString(R.string.preference_key2))) {
            EditTextPreference pref = (EditTextPreference) findPreference(key);
            pref.setSummary(pref.getText());
        }
    }
```

- Activityから呼んでやります

```java:settingsActivity
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_settings);
        if(savedInstanceState == null) {
            getFragmentManager().beginTransaction()
                .replace(R.id.settings_container, new SettingsFragment())
                .commit();
        }
    }
```

最小限ではこのくらいで動くはずです。
procmailはroot宛にメールを配送できないので注意。

aliasesで `root: username`に転送設定しておくこと。

## 参考

[PostfixでMaildir形式にし、procmailにローカル配送を任せていて mail root なんてやったら、次のエラーが出てきた …](https://plus.google.com/115525239317518891636/posts/LnzFPSdsX7u)

> PostfixでMaildir形式にし、procmailにローカル配送を任せていて
> 
> mail root なんてやったら、次のエラーが出てきた
> 
> to=<root@xxxxx.jp>, relay=local, delay=0, delays=0/0/0/0, dsn=5.2.0, status=bounced (can't create user output file. Command output: procmail: Couldn't create "/var/spool/mail/nobody" procmail: Couldn't chdir to "//Maildir/" procmail: Unable to treat as directory "./new" procmail: Skipped "." )
> 
> 何がどうしたのかと調べてみたら、procmailはrootへのメールを配送できないそうだ。
> aliasesにて root: user とかで、ユーザに配信しなければならない。
> 
> いや、そもそも、procmailをつかわなくても、PostfixでローカルのMaidlirに配送してくれるそうだ。
> 
> 2時間はこれに引っかかってしまった。
CakePHPで素書きのSQLでもPaginatorを使いたい！

#CakePHPで素書きのSQLでもPaginatorを使いたい！

どうしてもCakePHPのfindで記述ができないSQLでページを実装する必要があることってあると思います。

CakePHPのPaginatorは利用できると非常に楽なので出来れば使用したいところなのです。

##なんかできるっぽい！
```
<?php
App::uses('AppModel ', 'Model');
class RawSql extends AppModel {
	public $useTable = false;

	function paginate() {
		$extra = func_get_arg(6);
		$limit = func_get_arg(3);
		$page = func_get_arg(4);

		$sql = $extra['extra']['type'];
		$sql .= ' LIMIT ' . $limit;
		if ($page > 1){
			$sql .= ' OFFSET ' . ($limit * ($page - 1));
		}

		return $this->query($sql);
	}

	function paginateCount() {
		$extra = func_get_arg(2);
		return count($this->query(
			preg_replace(
				'/LIMIT \d+ OFFSET \d+$/u',
				'',
				$extra['extra']['type']
			)
		));
	}

}
```
こんな感じでモデルを作ると・・・

```
<?php
App::uses('AppController', 'Controller');

class PostsController extends AppController{
    public $uses = ['RawSql'];

    function index(){
        $sql = 'SELECT * FROM posts';

        $query = [
            'limit' => 20,
            'extra' => [
                'type' => $sql
            ],

        ];
        $this->Paginator->settings = $query;
        $history_lists = $this->Paginator->paginate('RawSql');
        $this->set('history_lists', $history_lists);
    }
}
```
これだけでpaginateが動作します！

##やってること
paginatorの第7引数にextraというカラムがあるので、そこにSQLを突っ込んで強引に実行しているだけです。

LIMITやらOFFSETやらは自分で計算して渡したSQLにくっつけているだけです。

ですが、Paginatorヘルパーの機能の件数やら、ページ番号やらが使えるので、ページングを素で実装するよりかなり楽になると思います。
DockerfileでADDする時は~が使えない

## バージョンなど
```
$ boot2docker -v
Boot2Docker-cli version: v1.3.1
$ docker -v
Docker version 1.3.1, build 4e9bbfa
```

## 動かなかった時のDockerfileは以下
```
FROM centos:centos6

MAINTAINER Mapyo

# Create vagrant user
RUN groupadd vagrant
RUN useradd vagrant -g vagrant

# Change user
USER vagrant
WORKDIR /home/vagrant
ENV HOME /home/vagrant

ADD test.txt ~/test.txt
```

こんな感じで書いてた。docker buildする時のフォルダには、もちろん、`test.txt`は存在している。

buildした時の結果も一見成功しているようにみえた。

```
Step 7 : ADD test.txt ~/test.txt
 ---> cda6ac3b2db4
Removing intermediate container 102d36aa40e9
Successfully built cda6ac3b2db4
```

しかし、実際に作ったイメージの中身を見てみると、存在しない。。。

```
# build時のコマンド
$ docker build -t test .
# コンテナを起動
$ docker run -i -t --name hoge test:latest /bin/bash

# 確認作業
$ pwd
/home/vagrant
$ ls -la
total 24
drwx------ 2 vagrant vagrant 4096 Nov 24 23:07 .
drwxr-xr-x 4 root    root    4096 Nov 24 23:07 ..
-rw------- 1 vagrant vagrant   20 Nov 24 23:08 .bash_history
-rw-r--r-- 1 vagrant vagrant   18 Oct 16 14:56 .bash_logout
-rw-r--r-- 1 vagrant vagrant  176 Oct 16 14:56 .bash_profile
-rw-r--r-- 1 vagrant vagrant  124 Oct 16 14:56 .bashrc
```

存在しない。。。。

## 動くようにする
上記のDockerfileのADDの部分を絶対パスにする。

```
ADD test.txt /home/vagrant/test.txt
```

確認作業

```
$ docker build -t test .
$ docker rm hoge
$ docker run -i -t --name hoge test:latest /bin/bash

# コンテナの中
$ ls -la
total 24
drwx------ 2 vagrant vagrant 4096 Nov 24 23:16 .
drwxr-xr-x 4 root    root    4096 Nov 24 23:16 ..
-rw-r--r-- 1 vagrant vagrant   18 Oct 16 14:56 .bash_logout
-rw-r--r-- 1 vagrant vagrant  176 Oct 16 14:56 .bash_profile
-rw-r--r-- 1 vagrant vagrant  124 Oct 16 14:56 .bashrc
-rw-r--r-- 1 root    root      11 Nov 24 21:44 test.txt
```

存在している！

しかし、権限周りがrootになってしまっているので、ちゃんと使うのであれば、
権限の変更が必要。
なので、以下のように変更する

```
ADD test.txt /home/vagrant/test.txt

USER root
RUN chown vagrant:vagrant ~/test.txt
```

確認

```
$ docker build -t test .
$ docker rm hoge
$ docker run -i -t --name hoge test:latest /bin/bash

# コンテナの中
$ ls -la
total 24
drwx------ 2 vagrant vagrant 4096 Nov 24 23:19 .
drwxr-xr-x 5 root    root    4096 Nov 24 23:19 ..
-rw-r--r-- 1 vagrant vagrant   18 Oct 16 14:56 .bash_logout
-rw-r--r-- 1 vagrant vagrant  176 Oct 16 14:56 .bash_profile
-rw-r--r-- 1 vagrant vagrant  124 Oct 16 14:56 .bashrc
-rw-r--r-- 1 vagrant vagrant   11 Nov 24 21:44 test.txt
```

ちゃんと権限が変わっている事が確認出来た。

## ちなみに
今回書いたDockerfileは以下。

```
FROM centos:centos6

MAINTAINER Mapyo

# Create vagrant user
RUN groupadd vagrant
RUN useradd vagrant -g vagrant

# Change user
USER vagrant
WORKDIR /home/vagrant
ENV HOME /home/vagrant

ADD test.txt /home/vagrant/test.txt

USER root
RUN chown vagrant:vagrant ~/test.txt
```

rootユーザになっても、`WORKDIR`と`ENV HOME`の環境変数は生きているのがちょっと不思議だった。そういうもんかー
プチコン3号での変数スコープ


公式ツールのソースの一部を抜き出そうとして、挙動が不明だったので調べてみた。

```
V1=1	'グローバル変数
? "V1=" + STR$(V1)	'V1=1

DEF F1	'関数定義より前に変数定義
 ? "F1.V1=" + STR$(V1)
 V1=10
 ? "F1.V1=" + STR$(V1)
END

DEF F2	'関数定義より前に変数定義がないのでローカル変数確定？
 ? "F2.V2=" + STR$(V2)
 V2=20
 ? "F2.V2=" + STR$(V2)
END

V2=2	'グローバル変数
? "V2=" + STR$(V2)	'V2=2

F1
? "V1=" + STR$(V1)	'V1=1

F2
? "V2=" + STR$(V2)	'V2=2

F3	'変数定義前に呼び出してみる　グローバル変数として動作？
	'関数定義は後でも良い！
? "V3=" + STR$(V3)	'V3=30
V3=3	'グローバル変数
? "V3=" + STR$(V3)

F3	'グローバル変数として動作！

'関数定義は後ろでも良いが、この挙動がややこしい
DEF F3
 ? "F3.V3=" + STR$(V3)
 V3=30
 ? "F3.V3=" + STR$(V3)
END

```

こんな感じで、関数定義の位置と、グローバルな変数の定義位置を変えて実行してみた。

```
V1=1
V2=2
F1.V1=1		'グローバル
F1.V1=10
V1=10
F2.V2=0		'ローカル！
F2.V2=20
V2=2
F3.V3=0		'グローバル？
F3.V3=30
V3=30		'グローバル動作だった模様
V3=3
F3.V3=3		'グローバル
F3.V3=30
V3=30
```

関数の定義時点(呼び出し時点ではない)での同名のグローバル変数の有無で挙動が変わっている模様。
関数定義自体は呼び出しより後にもかけるのでややこしい。

取り急ぎ、メモまで。
例外処理の書き方について

例外処理の書き方について気になったので書いてみる。

##事例から
Javaを例に挙げると、

```
public class hogeAction {
  public String main() {
    try {
       ・・・
       ビジネスロジック
       ・・・
    } catch (Throwable e) {
       return null;
    }

    return foo;
  }
}
```

このようになんでもCatchしちゃう包容力の高いコードをたまに見る。
こういうコードを見つけると、「臭うぞ！！」と思うのは自分だけだろうか？

まあ直接的すぎるのもあれなので、

「ちょっと例外処理広すぎやしませんか？
　例外処理は必要最低限の範囲で意図したものだけCatchしましょうよ」

くらいにレビューフィードバックしたりする。
言語やチームに限らず、ここまで激しくなくても、必要以上に大きくTry Catchで囲って必要以上にCatchする書き方をするエンジニアを数多く見てきた。

##なぜこういうコードが生まれるのか
あまりにも多いので、こういう書き方が昔は流行してたのかなーとも思い、Twitterなどで問いかけてみたけどどうやらそうでもなさそう。

ってことでせっかくなので理由を聞いてみたところ多かった回答は、

**「あまり意識して書いてなかった」**
**「もし漏れていたら処理（表示）に影響するので・・・」**

といった回答だった。

##つっこんでみる
前者は置いておいて、

**「もし漏れていたら処理（表示）に影響するので・・・」**

につっこんでみる。

### 意図したコードをかけていないのでは？
意図して書けている自信がないコードをプロダクトコードにのせていることが果たしてよいのだろうか？
ビジネスロジックだろうと予約メソッドだろうと、InputとOutputのパターンを理解できているのであれば、そのパターンごとに意図した適切な処理を書けばいい。

### それでも漏れるかもしれないから念のため？
もちろん人間だからバグを生む可能性があることは前提にすべきである。
だけどもしそうであればなおさら、ビジネスロジックでわざわざそう書かないと漏れたときに処理（表示）に影響しちゃう設計を疑うべきではないだろうか？

* Try Catchで囲うのを忘れてしまった場合
* このFunctionよりも大きいところで例外が発生した場合

に結局漏れちゃうのではないだろうか？

##どうするのがいいのか考えてみる
自分が考えてみた答えは、

* セーフティーネットとしての例外処理
* 意思を持った例外処理

をわけることである。

### セーフティーネットとしての例外処理とは
「それでも漏れるかもしれないから念のため」を拾うための例外処理がセーフティーネットとしての例外処理だ。
人間がバグを生む可能性が以上、それをそのままユーザーにさらすのはよろしくないので、セーフティーネットは必要であろう。
ただし、先ほど述べた通り、これをビジネスロジックで意識して書かないとセーフティーネットにならないのはリスクである。
フレームワークレベルなどビジネスロジックの範囲を包括する深い層で例外処理を行い、ビジネスロジックで意識しなくてもよい状態にするのが好ましい。

### 意思を持った例外処理とは
ほとんどの場合の例外処理と言われるものがこちらのことである。
ビジネスロジックで書く例外処理はこちらのことだ。

セーフティーネットとしての例外処理がされている前提であれば、意思を持ってコーディングを行い、意図した部分だけで意図した例外のみをCatchして適切な例外処理を行えばいい。

### バグは見つけて直す！！
例外処理もコードであり、意図していない場所で例外が発生した場合はもはやバグと呼んでいい。

つまるところ、セーフティーネットとしての例外処理にひかかったものが見つかった場合、基本的には適切な処理になるようにコードを直すべきである。

バグは変に握りつぶしてしまうよりも、バグらしくバグとして見つかる状態にしてとっとと直す方が健全である。

## まとめると・・・

* セーフティーネットとしての例外処理と意思を持った例外処理をわけて考える
* セーフティーネットとしての例外処理は、ビジネスロジックで意図しなくてもいい層で行う
* 意思を持った例外処理は、意図した部分で意図した例外のみを処理する
* セーフティーネットとしての例外処理にひかかったことがわかった場合はバグなのでとっとと直す

が私の考えです。
皆さんがは例外処理についてどう考えますか？

また、この考えは誰かから教えてもらったものなのか、なにかの本で読んだのかまったく記憶にありません。
よい本や文献などあればぜひご紹介ください。
Railsアプリ開発用のDockerコンテナでunicornを起動するにはsupervisord + unicornherderが良い

# 背景

* Dockerコンテナでrailsの開発環境を作ろうとしています。
* 想定している開発マシンはMacかWindowsです。
* VagrantでCentOS7のVMを動かしてその上でDockerコンテナを作って開発します。
* コンテナで使用するOSもCentOS7とします。
* railsアプリのソースコードはMacやWindowsのファイルシステム上に置いて、ソースコードを編集したら、コンテナを再起動せずにアプリに反映できるようにします。
    * MacとVagrant上のVM間はVagrantのshared_folderをtypeをNFSで使用します。
        * vboxsfは遅いのでNFSを使用することにしました。
    * WindowsとVagrant上のVM間はVagrantのshared_folderをtypeをrsyncで使用します。
        * vboxsfが遅いのと、Windowsファイルシステム上のファイルではファイルパーミションを自由に変更できないため。
    * Vagrant上のVMとDockerコンテナ間は `docker run -v` でファイル共有します。

# Dockerコンテナ内でサービスを起動する際の注意点

以下の2点に注意が必要です

* ゾンビプロセスを回収する必要がある
* `docker run -link` によって設定された環境変数を参照する必要がある

## ゾンビプロセスを回収する必要がある

[Baseimage-docker: A minimal Ubuntu base image modified for Docker-friendliness]( http://phusion.github.io/baseimage-docker/ )の"What important system services am I missing?"の"A correct init process"に詳しい説明がありますので、ご参照ください。

ゾンビプロセス回収の必要性を理解していなかったときに、DockerfileのENTRYPOINTでmonitを起動してそこからunicornを起動するようにしてみたのですが、 `monit restart unicorn` とかでunicornを再起動するとゾンビプロセスが残ったままになってしまいました。
しかも `docker exec -it コンテナ名 bash` でコンテナに入って `kill -9` しても消えない状態でした。

## `docker run -link` によって設定された環境変数を参照する必要がある

ゾンビプロセスを回収するには `systemd` を動かせば良いのではと思い、Dockerfileで `CMD ["/sbin/init"]` を試してみました。確かにゾンビプロセスは回収されるようになったのですが、 `docker run -link` によって設定された環境変数が参照できないことに気づきました。

例えば、MySQLのコンテナを `docker run -p 3306:3306 --name mysql ...` として起動し、unicornのコンテナを `docker run -link mysql:mysql ...` として起動すると `MYSQL_PORT_3306_TCP_ADDR` といった環境変数が設定されます。

ところが、systemd用に `*.service` ファイルを作って、そこでこの環境変数の値を参照しても空になってしまいました。

ふと考えると、そもそもsystemdは子プロセスとして起動することは想定していないので、親プロセスから環境変数を引き継ぐようにはなっていないのではないかと思い当たりました。

[Inherit environment variables in systemd Docker container - Unix & Linux Stack Exchange]( http://unix.stackexchange.com/questions/146995/inherit-environment-variables-in-systemd-docker-container )によると、 `init` の引数に `systemd.setenv=NAME=VALUE` のように指定すれば環境変数を引き継げるようです。が、 `docker run -link mysql:mysql ...` で設定される環境変数は名前も値も動的なので、全て指定するのも大変です。

# supervisordなら両方カバーしています

[supervisord]( http://supervisord.org/ )なら、ゾンビプロセスの回収もできますし、環境変数も引き継ぎます。dockerのサイトに[Using Supervisor - Docker Documentation]( https://docs.docker.com/articles/using_supervisord/ )という記事があるのは知っていたのですが、supervisordを選ぶのはこういう理由があったんですね。

# supervisordからunicornを起動するならunicornherderが必要

これは[Rails - supervisord ＋ unicornでhot restart (deploy) する - Qiita]( http://qiita.com/kazuph/items/55a5f74b9dca2d17bd65 )の記事が詳しいのでご参照ください。

unicornをリロードする際はUSR2シグナルを送るのですが、別プロセスを起動して切り替えるので、supervisordから直接unicornだとまずいことになります。unicornherderを使えば解決します。

# VagrantfileとDockerfileのサンプル

https://github.com/hnakamur/vagrant-docker-rails-development-example に置きましたので、よかったらご参照ください。ただし、Windowsでは未検証です。
ドットインストールの「jQueryで作るスライドショー」をJavaScriptで書いてみた

JavaScript勉強もかねて、
jQueryで書いているドットインストールさんのスライドショーを
JavaScriptで書き直してみた。

・要素の取得は、`document.getElementById`や`document.getElementsByClassName`を使用。
・CSSのクラス名付与・削除は`取得した要素.className = 'class名';`,
`取得した要素.classList.remove('class名')`を使用。
・サムネイル画像をクリックしたら、画像が切り替わるようにimgタグ分、クリックイベントを付与するのは、`for文`を使用。

```
<!DOCTYPE html>
<html lang="ja">
<head>
	<meta charset="utf-8">
	<title>スライドショー</title>
	<style>
		body {
			margin: 10px auto;
			text-align: center;
		}
		img {
			width: 50%;
		}
		.thumbnail {
			width: 125px;
			height: 83px;
			opacity: 0.5;
			cursor: pointer;
		}
		.current {
			opacity: 1.0
		}
			
		.thumbnail + .thumbnail {
			margin-left: 4px;
		}
	</style>
</head>

<body>
	<div id="thumbnails"></div>
	<div id="main"></div>
	<div id="nav">
		<button id="prev">&laquo; 前へ</button>
		<button id="next">次へ&raquo;</button>
		<button id="play">再生</button>
		<button id="stop">停止</button>
	</div>

<script>
	//変数の定義、ファイルを配列格納
	var files = [
			'img/photo01.jpg',
			'img/photo02.jpg',
			'img/photo03.jpg'
				];
				
	var img;
	var currentNum = 0;
	var timer;
	var isPlaying = false;
				
	//配列から動的にimageを表示するためのHTMLを作成
	for(var i=0; i<files.length; i++){
		img = document.createElement('img');
		img.src = files[i];
		img.className = 'thumbnail';
		document.getElementById("thumbnails").appendChild(img);
	}
	img = document.createElement('img');
	img.src = files[0];
	var mainImg = document.getElementById('main').appendChild(img);
	var imgs = [];
	imgs = document.getElementsByClassName('thumbnail');
	imgs[0].className = 'thumbnail current';
				
	var n = document.getElementById('main').getElementsByTagName('img')[0];
				
	for(var i=0;i<imgs.length;i++){
		imgs[i].onclick = function(){
			n.src = this.src;
			for(var j=0;j<imgs.length;j++){
					imgs[j].classList.remove('current');
			}
			this.className = 'thumbnail current';

			for(var j=0;j<imgs.length;j++){	
				if(imgs[j].classList[1] == "current"){
					currentNum = j;
				} 
			}
		};
	}
				
	//前へボタンの実装
	document.getElementById('prev').onclick = function(){
		currentNum--;
		if(currentNum < 0){
			currentNum = files.length - 1;
		}
		n.src = files[currentNum];
		for(var j=0;j<imgs.length;j++){
			imgs[j].classList.remove('current');
		}
		imgs[currentNum].className = 'thumbnail current';
	};
				
	//次へボタン実装
	var next = document.getElementById('next');
	next.onclick = function(){
		currentNum++;
		if(currentNum > files.length - 1){
			currentNum = 0;
		}
		n.src = files[currentNum];
		for(var j=0;j<imgs.length;j++){
			imgs[j].classList.remove('current');
		}
		imgs[currentNum].className = 'thumbnail current';
	};
				
	//一定時間でスライドしていく機能実装
	function autoPlay(){
		next.onclick();
		timer = setTimeout(function(){
			autoPlay();
		},1000);
	}
				
	//再生ボタンでスライドショー動作
	document.getElementById('play').onclick = function(){
		if(isPlaying)return;
		isPlaying = true;
		autoPlay();
	};
				
	//停止ボタンでスライドショーを止める
	document.getElementById('stop').onclick = function(){
		clearTimeout(timer);
		isPlaying = false;
	};
</script>
</body>
</html>

```
Sublime Text | Markdown Preview Plugin で Favicon を指定する

# Sublime Text | Markdown Preview Plugin で Favicon を指定する
## <i class="fa  fa-cubes" style="font-size:1em;"></i> 概要
Sublime Text の Markdown Preview Plugin で Favicon を指定します。
※ブラウザのタブを見た時にひと目で Markdown Preview のプレビューであることを判別可能にするためです
## <i class="fa  fa-cube" style="font-size:1em;"></i> Markdown Preview Plugin のテンプレートカスタマイズ
Sublime Text のメニューの

* Preferences
* Package Settings
* Markdown Preview
* Setting - User

を選択し、下記のように編集することで任意のテンプレートを利用できます。

~~~json
{
  "html_template": "/path/to/your/template/markdown_template/template.html"
}
~~~

テンプレートを作成し、 Favicon の Link タグを追加します

~~~html:/path/to/your/template/markdown_template/template.html
<!doctype html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>Markdown Preview</title>
  <link rel="shortcut icon" href="favicon.ico">
</head>
<body>
{{ BODY }}
</body>
</html>
~~~

## <i class="fa  fa-cube" style="font-size:1em;"></i> Preview を確認します

![markdown_preview_tab.png](https://qiita-image-store.s3.amazonaws.com/0/43480/a30621c9-2d22-e38b-8dfe-7a4db3142d9e.png)
Sublime Text | Markdown Preview Plugin で fontawesome を利用できるようにする

# Sublime Text | Markdown Preview Plugin で Font-Awesome の Icon を利用できるようにする
## <i class="fa  fa-cubes" style="font-size:1em;"></i> 概要
Sublime Text の Markdown Preview Plugin で Font-Awesome の Icon を利用できるようにします。
## <i class="fa  fa-cube" style="font-size:1em;"></i> Markdown Preview Plugin のテンプレートカスタマイズ
Sublime Text のメニューの

* Preferences
* Package Settings
* Markdown Preview
* Setting - User

を選択し、下記のように編集することで任意のテンプレートを利用できます。

~~~json
{
  "html_template": "/path/to/your/template/markdown_template/template.html"
}
~~~

テンプレートを作成し、 Font-Awesome の CSS の Link タグを追加します

~~~html:/path/to/your/template/markdown_template/template.html
<!doctype html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>Markdown Preview</title>
  <link rel="stylesheet" href="/path/to/your/css/github.css">
  <link href="http://maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css" rel="stylesheet">
</head>
<body>
{{ BODY }}
</body>
</html>
~~~

## <i class="fa  fa-cube" style="font-size:1em;"></i> Use Font-Awesome Icon

* マークダウンを下記のように記述します。

~~~markdown
# hoge
##  <i class="fa fa-futbol-o" style="font-size:10em;"></i></i> hige
##  <i class="fa fa-slideshare" style="font-size:10em;"></i></i> hage
~~~

* Preview を確認します

![Font-Awesome.png](https://qiita-image-store.s3.amazonaws.com/0/43480/a4a4aac6-ffff-a264-bd7f-a1b883aa8b76.png)

## <i class="fa fa-link" style="font-size:1em;"></i> 参照
* <i class="fa fa-external-link" style="font-size:1em;"></i> [Font-Awesome | Icons](http://fortawesome.github.io/Font-Awesome/icons/)
SwiftでFizzBuzz（Playgroundで無駄にキャプチャ）

XCPCaptureValueを無駄に併用した。
iの値をそれぞれfizzとbuzz定数でキャプチャしてみると面白い。  

### キャプチャで生成されたグラフ
![スクリーンショット 2014-11-26 2.28.32.png](https://qiita-image-store.s3.amazonaws.com/0/9628/92810006-113a-54f5-dba7-1a563a3f0e36.png)

### 普通のFizzBuzz
```swift:TestPlayground.playground

import UIKit
import XCPlayground

let fizz     = "Fizz"
let buzz     = "Buzz"
let fizzbuzz = fizz + buzz
let others   = "Others"

for i in 1...100 {
    if i % 3 == 0 && i % 5 == 0 {
        println(fizzbuzz)
        XCPCaptureValue(fizzbuzz, i)
    }
    else if i % 3 == 0 {
        println(fizz)
        XCPCaptureValue(fizz, i)
    }
    else if i % 5 == 0 {
        println(buzz)
        XCPCaptureValue(buzz, i)
    }
    else {
        println(i)
        XCPCaptureValue(others, i)
    }
}

```


### タプルに修正したFizzBuzz

```swift:FizzBuzzPlayground.playground
enum FizzBuzzResult {
    case FIZZ
    case BUZZ
    case FIZZBUZZ
    case OTHERS(Int)
    
    func toString() -> String {
        switch self {
        case .FIZZ:          return "Fizz"
        case .BUZZ:          return "Buzz"
        case .FIZZBUZZ:      return "FizzBuzz"
        case .OTHERS(let i): return String(i)
        }
    }
}

func fizzbuzz(i: Int) -> FizzBuzzResult {
    switch (i % 3, i % 5) {
    case (0, 0):
        return .FIZZBUZZ
    case (0, _):
        return .FIZZ
    case (_, 0):
        return .BUZZ
    case _:
        return .OTHERS(i)
    }
}

for i in 1...100 {
    
    var retString = fizzbuzz(i).toString()
    
    println(retString)
    
    XCPCaptureValue("capture_i", i)
}

```

参考
[ようこそ！ Swift Playgroundsへ](http://www.slideshare.net/KinkumaDesign/welcome-to-playgrounds)
[XCPlayground Module Reference](https://developer.apple.com/library/ios/documentation/Swift/Reference/Playground_Ref/Chapters/XCPlayground.html)
OSXとHomebrewでNeovimをお手軽にインストール


[21世紀版vim](https://www.bountysource.com/teams/neovim/fundraiser)とも[neovim = VM](http://www.slideshare.net/Shougo/vim-presentation2)とも言われ一部で盛り上がりを見せている[Neovim](http://neovim.org)ですが、[公式サイトのNewsページ](http://neovim.org/news/)を見ていたら[homebrew](http://brew.sh)に対応したようなのでインストールしてみます。

## インストール

**追記 2018年12月: 現在は`brew install neovim`でokです。**

neovimのリポジトリをtapしてからインストールします。

```bash
brew tap neovim/homebrew-neovim
brew install --HEAD neovim
```

[No neovim module found for Python X.X.X](https://github.com/neovim/neovim/issues/1524)のエラーが出る場合やneovimの新しいAPIを試したい場合はPythonのneovimパッケージをインストールします。

```bash
pip install neovim
```

## 設定

neovimの設定ファイルは`.nvimrc`です。一から書くか`.vimrc`をコピーしてneovim用に修正するかは好みの問題だと思います。ここではコピーします。

```bash
cp ~/.vimrc ~/.nvimrc
```

## 起動

```bash
nvim [ファイル名]
```

## アップグレード

```bash
brew update
brew reinstall --HEAD neovim
```

## まとめ

まだ動かないプラグインがあるなどvimと同じようには使えませんが、試しにインストールするくらいであれば誰でもできるようになってました。
MacでMajestouch MINILA Air茶軸(US配列）を使う


MacにBluetoothで接続できるキーボードが欲しくて色々探した結果、これに行き着いた。
今までHHKB Liteを使っていたのだけれど、それと比べるとすごく軽くて使いやすい。疲れないし楽しい。

仕様書を見ると対応OSはWindowsだけだけど、Macでも普通に使えた。
ただ、初期設定としていくらかカスタマイズをしたので、そのメモを残しておく。

## キートップの変更
本製品にはKeyPullerというキートップを取り外しする道具がついているのでこれをつかって取り外しをする。
最初使い方わからなかったけど、以下の写真みたいにキーの角に引っ掛けてから引っ張るだけ。写真でわからなくてもググれば動画とか見つかると思う。
![写真 2014-11-26 0 34 51.jpg](https://qiita-image-store.s3.amazonaws.com/0/2813/2d368199-7433-db44-257f-9cdbe8d8a39b.jpeg "写真 2014-11-26 0 34 51.jpg")

キートップは以下の変更を加えた。

- 「A」の左にあったCpasLockキーをCtrlキーに変更
- 「Z」と「X」の下部にあるAltとWinを交換
- 「Enter」キーの上にあった「\」キーを「←」キーに変更
- 右上にあった「←」キーを「\」キーに変更

完成写真
![写真 2014-11-26 0 33 37.jpg](https://qiita-image-store.s3.amazonaws.com/0/2813/56737a1c-7ccf-649c-e0da-a505b5b84911.jpeg "写真 2014-11-26 0 33 37.jpg")

## DIPスイッチの変更
次にキーボードの裏側にあるDIPスイッチの変更をした。
変更時はキーボードの電源をOFFにしないと危険らしいので気をつける。

DIPスイッチは6つあって、US配列の場合、ONにするとそれぞれ以下のような効果がある。

- 1: Winキー、Appキーを無効化
- 2: CapsLockとCtrlの入れ替え
- 3: 左Fnキーをスペースキーに変更
- 4: 右Fnキーをスペースキーに変更
- 5: Escと「`~」の入れ替え
- 6: 「←」キーと「|\」の入れ替え

このうち、2と6のスイッチをONにした。見難いけど写真。
![写真 2014-11-26 0 37 01.jpg](https://qiita-image-store.s3.amazonaws.com/0/2813/d8a4e54a-0197-7baa-5b7a-be2668095224.jpeg "写真 2014-11-26 0 37 01.jpg")


## キーリマップ
最後にキーリマップ。ここが変更中にこんがらがったりして時間かかった。
実現したかったのは以下の設定（キートップ変更後の状態を基準にしている）。

1. Aキーの左のキーを「Ctrl」にする
2. Enterキーの上にある左矢印キーを「delete」にする\
3. 最右上のキーをバックスラッシュにする
4. 左下にあるCapsLockキー（見た目はCtrlキー）を「Ctrl」にする
5. スペースキーの2つ左にあるWinキーと2つ右にあるAltキーを「Command」にする
6. Zキーの下にあるAltキーを「Option」にする
7. (3の変更が完了したら)右Commandキーで「かな」、左Commandキーで「英字」に変換する


このうち、先のDIPスイッチの変更で1と2と3の設定は完了しているのでスルー。

残りの4つは、正しい変更方法かちょっと自信無いけど、「System Preference > Keyboard > Modifier Keys..」からの設定変更と「Karabiner」の設定を変更することでできた。スクショだけ載せておく。

System Preference > Keyboard > Modifier Keys..
![Screen Shot 2014-11-26 at 1.26.44.png](https://qiita-image-store.s3.amazonaws.com/0/2813/0368dcae-d457-3295-f848-1ae86b90949a.png "Screen Shot 2014-11-26 at 1.26.44.png")

Karabiner
「Change Key > For Japanese > 左右のコマンドキーを「英数／かな」としても使う（v1）」にチェック
![Screen Shot 2014-11-26 at 1.32.06.png](https://qiita-image-store.s3.amazonaws.com/0/2813/6172d827-5300-3fea-379b-c3a545c5e5b8.png "Screen Shot 2014-11-26 at 1.32.06.png")


「Change Key > For Japanese > Change Option_R Key > Option_R to KANA」にチェック
![Screen Shot 2014-11-26 at 1.32.31.png](https://qiita-image-store.s3.amazonaws.com/0/2813/f03bafb7-b240-db12-b54a-3c8474beed86.png "Screen Shot 2014-11-26 at 1.32.31.png")

終わり。
AndroidStudio+SalesforceMobileSDKによるAndroid開発環境構築


MacでAndroid StudioとSalesforce Mobile SDKを利用したAndroidアプリ開発環境を構築するためのメモ書きです。

## 事前準備
### Java SE Developer Kit 7をインストールする
公式サイトからJDKをダウンロードしてインストールする
http://www.oracle.com/technetwork/java/javase/downloads/index.html

### Android Studioをインストールする

公式サイトからAndroid Stadioをダウンロードしてインストールする
http://developer.android.com/sdk/installing/studio.html

インストール先: /Applications/Android\ Studio.app

Android SDK ManagerでSDKをインストールする
今回インストールしたPackage

- Tools
 - Android SDK Tools
 - Android SDK Platform-tools
 - Android SDK Build-tools
- Android 4.4.2 (API 19)
 - SDK Platform
 - Intel x86 Atom System Image
 - Google APIs (x86 System Image)
- Extras
 - Android Support Repository
 - Android Support Library
 - Google Repository
 - Intel x86 Emulator Accelerator (HAXM installer)

検証バージョン: 0.8.14(2014/11/22時点)

### Node.jsをインストールする

公式サイトからNodeJSをダウンロードしてインストールする
http://nodejs.jp/

### Gradleをインストールする
公式サイトからGradleをダウンロードしてインストールする
http://www.gradle.org/downloads

### Salesforce Mobile SDK for Android
npmを利用してforcedroid(Salesforce Mobile SDK for Android)をインストールする

```bash:shell
> sudo npm install -g forcedroid
```

ANDROID_HOMEを設定する

```bash:.bash_profile
export ANDROID_HOME=(Android SDKをインストールしたディレクトリ)
...
```

検証バージョン: 2.3.1(2014/11/22時点)

## Androidアプリを作成する
### Salesforceで接続アプリケーションを作成する
1. Developer Edition にログインする
2. 接続アプリケーションを作成する(コンシューマ鍵、コールバックURLをあとで利用する)

### forcedroidでアプリケーションを作成する
Salesforce接続処理が組み込まれたアプリケーションのサンプルプロジェクトを作成する

```bash:shell
> forcedroid create
Enter your application type (native, hybrid_remote, or hybrid_local): native
Enter your application name: Test
Enter the target directory of your app: Test
Enter the target android api for your application (number between 8 (Froyo) and 19 (KitKat): 19
Enter the package name for your app (com.mycompany.my_app): com.example.test
Do you want to use SmartStore in your app? [yes/NO] ('No' by default) 
```

### Android Studioにインポートする
下記の手順でサンプルプロジェクトをインポートする

1. Android Studioを起動し、Import Project...をクリックする
1. 上記で作成したディレクトリを選択してOKボタンをクリックする
1. Create project from existing sourcesを選択してNextボタンをクリックする
1. Project name、Project locationを確認してNextボタンをクリックする
1. Source filesを確認してNextボタンをクリックする
1. Librriesの名称を確認してNextボタンをクリックする
1. Modulesの名称を確認してNextボタンをクリックする
1. Project SDKを確認してNextボタンをクリックする
1. Manifestファイルを確認してNextボタンをクリックする
1. Open Module Settingsを開く
1. Module「Test」のSourcesタブを開き、srcのマークをSourcesに変更する
1. Module「Test」のDependenciesタブを開き、libs(Library)を追加する
1. Test/res/values/bootconfig.xmlを開き、remoteAccessConsumerKey、oauthRedirectURIをSalesforce接続アプリケーションの設定値に書き換える

### サンプル・アプリケーションを実行する
Android Studioからインポートしたプロジェクトを実行する
1. サンプルプロジェクトを開き、Runボタンをクリックする

## 補記
Salesforce Mobile SDKのバージョンによって動作させるまでの最低限の手順が異なるので注意が必要です
たまに便利な、Rubyの組み込み定数


ちょっとしたコマンドラインツールとかに使えそうな、Rubyの組み込み定数についていくつかメモ。

# STDIN

標準入力を受け取るオブジェクトです。

```stdin.rb
str = STDIN.gets
p str
```

こんな感じで入力した値を受け取る事ができます。

```実行
$ ruby stdin.rb
hoge #hogeと入力
#=> "hoge\n" 
```

# STDOUT, STDERR

それぞれ、```STDOUT ```は標準出力、```STDERR ```は標準エラー出力に対応するオブジェクトです。

```std.rb
STDOUT.puts "STDOUT!"
STDERR.puts "STDERR!"
```

```実行
#  標準出力
$ ruby ./std.rb > hoge.log
#=> STDERR!
$ cat hoge.log
STDOUT!

# 標準エラー出力
$ ruby ./std.rb 2> fuga.log                                                                                  #=> STDOUT!
$ cat fuga.log
STDERR!
```

# ENV
環境変数を表すオブジェクトです。
例えば、以下のような値が取得できます。

```
home = ENV['HOME']
p "user home = #{home}" 
#=> "user home = /Users/USERNAME"

shell = ENV['SHELL']
p "user shell = #{shell}" 
#=> "user shell = /bin/zsh"
```

# ARGF

引数で作られる、仮想ファイルを表すオブジェクトです。
以下の様な動きをします。

```test.text
a
b
c
```

```argf.rb
p ARGF.filename
while line = ARGF.gets
  p line
end
```

```実行
$ ruby ./argf.rb ./test.txt
#ファイル名を取得して出力
"./test.txt" 
#1行ずつ読み込んだものを出力
"a\n" 
"b\n"
"c\n"
```

# ARGV
Rubyスクリプトに与えられた引数を表す配列です。
与えらた引数が配列で出力されます。

```argv.rb
p ARGV
```

```
$ ruby ./argv.rb aaa bbb ccc
#=> ["aaa", "bbb", "ccc"]
```

# DATA

```__END__ ```と組み合わされて使われるんだと思います。

``__END__`` は Ruby スクリプトの終わりを表すキーワードで、これ以降はスクリプトとして読み込まれません。
```DATA```は```__END__```以降にアクセスできます。

```data.rb
p DATA.gets
p DATA.gets
p DATA.gets

 __END__
aaaa
bbb
ccc
```

```実行
$ ruby ./data.rb
"aaaa\n"
"bbb\n"
"ccc\n"
```


# 参考
http://www.geocities.jp/taka_owl2005/job/UNIX/tool/ruby/ENV.html
http://passingloop.tumblr.com/post/12376208854/ruby-end-data
はじめてのHadoop[激動の期間(2014年10月)の株価の相関を求める]

#HadoopをVagrant上に構築して、株価の相関を求める

「Hadoopなんて、クラスタ環境を用意しないと使えない」と思っていたが、1PCでHadoopを動かせると知ったので、Vagrantの中で動かしてみた。

目次

1. Hadoop環境構築
2. Job作成
3. 低スペックによる悲劇

##Hadoop環境構築

Vagrant(CentOS6.5)を使用。
[Hadoop のシングルノード作成方法](http://hadoop.apache.org/docs/r1.2.1/single_node_setup.html)を見ながら作成。

基本的に
JDK本体と、Hadoopをインストールして、SSHを使えるようにすれば完成。
この環境でコンパイルして、Hadoopコマンドで、実行できる。

## Job作成

身近な題材として、株価の相関を求めることに決定。暴落と暴騰による阿鼻叫喚を引き起こした2014年10月の3週間(10/5~10/27)の変動で、似た動きの株があるかどうかを確かめてみる。

対象は、日本に上場している株式約4000と、SBI証券で公開されている投資信託約2000。

普段はpythonで一瞬相関を出しているが、今回はHadoopの分散を意識し、分散共分散行列から相関行列を自力で出している。詳細は[Github](https://github.com/mrasu/hadoop-correlate)
基本的に日数のオーダーのデータ量は１リデュースで処理できると想定している。

フローとしては、ステップを分け、それぞれでMRを実行する。
(runjob.shが実行順序)


1.時系列データから行列を作成する
マップでは株をキーとして分割し、リデュースで日付と株価のMapを作成
![1.時系列→行列.png](https://qiita-image-store.s3.amazonaws.com/0/14254/e4af8dc1-c66c-37d9-4b97-bc5bee911559.png)


2.株価の行番号を求める(行列として計算したいが、株データがばらばらに来るせいで行番号がわからないため)

3.各株の平均から正規化する
マップでは、株をキーとして分割するだけ。
リデュースで平均をだし、各値を平均で引く。


4.分散共分散行列を出す
株Aと株Bのデータを求めるためには、両株のデータが全てがそろっている必要があるので、株数x株数にキーを分けてマップする。
リデュースでは共分散(分散)を求めるのに必要なデータがそろっているので計算する。


5.相関行列を出す。
分散共分散行列からそれぞれの相関を出すために必要なデータをキーに分けてマップする。(今回は対角をキーとしてマップしている。(2,1)のデータは(2,2)をキーとする)
リデュースで、各相関を計算する。


6.各相関は行列の番号になっているので、銘柄名に置き換える。


以上でコードが完成したので、実行する。

#低スペックによる悲劇

実行したら、データが得られると思ったのだが、スペックが低すぎたため完全なデータが得られなかった。

1.ディスク容量不足

Hadoopでは、全マップ計算後にリデュースを行うためにマップで作成したデータを一時ファイルにする。その合計量がVagrantのデフォルト設定である40GBを超えて、クラッシュした。対象データから投資信託の一部を外して再開。

2.スワップによる遅延

データ量が多く、メモリに乗り切らず大量のスワップが発生。計算に4時間を要した。

# 実行完了

データ量を少なくして放置してやっと結果取得に成功。
結果としては、日経とTOPIXが最も相関が高いという、当たり前の結論等を得た。
Uriからファイルパスを取得する

普通にUriからgetPathメソッドでPathを取得すると、

```
「/external/images/media/401」
```

のような形でパスの内容が取得されます。
これを実際のファイルパスである、

```
「/mnt/sdcard/Test_20111101_145318.jpg」
```

のような形で取得する為には、「ContentResolver」を使用する必要があります。
Uriからファイルパスを取得する実際の処理は以下のとおり。

```
/**
 * UriからPathへの変換処理
 * @param uri
 * @return String
 */
public static String getPath(Context context, Uri uri) {
    ContentResolver contentResolver = context.getContentResolver();
    String[] columns = { MediaStore.Images.Media.DATA };
    Cursor cursor = contentResolver.query(uri, columns, null, null, null);
    cursor.moveToFirst();
    String path = cursor.getString(0);
    cursor.close();
    return path;
}
```
Yeomanをインストールしてみる


[Yoeman](http://yeoman.io/)(ヨーマン)はWebアプリの作成時の色々な作業（例えば、アプリ開発時にの定型作業の自動化など）をサポートしてくれる便利ツール。

### Yoemanの構成ツール
- yo - 雛形作成ツールです。yeoman-generator
- bower - JavaScriptライブラリ、CSSフレームワークなどのパッケージマネージャ
- grunt - ビルドツール。JavaScriptベースのタスクランナー。

### Yoemanのセットアップ
####前提
Node.jsがインストールされており、npmが利用できること。

#### yoと必要なツールをインストール
```bash
$ npm install -g yo bower
```

#### generator-webappジェネレータのインストール
```bash
$ npm install -g generator-webapp
```

#### プロジェクトディレクトリの作成
```
$ mkdir my-yo-project
$ cd my-yo-project
```

### Webアプリ雛形を作成する

```bash
$ yo webapp

     _-----_
    |       |    .--------------------------.
    |--(o)--|    |    Welcome to Yeoman,    |
   `---------´   |   ladies and gentlemen!  |
    ( _´U`_ )    '--------------------------'
    /___A___\    
     |  ~  |     
   __'.___.'__   
 ´   `  |° ´ Y ` 

Out of the box I include HTML5 Boilerplate, jQuery, and a Gruntfile.js to build your app.
? What more would you like? 
❯◉ Bootstrap
 ◯ Sass
 ◯ Modernizr
:
:

$ ls -la
total 88
drwxr-xr-x  15 user  staff   510 11 25 23:48 .
drwxr-xr-x  13 user  staff   442 11 25 23:42 ..
-rw-r--r--   1 user  staff    38 10  8 06:10 .bowerrc
-rw-r--r--   1 user  staff   415 10  8 06:10 .editorconfig
-rw-r--r--   1 user  staff    11 10  8 06:10 .gitattributes
-rw-r--r--   1 user  staff    40 11 25 23:47 .gitignore
-rw-r--r--   1 user  staff   353 10  8 06:10 .jshintrc
-rw-r--r--   1 user  staff    27 11 25 23:47 .yo-rc.json
-rw-r--r--   1 user  staff  9462 11 25 23:47 Gruntfile.js
drwxr-xr-x   8 user  staff   272 11 25 23:47 app
-rw-r--r--   1 user  staff    99 11 25 23:47 bower.json
drwxr-xr-x   4 user  staff   136 11 25 23:48 bower_components
drwxr-xr-x  25 user  staff   850 11 25 23:48 node_modules
-rw-r--r--   1 user  staff   885 11 25 23:47 package.json
drwxr-xr-x   7 user  staff   238 11 25 23:47 test
```

### サーバーを起動する

```bash
$ grunt server
-bash: grunt: command not found
```

あれ、どうやら事前にgrunt-cliもインストールする必要があるみたい。1

```bash
$ npm install -g grunt-cli
```

これでもう一度。

```bash
$ grunt server
Running "server" task
>> The `server` task has been deprecated. Use `grunt serve` to start a server.

Running "serve" task

Running "clean:server" (clean) task
>> 0 paths cleaned.

Running "wiredep:app" (wiredep) task
app/index.html modified.

Running "concurrent:server" (concurrent) task
    
    Running "copy:styles" (copy) task
    Copied 1 files
    
    Done, without errors.
    
    
    Execution Time (2014-11-25 15:02:04 UTC)
    loading tasks  1.1s  ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 99%
    Total 1.1s
    
Running "autoprefixer:dist" (autoprefixer) task
File .tmp/styles/main.css created.

Running "connect:livereload" (connect) task
Started connect web server on http://localhost:9000

Running "watch" task
Waiting...
```

これでサーバーが起動して、ブラウザが自動で開いて画面が表示される。

![起動後の画面](/Users/dai/Desktop/screen.png)
Net::HTTPのコードを簡潔に書いてみた


RubyのNET::HTTPを使ったコードが汚い！！
リファクタリングしたい！！
ってなったので、よく使う部分を以下に。

# コード
```
require 'net/http'

uri = URI.parse 'http://example.com'

params = Hash.new
params.store("hoge","1")
params.store("fuga","2")

if method == :get
  uri.query = URI.encode_www_form(params)
  req = Net::HTTP::Get.new uri
end

if method == :post
  req = Net::HTTP::Post.new uri.path
  req.set_form_data(params)
end

res = Net::HTTP.start(uri.host, uri.port) {|http| http.request req }

```

# 参考
##  Get
[Class: Net::HTTP (Ruby 2.1.5)](http://ruby-doc.org/stdlib-2.1.5/libdoc/net/http/rdoc/Net/HTTP.html)
[module URI](http://docs.ruby-lang.org/ja/2.1.0/class/URI.html)
##  Post
[Net::HTTP Cheat Sheet](http://www.rubyinside.com/nethttp-cheat-sheet-2940.html)

# おまけ
って記事を書いたあとに友人から教えてもらいました。
Net::HTTPを無理に使う必要のない方は以下を使ったほうが幸せになれるかも。
[rest-client/rest-client](https://github.com/rest-client/rest-client)
ブラウザでjavascriptを書いて実行できるオープンソースの jsbin と plunker について調べたのでまとめたよ ヽ(ﾟｰﾟ*ヽ)(ﾉ*ﾟｰﾟ)ﾉわぁい

みなさん、おはこんばんにちはでス。ブラウザからjs書いて、動作確認できる仕組みについて調べて :notebook: 次の2つ、jsbin と plunker が比較的メジャーそうなのでまとめた :pencil: 同じようなこと調べているひとがいたら参考になる程度の調査量。つまり少ない。 :scream: 

えっと、 https://jsdo.it の証明書が切れているのは内緒だぞ！

# この記事の内容 :mag: 

『jsFiddle 的なものを実装するために必要な技術調査』をする過程でオープンソースの jsbin と plunker を見つけたのでまとめた。

## 調査時の条件

 - 操作がブラウザのみで完結しているもの :earth_americas: 
 - 実行可能 :arrow_forward:  な言語は javascript だけで良い
 - クライアントサイド（ブラウザ側）のjavascriptだけで良い

## 調査対象としたサービス/サイト

 - jsdo.it http://jsdo.it (https://jsdo.it の証明書が切れてて調査できん)
 - jsFiddle http://jsfiddle.net/ (いろいろオリジナルっぽい)
 - paiza.io https://paiza.io/ (エディタにace.jsを使ってる、ace.jsいいよね)
 - jsbin http://jsbin.com/ (オープンソース)
 - plunker http://plnkr.co/ (オープンソース)

ソースコードが公開されているものが jsbin と plunker だったのでこの記事を書いている次第

# jsbin vs plunker 簡単な比較表

|      |jsbin      | plunker |
|:---------------|:---------------:|:---------------:|
| ウェブサイト | http://jsbin.com/ | http://plnkr.co/ |
| ソースコード | https://github.com/jsbin/jsbin | https://github.com/filearts/plunker |
| ライセンス | MIT | MITっぽい |
| 言語 | Node.js | Node.js |
| DB | たぶん mysql | MongoDB |
| 利用フレームワーク | Express | Express |
| コミット数（2014/11時点）※ | 5,219 | 151 |
| ウォッチ数（2014/11時点）※ | 110 | 13 |
| スター数（2014/11時点）※ | 1,967 | 110 |
| フォーク数（2014/11時点）※ | 561 | 30 |
| その他の特徴 |  | 複数のプロジェクト（レポジトリ）に分かれている |

※plunkerは複数のレポジトリがあるため plunker_www https://github.com/filearts/plunker_www の数字
MacOSXでオンラインサービスを使わずにQRコードを生成するには

## brew でqrencodeをインストール

```
brew install qrencode
```

## QRコードを生成する

例えばhoge.pngというファイル名で画像の形式はPNG,QRコードに埋め込む文字列はhogeという場合は、以下のとおり

```
qrencode -o hoge.png -t PNG hoge
```

## 詳細

```
qrencode -h
```
さくらのVPSをAnsibleでプロビジェニングしてみる



## 概要

* さくらのVPSでCentOS 6のサーバ1台用意
* 用意したサーバをAnsibleでプロビジョニング
	* ユーザの追加
	* 追加ユーザをsudo可能にする
	* 追加ユーザが鍵認証でsshログインできるようにする


## さくらのVPSの準備

### 契約する

[さくらのVPS](http://vps.sakura.ad.jp/)の利用者登録を行う。
今回はさくらのVPS(1G)を契約。

### IPアドレスを確認する

1. [さくらインターネット 会員メニュー](https://secure.sakura.ad.jp/member/)にアクセスしてログインする
2. _契約情報_ > _契約サービスの確認_ を選択する
3. 一覧上で、契約したサーバのIPアドレスが確認できる

### OSインストール

#### さくらインターネット 会員メニュー

1. [さくらインターネット 会員メニュー](https://secure.sakura.ad.jp/member/)にアクセスしてログインする
2. [契約情報] > [契約サービスの確認] > (一覧から契約したサービスの) [サーバ設定] を選択する

#### さくらのVPSコントロールパネル

標準OSインストールで CentOS 6.7 をインストールする。

1. [OSインストール] > [標準OSインストール] を選択する
2. [rootパスワード] を入力して [設定内容を確認する] を選択する
3. [インストールを実行する] を選択する


## Ansibleの準備

### プロジェクト構成

```bash
$ tree
.
├── fuga.pub      # 追加ユーザの公開鍵
├── hosts         # インベントリファイル
└── playbook.yml  # プレイブック
```

```:hosts
***.***.***.***

[all:vars]
ansible_ssh_user=root
```

```:playbook.yml
---
- hosts: all
  sudo: yes
  vars:
    user_name: hoge                                # 追加するユーザ名
    user_password: $1$hoge$DP2bw0KOW0ZhAg2ssVHY7.  # パスワード
    user_public_key_path: fuga.pub                 # 公開鍵の相対パス
  tasks:
    # 必須
    - name: install libselinux-python
    - yum: name=libselinux-python state=latest

    # ユーザを追加
    - name: add a my user
      user: name={{ user_name }} password={{ user_password }} state=present
      
    # sudoユーザに追加
    - name: add a sudo user
      lineinfile: "dest=/etc/sudoers backup=yes state=present regexp='^{{ user_name }}' line='{{ user_name }} ALL=(ALL) NOPASSWD: ALL'"
    
    # 公開鍵の登録
    - name: register a public key
      authorized_key: user={{ user_name }} key="{{ item }}"
      with_file:
        - "{{ user_public_key_path }}"
```

パスワードは以下で生成する。

```bash
$ openssl passwd -salt hoge -1 fuga
$1$hoge$DP2bw0KOW0ZhAg2ssVHY7.
```

### プロビジョニング実行

```bash
$ ansible-playbook -i hosts playbook.yml -k -c paramiko
# 設定した root のパスワードを入力
```
Linux自動インストール = Kickstart



## Kiskstartファイル  ks.cfg

Kickstartでは自動インストールのレシピをファイル化しそれをLinuxインストール時に読み込ませて自動インストール実施します。
Kickstartファイルはあちこちでサンプルが落ちていますが、前回CentOSをインストールした時にその記録が ```/root/anaconda-ks.cfg``` に保存されています。これがKickstartファイルとして利用できます。こんな感じです。

```
# Kickstart file automatically generated by anaconda.

#version=DEVEL
install
url --url=http://ftp.riken.jp/Linux/centos/6.5/os/x86_64/
lang en_US.UTF-8
keyboard jp106
network --onboot yes --device eth0 --bootproto dhcp --noipv6
network --onboot no --device eth1 --bootproto dhcp --noipv6
rootpw  --iscrypted $6$xMBrykBveErIkSvJ$CX1l27S1.jpV7kGs9RtcMgrjchmhQ4PVApun5B/w/WEDQtTkRxDsyl/KcpwZtIG7JYwuEp3Rtj2k06rXjnwhc0
firewall --service=ssh
authconfig --enableshadow --passalgo=sha512
selinux --enforcing
timezone --utc Asia/Tokyo
bootloader --location=mbr --driveorder=sda --append="crashkernel=auto rhgb quiet"
# The following is the partition information you requested
# Note that any partitions you deleted are not expressed
# here so unless you clear all partitions first, this is
# not guaranteed to work
#clearpart --linux --drives=sda
#volgroup VolGroup --pesize=4096 pv.008002
#logvol / --fstype=ext4 --name=lv_root --vgname=VolGroup --grow --size=1024 --maxsize=51200
#logvol swap --name=lv_swap --vgname=VolGroup --grow --size=819 --maxsize=819

#part /boot --fstype=ext4 --size=500
#part pv.008002 --grow --size=1


repo --name="CentOS"  --baseurl=http://ftp.riken.jp/Linux/centos/6.5/os/x86_64/ --cost=100

%packages --nobase
@core
%end
```

1. eth1がonboot no になってますね。これを yes にすればいい感じになりそう
- selinux --enforcing ってなってるからこれを --disabled にしたらいい感じになりそう。
- firewallってのはiptablesのデフォルト設定みたいです。
などなど、色々なオプションはRedHadのドキュメント - https://access.redhat.com/site/documentation/ja-JP/Red_Hat_Enterprise_Linux/5/html/Installation_Guide/s1-kickstart2-options.html に記載されています。

まずはKickstartを試してみることを再優先にすべくあまり編集せずに以下の３行だけ変更

```
network --onboot yes --device eth1 --bootproto dhcp --noipv6
firewall --disabled
selinux --disabled
```

このファイルをLinuxインストール時にしているんですが、どうやって読み込ませるのか色いろあるんですが(FDDやCDROMからとか)、ネットワーク越しでHTTPダウンロードさせるのが楽で慣例っぽいのでそれにする。HTTPサーバは母艦にhttpdたてるのもよし、外部のサーバからダウンロードさせるもよし、今回はGitHubに保存してそこからダウンロードさせることにします。

https://raw.githubusercontent.com/hiyuzawa/centos_install/master/anaconda-ks.cfg

## Kiskstart での自動インストール

VirtualBoxで新規OSをエントリーするところまでは同じ。(CentOS.isoを指定したり、ホストオンリーアダプターアダプタの追加も忘れずに)
インストールCD-ROM起動直後のメニューで「esc」を押します。boot: プロンプトが出るので

```
> linux text ks=https://raw.githubusercontent.com/hiyuzawa/centos_install/master/anaconda-ks.cfg
```

として起動します。
...
...
と思ったらなぜか、「Error downloading kickstart file」って言われた。。
ホストPCにhttpd立ち上げて http://192.168.56.1/anaconda-ks.cfg だとうまくいった。(http://localhost/にしててハマった)

若干対話的な選択が残るもののおおかた自動でインストールされた。
VirtualBox に CentOS をインストール


VirtualBox を使ってCentOS入れる手順メモ

## CentOS

[CentOS Project](http://www.centos.org/) にて ISO イメージをダウンロード. 毎回netinstall版をダウンロードするので今回も http://isoredirect.centos.org/centos/6/isos/x86_64/ この辺から適当に CentOS-6.5-x86_64-netinstall.iso をダウンロード. ( CentOS6 64bit版 )

## VirtualBox

[VirtualBox](https://www.virtualbox.org/) からインストールします。新規作成で

* Linux
* RedHat (64bit)
* メモリサイズ : 1024MB 
* HDD : 新規作成 (VDIタイプ/可変サイズ/8GB)

選んで、次に「設定」から「ストレージ」にて仮想CD-ROMドライブを選択してCentOSサイトからダウンロードしたISOファイルを選択(CD-ROMのアイコンをクリックするのが分かりにくい...)。いよいよインストール。以下の手順にて行う。

1. Virtual BoxのUIで起動をクリック
+ (GUIインストールはキライなので)いきなり出る選択肢でどれも選ばず <span style="color: #cc0000">escキーを押す</span>
+ boot:というプロンプトが出るので <span style="color: #cc0000">linux text</span>と打ち込んでリターン
+ メディアチェックは面倒なので「Skip」
+ インストール言語を「English」選択
+ キーボードを「jp106」選択
+ インストールメディアは「URL」
+ IPv6のsupportはとりあえず外しとく。
+ CentOSのインストールイメージサーバの指定は以下のようにする。
http://ftp.riken.jp/Linux/centos/6.5/os/x86_64/  (好きなミラーでOK)
+ うまく疎通すれば(疎通しない場合はProxyとかネット環境を見直す) install.img がダウンロードされる
+ パーティション設定(GUIキライなので)「Use text mode」
+ Welcome to CentOS ! 「ハイ」
+ HDDは「Re-initialize all」を選択
+ TimeZone は「Asia/Tokyo」
+ root パスワードを設定
+ インストール先パーティション選択はそのまま「OK」
+ 脅しが入るけど構わず「Write changes to disk」
+ インストールが始まる (Packages completed: 217 of 217)
+ 終わったら「Reboot」ボタン。
+ CD-ROMブートしてるとまたインストーラが立ち上がってしまうから一度VirtualBoxの設定でCD-ROM外して起動。
+ loginプロンプトがでたらとりあえずインストール成功

## インストール後の超初期設定

* ユーザ作成

```sh
# useradd [アカウント名]
# passwd [アカウント名]
```

* sudoers設定

```sh
# vi /etc/sudoers
以下の一行を追加
[アカウント名] ALL=(ALL) ALL
```

* 動作確認

```sh
$ # アカウント名でログイン後
$ sudo bash
# #rootになれればOK
```

* selinuxはdisableにしとく

```sh
$ sudo vi /etc/selinux/config
SELINUX=disabled
```

* iptablesもとりあえず全開放

```sh
$ sudo iptables -L  # デフォルトを一応確認
$ sudo iptables -F  # 設定消去
$ sudo iptables -L  # 設定消えていること確認
$ sudo /sbin/service iptables save #設定を保存
```

* ここまでやってとりあえず再起動
 
```sh
$ sudo reboot
```

* ホストOS(macのターミナル)からssh接続

Vmware とか parallels ならあまり考えずにそのまま ssh [アカウント名]@[IPアドレス] で接続できるんだけどVirtualBoxの場合はちょっと手間がかかる。一度CentOSをシャットダウンする。

1. VirtualBoxのグローバルなメニューの「環境設定」を選択し「ネットワーク」にて「ホストオンリーネットワーク」にアダプタを追加する。<span style="color: #cc0000">vboxnet0</span>ってのが追加されるはず。
+ VirtualBoxのゲスト(CentOS)の「設定」にて「ネットワーク」を選択して「アダプター2」ってやつを有効化する。その際の設定は
- ホストオンリーアダプター
ってのを選択する。
+ CentOSを起動する
+ eth1を追加する

```sh
# cd /etc/sysconfig/network-scripts/
# vi ipcfg-eth1

DEVICE=eth1
BOOTPROTO=static
ONBOOT=yes 
IPADDR=192.168.56.2
NETMASK=255.255.255.0
NETWORK=192.168.56.0

# /sbin/service network restart
```

* 以上で Mac(ホストOS)から ssh で接続できるようになる。

```sh
$ ssh [アカウント名]@192.168.56.2
```

* 最後に

```sh
sudo yum update
```

でもしときましょう。

* 番外

eth1を追加するところってなんかイマイチな感じがする。ゲストOS入れる前に vboxnet0 (ホストオンリーアダプター)を定義してゲストOSインストール前の新規構成を作った段階で「アダプタ2」を追加すればいいんじゃね。と思ってやってみた。

1. ipcfg-eth1 がOSインストール時からできていた
- ただし ONBOOT=no だった
- ONBOOT=yesにして再起動してみた. eth1 が 192.168.56.101 でdhcp割り当てられてすんなりホストOSからSSHできた。