OmniAICreator/Qiita-1.07M huggingface dataset:
[Swift] ARCについて [和訳]

# はじめに
ドキュメントを自分なりに和訳し簡単にまとめました. 間違いがあれば指摘をお願いします

# ARC(Automatic Reference Counting)とは
Swiftではメモリの追跡、管理にARCが用いられている. ARCはいらなくなったインスタンスのメモリの割り当てを自動的に解除する. ガベージコレクトの一種.

### ARCの働き
ARCはインスタンスのメンバを追跡しており, 参照が残っているかどうかを見ている. 
変数のweak, strongはここに関連してくる. 強い参照が残っている限り, インスタンスのメモリ割り当ては解除されない(アクティブな参照が存在するということ)

# ARCの動作
ARCの動きを見るために以下のようなPersonクラスを定義します.

```swift
class Person {

    let name: String
    
    init(name: String) {
        self.name = name
        print("\(name) is being initialized")
    }
    
    deinit {
        print("\(name) is being deinitialized")
    }

}
```

Pesonクラスはnameというメンバを持っており、インスタンスが生成されると

``` hoge is being initialized ```

と出力されます. (ここではname = hoge)
また、インスタンスのメモリの割り当てが解除されるとdeinitが呼ばれ、

``` hoge is being deinitalized ```

と出力されます.

インスタンスの動きを見ていきましょう

```swift
var reference1: Person?
var reference2: Person?
var reference3: Person?
```
と宣言し

```swift
reference1 = Person(name: "kyrie")
```
インスタンスを生成, 代入すると、
```kyrie is being initialized```
と出力されました. この時kyrieへの強い参照の数は1となります.

また,

```swift
reference2 = reference1
reference3 = reference1
```
とするとkyrieへの強い参照の数は3となりました.

ここで、参照を減らして見るとどうなるでしょう

```swift
reference1 = nil
reference2 = nil
```
参照を2つ減らしました. ここまではなにも出力されません. 強い参照が1つ残っているためです.

```swift
reference3 = nil
```
3つ目の参照を解いて見ました. すると

```kyrie is being deinitialized```

と出力されました. インスタンスのメモリの割り当てが解除されたということです.


次回は循環参照についてまとめてみたいとおもいます.
ありがとうございました.

## 参考

[The Swift Programming Language (Swift 4.0.3)](https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/AutomaticReferenceCounting.html)
PHP 7.1 on jupyter notebook

