OmniAICreator/Qiita-1.07M huggingface dataset:
ファイル作成時間の偽装

# 概要

期限切れのファイルを削除するようなスクリプトをテストするため、ファイルの作成日時を偽装する方法について調べた。まとめると下記の通り。

- 作成日時を偽装するには `touch -t 'YYYYMMDDhhmm' hoge.txt`
- 作成日時を確認するには
  - coretuils あり `ls -lt --time-style=long-iso`
  - coretuils なし `ls -lT`

# 詳細

もっと具体的な例や、表示結果については以下に書く。

## ファイル作成時間の偽装

`touch` コマンドのオプション `-t` を使えば過去または、未来の作成日時を持つファイルを作ることができる。使い方は下のコードを参照。[man touch](https://linuxjm.osdn.jp/html/gnumaniak/man1/touch.1.html) を見ればもっと詳しく書いてある。

```.sh
# 1999年4月1日0時0分のファイル作成
touch -t '199904010000' hoge.txt

# 上と同じファイルを作成（年を2桁で書く）
# 但し、ルールが特殊（1969年〜2068年で解釈する）ので、使わないほうが良さそう。
touch -t '9904010000' hoge.txt

# 今年4月1日0時0分のファイル作成
touch -t '04010000' hoge.txt
```


## ファイル作成日時の確認

確認する際は、`ls` のオプションを使う。GNU ls と BSD ls でオプションが異なる。環境によって違うのでとりあえず両方試してみたら良いと思う。mac の場合はデフォルトでは BSD ls しか入ってないので GNU ls が使いたければ「[homebrew でMacコマンドをLinuxのGNU風に置換する](
http://takuya-1st.hatenablog.jp/entry/20111230/1325272152)」を参考に coreutils をインストールすれば良い。

```.sh
ls -lT
# -rw-r--r--  1 user  staff     0  4  1 00:00:00 1999 hoge.txt

ls -l --time-style=long-iso
# -rw-r--r-- 1 user staff    0 1999-04-01 00:00 hoge.txt
```

## ファイル作成スクリプト

最後に、テストするための作ったスクリプトを載せておく。下のコードを実行すると、過去10日分の空ファイルを作成する。ここで使っている date -d は GNU のバージョンでないと利用できない。

```.sh
for i in {0..9}
do
  stamp=`date -d "$i days ago" +%m%d0000`
  touch -t $stamp "hoges_$i.txt"
done

# ワンライナー版
for i in {0..9}; do touch -t `date -d "$i days ago" +%m%d0000` hoge_$i.txt; done
```
Storyboardで設定した項目が半透明になっている症状の解決方法

アプリのアップデート実装を行っていたところ、Storyboardを開くとこのようになって、設定したオブジェクトやLayoutの設定が全て半透明になっていました。

<img width="90%" src="https://qiita-image-store.s3.amazonaws.com/0/40009/b1b0c68c-d25e-04e8-8605-54969e2efd9e.jpeg">

半透明になっているせいか、レイアウトの編集など何もできない状態になってしまっていました。

アプリを起動すると、問題なくきちんと表示はされる。
コード上ではきちんとオブジェクトと連携はされている。

なぜかStoryboard上だけ。。。と思い返してみるとSizeClassesの設定がリセットされていました。

<img width="353" src="https://qiita-image-store.s3.amazonaws.com/0/40009/9149b9ce-ef1c-45dc-245c-983355103d2d.jpeg">

これを

<img width="374" src="https://qiita-image-store.s3.amazonaws.com/0/40009/e6971e1a-6277-519b-bff8-d272b94f24f1.jpeg">

このように変更してみると、

<img width="90%" src="https://qiita-image-store.s3.amazonaws.com/0/40009/e8f7d4c9-6023-7e12-51e4-fa54100a95ca.jpeg">

戻った！

かなり前に作成したアプリで、SizeClassesはiPhoneだけでいいや…というものがこんなところでつまずくとは。。。

原因はおそらくcocoaPodsの導入をしたからかな…と思っています。
xcodeprojファイルではなく、xcworkspaceファイルから起動すると、こういうことが起こるのでしょうか。

ひとまず解決。
あまりないかもしれませんが、何かの役に立てれば幸いです。


余談ですが、逆を言えば、
SizeClassesを変更したいときには全てレイアウト等全て再設定する必要があるということですね。。
かなりしんどい。。このあたりうまいことやってくれないでしょうかね。。。。
RailsでDragonflyを利用して動的に処理しつつS3側のCDNを利用したい。


## これはなに？
- Dragonflyを利用してリサイズなどの画像処理をしたい
- リサイズ画像をS3に都度アップロードしたい
- Railsではなくて、S3のbucketのドメインにCDNしたい。

上記要件を達成するために、色々ゴニョった結果案外シンプルなことになったので、結果を共有というかメモしておきます。


## 都度S3にアップロードする処理
Dragonfly のドキュメントに一応載ってるけど、転載します。

まずTableの作成、カラムが2つあればOK。

- signatureは、sha部分が入ります。
- uidは、s3のbucket以下のpathが入ります。

```db/schemas/thumbnails.schema
create_table "thumbnails", id: :bigint, unsigned: true, force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4" do |t|
  t.string   "signature",                limit: 191, null: false
  t.string   "uid",                      limit: 255, null: false
  t.datetime "created_at",                           null: false
  t.datetime "updated_at",                           null: false
end

add_index "thumbnails", ["signature"], name: "xxxxx", unique: true, using: :btree

```

続いて、configureの設定

```config/initializers/dragonfly.rb
require 'dragonfly'
require 'dragonfly/s3_data_store'

Dragonfly.app.configure do
  ...
  define_url do |app, job, opts|
    thumb = Thumb.find_by(signature: job.signature)
    if thumb
      app.datastore.url_for(thumb.uid)
    else
      app.server.url_for(job)
    end
  end

  before_serve do |job, env|
    uid = job.store
    Thumb.create!(uid: uid, signature: job.signature)
  end
end

...
```

注意点としては、S3DataStoreの `url_for` で期待するpathが返ってくるように設定する必要があります。

- 参照: [processing-on-the-fly-and-serving-remotely](http://markevans.github.io/dragonfly/cache/#processing-on-the-fly-and-serving-remotely)

## Railsではなくて、S3のbucketのドメインにCDNしたい
Dragonflyのドキュメントや、見つけた参考になりそうなQiitaなどは、みなさんサービスドメインに対してCDNを設定する前提になっているので、そうじゃなくて「`S3のバケットをCDNしたいんだよ！`」ということでゴニョりしました。

```config/initializers/dragonfly.rb
...
  datastore :s3,
      bucket_name:       ENV['S3_BUCKET_NAME'],
      access_key_id:     ENV['AWS_ACCESS_KEY'],
      secret_access_key: ENV['AWS_SECRET_ACCESS_KEY'],
      url_scheme:        ENV['S3_SCHEME'],
      url_host:          ENV['S3_CDN_HOST'],
      region:            ENV['S3_REGION']

...
```

- url_schemeは、httpsを利用する必要があれば追加してください。(defaultは httpです）
- url_hostは、CDNのhost名を設定します。datastore側のurl_hostに設定することで、 `url_for` methodで期待するhostを返してくれるようになります。（何も設定しないと、bucket名から生成したs3のホスト名です）

## 最終的な、configure

参考までに掲載しておきますね。

https://gist.github.com/kozyty/d1eb6a89cb7e4a1c8a93028dc6d19ea8

ポイントとしては、shaをquery string にせず、pathに入れたりできるので、それをやってます。

## 参考
みなさんのアウトプットに感謝します。

- [markevans/dragonfly-s3_data_store/s3_data_store.rb](https://github.com/markevans/dragonfly-s3_data_store/blob/master/lib/dragonfly/s3_data_store.rb)
- http://qiita.com/shimbaco/items/7ab547a9eceb37793f3a
- http://qiita.com/anoworl/items/0e3f1643ef794de058df
- http://qiita.com/anoworl/items/35e75a20e70d2ad0f658
Json.NET でシリアライズ/デシリアライズ時に日付フォーマットを指定する

Json.NETがとても便利なのです。
![Json.NET logo](https://raw.githubusercontent.com/JamesNK/Newtonsoft.Json/master/Doc/icons/logo.jpg)

基本的にはこちらの[C#でJSONを扱うライブラリ「Json.NET」を使ってみました](https://dynamicjson.codeplex.com/)でまとめられています。

## DateTime型のフィールドを扱いたい
モデル上ではDateTime型で扱い、JSONにパースする際は決まったフォーマットで扱いたい。
あるいは、決まったフォーマットの日付文字列をDateTime型のフィールドに収めたい。
皆さんこんな気持ちありますよね。

そんな時にはDateTimeConverterを `SerializeObject()` や `DeserializeObject()` に渡してあげます。
http://www.newtonsoft.com/json/help/html/datesinjson.htm

僕はISO8601のフォーマット(+09:00付き)としたかったのでこんな感じになりました。

```csharp
using NewtonSoft.Json;
using NewtonSoft.Json.Converters;

// Serialize
var jsonStr = JsonConvert.SerializeObject(json, new IsoDateTimeConverter());

// Deserialize
var json = JsonConvert.DeserializeObject<Model>(jsonStr, new IsoDateTimeConverter());
```
何と簡単!

### すでに引数へJsonSerializerSettingsを渡している場合

```csharp
using NewtonSoft.Json;
using NewtonSoft.Json.Converters;

// Serialize
var jsonStr = JsonConvert.SerializeObject(json, new JsonSerializerSettings { Converters = { new IsoDateTimeConverter() } });

// Deserialize
var json = JsonConvert.DeserializeObject<Model>(jsonStr, new JsonSerializerSettings { Converters = { new IsoDateTimeConverter() } });
```
こちらも簡単ですね。

### カスタムフォーマットの場合

```csharp
new IsoDateTimeConverter { DateTimeFormat = "yyyy年MM月dd日 HH時mm分ss秒" };
```
とやると、できるとかできないとか。(未検証)
GPUImagePictureで透過画像を合成すると灰色になっちゃうよー問題


GPUImage便利ですね。

そんな便利なGPUImageですが、透過PNG画像を合成させると灰色になってしまう、というハマりポイントがあります。

具体的には、こんなコードを書いてしまうと(細部は省略)

```objc
sourceOverBlendFilter = [[GPUImageSourceOverBlendFilter alloc] init];
overlayPicture = [[GPUImagePicture alloc] initWithImage:overlayImage];

[source addTarget:sourceOverBlendFilter];
[sourceOverBlendFilter addTarget:self.movieWriter];
[overlayPicture addTarget:self.sourceOverBlendFilter];
[overlayPicture processImage];
```

こんな画像を合成させたのに、
![nice.png](https://qiita-image-store.s3.amazonaws.com/0/43690/0bf31dc5-4d2c-2350-28bb-0ba4258bd5bd.png "nice.png")

こんなになっちゃうことがあります。
![dame.png](https://qiita-image-store.s3.amazonaws.com/0/43690/e7fe386f-9344-95cc-37a0-89ba6f9fd813.png "dame.png")


これはなぜかというと、この画像のビットマップ配列が`kCGImageAlphaPremultipliedFirst`になっているのですが、GPUImagePictureはそのままテクスチャにしてしまうので、プレマルチではない（＝ストレートな）ビットマップを期待するOpenGL ES側で合成すると、そのまま計算されて灰色がかかってしまっています。
(プレマルチプライドアルファについては 例えば http://www.nekomataya.info/nekojyarashi/wiki.cgi?AlphaMode#i3 とか)


これは既知の問題で、[Issue](https://github.com/BradLarson/GPUImage/pull/2028)にも上げられていてマージ済です。ですので、上のコードの`GPUImagePicture`を作っている部分を

```objc
overlayPicture = [[GPUImagePicture alloc] initWithImage:overlayImage smoothlyScaleOutput:NO removePremultiplication:YES];
```

このように書き換えれば治るようなきがするのですが、治らない!!
このPRをよく読むと、`kCGBitmapByteOrder32Little`の時に動かないバグがあるのでパッチを書きました。

https://github.com/shnjp/GPUImage/commit/93577b04980aadedbb71938bcec114723e42f1ac
 
やった！できた！
 
おしまい。   



GPUImageはPR溜まり過ぎじゃよ
[cakephp3]クエリビルダでアソシエーションの条件を変える

## 結合方法を変える
typeで指定する

<pre>
$query = $this->Articles->find()->contain([
    'Authors' => [
        'joinType' => 'LEFT',
        'queryBuilder' => function ($q) {
            return $q->where(...); // フィルタのための完全な条件
        }
    ]
]);
</pre>

## ONの条件を増やす
containのwhereでvalueに結合条件を書く

<pre>
$query = $this->Articles->find()->contain([
    'Authors' => function ($q) {
        return $q->where([
            'Articles.group_id = Authors.group_id',
            …
        ]);
    }
]);
</pre>
WebStormで想定しないブラウザーが開かれてしまう時の設定場所

![image 2016-04-01 18.13.25.png](https://qiita-image-store.s3.amazonaws.com/0/1423/f4b3b629-5303-f2c3-298d-b8117ea72a8d.png)
▲ index.htmlなどの時に表示されるボタン。クリックした時に、Pararells Desktopの上のWidnowsのChromeが開かれてしまった。


![image 2016-04-01 18.17.10.png](https://qiita-image-store.s3.amazonaws.com/0/1423/38183246-82ac-7a75-1fe3-460c9043b0d1.png)
▲ [WebStorm]→[Preferences]→[Tools]→[Web Browsers]の[Path]を変更で、想定のブラウザが開いた。
dashDB を Excel から利用する時の通信エラーの解決

dashDBのGUIを利用してSQLを実行すると以下の図の赤枠にある
「Run Query in Excel via ODC file」というボタンが表示されます。

このODCファイルというのは　Office データ接続 (.odc) ファイルと呼ばれるファイルで、データソースへの接続情報とクエリが含まれています。

つまり、このODCファイルをダウンロードしてExcelで開くとExcelからdashDBに接続してクエリの実行結果がExcelに取り込まれるという便利なファイルです。

![image](https://qiita-image-store.s3.amazonaws.com/0/112854/80b66db1-7a25-9b91-3332-983da8da0184.png)

**しかし…**
私の環境では以下、SQL30081N 通信エラーとなってしまいました…
![image](https://qiita-image-store.s3.amazonaws.com/0/112854/8b7565fb-1899-cdea-e2b0-9f36d0077b87.png)

さて、ODCファイルを見てみるとどうも ``Hostname=;`` ホスト名が空欄になって何もインプットされていないようでした。

```lang:ODCfile
<html xmlns:o="urn:schemas-microsoft-com:office:office"   xmlns="http://www.w3.org/TR/REC-html40">
   <meta http-equiv=Content-Type content="text/x-ms-odc; charset=utf-8">
   <meta name=ProgId content=ODC.Table>
   <meta name=SourceType content=OLEDB>
<meta name=Schema content=dashXXXX>
<meta name=Table content=PERSON>
<title>dashXXXX</title>
<xml id=docprops><o:DocumentProperties     xmlns:o="urn:schemas-microsoft-com:office:office"     xmlns="http://www.w3.org/TR/REC-html40">
<o:Name>dashXXXX</o:Name>
</o:DocumentProperties>
</xml><xml id=msodc><odc:OfficeDataConnection
xmlns:odc="urn:schemas-microsoft-com:office:odc"
xmlns="http://www.w3.org/TR/REC-html40">
 <odc:Connection odc:Type="OLEDB">
   <odc:ConnectionString>Provider=IBMDADB2.IBMDBCL1;Persist Security Info=False;User ID=dashXXXX;Mode=ReadWrite;Extended Properties=&quot;Database=BLUDB;Hostname=;Protocol=TCPIP;Port=50000&quot;</odc:ConnectionString>
 <odc:AlwaysUseConnectionFile/>
 <odc:CommandType>SQL</odc:CommandType>
 <odc:CommandText>SELECT CLOSE_DAY_KEY, EMPLOYEE_KEY, GROSS_MARGIN, GROSS_PROFIT, ORDER_DAY_KEY,
ORDER_METHOD_KEY, ORGANIZATION_KEY, PRODUCT_KEY, PROMOTION_KEY, QUANTITY, RETAILER_KEY
RETAILER_SITE_KEY, SALES_ORDER_KEY, SALE_TOTAL, SHIP_DAY_KEY, UNIT_COST, UNIT_PRICE, UNIT_SALE_PRICE
FROM GOSALESDW.SLS_SALES_FACT
WHERE QUANTITY > 9000
ORDER BY GROSS_PROFIT DESC</odc:CommandText>
 </odc:Connection>
 </odc:OfficeDataConnection>
</xml>
</html>
```

ファイルを編集し、ホスト名を入力して再度実行したところうまく実行できました！
ちなみに接続情報は左のメニューから Connect -> Connection Information で確認出来ます。
![image](https://qiita-image-store.s3.amazonaws.com/0/112854/6325d107-f94d-3b9c-452f-512c71782b12.png)

うまくいくとODCファイルを開くとパスワードを聞かれます。
![image](https://qiita-image-store.s3.amazonaws.com/0/112854/61c362ae-dbdf-e251-ac0a-b1901661e2e7.png)

入力してしばらくODCファイルに含まれるクエリの実行結果ががExcelにダウンロードされるのを待ちます。
![image](https://qiita-image-store.s3.amazonaws.com/0/112854/97b2f5be-fd91-114f-0cd0-7831e3d22f9e.png)

Excel連携は便利なので試してみてはいかがでしょうか。
debian sidでvagrant plugin install ができなくなったときの対処方法

# 概要

debian sidのvagrantパッケージを使っていて、
vagrant のプラグインをいれようとしたら、エラーがでた。

```
/usr/lib/ruby/2.3.0/rubygems/specification.rb:946:in `all=': undefined method 
```

# 結論

* [Install error: in `all=': undefined method `group_by' for nil:NilClass (NoMethodError) · Issue #575 · pradels/vagrant-libvirt](https://github.com/pradels/vagrant-libvirt/issues/575)

こちらを参考に、hashicorpから直接ダウンロードしてきたら、インストールできた。

# エラーがでたときのログ

```
$ vagrant plugin install vagrant-chef-zero
Installing the 'vagrant-chef-zero' plugin. This can take a few minutes...
/usr/lib/ruby/2.3.0/rubygems/specification.rb:946:in `all=': undefined method `group_by' for nil:NilClass (NoMethodError)
	from /usr/lib/ruby/vendor_ruby/vagrant/bundler.rb:275:in `with_isolated_gem'
	from /usr/lib/ruby/vendor_ruby/vagrant/bundler.rb:231:in `internal_install'
	from /usr/lib/ruby/vendor_ruby/vagrant/bundler.rb:102:in `install'
	from /usr/lib/ruby/vendor_ruby/vagrant/plugin/manager.rb:62:in `block in install_plugin'
	from /usr/lib/ruby/vendor_ruby/vagrant/plugin/manager.rb:72:in `install_plugin'
	from /usr/share/vagrant/plugins/commands/plugin/action/install_gem.rb:37:in `call'
	from /usr/lib/ruby/vendor_ruby/vagrant/action/warden.rb:34:in `call'
	from /usr/lib/ruby/vendor_ruby/vagrant/action/builder.rb:116:in `call'
	from /usr/lib/ruby/vendor_ruby/vagrant/action/runner.rb:66:in `block in run'
	from /usr/lib/ruby/vendor_ruby/vagrant/util/busy.rb:19:in `busy'
	from /usr/lib/ruby/vendor_ruby/vagrant/action/runner.rb:66:in `run'
	from /usr/share/vagrant/plugins/commands/plugin/command/base.rb:14:in `action'
	from /usr/share/vagrant/plugins/commands/plugin/command/install.rb:32:in `block in execute'
	from /usr/share/vagrant/plugins/commands/plugin/command/install.rb:31:in `each'
	from /usr/share/vagrant/plugins/commands/plugin/command/install.rb:31:in `execute'
	from /usr/share/vagrant/plugins/commands/plugin/command/root.rb:56:in `execute'
	from /usr/lib/ruby/vendor_ruby/vagrant/cli.rb:42:in `execute'
	from /usr/lib/ruby/vendor_ruby/vagrant/environment.rb:268:in `cli'
	from /usr/bin/vagrant:173:in `<main>'
```

## なぜ？

debian 側の問題？

## 今後

chef dk のdebianパッケージがあるようなので、これにしたほうが良さそうかな。

* [Chef Development Kit | Chef Downloads | Chef](https://downloads.chef.io/chef-dk/debian/)
AWS S3でGZIP圧縮を利用してPOSTリクエストを減らす

コンテンツを公開する際の一つの手段として便利なS3
それをさらにもう一歩お得に使える方法を書いてみようと思います

S3上に配置するコンテンツが、もし多数でありなおかつ何度も更新されるような場合
そんな時に使える方法です。

# 概要

1. コンテンツをローカルでgzipで圧縮する
2. 圧縮したコンテンツをconcat（連結）する
3. 連結する際に圧縮した際のコンテンツのサイズと、インデックスをメモする
4. メモしたサイズ・インデックスを元にRangeリクエストをする

# 備考

上記の方法を使うと、POSTリクエストを一つにまとめることが出来てとてもお財布に優しくなります。
サイズとインデックスのメモデータを取得する必要があるのでGETリクエストが増えると感じるかも知れませんが、AWSの料金は以下のようになっています
大事なのはGETリクエストの方は10,000リクエストとPOSTリクエストに比べて一桁安く設定されています


2016年4月時点
POSTリクエストが $0.0047/1,000リクエスト
GETリクエストが $0.0037/10,000リクエスト
[Git] リモートリポジトリのパスの書き方一覧

```bash
git clone 'ここの書き方を毎回忘れる'
```

ので整理しておく。
リモートリポジトリのパスの書き方は大きく以下の6種類に分かれる。

* Localプロトコル(1)
* Localプロトコル(2)
* HTTP(S)プロトコル
* SSHプロトコル(1)
* SSHプロトコル(2)
* Gitプロトコル

# Localプロトコル(1)
## 記法
* 例: `/path/to/repo.git/`
* 絶対パスのみ指定可能（~展開無し）
* （NFSを含む）ファイルシステムからアクセスできるリポジトリのみ指定可能

## 特徴
* Gitはハードリンクを行うか必要に応じて直接ファイルをコピーする（ので高速）

# Localプロトコル(2)
## 記法
* 例: `file:///path/to/repo.git/`
* 絶対パスのみ指定可能（~展開無し）
* （NFSを含む）ファイルシステムからアクセスできるリポジトリのみ指定可能

## 特徴
* Gitはわざわざネットワーク越しにファイルを転送する（ので低速）
* 他のバージョン管理システムからインポートしたときなどに現れる、関係のない参照やオブジェクトを除いた、クリーンなコピーが欲しいときに使う

# HTTP(S)プロトコル
## 記法
* 例: `http[s]://example.com[:443]/path/to/repo.git/`
* ポート番号指定可能

## 特徴
* GitはHTTP(S)を使ってファイルを転送する
* HTTP(S)の認証機構を利用することもしないこともできる
* 匿名のpullが可能
* 認証を行った上でのpushが可能
* HTTPSならば通信の暗号化が可能
* Gitが最も推奨しているプロトコル

# SSHプロトコル(1)
## 記法
* 例: `ssh://[user@]example.com[:22]/~/path/to/repo.git/`
* 絶対パスのみ指定可能（~展開あり）
* ポート番号指定可能

## 特徴
* GitはSSHを使ってファイルを転送する
* SSHの認証機構を必ず利用する
* 匿名のpullが不可能
* 認証を行った上でのpushが可能
* 通信の暗号化が可能

# SSHプロトコル(2)
## 記法
* 例1: `[user@]example.com:path/to/repo.git/`
* 例2: `[user@]example.com:/~/path/to/repo.git/`
* ホームディレクトリからの相対パスも絶対パスも指定可能（~展開あり）
* ポート番号指定不可能

## 特徴
記法を除いてSSHプロトコル(1)と全く同じ

# Gitプロトコル
## 記法
* 例: `git://example.com[:9418]/~/path/to/repo.git/`
* 絶対パスのみ指定可能（~展開あり）
* ポート番号指定可能

## 特徴
* GitはデフォルトではTCP/9418を用いる独自プロトコルでファイルを転送する
* リモートリポジトリ側はGitデーモンを動かした上でプロジェクトごとにgit-export-daemon-okというファイルを作る必要がある
* 認証機構が無いので実質read-only
* 匿名のpullが可能
* 認証を行った上でのpushが不可能
* 通信の暗号化が不可能

# まとめ
||Local|HTTP|HTTPS|SSH(1)|SSH(2)|Git|
|:---|---|---|---|---|---|---|
|リモートアクセス|$\color{lightgreen}{\rm △}$（要NFS）|$\color{blue}{\rm ○}$|$\color{blue}{\rm ○}$|$\color{blue}{\rm ○}$|$\color{blue}{\rm ○}$|$\color{blue}{\rm ○}$|
|絶対パス|$\color{blue}{\rm ○}$|N/A|N/A|$\color{blue}{\rm ○}$|$\color{blue}{\rm ○}$|$\color{blue}{\rm ○}$|
|ホームディレクトリからの相対パス|$\color{red}{\rm ×}$|N/A|N/A|$\color{red}{\rm ×}$|$\color{blue}{\rm ○}$|$\color{red}{\rm ×}$|
|~展開|$\color{red}{\rm ×}$|N/A|N/A|$\color{blue}{\rm ○}$|$\color{blue}{\rm ○}$|$\color{blue}{\rm ○}$|
|ポート番号指定|N/A|$\color{blue}{\rm ○}$|$\color{blue}{\rm ○}$|$\color{blue}{\rm ○}$|$\color{red}{\rm ×}$|$\color{blue}{\rm ○}$|
|匿名のpull|N/A|$\color{blue}{\rm ○}$|$\color{blue}{\rm ○}$|$\color{red}{\rm ×}$|$\color{red}{\rm ×}$|$\color{blue}{\rm ○}$|
|認証済のpush|N/A|$\color{blue}{\rm ○}$|$\color{blue}{\rm ○}$|$\color{blue}{\rm ○}$|$\color{blue}{\rm ○}$|$\color{red}{\rm ×}$|
|通信の暗号化|N/A|$\color{red}{\rm ×}$|$\color{blue}{\rm ○}$|$\color{blue}{\rm ○}$|$\color{blue}{\rm ○}$|$\color{red}{\rm ×}$|

# 参考リンク
* [git/urls.txt at v2.8.0 · git/git](https://github.com/git/git/blob/v2.8.0/Documentation/urls.txt)
* [Git - プロトコル](https://git-scm.com/book/ja/v2/Git%E3%82%B5%E3%83%BC%E3%83%90%E3%83%BC-%E3%83%97%E3%83%AD%E3%83%88%E3%82%B3%E3%83%AB)
Laravel5 FuelPHP Windows 構築メモ1 PC環境構築

# はじめに
Homesteadを利用してphp開発環境をwindows10で構築する。
PC:Surface3 windows 10
PHP: Laravel ,FuelPHP
##対応バージョン
Git for Windows 2.12.2(2)
TortoiseGit 2.4.0
Virtualbox 5.1.18
Vagrant 1.9.3

#git for windows インストール
https://git-for-windows.github.io/

#TortoiseGitのインストール
https://tortoisegit.org/download/
(1)64-bitまたは32-bitを選択
(2)言語パックもダウンロード(Japanese)

本体をインストール後言語パックをインストール

# Virtualbox インストール
https://www.virtualbox.org/
![Virtualbox](https://www.virtualbox.org/graphics/vboxlogodown.png)
VirtualBox 5.x.x for Windows hosts  x86/amd64
をダウンロードしてインストール。

# Vagrant インストール
https://www.vagrantup.com/downloads.html
![Vagrant](https://www.vagrantup.com/assets/images/favicons/apple-touch-icon-fcccc581.png)
Windows版
Universal (32 and 64-bit)
をダウンロードしてインストール。

[→構築メモ2 homesteadのインストールへ](http://qiita.com/sheena_gl/items/bc264cd59e8c591dae2f)
lolexでE2Eテストの現在時刻をモックする


# **概要**

E2Eテストで、現在時刻を決め打ちしたく、ブラウザ上で時間をモックする方法を試行錯誤した。その過程と解決方法をメモしておく。フレームワークはNightwatchを使っている。

# **プロセス**

## **sinon.jsとwebpackの相性が悪い**

sinon.jsに<a href="http://sinonjs.org/docs/#clock" target="_blank">Fake timer</a>というのがあったのでそれを使おうと試みた。

Nightwatchでできるのが、ブラウザの中でサードパーティを読み込む感じのことではなかったため、webpackでサーバーを立てるときに、`NODE_ENV=e2eTest`の時だけsinon.jsをglobalに読み込もうとした。

そこで以下のissueにあるような問題が生じた・・・。一通り試したが、どうもブラウザに読み込むのは難しいようだった(ここで結構時間を消耗しすぎた感があった)。

* <a href="https://github.com/webpack/webpack/issues/304" target="_blank">Sinon causing issues again · Issue #304 · webpack/webpack</a>
* <a href="https://github.com/airbnb/enzyme/issues/47" target="_blank">Webpack build issues · Issue #47 · airbnb/enzyme</a>

## **lolexを試してみることに**

そもそもsinon.jsのFake timerは<a href="https://github.com/sinonjs/lolex" target="_blank">lolex</a>というライブラリを使用しているらしい。今回はsinon.jsすべての機能が必要だったわけではないので、時間操作だけできるlolexを使用してみることに。

結果的には以下の様なコードでlolexを読み込むことができた。ワークアラウンドっぽいですが・・・。

```js
// アプリケーション側のコード
if (__E2E__) {
  window.lolex = require('lolex');
}
```

これをE2E側の必要な箇所で使用する。Nightwatchの実行環境はNode.jsなので、ブラウザ側で実行するために`execute`を使う必要がある。

```js
// テストコード
browser
  .execute(function () {
    const clock = window.lolex.createClock(new Date(2015, 7, 20, 19, 45));
    window.Date = clock.Date;
  });
```

これにてブラウザ側でも時間を自由に操作することができた。注意点として、moment.jsをアプリケーション側で使っている場合、以下のように書く必要がある。

```js
// NG
moment();

// OK
moment(new Date());
```

詳細な理由は以下のissueに書いてあった。

* <a href="https://github.com/sinonjs/sinon/issues/171" target="_blank">useFakeTimers does not seem to work with moment.js · Issue #171 · sinonjs/sinon</a>

# **まとめ**

解決のプロセスにも問題があったと思うが、E2Eはけっこう独特なスキルが必要だなと改めて感じた・・・。どうにかいい感じに付き合ってゆく方法を見つけたい
【続】SwiftでFacebook連携しよう！（＜CocoaPods＞でuse_frameworks!を有効にした場合）

# 概要
* この記事は『[SwiftでFacebook連携しよう！](http://qiita.com/natsumo/items/f5c4d41edae17a4a75ce)』の続編です！
* 『SwiftでFacebook連携しよう！』では、CocoaPodsを使用してSDKを導入する部分でPodfileに`use_framewoeks!`を使用せず、ブリッジファイルを作成して読み込む形式を取っていましたが、ぜひ「`use_framewoeks!`を有効化した場合の方法が知りたい」とのご要望をいただきました。調べてみましたので報告します。


# **Podfileの「use_frameworks!」を有効にした場合の導入方法**
* 下記の操作以外は基本的に『[SwiftでFacebook連携しよう！](http://qiita.com/natsumo/items/f5c4d41edae17a4a75ce)』と同様です。詳しくは記事をご覧ください。

## 操作手順
(1) mBaaSのiOS SDKを一部編集して使用します。mBaaSのiOS SDKは[GitHub上](https://github.com/NIFTYCloud-mbaas/ncmb_ios)にありますで、右上の「Fork」ボタンをクリックして自分のディレクトリにコピーします
  ![171.png](https://qiita-image-store.s3.amazonaws.com/0/112032/bbca36f0-2146-c5ea-33b3-9d41e2dc5f01.png)

(2) 自分のディレクトリ内にコピーしたSDKの中に、Pod installするときに読み込むファイル「NCMB.podspec」ファイルを開きます、
  ![170.png](https://qiita-image-store.s3.amazonaws.com/0/112032/430f4fca-65b0-806c-fde9-4a561bd18abe.png)

(3) 右上のペンマークをクリックして編集画面を開きます、最後の「end」の１行前に下記を追記してcommitします

```rb:AppDelegate.NCMB.podspec
s.dependency 'FBSDKLoginKit'
```

![169.png](https://qiita-image-store.s3.amazonaws.com/0/112032/3555110c-b7ce-31d2-528b-107fa4a7c691.png)

* SDKの操作は以上です

(4) __既存のプロジェクトを使用する場合のみ：__.xcodeprojディレクトリ内にある下記のファイルあるいはフォルダを削除します

 * `****.xcworkspace`
 * `Podfile.lock`
 * `Pods`フォルダ

(5) 「Podfile」を下記内容に修正して、ふたたびターミナルでpod installを行います

```rb:Podfile
# Uncomment this line to define a global platform for your project
platform :ios, '8.0'
# Uncomment this line if you're using Swift
use_frameworks!
target '****プロジェクト名****' do
    pod 'NCMB', :git => 'https://github.com/****自分のGitHubディレクトリ名****/ncmb_ios.git'
end
```
※「`https://github.com/****自分のGitHubディレクトリ名****/ncmb_ios.git`」は2.の画像にある「HTTPS▼」の所からコピーしてください

(6) 新たに作成された`.xcworkspace`ファイルをダブルクリックしてXcodeを立ち上げます

(7) __既存のプロジェクトを使用する場合のみ：__`****-Bridging-Header.h`ファイルを削除します

(8) (7)の代わりに、`AppDelegate.swift`と`ViewController.Swift`に次を追記します

```swift:AppDelegate.swift&&ViewController.Swift
import NCMB
import FBSDKLoginKit
```
(9) 動作確認をします

## 考察と解説
* 参考Qiita記事([iOS9でFacebook Single Sign On](http://qiita.com/yokomotod/items/c78136f1f15d0e424d20))を見て、別のやり方があることを知りました。同様にできるのかな？とやってみるも上手くいきませんでした。。浅はかでした。原因はSDK同士の参照関係の問題が絡んでいるようでした。
* 調べると`podspec`ファイルに`'FBSDKLoginKit'`を追記したmBaaSのSDKをインポートすることで、mBaaSのNCMB SDKだけでなくFBSDKCoreKitとFBSDKLoginKitもプロジェクトに組み込まれるようでした。逆にこれら３つのSDKの**参照関係**の問題でこの方法でないとエラーが出てしまうようでした。
* SDKを触るわのは少し抵抗がありましたが、`$ pod install`するときに読み込む`podspec`ファイルの編集だけなの、ブリッジして使う方法よりも楽？でしょうかね。
* 一応[ニフティクラウドmobile backendのドキュメント](http://mb.cloud.nifty.com/)には前者の方法で書かれていますが一応こちらでもできましたのでご紹介させていただきました！
SphinxでMarkdownを使うときに注意すること

SphinxでMarkdownを使うときにつまずいた。

## 参考にしたページ
1. http://blog.readthedocs.com/adding-markdown-support/
2. https://github.com/rtfd/recommonmark/issues/24

## 問題
私の場合、下記のような状況でした。2.を読んでみるとversionがあっていなかったので、versionを合わしてあげたら実行できるようになりました。

```py

from recommonmark.parser import CommonMarkParser
....
ImportError: cannot import name DocParser
```

## やった事
```sh
$ pip install recommonmark==0.4.0
```
Sphinxプロジェクトのconf.pyの中を編集

```py
from recommonmark.parser import CommonMarkParser

source_parsers = {'.md': CommonMarkParser}

source_suffix = ['.rst', '.md']
```
Jenkinsのユーザー作成と権限管理

#セキュリティガバガバおじさん
Jenkinsはデフォルトで匿名ユーザー（anonymous）しかいないため、きちんとセキュリティ設定をしないと**「誰でも入れて何でも操作できちゃうセキュリティガバガバおじさん状態」**らしい。

あかんやろ…
ってことでユーザーの作成と権限管理の設定をしてみた。

ユーザー情報の管理方法はいくつかあるけど、今回は「Jenkinsのユーザーデータベース」を利用する場合の手順をメモしておく。

<img width="297" alt="スクリーンショット 2016-04-01 17.20.54.png" src="https://qiita-image-store.s3.amazonaws.com/0/6380/af186871-fbd3-3c8c-518e-6fd3dda5fa94.png">

# セキュリティの有効化
1. [Jenkinsの管理] - [グローバルセキュリティの設定] を開く
2. 「セキュリティを有効化」にチェックをつける
3. [アクセス制御] - [ユーザー情報] の「Jenkinsのユーザーデータベース」を選択
4. 「ユーザーにサインアップを許可」のチェックをはずして保存
5. 管理者のユーザー名、パスワードなどを入力してサインアップする

# ユーザーの作成
1. [Jenkinsの管理] - [ユーザーの管理] - [ユーザーの作成] を選択
2. 必要に応じて管理者ユーザーや一般ユーザーなどを作成する

# 権限管理
1. [Jenkinsの管理] - [グローバルセキュリティの設定] を開く
2. [権限管理] で「行列による権限設定」を選択
3. 「追加するユーザー/グループ」に、先ほど作成したユーザー名を入力して追加する
4. ユーザー毎に必要な権限を付与して保存する
<img width="1738" alt="スクリーンショット 2016-04-01 16.59.00.png" src="https://qiita-image-store.s3.amazonaws.com/0/6380/0339e1a2-7f5c-3723-e569-69acd49168fa.png">
5. 各ユーザーでログインし、設定した権限が反映されているか確認する

おわり。
Gmailで送信元アドレスを追加するためのメモ

#これはなに
Gmailで送信元アドレスを転送用アドレスに設定しようとしたら詰まったのでメモ

#やったこと
右上の歯車→設定→アカウントとインポート→メールアドレスを追加
名前とメールアドレスを入れる．エイリアスの設定はお好みで．

SMTPサーバをsmtp.gmail.comに
ユーザ名・パスワードはGoogleアカウントのものを入力
→ログインできない！！
ユーザー名とパスワードを確認するよう促すエラーが出るが，間違ったユーザー名とパスワードを入力した時とは異なったエラーが出る．

#対処法
https://support.google.com/mail/answer/14257を参考にした．
1. https://www.google.com/settings/security/lesssecureapps より安全性の低いアプリからのログインを許可する．
2. https://accounts.google.com/DisplayUnlockCaptcha よりGoogleアカウントへのアクセスを許可する．
3. 再度ログインすると無事認証される．届いたメールに書かれたURLをクリックしてアドレスを認証，送信元アドレスとして使用可能になる．
※1.と2.は逆順だと認証できなかった．注意

二段階認証を有効化している場合アプリキーを設定し，パスワード欄に入力することでログイン可能となる．

#どうしてこうなった
アクティビティを確認すると，SMTPとしてアメリカ合衆国からのアクセスが確認できた．アメリカからのアクセスとして弾かれている？←何でこの方法でいけるか分からない

#結論
二段階認証を使いましょう．

#参考
http://andmem.blogspot.jp/2014/08/gmail-issue-sender-adress.html
ミリ秒を秒に変換する際に~~を使ってはいけない(と思う)という話

JavaScriptで浮動小数点型の数字を整数型に直す方法はいくつかある．

* parseInt
* Math.floor (Math.ceil, Math.round)
* ~~

一応知らない人のために説明しておくと，最後のチルダ演算子はビットの反転を行っているのだが，その際に32ビット整数に変換されるので，2度ビット反転をすることにより浮動小数点型を整数型に変換できる．しかもMath.floorやparseIntよりも割と高速に．
そもそもparseIntはstringをnumberに変換するメソッドなので，TypeScriptではエラーを吐いたりする．
そこで~~を使いたくなるのだが，エポックミリ秒をエポック秒に変換し，整数型として扱いたい場合，例えば以下の場合にこれを用いるのは控えた方が良いと思う．

```
var epochSec = ~~(new Date().getTime() / 1000);
```

なぜなら32ビット整数に変換されるので，このコードでは2038年1月19日12:14:08(GMT+0900)以降実行するとオーバーフローを起こし負の値になる．
他にも32ビットを超える可能性がある場合にこのチルダ演算子による変換を用いるのは賢明ではないだろう．
[JavaScript]フォーカスが当たっている要素を取得してフォーカスを外す

文書内でフォーカスされている要素を取得して、その要素のフォーカスを外す。
モバイルなどでキーボードが出ている状態などを解除できる。
#フォーカスが当たっている要素を取得
```js
document.activeElement
```

#要素のフォーカスを外す
```js
Element.blur()
```

#合成
```js
document.activeElement.blur()
```

#サポート状況
<a href="https://developer.mozilla.org/ja/docs/Web/API/Document/activeElement">document.activeElement - Web API インターフェイス | MDN</a>を見てみたが、サポートされているモバイルブラウザのバージョンはわからなった。
多分、ほぼサポートされていると思う[要出典]
IntelliJ IDEA 2016 で npm script が実行できないときの対処法

[2016年3月17日に IntelliJ IDEA 2016.1 がリリースされました](https://blog.jetbrains.com/idea/2016/03/intellij-idea-2016-1-is-here/)。ちなみに 2016.1.1 もつい先日リリースされました。TypeScript を使ってる人はすぐにアップデートした方がいいと思う。

つい先日までの最新バージョンが 15 だったメジャーバージョンが一気に 2016 に。すごい。

とかいう冗談はさておき、JetBrains 教徒である筆者はさっそくアップデートしたのですが、なんともわかりにくいトラップにハマり、今日になって解決法が見つかったので、英語読めない病の皆さんのためにも共有しておきます。

※ WebStorm 2016.1 でも同じだと思いますが確認はしていません（持っていないので）。

## トラップ編: npm script が実行できない！
IntelliJ IDA には `package.json` を読んで `scripts` に定義した npm script を IDE 上で実行できる機能があります。やり方を知らない方は[公式ヘルプ](https://www.jetbrains.com/help/idea/2016.1/running-npm-scripts.html)を読むかググってください。

Ver.15 までは、何も考えずにこの機能を使って監視タスクなんかをゴキゲンに実行していたのですが、Ver.2016 になったとたんに以下のようなエラーを吐いて動かなくなってしまいました。

> Please specify npm package.

「npm のパッケージを指定しろ（設定しろ）」って事みたいですが、探せどもどこにも見当たらず。エラーメッセージを Google 先生に投げても、バージョンが新しいせいかまったく情報がありません。途方に暮れる日々が続きました。

## 解決編
本日、久々に検索したら解決方法が見つかりました。

- [WebStorm - error: Please specify npm package](http://stackoverflow.com/questions/36223947/webstorm-error-please-specify-npm-package)

WebStorm についての話みたいですが IntelliJ でもそのまま適用できました。

まずは `Run > Edit Configurations...` から `Run/Debug Configurations` を開きます。

![スクリーンショット 2016-04-01 16.27.18.png](https://qiita-image-store.s3.amazonaws.com/0/17109/7c88bc51-bc03-3435-86dc-c7a33d58290c.png)

次に `Node Interpriter` の右にある `...` をクリックすると次のダイアログが開きます。

![スクリーンショット 2016-04-01 16.35.00.png](https://qiita-image-store.s3.amazonaws.com/0/17109/d5b5635e-37a5-903a-4bfd-369a28a229d5.png)

「npm package を指定しろ」っていうのはここのことだったんですね！

![スクリーンショット 2016-04-01 16.27.34.png](https://qiita-image-store.s3.amazonaws.com/0/17109/dcce4e28-5b37-3f45-3cab-8b3fbe83c06d.png)

このように `npm` パッケージがインストールされているディレクトリを指定することで、無事 npm script が実行されるようになりました。`npm` コマンドのパスや、コマンドがインストールされているパスではないので間違えないようにしてください。

設定後、うまく動かない場合は IntelliJ/WebStorm 自体を再起動すれば OK です。

以上で IntelliJ から npm script を実行できるハッピーでゴキゲンな毎日が帰ってきます。grunt? gulp? 知らない子ですね……。
備忘メモ Swiftでtableviewの明細行にボタンを追加して他の画面に遷移する

久しぶりに実装し、結構はまったので備忘がてら残します。

## buttonをプログラムで実装して、TableViewのCellに追加

```swift
    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as UITableViewCell
        
        let button : UIButton = UIButton.init(type: UIButtonType.Custom) as UIButton
        button.frame = CGRectMake(40, 60, 100, 24)
        let cellHeight: CGFloat = 44.0
        button.center = CGPoint(x: view.bounds.width / 2.0, y: cellHeight / 2.0)
        button.backgroundColor = UIColor.redColor()
        button.addTarget(self, action: #selector(ViewController.buttonClicked(_:)), forControlEvents: UIControlEvents.TouchUpInside)
        button.tag = indexPath.row
        button.setTitle("Click Me !", forState: UIControlState.Normal)
        
        cell.addSubview(button)

        return cell
    }
```

## ボタンがクリックされた時に、他の画面に遷移する

```swift
    @IBAction func buttonClicked(sender: AnyObject) {
        print("clicked")
        
        let storyBoard : UIStoryboard = UIStoryboard(name: "Main", bundle:nil)
        
        let nextViewController = storyBoard.instantiateViewControllerWithIdentifier("NextViewController") 
        self.presentViewController(nextViewController, animated:true, completion:nil)
    }
```

Objective-CからSwiftになったからといって、この辺の書きっぷりが抜本的に変わったわけではないことを痛感しました。しょぼん。。


## 追加されるボタンイメージ

![スクリーンショット 2016-04-01 16.43.01.png](https://qiita-image-store.s3.amazonaws.com/0/49547/5282dd66-8429-bcbf-85c1-89813716f768.png)
Jenkinsのビルド結果をSlackに通知させる

Jenkinsのビルド結果をSlackに通知投げるようにしたのでやり方をメモしておく。

:::note alert
本記事の情報は2016年時点のものとなっています。2022年版の手順を書いてくださった方が居ますので、最新の通知設定はぜひ該当記事をご参考ください。
https://qiita.com/typememo/items/e85a76fd49a5a2cf7573
:::

# Slack側の設定
1. Slackメニューの [Apps & Integrations] をクリック（ブラウザでSlackが開く）
2. 「Jenkins CI」を検索して、対象チームにインストール
<img width="1295" alt="スクリーンショット 2016-03-31 16.22.35.png" src="https://qiita-image-store.s3.amazonaws.com/0/6380/67387ec1-7c17-a659-8b47-c0cc8b42c274.png">
3. 対象チャンネルを選択してAddする
<img width="1000" alt="スクリーンショット 2016-03-31 16.24.22.png" src="https://qiita-image-store.s3.amazonaws.com/0/6380/bf3bf9e6-cd28-5f42-082e-6d06d19d2cf5.png">
4. Jenkinsへのセットアップ手順が表示されるので「Team Domain」と「Integration Token」をメモしておく
<img width="974" alt="スクリーンショット 2016-03-31 16.24.58.png" src="https://qiita-image-store.s3.amazonaws.com/0/6380/ccd2dc09-9d24-7b22-7e89-f84450b6b2d8.png">

# Jenkins側の設定
1. [Jenkinsの管理] - [プラグインの管理] - [利用可能] の「Slack Notification Plugin」にチェックをつけてインストール
2. [Jenkinsの管理] - [システムの設定] - [Global Slack Notifier Settings] にて「Team Domain」と「Integration Token」を設定
3. ジョブの設定にて [ビルド後の処理の追加] - [Slack Notifications] を選択
4. チャンネル（高度な設定）や通知したいビルドの工程・結果などにチェックをつける
<img width="784" alt="スクリーンショット 2016-04-01 16.17.16.png" src="https://qiita-image-store.s3.amazonaws.com/0/6380/7c9e0855-8e65-19c9-f00d-896c84fafee9.png">

これでJenkinsの実行結果がSlackの指定チャンネルに流れるようになる。
<img width="611" alt="スクリーンショット 2016-04-01 16.16.44.png" src="https://qiita-image-store.s3.amazonaws.com/0/6380/729b376e-e2ef-1a07-a719-3f79510f025e.png">
babylonでコード変換する超基礎的なまとめ


社内勉強会資料。

最近、babylonでJavaScriptのコードを変換するツールを作っていて、まだ出来てませんが、現状調べたことのまとめです。

## ASTの基礎

[JavaScript ASTを始める最初の一歩 | Web Scratch](http://efcl.info/2016/03/06/ast-first-step/)

上記記事がよいです。ざっくりまとめると、

- AST => コードをパースした抽象構文木のこと
  - JavaScriptの場合はJavaScriptオブジェクト(JSON)として表現
- ツールの分類
  - Parser ... ソースコードをASTに変換する
  - Traverser ... ASTの木構造を探索。ノードを差し替えたり、削除したりする
  - Generator ... ASTからソースコードを生成する
- Parserは大きく2系統（Esprima, Acorn）
  - babylonはAcornベースで、JSXなど[ESTree](https://github.com/estree/estree)から拡張してる
- ParserによってASTのフォーマットが若干（ではないかも）異なるので、Generatorは同じ系統のものを使う
  - Esprima -> escodegen, babylon -> babel-generatorみたいな感じ

>  Esprimaで試して、何か足りないならAcorn -> Babylonという感じでやるのが良いと思います。

上記記事に気付かず始めてしまったのでbabel系のツールを使っていますが、EsprimaかAcornの方が安定している＆ドキュメントが充実しているようです。

### babel系のツール群

- babylon
  - Parser
  - https://github.com/babel/babylon
  - Acornベース、JSXやFlowtype、stageN系のやつもパースできる
- babel-generator
  - Generator
  - https://github.com/babel/babel/tree/master/packages/babel-generator
- babel-traverse
  - Traverser
  - https://github.com/babel/babel/tree/master/packages/babel-traverse
  - ドキュメントがないので泣きながらテストコードやソースコードを読んだが、[ast-types](https://github.com/benjamn/ast-types)と同じインタフェースな気がする。。
- babel-types
  - ASTのNodeの生成など

## コードの変換

### ASTを使ったソースコード変換の流れ

JSer.infoの記事にも書いておりますが、下記のような流れです。

1. JavaScriptのソースコードをASTに変換する（Parser）
2. ASTを探索して、任意のノードを入れ替えたり、削除したりする（Travarser）
3. 2で出来たASTからJavaScriptのソースコードを生成する（Generator）

babel-parserでソースコードをASTに変換して、babel-traveseでASTを探索して、babel-typesで作ったASTと入れ替えたりしつつ、出来上がったASTをbabel-generatorでソースコードに変換するという感じです。


### 小さなサンプル

パッケージをインストールします。

```sh
$ npm install -S babylon babel-traverse babel-generator babel-types
```

`hoge`を`fuga`に変換するコードを書いてみました。（babelで書いてしまったので、その辺りのパッケージも入れてください）

```js
// hoge.js
import {parse} from 'babylon';
import generate from 'babel-generator';
import traverse from 'babel-traverse';
import * as t from 'babel-types';

// hogeをfugaに変更する関数
const replaceHogeToFuga = code => {
  // 1. JavaScriptのソースコードをASTに変換する
  const ast = parse(code);

  // 2. ASTを探索して、任意のノードを入れ替えたり、削除したりする
  traverse(ast, {
    // ノードがIdentifierの場合に呼び出される
    // pathはNodePathのインスタンス、ast-typesと似た感じのインタフェース
    Identifier: path => {
      if (path.node.name === 'hoge') {
        // ast-typesと同じかと思われたが, replaceはreplaceWithだった
        path.replaceWith(t.identifier('fuga'));
      }
    }
  });

  // 3. 2で出来たASTからJavaScriptのソースコードを生成する
  const output = generate(ast, {}, code);
  return output.code;
};

console.log(replaceHogeToFuga("hoge('Hello');"));
```

babel-nodeで実行してみます。

```sh
$ babel-node hoge.js
fuga('Hello');
```

いえーい

## おわり

- babel-traverseのドキュメントがなく、調べるのに時間がかかってしまい、本当に基礎の基礎の話になってしまった。
- そもそもbabylonを選んでしまったのが間違いだったかもしれない。
- 次はもうちょっと濃いノウハウを
Homeボタンを押したときの挙動をプログラムで再現する


サーバーメンテナンス時にアプリを動かしてもらいたくない(?)という要望があり、ダイアログを出してアプリを終了したい。アプリをキルするよりもHomeボタンを押下時の挙動の方がアプリに優しいと思って調べた。

#サンプルコード

``` java

	public void alertServerMaintenance(String message) {
        new AlertDialog.Builder(this)
                .setMessage(message)
                .setPositiveButton("OK", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        onClickHomeBehavior();
                    }
                })
                .setCancelable(false)
                .show();
    }
    
    public void onClickHomeBehavior() {
        Intent intent = new Intent(Intent.ACTION_MAIN);
        intent.addCategory(Intent.CATEGORY_HOME);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        startActivity(intent);
    }

```
Microsoft が無償提供してくれたもの

#Web Design
-Expression Design(無償化→開発終了)
-Expression Web(無償化→開発終了)
#Server/Client OS
-SQL Server Express
-Upgrade to Windows10(1年間という時限あり)
#Virtualization
-Virtual PC(買収→無償提供)
-Virtual Server
-Hyper-V Server
#Developer Tools
-Visual Studio Express/Community
-Visual Studio Online(有料プランあり)(名前変わった気がする)
-Xamarin(買収→無償提供)
#Business Inteligence
-Power BI Desktop
#Other
-[OneNote](https://www.onenote.com/)
-[OneDrive](https://onedrive.live.com/about/ja-jp/)(有料プランあり)

やったね！
Macのdockアイコンが跳ねるアニメーションを停止する（スカイプなどの通知など）

# ターミナルから設定できる

## オフにする
```
defaults write com.apple.dock no-bouncing -bool true
```

## 元に戻す
```
defaults delete com.apple.dock no-bouncing
```

# 参考
[MacのLINEに新着メッセージが来た時にDockでアイコンが跳ねるのがウザいからオフにした](http://www.danshihack.com/2014/03/23/junp/mac-dock-no-bouncing.html)
CSS 3Dを使ってアニメーションさせたときの不可解な挙動


CSS Animationのtransform 3dを使ってkeyframe animationを記述し、それをclassの付け外しによって発火できるようなcssを書いた。
すると、特定の端末で、アニメーション途中の奇跡が画面上に残るような不思議な挙動を起こすときがあった。

解決作としては、css animationが付与されていない側のclassでも、transform 3dの値を何かしら当てる方法をとって解決した。
(具体的には、transform: translateZ(0px);を書いた)
note

hidden_field_tag 可以操纵paramter

flash message不能和ajax一起用 当然做些hack也可以

http://stackoverflow.com/questions/7465259/how-can-i-reload-the-current-page-in-ruby-on-rails

```ruby
respond_to do |format|
   format.js { render 'button.js.erb' }
end
```

```rb
respond_to do |format|
   format.js { flash.now[:warning] = "只有状态为已生成才可以操作撤销" }
end
```
update文とかdelete文かくときうっかりwhere句かきわすれて全件更新しないための超絶テクニック

最初にwhere句かいちゃう

```sql
update hoge where id = 5;
```

そしてset句をかく

```sql
update hoge set name = "ponpoko" where id = 5;
```

これであんしんですね！！！！！！

うそです
いえ、うそではありませんが

```sql
begin;
```

トランザクションはりましょう
OSXやCentOSなどのCLI環境でのproxyとの闘いの記録（めも）

# OSXやCentOSなどのCLI環境でのproxyとの闘いの記録（めも）
認証proxyありな環境で、OSXのTerminalやVirtualBox上のCentOSなどCLI環境からインターネット接続しようとしてホストOSの自動プロキシ設定が効いてくれずにはまった時の対応メモです。今後増えるかもしれません。

## 環境
+ OSX Yosemite Terminal
+ CentOS CLI

### 1) Terminal操作
+ 設定

```
export http_proxy=http://ID:PWD@PROXY_IPADDRESS:PROXY_PORTNO
export https_proxy=http://ID:PWD@PROXY_IPADDRESS:PROXY_PORTNO
export ftp_proxy=http://ID:PWD@PROXY_IPADDRESS:PROXY_PORTNO
```

+ 毎回設定が面倒な時は`~/.bash_profile` や `~/.bash_profile`に上記を記載

+ 解除

```
unset http_proxy
unset https_proxy
unset ftp_proxy
```

### 2) 各種コマンド単位でのPROXY設定方法
#### 2−1)curl

```
curl -U ID:PWD -x PROXY_IPADDRESS:PROXY_PORTNO -s http://xxxx
```

#### 2−2)wget

```
wget -e HTTP_PROXY=http://ID:PWD@PROXY_IPADDRESS:PROXY_PORTNO https://xxxx
```

#### 2−3)rpm
```
rpm --httpproxy ID:PWD@PROXY_IPADDRESS --httpport PROXY_PORTNO http://xxxx
```

#### 2−4)Ruby

```
bundle exec ruby br_test.rb --http_proxy=http://ID:PWD@PROXY_IPADDRESS:PROXY_PORTNO
```

#### 2−5)gem

```
gem install パッケージ名 -r -p http://ID:PWD@PROXY_IPADDRESS:PROXY_PORTNO
```

#### 2-6)pip

```
pip install パッケージ名 --proxy=http://ID:PWD@PROXY_IPADDRESS:PROXY_PORTNO
```


### 3) 設定ファイルや設定
#### 3-1)yum
`/etc/yum.conf`に以下を追記

```
proxy=http://ID:PWD@PROXY_IPADDRESS:PROXY_PORTNO
https_proxy=http://ID:PWD@PROXY_IPADDRESS:PROXY_PORTNO
```

#### 3-2)git

+ 設定

```
git config --global http.proxy http://ID:PWD@PROXY_IPADDRESS:PROXY_PORTNO
```

+ 解除

```
git config --global --unset http.proxy
```
【Windows】作業がはかどる(かもしれない)Tips

# 1. はじめに
会社のシステムが昔からWindowsサーバだとか、
家ではMac使いだけど職場は頑なにWindowsだとか、
そんな「やむなく」Windowsでの作業を強いられてもなお
はかどりたいみなさまにお送りするエントリです。  
同僚に「ストックされるんじゃね?w」と言われて試しに投稿してみるものでもあります。
※全く大したことは書いていない。

# 2. 実行環境
+ Windows 7 32bit
+ Windows Server 2008 R2 32bit
+ Windows Server 2012 R2 Standard 64bit

など。

# 3. いろいろ
(1) リモートデスクトップをコマンドプロンプトから呼ぶ

```
Windowsキー + Rして、「mstsc」と入力しEnter。
```

(2) タスクマネージャをキーボードショートカットで呼ぶ

```
Ctrl + Shift + Esc。
※Ctrl + ShiftはJPキーボードでもENキーボードでも、親指１本で押すとよいと思う。
```

(3) タスクマネージャをコマンドプロンプトから呼ぶ

```
Windowsキー + Rして、「taskmgr」と入力しEnter。
```

(4) Windows Firewallのデフォルト設定ではパブリックカテゴリのネットワークにRDPが通らないから手っ取り早く通るようにする(PowerShell限定)

Power Shellを管理者権限で起動して以下

```ps1:ネットワークカテゴリをPrivateにする
Set-NetConnectionProfile -NetworkCategory private
```

また、細かすぎて伝わらなそうなチンケな芸当が思いついたら書き足します。

# 4. あとがき
マシン室作業でディスプレイはラック前面、キーボードとマウスはラック背面という
状況でディスプレイなしでも設定作業が進められるように鍛えられると、
スキルレベルとは関係ないこういうチンケな芸当を覚えていくと思います。
PHPでDateTimeを使って年度を取得

会計年度を取得する関数を作ってみた。

# 参考

> 年と月から年度を取得する
> http://qiita.com/kidatti/items/e9ecfb76924d432994c0

> [#php]年度を取得する関数
> http://qiita.com/sshojiro/items/23aa3abc821c2b8c1de4

# コード

@smzk さんに指摘をもらって閏年の判定がうまく行かない件を直しました。Thanks!

```php
<?php
main();

/**
 * (会計)年度を取得する
 * ex.)
 * 2016-04-01 => 2016
 * 2016-12-31 => 2016
 * 2017-01-01 => 2016
 * 2017-03-31 => 2016
 * 2017-04-01 => 2017
 *
 * @param DateTime $theDate 判定したい日時
 * @param string $startDay 年度開始日(変更する場合に指定)
 *
 * @return int 年度
 */
function getFiscalYear(DateTime $theDate, $startDay='04-01') {
	/**
	 * 年度開始日との差分を取得
	 * ex.) 2016年04月01日 -(引く) 2016年04月01日(年度開始日) = 差分0日 (invert = 0
	 * ex.) 2016年01月01日 -(引く) 2016年04月01日(年度開始日) = マイナス3ヶ月 (invert = 1
	 */
	$diff = (new DateTime($theDate->format('Y') . '-' . $startDay))->diff($theDate);
	if ( $diff->invert ) { // 引き算の結果がマイナスだった場合には早生まれ状態
		return intval($theDate->format('Y')) - 1;
	} else { // そのまま
		return intval($theDate->format('Y'));
	}
}

function main() {
	$date = new DateTime('2016-05-02');
	$fiscalYear = getFiscalYear($date);
	var_dump($date->format('Y-m-d'), $fiscalYear); // 2016

	$date = new DateTime('2016-04-01');
	$fiscalYear = getFiscalYear($date);
	var_dump($date->format('Y-m-d'), $fiscalYear); // 2016

	$date = new DateTime('2016-03-31');
	$fiscalYear = getFiscalYear($date);
	var_dump($date->format('Y-m-d'), $fiscalYear); // 2015

	$date = new DateTime('2016-01-01');
	$fiscalYear = getFiscalYear($date);
	var_dump($date->format('Y-m-d'), $fiscalYear); // 2015

	$date = new DateTime('2016-08-01');
	$fiscalYear = getFiscalYear($date, '09-01'); // 年度開始日指定
	var_dump($date->format('Y-m-d'), $fiscalYear); // 2015

	$date = new DateTime('2016-09-01');
	$fiscalYear = getFiscalYear($date, '09-01'); // 年度開始日指定
	var_dump($date->format('Y-m-d'), $fiscalYear); // 2016

	$date = new DateTime('2016-02-28');
	$fiscalYear = getFiscalYear($date, '03-01'); // 年度開始日指定
	var_dump($date->format('Y-m-d'), $fiscalYear); // 2015

	$date = new DateTime('2016-02-29');
	$fiscalYear = getFiscalYear($date, '03-01'); // 年度開始日指定
	var_dump($date->format('Y-m-d'), $fiscalYear); // 2015

	$date = new DateTime('2016-03-01');
	$fiscalYear = getFiscalYear($date, '03-01'); // 年度開始日指定
	var_dump($date->format('Y-m-d'), $fiscalYear); // 2016

	$date = new DateTime('2017-02-28');
	$fiscalYear = getFiscalYear($date, '03-01'); // 年度開始日指定
	var_dump($date->format('Y-m-d'), $fiscalYear); // 2016

	$date = new DateTime('2017-02-29'); // DateTimeの仕様で03-01扱い
	$fiscalYear = getFiscalYear($date, '03-01'); // 年度開始日指定
	var_dump($date->format('Y-m-d'), $fiscalYear); // 2017
}
```
SharedPreferencesの使い方(基礎編)


## 基本情報
SharedPreferencesはデバイス内にデータを保存するための仕組みです。
保存されたデータはActivityが終了しても保持されるので、基本的にはアプリの設定を保存するために用いられます。

保存できるデータは以下の5つです。

* String型
* boolean型
* int型
* long型
* float型

## インスタンスの取得方法
インスタンスの取得方法には以下の3つのメソッドがあります。

* Context#getPreferences(int)
* Context#getSharedPreferences(String, int)
* PreferenceManager#getDefaultSharedPreferences(Context)

ではそれぞれの使い方について見ていきましょう
### Context#getPreferences(int)

```java:GetPreferences.java
SharedPreferences prefs = getPreferences(Context.MODE_PRIVATE);
```
引数でモードを渡します。
他にMODE_WORLD_READABLE / MODE_WORLD_WRITEABLE / MODE_MULTI_PROCESSがありますが、モードについては後述します。

### Context#getSharedPreferences(String, int)

```java:GetSharedPreferences.java
SharedPreferences prefs = getSharedPreferences("SaveData", Context.MODE_PRIVATE);
```
引数で保存データの名前とモードを渡します。

### PreferenceManager#getDefaultSharedPreferences(Context)

```java:GetDefaultSharedPreferences.java
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
```
\*getDefaultSharedPreferencesで作成したSharedPreferencesのモードはデフォルトでMODE_PRIVATEです。

## データの書き込み
```java:put.java
SharedPreferences.Editor editor = prefs.edit();
editor.putString("string", "value");
editor.putBoolean("boolean", false);
editor.putInt("int", 0);
editor.putLong("long", 0);
editor.putFloat("float", 0.0);
editor.apply();
```
それぞれのデータ形式に対応するputメソッドの引数にKey=Vakue形式でデータを書き込み、最後にapply(保存)をします。

## データの読み込み
```java:get.java
String str = prefs.getString("string");
boolean bool = prefs.getBoolean("boolean");
int intNum = prefs.getInt("int");
long longNum = prefs.getLong("long");
float floatNum = prefs.getFloat("float");
```
それぞれのデータ形式に対応するgetメソッドの引数に保存した際のKeyを渡し取得します。

## 保存したデータ
### ファイルパス
`/data/data/[パッケージ名]/shared_prefs/`
### ファイル名
getPreferences(int)で作成した場合
[Activityのクラス名].xml

getSharedPreferences("SaveData", int)で作成した場合
`SaveData.xml`

getDefaultSharedPreferences(Context)で作成した場合
`[パッケージ名]_preferences.xml`
### 形式
XML形式で保存されます。

```xml:[パッケージ名]_preferences.xml
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
	<string name="string">value</string>
	<boolean name="boolean" value="false" />
	<int name="int" value="0" />
	<long name="long" value="0" />
	<float name="float" value="0.0" />
</map>
```

## 保存したデータのモードについて

|モード名|効果|備考|
|:--|:--|:--|
|[MODE_PRIVATE](http://developer.android.com/intl/ja/reference/android/content/Context.html#MODE_PRIVATE "MODE_PRIVATE")|自アプリのみ読み書き可能||
|[MODE_WORLD_READABLE](http://developer.android.com/intl/ja/reference/android/content/Context.html#MODE_WORLD_READABLE "MODE_WORLD_READABLE")|他アプリから読み取り可能|API Level17で非推奨|
|[MODE_WORLD_WRITEABLE](http://developer.android.com/intl/ja/reference/android/content/Context.html#MODE_WORLD_WRITEABLE "MODE_WORLD_WRITEABLE")|他アプリから書き込み可能|API Level17で非推奨|
|[MODE_MULTI_PROCESS](http://developer.android.com/intl/ja/reference/android/content/Context.html#MODE_MULTI_PROCESS "MODE_MULTI_PROCESS")|複数のプロセスで読み書き可能|API Level23で非推奨|
Mac x Unity で 360度動画作成（VR Panorama 360 PRO Renderer 編）


#はじめに
Mac 環境で Unity を使って VR 動画を作成しようとしたところ、所々、問題が起きたのでメモしておく。

#アセットについて
360度動画としてキャプチャできるアセットを探したところ、
基本は Windows Only のものが大半で、Mac だと下記のアセットくらいしかない模様。
なので今回はこれを使用した。

[VR Panorama 360 PRO Renderer](https://www.assetstore.unity3d.com/jp/#!/content/35102)
有償：40$
環境：Unity 5.0.1 以上

設定できるパラメータは[こちら](http://qiita.com/dockurage/items/99d86f3322eb2346e2b3)にまとめておく

#問題発生
import を済ませ、いざキャプチャを取ろうとしたところ問題が発生。
どうも Mac 環境では動画変換部分がうんともすんともいわない。

#修正範囲
下記 Windows のみの対応になっているので Mac 用の対応を入れる必要がある。

```csharp
// デフォはこんな記述になっている
string ffmpegPath = Path.GetFullPath (string.Format (@"{0}/", "Assets\\VRPanorama\\External\\"));

// Mac で動作するパスの設定はこんな感じ
string ffmpegPath = Path.GetFullPath (string.Format (@"{0}/", "Assets/VRPanorama/External/"));
```

あと ffmpeg が権限の問題で実行ができない問題も発生したので権限も調整する。

```csharp
chmod ffmpeg 755
```

#キャプチャ手順
###書き出す動画の種類を設定
**「Capture Type」** で動画の種別を設定する。
VRヘッドマウント用の場合 **「Equidistant Stereo」**
360度動画の場合 **「Equidistant Mono」**

※ Youtube にアップロードする場合は 「Equidistant Mono」 で書き出しておけば、
360度動画 と VR どちらにも対応してくれる。

###キャプチャ作成する
下記のボタンで音声と画像をキャプチャする。
**「Capture Audio」** で wav を作成 （音声はテスト版らしいんで不具合あるかも...）
**「Render Panorama」** で 静止画の連番を作成

###キャプチャから動画を作成する
両方揃ったら下記のボタンで動画を作成する。
**「Encode H.264 Video From Existing sequence」** で mp4 を作成

そのほか設定できるパラメータは[こちら](http://qiita.com/dockurage/items/99d86f3322eb2346e2b3)にまとめておく

#Youtube へアップロード
作成した MP4 をそのままアップロードしても 360度動画として動作してくれない。
これ関しては Youtube のドキュメントを読み MP4 にメタデータを仕込む必要がある。
下記にメタデータの登録する方法が記載している。

[Youtube 360 度動画のアップロード](https://support.google.com/youtube/answer/6178631?hl=ja&ref_topic=2888648)

アップロード後、すぐに確認にいっても 360度動画として再生されない。
最大１時間ほどかかるらしいが、この時は 5分くらい待ったら 360度動画としてみれるようになった。

![capture1.png](https://qiita-image-store.s3.amazonaws.com/0/56504/29d03a9d-9d96-c3f9-9d16-7fb428d57183.png)
Apache Solr Cloudを構築してみる part.1

# SolrCloudとは

公式 wiki
https://wiki.apache.org/solr/SolrCloud

apacheさんが作っているので安心 ?

# 構成

全部で3部構成にする予定

+ Part.1
    + CentOS上にzookeeperを構築する [今回]

+ Port.2
    + CentOS上にSolrを構築する [次回]

+ Port.3
    + CentOS上にSolrCloudを構築する [次々回]


# Part.1 Zookeeperを構築する

### 環境

+ arch

```
# cat /etc/redhat-release 
CentOS release 6.7 (Final)
# arch
x86_64
```

### インストール

+ Oracle Javeのインストール

```
# cd /var/tmp/
# wget --no-check-certificate --no-cookies - --header "Cookie: oraclelicense=accept-securebackup-cookie" http://download.oracle.com/otn-pub/java/jdk/8u45-b14/jdk-8u45-linux-x64.rpm
# rpm -Uhv jdk-8u45-linux-x64.rpm
```

+ Zookeeperのインストール

```text:cmd
# cd /var/tmp
# wget http://ftp.meisei-u.ac.jp/mirror/apache/dist/zookeeper/zookeeper-3.4.8/zookeeper-3.4.8.tar.gz
# tar zxvf ${ZKR}.tar.gz
# cp -ar zookeeper-3.4.8 /opt/
# ln -s /opt/zookeeper-3.4.8 /opt/zookeeper    ### 後ほど、VersionUPする際に移設を簡単にするためにシンボリックリンクで紐付ける
# cd /opt/zookeeper
# cp -a ./conf/zoo{_sample,}.cfg
```

### 単体起動 && ステータスチェック

これで基本的なインストールは終わり。
    
```text:cmd
# cd /opt/zookeeper
# ./bin/zkServer.sh status
ZooKeeper JMX enabled by default
Using config: /opt/zookeeper/bin/../conf/zoo.cfg
Mode: standalone
```



### 複数台起動する(レプリケーション)

zookeeperの仕様により、奇数台が望ましいらしい(じゃんけん? 多数決?)
    
+ まずはZookeeperを複数台用意し、単体起動するところまでやる。
    + svr01 : 192.168.33.71
    + svr02 : 192.168.33.72
    + svr03 : 192.168.33.73


+ 各サーバーごとにIDを決める
    + このIDは数字しか使えないので注意(これで約半日詰まった)
    
```text:srv01
### svr01にて
# mkdir -p   /tmp/zookeeper
# echo '1' > /tmp/zookeeoer/myid
```

```text:srv02
### svr02にて
# mkdir -p   /tmp/zookeeper
# echo '2' > /tmp/zookeeoer/myid
```

```text:srv03
### svr03にて
# mkdir -p   /tmp/zookeeper
# echo '3' > /tmp/zookeeoer/myid
```

+ 上記のパスは「dataDir」として、/opt/zookeeper/conf/zoo.cfgのL.12行目に書いてある

```text:/opt/zookeeper/conf/zoo.cfg
 11 # example sakes.
 12 dataDir=/tmp/zookeeper
 13 # the port at which the clients will connect
```

+ さらにzoo.confに上記のサーバーリストを記述する。

```text:/opt/zookeeper/conf/zoo.cfg
#autopurge.purgeInterval=1
...
...
server.1=192.168.33.71:2888:3888
server.2=192.168.33.72:2888:3888
server.3=192.168.33.73:2888:3888
```

+ zookeeperの再起動

```text:cmd
# pwd
/opt/zookeeper
# ./bin/zkServer.sh restart
ZooKeeper JMX enabled by default
Using config: /opt/zookeeper/bin/../conf/zoo.cfg
ZooKeeper JMX enabled by default
Using config: /opt/zookeeper/bin/../conf/zoo.cfg
Stopping zookeeper ... STOPPED
ZooKeeper JMX enabled by default
Using config: /opt/zookeeper/bin/../conf/zoo.cfg
Starting zookeeper ... STARTED
```

+ チェック

```text:svr01
# ./bin/zkServer.sh  status
ZooKeeper JMX enabled by default
Using config: /opt/zookeeper/bin/../conf/zoo.cfg
Mode: leader
```

```text:svr02
# ./bin/zkServer.sh  status
ZooKeeper JMX enabled by default
Using config: /opt/zookeeper/bin/../conf/zoo.cfg
Mode: follower
```

# 検証

+ svr01で書き込んだ情報をsvr02,svr03で読み取れるか

```text:svr01

```

+ ノードを増減させるとどうなるか