OmniAICreator/Qiita-1.07M huggingface dataset:
onFocusでsetStateするとonClickが実行されない

こんな感じの仕様のドロップダウンを実装するとします。

- クリックだけでなく、 Tab でフォーカスしたときにも開く
- クリックの場合はイベントをトラッキングしてからドロップダウンを開く

色々足りませんがこんな感じのコードを書いたとします:

```js
class Dropdown extends React.Component {
  open() {
    this.setState({ isOpen: true });
  }

  render() {
    return (
      <div
        tabIndex="0"
        onClick={e => {
          trackClickEvent(e).then(() => this.open());
        }}
        onFocus={this.open.bind(this)}
      >
        {/* ... */}
      </div>
    )
  }
}
```

しかし、このコードは意図したように動きません。クリック時に `onFocus` だけが実行されて `onClick` が実行されないのです。何故でしょうか？

## （おそらく）`onClick` が実行されない理由

まずブラウザの仕様として（要出典） フォーカス可能な要素をクリックすると、先に `FocusEvent` が発生し、その後でクリックによる `MouseEvent` が発生します。つまり `onFocus` が先に実行されます。

そして（React の中を追っていないので正確なところは分からないのですが） `onFocus` の中で `setState` すると次のフレームで再レンダリングされ、その過程で何かがあって `onClick` が実行されなくなります。

## 対処方法

`onFocus` の前に `onMouseDown` が実行されるので、 `onClick` の代わりにそちらを使うという方法があります:

```diff
      <div
        tabIndex="0"
-       onClick={e => {
+       onMouseDown={e => {
          trackClickEvent(e).then(() => this.open());
        }}
        onFocus={this.open.bind(this)}
      >
```

この場合たしかに `onMouseDown` が先に実行されるのですが、なぜか `onFocus` が実行されます :thinking: 


## おわりに