## jupyter-notebook はpython だけのものじゃない！  
ということで、PHP7.1 が jupyter-notebook 上で動く、Docker Image を作成しました。  
ベースイメージは、 Ubuntu:16.04 を使っていて、 python のバージョンは 3.6.3 です。
[docker hub](https://hub.docker.com/r/gorogoroyasu/jupyter-php-docker/)

```
docker run -it --rm -p 8080:80 gorogoroyasu/jupyter-php-docker /bin/bash
```
でdocker を起動した後、  
任意のディレクトリで  

```
jupyter-notebook --port 80 --ip 0.0.0.0 --allos-root &
```
をすると、 localhost:8080 で PHP7.1 が動く jupyter-notebook が起動します。  

## jupyter notebook とは？  
[参考サイト](https://pythondatascience.plavox.info/python%E3%81%AE%E9%96%8B%E7%99%BA%E7%92%B0%E5%A2%83/jupyter-notebook%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6%E3%81%BF%E3%82%88%E3%81%86)
リンクを見るのが早いと思います。  

## 使ってみたらどんな感じ？  
実際の画面はこんな感じ。  
![Home.png](https://qiita-image-store.s3.amazonaws.com/0/115634/533f55b8-47ea-1dd5-9947-5a686cce269a.png)

使用する機会は、どんな動きをするのかふとわからなくなって試してみるとき ぐらいかなと思います。
めちゃくちゃ便利か？ と言われると微妙かもｗ  

![php_on_jupyter](https://qiita-image-store.s3.amazonaws.com/0/115634/207d1a01-a0be-a27c-d26b-e337d2c48b0f.png)  




## 参考にしたサイトなど  
`jupyter-php-installer.phar` というやつを使えばいいことを知った。
http://bitwave.showcase-tv.com/%E3%80%8Ejupyter%E3%80%8F%E3%82%92%E4%BB%96%E8%A8%80%E8%AA%9E%E6%B4%BB%E7%94%A8%E3%81%97%E3%81%A6%E3%81%BF%E3%82%8B/
何を入れればいいかがわかりやすくまとまってた。
http://theartofzero.php.xdomain.jp/jupyter%E3%81%A7php%E3%82%92%E4%BD%BF%E3%81%88%E3%82%8B%E3%82%88%E3%81%86%E3%81%AB%E3%81%99%E3%82%8B-in-windows-10-1461/
【FE】DBのトランザクション処理

基本情報処理技術者試験の勉強メモです．
自分が後から見返してわかればおｋのスタンスで書いてますので悪しからず．

#トランザクションとは
データベースに対するひとまとまりの処理．1つあるいは複数のSQL文から構成される．
SQLがすべて実行されてトランザクションが完了することを**コミット**という．
#ACID特性
データベースには４つの特性があり、それぞれの頭文字をとってACID特性と呼ばれている。簡単にまとめたものが下表。

|性質|内容|
|:-----------------:|:------------------|
|原子性　(Atomicity)|トランザクションは分割不可|
|一貫性　(Consistency)|データベースのルールを守る|
|独立性　(Isoration)|トランザクション同士が影響を与えない|
|耐久性　(Durability)|トランザクションの結果は失われない|
以下、詳細に解説する。
##Atomicity 原子性
1つのトランザクションはそれ以上細かく分割できない性質．複数のSQLで構成されていても，それらを分割して実行することはできない．

（例）
口座Aから口座Bに1万円送金する場合
１，Aからマイナス1万円する
２，Bにプラス1万円する
の二つの処理が必要．片方だけを実行しただけだとA,Bに整合性がとれない．
##Consistency 一貫性
トランザクション開始～終了までで，整合性が取れることを保証する性質．データベースが定めたルール（非負制約など）一貫して守らなければいけないということ．

（例）
残高が1万円の口座から2万円引き出そうとすると残高が負になるため，一貫性が取れずトランザクションは中断される．
##Isolation 独立性
それぞれの処理・トランザクションは独立していて他の処理に影響を及ぼさない性質．送金の例でいえば，Aからマイナスする処理とBにプラスする処理は互いに影響を及ぼさない独立した処理であることがわかる．
また，送金途中の結果は外部から読み込めない．（Bにプラスされる直前のAが減っただけの状態は外部から見れない．完了してから初めて見える．）
##Durability 耐久性（永続性）
一度完了したトランザクションは，結果が永続的に保持される性質．

#トランザクション処理が途中で中断された場合
バグやトラブルが発生した場合、トランザクションが中断されることがある。その際に、中断されたトランザクションを正常にコミットするための仕組みが存在する。
##ロールバック
途中でトランザクションが中断されたときに，トランザクション開始前まで状態を戻すこと．
##ロールフォワード
ロールバックされた処理を再実行する．ユーザからのこれといった操作は必要なく、DBMSが自動でやってくれるらしい。

ロールバック時（＝トランザクション開始前）とロールフォワード完了時（＝コミット完了時）の状態は**ログファイル（またはジャーナルファイル）**に記録される．
#排他制御
複数のトランザクションを同時に実行してしまうと不具合が起こる．これを**ロストアップデート**という．

（例）
処理A：口座Xに1万円振り込む
処理B：口座Xに2万円振り込む
を同時に行うと...

１，Aが残高を照会（残高0円），Bも残高を照会（残高0円）
２，Aが1万円をプラスする（残高1万円）
３，Bは2万円をプラス（残高2万円）
４，Aが変更を更新（残高1万円）
５，Bが変更を更新（残高2万円）*←これが最終の残高！*

となり，本来3万円になるはずの残高が2万円になってしまう．

このロストアップデートを防ぐために**排他制御**を行う．具体的には，データに**ロック**をかける．ロックには専有ロックと共有ロックがある。
##専有ロック
他のトランザクションからの一切の操作を受け付けない。もうガチガチにロックする。
##共有ロック
読み出し以外の操作を受け付けない．（登録・更新・削除は不可能）共有ロック中のデータベースに、別のトランザクションからの共有ロックは受け付けることができる。
##デッドロック
二つ以上のトランザクションが互いにロックをかけてしまい，身動きが取れなくなる状態．

（例）
データa：Aさんの所有するデータ
データb：Bさんの所有するデータ

があるとする。

1：Aさんはデータaに専有ロックをかける
2：Bさんはデータbに専有ロックをかける
3：Aさんがデータbにアクセスしようとする　→　Bさんがロックしているため、アクセス不可
4：Bさんがデータaにアクセスしようとする　→　Aさんがロックしているため、アクセス不可
お互いにアクセス不可状態になってしまい、身動きが取れない！
Macにnodejsインストール(homebrewとnを使った)

# 概要

MacにNode.jsをインストールするメモ :notebook_with_decorative_cover: 
Node.jsはアップデートが早いのでバージョン管理ツールを導入すべき。ここではなんか名前がかっこいいので「n」ってやつ使います。

# 目指す環境

* Mac
* Node.js (安定版)
* n　(Node.jsのバージョン管理)

# はい、インストールはじめるよ

*Homebrew*
MacOS上でソフトの管理を一元化するパッケージ管理システム。既にインストール済ならいらないよ。

```
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
```

*n*
Node.jsのバージョン管理ツール。nodebrewとかそのへんと似たやつ。なんか名前かっこいい。

```
brew install n
```

*Node.js*
サーバーサイドで動くJavaScript。すごいね。Reactとかフロント界隈の開発するときの環境構築でめっちゃ使うよね〜。

```
sudo n stable #安定版を使う場合のコマンド
```
※ n のコマンドは他にも色々あって、シンプルで便利そうなので公式みてみてね。

# おわり

おわりだよ :sushi:
jQuery Ajaxでファイルを含む複数のデータを送信する

# jQuery Ajaxでhtmlの\<input\>タグで入力したファイルを送信する方法はいろいろ

- \<form\> タグの〜機能を使う
- 新しく定義したDataFormオブジェクトにappend()でファイルをセットし、.ajax()で送信


# 複数のデータを渡したい時
ファイルやその他文字列を含む複数のデータを渡したい時は、後者

例）ユーザが入力したテキストファイルと一緒に識別子を送って処理分岐したい

```html:test.html
<form id="txt_form">
  <input type="file" name="fl" id="txt_file">
</form>
```

```js:test.js
$('#txt_file').on('change', '', function(){
    var formdata = new FormData($('#txt_form').get()[0]);
    formdata.append("hoge","fuga");
    $.ajax({
        url  : "test.php",
        type : "POST",
        data : formdata,
        processData : false,
        contentType : false
    }).done(function(data) {
       alert('SUCCESS!');
     }).fail(function(data) {
       alert('ERROR!');
     });
  })
```

例えばPHPで受け取る時はこう

```PHP:test.php
<?
if ($_SERVER['REQUEST_METHOD'] === 'POST') {

  //ファイル系は$_FILES[（<input>タグのname属性の値）]に格納される
  //$_FILES[（<input>タグのname属性の値）]["tmp_name"]で一時格納場所のパスが取得できるので、
  //move_uploaded_file()を使ってmvして処理する
  move_uploaded_file($_FILES["fl"]["tmp_name"], "（任意のパス）");

  //その他の値は$_POST[（キー値）]で取得可能
  if($_POST['hoge'] === "fuga"){
   ...
  }else{
   ...
  }
}
```

# 注意
html側で\<input\>タグにname属性を付け忘れると正しく格納されない。

```
var formdata = new FormData($('#txt_form').get()[0]);
```
この記述によって、idが'txt_form'であるフォームの子要素のうち、name属性の値をキー値となり、入力された内容がバリュー値となってFormDataオブジェクトに格納される。
SoftEther VPN Serverをsystemd対応にする

何番煎じか分かりませんが、自分用の備忘録として残しておきます。。。

# SoftEther VPNとは

筑波大学 SoftEther VPN プロジェクトで開発されたフリーウェア。
独自のSE-VPNプロトコルの他、OpenVPN、MS-SSTP、L2TP over IPSec等 様々なプロトコルに対応する。
[SoftEtherプロジェクト公式サイト](https://ja.softether.org/)


公式のインストール手順に則れば問題なく動作するものの、
サービス用の設定ファイルが`init`システム用なので、これを`Systemd`に乗っけて動かすことが出来ないか？
[SoftEther VPN - 7.3 Linux へのインストールと初期設定](https://ja.softether.org/4-docs/1-manual/7/7.3)


# Systemdとは

Linuxのinitシステムを置き換える目的で開発されているシステム管理デーモン。

[Wikipedia - systemd](https://ja.wikipedia.org/wiki/Systemd)

最近のディストリで採用例が増えている？


# 早速実例

`/etc/systemd/system/softether-vpn.service` というファイルを作る。

※ファイル名、`Description`は任意。
ファイル名はそのままサービス名になるので、他と被らない名前にする。


```text:softether-vpn.service
[Unit]
Description=Softether VPN Server Service
After=network.target

[Service]
Type=forking
User=root
ExecStart=/usr/local/vpnserver/vpnserver start
ExecStop=/usr/local/vpnserver/vpnserver stop
Restart=on-abort
WorkingDirectory=/usr/local/vpnserver/
ExecStartPre=/sbin/ip link set dev eth0 promisc on

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


以前まで `ifcfg-eth0` 等に `PROMISC=yes` と書けばプロミスキャスモードが有効になっていたが効かなくなったようなので
`ExecStartPre`を使用し、実プログラム起動前に`ip`コマンドで都度プロミスキャスモードをONにする作戦。


ファイルを作った後は、設定ファイルの再読み込みを行う

```bash
$ sudo systemctl daemon-reload
```

起動できるか試す

```bash
$ sudo systemctl start softether-vpn.service
$ sudo systemctl status softether-vpn.service
● softether-vpn.service - Softether VPN Server Service
   Loaded: loaded (/etc/systemd/system/softether-vpn.service; disabled; vendor preset: disabled)
   Active: active (running) since Sun 2017-12-10 14:17:17 JST; 3s ago
  Process: 2127 ExecStart=/usr/local/vpnserver/vpnserver start (code=exited, status=0/SUCCESS)
 Main PID: 2129 (vpnserver)
    Tasks: 24 (limit: 4915)
   CGroup: /system.slice/softether-vpn.service
           ├─2129 /usr/local/vpnserver/vpnserver execsvc
           └─2130 /usr/local/vpnserver/vpnserver execsvc

Dec 10 14:17:13 localhost.localdomain systemd[1]: Starting Softether VPN Server Service...
Dec 10 14:17:17 localhost.localdomain vpnserver[2127]: The SoftEther VPN Server service has been started.
Dec 10 14:17:17 localhost.localdomain systemd[1]: Started Softether VPN Server Service.
```

`Active: active (running)` と表示されているので、正常に起動している。

問題なさそうなら、自動起動設定を行う

```bash
$ sudo systemctl enable softether-vpn.service 
Created symlink /etc/systemd/system/multi-user.target.wants/softether-vpn.service → /etc/systemd/system/softether-vpn.service.
```
Google HomeからiPhoneのリマインダーにタスクを登録する


先日Google Home miniが半額になっていたので購入してきました。
ほんのちょっとしか触れていないですが、Google HomeからiOS標準のリマインダーにタスクを追加することが
できたので、記事にまとめます。

## できたこと
Google Homeに「OK Google,リマインダーにXXXを追加」と話し掛けると
iPhoneのリマインダーにXXXというタスクが追加される。

## 必要なもの

* Google Home
* iPhone/iPad
* Googleアカウント
* IFTTTアカウント

* IFTTTのiOSアプリ

## 方法

### 1. IFTTTのアカウントを作成する

 Google Homeに設定しているアカウントで[IFTTT](https://ifttt.com/discover)のアカウントを作成します。
 
### 2. IFTTTでAppletを作成する
 
 以下のようにAppletを設定します。画像は一度登録したAppletの設定画面です。
 
* Google Assistant側の設定
 「リマインダーに\\$を追加」と話し掛けるとAppletが実行されるようにしました。
 $が変数でGoogleHomeに話し掛けた内容が入ります。


* iOS Remainder側の指定
 ListName(タスクリストの名前)とPriority(タスクの優先度)は適当です。お好みで。
 
 ![IFTTT_Applet.png](https://qiita-image-store.s3.amazonaws.com/0/33324/de93001a-d9f2-3cf2-7d0f-61207aaf79b4.png "IFTTT_Applet.png")

### 3. IFTTTのiOSアプリをiPhone/iPadにインストールする。

 [IFTTTのiOSアプリ](https://itunes.apple.com/jp/app/ifttt/id660944635?mt=8)をインストールします。
 インストールしたら、1.で作成したアカウントでログインします。
 ここまでできたら準備は完了です。

## 実行結果

自分「OK Google,リマインダーにゴミ出しを追加」
　　　　　　　　　↓
Google Home mini「リマインダーにゴミ出しを追加しました」
　　　　　　　　　↓
タスクリストに追加された
<img src=https://qiita-image-store.s3.amazonaws.com/0/33324/5cd823e6-f14d-3887-dff9-bc1a97448b71.png "IMG_2337.PNG" width=50%>


詳細はこのようになっている
<img src=https://qiita-image-store.s3.amazonaws.com/0/33324/f1db947f-a0b9-f888-2e14-d20007b59670.png width=50%>

以上です。

### 注意事項/その他

* IFTTTのiOSアプリの設定でリマインダを許可する必要があります。
iOSの[設定]>[IFTTT]>[リマインダー]をON
<img src=https://qiita-image-store.s3.amazonaws.com/0/33324/5769d52b-c963-987f-934e-8cbd0a2ea86b.png "IMG_2339.PNG" width=50%>

* 指定したタスクリストが存在しない場合は新規作成されます。
* タスク名が複数の単語からなる場合、間にスペースが入ってしまうようです。

### できなかったこと
* 登録先のリストを音声で指定してタスクを追加する
* タスクの開始日/期限の指定

### 参考

Google HomeとIFTTT連携の方法が詳しく＆わかりやすく纏められています。とても助かりました。
[Google HomeをIFTTTと組み合わせてTwitterやLineなどと連携しよう！](https://yuki-no-yabo.com/combined-googlehome-with-other-services/)
DynamoDBに書き込む AWS IoT のルールの作り方

1)　DynamoDB のテーブルを作成します。
ハッシュキーを id、レンジキーを time にします。

![iot_rule_dec1001.png](https://qiita-image-store.s3.amazonaws.com/0/179446/35bbff7f-09f1-0bb8-7a40-2ff5c51cc6db.png)

次のプログラムでも作成できます。

```py3:dynamo_create.py
#! /usr/bin/python
# -*- coding: utf-8 -*-
#
#	dynamo_create.py
#
#					Dec/10/2017
# ---------------------------------------------------------------
import	sys
import	datetime
import	boto3
from decimal import *

# ---------------------------------------------------------------
def create_table_proc(table_name):
	table = dynamodb.create_table(
		TableName=table_name,
		KeySchema=[
		{
		'AttributeName': 'id',
		'KeyType': 'HASH'
		},
		{
		'AttributeName': 'time',
		'KeyType': 'RANGE'
		},
		],
		AttributeDefinitions=[
			{'AttributeName': 'id', 'AttributeType': 'S' },
			{'AttributeName': 'time', 'AttributeType': 'S' },
			],
		ProvisionedThroughput={
			'ReadCapacityUnits': 1,
			'WriteCapacityUnits': 1
			}
		)

	print("Table status:", table.table_status)
#
# ---------------------------------------------------------------
sys.stderr.write ("*** 開始 ***\n")
#
dynamodb = boto3.resource('dynamodb')

table_name = 'iot_test'

try:
	create_table_proc(table_name)
except Exception as ee:
	sys.stderr.write("*** error *** in create_table_proc ***\n")
	sys.stderr.write(str(ee) + "\n")

sys.stderr.write ("*** 終了 ***\n")
# ---------------------------------------------------------------
```

2) IoT のルールを作成します。
AWS Iot コンソールの ACT に入ります。
![iot_rule_dec1002.png](https://qiita-image-store.s3.amazonaws.com/0/179446/67f6c007-5edc-a08f-d51c-4afa00ef0e32.png)

ハッシュキー値　${id_in}
レジスターの値　${time_in}

![iot_rule_dec1003.png](https://qiita-image-store.s3.amazonaws.com/0/179446/f73e2073-568f-0874-b05c-fd596da7a0e6.png)

3) IoT Thing （ブローカー）を作成します。

![iot_rule_dec1004.png](https://qiita-image-store.s3.amazonaws.com/0/179446/ed78b7b2-8ae2-d232-52c6-492621e0edee.png)

AWS コンソールで作成する方法は、
[AWS IOT の簡単な使い方](https://qiita.com/ekzemplaro/items/9b1293428c69cd2025cd)

AWS CLI で作成する方法は、
[AWS IOT を AWS CLI で設定](https://qiita.com/ekzemplaro/items/a95df050833204c266fb)

4) Pub/Sub のテストを行ないます。
IoT Thing を作成した時に出来た認証ファイルを使います。

こちらにその方法があります。
[Raspberry Pi で、mosquitto を使って、AWS IOT に Pub/Sub する](https://qiita.com/ekzemplaro/items/f2c74afcd716a9251e65)

Publish する JSON を次のようにして下さい。

```json:in01.json
{
  "id_in": "rasp_10001",
  "time_in": "2017-12-10 17:07:10",
  "message": "Hello"
}
```

次のように、DynamoDB に書き込まれます。
![iot_rule_dec1005.png](https://qiita-image-store.s3.amazonaws.com/0/179446/d7eb79f9-f8ab-9266-cbd1-cb3a7aec4bd8.png)
Gitでよくあるハプニングの対策とコマンドメモ

自分用の逆引き対策メモとして作りました。
他にも困っている人の役に立てたら嬉しいなぁ。

## 間違えて必要なファイルを消しちゃった

```
git checkout HEAD [ファイル名]
```

コミット前ならこれで復活できる

## masterにコミットしちゃった

### ■ローカルにとどまっている場合

#### 新しいブランチを切って回避

* 新しいブランチを切って、そのまま変更を連れて行く

```
git checkout -b [新規ブランチ名]
```
* 一回コミットしてしまったブランチの方は、リセットをしてリモートと状態をあわせておく

```
git reset --hard
```

### ■pushしてしまった場合

* まずは深呼吸する
* **エンジニアを召喚する**
  * このとき、何をしていて、どんな状態になったかを端的に共有する
  * そしてどうなって欲しいかを、端的に伝える
  * 擬音で表現しないように気をつける

## masterにマージした時にコンフリクトする

地道にコンフリクトを解消していく

* まずはdiffでコンフリクトしている箇所を確認する

```
git diff
```

* 確認して、修正対応できたら、add

```
git add
```

## コミットをなかったことにしたい

```
git reset --hard HEAD^
```

## すでにあるコミットをまとめたい

```
git  rebase -i [コミットID]
```

## 作業したファイルをコミットせずに破棄したい
```
git reset --hard
```

新規作成ファイルだとこれだけじゃ消えないので注意

## 特定のcssや文章がどこに書いてあるのか見つけたい

```
git grep [検索したいワード]
```

### 便利なオプション

* 私がよく使うオプション
    * -n : 対象の行番号も表示する

あとはhelp叩くか、下記参照

* [Git - git-grep Documentation](https://git-scm.com/docs/git-grep)
* [個人的によく使うgit grepのまとめ](https://qiita.com/zwirky/items/19df2d8d3d584da2790b)

## HEADの位置を過去に移動したい

```
git checkout [コミットID]
```

## 差し込み案件のbranchの扱い方

* 新しいbranchをどこからきるのかが重要

## コミットし忘れた変更を、一つ前のコミットに混ぜたい

```
git commmit --amend
```

## コミットメッセージにtypoを見つけたからなおしたい

```
git commmit --amend
```

## branchが遅れすぎてて、うまくマージできない

```
git rebase [リベース先のbranch名]
```

次のフォースPushもも覚えるといいけど、難しいところもある。
マージ運用のメリットと一緒に、またそのうちメモ追加したい


## ローカルとリモートのbranshの歴史が変わって、pushできなくなった

```
 git push -f [リポジトリの名前] [ブランチ名]
```

## ローカルのbranchを破棄して、リモートのbranchを再度取り込みたい

* 違うbranchに移動
* ローカルのbranchを削除
* リモートのbranchにcheckout

## カレントのbranchを切り替えずに、リモートのmasterをとりこみたい（リリースされたbranchに乗っかりなおしたい）

```
git pull --rebase
```

## 変更したbranchの一部だけ、別のbranchに持ってきたい
```
git cherry-pick
```

## 一瞬違うブランチを見に行きたいけど、変更ファイルがあるよって怒られる

```
git stash
```

### ■stashの付属コマンドたち

#### 1)stashしたものが複数あって、リストを見たい時

```
git stash list
```

#### 2)戻す時

```
git stash apply [stashのリストナンバー]
```

最新だったらリストナンバーは省略可

#### 3)リストから消す時

```
git stash drop [stashのリストナンバー]
```

最新だったらリストナンバーは省略可

#### 4)リストから消す時その２

```
git stash pop [stashのリストナンバー]
```

最新だったらリストナンバーは省略可

## stagingからおろしたい

```
git reset HEAD [ファイルパス]
```
#作業してくる で実装した、mp3によるゲームBGMのようなループ再生について

# はじめまして
プログラミングについてちゃんと発信するのが初めてで震えています。
ドキドキしてきました。よろしくおねがいします。
雰囲気でプログラミングをしているので、認識等間違っていたら優しく指摘してください。

・MIDI投稿サイト「[Picotune](http://picotune.me)」
・開いておくだけで作業が捗るサイト「[#作業してくる](https://sitekuru.net)」
という２つの音楽系のウェブアプリを開発・運営しています。
先週公開した [#作業してくる](https://sitekuru.net) では100名を超える作曲家の方に参加していただいて、ゲームBGMのような終わりなくループする曲を配信しています。
そのループの部分で四苦八苦したので、、、書きます。
今回の実装はWeb Audio API周辺でしています。
たぶんゲームのBGMとかで同じ手法が使えるとおもいます。
(MediaElementAudioSourceNodeではなくAudioBufferSourceNode利用での実装になるので負荷によるかも…？)

ちなみに、[#作業してくる](https://sitekuru.net) の企画関連のことはブログに書いているので、よければ覗いてみてください。
・[#作業してくる 企画メモ 発案・企画編](http://cagpie.hateblo.jp/entry/2017/11/08/133329)
・[#作業してくる バズらせるための仕掛け(サイト公開編)](http://cagpie.hateblo.jp/entry/2017/12/09/212253)

#そもそも…
## なぜmp3か
一般的にループ系のゲームBGMには、mp3ではなくOgg(Vorbis)やもっと別の方式(MIDI+SoundFontのような形)がとられる。
iOS11の対応状況はあまり追ってないが、2017年11月時点で、OggはSafariとiOSブラウザで再生できないため、一番多くの端末で対応していてファイルサイズが妥当なmp3を扱うことにした。

## 何が問題か
実際にwav等からmp3に変換して比べると一目瞭然なのだが、
mp3に変換する際に、前後に無音が挿入されたり、末尾が切れてしまったりする。(試した感じではコンバータによって結果はまちまち)
これはmp3の規格によるもので、どうにかしようと思っても基本的になんとかなるものではないらしい。
これにより、楽曲のつなぎ目が不自然になってしまう。

このような形のループ楽曲は、ファイルをイントロ部分とループ部分の2つに分け、
イントロ→ループ→ループ→ループ→…と再生していくが、
・イントロ部分からループ部分
・ループ時
の二つが繋ぎの部分となり、今回も同じループ方法をとっている。
曲としてのイントロの有無にかかわらずイントロ部分の用意は必須とした
(リバーブ等の問題もあるので…後述)

100名以上参加していることもあり、作曲家側になるべく手間をかけず、こちらも説明がすくなくて済むような、繋ぎ部分を自然にする手法を考えた。

# 実装
## 動くもの
[#作業してくる 楽曲募集時の説明ページ](https://cagpie.net/static/test/test.html)
音楽ファイルの処理や、イントロ・リバーブについての説明も書いている。
先にザッと目を通してもらえると良いかも。
## 音楽ファイル側の準備
・ループする曲を作る
・イントロ部分とループ部分を切り分け
・それぞれの部分に、前後にある程度(0.5秒とか)の無音を挿入してmp3で書き出し
(無音を挿入する理由は、「そもそも…何が問題か」の部分で、末尾が切れてしまうのをカバーするため)
## 再生側の処理
### ざっくりと
intro.mp3読み込み
→decodeAudioData()によるデコード
→AudioBuffer.getChannelData()で曲の波形データを取得
→波形データから前後の無音を切り取り
→intro.mp3 再生開始
→loop.mp3読み込み
→同様にデコード
→同様に無音切り取り
→BufferSource.loopStart/loopEndを設定
→BufferSource.loopをtrueにして再生
という流れで再生する。
loop.mp3周りの処理前にintro.mp3を再生開始すると、環境によっては曲が途切れる原因になりますが、上手く使えば再生までの時間短縮にもなる。
### 細かい実装
いまコードをみたら全部ここに載せるには結構アレなので、全体は
[#作業してくる 楽曲募集時の説明ページ](https://cagpie.net/static/test/test.html)
を見てください。
以下、公開の実装のアレだった部分の解説
コードも上記のページからの抜粋
#### ・デコード
Safari/iOSだとmp3のdecodeAudioData()が失敗するので、
[decodeAudioData returning a null error](https://stackoverflow.com/questions/10365335/decodeaudiodata-returning-a-null-error)
を参考に対応する。
#### ・波形データの取得～無音の切り取り
```javascript
// 波形データの用意
var channelLs = new Float32Array(audioBuffer.length);
channelLs.set(audioBuffer.getChannelData(0));
// 取得した波形データから、どこまでが無音かを探す
channelLs.some(function(val, idx){
    // ここのthresholdはユーザ定義
    // 切り取りの際、threshold以下は無音とみなすという意味合い
    if(Math.abs(val) > threshold){
        // サンプルレートからidxを秒数に直して設定
        source.loopStart = idx / context.sampleRate;
        return true;
    }
});
```
channelData周りは、
[【Web Audio API入門】音楽プレイヤー作成　第3弾](http://ticablog.com/archives/191) から知った。
#### ・そのほか
その他再生周りは Web Audio API のよくあるサンプルと変わらないはず。
本題ではないが、全体の音量調節用、個々の音量調節用(フェードアウトしたり…)など、gainNodeを複数作り、それを噛ませて音量を制御できると楽。
# 最後に
書いてみたら滅茶苦茶疲れました。
Web Audio API 的には、MIDI投稿サイト [Picotune](http://picotune.me) のほうがゴリゴリ書いているので、よかったら見てみてください(バグ放置中で初めてのページ読み込み時だと動かなかったような気が…)(ガバガバ)(何度かリロードしてみてください)

2017年も残すところ僅かとなりました が、どうぞよろしくおねがいします～
UDG-1-WSNEをOpenWrt上で使う

Wi-SUN対応USBドングル[UDG-1-WSNE](http://web116.jp/shop/netki/miruene_usb/miruene_usb_00.html)は大抵のLinux環境で刺せばいきなり使えると思いますが、OpenWrtでは明示的にカーネルモジュールをインストールする必要があったので、その記録。

```
# opkg update
# opkg install kmod-usb-uhci
# opkg install kmod-usb-ohci
# opkg install kmod-usb2
# opkg install kmod-usb-acm
```

インストール後に`dmesg`を見ると`/dev/ttyACM0`が出来ていることがわかります。

```
$ dmesg
(snip)
[  341.361349] cdc_acm 1-1.2:1.0: ttyACM0: USB ACM device
[  341.372880] usbcore: registered new interface driver cdc_acm
[  341.384277] cdc_acm: USB Abstract Control Model driver for USB modems and ISDN adapters
```

このデバイスファイル経由で他の環境と同様に動作確認ができます。（参考：「[ミルエネのUSBドングルUDG-1-WSNEの動作確認 - Qiita](https://qiita.com/hnw/items/e2cd07929cc82129f1a5)」）

```
# screen /dev/ttyACM0 115200
EVER 1.0
OK
```

↑`SKVER`と打った結果。自分のタイプした内容はエコーバックされない。

## 参考URL

- [ミルエネのUSBドングルを使ってDatadogで電力見える化 - Qiita](https://qiita.com/YamaguchiRei/items/2debdbb908445036bcc0)
MapR-DB JSONとBinaryについて　データモデル編

アドベントとしては既にかなり破綻していますが、ノロノロ粛々と記事を書いていきたいと思っている4日目です。
本日のお題はMapR-DBです。

MapR-DBはMapR Technologies社が提供するNOSQL DBとなります。
MapR-DBにはMapR-DB JSON(以下、JSONテーブル)とMapR-DB Binary(以下、Binaryテーブル)の2種類存在します。

本記事ではこれらの違いについてデータモデル的な観点から比較を行っていきます。
性能や管理コマンド、MapR 6.0でJSONテーブルに追加された新機能などについては他の日のエントリーに回します。
なお、本記事の内容は[こちら](https://maprdocs.mapr.com/home/MapROverview/maprDB-data-model.html)の内容を和訳して簡単にまとめたものとなります。※完訳ではありません。

# JSON テーブル

* JSONテーブルは名前の通りJSONドキュメントを格納します。つまり、階層的かつネストになったデータを格納出来、かつデータは更新可能となります。
* JSONテーブルではMapR社がメインで開発しているOJAI : Open Json Application Interface（オージェーエーアイ、もしくはオーハイ）データ・モデルとOJAI APIを利用します。
* ドキュメントはJSON形式ですが、実際にはバイナリで保存されており、テキスト形式で保存されているわけではありません。
* JSONテーブルでは'_id'フィールドがrowkeyとして扱われ、JSONドキュメントがvaueとなります。
* テーブルはMapRファイルシステム上の任意のパスに格納されます。
* それぞれのドキュメントのフィールド、もしくはフィールドのサブセット、もしくはドキュメント全体をディスクから読み書きします。個々のフィールド、もしくはフィールドのサブセットの更新の際には、ドキュメント全体を読む必要はなく、更新を行ったらその分だけディスクに書き出します。
* OJAIではJSONがサポートする標準的な型よりも多くのデータ型を利用して複雑なクエリを生成し、コネクションやコンフィグレーションオブジェクトなしにJSONテーブルにアクセス可能です。
* クエリ結果のフィルタはクライアントに戻る前にMapR-DB内で行われます
* サポートするプラットフォームはLinux, OS X, Windowsです。
* 他のクラスタにデータをコピーすることなく、リアルタイムにApache Drillやその他の解析ツールからアクセス可能となります。
* 数千ノード規模でスケールします。
* MapRのAccess Control Expression(ACE)機能により、単一、もしくは複数のフィールド単位で読み書き制御狩野です。
* JSONテーブル内の単一フィールドとサブドキュメントのディスクレイアウトを制御できます。

## JSON ドキュメント

JSON テーブルが利用するJSON ドキュメント特徴としては以下のような点が挙げられます。

* スカラー、ネストドキュメント、配列の3つのタイプでデータを格納可能
* スキーマは柔軟であり、新たなフィールドをいつでも追加出来ます。各rowでJSONの構成が同一である必要はありません
* フィールドを特定する際には”.”(ドット)を利用することが出来ます

```
{
  "a" : {
          "b" : {
                  "c" : {
                          "d" : "value_for_d"
                        }
                 }
         }
} 
```

上記のdのパスはa.b.c.dとなります


## JSONテーブルのカラムファミリー（CF)

JSONテーブルはCF上に格納され、CF単位でディスク上に格納されます。
JSONテーブルではCFを新たに作成し、一つ以上のフィールドを別のCFに格納することで、ディスク上の離れた場所にデータを格納できます。
一つのCFに格納されたデータに対してクエリやオペレーションを実行することで、テーブル内のその他のデータと同居するデータよりも、より効率的かつ高い性能を実現出来ます。
またキャッシュの効率も良くなります。
JSONテーブルでは64個までCFを作成できます



# Binary テーブル

* BinaryテーブルはApache HBaseとコンセプト的には同じで、ワイドカラムストア型のデータベースとなります。
     * 実際にBinaryテーブルはHBaseのデータ・モデルを利用し、HBase APIをサポートしています。
* Binaryテーブルはカラムナデータを必要とする大規模アプリケーションでも利用可能となり、標準的なHBaseアプリケーションAPIを利用するアプリケーションとバイナリ互換性を持ちます。
* Binaryテーブルでは、keyによってrowがインデックスされ、各行のカラムによってデータ要素が決定されます。CFは一つ以上のカラムのグループから成ります。
* Keyのサイズは最大で64KBまでとなります。ただし、数百バイト程度にしておくのが推奨されます。
* Rowは一つ以上のCFにまたがります。Rowのサイズは最大で2GBまでサポートされます。ただし、2MB程度までにしておくのが推奨されます。一般的にはMapR-DBの性能はたくさんの小さいRowを持つテーブルほど良くなります。
* CFは一つ以上のカラムから成り立ちます。MapR-DBでサポートされるCFの数は64までとなります。
* カラムは一連のタイムスタンプと関連してValueを決定するキーとなります。

## BinaryテーブルのCF

テーブル全体をスキャンするのは非効率的ですが、CFにアクセスすることでアクセスする範囲を狭め、性能を高めることが出来ます。
また、CFごとに圧縮機能を設定することで、ニーズに応じたレイテンシや消費ディスクの効率を設定することが出来ます
ただし、各CFに存在するおおよその行数である、cardinality(カーディナリティ)に注意する必要があります。
CFごとのカーディナリティの差が大きい場合、行数の少ないCFのデータは複数のノードに散らばりがちになります。
これは行数が多いCFがより多くのSplitを必要とするためです。
そのため、CFごとのカーディナリティの差が大きい場合、行数の少ないにも関わらずCFのスキャンに時間がかかることがあります。

MapR-DBではカラムレベルではなく行レベルでSplitが発生します。
そのため、非常に多くのカラムを持つ極端にワイドなテーブルにおいては、行数が比較的少なくともスプリットが推奨されるテーブルサイズに到達します。
そのため、一般的には行数が多く、カラム数が少なくなるように設計することが重要です。

MapR-DBテーブルではカラムをいつでも追加することが出来ます。
また、カラムがNullの場合はストレージ容量は消費されません。


# まとめ

以上、各テーブルのデータモデル観点から説明でした。
MapR-DBについてはまだまだ紹介することがたくさんありますので、新しい記事が出てくることでしょう！！！（期待）
私の Touch Bar (Control Strip) カスタマイズ

Touch Bar 付 Macbook Pro をお使いの方、Touch Bar 活用されてますか？
今回は私の Touch Bar (Control Strip) の設定について書きます。

私は Control Strip をこんな感じに設定しています。

# 配置

![IMG_6845_mod.jpg](https://qiita-image-store.s3.amazonaws.com/0/23579/e951a8fb-3aa1-6280-3792-6144103945af.jpeg)

左から順に次のようにしています。

- Brightness
- Mission Control
- Launchpad
- Keyboard Brightness
- Do Not Disturb
- Notification Center
- Volume
- Screen Saver

# なぜこのようにしたか？

Brightness, Volume について、Brightness Slider, Volume Slider への入れ替えも考えましたが、普段 Apple Magic Keyboard を使う場面があるのでインターフェイスを同じままにしました。
私の場合、Media, Siri キーの使用頻度が低かったので、そこだけを入れ替えた形です。
代わりに追加したアイテムは次の3つです。

- Do Not Disturb
- Notification Center
- Screen Saver

## Do Not Disturb

ChatWork や Slack などのチャットアプリのデスクトップ通知を表示させたくない、集中したい時ってありますよね。
かといってチャットアプリを終了しておくと今度は起動時間がもったいない。
そんな時に通知の ON/OFF をしやすくしています。

## Notification Center
好きなアイテムを設定しておくことができます。
WORLD CLOCK, CALCULATOR をよく使うので、ここから見られるようにしています。

### WORLD CLOCK

<img width="336" alt="Screen Shot 2017-12-10 at 16.06.59.png" src="https://qiita-image-store.s3.amazonaws.com/0/23579/6ed25f13-e0f9-c3b3-a622-200f0b40746f.png">

各地との時差を意識して仕事をする際に、アナログ時計の方が時刻を認識しやすいですよね。
時計を並べて見られるので便利です。

### CALCULATOR

<img width="335" alt="Screen Shot 2017-12-10 at 16.07.12.png" src="https://qiita-image-store.s3.amazonaws.com/0/23579/25f06089-67ad-846e-74da-0d7c1aa26692.png">

Dashboard やアプリの電卓を使うこともあるのですが、こちらの方が入力した値を保持していてくれたり、表示位置を調整しなくてよいので便利です。

## Screen Saver

離席時のスクリーンロック用です。
Control Strip のアイテムとして Screen Lock も選択できますが、ロック画面が「バン！」と表示されるのはちょっと味気ないのでスクリーンセーバーで即ロックがかかるようにしています。

# 設定手順
次の手順で Control Strip を設定しています。

## Preferences の Keyboard で Touch Bar の設定

<img width="668" alt="Screen_Shot_2017-12-10_at_14_42_06.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/23579/6c9e9b07-fd70-e41c-dee0-73daf3af5f8c.jpeg">

- Touch Bar shows で "Expanded Control Strip" を選択
- Press Fn Key to で "Show F1, F2, etc. Keys" を選択
- "Customize Control Strip" ボタンをクリック

## Control Strip に表示するアイテムの選択と配置

<img width="733" alt="customcontrolstrip.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/23579/9653e313-7712-034d-adbb-ef9a76b4d713.jpeg">

ベースはデフォルトの Control Strip で、次の変更を行っています。

- Media と Siri を Touch Bar から外す
- Media のあった場所に Do Not Disturb, Notification Center を配置
- Siri のあった場所に Screen Saver を配置

# まとめ
ちょっとしたカスタマイズでよく使う機能やアプリを簡単に利用できるようになりました。
手元の操作でできることが増えると姿勢が固定されて運動不足になってしまいがちなのが悩みどころです。
適度に体を動かすことも忘れずにやっていきたいと思います。
ansibleでリモート側にある複数のzipファイルを展開する方法


これは [FUJITSU Advent Calendar 2017](https://qiita.com/advent-calendar/2017/fujitsu) 11日目の記事です。
皆さんがっつり書いてますが私は軽めです。

## unarchive機能のおさらい
ansibleでリモートマシン上に圧縮ファイルを展開する方法としてunarchiveというモジュールがありますが、これはansibleの管理マシン上にある圧縮ファイルを送って展開するというのがデフォルトの動きです。


> ```
> - name: Extract foo.tgz into /var/lib/foo
>   unarchive:
>     src: foo.tgz
>     dest: /var/lib/foo
> ```

[公式マニュアル][man]より引用
[man]:http://docs.ansible.com/ansible/latest/unarchive_module.html

リモートマシン上に既に置いてあるzipファイルを展開するためには`remote_src: yes`というオプションをつけます。

> ```
> - name: Unarchive a file that is already on the remote machine
>   unarchive:
>     src: /tmp/foo.zip
>     dest: /usr/local/bin
>     remote_src: yes
> ```

[公式マニュアル][man]より引用


でもですね、zipファイル名なんてずっと同じか分からんのですよ。
zipファイル増えるかもしれんのですよ。

## 結局どうやるか
そういった場合はどうするかというと、その場でファイルリストを作ってループします。

```
- name: filelist of Hoge test set
  shell: chdir=/home/hoge/testset/zipfiles find `pwd` | grep .zip
  register: filelist
- name: unzip Hoge test set
  unarchive:
    remote_src: yes
    src: "{{ item }}"
    dest: "/home/hoge/testset/SRC"
  with_items: "{{ filelist.stdout_lines }}"
```

今更ながら2行目のshellのところは、もうちょっと改良の余地ありかも。



## 余談
見てのとおりテストセットをサーバに展開するときにこれをやってました。
なんでわざわざzipに固めてたかというと、転送のスピードが全然違うためです。
zipがテストセットのリポジトリ(ファイルサーバじゃないよ)にあって、それをチェックアウトしてくるという処理が上記の前段にあります。

組織的にですね、[Interstage Application Development Cycle Manager](http://software.fujitsu.com/jp/manual/manualfiles/m130012/b1wd2996/04z000/b1wd-2996-04z0.pdf)を使ってリソース管理していたもので、
こんな感じのチェックアウト処理です。

```
- name: check out Hoge test set
  command: chdir=/home/hoge creates=/home/hoge/testset {{ escm_path }}/escm co -s {{ escm_server }} -d {{ escm_repository }} -p {{ escm_project }} -r {{ escm_release }} -c {{ escm_branch }} -i zipfiles -q
  environment: "{{ env }}"
```

gitならソースをベタで登録してもチェックアウト速いんだろうなー。
Dockerのインストール&操作方法(CentOS7.3)

## 環境

- ホストOS：CentOS 7.3-1611 64bit Minimal
- Docker：1.12.6, build 85d7426/1.12.6

## セットアップ

### インストール

CentOS7の場合、yum一発で簡単にインストールできます。

```shell-session
$ sudo yum -y install docker
```

### バージョンの確認

インストールできたかどうか、バージョンを確認してみます。

```shell-session
$ docker --version
Docker version 1.12.6, build 85d7426/1.12.6
```

バージョンが表示されているため、インストールに成功しています。

### サービスの開始・自動起動

Dockerサービスの開始と自動起動の設定を行います。

```bash
# Dockerを開始する
$ sudo systemctl start docker

# OSの起動時にDockerが自動で起動するようにする
$ sudo systemctl enable docker
```

### `sudo` なしでDockerコマンドを実行できるようにする

インストール直後、Dockerコマンドは `sudo` を付けないと実行できないようになっています。
そこで、[こちら](https://qiita.com/DQNEO/items/da5df074c48b012152ee)の記事の通りに設定し、 `sudo` なしでDockerコマンドを実行できるようにします。

```bash
# dockerグループを作成する
$ sudo groupadd docker

# ログイン中のユーザーをdockerグループに追加する
$ sudo gpasswd -a $USER docker

# Dockerを再起動する
$ sudo systemctl restart docker

# exitして再ログインすると反映される
$ exit
```

ここから先は Dockerコマンドに `sudo` を付けません。

## 操作方法

### イメージのダウンロード

まず、コンテナの元となるイメージをダウンロードします。

```shell-session
$ docker pull {ユーザー名}/{イメージ名}
```

公式イメージの場合、ユーザー名はありません。

```bash
# 例：ubuntuの公式イメージをダウンロードする
$ docker pull ubuntu
```

### イメージ一覧の表示

ダウンロードしたイメージの一覧を表示します。

```shell-session
$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
docker.io/ubuntu    latest              20c44cd7596f        3 weeks ago         122.8 MB
```

ubuntuが表示されているため、ダウンロードに成功しています。

### コンテナの作成・実行

イメージをダウンロードしたら、それを元にコンテナを作成して実行します。

```shell-session
$ sudo docker run ({オプション}) {ユーザー名}/{イメージ名} {コマンド}
```

```bash
# 例：ubuntuのコンテナを作成して実行し、シェルを操作する
$ docker run -it ubuntu /bin/bash
```
一瞬でubuntuが起動すると思います。コンテナ、すごいです。

### コンテナの抜け方

<kbd><kbd>Ctrl</kbd> + <kbd>p</kbd></kbd>, <kbd><kbd>Ctrl</kbd> + <kbd>q</kbd></kbd>でコンテナを実行したままシェル操作などを抜けます。
`exit` コマンドで抜けるとコンテナが停止します。

### コンテナの各操作

#### コンテナ一覧の表示

```bash
# 実行中のコンテナのみ表示する
$ docker ps

# 停止中のコンテナも含めて表示する
$ docker ps -a
```

#### コンテナの操作

実行中のコンテナのみ操作できます。

```shell-session
$ docker attach {コンテナ名} or {コンテナID}
```

#### コンテナの開始

```shell-session
$ docker start {コンテナ名} or {コンテナID}
```

#### コンテナの停止

```shell-session
$ docker stop {コンテナ名} or {コンテナID}
```

#### コンテナの削除

停止中のコンテナのみ削除できます。

```shell-session
$ docker rm {コンテナ名} or {コンテナID}
```

#### コンテナの一括削除

停止中の全コンテナを一括で削除します。

```shell-session
$ docker rm $(docker ps -aq)
```

### `docker run` の主なオプション

|オプション|略|説明|
|:--|:--|:--|
|-d|detached|コンテナをバックグラウンド(デタッチド・モード)で実行する|
|-i|input|コンテナの標準入力を開く|
|-t|tty|コンテナの疑似端末を確保する|
|-p {ホスト側ポート}:{コンテナ側ポート}|port|コンテナのポートをホスト側に公開する(ポートフォワーディング)|
|-v {ホスト側ディレクトリ}:{コンテナ側ディレクトリ}|volume|ホストのディレクトリをコンテナ側にマウントする|
|-h {ホスト名}|host|コンテナのホストに名前を付ける|
|--rm|remove|コンテナの終了時に削除する|
|--name={コンテナ名}|name|コンテナに名前を付ける|
|--link="{コンテナ名} or {コンテナID}”|link|他のコンテナへのリンクを追加する(**非推奨**)|

`-i` と `-t` を組み合わせる( `-it` )ことで、シェルを操作できます。

## 参考リンク

- [Docker run リファレンス — Docker-docs-ja 17.06.Beta ドキュメント](http://docs.docker.jp/engine/reference/run.html)
Parceljsをつかってみました。

# 概要

https://qiita.com/bitrinjani/items/b08876e0a2618745f54a

こちらの記事をみかけて
確かにwebpackって設定ファイル書くのめんどくさいよね
ちょっと試してみよう
と思いました。

なので、ちょっとやってみた。

# 動くプログラム

https://github.com/taktod/parcelTest
手元
node v9.2.1
npm 5.6.0

で動作しました。
つかいかた

```
$ git clone https://github.com/taktod/parcelTest.git
$ cd parcelTest
$ npm install
$ npm test
```

あとは http://localhost:1234/
で適当なブラウザでアクセスすればOK

# parcelをつかったプログラムの作り方

とっても簡単でした。

1. 適当なnodeのプロジェクトを作る
2. npm installでparcel-bundlerいれる
3. index.htmlを適当に書く
4. node_modules/.bin/parcel index.html でパッケージ化してhttpでアクセスできる状態にしてくれた

これだけ
typescriptを使いたい場合はtypescriptをnpm installでいれてindex.htmlで利用しているscriptタグのsrcをターゲットのtsファイルにするだけでした。

# 今後したいこと

AssetとPackagerというモジュールをつくるといろいろいじれるみたいなので
そっちを勉強してemscriptenでpackage化するときに自動的にコンパイルするコード書きたいなと思ってます。
CentOS7にFML4を導入(そんな古いの入れるな！)

#メーリングリスト用のサーバ
先日メーリングリスト(ML)を行っているサーバの更新を行う事にしました。

OS: CentOS7.4/64bit

MLサーバソフトは結構古いものでして

>fml-4.0-stable-20040215.tar.bz2

を使っていました。さすがに古いかなと思いまして、

>fml-7.98.18-20150815.tar.gz

を導入して検証していたところ、、Moderator機能が動かない事に気がつきました。

しらべたら動かない旨の記載がソースコードに書いてありました。

```fml-7.98.18-20150815/regress/simulation/00_MEMO
[TODO]  無限 confirmation 問題(?)
```

デバックする根性はなかったので、古いfml-4系を導入する事にしました。

#CentOS7.xにfml-4を導入すると
CentOS7.xにfml-4を導入するとperlがいっぱい警告だします。最新のperlに対応していない事が原因です。

CentOS7.4には以下のperlが入ってます。

```
$ perl --version
This is perl 5, version 16, subversion 3 (v5.16.3) built for x86_64-linux-thread-multi
(with 33 registered patches, see perl -V for more detail)
```

#古いperlの導入
CentOS7.xのperlは新しいので古いperlを導入します。

参考文献
> https://cloudpack.media/754
> Perl5.8系をインストール

すでに入っているperlを消して古いperlを入れると障害が発生しますので、別の場所に入れる必要あります。古いperlは上記文献のように/usr/local/perl-5.8へ導入しました。

```
$ tar xvfz perl-5.8.9.tar.gz
$ cd perl-5.8.9.tar.gz
$ ./Configure -de -Accflags='-fPIC' -Dprefix=/usr/local/perl-5.8
$ make
$ make test
  -> 2個エラー, 気にしない(^_^;
$ sudo make install
$ cd /usr/local/bin
$ sudo  ln -s /usr/local/perl-5.8/bin/perl perl58
```

#FML-4の導入
あとは通常のFML4のインストールに従っていただければと思います。

インストール時にperlを変更する作業が必要です。

```
$ env _PATH_PERL=/usr/local/bin/perl58 perl58 makefml install
```

以上
GASからAdd to Pocketする(本当はAndroidのIntentからやりたかった)

趣味プログラマーの自分用メモです。信頼性に注意。

# 目的
* RSSが廃れてきたが自分はRSSがないと死んでしまうのでGASで自製した
* いい感じに運用できていたが、大量にありすぎて消化が追いつかない
* 消化が追いつかない原因はお昼休みのスマホ回線状況が悪く開くのに時間が掛かるから (地方のMVNO）
* Pocketはあらかじめ追加したアイテムはダウンロードしてくれる（ことが多い）
* 暇なときに自製RSSGASからPocketに追加、PocketにてバックグラウンドでDL、さくさくPocketで読む。完璧。

# 実装方法の検討
* Androidの基本がわかってないので、当初、Android OS上でPocketのlocalhostにデータを投げればいいと思っていた
    * 当初の想定 ： Chromeブラウザ → Aタグリンク → Javascript → Android内のAppへデータを投げる
    * でも暗黙的インテントだとイチイチ共有するアプリを選択するのダルい。
    * 明示的インテントの渡し方わからん。下記みたいなことがやりたかったけど断念。

```html
<a href="intent://send/#Intent;package=com.ideashower.readitlater.pro;action=android.intent.action.SEND;category=android.intent.category.DEFAULT;extras=android.intent.extra.TEXT:https%3a%2f%2fwww%2egoogle%2eco%2ejp%2f;end">pocket add test</a>
```


* 作戦変更して、自製RSSはGAS上で動いているので、GASを経由してPocketのWEB APIを叩くことにした。

# コーディング
* この方針に決めて調べたら、すぐに下記サイトに行き当たり、ほぼこれで行けました。大変感謝。
    * [Presso と Pocket を連携するスクリプトを作りました](http://realtor-readyabooks.hatenablog.com/entry/20140329/1396092391)
* slack botを作るときにcallback URLも弄ったことあったので挙動の流れも分かった

# 諦めきれないIntent
* どなたか参考記事あれば教えてください。
* Androidアプリで呼び出す方法があるんですがWebブラウザから同様にやりたいのです
    * （理由：追加したときに下部に出るUIがカッコイイから）
    * こんな感じに構成すればいいらしい
        * [Android Intents with Chrome](https://developer.chrome.com/multidevice/android/intents)
        * [Launch custom android application from android browser](https://stackoverflow.com/questions/2958701/launch-custom-android-application-from-android-browser)


```
intent:
   HOST/URI-path // Optional host 
   #Intent; 
      package=[string]; 
      action=[string]; 
      category=[string]; 
      component=[string]; 
      scheme=[string]; 
   end; 
```

    * packeage=com.ideashower.readitlater.pro; //これは確実に合ってる
    * action=android.intent.action.SEND; //怪しい
    * category=android.intent.category.DEFAULT; //怪しい
    * component= //mimeTypeをtext/plainに、EXTRA_TEXTに追加したいURLを入れるんだろうが、、、
    * scheme= //わからん

といったところで日曜のプログラム終了です。
WebViewClinetのonPageStartが呼ばれなくなった日

# TL;DR
- 特定のURLをネイティブで処理したい場合は、`shouldOverrideUrlLoading`内で
- アプリはちゃんとメンテしましょう

# 発生した問題
2017/12/08、一部の端末のWebviewで特定のURLが読み込まれないという問題に遭遇しました。
Galaxy、ZenFoneで発生し、Xperia、Nexusでは発ししません。

## とあるアプリでやっていたこと
1. WebviewでURLにアクセス
2. カスタムURLスキームへのリダイレクトレスポンスが返る
3. 特定のURLへのアクセスだった場合、Webviewのロードを止めネイティブ側で処理する

3の処理に問題があり、WebviewClientが以下のような実装になっていました

```
boolean shouldOverrideUrlLoading (WebView view, String url) {
    if (url.eqauls("some://app.request/")) {
        return true;
    }
    return false;
}
void onPageStarted (WebView view, String url, Bitmap favicon) {
    if (url.eqauls("some://app.request/")) {
        someAction();
    }
}
```

本来なら`onPageStarted`で`someAction()`を実行せず、`shouldOverrideUrlLoading`内で呼ぶべきところです

## これにより何が起きていたのか
`shouldOverrideUrlLoading`で`ture`を返した場合、`onPageStarted`が呼ばれなくなりました
※普通に考えれば正しい挙動です

## そもそもなぜ`onPageStarted`で処理していたのか
調べた・聞いたところ太古の昔、Android2.3や3.0の時代にリダイレクト時に`shouldOverrideUrlLoading`が呼ばれない問題があったようです。
苦肉の策として、`onPageStarted`で処理するようにしたものと思われます。
CentOS関係ないですが、backupしましょうね。RAIDは壊れる。

#数年前のとある日の出来事

同僚がサーバのファイルが読めないっと飛びついてきた。

サーバ室に行き確認しましたが、読めませんでした。専用のRAIDコントローラーにつながっているんだが、RAIDコントローラーから外して単発のHDDとして繋いでも読めなかった。

RAIDコントローラーが壊れたんではないかという結論になった。

そうです。RAIDはRAIDコントローラーが死んでデータが破壊される可能性あります。

事例としては経験してませんが、OSが暴走してデータが壊れる可能性もあります。

#別のHDDにbackupしましょうね(^_^;

backup先としては外付けのUSB-HDDがおすすめです。

注意：USB-HDDが盗まれるとデータ漏洩しますので、自己責任でお願いします。

詳細は省略しますが、 市販の外付けHDDはたいていWindows用のNTFSかFATフォーマットになっていますので、/sbin/parted (GNU Parted)でLinux用のパーティションに変更して、フォーマットしてください。フォーマット形式はext4(/sbin/mkfs.ext4)とかxfsで(/sbin/mkfs.xfs)いいんでないかな。フォーマットしたら/etc/fstabに加筆してください。UUIDは/dev/disk/by-uuid/あたりを見たらわかります。

#backupのアプリ
rsyncがおすすめです(^_^;

ちな私は次のような自作ツールを使ってます。面倒なので説明は省略しますが、ソース読んでください。

バックアップ先の外付けHDDをマウントしたディレクトリは /backup/1, /backup/2とします。

crontab の設定。毎月１日に/backup/1にbackupして、15日に/backup/2にbackupします。

```
$crontab -l
15 5 1 * * /usr/local/sbin/BACKUP.pl /backup/1 < /usr/local/etc/backup-all.txt > /tmp/backup.all.log 2>&1
15 5 15 * * /usr/local/sbin/BACKUP.pl /backup/2 < /usr/local/etc/backup-all.txt > /tmp/backup.all.log 2>&1
```

バックアップ対象ファイルを設定。

```/usr/local/etc/backup-all.txt
/etc/
/home/
/var/
/usr/
/root/
/boot/
```

プログラム。

```/usr/local/sbin/BACKUP.pl
#!/usr/bin/perl

#　By Ryuji MATSUMOTO
#
# rev 1.9 : debug = 1
# rev 2.0 : append exclude.

#$debug = 1;

if($#ARGV== -1)
{
        die "usage $0 STORE_DIR\n";
}

$STORE=$ARGV[0];

die "No Such Directory \"${STORE}\"\n" unless(-d $STORE);

$RSYNC = "/usr/bin/rsync --delete -va";

$RSYNC .= " -n" if($debug);

while(<STDIN>)
{
    chop;
    ($dir , @execlude) = split(/\s/, $_);

    if(-d $dir)
    {
        unless(-d "${STORE}${dir}")
        {
                system("/bin/mkdir -p ${STORE}${dir}");
        }

        $dir =~ s#\/$##;
        $dir .= "/";

        local($r)=$RSYNC;
        for $i ( 0 .. $#execlude)
        {
            local($t) = $execlude[$i];
            if($t=~ /^\S+$/)
            {
                $r = $r . " --exclude=\"" . $t . "\"";
            }
        }

        print("${r} ${dir} ${STORE}${dir}\n");
        system("${r} ${dir} ${STORE}${dir}");
    }
}

#EOF
```

以上です。
事情がありCentOSの文字コードをEUC-JPにしてみたはなし。

#文字コード
最近のLinux Distributionはほとんど文字コードがUTF-8になってますが、ちょと前まではEUC-JPが多かったです。 Sun Solarisでも SunOS4.Xの頃はEUC-JPがメインでしたね。

それでなんですが、一部都合でEUC-JPの環境が残ってます。それようのサーバを作る必要がありまして、CentOS7で設定してみました。

このサーバで提供しているのはsshでのログインとsamba です。（仮想環境なんでGUIは試してませんが、おそらく文字化けしてダメじゃないかな。。）

#文字コードの切り替え

参考文献
http://zero-config.com/centos/changelocale-002.html

上記文献を参考にしました。

現在のロケール。

```
$ localectl status
   System Locale: LANG=ja_JP.UTF-8
       VC Keymap: jp
      X11 Layout: jp
```

ロケール変更(root作業)

```
$ localectl set-locale LANG=ja_JP.eucjp
```

変更されたかの確認

```
$ localectl status
   System Locale: LANG=ja_JP.eucjp
       VC Keymap: jp
      X11 Layout: jp
$ more /etc/locale.conf
LANG=ja_JP.eucjp
```

以上で変更できます。

#だがしかし
UTF-8の環境から上記サーバにsshでログインしてみてください。文字コードがUTF-8になってます。

```
$ echo $LANG
ja_JP.UTF-8
```

なんでや！

原因追及に時間がかかりましたが、/etc/ssh/sshd_configの設定で環境変数LANGなどが引き継がれていました。

EUC-JPのサーバで以下の修正を行ってください。（関係ありそうなのをすべて止めてます。一つ一つ確認していません）

```
/etc/ssh/sshd_config
# 以下の行をすべてコメントに変更
#AcceptEnv LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES
#AcceptEnv LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT
#AcceptEnv LC_IDENTIFICATION LC_ALL LANGUAGE
```

sshdの再起動。

```
$ /sbin/service sshd restart
```

以上で引き継がれなくなると思います。


# Emacsの設定

EUC-JPに文字コードを変更します。

```~./emacs
; 加筆
(set-language-environment "Japanese")
(set-terminal-coding-system 'euc-japan)
(set-keyboard-coding-system 'euc-japan)
(set-buffer-file-coding-system 'euc-japan)
(setq default-buffer-file-coding-system 'euc-japan)
(prefer-coding-system 'euc-japan)
(set-default-coding-systems 'euc-japan)
(setq file-name-coding-system 'euc-japan)
```

これでデフォルトで文字コードがEUC-JPになると思います。

# Sambaの設定

文字コードを指定してください。この文字コードの指定はsambaが作成するファイル名のみに影響します。Sambaで共有するファイルの本文は影響しません。

```/etc/samba/smb.conf

[global]
        ....
        unix charset = EUCJP-MS
        ....
```

以上で、とりあえずEUC-JPで動いていますが、なんか不具合があれば加筆します(^_^;
Linuxディストリビューションのバージョン確認方法

Linuxディストリビューションのバージョンは `○○-release` というテキストファイルに記述されているので、 `cat` コマンドで出力することで確認できます。
ディストリビューションごとにファイル名が異なります。

## CentOS

```bash
$ cat /etc/centos-release
CentOS Linux release 7.3.1611 (Core)
```

## Ubuntu

```bash
$ cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=16.04
DISTRIB_CODENAME=xenial
DISTRIB_DESCRIPTION="Ubuntu 16.04.3 LTS"
```
Android開発で繰り返しググちゃうこと（kotlin編）

Android開発をしていて、よく忘れて調べることを追加していきます。

### Actionbarのタイトルを変更する

```kotlin
supportActionBar?.title = ""
```

### Actionbarに戻るボタンを表示する
onCreateなどに下記を追加

```kotlin
supportActionBar?.setDisplayHomeAsUpEnabled(true)
```

下記リスナーをオーバーライド

```kotlin
override fun onSupportNavigateUp(): Boolean {
    finish()
    return super.onSupportNavigateUp()
}
```

トップの階層では表示させたくない場合は下記で判定できる

```kotlin
// バックスタックにFragmentがある場合のみ戻るボタンを表示する
val canback = supportFragmentManager.backStackEntryCount > 0
supportActionBar?.setDisplayHomeAsUpEnabled(canback)
```

### 画面を縦固定にする
Activityの定義にandroid:screenOrientationを指定する

```xml:AndroidManifest.xml
<activity
    android:name=".Presentation.Activity.HogeActivity"
    android:screenOrientation="portrait" />
```

### 数字をカンマ区切で表示したい

```kotlin
// 2,000と表示したい
"%,d".format(2000)
```

### TextViewに打ち消し線を入れる
```kotlin
val textView = findViewById(R.id.text_view)
val paint = textView.paint
paint?.flags = Paint.STRIKE_THRU_TEXT_FLAG
// 線がギザギザにならないようにアンチエイリアスを有効にする
paint?.isAntiAlias = true
```

### 1行でif/elseを書く

```kotlin
val nextPage = if (page == 0) 1 else page + 1
```

### ImageAssetsを使用したアイコン生成方法
https://developer.android.com/studio/write/image-asset-studio.html?hl=ja
CircleCI2.0を使ってGoで開発したツールをLint,UT,ビルドしてGithubにリリースする


この記事は [LIFULL Advent Calendar 2017](https://qiita.com/advent-calendar/2017/lifull)の10日目の記事です。
株式会社 LIFULL 技術開発部の冨田です。

## はじめに

社内でも[自分自身の開発しているツール](http://github.com/tomiyan/pmd2cs)でもCircleCI2.0を利用し始めるようになりました。

今回は下記のように動作するように設定しました

* リモートにブランチをpushした時にLint,UT,カバレッジ計測する
* リモートに「v[0-9]+(\.[0-9]+)*」タグをpushした時にBuildしてGitHubにバイナリをアップロードする

## 環境

* Go 1.9
* [CircleCI 2.0](https://circleci.com) CIサービス
* [codecov.io](https://codecov.io/) コードカバレッジ可視化できるサービス
* [golint](https://github.com/golang/lint) Linter
* [goverage](https://github.com/haya14busa/goverage) 複数パッケージを1発でカバレッジ計測できるツール
* [gox](https://github.com/mitchellh/gox) 複数OS、アーキテクチャをビルドできるツール
* [ghr](https://github.com/tcnksm/ghr) GitHub Release pageにビルドしたバイナリをアップロードするツール

## CircleCIの環境変数

CircleCIのコンソールからSettingsでリポジトリごとのEnvironment VariablesでTOKENを登録しておきます

* CODECOV_TOKEN
	* https://codecov.io/ でリポジトリを選択するとTOKENが発行されるのでそれを利用します
* GITHUB_TOKEN
	* https://github.com/settings/tokens/new で public_repo を選択してTOKENを発行します

## CircleCIの設定ファイル

プロジェクト直下に.circleci/config.ymlを作成します
working_directoryは適宜変更してください

```yaml:.circleci/config.yml
version: 2
jobs:
  build:
    environment:
      - GOPATH: /home/circleci/go
    docker:
      - image: circleci/golang:1.9
    working_directory: /home/circleci/go/src/github.com/tomiyan/pmd2cs
    steps:
      - run: echo 'export PATH=${GOPATH}/bin/:${PATH}' >> $BASH_ENV
      - checkout
      - run: go get -v -t -d ./...
      - run: go get github.com/golang/lint/golint
      - run: go get github.com/haya14busa/goverage
      - run: golint ./...
      - run: go vet ./...
      - run: go test -v -race ./...
      - run: goverage -coverprofile=./coverage.text ./...
      - run: bash <(curl -s https://codecov.io/bash)
  deploy:
    environment:
      - GOPATH: /home/circleci/go
    docker:
     - image: circleci/golang:1.9
    steps:
      - run: echo 'export PATH=${GOPATH}/bin/:${PATH}' >> $BASH_ENV
      - checkout
      - run: go get -v -t -d ./...
      - run: go get github.com/mitchellh/gox
      - run: go get github.com/tcnksm/ghr
      - run: gox -output "${GOPATH}/pkg/{{.Dir}}_{{.OS}}_{{.Arch}}"  ./ ./...
      - run: ghr -u $CIRCLE_PROJECT_USERNAME $CIRCLE_TAG $GOPATH/pkg/

workflows:
  version: 2
  build:
    jobs:
      - build:
          filters:
            branches:
              only: /.*/
  deploy:
    jobs:
      - deploy:
          filters:
            branches:
              ignore: /.*/
            tags:
              only: /v[0-9]+(\.[0-9]+)*/
```

これで完了です
CircleCI2.0で開発が自動化できますね🍻

## ハマりどころ

私はPATHとgit tagのフックでハマりました

### PATHの通し方

environmentにPATHを設定しても反映されません

```yaml
run: echo 'export PATH=${GOPATH}/bin/:${PATH}' >> $BASH_ENV
```

のような形でstepのrunで指定する必要があります

### git tagのフック

jobsのdeployに直接filtersを記述しても作用しません
workflowsでfiltersを記述する必要があります
また、branches ignoreをしていしないと、branch push時にもフックしてしまいます

## 参考文献

* https://github.com/tcnksm/ghr
* [Go の CI で Lint と カバレッジ回して非人間的なレビューは自動化しよう in 2016年](http://haya14busa.com/ci-for-go-in-end-of-2016/)
DNSを監視して動的にipfwのルールを追加/削除するツール．

本文は「FreeBSD Advent Calendar 2017」の10日の記事です。
https://adventar.org/calendars/2797

1.事の発端

職場のメール環境は某大手メーカーが提供しているメールサービス上(本文では以降「クラウド」と書きます。)にあるのですが、FreeBSD上で構成したルータの/etc/rc.firewallにSMTP/IMAP用の穴をあけときました。

```
${fwcmd} add allow tcp from LOCAL-IP to SMTP-SERVER smtps,submission setup
${fwcmd} add allow tcp from LOCAL-IP to IMAP-SERVER imaps,pop3s setup
```

これなんですが、、、 専用サーバなら問題ないんですが、クラウドだとダメだったりします。実際設定直後は動作していましたが、しばらくして確認したらダメになっとりました。

理由は簡単です。クラウドサービスはIPアドレスがたまに変わります。

FreeBSDのFirewall(ipfw)は、hostnameを指定した場合でも名前参照は初回のみで、IPアドレスが変わっても動的に変化しません。

```
http://www.jp.freebsd.org/man-jp/search.html
日本語マニュアル RELEASE 10-1-RELEASE-K
ipfw抜粋

	numeric-ip | hostname
        ドットで区切った数字 4 つ組またはホスト名で指定した、1 つ
        の IPv4 アドレスが適合します。ホスト名の名前解決は、その
        規則がファイアウォールのリストに追加されるときに行われま
        す。
```

つまり、最初に挙げた設定は、専用サーバなら問題ありませんがクラウドだとダメなんですね。

2.DNSを監視してルールを追加削除する必要あります
同様の事で困った方はいるだろうと思ってMLの「FreeBSD-users-jp」に尋ねてみました。

>https://lists.freebsd.org/pipermail/freebsd-users-jp/2017-March/001055.html
>[FreeBSD-users-jp 96055] DNSを監視して動的にipfwのルールを追加/削除するツール．

すぐに回答いただきました！

> https://lists.freebsd.org/pipermail/freebsd-users-jp/2017-March/001056.html
> [FreeBSD-users-jp 96056] Re: DNSを監視して動的にipfwのルールを追加/削除するツール．

ありがどうございます。

3.実は、、
私のメール自動仕分けの設定が悪かったがため、メールを見落としていました(;_;)

返事がないと思い込み、自作のツールを作成していました。　せっかく作ったのでこちらで公開しています。

一応履歴機能がありまして、IPアドレスが変化してもしばらくは古いIPアドレスのルールを覚えている機能があります。

> https://github.com/githubmatumoto/ipfw-dns-kanshi
> ipfw-dns-kanshi

よろしければどうぞ(^_^;

以上です。
nodebrewが壊れた

# 概要

利用しているMacBookに入っているnodebrewを久しぶりに使おうとしたら

```
$ nodebrew install-binary latest
```

実施するとなぜか最新のnodeがインストールできなかった。
なんかダウンロードファイルが見えない的なエラーがでてた。

仕方ないのでなんとかしようと思った。

# 本来はこうすればよかったんだと思う(未確認)

```
$ nodebrew selfupdate
```

これでnodebrewをバージョンあげて利用する

# こんなことしてしまった。

brewでインストールしたものと思ってたんですが、どうやら別で入れてたみたい。

```
$ brew install nodebrew
```

でうまく動作しなかったので
完全に抹消したかった

```
$ cd 
$ rm -rf .nodebrew
```

これを実行してしまった。

```
$ brew install nodebrew
```

これでシステム的にnodebrewは入った。
ただし、次のような状態になってしまった。

```
$ nodebrew install-binary latest
-bash: /Users/taktod/.nodebrew/current/bin/nodebrew: No such file or directory
```

# こうやったら治った

```
$ cd .nodebrew/
$ ln -s /usr/local/opt/nodebrew current
```

これで.nodebrew/current/bin/nodebrewが見える状態になった。

```
$ nodebrew install-binary latest
$ node -v
v9.2.1
```

よかったよかった。
UniRxで複数のボタンが指定の順番で押されたかを判定する


## 解きたい問題

- ボタンが 3 つあるとします(それぞれ 1, 2, 3 番とする)
- ボタンが特定の順番で押されたときに限り、指定の処理を行いたい(よくあるパズル)

UniRx を使うと、外部に変数を定義することなく、オペレータの組み合わせのみで実現することができます。

## プログラム

以下は、ボタンが 1, 3, 2 の順番で押されたかどうかを判定するプログラムです。

```csharp
var o = Observable.Merge(
    _button1.OnClickAsObservable().Select(_ => _button1),
    _button2.OnClickAsObservable().Select(_ => _button2),
    _button3.OnClickAsObservable().Select(_ => _button3));

o.Buffer(3, 1)
    .Where(e => e[0] == _button1 && e[1] == _button3 && e[2] == _button2)
    .First()
    .Subscribe(e => Debug.Log("1, 3, 2 の順にボタンが押されました"));
```

- `Merge` で 3 つのボタンクリックイベントをマージ
- `Buffer` でボタンのクリックイベントを 3 つずつにまとめる
- `Where` で押された順番が 1, 3, 2 かどうかフィルタリング
- `First` で条件を満たした先頭要素のみ取り出す

## 正しいボタンが押されたときに何らかの処理を行いたい

- 押されたボタンが正しい手順と一致する場合は、そのボタンの色を変える
- 誤ったボタンが押された場合は、全てのボタンの色をリセットする(最初からやり直し)

プログラムは以下になります。

```csharp
var o = Observable.Merge(
    _button1.OnClickAsObservable().Select(_ => _button1),
    _button2.OnClickAsObservable().Select(_ => _button2),
    _button3.OnClickAsObservable().Select(_ => _button3));

o.Scan(0, (step, button) =>
{
    switch (step)
    {
        case 0: // はじめに _button1 を押したか
            if (button == _button1)
            {
                _button1.GetComponent<Image>().color = Color.gray;
                return 1; // 次のステップへ
            }
            break;

        case 1: // つぎに _button3 を押したか
            if (button == _button3)
            {
                _button3.GetComponent<Image>().color = Color.gray;
                return 2; // 次のステップへ
            }
            break;

        case 2: // さいごに _button2 を押したか
            if (button == _button2)
            {
                _button2.GetComponent<Image>().color = Color.gray;
                return 3; // Where でフィルタリングする値
            }
            break;
    }

    // 誤ったボタンが押されたときは、ボタンの色を初期値に戻す
    foreach (var b in new[] { _button1, _button2, _button3 })
        b.GetComponent<Image>().color = Color.white;

    return 0; // 最初のステップにもどる
}).Where(e => e == 3).First().Subscribe(e => Debug.Log("1, 3, 2 の順番にボタンが押されました"));
```

- `Merge` で 3 つのボタンのクリックイベントをマージ
- `Scan` でボタンの押された順番をチェック。進行状況を step で引き回す
- `Where` で条件を満たすものだけフィルタリング
- `First` で先頭要素のみ取り出す

`Scan` を使えば、今回の問題に限らず、イベントが特定の順番で発生したかを、内部処理だけで完結するように書けますね。