ちなみに同じく VDom を使っている [hyperapp](https://hyperapp.js.org/) でも同じような現象が発生するので、 React の問題というよりはブラウザの挙動なのではないかと思います。
Swift4でsubstringの処理で警告が出た際の修正方法

初投稿かつTipsレベルでもないかもしれませんが・・・

Xcodeをアプデしてエラーを取っていたら文字列操作に関して

![スクリーンショット 2017-09-26 16.57.14.png](https://qiita-image-store.s3.amazonaws.com/0/204184/fc66e6b0-9910-e711-710d-b0a6424b2608.png)

'substring(from:)' is deprecated: Please use String slicing subscript with a 'partial range from' operator.

というエラーを吐いていました。

今回のSwift4ではsubstring(...)が非推奨になった関係で警告が出ていたのでrangeを使って書き直しました。

具体的には

例えば "ABCD//EFGH" というStringの"//"以下を取り出して"EFGH"を取り出すために

Swift3では

``` Swift3
let data = "ABCD//EFGH"
let result = data.range(of: "//")

if let theRange = result{
    print(data.substring(from: theRange.upperBound))
}
```

このようにしていましたが

```
let data = "ABCD//EFGH"
let result = data.range(of: "//")

if let theRange = result{
    print(data[theRange.upperBound..<data.endIndex])
}
```
追記:もう少し簡潔な書き方もコメ欄で教えていただきました

と書き直すことで解決できました。
【メモ】移行開始規準_チェック項目

# 移行開始規準_チェック項目
　①　移行対象が明確か
　②　移行手順は明確か
　③　移行中の影響は洗い出されているか
　④　移行失敗時に発生する障害に関する対策はあるか
　⑤　上記①～④のリハーサルは行ったか
　⑥　移行スケジュールは明確か
　⑦　移行チームの体制や役割分担は明確か

# 移行完了判定規準_チェック項目

追って記載
[Swift] 読み上げ機能、簡単に使えるライブラリつくったよ

こんにちは。

読み上げ、音源ファイルの再生、を簡易化するライブラリをつくってみました。

# 特徴

・コード1行で実装できる (発音してほしいテキスト、言語を渡すだけです)
・発音の割り込み、スピード、トーンを調節できる
・発音開始、終了タイミングを感知できる
・国で言語指定できる (Country Codeを調べる必要ありません)
・37カ国の言語に対応している
・Swift4.0でも使える
・音源ファイルの再生も可能。終了タイミングを感知できる

ライブラリは[ こちら ](https://github.com/WataruMaeda/speaker)にあります。

# 対応する国とコード

アイルランド(en-IE), イギリス(en-GB), イスラエル(he-IL), イタリア(it-IT), インド(hi-IN), インドネシア(id-ID), オーストラリア(en-AU), オランダ(nl-NL), カナダ(fr-CA), ギリシャ(el-GR), サウジアラビア(ar-SA), スウェーデン(sv-SE), スペイン(es-ES), スロバキア(sk-SK), タイ(th-TH), チェコ(cs-CZ), デンマーク(da-DK), ドイツ(de-DE), トルコ(tr-TR), ノルウェー(no-NO), ハンガリー(hu-HU), フィンランド(fi-FI), ブラジル(pt-BR), フランス(fr-FR), ベルギー(nl-BE), ポーランド(pl-PL), ポルトガル(pt-PT), メキシコ(es-MX), ルーマニア(ro-RO), ロシア(ru-RU), 中国(zh-CN), 南アフリカ(en-ZA), 台湾(zh-TW), 日本(ja-JP), 米国(en-US), 韓国(ko-KR), 香港(zh-HK)

コード上[こちら](https://github.com/WataruMaeda/speaker/blob/master/Speaker/Speaker.swift#L147L184)で指定しています。

# インストール

Xcodeに手動でドロップします。[こちら](https://github.com/WataruMaeda/speaker/tree/master/Speaker)のソースをとりこんでください。

# 使い方

コード1行で完了です。

```Swift
Speaker.speech(text: "こんにちは！", language: "ja-JP")
```
上は言語で指定する方法です。国で指定する場合は以下のようになります。

```Swift
Speaker.speech(text: "こんにちは！", country: .Japan)
```

# 割り込みさせたい

読み上げ最中で、中断させて、再度読み上げさせたい場合、以下で実現できます。

```Swift
Speaker.speech(text: "こんにちはあ！！", country: .Japan, interrupt: true)
```
`interrupt`を追加することで、直前の読み上げを強制終了させます。デフォルトは`false`です。

# スピード変えたい

発音のスピードを調整したい場合、`rate`の値を変更してください。
最小値は`0.0`で、最大`1.0`まで指定できます。

```Swift
Speaker.speech(text: "こんにちはああ！！！", country: .Japan, rate: 1.0)
```

[*追記] 言語によって`rate`のデフォルト値は変化するようです。全ての言語を倍速、低速対応させたい場合、`AVSpeechUtteranceMaximumSpeechRate`または`AVSpeechUtteranceMinimumSpeechRate`をrateに指定してください。
デフォルトは`AVSpeechUtteranceDefaultSpeechRate`です。

```Swift
import AVFoundation

Speaker.speech(text: "倍速再生！！！", country: .Japan, rate: AVSpeechUtteranceMaximumSpeechRate)

Speaker.speech(text: "低速再生！！！", country: .Japan, rate: AVSpeechUtteranceMinimumSpeechRate)
```

# ピッチ変えたい

声の高さを変えたい場合、`pitch `を調整してください。
デフォルトは、`1.0`で、`0.5`〜`2.0`の区間で調節できます。

```Swift
Speaker.speech(text: "こんにちはあああ！！！！", country: .Japan, pitch: 1.0)
```
# 発音の開始、終了を感知したい

`started`、`finished`のコールバックを指定してください。

```Swift
Speaker.speech(text: "こんにちはああああ！！！！！", country: .Japan, started: {
  print("Started")
})
```

```Swift
Speaker.speech(text: "こんにちはああああ！！！！！", country: .Japan, finished: {
  print("Finished")
})
```

* 両方指定できます。

```Swift
Speaker.speech(text: "こんにちはああああ！！！！！", country: .Japan, started: {
  print("Started")
}, finished: {
  print("Finished")
})
```

# 音源ファイル再生させたい

リソース名とタイプを指定してください。

```Swift
Speaker.play(resource: "sample", type: "mp3")
```

* 終了時のcallbackも指定できます。

```Swift
Speaker.play(resource: "sample", type: "mp3", finished: {
  print("Finished")
})
```

# 開発環境

iOS 8+
Swift 3.0+
Xcode 8.0+
LVM関係のコマンドを実行すると"connect() failed on local socket: No such file or directory"が表示される

現象

LVM関係のコマンドを実行すると

```
  connect() failed on local socket: No such file or directory
  Internal cluster locking initialisation failed.
  WARNING: Falling back to local file-based locking.
  Volume Groups with the clustered attribute will be inaccessible.
  No volume groups found
```

このような警告メッセージが表示されてしまう。

解決策

Cluster LVMが有効になっているので次のコマンドで無効にする
```lvmconf --disable-cluster```
[Survey] Kaggle - Instacart 12位解法まとめ

Kaggle - Instacart Market Basket Analysis[^1]の1位解法[^2]の調査記事です．

Title: 12th solution
Name: plantsgo
Kaggle Discussion: https://www.kaggle.com/c/instacart-market-basket-analysis/discussion/38110
Code: https://github.com/plantsgo/Instacart-Market-Basket-Analysis/tree/master


## モデル

- ユーザーがどの商品を買うか
- 次の注文があるかどうか

## 特徴量

- 製品の特徴量
- 通路の特徴量
- 部門の特徴量
- 注文順からなる特徴量
- ユーザーの特徴量
- ユーザー x 注文順からなる特徴量
- ユーザー x 製品の特徴量
- ユーザー x Aisleの特徴量
- ユーザー x 部門の特徴量

## データ

- 訓練データとして直前の注文も追加.(2回前も追加してみたが，改善は見られなかった)

## アンサンブル

```
all["label"] = 0.28 * all["prediction_arbor"] + 0.12 * all["prediction_lgbm"] + 0.36 * all["label_2"] + 0.24 * all["label_1"]
```

- arbor: arboretum[^3]
- lgbm: LightGBM
- label1: ユーザーごとに分けて学習
- label2: 全てシャッフルして学習

## 備考

- FaronのF1最適化[^4]を利用．

## Refererences

[^1]: Kaggle, [Instacart Market Basket Analysis](https://www.kaggle.com/c/instacart-market-basket-analysis)
[^2]: plantsgo, [12th solution](https://www.kaggle.com/c/instacart-market-basket-analysis/discussion/38110)
[^3]: sh1ng, [arboretum](https://github.com/sh1ng/arboretum)
[^4]: Faron, [Get Expected F1-Score in O(n²)](https://www.kaggle.com/c/instacart-market-basket-analysis/discussion/37221)
Windows10 で laradock を使用し、複数のlaravelプロジェクトのローカル実行環境を作る

# 実行環境
- Windows10
- composer git インストール済み

# 想定
laravel で testproject を作り、ドメインを testproject.local で設定し、http://testproject.local:8080/ でブラウザから実行できるようにする
#### 複数のプロジェクトを保存するディレクトリ
	c:\project\
#### Webサーバ
	nginx
#### DBサーバ
	mysql

# ドメインの設定
ブラウザ等で確認する際に、ドメインでローカルサーバにアクセスするようにする

#### メモ帳を管理者権限で実行し下記ファイルを開く
	C:\Windows\System32\drivers\etc\hosts
	
#### 下記を追加し保存
	127.0.0.1 testproject.local
	
# laravel でプロジェクトを作成
#### コマンドプロンプトを起動し下記を実行
	cd c:\project\
	composer create-project --prefer-dist laravel/laravel testproject

# docker for windows (stable)をインストール
インストール時のバージョンは(varsion 17.06.2-ce-win27)でした

ダウンロード元
https://docs.docker.com/docker-for-windows/install/

Stable channel をダウンロード後実行し、手順に従ってインストール


# laradock をインストール
laradock を ダウンロード後初期設定
#### コマンドプロンプトを起動し下記を実行
##### laradock を git で clone
	cd c:\project\
	git clone https://github.com/Laradock/laradock.git

 (コマンドの例だがSourceTree等からでも問題なし)

##### 実行に必要なファイルをコピー
	cd c:\project\laradock
	copy env-example .env


# laradock の設定
dockerのコンテナの基本的な設定値は .env に記載してあるので変更可能
どうしても .env にない値を変更したい場合は /docker-compose.yml を直接編集

phpmyadmin はデフォルトポートが 8080 だったので
nginx の待ち受けポートを 8000 に変更（.env 内の NGINX_HOST_HTTP_PORT=8000）

application のパスは一階層がデフォルトなので変更なし
##### 例)
	c:\
		project/
			laradock/
			testproject/
と他のプロジェクトは laradock と同一階層に設定する

# nginx の設定
#### コマンドプロンプトを起動し下記を実行
	cd c:\project\laradock\nginx\sites
	copy laravel.conf.example testproject.conf
	
#### testproject.conf の主な変更点
	
##### サーバ名の変更（hostsで設定したドメインに変更）
	server_name testproject.local;
	
##### パスの変更(先ほど設定した laradock の application のパス は /var/www/ がベースになるので c:\project = /var/www/ なので c:\project/testproject/public は /var/www/testproject/public になる)
	root /var/www/testproject/public;

##### エラーログファイルの変更(ファイルの置き場所は変えずファイル名のみ変更)
	error_log /var/log/nginx/testproject_error.log;
	
##### アクセスログファイルの変更(ファイルの置き場所は変えずファイル名のみ変更)
	access_log /var/log/nginx/testproject_access.log;

以上の作業をtestprojectと書いてある箇所を各々のプロジェクト名に変更しプロジェクト毎に行う

# コンテナの起動
#### コマンドプロンプトを起動し下記を実行
	cd c:\project\laradock
	
##### 起動(nginx mysql phpmyadmin を起動する場合)
	docker-compose up -d nginx mysql phpmyadmin
	
##### 起動確認(プロセス)
	docker-compose ps
	
##### webサーバのエラー確認(laradock_nginx_1はプロセスリストにあった名前)
	docker logs -f laradock_nginx_1
	
##### ファイル変更等でワークスペースで作業を行う場合(artisanコマンド等の変更を行いたい場合)
	docker-compose exec workspace bash
	
##### コンテナを停止
	docker-compose stop

# mysql の設定
##### phpmyadmin の閲覧
	http://localhost:8080/
##### ログイン時の設定値
	サーバ:mysql
	ユーザ:default  (.env 内 PMA_USER にて設定)
	パスワード:secret  (.env 内 PMA_PASSWORD にて設定)

mysql本体は 3306 にて動作(デフォルトだと)

mysql にデータベース testproject を追加

# 各プロジェクトで.env を設定する
#### コマンドプロンプトを起動し下記を実行
	cd c:\project\laradock
	docker-compose exec workspace bash
	cd testproject/
	cp .env.example .env
	php artisan key:generate
	
# ブラウザから確認
	http://testproject.local:8080/

# 次回以降
	コンテナの起動
	↓
	ブラウザから確認
UiPathでRPAを実践してみる(9) ～例外処理を記述する～

UiPathはロジックを非常に簡単に記述できる半面、何かエラーがあった時の例外処理を、疎かにしがちかもしれません。
例えば下記の処理では、**既に起動している**メモ帳に、「これはテストです。」という文章を書き込んでいます。
![キャプチャ.PNG](https://qiita-image-store.s3.amazonaws.com/0/154110/489abc22-9cee-0ac8-c669-efd3040832e9.png)

もちろん、上記の前提通りメモ帳が既に起動していれば良いのですが起動していない場合は下記のエラーが発生してプログラムが停止します。
![キャプチャ2.PNG](https://qiita-image-store.s3.amazonaws.com/0/154110/9a13db99-b377-63e5-c742-4efc5d3c4d13.png)

Attachのデフォルトのタイムアウト時間は30秒ですから、ユーザーが手動で起動した場合には30秒待たされた挙句に、エラーが出るという悲しい事態になります…

これを避けるために例外処理を記述していきましょう。プログラムに親しんでいる方にはなじみがあると思いますが、`try～catch`を使っていきます。

Attach処理で右クリックをすると、`Sorround with Try Cath`があると思います。これを選択しましょう。
![キャプチャ4.PNG](https://qiita-image-store.s3.amazonaws.com/0/154110/904095d5-0f14-def5-0f02-fa6727c5a157.png)

下記の様に作成した処理が`Try`と`Catch`で囲われます。
![キャプチャ5.PNG](https://qiita-image-store.s3.amazonaws.com/0/154110/965e6cab-17c8-21b5-4cd7-525e7e823196.png)

この時点では:exclamation:が出ていて処理が実行できません。catchに適切な記述をするように求められています。
ここで、Catch句のExceptionを入力していきます。
今回エラーとなったのは、メモ帳が起動していなかったために起こった`SelectorNotFoundException`でした。(これは上記のエラーメッセージで確認できます。)
これを入力していきましょう。
選択肢には上記の例外は存在していないので、Browse For Typesを選択します。
![キャプチャ6.PNG](https://qiita-image-store.s3.amazonaws.com/0/154110/2f0d4b66-dfc6-f571-7076-5124088f22d3.png)

ここで、Catchしたい例外の名称を打ち込んで選択します。
![キャプチャ7.PNG](https://qiita-image-store.s3.amazonaws.com/0/154110/db7adee1-2a20-c7b8-a726-4a3b06f8e23e.png)

無事に設定されました。
![キャプチャ8.PNG](https://qiita-image-store.s3.amazonaws.com/0/154110/bb945353-0d22-7678-198f-4914f962ed07.png)

次に`catch`内で行いたい処理を記述しましょう。
今回のケースでは、とりあえずメモ帳を起動して「例外を補足しました！」をタイプする事にします。
![キャプチャ9.PNG](https://qiita-image-store.s3.amazonaws.com/0/154110/8853b4b8-9052-cefb-7cc3-7aa39c88d76f.png)
ここでは、ベタ打ちをしましたが以前書いた[Invoke](https://qiita.com/motuo/items/977c6455764ac24f5146)を組合わせると、同じロジックをあちこちで書かなくてよくなります。
この様にしてから、メモ帳を閉じた状態で処理を実行すると、メモ帳に「例外を補足しました！」という文字がタイプされます。メモ帳を閉じずに、もう一度実行すると、「これはテストです」がタイプされます。

また、例外には名前を付けられます。(例外のすぐ右側のexceptionがそれにあたります。)今回はデフォルト値のexceptionを使ってしまいましたが、複数の例外をCatchする場合には適切な名前を付けましょう。

最後に、`Finally`です。こちらは、正常系の場合でも例外の場合でも必ず通る処理となります。
とりあえずメモ帳を閉じる処理を入れておきましょう。メモ帳の場合は単純に閉じるだけですと、保存するかどうか聞かれてしまうのでイケていないのですが、業務アプリやブラウザも`Finally`で閉じるようにするとデスクトップ上に無用なプロセスが残らないので良いと思います。
![キャプチャ10.PNG](https://qiita-image-store.s3.amazonaws.com/0/154110/7dfb093e-5ed6-348d-75cb-0d3f283730e2.png)


UiPathを実際に使ってみると、様々なケースで例外が発生します。今回はメモ帳を再起動して処理をしましたが、例外の内容をログに書き込んでメール通知する等、他にも様々な使い道があります。
適切なエラーハンドリングは、ユーザーの使い勝手を向上させたり、障害を未然に防ぐことにつながりますので必ず意識するようにしましょう。
Gmailへのメールが迷惑メールに入ってしまう際にした対策4つ。

運用中のサービスにて、"送信するメールのうち、Gmailあてのものが、迷惑メールに入ってしまう。"、と言う事で、以下を実施しました。
※ちなみに、メールはPostfixとDovecotで社内で運用中。

# DKIM設定
メールサーバ(Postfix)にDKIMのインストール。
参考 => [Postfix + OpenDKIMで送信元ドメイン認証を実装するメモ](http://qiita.com/taku1201/items/3b2dffd950340b9726d0)	  
DNSによっては鍵が長すぎるとTXTレコードの登録でエラーになるので、1024で作成するのが良いかも知れません。

# SPF設定
DNS(以下はBindへの設定)に、a、ip4とip6を追加し、Namedの再起動。

```ruby:/var/named/chroot/var/named/(ドメイン).db.wan
(ドメイン). IN TXT "v=spf1 +a:(ドメイン) +ip6:0000:0000:000:0000:000:000:000:000 +ip4:000.000.000.000 ~all"
```
上記二つを設定すると、Gmailの受信メールのヘッダーは以下の様に"PASS"となります。
ここは自前DNSだったので結構大変でした...。
![スクリーンショット_2017-09-12_20_56_47.png](https://qiita-image-store.s3.amazonaws.com/0/6446/2699fce0-5769-526c-289e-bd3de29227f0.png)

# メールの暗号化
SSLの証明書をPostfixに設定。
参考 => [Postfixの証明書認証アレコレ](http://qiita.com/jem_3/items/23199dfcb8c1f8b2a3be)	
# DNSの逆引きを追加
メールサーバとして使用しているレンタルサーバーのコントロールパネルよりDNSの逆引きを追加。

```ruby:Terminal
Mymac:~ me$ dig -x xxx.xxx.xxx.xxx | grep mail
yyy.yyy.yyy.yyy.in-addr.arpa. 3600 IN	PTR	mail.DOMAIN.
```

#最後に
上記4つを設定しても、相変わらず迷惑メールに入っていたので、Googleに、該当受信メールのヘッダーを添付しスパム解除依頼を出した所、2ヶ月後くらいに迷惑メールに入らなくなっているのを気づいたと言う感じです。  
最終的にうまくいってよかったのですが、実際どれが効いたのかはわかりません。とりあえずセキュリティ的にやった方が良さげだよネ！と言う設定でした。
Debian 9 にDocker, Docker Composeをインストールする

記録するほどの事ではないですが、メモ書きとして

# 環境

* OS
    * Debian 9/amd64
    * SSHサーバとシステムユーティリティのみをインストール

https://docs.docker.com/engine/installation/linux/docker-ce/debian/
このページ通りにやると出来るんだけど、sudoが入ってないので、先に入れる

## 前準備

```
# apt-get install sudo
```

visudoを実行し、ログインしているユーザにsudoの権限を与える

```
# visudo

tatsuya ALL=(ALL:ALL) ALL
```

## Dockerの導入

```
$ sudo apt-get remove docker docker-engine docker.io
$ sudo apt-get update
$ sudo apt-get install \
     apt-transport-https \
     ca-certificates \
     curl \
     gnupg2 \
     software-properties-common
$ sudo curl -fsSL https://download.docker.com/linux/$(. /etc/os-release; echo "$ID")/gpg | sudo apt-key add -
```

KeyのFingerPrintが下記と一致していることを確認する

```
$ sudo apt-key fingerprint 0EBFCD88

pub   4096R/0EBFCD88 2017-02-22
      Key fingerprint = 9DC8 5822 9FC7 DD38 854A  E2D8 8D81 803C 0EBF CD88
uid                  Docker Release (CE deb) <docker@docker.com>
sub   4096R/F273FCD8 2017-02-22
```

```
$ sudo add-apt-repository \
   "deb [arch=amd64] https://download.docker.com/linux/$(. /etc/os-release; echo "$ID") \
   $(lsb_release -cs) \
   stable"
$ sudo apt-get update
$ sudo apt-get install docker-ce
```

下記コマンドで、HelloWorld出来れば成功

```
$ sudo docker run hello-world
```

## Docker Composeの導入

https://docs.docker.com/compose/install/#install-compose
これもこのページの通り

~~~
$ sudo curl -L https://github.com/docker/compose/releases/download/1.16.1/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
$ sudo chmod +x /usr/local/bin/docker-compose
$ docker-compose --version
docker-compose version 1.16.1, build 1719ceb
~~~
離脱防止モーダルを作ってみた

#離脱防止のモーダルの作成
離脱防止モーダルを作成したのでその時のメモ。

##コード
```js

const onBeforeunloadHandler = (e) => {
  const val = e;
  val.returnValue = '';
};

window.addEventListener('beforeunload', onBeforeunloadHandler);
```

##動き
この数行でユーザーがアクションを起こし、
ページ遷移をしようとすれば離脱防止のアラートが出てくる。

ちなみにdefaultで
「このサイトを離れてもよろしいですか？」とアラートが表示される。
val.returnValue = '';で
アラートに表示する文字を設定できたみたいなのですが
現在はできなくなっているみたいです。(でも、このコード入れないとエラー起こすかも)

##予想外の出来事
今回、実装にあたり予想外の出来事が起きた。
ページにアクセスしてアクション(スクロールしたり、クリックしたり)しないで
クローズボタン、戻るボタンを押すと離脱アラートが出てこない。

これは仕様らしいです。。
CSSで三角をつくる

CSSでボックスのかどっこに三角表示させたいとの要望があったのでメモです。

# HTML
```
<div class="sankaku_block">
  <div class="sankaku_border"><div class="sankaku"></div></div>
</div>
```

# CSS
```
.sankaku_block {
  border: 1px solid #000;
  width: 300px;
  height: 300px;
  position: relative;
}
.sankaku_border {
  border-left: 1px solid #000;
  border-bottom: 1px solid #000;
  position: absolute;
  right: 0;
  top: 0;

}
.sankaku{
  width: 0;
  height: 0;
  border: 10px solid transparent;
  border-top: 10px solid #00f;
  border-right: 10px solid #00f;
  border-bottom: 10px solid #f00;
  border-left: 10px solid #f00;
}
```

![スクリーンショット 2017-09-26 14.59.21.png](https://qiita-image-store.s3.amazonaws.com/0/170830/c2c50015-32e8-1acc-f99c-f1e413310591.png)
Apacheのよく忘れるコマンド

# Apacheのよく忘れるコマンドメモ

よく忘れるというか、覚えられないからaliasにしているけど、誰かの検索のとっかかりになればという思いで書く。

### 目次

* Apacheが読み込んでいるモジュールを確認
* Apacheの設定確認
* VirtualHostの一覧を表示


## コマンド

#### Apacheが読み込んでいるモジュールを確認

```
$ httpd -M
```

#### Apacheの設定確認

```
$ httpd -S
```

#### VirtualHostの一覧を表示

> Apacheの設定確認でも出ますが、こちらだとVirtualHostの一覧だけが表示されます。

```
$ httpd -t -D DUMP_VHOSTS
```

---

随時更新予定です。
必須だろこれ！っていうのがあったら教えてください！！
[AWS Directory Service] Microsoft ADのセットアップ手順

#AWS Directory Serviceとは

ユーザー、グループ、コンピューター、およびその他のリソースといった組織についての情報を含むディレクトリ機能を提供するマネージド型サービス。

#MicrosoftADセットアップ

サービスメニューから[Directory Service]を検索。

![AD01.png](https://qiita-image-store.s3.amazonaws.com/0/174392/9d896b7c-9daf-b14f-3f96-bfa7c44d0030.png)

今回はMicrosoftADのセットアップなので、[MicrosoftAD]を選択。

![AD02.png](https://qiita-image-store.s3.amazonaws.com/0/174392/46377742-6793-d401-fc73-b8b3e3ce3693.png)

ディレクトリDNS：ActiveDirectory名(ex.xxxxx.intra)
VPC：ADを作成するVPCを設定する

![AD03.png](https://qiita-image-store.s3.amazonaws.com/0/174392/14ecd04b-6204-15cd-d70a-921df837369f.png)

確認画面　＞　MicrosoftADの作成をポチッとすると。

![AD04.png](https://qiita-image-store.s3.amazonaws.com/0/174392/2c13f578-a569-4833-3d35-ad89c5f33318.png)

ADの作成が開始されます！

![AD05.png](https://qiita-image-store.s3.amazonaws.com/0/174392/88598e56-16e1-5e90-e546-6aae916d3bbe.png)


#Windowsサーバの登録

構築したwindowsサーバにログインし、まずはネットワークの設定から。
注意点として、windowsサーバとADは同じVPCである必要があります。
コントロールパネルからネットワークの設定へ、DNSサーバのIPを登録します。※ADの設定を行った際に取得したもの。

![AD11.png](https://qiita-image-store.s3.amazonaws.com/0/174392/82bbab0e-d359-f091-88ff-e37f115a7394.png)

続いて、コントロールパネル＞システムとセキュリティから設定の変更。

![AD07.png](https://qiita-image-store.s3.amazonaws.com/0/174392/1349193e-4c16-27ad-1d86-1e02638d428a.png)

コンピュータ名：任意
ドメイン：AD登録を行ったドメイン名

![AD08.png](https://qiita-image-store.s3.amazonaws.com/0/174392/6ac7153a-d854-094a-94fe-7d634d097c26.png)

OKすると管理者情報の入力を求められます。

ユーザー名：Admin
パスワード：作成時に設定したパスワード

無事にログインが完了したら再起動を行って設定は完了です。
componentDidUpdateでsetState()が実行できない？

# 「componentDidUpdateでsetState()が実行できない」っていう情報を先輩から教わりました。

メモです。
全く知らない情報　かつ　なぜ禁止されているかがわからなかったので調べました。

この[stack overflow](https://stackoverflow.com/questions/30528348/setstate-inside-of-componentdidupdate)に回答がありました。

> You can use setStateinside componentDidUpdate. The problem is that somehow you are creating an infinite loop because there's no break condition.

要は無限ループになっちゃうよっていう意味ですよね。

`componentDidUpdate()`の中で`setState()`すると、また`componentDidUpdate()`が動作してしまうから・・・っていう感じですよね。

言われてみれば確かに！
ag(The Silver Searcher)で検索かけても出てこないファイルがある

## agとは
[The Silver Searcher](https://github.com/ggreer/the_silver_searcher)
要するに早い `ack` とか `grep` みたいなもの

## 検索されないファイルがある問題
仕事で「`ack`だと検索でひっかかるけど `ag` だとひっかからない」状況に遭遇した。
状況調べてみると、ひっかからないファイルは `UTF-8` 以外の文字コードであるらしい。`SHIFT-JIS`, `EUC-JP`, `nkf -g` すると `BINARY FILE`と表示されるがなぜか動いているやつ etc...

## 対処法
`UTF-8` を使う。
というのは冗談で、いや冗談でもなくて現代で使っていないほうがおかしいんだけど、それはそうとして検索でひっかかってほしい。`ack` は遅いから `ag` で検索かけたい。
ので、とりあえず `ag -a` でオプションつけて検索かけると、 `Binary file {something file} matches.` みたいにひっかかるのでちょっと嬉しい。ただ、マッチした文字列ハイライトして表示してくれないのでそこはなんとか目でがんばることにした。
`alias ag="ag -a"` とかで alias はっておくとちょっと幸せになりました。

## 余談
最初から [The Platinum Searcher](https://github.com/monochromegane/the_platinum_searcher) 使え説、あります。
OpenJ9 を試す

[OpenJ9](http://www.eclipse.org/openj9/) とか言うものが Java 9 と同時にリリースされてたのでちょっと気になってた。
トップページに以下のような文言が。

> # Boost your Java application performance
>
> Low memory footprint. Fast start-up time. High application throughput.
> Optimized to run Java applications cost-effectively in the cloud.
> Want an OpenJDK build that contains an enterprise grade, open source, Java virtual machine?
> Grab a pre-built binary and try it for yourself...

処理が早いのか？JVMより起動が早いのか？メモリ使用量が少ないのか？
などなど気になりますが、とりあえず処理速度の面で見てみます。

## 免責

仕事の息抜きにスーパー雑にやっただけなので、ちゃんとした詳細なベンチは他の方のを御覧ください。

## 環境

- Vagrant 1.9.1
- 使用Box: [ubuntu/xenial64](https://app.vagrantup.com/ubuntu/boxes/xenial64)
- 3つの仮想環境にそれぞれ [JDK8](https://adoptopenjdk.net/releases.html?variant=openjdk8) / [JDK9](https://adoptopenjdk.net/releases.html?variant=openjdk9) / [JDK9+OpenJ9](https://adoptopenjdk.net/releases.html?variant=openjdk9-openj9) をインストール

## コード

```java:test.java
import java.math.*;

public class test {
    final static int LOOP_COUNT = 1_000_000_000;
    public static void main(String[] args) {
        BigInteger bi = BigInteger.ZERO;
        for(int i = 0; i < LOOP_COUNT; i++) {
            BigInteger _bi = BigInteger.valueOf(i);
            bi = bi.add(_bi);
        }
        System.out.println(bi);
    }
}
```

10億回ループして足すだけの目も当てられない雑なコード。

## 計測方法

```bash
javac test.java
time java test
```

雑な計測。

## 結果

### JDK8

```bash
$ time java test
499999999500000000

real	0m31.215s
user	0m22.668s
sys	0m7.332s
```

### JDK9

```bash
$ time java test
499999999500000000

real	0m24.734s
user	0m18.532s
sys	0m4.936s
```

### JDK9 + OpenJ9

```bash
$ time java test
499999999500000000

real	0m54.416s
user	0m48.192s
sys	0m4.500s
```

------

「あれ、なんか間違えたかな…」って気分になりました。

メモリ使用量は Minecraft の JVM として使ってみると実感できるかも？(適当)
UnityでAndroid端末の音量を操作する

UnityからAndroid端末の音量を操作したかったのでやり方を調べました。Androidでは[AudioManager.setStreamVolume](https://developer.android.com/reference/android/media/AudioManager.html#setStreamVolume(int, int, int))を使うことでプログラムから音量を変えることができるので、このAPIをUnityから叩いてみようと思います。

結論からいうと、以下のようなコードで実装できます。

```csharp
private static readonly int STREAM_MUSIC = 3;

public static void SetVolume(int volume) {
  var UnityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
  var context = UnityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
  var audioManager = context.Call<AndroidJavaObject>("getSystemService", "audio");
  audioManager.Call("setStreamVolume", STREAM_MUSIC, volume, 0);
}
```

`volume`は音量レベルを指定します。指定可能な値は0から[AudioManager.getStreamMaxVolume](https://developer.android.com/reference/android/media/AudioManager.html#getStreamMaxVolume(int))で取得できる値までです。
問答無用で端末の音量を最大にしたい時は、以下のようにします。

```csharp
var maxVolume = audioManager.Call<int>("getStreamMaxVolume", STREAM_MUSIC);
SetVolume(maxVolume);
```

音量を絶対指定するのではなく、現在の音量から上げ下げする場合は、[AudioManager.adjustStreamVolume](https://developer.android.com/reference/android/media/AudioManager.html#adjustStreamVolume(int, int, int))を使います。

```csharp
private static readonly int STREAM_MUSIC = 3;

// volume には以下のいずれかを渡す
private static readonly int ADJUST_LOWER = -1;
private static readonly int ADJUST_SAME = 0;
private static readonly int ADJUST_RAISE = 1;

public static void AdjustVolume(int volume) {
  var UnityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
  var context = UnityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
  var audioManager = context.Call<AndroidJavaObject>("getSystemService", "audio");
  audioManager.Call("adjustStreamVolume", STREAM_MUSIC, volume, 0);
}
```

より詳しくは、[AudioManager](https://developer.android.com/reference/android/media/AudioManager.html)のドキュメントを見てください。
プログラミング言語別：高階関数名比較表

| 言語 | 型 | 変換 | 選択 | 畳込 | 反復 | 全称 | 特称 |
|:--- |:---:|:---:|:---:|:---:|:---:|:---:|:---:|
| Java | [`Stream`](https://docs.oracle.com/javase/jp/8/docs/api/java/util/stream/Stream.html) | `map` | `filter` | `reduce` | `forEach` | `allMatch` | `anyMatch` |
| JavaScript | [`Array`](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array) | `map` | `filter` | `reduce` | `forEach` | `every` | `some` |
| PHP | [`Array`](http://php.net/manual/ja/ref.array.php) | `array_map` | `array_filter` | `array_reduce` | `foreach` <br><sub>(syntax)</sub> | N/A | N/A |
| Python | N/A | [`map`](https://docs.python.jp/3/library/functions.html#map) <br><sub>(built-in)</sub> | [`filter`](https://docs.python.jp/3/library/functions.html#filter) <br><sub>(built-in)</sub> | [`functools.reduce`](https://docs.python.jp/3/library/functools.html#functools.reduce) | `for...in` <br><sub>(syntax)</sub> | N/A | N/A |
| Ruby | [`Enumerable`](https://docs.ruby-lang.org/ja/latest/class/Enumerable.html) | `map`, `collect` | `select` | `reduce`, `inject` | `each` | `all?` | `any?` |

- 言語はアルファベット順
- 随時更新
- **編集リクエスト大歓迎** 🎉 🎉 🎉
Hyper-Vを使ったdocker-machineのネットワークのためのNAT

# WindowsNATが作れない人向け
記事が長くなるため、Dockerホストのネットワークの設定は別記事でまとめます。
Windows10からPowerShell上でWindowsNATと呼ぼれるNATを作成できるため、本記事は、WindowsNATが作れない(もしくは何らかの理由でうまく動かない)人向けとしています。
また、WindowsNATは一つしか作れないため、複数のNATが欲しい時に良いかもしれません。
本記事では、NATとしてソフトイーサのSecureNATを利用します。
この記事でNATを構成すると、以下のような構成になります。
![図1.png](https://qiita-image-store.s3.amazonaws.com/0/194293/681c2d31-350d-189d-7283-c322f91720a4.png)

## 行う流れ
1. SoftetherVPN(サーバとクライアント)をインストール
2. 仮想HUBを作る
3. 仮想HUBにSecureNATを作る
4. SoftEtherVPNの仮想NICを作りIPを静的に決める
5. 仮想HUBにSoftEtherVPNの仮想NICを繋ぐ
6. Hyper-Vマネージャから仮想スイッチを作る。

## 1. SoftEtherVPN(サーバとクライアント)をインストール
使用する端末ではSoftEtherVPNのサーバとクライアント両方とも入れます。
特に気をつけるところもないため、普通にインストールしてください。

## 2. 仮想HUBを作る
SoftEtherVPNで仮想HUBを作ります。図ではSecureNATがホストOSのNICとブリッジと書いてありますが、実際はこの仮想HUBがブリッジしています。

## 3. 仮想HUBにSecureNATを作る
SecureNATを有効にします。DHCPを有効にするかどうかは好みで。
私は払い出しするIPを一つにしてDHCPで実質固定IPにしています。
そして、任意のネットワークにつながっているNICと仮想HUBをブリッジします。
無線LANのNICの場合そのままではブリッジできないため、[ここ](https://ja.softether.org/4-docs/3-kb/VPNFAQ003)を見てconfigを設定します。ShowAllInterfacesとNoPromiscuousModeをtrueにします。
また、複数のパソコンが存在する場合、アクセスリストでSSDPとLLMNRパケット(どちらもUDPでポートはそれぞれ1900と5355)を破棄するようにしておくと良いです。
これは仮想HUBのIPアドレステーブルが溢れないようにするためです。

## 4. SoftEtherVPNの仮想NICを作る
SoftEtherVPNで仮想NICを作りましょう。

## 5. 仮想HUBにSoftEtherVPNの仮想NICを繋ぎ、IPを静的に割り振る
4.で作ったNICを仮想HUBにつなぎます。この仮想NICはIPを静的に割り振ります。DockerホストのNICに実質固定のIPを振らない場合はDHCPで取得しても良いです。

## 6.Hyper-Vマネージャから仮想スイッチを作る。
Hyper-Vマネージャから仮想スイッチを作ります。この仮想スイッチは種類は外部ネットワークに設定し、接続先は先程作った仮想NICにします。そして、管理オペレーティングシステムに～のチェックボックスをつけます。

ここまでで、Dockerのネットワーク以外のネットワークが作成できました。続きます。
Mastodonアップデート手順（基本）・非Docker版

# 前提条件
* 非Docker
* Mastodonは、公式の手順で構築済みであること。

# 制限事項
* 本手順は、CentOS 7 にて使用したものである。
* Fedora Server (28) でも使えている。

# 特記事項
* アップデート作業後、CSS・画像ファイル等にアクセスが出来なくなった場合(403)は、Nginxの実行ユーザを「mastodon」に切り替えることで対応可能

# 手順

**(重要)まず、公式のリリースノートを読み、手順を確認する。**
https://github.com/tootsuite/mastodon/releases

**以下に示す手順を鵜呑みにせず、公式の手順通り行うこと。**


だいたい共通しているものを下に示す。

1. Mastodonのサービス3点セットを止める
1. データベースのバックアップを取る
1. Mastodon専用ユーザに切り替える
1. タグ一覧から任意のバージョンに上げる
1. 依存パッケージのインストールを行う
1. データベースマイグレートを行う（変更なしの場合は空振りするのでOK）
1. アセットのプリコンパイルを行う
1. Mastodonのサービス３点セットを動かす


## 前準備

Mastodon3点セットを止めて、mastodonユーザになる

```bash
sudo systemctl stop mastodon-{web,sidekiq,streaming}

sudo su - mastodon
```

## データベースバックアップ

```bash
# DBが同一ホストで動いている場合
pg_dump --username=mastodon --no-owner mastodon > mastodon.`date +%Y%m%d_%H%M%S`.pgdump

# DBのホストが違う場合
pg_dump --host=10.1.1.20 --username=mastodon --no-owner mastodon > prefix.`date +%Y%m%d_%H%M%S`.pgdump
```

`--no-owner` オプションは必須ではない。異なる環境にデプロイする場合にオーナー指定が邪魔になることがあるので、念のため付加している。


## パブリックディレクトリバックアップ

巨大になるので注意。可能ならしたほうがよいが必須ではない

```bash
# 先に、どのくらいのサイズ感か確認しておく
du -h -d 1 live/

# バックアップ（gzipかけても圧縮率80%程度な感じ）
tar -czf  public.`date +%Y%m%d_%H%M%S`.tar.gz live/public
```


## Gitでタグ指定アップデート

```bash
cd ~/live/

git fetch 
git tag
 
git checkout vX.X.X
 
bundle install && yarn install

# 他に必要な手順があればここで行う（前）

RAILS_ENV=production bundle exec rails db:migrate
RAILS_ENV=production bundle exec rails assets:clobber
RAILS_ENV=production bundle exec rails assets:precompile

# 他に必要な手順があればここで行う（後）

exit

sudo systemctl start mastodon-{web,sidekiq,streaming}
```

データベースマイグレーションが必要ないアップデートにおいて`db:migrate`を実行した場合、何も行われず空振りする。
空振りしたところで特に害はないはずなので、ルーチンワークとして念のため実行しておくとよいかもしれない。

`assets:clobber`を実行すると、生成済みのアセット(静的ファイル)を全てクリアする。
アセットのキャッシュが残りっぱなしになってディスク容量を浪費することがあるので、必要に応じて実行する。

どのバージョンからか不明だが、`assets:precompile`を実行すると`yarn install`も一緒に実行されるように見受けられる。
ので、前もって`yarn install`する必要はないのかもしれない。


# あとがき

* 自分用にメモした手順です。必要に応じて読み替えてください。
* ここ、こうしたほうがいいよ的なアドバイスを頂けると大変助かります。

以上
VMWare ESXi6.5とCatalyst3750をTrunk接続する際の設定方法

# VMWare ESXi6.5とCatalyst3750をTrunk接続する際の設定方法

### 概要

NICが一つだけのPCにESXi6.5をインストールし、ゲストOSには異なるVLAN（ポートグループ）のネットワークアダプタを2枚搭載する。
複数のVLANでの接続を実現するため対向のCatalystスイッチとTrunkで接続する。
今回は対向スイッチにCatalyst3750を用いた。
また今回ゲストOSには以下のネットワークが割り当てられるが、
　・192.168.3.0/24
　・192.168.4.0/24
デフォルトゲートウェイは192.168.3.0/24にのみ設定されるが、192.168.3.0/24と通信できないネットワーク上にあるPCがゲストOSに接続するため、192.168.4.0/24経由で通信させるため踏み台PCを用意する。
（192.168.4.0/24にはデフォルトゲートウェイが設定できないため、192.168.3.0/24, 192.168.4.0/24以外のネットワーク上にあるPCがゲストOSに接続するには192.168.4.0/24上に踏み台となるPCを別に配置する必要がある）

### Trunk処理について

今回の構成ではESXiのTrunk処理方法はVST Modeである。
VST ModeではvSwitchがタグの着け外しを自動的に行ってくれるため、Catalyst側のTrunk設定のみ行えば
ESXi側はVLAN IDの設定のみ行えばよい。

### 構成

ESXi本体、操作用PC、ゲストOS、ゲストOSへ接続する踏み台PCのネットワーク設定は以下の通り。

| Name | IP | Netmask | Default gateway | DNS |
|------|----|---------|-----------------|-----|
|ESXi|192.168.1.250|255.255.255.0|-|-|
|操作用PC|192.168.1.10|255.255.255.0|-|-|
|ゲストOS NIC1|192.168.4.247|255.255.255.0|-|-|
|ゲストOS NIC2|192.168.3.247|255.255.255.0|192.168.3.1|192.168.3.1|
|踏み台用PC|192.168.4.10|255.255.255.0|192.168.4.1|(適宜DNSのIP)|

VLAN（ポートグループ）は以下の通り。

| Name | VLAN ID |
|------|----|
|Management Network|10|
|VM Network|30|
|VM Network|20|

※VM Networkの順番とVLAN IDの順番は都合上逆にしている。

### 手順

1. Catalyst3750にVLAN10, 20, 30を作成

    ```
    (config)vlan 10
    (config-vlan)vlan 20
    (config-vlan)vlan 30
    ```

2. 検証としてVLANインターフェイスを作成

    ```
    (config)interface vlan 10
    (config-if)ip address 192.168.1.1 255.255.255.0
    (config-if)no shut
    (config-if)interface vlan 20
    (config-if)ip address 192.168.4.1 255.255.255.0
    (config-if)no shut
    (config-if)interface vlan 30
    (config-if)ip address 192.168.3.1 255.255.255.0
    (config-if)no shut
    ```

3. 操作用PCとESXiを通信させるため一時的にアクセスポートを設定
FastEthernet1/0/1と1/0/2に以下を設定しそれぞれ接続

    ```
    (config)interface range fastethernet1/0/1-2
    (config-if)switchport mode access
    (config-if)switchport access vlan 10
    (config-if)no shut
    ```

4. ESXiの設定完了後に接続するポートとしてfe1/0/23にTrunkを設定

    ```
    (config)interface FastEthernet1/0/23
    (config-if)switchport mode trunk
    (config-if)switchport trunk allowed vlan 1,10,20,30
    (config-if)switchport nonegotiate
    (config-if)switchport trunk encapsulation dot1q    (※不要かもしれない / Catalyst2960には設定不可)
    (config-if)no cdp enable    (※不要かもしれない)
    (config-if)spanning-tree portfast trunk    (※不要かもしれない)
    ```

5. ESXiをインストール、IDとパスワードを設定
　
6. ESXiにIP 192.168.1.250/24 を設定
　
7. PCにIP 192.168.1.10/24 を設定
　
8. PCからESXiのWebUIに接続
　
9. Management Network のVLAN ID を0から10に変更
　
10. ESXiをCatalystのfe1/0/23に接続し、TrunkリンクでPCとESXiが通信できるか確認
　
11. ESXiにVM Network2を作成し、VM NetworkをVLAN30、VM Network2をVLAN20に設定
　
12. ゲストがインストールできたらそれぞれ対応するIPを設定
CodeReading/CodeWriting

##はじめに
**JJUG CCC 2017 Spring**の登壇者が、こんな事を言ってました。
*「コードは書く時間よりも読む時間の方が長いんだから、読みやすいコードを書きましょう」*

また、**WEB+DB Press vol.99**にて、こんな記事がありました。
*「コードを書くのは人で、コードを読むのも人である」*

エンジニア歴4年目になる僕も、同じ事を思います。
各言語で、トレンドの書き方や最新バージョンの書き方があって、それを取り入れるのは賛成です。
自身の成長にも、プロジェクトの成長にも繋がると思いますし、コード自体もより良いものになっていくかと思うからです。

しかし、その一方で、**最新技術を使う自分に自己陶酔して周りが見えなくなっている人**もいるのが現実です。
また、**自信過剰で自分のコードに絶対的な自信を持っている人**もいるのも現実です。
~~言ってしまえば技術オナニー。~~

こういった人がプロジェクトに与える影響として主に考えられるのは「属人化」「開発効率の低下」といったところでしょうか。
一人で開発を進める分には良いかと思います。
しかし、会社は組織です。組織は他者とのコミュニケーションにより成り立ちます。そして、組織の人材は入れ替わります。
他者とのコミュニケーションが取れないコーディングをしたり、担当者がいなくなった途端に理解できる人がいなくなっては意味がありません。

読みやすいコード。
適切なコメント。
後任者に対してのドキュメント。

こういったものがあって初めて成り立ちます。

長くなりましたが、ここでは、コードの読み方や書き方を、簡単にまとめていきます。
(僕もまだペーペーなので、参考程度に...)


##コードリーディング
基本的にはこんなところでしょうか。

- 目的を持って読むこと
- スコープを意識すること

新人の時に、「コードを読め」とよく言われますね。
部下ができた人も、こんな指示をした事があるのではないでしょうか。

「コードを読む」のは手段であって目的ではありません。
コードを読む目的で考えられるのは、「言語理解」「コード規約理解」「仕様理解」「先人のイケてる実装/イケてない実装の理解」などでしょうか。
指示する側も、「新人だから言語理解してね」「プロジェクト固有の書き方があるからコード規約を理解してね」「コードから仕様を理解してね」と一言添えてあげると、優しいですね。

また、「コードを読め」と言われても、蓋を開けてみると数万〜数十万行ものコードがあって、どこを見ればいいのか分からない...といった事は多々あるかと思います。
スコープが広過ぎるというのは雲を掴むようなもので、手当たり次第に読み込んでも意味がなく、無駄に時間がかかります。
なので、今見なければならない機能や箇所を理解した上で、数万〜数十万行から、数千〜数百行にスコープを狭めていく事が大切です。
読むコードを無駄撃ちしないようにして、時間コストをかけないように心がけましょう。


また、読み続けるとコードレビューも出来るようになるので、気持ち悪いコードやディレクトリ構成をしていたら、PM/PLに相談してみるのも有りです。
最初は煙たがられますが、プロジェクトの将来性を考えると大事な事なので、ガンガン行きましょう。
英語のことわざにも`The squeaky wheel gets the grease.`とあります。ガンガン行きましょう。
~~正しい事を言って煙たがられるのもどうかしてますが。~~


##コードライティング
基本的にはこんなとろでしょうか。

- 適切なコメント
- スコープの狭い変数
- 分かりやすい命名
- 再利用可能なコード

「そんなの当たり前じゃん」と思ってる人もいるかと思いますが、実践できてない人がいるのも現状です。

特に僕が言いたいのは**適切なコメント**。
理由は二つあります。

1つ目は、**コーダーの意図を伝えるため**です。
コーダーは人間です。
人間は間違えますし、処理能力にも限界があります。
getXxx()というメソッド名なのに返却値がなかったり、setXxx()というメソッド名なのに何も設定していなかったり、あると思います。
処理が複雑になってくると、コーダー自身も理解が追いつかない...といった事もあるかと思います。
また、パフォーマンス向上が図れそうだけど、時間の都合上で止むを得ずクソコードを...といった事もあるかと思います。
そういった時に、コメントで`// aaaをbbbしてcccする(複雑でゴメンなさい)`とか`// TODO パフォーマンス改善の余地あり(後は任せた)`とか書かれていれば、後任者も修正しやすいです。
逆に、コメントが書かれていないと、後任者は「複雑な処理だけど崩していいのかな...」「パフォーマンス改善出来そうだけど理由があってわざと重い処理にしてるのかな...」と混乱を招きます。

2つ目は、**コードは大概英語**で書かれます。
これは完全に私事ですが、英語が苦手です。(ちゃんと英語を理解するようには努めてますよ！！！)
そもそも日本人の英語レベルはどのくらいなものなんでしょう。
と思ってざっくり調べたら、こんなのがありました。
[https://www.rarejob.com/englishlab/column/20160729-2/](https://www.rarejob.com/englishlab/column/20160729-2/)
[http://www.ivyleague-english.com/newpage5.html](http://www.ivyleague-english.com/newpage5.html)
[http://bellthrough.com/diary/japanese-english](http://bellthrough.com/diary/japanese-english)
やはり日本人全体として英語力が低いようです。
それなのに英語に頼るなんて.....と、英語が苦手な僕は思ってしまいます。(ちゃんと英語を理解するようには努めてますよ！！！)
そして、**コメント書かない主義の人**はこう言います。
*「綺麗な英語書いてればコメントなんて必要なくない？」*
~~こんなこと言ってる人に限って、気色悪い英語を使ったり、ルー語みたいにカタカナ英語使っていて、正直反吐が出る。~~

英語ばかり並んでるコードより、母国語である日本語が要所要所に入ってる方が落ち着かない？？僕だけ？？？(ちゃんと英語を理解するようには努めてますよ！！！)

スコープの狭い変数は、
　*一時的なものなんだからあちこちで使い回さずにすぐに殺せ。*
分かりやすい命名は、
　*変数が何を保持しているのか、メソッドが何を処理するのか、端的に表現しろ。*
再利用可能なコードは、
　*同じコードは書くな。同じになるなら外出しして他でも使えるようにしろ。拡張性大事。*
みたいな感じです。

****

最後に余談。
Qiita見てる人って、この記事の事くらい意識もしてるし、理解も実践もしてるよね。
実際に読んでほしいのはQiitaとか見ない人なんだけど、そういう人って以下略(
Shader経験皆無で始めるShader理解事始め

## Shader経験皆無で始めるShader理解事始め

※Unity ShaderLab Cg/HLSLを想定
# 自分なりに構造理解（間違っていたら指摘ください）

Shader "Unlit/NewUnlitShader"
・シェーダー名、/で階層毎に分類

Properties
・UnityでいうInspector変数（外部から設定できる値）
	// 変数名、"表示名"、デフォルト値
	_MainTex ("Texture", 2D) = "white" {}

SubShader
・シェーダーセット
　→環境によって使えなかったりするのでいくつかのSubShaderが用意できるみたい

Pass
・SubShaderの中で実行される命令、複数あると上から実行される？

"#pragma/#include"
・独自メソッドを定義、操作に必要なものをここで定義しているのかな？

struct
・独自メソッドで操作する変数を構造体で定義、引数として入る
　→大文字で定義されているものは自動的に値が入ってくるっぽい

v2f vert (appdata v)
・#pragma vertex vertで定義したので頂点を操作する、内部でゴニョゴニョして形を変える

fixed4 frag (v2f i) : SV_Target
・#pragma fragment fragで定義したもの、ピクセル情報を操作する
　→受け取ったピクセル情報をすべて赤とかに変更すると対象が赤一色になる

ソースとか

```
Shader "Unlit/NewUnlitShader"
{
	Properties
	{
		// 外部から操作できる変数
		_MainTex ("Texture", 2D) = "white" {}
	}
	SubShader
	{
		Tags { "RenderType"="Opaque" }
		LOD 100

		Pass
		{
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			// make fog work
			#pragma multi_compile_fog
			
			#include "UnityCG.cginc"

			struct appdata
			{
				float4 vertex : POSITION;
				float2 uv : TEXCOORD0;
			};

			struct v2f
			{
				float2 uv : TEXCOORD0;
				UNITY_FOG_COORDS(1)
				float4 vertex : SV_POSITION;
			};

			sampler2D _MainTex;
			float4 _MainTex_ST;
			
			v2f vert (appdata v)
			{
				v2f o;
				o.vertex = UnityObjectToClipPos(v.vertex);
				o.uv = TRANSFORM_TEX(v.uv, _MainTex);
				UNITY_TRANSFER_FOG(o,o.vertex);
				return o;
			}
			
			fixed4 frag (v2f i) : SV_Target
			{
				// sample the texture
				fixed4 col = tex2D(_MainTex, i.uv);
				// apply fog
				UNITY_APPLY_FOG(i.fogCoord, col);
				return col;
			}
			ENDCG
		}
	}
}
```
GPLv3 > link > COPYING or LICENSE?

GPL v3コードの修正と公開に関して、気になった点。

ライセンスファイルをCOPYINGとしている例とLICENSEとしている例がある。

違いは何か?

以下を見つけた。

https://stackoverflow.com/questions/5678462/should-i-provide-a-license-txt-or-copying-txt-file-in-my-project

> COPYING is standard in the GNU project. I think that either of COPYING or LICENSE would be understood. The FSF has [a guide on how to use the GPL](https://www.gnu.org/licenses/gpl-howto.html), which suggests COPYING, while the [Producing Open Source Software](http://producingoss.com/en/license-quickstart.html) book suggests either COPYING or LICENSE. The [Apache License](http://www.apache.org/licenses/LICENSE-2.0.html) recommends a boilerplate that just points to the license online, though the Apache project seems to also include a LICENSE file in their code containing the relevant license or licenses.
linuxでディレクトリ丸ごとコピーをcpではなくtarで

#結論から
(cd /home/projects/wp && tar cf - site1) | (cd /home/backup && tar xvf -)
/home/projects/wp/site1というディレクトリを/home/backup/site1という形に
コピーしたい場合上記のように書くといいとの情報があったのでメモしておきます。

#理由（個人の解釈）
cpコマンドはコピーをするコマンド
tarコマンドは圧縮、展開するコマンド
正確にはアーカイブを作成、つまりファイルをまとめるという意味かなと個人的には解釈しました。

上記はsite1というディレクトリを圧縮しディレクトリを移動して展開するという流れ。

情報元に理由は書いてなかったのですが個人的な予想としては
cp -aなどの実行時に状況によってパーミッションが変わるなどの場合が発生するため
tarで圧縮解凍したほうが確実という意味合いなのでは？
（ほかのメリットなどありましたらぜひコメントお願いいたしますm(_)m）

また&&の部分は以下のように書くことも可能なのですが
(cd /home/projects/wp; tar cf - site1) | (cd /home/backup; tar xvf -)
&&にすることでcdを間違えて指定した場合にtarが実行されるのを防いでくれるとのこと。



#cpコマンドのおさらい（自分がよく使うポイントだけまとめ）
cp -a は cp -dpRと同じ。
オプション解説すると
dはリンクを保持する（シンボリックリンク、ハードリンク共に）
pは**可能なら**属性をコピーする。可能ならというところが味噌ですな。
この辺りの一つの解決方法としてのtarなのかなと個人的には解釈しました。

#つっこみありましたらぜひお願いいたします
cpコマンドもうまく使う方法あるよ。
tarだとリスクがあるよなどなど
突っ込むポイントありましたら是非コメントお願いいたします。
phpcsをcomposerで導入しつつ、独自rulesetを使う

# phpcsをcomposerで導入する

```shell-session
$ composer global require squizlabs/php_codesniffer
```

実行したユーザの ~/.composer/bin/phpcs にパスが通るようにしておく

```shell-session:.basrhcなど
export PATH=$HOME/.composer/vendor/bin:$PATH
```

```shell-session
$ which phpcs
~/.composer/vendor/bin/phpcs
```

# 独自rulesetを使う

* 独自rulesetを置くパスを指定

```
$ phpcs --config-set installed_paths ~/.phpcs
```

* ruleset.xmlを置く

```shell-session
$ mkdir -p ~/.phpcs/MyStandard
$ cp ruleset.xml ~/.phpcs/MyStandard
$ phpcs -i
The installed coding standards are Zend, Squiz, PSR2, MySource, PEAR, PSR1 and MyStandard
```

* デフォルトのrulesetを指定

```shell-session
$ phpcs --config-set default_standard MyStandard
```

# 参考

https://github.com/squizlabs/PHP_CodeSniffer/wiki/Configuration-Options#setting-the-installed-standard-paths
https://github.com/squizlabs/PHP_CodeSniffer/wiki/Configuration-Options#setting-the-default-coding-standard
実務に役立つかどうかちょこっとだけk平均法によるクラスタリングを試してみた

# はじめに

- WEBサービスを運営していることから、レコメンデーションなどがとっつきやすい実例なのかもしれないと思い、軽く触ってみました。
- 専門的に設定値や軸などがそもそも正しいのかは置いておいて、仮定のような状態としてあります。

# 参考

[scikit-learn による最も基本的なクラスタリング分析](https://qiita.com/ynakayama/items/1223b6844a1a044e2e3b)

# scikit-learnのインストール

```
pip install scikit-learn 
```

# 概要

- 例えば、お店を紹介するようなWEBサービスがあるとします。
- WEBページは主に検索ページ、店舗ページ、CVの入力／確認ページ、CVの完了ページがあるとします。
- ユーザの行動履歴を用いてユーザの検索意欲やCV意欲をクラスタリングできればと思います。
- 以下のプログラムコメントに記載はありますが、ページによってポイントを振って重みをつけてます。
- また、ユーザの行動履歴を各店舗毎に最終閲覧ページ番号をランダムにデータとして用いてます。

# プログラム

```py3
#!/usr/local/bin/python3
#! -*- coding: utf-8 -*-

import numpy as np
from sklearn.cluster import KMeans

if __name__ == '__main__':

    # 店舗毎に番号を与える
    #
    # 行はユーザ
    # 各配列キーは店舗
    #
    # 最終閲覧ページ（検索/CV意欲が高いほど数値が高い）
    #   0: 未閲覧
    #   1: その他
    #   2: 検索
    #   3: 店舗
    #   4: CV入力/確認
    #   5: CV完了
    features = np.array([
        [ 0, 5, 0 ],
        [ 1, 3, 0 ],
        [ 3, 1, 3 ],
        [ 3, 2, 2 ],
        [ 5, 0, 1 ],
        [ 1, 0, 2 ],
        [ 2, 3, 4 ],
        [ 4, 2, 2 ],
        [ 5, 3, 2 ],
        [ 5, 4, 5 ],
        [ 0, 1, 3 ],
        [ 0, 2, 0 ],
        [ 0, 0, 1 ],
        [ 0, 2, 2 ],
        [ 2, 4, 4 ],
        [ 3, 4, 1 ],
        [ 1, 0, 2 ],
        [ 2, 4, 5 ],
        [ 0, 1, 4 ],
        [ 0, 0, 0 ],
        [ 4, 0, 3 ],
        [ 4, 3, 3 ],
        [ 4, 0, 2 ],
        [ 5, 3, 0 ],
        [ 5, 4, 0 ],
        [ 2, 0, 4 ],
        [ 3, 2, 2 ],
        [ 1, 1, 2 ],
        [ 0, 2, 0 ],
        [ 2, 3, 3 ],
        [ 3, 2, 3 ],
        [ 0, 5, 4 ],
        [ 0, 3, 4 ],
        [ 1, 0, 5 ],
        [ 2, 5, 4 ],
        [ 3, 4, 0 ],
        [ 4, 5, 3 ],
    ])

    # K-meansクラスタリングをおこなう
    # この例では3つのグループに分割 (メルセンヌツイスターの乱数の種を10とする)
    kmeans_model = KMeans(n_clusters=3, random_state=10).fit(features)

    # 分類先となったラベルを取得する
    labels = kmeans_model.labels_

    # label クラスタリングラベル
    #   0: 検索意欲/CV意欲が高いユーザ
    #   1: 検索意欲/CV意欲がまずまずなユーザ
    #   2: 検索意欲/CV意欲が低いユーザ
    # feature 店舗毎の最終閲覧番号
    # feature.sum() 最終閲覧ページ番号の加算
    for label, feature in zip(labels, features):
        print(label, feature, feature.sum())
```

# 実行結果

```text
2 [0 5 0] 5
2 [1 3 0] 4
1 [3 1 3] 7
1 [3 2 2] 7
1 [5 0 1] 6
2 [1 0 2] 3
0 [2 3 4] 9
1 [4 2 2] 8
1 [5 3 2] 10
0 [5 4 5] 14
2 [0 1 3] 4
2 [0 2 0] 2
2 [0 0 1] 1
2 [0 2 2] 4
0 [2 4 4] 10
1 [3 4 1] 8
2 [1 0 2] 3
0 [2 4 5] 11
2 [0 1 4] 5
2 [0 0 0] 0
1 [4 0 3] 7
1 [4 3 3] 10
1 [4 0 2] 6
1 [5 3 0] 8
1 [5 4 0] 9
2 [2 0 4] 6
1 [3 2 2] 7
2 [1 1 2] 4
2 [0 2 0] 2
0 [2 3 3] 8
1 [3 2 3] 8
0 [0 5 4] 9
0 [0 3 4] 7
2 [1 0 5] 6
0 [2 5 4] 11
1 [3 4 0] 7
0 [4 5 3] 12
```

# まとめ

- プログラムコメントにも書いてるように、閲覧ページの加算が高いほど意欲が高く、低いほど意欲も低いような傾向になんとなく見えます。
- 例えば、このデータを元に意欲の高いユーザのページ行動フローや流入経路を分析したり、ラベル毎にアプローチを変えてみたりとかできそうですね。
Raspberry Pi 3 Model B 初期セットアップ

Raspberry Piの初期セットアップを簡単・確実に完了するために必要な物・手順をまとめました。

#1 RaspberryPiの初期設定に必要な物
・本体 RaspberryPi 3 Model B
・2.5A電源
・Micro SDカード 8GB以上
・PC
・カードリードライター（PCにSDカードドライブがあれば不要。100円ショップで購入可能）
・HDMIモニター/ケーブル
・USBキーボード
・USBマウス

本体は2017年9月現在最も高性能（最新モデルという意味では廉価版のZeroがでてはいますが）を選択しました。値段的には古いモデルとあまり差がありませんでしたので新しく高性能なものがよいと思います。
2.5Aの電源が必要かどうかという点についてはいろいろあるようですが、推奨スペックなので確実のため2.5A電源を用意しました。アマゾンで電源・本体セットで7千円弱で購入可能です。
Micro SDカードはRaspberry PiのOSインストール領域になります。容量は4GBあればインストールはできるようですが、8GB以上あれば安心とのことだったのでこちらもアマゾンで千円程度で購入。
他は家であるものなどで準備しました。

#2 SDカード設定
OSインストール前にSDカードの設定を行います。
OSはRaspberryPi用のOSであるRaspbian、インストールにはインストーラーのnoobsを使用しました。

・フォーマット
・noobsダウンロード/コピー

フォーマットは以下のフォーマット用ツールを使用しました。
https://www.sdcard.org/downloads/formatter_4/

noobsはLiteではなく、1.5GBのフルzip版をダウンロードしてください。
https://www.raspberrypi.org/downloads/noobs/

zipを解凍してSDカードのルートディレクトリ直下に解凍時にできたフォルダ以下のファイル群をコピーしてください。（直下にフォルダごとコピーするとインストーラーが起動しませんでしたので注意）

#3 起動・インストール
インストーラーをコピーしたSDカードをセットし、HDMIのモニター/USBキーボード・マウスをついないでRaspberryPiを起動します。電源ボタンはないので電源をつないだ時点で起動します。SDカードの準備に問題なければ、すぐにインストール開始の画面がモニターに表示されます。

起動直後の画面
![cap1.jpg](https://qiita-image-store.s3.amazonaws.com/0/199314/d3ca3b77-e61f-cd22-7caf-d0d91b4fd729.jpeg)

RECOMMENDEDと表示されているRaspbianにチェックを入れます。
![cap2.jpg](https://qiita-image-store.s3.amazonaws.com/0/199314/600cda68-e601-e003-3cbf-dfca1030b8ba.jpeg)

警告が表示されるので「Yes」をクリック。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/199314/518ad5e2-010f-6902-b371-41bc16971810.png)

インストールが開始されます
![image.png](https://qiita-image-store.s3.amazonaws.com/0/199314/a7c7a91b-a221-f826-33b1-01a055a33687.png)

数分でインストールは完了し、OSが起動します。

#4 OS初期設定
以下は通常のLinuxと同様の手順で実施します。
・デフォルトのユーザー「pi」のパスワード変更
・SSHを使用可能に

#4 ネットワーク設定
・wifi設定
USBマウスを使用してGUI経由で設定しましたが、こちらを参考にさせていただきコマンドでの設定も確認できました。
http://takuya-1st.hatenablog.jp/entry/2015/05/17/155229

#5 追加パッケージ導入
パッケージリストの更新（RaspbianはDebian系なのでaptコマンドです）
> apt update

エディターインストール
> apt install vim

VNCサーバーのインストール
> apt install tightvncserver

設定は以下を参考にさせていただきました。
http://yamaryu0508.hatenablog.com/entry/2014/08/16/202441

以上でとりあえず次回起動以降ネットワーク経由（同一LANセグメント）でPCからの接続もできるようになりましたのでUSBキーボードやマウスは不要になります。


#6 感想
いろいろな情報があふれていて逆にわからなくなってしまったので、とりあえずやってみましたが物がそろえば手順はほとんど失敗する箇所はなさそうでした。初期設定が終わったので、次回はUSBカメラを接続してOpenCVを動かしてみようと思います。
git で single-branch を使用した後に別ブランチを fetch する方法

#はじめに
前回投稿した [「容量の大きいリポジトリを必要最低限の情報だけ clone する方法」](http://qiita.com/kinpira/items/21c3a24f7a74b1056904) という記事の続きです。
前回は容量を抑えるために --single-branch で master ブランチを指定して、よけいなブランチは落としてこないようにしていました。
しかし、今回他のブランチを落として来たくなった時にちょっと困ったので、今回も備忘録を残しておくことにします。

#追跡できない理由

通常 clone 時に何も指定していなければ、下記のようにワイルドカードが指定されているため、全てのブランチに対応できます。

```bash
[remote "origin"]
    url = https://foobar.com/test.git
    fetch = +refs/heads/*:refs/remotes/origin/*
```

しかし、single-branch を指定して clone して来た場合は .git/config の中身が変わります。
下記のように fetch の設定値が master 指定になっています。

```bash
[remote "origin"]
    url = ssh://foobar.com/test.git
    fetch = +refs/heads/master:refs/remotes/origin/master
```
そのため、master 以外を指定すると下記のように origin/develop ブランチ(追跡ブランチ)を作成しません。

```bash

$ git fetch origin develop
remote: Counting objects: 1, done.
remote: Compressing objects: 100% (1/1), done.
remote: Total 8393 (delta 1), reused 1 (delta 1)
Receiving objects: 100% (1/1), 2.90 MiB | 0 bytes/s, done.
Resolving deltas: 100% (1/1), completed with 1 local objects.
From ssh://foobar.com/test.git
 * branch            develop    -> FETCH_HEAD
# * [new branch]      develop    -> origin/develop ←本来はこのようにorigin/developが作成される

$ git branch -r
origin/master
```

#解決策
## .git/config を修正する
解決策として、一番簡単な方法は .git/config を編集することです。
編集方法は 2通りあります。

### (1) single-branch はやめてワイルドカードに戻す
手っ取り早く下記のように、通常 clone して来た時と同じ状態に修正してしまう方法があります。

```bash
[remote "origin"]
    url = https://foobar.com/test.git
    fetch = +refs/heads/*:refs/remotes/origin/*
```

### (2) fetch 先を追加する
fetch を追加する方法もあります。
余計なブランチはいらないので、自分はこちらの方法で対処しました。

```bash
[remote "origin"]
    url = https://foobar.com/test.git
    fetch = +refs/heads/master:refs/remotes/origin/master
    fetch = +refs/heads/develop:refs/remotes/origin/develop
```

## コマンド時に fetch 先まで指定する
リモートブランチの追跡が1回きりでも良い場合は、fetch コマンド時に fetch 先を指定する方法もあります。

```bash
$ git fetch origin develop:refs/remotes/origin/develop
```

#最後に
この辺りを詳しく知りたい場合は、 [gitドキュメントのRefspec](https://git-scm.com/book/ja/v1/Git%E3%81%AE%E5%86%85%E5%81%B4-%E5%8F%82%E7%85%A7%E4%BB%95%E6%A7%98%EF%BC%88Refspec%EF%BC%89
) に書かれているので、こちらを参考にしています。
DOM配列を回すのが億劫だった歴史(思い出補正)

#jQueryのループは便利ですね

```javascript
$('a').each(function(){
　//thisで処理
})
```
#旧来
##こうやってた
class名なんて使わせてもらえない

```javascript
 var dom = document.getElementsByTagName('a');
 for(var i=0, len=dom.length; i<len; i++){
  //dom[i].hogehoge.fugafuga;
 }
```

##querySelectorAllが登場した
class指定とか簡単に

```javascript
 var dom = document.querySelectorAll(selector);
 for(var i=0, len=dom.length; i<len; i++){
  //dom[i].hogehoge.fugafuga;
 }
```
結局for文がめんどくさかった

##Array.forEachが登場した(あったの知らなかった)
しかし、DOM配列は普通の配列ではないので、無理やりやった

```javascript
Array.prototype.forEach.call(document.querySelectorAll('a'),function(el,i,arr){
 //el.hogehoge.fugafuga;
});
```

なんか省略できる
jQuery不在時には今でも活躍

```javascript
[].forEach.call(document.querySelectorAll('a'),function(el,i,arr){
 //el.hogehoge.fugafuga;
});
```
GitHubでForkした際に使用するGitコマンド

# 構成
![repo.png](https://qiita-image-store.s3.amazonaws.com/0/109685/6c2cee9b-8f6b-113b-6ad4-601795978ae9.png)

# はじめに…

## upstreamの設定
```
$ git remote add upstream https://github.com/ORIGINAL/REPOSITORY.git
```

#### 設定の確認
```
$ git remote -v
origin    https://github.com/MY_USERNAME/REPOSITORY.git (fetch)
origin    https://github.com/MY_USERNAME/REPOSITORY.git (push)
upstream  https://github.com/ORIGINAL/REPOSITORY.git (fetch)
upstream  https://github.com/ORIGINAL/REPOSITORY.git (push)
```

## ユーザーの設定
```
$ git config --local user.name MY_USERNAME
$ git config --local user.email MY_EMAIL_ADDRESS
```

# 定期的に…

## upstreamとの同期
#### コミット(upstream → local)
```
$ git fetch upstream
$ git checkout master
$ git rebase upstream/master
```
#### コミット(local → origin)
```
$ git push origin master
```

#### タグ(local → origin)
```
$ git push --tags origin
```

#### 削除されたブランチ(upstream → local)
```
$ git fetch --prune upstream
```
または

```
$ git remote prune upstream
```

#### 削除されたブランチ(origin → local)
```
$ git fetch --prune origin
```
または

```
$ git remote prune origin
```
【Unity2017】TileMapエディターを簡単に開くエディター拡張を作ってみた

# はじめに
Unity2017.2でタイルマップエディターが新しく追加されました。
タイルマップエディターは素晴らしい機能ですが、タイルマップを編集するには

>1. ProjectビューでGridアセットを選択
>2. メニューから"Window/Tile Palette"を選択してウィンドウを開く

という手順を踏む必要があって若干めんどくさいです。

そこで、Gridコンポーネントの**インスペクター上から**直接Tile Paletteウィンドウを開くエディター拡張を作ってみました。

# 環境
Unity2017.2.0f1
Windows 10

# つくったもの
![1.gif](https://qiita-image-store.s3.amazonaws.com/0/44288/3e3d9b78-a772-e243-68d8-0a70f8403972.gif)

Gridコンポーネントのインスペクター上からTile Paletteウィンドウを開くエディター拡張を作ってみました。

**Hierarchy**からでもTile Paletteウィンドウを開くことができるので、わざわざProjectビュー上でGridアセットを選択する必要がありません。

これさえあれば快適にTileMapエディターが使えるかと思います。

# ソースコード
プロジェクト内にEditorフォルダを作成し、以下のスクリプトを入れるとこのエディター拡張が使えるようになります。

```GridInspector.cs
using UnityEngine;
using UnityEngine.Tilemaps;
using UnityEditor;

[CustomEditor(typeof(Grid))]
public class GridInspector : Editor
{
    public override void OnInspectorGUI()
    {
        if (GUILayout.Button("Open Tile Palette"))
        {
            // Tile Paletteウィンドウを開く
            EditorApplication.ExecuteMenuItem("Window/Tile Palette");

            // Gridアセットの選択
            Selection.activeObject = null; // いったん選択を外す
            EditorApplication.delayCall += () =>
            {
                Selection.activeObject = PrefabUtility.GetPrefabParent(target) ?? target; // Gridアセットを選択
            };
        }
        base.DrawDefaultInspector();
    }
}
```