OmniAICreator/Qiita-1.07M huggingface dataset:
Ubuntu16.04 + GPU（GTX1080）にAnacondaを使ってTensorFlow1.4をいれるも、NVIDIA周りとPythonのバージョンでつまづいたのでメモ

## 状況

タイトル通り、Ubuntu+GPUにバージョンアップしたTensorFlow1.4を入れるとNVIDIAドライバとPyhtonバージョンの間でトラブルがあったので、一通りメモ。結果的に、うまくGPUが動いてMLできているのでとりあえず成功。
## Anacondaインストール
まずはapt-get更新。

```
$ sudo apt-get update
```

更新できたら、Anacondaの公式サイトにいってインストーラーダウンロード。

```
$ bash ~/Downloads/Anaconda3-5.0.1-Linux-x86_64.sh
```

シェルを使ってインストール。※リモート操作などの場合は、pyenvを使うのがスマートっぽい。
Anacondaが入ったらPythonの主要なライブラリはデフォルトでインストールされているのでとりあえず

```
$ pip install conda
```

でcondaをインストール。エラーが出た場合は、

```
$ pip install --upgrade pip
```

でpipを更新するとできる（かも）
condaがインストールできたら、TensorFlow用の仮想環境を構築する。
## condaコマンドで仮想環境を作る
下記のように。

```
$ conda create -n [env name] python=[Python version] anaconda
```

たとえば

```
$ conda create -n tensorflow13 python=3.6 anaconda
```

みたいな。

※タイトルにもあるようにTensorFlowが1.3のときは3.6に対応してたが…1.4から3.6だとエラーが出るようになった？結果的に3.5にするとうまくいったという記事ですが、TensorFlow側でいつの間にか対応しているということはありそう。

【以下、NVIDIAのTensorFlow用のチュートリアル】
https://www.nvidia.com/en-us/data-center/gpu-accelerated-applications/tensorflow/
## NVIDIAドライバの最新版をインストール
```
$ sudo add-apt-repository ppa：graphics-drivers / ppa
$ sudo apt-get install nvidia-375
```

このあとグラフィックドライバを有効にするために再起動したほうが良いみたい。

## CUDA ToolKitインストール（ver8.0）Linux用をダウンロード
**重要** ver.9.0が最新ですが、TensorFlow1.4に対応したCuDNNのバージョン6.0に対応してないので8.0をインストールする。
https://developer.nvidia.com/cuda-toolkit
公式サイトでdebファイルをダウンロードしようとすると、9.0しかダウンロードできないので、Additional ResourcesのLegacy Releasesから8.0 GA2をダウンロードする。
とにかく最初に8.0をダウンロードするのが重要で、もし最新版をインストールしてる場合はアンインストールしたほうがよさそうです。（ディレクトリ構造が違うらしくCuDNNがスマートにインストールできない）

```
$ sudo dpkg -i cuda-repo-ubuntu1604_8.0.61-1_amd64.deb```
$ sudo apt-get update
$ sudo apt-get install cuda
```
を手順通り行う。CUDA ToolKitがインストールされた。

## CuDNN for Linuxをインストール
NVIDIAにログインして素直にcuDNN v6.0 Library for Linuxをダウンロード。

```
$ tar -xzvf cudnn-8.0-linux-x64-v5.1.tgz
```
で解凍で中身をコピー。

```
$ sudo cp cuda/include/cudnn.h /usr/local/cuda/include
$ sudo cp cuda/lib64/libcudnn* /usr/local/cuda/lib64
$ sudo chmod a+r /usr/local/cuda/include/cudnn.h /usr/local/cuda/lib64/libcudnn*
```

と、順番に実行。最新版をインストールしていると、そもそもusr/local配下にcudaなんてディレクトリが生成されなかったんですが自分だけでしょうか。
TensorFlowとの依存関係に必要なパッケージをインストール。

```
$ sudo apt-get install libcupti-dev
```

これでNVIDIAのドライバ周りが整った。

## TensorFlowをインストールする。

さきほど作ったAnacondaの仮想環境を有効にする。

```
$ source activate [env name]
```

で、

```
pip install tensorflow-gpu
```

してTensorFlowのGPU版をインストール。

で、ここからが問題。TensorFlow1.4だと、ここでなぜかPython3.5じゃないと動きませんよといわれる。
エラーメッセージで検索すると、GitHubのTensorFlowのフォーラムでもガヤついていたので、自分だけじゃないという安心感。

だったらばということでAnacondaで再度Python3.5の実行環境作って走らせたら動いたよかったね！
『独習Git』7章メモ

# 試したコマンド
- git rm
- git mv
- git reset
- git checkout

# メモ

## git reset
```
ubuntu# git ls-files
ubuntu#
ubuntu# vim file1
ubuntu#
ubuntu#
ubuntu# git status
On branch master
Untracked files:
  (use "git add <file>..." to include in what will be committed)

        file1

nothing added to commit but untracked files present (use "git add" to track)
ubuntu# git add .
ubuntu# git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        new file:   file1

ubuntu# git diff
ubuntu# git diff --staged
diff --git a/file1 b/file1
new file mode 100644
index 0000000..bda0724
--- /dev/null
+++ b/file1
@@ -0,0 +1,2 @@
+file1
```

## git checkout

```
ubuntu# vim file1
ubuntu#
ubuntu#
ubuntu# git status; git diff; git diff --staged
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   file1

no changes added to commit (use "git add" and/or "git commit -a")
diff --git a/file1 b/file1
index bda0724..2cfbed9 100644
--- a/file1
+++ b/file1
@@ -1,2 +1,2 @@
 file1
-
+file111111111111
ubuntu# git checkout -- file1
ubuntu#
ubuntu#
ubuntu# git status; git diff; git diff --staged
On branch master
nothing to commit, working directory clean
ubuntu# cat file1
file1
```
CODE BLUE 2017レポート(DAY1後編)

こんにちは、ひろかずです。

[CODE BLUE 2017レポート(DAY1前半)](https://qiita.com/fnifni/items/b966f6c6da0cf63568d2)の続きです。

お昼も食べてリフレッシュ
去年からお弁当は出なくなったそうです（残念）

例によって、リアルタイムでの書き起こしになりますので、誤字脱字記載漏れ表記ゆれにつきましては、ご容赦ください。

# お品書き
基調講演：サイバースペースにおける国家主権 
Session1：Step-Oriented Programming による任意コード実行の可能性
=== 今回はここから ===
Session2：SSRFの新時代 - 有名プログラミング言語内のURLパーサーを攻撃！
Session3：アルファベイ・マーケット - サイバー犯罪主導者を振り返る 
Session4：マン・イン・ザ・NFC 
Session5：事例から考える脆弱性と法 

# SSRFの新時代 - 有名プログラミング言語内のURLパーサーを攻撃！
オレンジ・サイ - Orange Tsai - 

様々なセキュリティカンファレンスで登壇し、CTFプレイヤー、
サーバーサイドの攻撃（リモートコード実行）に関心がある。

SSRFとは10年前に発見されたWebアプリケーションの攻撃手法
FWを回避してイントラネットに攻撃する。
イントラネットが大きければ（あるものが多ければ）、その効果は大きくなる。

HTTPベースプロトコル、テキストベースプロトコル(FTP,smtp,)

今回の研究は、SSRFを高度化し強化するもの。

pythonを使う時のライブラリは何を使う？（多くは、url.libでしょう）
pythonはライブラリごとに処理する場所が違う

gopher使う？
ブロックするのは容易で、攻撃対象がサポートするとは限らないので、使わない。

SSRFは常にHTTPが付きまとう。
HTTPSで暗号化されない部分はSNI部分
SNI拡張にLRLFを仕込めばホストを注入できる。

## URLのパーシング問題
URLのバリデーションは大変（RFC3986に仕様がされているが、実装方式は定められていない）
URLパーサーには多くの問題を含むものがある。
今回はスキーム、オーソリティ、パスを使う（クエリーとフラグメントは今回は触れない）

URLパラメータの悪用
`https://127.0.0.1:11211:80`の例では、ライブラリによって処理する場所が違う
同じようにcurlやJAVA等にも同じ問題がある。

パッチが出たが`https://127.0.0.1 :11211:80`でバイパスできる。
curl Teamはプログラム実装の問題と認識している（修正されない）

glibcのNSS機能ではRFC1035に準じて、ドメインシステムとプロトコルの詳細を規定している。
ドメインネームにバックスラッシュを2つつけることで難読化（ブラックリストの回避）ができる

getadressinfo()は、`127.0.0.1 aaa`を127.0.0.1と解釈する。

IDNAスタンダード
IDNA2008は厳しすぎるので、依然古いIDNAが使われている
ここでも特殊文字が変換されてしまうので、ブラックリストバイパスに繋がる

WordpressにはSSRFが3ケースある（未修正）
URLパーサーとDNSチェッカーとURLチェッカーの機能差を利用する。
チェックの結果が異なる場合があるのを利用してバイパスする

curlで対応されている脆弱性もあるが、古いライブラリを使っている製品は依然ある。

## 軽減策
アプリケーションレイヤー

- IPのみ試用し、ユーザーから引き渡されたURLは使用しない

ネットワークレイヤー

- ファイアウォールポリシーでインタネットトラフィックをブロックする。

## 質疑応答
バイパスの手段は機械的なファジングで見つけるのですか？クリエイティブなアプリケーションで見つける？

- Tiny-URL-Fuzzerを使いました。オープンソースなので見てもらった方が分かりやすいですよ！

ひらめきやアイデアで見つけることはありますか？

- はい

たくさんの例が提示されて書ききれませんでした汗
詳しくは資料を参照してください！


# アルファベイ・マーケット - サイバー犯罪主導者を振り返る 
クリスティ・クイン - Christy Quinn - 

SNS投稿禁止セッションのため、公開は自粛しますｍｍ

# マン・イン・ザ・NFC 
ハオチー・シャ,クイン・ヤン - Haoqi Shan, Qing Yang - 

どのようにNFC proxy tool を作るか？

ハードのデザインの話をしていく
いかに攻撃するかではない
uniproxyってなにか感触を知ってほしい

## デモ
用意するのはツール二つ
ツールにクレジットカードを載せる
もう一つのツールに決済機を接触
決済できた

## unicorn チーム
2014年設立のハッキングと防御の研究チーム
DEFCONやブラックハットて発表

## NFC
電力不要でローコスト
ISO14443
銀行カード、クレジットカード、パスポートをはじめ、たくさんのアプリでサポートされている。

中国ではI.D.カードでホテルに泊まれる。
スタバにもPOSマシンがあり、カードでコーヒーを買える。

対象はquick pass（VISAが載ってるもの）
Proxmark2とchameleon miniを使った
NFCproxyとNFCgateは強力だけど使えなかった。
Androidベース
データ伝送がWi-Fiに依存しているので、100ミリ秒単位の遅延で失敗する。
バックできないからマーク3は使わなかった 。

なので新しいツールを作った

## uniproxy
早くて遠くまで届く
アンプなしで50m届く
ISO14443aを対象に開発したが、拡張可能。
PN7462AUベースのNFCrelay proxyデバイス

### PN7462AUとは
NXPチップ
POSをエミュレートできる（Read right）
MIFAREファミリーを完全サポート
チップを買うとアンテナが付いてくる
開発やハッキングにも使い勝手が良い

ハードウェアデザインはシンプル
標準パーツの組み合わせで作った

### デプロイ時の問題
UIDのFirstbyteを変更できない（クレジットカードでは無視できた。入館カードでは問題になるかも）
待ち時間とウェイクアップ時間の書き換えが必要だった
ISO14443パート4はフェイクじゃない。

### マクドナルドて実験
セルフレジで試したらカードを接触させずにNFCproxyを接触させて決済できた。
より遠距離で使おうとすると（すれ違いとかで使おうとすると）アンテナが大きくなる。

## 防御策
ブロッキングスリーブとNFCジャマーは有効だった。

## 制作に際して
原理は簡単だった。
オフィシャルサポート買えば一ヶ月で開発できそう。
サポートなしで半年かかった。

将来的には自動化したい。

# 事例から考える脆弱性と法 
橋本 早記 , 武田 真之 - Saki Hashimoto , Masayuki Takeda - 

SNS投稿禁止セッションのため、公開は自粛しますｍｍ

今年も濃密なセッション盛りだくさんです！
次回に続きます。
脆弱性診断などで、cookieをsecureにしましょうと言われた時に

# 常時SSL化にともなって最近指摘が多くなってきて、その際に時間もなくプログラムのソースコードをすべてチェックできない場合に

mod_headers.so を有効にしてから

## すいません、やってませんでしたの場合、cookie を強制セキュア

<code>
Header edit Set-Cookie ^(.*)$ $1;HttpOnly;Secure
</code>

## すでに設定している箇所があるかもという場合に、セキュア設定にしている場所をチェックして最適化

<code>
Header edit Set-Cookie ^(.);\s?Secure;?\s?(.);\s?Secure;?\s?(.)$ "$1; $2; $3; Secure"
Header edit Set-Cookie ^(.);\s?HttpOnly;?\s?(.);\s?HttpOnly;?\s?(.)$ "$1; $2; $3; HttpOnly"
Header edit Set-Cookie ^(.);\s?;\s?(.)$ "$1; $2"
</code>

こちらの設定をいつも入れておけば・・安心ですね。

備忘録でした。
RubyでSQL Serverに接続する（TinyTDS）

RubyからSQLServerに接続する方法です。
TinyTDSを使います
> Ruby Driver for SQL Server
https://docs.microsoft.com/ja-jp/sql/connect/ruby/ruby-driver-for-sql-server

#前提条件
- Ruby2.3.3p222を使用します。
- path等は自分の環境で適宜読み替えて下さい。
- Windows 10 環境で確認しました。
- CentOS 7.4 環境で確認しました。
- Debian環境では確認していません。

#環境構築
##Windows
###Ruby+Devkitのインストール
RubyInstallerを使いインストールします。
https://rubyinstaller.org/downloads/
参考：[WindowsにRubyをインストールする(初心者向け)](https://qiita.com/shimoju/items/41035b213ad0ac3a979e)

###uruのインストール
uruを使ってバージョン管理をします。[^1]

1. https://bitbucket.org/jonforums/uru/wiki/Downloads から`uru-0.8.4-windows-x86`をダウンロード
1. ダウンロードしたuruを`C:\Ruby\tools\uru`へ解凍
1. 以下コマンドにてインストール

```
cd C:\Ruby\tools\uru
uru_rt admin install
```

####Rubyバージョン切り替え

```
uru admin add C:\Ruby\Ruby23-x64\bin
uru 233p222
```

参考：[pikの替わりにuru～windowsで複数バージョンのrubyを切り替える～](https://qiita.com/tikkss@github/items/a70af204d5fb3612bb39)


##Linux
###rbenvのインストール
rbenvを使ってバージョン管理をします。[^1]
参考：[rbenvを用いたruby環境構築手順（CentOS7.1）](https://qiita.com/ksugawara61/items/e3bb87d5e0dd49d20c8f#_reference-3eeaae16231c47d24836)
参考：[rbenv で ruby の環境を整える](https://qiita.com/ringo/items/4351c6aee70ed6f346c8)

###Rubyのインストール
`rbenv install 2.3.3`

###FreeTDSのインストール
- Debian  
`sudo apt install freetds-common freetds-bin`
- RHEL  
`yum install -y freetds freetds-devel`

##Windows・Linux共通
###bundlerのインストール
bundlerを使ってgemの管理をします。[^1]
`gem install bundler`

###TinyTDSのインストール
- Gemfileの作成  
`bundle init`
- Gemfileに追記  
`gem 'tiny_tds'`
- インストール  
`bundle install --path vendor/bundle`

#使い方

##SELECT文サンプル
```rb:test.rb
require 'rubygems' #bundlerを使わない場合
require 'bundler/setup' #bundlerを使う場合
require 'tiny_tds'

client = TinyTds::Client.new username: '<user>', password: '<pass>', host: '<target_host>', port: 1433, database: '<db_name>', azure: false

results = client.execute 'SELECT * FROM <table_name>'

results.each do |row|
  puts row['<column_name>']
end
```

###実行結果
```
# ruby test.rb
<column_data>
<column_data>
<column_data>
<column_data>
...
```

###メモ
- `port: 1433`は省略可能
- `azure: false`もfalseなら省略可能
- CentOS 7.4環境で実行すると警告`warning: TinyTds: :use_utf16 option not supported in this version of FreeTDS.`が発生する。`use_utf16: false`にしてもダメ


[^1]: しなくてもいいけど、したほうがいい
文字コードにnkfコマンドで打ち勝つ

# 概要
何回もnkfコマンドについて調べているため、nkfコマンドについてまとめる。

# nkf(network Kanji Filter)コマンドってなんだ？


標準入力を文字コードを変換しながらそのまま標準出力に吐き出す。
引数にファイル名を指定すれば、標準入力ではなくそのファイルを読み込む。

# 前提

- MacOS(Sierraでも良い)であること
- Homebrewがインストールされていること

# インストール

以下コマンドを実行すれば、よほど古いバージョンでなければ、うまくいくはず。
Homebrewと他のコマンドとの共存でパスがおかしくなっている人は注意が必要。


``` コマンド
$ brew install nkf
```

# コマンドまとめ
## 基本
```
nkf オプション ファイル
```

## よく使うオプション

### 文字コード変換用オプション
|オプション|内容|
|:---:|:---:|
-j|JISコードに変換
-e|EUCコードに変換
-s|シフトJISコードに変換
-w|UTF8コードに変換

### その他

|オプション|内容|
|:---:|:---:|
|-g|ファイルの文字コード出力|
|--overwrite|現在あるファイルを上書き|
CODE BLUE 2017レポート(DAY2前篇)


こんにちは、ひろかずです。
昨日に引き続き、CODE BLUE 2017のDAY2をレポートします。

5階では各種コンテストが催されているとのことです。
年々新たな取組がなされていますね！

# お品書き
- "商用ホワイトボックス暗号方式" に対する "鍵回復攻撃"
- LG vs. Samsung スマートTV: あなたを追跡できるのはどちら？

=== 今回はここまで ===

- インサイドShell：.NETハッキング技術を応用したPowerShell可視性の向上
- 国産IT資産管理ソフトウェアの（イン）セキュリティ
- Trueseeing: Effective Dataflow Analysis over Dalvik Opcodes -
- OSSによる自動車の自動運転化

# "商用ホワイトボックス暗号方式" に対する "鍵回復攻撃"
アン・サンファン - Sanghwan Ahn - 

## イントロダクション
商用のホワイトボックスソリューションでは、攻撃はなかなか成功しない状況だった。
サイドチャネルアタックを使って、攻撃に成功（鍵回復）した。
この成功は初めてである。

アプリケーションセキュリティは2fa等様々な方式で保護されている
鍵はハードウェアに格納されている
システムの保護が不十分であれば、メモリから鍵情報を抜くことができる
データが暗号化されても、鍵がメモリに格納されているので、情報は読み取れる。

## ホワイトボックス脅威モデル
攻撃者は

- バイナリを完全に見える
- 暗号アルゴリズムにアクセスできる
- 実行環境を完全に制御できる
- 何度もクエリを事項できる

信頼できる実行環境(TEE)は、ほぼ安全だがサポートされるデバイスは少ない
ホワイトボックス暗号(WBC)は、学術レベルの実装は破られているが、商用WBCへの攻撃成功は事例がない

ハードウェアにあまりにも依存するのは危険。
WBCはアプリケーションレベルで実装されるべき。

ホワイトボックス暗号は、データだけでなく、アルゴリズムそのものも暗号化されている。
攻撃者は、何処に鍵があるのかわからず、抽出することも困難。

鍵とデータ、0-255の数字でスクランブルかけた(Sbox)ものがTboxになる。
通常のAES暗号と同じオペレーションが使われる。
テーブルベースのAES暗号実装では、Tboxを通じて暗号化が行われる。
Tbox（すなわちSbox）が破られると、鍵の復号化が可能になる。

ホワイトボックスAES実装は、外部の入力値をエンコードし、デコードすることができる。

多数Tboxを用意する(Lookup Table)ことで、攻撃者が鍵を解読することを更に困難にできる。

### 既存の攻撃
table-decomposition
全てのTboxを分散関数で計算し、鍵を抽出する手法がある。

power anakysis(電力解析)
電力消費と途中の計算結果を基に、シミュレートされたデータを比較する手法
もっとも強力
保護されていないAES暗号は、途中計算結果の直列が0,1で表現される。
機密データと1バイトの256鍵推測の消費電力との相関で、鍵を抽出することができる。

fault analysis
中間データを変更して、誤りを発生させる

### 既存の研究
ソフトウェアの実行トレースを観察することで、リバースエンジニアリングなしでプリミティブを読み取ることができる

### 商用のWBC実装を対象にした攻撃
実装方式は２つ

- シンプル暗号モード(パフォーマンス重視)
- コンプレックス暗号モード(複雑さ重視)

ラウンド演算解析

- シンプル暗号モードでは、ラウンド演算パターンを見出すことはできなかった。

テイント解析

- データフローと使われたコードから解析する。
- シンプル暗号モードにて、平文トレースでは簡単に暗号プリミティブを見る事ができた。
- 可視化するとただのfor文の繰り返しに見えた
- シンプル暗号モードでは、鍵を抽出することができた。
- コンプレックス暗号モードでは無理だった

fault analysis

- コンプレックス暗号モードでは何処に失敗を注入するかわからないので、使えなかった
- リバースエンジニアリングを通じて、失敗を注入することができ、その出力結果から鍵を復元することができた

## まとめ
WBCは強力でコストパフォーマンスに優れるので、考慮点としては

- マスター鍵を流用しない
- 鍵をハードコートしない
- IVを固定しない

そして、外部エンコードを利用して、電力解析とfault analysisを使えないようにする
WBベース公開鍵アルゴリズムを使用する
コード、データの完全性

デバイスバインディングについては、研究が行き届いていないので、調査が必要。

# LG vs. Samsung スマートTV: あなたを追跡できるのはどちら？
イ・サンミン - Sangmin Lee - 

いろいろあって書けませんでした！
内容は資料を参照してください！

続きます！
Msys2でaws cli with Python pip

# Msys2でaws cli

## Python pipからAWS CLIをインストール

@yumetodo さんにコメントされて気づいたけど、awscliはpython pipからインストールできたんだ。

なおかつ、pipはmsys2のpacmanで配布されてるんでget-pip.pyで入れる必要もなかった。

```shell-session
$ pacman -S python3-pip
$ pip install awscli
$ aws configure
```

これで動かしたらうまく動いた。

## cmd版のAWS CLIを使おうとした記録

シンボリックリンクを張ればOK

```shell-session
$ ln -s /c/Program\ Files/Amazon/AWSCLI/aws /usr/bin/

$ which aws
/usr/bin/aws

$ aws --version
aws-cli/1.11.42 Python/2.7.9 Windows/8 botocore/1.5.5
```

世の中そんなに単純ではなかった…

```shell-session
LoadLibrary(pythondll) failed▒w▒肳▒ꂽ▒▒▒W▒▒▒[▒▒▒▒▒▒▒▒▒▒܂▒▒▒B
C:\msys64\usr\bin\PYTHON27.DLL
```
オススメのPython環境構築

顔認識をTensorFlowでやってみた際、開発環境の構築方法が複数あったり、Python2に問題があってPython3に切り替えたりいろいろ試行錯誤がありました。

その中で一番楽で開発しやすいと思った環境の構築手順をまとめておきます。

メモ書きそのままコピペなので、少しずつ記事として読みやすくしていきます。

# 各OSデフォルトのPython

## Python 2.x系
* MacOS
* CentOS 7
* Ubuntu 16,17

## Not installed
* Windows

---

# Python 2.x系の問題点
* 文字コードのデフォルト設定がASCII
* 3.x系と互換性が無い

---

# とは言え、OSデフォルトのPythonを変えるのは怖い

## 解決策：pyenv
* OSデフォルトのPythonはそのまま残せる
* 開発環境毎にPythonバージョンを切り替えられる

---

# + pyenv-virtualenv
* pyenvのプラグイン
* Pythonバージョンと合わせて開発環境も管理
	* →複数の開発環境をすぐに切り替えられる
	* 例）Stable版とDevelop版

---

# pyenvのインストール
↓この記事の手順を参考にインストール
[PyenvによるPython3.x環境構築(CentOS, Ubuntu)](https://qiita.com/akito1986/items/be5dcd1a502aaf22010b)

---

# インストール可能なバージョン一覧

```bash
$ pyenv install --list
Available versions:
  2.1.3
  2.2.3
  2.3.7
 ~
  3.5.1
  3.5.2
  3.5.3
  3.6.0
  3.6-dev
  3.6.1
  3.6.2
  3.7-dev
```

---

# 任意のバージョンをセットする

```bash
$ pyenv local 3.4.6

$ pyenv versions
  system
* 3.4.6 (set by
/Users/k_nagadou/Documents/Workspace/Documents/.python-version)
  3.4.6/envs/tensorflow
  tensorflow
```
Let's Encryptを利用してApache 2.4サーバをHTTPS化する

#はじめに
[前回の記事](https://qiita.com/ariaki/items/174aacfc224d2af5f2ee)ではApache2.4のHTTPS化する手順をご紹介しましたが、今回は実際に「[Let's Encrypt](https://letsencrypt.jp/)」が発行するSSL証明書を使う方法を紹介します。
また証明書の取得／更新を自動化する手順も併せてご紹介します。

#### 更新履歴
- 2019.6.19 ディレクトリ名を変更

# インストール手順

## 作業方針
前回までと同様にCentOS7向けの手順となります。
その他のOSにインストールする場合は、公式の「[Certbotクライアントのインストール手順](https://letsencrypt.jp/usage/#Install)」をご覧ください。

## Apacheの準備
まずはApache HTTPDサーバを起動し、HTTP通信が可能な状態にしてください。
※初めて証明書を作成する場合はまだSSLが利用できない為、以下のファイルは設置せずにApache HTTPDサーバを起動してください。

- /etc/httpd/conf.d/rewrite.conf
- /etc/httpd/conf.d/ssl.conf


## Certbotインストール
以下のコマンドでCertbotをインストールします。

```
yum -y install certbot
```

## 証明書の初回作成
以下のコマンドで証明書を初回作成する事ができます。

```
certbot certonly --agree-tos --non-interactive -d [ドメイン名] --webroot -w [ドキュメントルートのパス] --email [管理者のメールアドレス]
```

コマンドの実行が完了したら、ディレクトリ`/etc/letsencrypt/live/[ドメイン名]/`に証明書が自動保存されます。

| # | ファイル名 | 設定ディレクティブ | 説明 |
|--:|:----------|:-----|:----|
| 1 | cert.pem | SSLCertificateFile | サーバ証明書 |
| 2 | chain.pem | SSLCertificateChainFile | 中間CA証明書 |
| 3 | fullchain.pem | SSLCertificateFile | サーバ証明書＋中間CA証明書を結合したもの |
| 4 | privkey.pem | SSLCertificateKeyFile | サーバ証明書の秘密鍵 |

## Apache 2.4設定
まずは以下のコマンドでApache設定ディレクトリにシンボリックリンクします。

```
cd /etc/httpd/
ln -s /etc/letsencrypt/live live
```

次に、[前回紹介した手順](https://qiita.com/ariaki/items/174aacfc224d2af5f2ee)をもとに、設定ファイルを追加していきます。

#### ssl.conf

```conf:/etc/httpd/conf.d/ssl.conf
:
<VirtualHost *:443>
    :
    SSLCertificateKeyFile live/[ドメイン名]/privkey.pem
    SSLCertificateFile live/[ドメイン名]/cert.pem
    SSLCertificateChainFile live/[ドメイン名]/chain.pem
    :
</VirtualHost>
```

#### rewrite.conf

```conf:/etc/httpd/conf.d/rewrite.conf
<IfModule rewrite_module>
    RewriteEngine On
    LogLevel alert rewrite:trace3
    RewriteCond %{HTTPS} off
    RewriteCond %{REQUEST_URI} !(^/.well-known/)
    RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R,L]
</IfModule>
```

※前回の手順と比べ、`/.well-known/`パスをリダイレクトしないように変更しています。

## 証明書の更新設定
Let's Encryptが発行する証明書の有効期限は**90日間**と短い為、自動で更新されるように設定しましょう。

```sh:/etc/letsencrypt/letsencrypt-renew.sh
#!/bin/sh
certbot renew -q --no-self-upgrade --post-hook "systemctl restart httpd.service"
```

上記のスクリプトに実行権限を付与し、crontabを設定しましょう。

```
chmod 0700 /etc/letsencrypt/letsencrypt-renew.sh
crontab -e
```

以下の例では、毎日3時に更新チェックが実行されます。

```
0 3 * * * /etc/letsencrypt/letsencrypt-renew.sh
```

## おわりに
今回まででCentOS7インスタンスの作成～Webサーバの設定まで一通りご紹介しました。
それでは楽しいコーディングをエンジョイしてください！

関連記事のリンクを以下にまとめています。

- [GCPに共通鍵を追加する手順まとめ](https://qiita.com/ariaki/items/e225b815924d37bc19d5)
- [GCP Compute Engineを使ってLinuxサーバを始める](https://qiita.com/ariaki/items/1d4dbfeb41a4080a3f66)
- [Cent OS 7開発用サーバを初期設定する](https://qiita.com/ariaki/items/d84a651427f418c5103e)
- [Cent OS 7上でApache/PHP開発環境を構築する](https://qiita.com/ariaki/items/2ec627a7567437f893ee)
- [Cent OS 7上でApache/Tomcat開発環境を構築する
](https://qiita.com/ariaki/items/6fafac7d89ea14b12203)
- [Apache 2.4にmod_sslを設定する](https://qiita.com/ariaki/items/174aacfc224d2af5f2ee)
Javaのリソース取得 ～高負荷・長時間化・フリーズ対応～

## はじめに
取得すべき情報の調査方法までは言及しません。
個人的な備忘録を兼ねて、Javaが高負荷・長時間化・フリーズしたという時に
取得したい情報についてまとめます。
※ここでいう長時間化は「処理は止まっていないがSLAを守れない速度で処理し続けている」ことを表す。


## そもそもの発端
Javaが長時間化・フリーズした場合、自分（もしくはチーム）で調査するか
どこか別のチームに調査依頼するか行うと思いますが、

「○○が長時間化しました！調査お願いします！情報は無いよ！」
「（情報の取り方わからないし、何取ればいいかもわからない）とりあえずkillした」

ということが時たまあります。
これでは聞かれた側も調査できません。
場合によっては
「情報が無いから調査無理、再現待ち」
となるか
「情報取るためにとりあえずもう一回動かそう」
となります。
それは避けたいので発生したときの情報を取得するか、取得してもらいましょう。

ただし、高負荷が発生しているときは別です。
放置するとシステム全体に悪影響を与える可能性があるため、情報の取得をすぐにできない
場合は一旦諦めて高負荷のプロセスをkillする等の対応を優先する必要があります。

## プロセスIDの特定
情報を取得するためにはJavaアプリのプロセスIDを特定する必要があります。

【高負荷の場合】
psコマンドで特定してもいいですが、topコマンドの方が視覚的にわかりやすいです。
topコマンドではパフォーマンス状態をモニタリングすることができます。
高負荷が発生しているサーバにログインしてからtopコマンドを実行。
※高負荷過ぎてsshで接続できない場合は接続を何回か試してください。
```top -c```
topコマンド実行後、下記コマンドを入力すると高負荷のプロセスIDを特定できます。
「Shift+m」：メモリ使用率順にソート
「Shift+p」：CPU使用率順にソート

【長時間化・フリーズの場合】
psコマンドでプロセスIDを特定できます。
Javaアプリをバッチ起動している場合はそのコマンド文（スクリプト文）から
プロセスIDを特定することができます。
```ps -ef | grep "コマンド文"```
上記コマンドでコマンド文のプロセスIDが取得できるため、そのコマンド文が
親プロセスIDであるプロセスのプロセスIDを取得し、さらにそのプロセスIDが
親プロセスIDであるプロセスを取得し……を繰り返せばJavaアプリのプロセスIDを
特定できます。
（もっとスマートな方法があるかもしれません……）

## 取得したい情報の取得
若干過剰気味に記載しています。
リダイレクトすればファイルに出力することが可能です。

【ディスク情報の取得】
```df -k```

【生存しているオブジェクトのみのヒープダンプの取得】
```jmap -histo:live ${PID}```

【全てのヒープダンプの取得】
```jmap -dump:format=b,file=${OUT_PATH}/jmap_heap-dump.dat ${PID}```

【スレッドダンプの取得】
```jstack -l ${PID}```

【パフォーマンス状態の取得】
```top -bc -n 1```

【プロセス情報の取得】
```ps -ef |grep ${PID}```

【GC状態の取得】
```jstat -gcutil ${PID} 10000 5```

【ネットワーク接続状態の取得】
```netstat```

【プロセスが利用しているポートの取得】
```lsof```

【CPU情報の取得】
```cat /proc/cpuinfo```

【メモリ情報の取得】
```cat /proc/meminfo```


## さいごに
発端に軽く記載しましたがこの記事で伝えたかったのはリソースの取得方法よりも、
問題が発生した事象だけ伝えて丸投げするのはやめましょう、ということです。
調査を依頼するときは自分が言われて調査できるだけの内容を添付した上で
依頼することを勧めます。
Vagrant上のGoコードにホスト側のVS Codeから補完を効かせる

# なにがしたいのか

VM上で実行させているGoのコードについて、ホスト側のエディタで補完やGo fmtを効かせたい

# 環境
Vagarnt
Mac 
Goの実行環境はホスト側、VM側に両方に入れておく
ホストのエディタは Visual Studio Code (VS Code)

# ホスト側

```:フォルダ構成
<VMのルートフォルダ>
└Vagrantfile
└src
  └<Goのソースフォルダ>
    └model (例)
      └dao (例)
```

srcフォルダの下に、Goのソースフォルダを配置するのがポイントです。

# VS Codeの「ワークスペースの設定」

VS Codeで src フォルダを開く。
基本設定⇒設定　を開いて「ワークスペースの設定」より、以下を追記

```json:ワークスペース設定
{
    "go.gopath": "<VMのルートフォルダ>"
}
```

# Vagrant VM側

コレがなくても補完は出来ますが、VM上でGoのソースを実行するための必要な同期設定です。

```rb:Vagrantfile
    config.vm.synced_folder "./src/<Goのソースフォルダ>", "<マウント先>"
```

# Goからのimport例

```go:main.go
import (
	"<Goのソースフォルダ>/model/dao"
}
Visual Studio | WPF | C# > 関連記事リンクのマップ

```txt:動作環境
Windows 8.1 Pro (64bit)
Microsoft Visual Studio 2017 Community
Sublime Text 2
```

### 前置き

linux上でcsh, bash, NCL, Pythonを使いながら数値計算を行いつつ、C++ Builder上でVCLのソフトを設計、C++実装しつつ、MatlabコードをNumpyで実装しなおそうとしたり、Jupyter + Matplotlibでグラフ描画したり、Rを使って膨大なデータの処理をしてみる。
Raspberry PiでPythonを使ったツールを作り、ESP8266で通信処理ツールをC実装してみる。
PowerShellでPCの調子をロギングしたり、Excel VBAでちょっとした処理ファイルを実装する。

ちょっと時間ができそうなので、今のうちにVisual Studio / WPFに慣れよう。

さて、文字列置換の関数は何だったっけ。。。

### マップ

自分がC++ Builderで実装したことがある機能に関して、Visual Studio + WPF + C#でどのように実装するかを整理する。

[mindmup](https://atlas.mindmup.com/yasokada/_171109/index.html)

将来、別の言語、プラットフォームから戻ってきたときに、すんなり実装作業に入れたらいいなぁ。

記憶力の良い人は、上記のような環境についてそれぞれ詳細を覚えていていつでも使えて、それぞれのコーディングルールをきちんと切替えて使い分けるだろう。

目標は「４０秒で支度しな！」に応える。
Google Home 「OK Google, 」 が恥ずかしくて言えない...

# おっけーグーグル
言えない。どうしても言えない。なんなら、アキラ100%を忘年会でやる方を選ぶ。
API.AI(Dialogflow)と繋げて遊ぶにはどーすればいい？

e.g. [OK Google]("https://www.youtube.com/watch?v=pKJD39Q26rQ&t=7s")
## 神アプリ
[「ゆっくり棒読みトーク」]("https://goo.gl/M4z9ce") ... なんと素晴らしい！これだ！！

## 基本的な流れ
1. Google Homeに話しかけた内容でメールしてもらう
2. やり方は[これ]("https://qiita.com/diescake/items/4f354a5dc7cb738efd4f")と同じ。[Twitter編]("https://qiita.com/kazunori279/items/fdadbfde58ed133bb9d5") はこちら

## IFTTT
### This
![IFTTT_Flex.png](https://qiita-image-store.s3.amazonaws.com/0/149993/ceb33ba6-461a-6820-3b86-a6f8d663ecf5.png)
### That
Gmailを選択自分宛に送信テストの準備

## 神アプリ起動、準備
![IMG_1004.jpg](https://qiita-image-store.s3.amazonaws.com/0/149993/b6086cff-7e51-16b8-fa6f-48c1c6472840.jpeg)

周りのノイズに全く影響受けずに、アプリの「おっけーグーグル」にちゃんと反応！
スピードはデフォルトで十分反応してくれる。素晴らしい！

## きたー
![IMG_1005.jpg](https://qiita-image-store.s3.amazonaws.com/0/149993/a008fcc5-2e56-f06c-3512-807dd772443e.jpeg)
DOM Event フローのおさらい

DOM Event がどのように発火するのか


https://www.w3.org/TR/DOM-Level-3-Events/

上記のページで Chrome Dev Tool を開きコンソールで以下のコードをコピペして実行して、画面をクリックしてみてください。

以下のコードでは `window` `body` `div#MAIN0` にそれぞれクリックイベントをバインドし、`console.log` でメッセージを吐き出しています。
メッセージがどういう順番で出力されれるかわかるでしょうか？

```js

document.getElementById('MAIN0').addEventListener('click', function(e){ console.log('MAIN0 clicked'); }, false);

window.addEventListener('click', function(e){ console.log('window clicked'); }, false);

document.getElementsByTagName("body")[0].addEventListener('click', function(e){ console.log('body clicked'); }, true);

```

答えは・・・

```text
body clicked
MAIN0 clicked
window clicked
```

こうなります。


`addEventListener` では第三引数の Boolean がキャプチャのフラグになっていて、`true` にするとキャプチャされて実行順序が変化しています。整理すると以下のようなフローになります。

- キャプチャーフェーズでルートの Window からイベントが発火したターゲットまでをたどり、キャプチャされているイベントを発火
- ターゲットのイベントを発火
- 伝播フェーズでターゲットからルートまでを遡り、バインドされているイベント発火

それでは次のコードはどうでしょうか。

```js

document.getElementById('MAIN0').addEventListener('click', function(e){ console.log('MAIN0 clicked'); }, false);

window.addEventListener('click', function(e){ console.log('window clicked'); }, false);

document.getElementsByTagName("body")[0].addEventListener('click', function(e){ console.log('body clicked'); e.stopPropagation(); }, true);

```
答えは・・・

```text
body clicked
```

- `body` でクリックイベントがキャプチャされ `stopPropagation()` で伝播が停止しているので、それ以上のイベントフローが停止します。


ちなみに jQuery だとこのようになります。

```js
$('#MAIN0').on('click', function(e){ console.log('MAIN0 clicked'); });
$(window).on('click', function(e){ console.log('window licked'); });
$('body').on('click', function(e){ console.log('bodyclicked'); });
```

キャプチャフラグは jQuery では false で固定なので使えません。
ネイティブでしか使う機会がありませんが覚えておきたいですね。

W3C の図版が非常にわかりやすいので引用しておきます。

![](https://www.w3.org/TR/DOM-Level-3-Events/images/eventflow.svg)

Graphical representation of an event dispatched in a DOM tree using the DOM event flow
Csharp > string > 置換 > Replace() 

```txt:動作環境
ideone > C# (gmcs 4.6.2)
```


https://ideone.com/4D4OKS

```csharp
using System;

public class Test
{
	public static void Main()
	{
		string txt = "Hello";
		txt = txt.Replace("l", ":");
		Console.WriteLine(txt);
	}
}
```

```txt:run
Success	#stdin #stdout 0.01s 131648KB
He::o
```

### link

https://msdn.microsoft.com/ja-jp/library/fk49wtc1(v=vs.110).aspx
Cygwinにpipを入れる

しょうもない記事(メモ書き)です。

**※apt-cyg導入済みの前提です。**

# 結論

```bash
# 2系のpip
apt-cyg install python-pip
apt-cyg install python2-pip

# 3系のpip
apt-cyg install python3-pip
```

# 余談

ググると何故か皆さん謎の苦労をかけてインストールしていて、
なんとなくそれはないだろうと思って`searchall`してみたらあったという訳でした。

```shell-session
$ apt-cyg searchall python | grep pip
--2017-11-10 10:28:07--  http://cygwin.com/cgi-bin2/package-grep.cgi?text=1&arch=x86_64&grep=python
cygwin.com (cygwin.com) をDNSに問いあわせています... 209.132.180.131
cygwin.com (cygwin.com)|209.132.180.131|:80 に接続しています... 接続しました。
HTTP による接続要求を送信しました、応答を待っています... 200 OK
長さ: 特定できません [text/plain]
`matches' に保存中

matches                     [        <=>                  ] 188.77K  15.7KB/s 時間 12s

2017-11-10 10:28:21 (15.7 KB/s) - `matches' へ保存終了 [193298]

python-pip
python2-pip
python3-pip
```
micro:bitにサードパーティーのPythonライブラリをインストールしたい（mac）

はじめに、私はPythonや電子工作に関しては素人です（英語も苦手）。
子供と遊ぶために入手したmicro:bitで、父の威厳を見せつけるために、カッコつけてpythonでコードを記述したのですが、自作のライブラリをMac環境からインストールしようとして苦戦したのでメモします。

## 参考サイト
https://microbit-playground.co.uk/howto/add-python-module-microbit-micropython

## 準備
- Pythonエディタ「mu」をインストール
- USBケーブルでmicrobitを接続してマウント

## インストール手順
1. ~/mu_code へ、ライブラリとメインコードのpyファイルをコピーする
2. mu を起動し、Command+Nでundefinedファイルを開いて(空のファイルなら何でもOK)muの「Flash」を実行する
3. muの「Files」を押してライブラリファイルをmicrobitへドラッグ&ドロップ
4. 最後にメインコードをドラッグ&ドロップ。
5. muの挙動があやしくなる。マウスカーソルが処理中のまま復帰しないが、microbitの黄色LED点滅が停止したら成功？

~/mu_code はmuで自動的に生成されるあのディレクトリです。

自分の開発環境や作成したコードのせいかもしれないのですが、メインプログラムがインストールされたmicrobitはFilesで開こうとすると、マウスカーソルが処理中のままmuが反応しなくなる。まずここで苦戦しました。
5でmuが反応しなくなるのはこれのせい？

次に、microbitへコードをインストールするとき、今まではmuでコードを開いた状態でFlashを押してインストールしていました。なので、Filesでドラッグ&ドロップしてメインコードをインストールする発想がありませんでした。
AWS BatchでError: listen EADDRINUSE :::3000


コンテナ内で3000ポートを使用するジョブが1つのEC2インスタンス内に複数存在すると, `Error: listen EADDRINUSE :::3000`エラーになる問題でハマりました。

サポートに問い合わせたところ、Batchでは`docker run`のオプションとして`--network="host"`を固定で設定しているおり、コンテナ内でLISTENするポートはホストでもLISTENされるため、`EADDRINUSE`エラーになるとの回答でした。

現時点では`--network="host"`を手動で設定することはできないため、`EADDRINUSE`になったら別のポートでリトライするという実装にして問題を回避することにしました。
Androidでパッケージマネージャーから起動した場合二重起動してしまった

Androidで

- A.ホームからアプリアイコンから起動した場合
- B.アプリをブラウザでダウンロードしインストール後のパッケージマネージャーアプリから起動した場合

の２つの起動方法で動作が異なり、ネットを彷徨い続けたのでメモ。

具体的にはスプラッシュ画面を実装しているのだが、

- Aで起動　→ スプラッシュが終了 → ホームボタン → Aで起動 → 前回終了画面
- Bで起動　→ スプラッシュが終了 → ホームボタン → Aで起動 → スプラッシュ画面が起動

なぜか、インストールを行ったパッケージマネージャーでそのまま、開くを押して起動した場合に前回終了画面から再開してくれない。

一応 ```android:launchMode="singleTask"```　にすれば、動作の違いは解消しますが、
前回終了画面から再開してほしい・・・

この現象調べまくっていると、
https://groups.google.com/forum/#!topic/android-group-japan/xTkgh24lnRc
全く同じ現象をやりとりしていて、これだ！と思ったのですが、
```android:launchMode="singleTask"```
にするとの回答しかありませんでした。
>Launcher Activity に android:launchMode="singleTask"を設定すると、
>既に起動されているTaskが使用されますが、最後に表示していたActivity
>が表示される保障があるわけではなく、Launcher Activityが最前面になり
>ますよね？

中にこのような質問があり、そう！そうなんですよ！と思いましたが、それの回答は見当たらず・・・

最終的に以下サイトに行き着きました。
http://d.hatena.ne.jp/kk_Ataka/20130804/1375624170


>ブラウザからinstallして起動したときと、ランチャーから起動した時では、
起動するときのIntentが微妙に異なります。
その為、ランチャーから起動した場合の、「既に起動していたら二重起動しない」という
仕組みが動作しません。
二重起動されたActivityでは、起動IntentにFLAG_ACTIVITY_BROUGHT_TO_FRONTがセットされるようなので、

```SplashActivity.java
protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  if ((getIntent().getFlags() & Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT) != 0) {
    finish();
    return;
  }
}
```

>のようにすると、所望の動作になると思います。

上記の修正をそのまま対応して解決。
【Ubuntu Server 16.04 LTS】機械学習用にPCを組んでみた その4（python開発環境構築）

python環境は、pyenv + anacondaを用いて構築します。

#それぞれの役割
pyenv：pythonの複数バージョンの管理
anaconda：仮想環境の管理　※正確にはanacondaに含まれるcondaで
pyenv >> conda >> 仮想環境

#事前準備
必要なパッケージをインストールします。

```bash
$ sudo apt-get install -y make build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev libpng-dev
```
#pyenvのインストール

pyenvおよびプラグインをインストールし、環境を整えます。

```bash
$ git clone git://github.com/yyuu/pyenv.git ~/.pyenv
$ git clone https://github.com/yyuu/pyenv-pip-rehash.git ~/.pyenv/plugins/pyenv-pip-rehash
$ echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bashrc
$ echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bashrc
$ echo 'eval "$(pyenv init -)"' >> ~/.bashrc
$ source ~/.bashrc
```
#Anacondaのインストール

最新のAnaconda (python3系) のバージョンを確認します。

```bash
$ pyenv install -l | grep anaconda3
  anaconda3-2.0.0
  anaconda3-2.0.1
  anaconda3-2.1.0
  anaconda3-2.2.0
  anaconda3-2.3.0
  anaconda3-2.4.0
  anaconda3-2.4.1
  anaconda3-2.5.0
  anaconda3-4.0.0
  anaconda3-4.1.0
  anaconda3-4.1.1
  anaconda3-4.2.0
  anaconda3-4.3.0
  anaconda3-4.3.1
  anaconda3-4.4.0
  anaconda3-5.0.0
```
最新のAnaconda (5.0.0) をインストールし、デフォルトの環境として設定します。

```bash
$ pyenv install anaconda3-5.0.0
$ pyenv global anaconda3-5.0.0
$ echo 'export PATH="$PYENV_ROOT/versions/anaconda3-5.0.0/bin:$PATH"' >> ~/.bashrc
$ source ~/.bashrc
```
Pythonの環境を確認します。

```bash
$ python --version
Python 3.6.2 :: Anaconda, Inc.
```

練習がてらpython2.7の仮想環境を作ってみます。
ここでは仮想環境の名称をpy27とします。

```bash
$ conda create -n py27 python=2.7 anaconda
```

仮想環境が出来ていることを確認します。

```bash
$ conda info -e
# conda environments:
#
py27                     /home/hoge/.pyenv/versions/anaconda3-5.0.0/envs/py27
root                  *  /home/hoge/.pyenv/versions/anaconda3-5.0.0
```

下記コマンドで環境を切り替えます。

```bash
$ source activate py27
(py27)$
```
※仮想環境に入ると先頭に(py27)がつきます。

念の為、python環境が切り替わっていることを確認します。

```bash
$ python --version
Python 2.7.12 :: Anaconda 4.1.0 (64-bit)
```

仮想環境を抜けるときは下記コマンド。

```bash
$ source deacivate
```

あとは仮想環境内で必要なpythonライブラリをcondaやpipでインストールしていきます。
もし仮想環境がグチャグチャになったら下記コマンドで削除できます。

```bash
$ conda remove -n py27 --all
```
Puppeteer で FirstMeaningfulPaint を取得する

## 概要

- パフォーマンスメトリクスのAPIを有効化する
- setTimeout ループで FMP取得まで待つ

## コード

`npm install -S puppeteer`

```js:fmp.js
const puppeteer = require('puppeteer')

async function getPerformanceMetrics(page) {
  const { metrics } = await page._client.send('Performance.getMetrics')
  return metrics.reduce((acc, i) => ({ ...acc, [i.name]: i.value }), {})
}

async function waitForFMP(page) {
  let doneMet = null
  while (true) {
    const data = await getPerformanceMetrics(page)
    if (data.FirstMeaningfulPaint !== 0) {
      doneMet = data
      break
    }
    await new Promise(resolve => setTimeout(resolve, 300))
  }
  return doneMet
}

async function run(url) {
  const browser = await puppeteer.launch()
  const page = await browser.newPage()
  await page._client.send('Performance.enable')
  await page.goto(url)
  const m = await waitForFMP(page)
  console.log(
    `${url}: ${~~((m.FirstMeaningfulPaint - m.NavigationStart) * 1000)}ms`
  )
  browser.close()
}
;(async () => {
  await run('https://google.com')
  await run('https://qiita.com')
  await run('https://github.com')
  await run('https://twitter.com/mizchi')
  await run('https://r.nikkei.com')
  await run('https://yahoo.co.jp')
  await run('https://www.rakuten.co.jp/')
})()

```

ターゲットはそれっぽいサイトを適当に選びました。

```
$ node fmp.js
https://google.com: 669ms
https://qiita.com: 723ms
https://github.com: 1089ms
https://twitter.com/mizchi: 992ms
https://r.nikkei.com: 849ms
https://yahoo.co.jp: 618ms
https://www.rakuten.co.jp/: 452ms
```

async/await と object-rest-spread 使ってるのでたぶん node 8.x じゃないと動かないです。

これたぶんUnixtime で返ってて Timestamp からの差分だと思うけど自信はない。

## おまけ: 取得できる内部パラメータ

今回は getPerformanceMetrics の FirstMeaningfullPaint だけ使いましたが、内部的にはこんなパラメータが取れています。

```js
export type Metrics = {
  Timestamp: number,
  AudioHandlers: number,
  Documents: number,
  Frames: number,
  JSEventListeners: number,
  LayoutObjects: number,
  MediaKeySessions: number,
  MediaKeys: number,
  Nodes: number,
  Resources: number,
  ScriptPromises: number,
  SuspendableObjects: number,
  V8PerContextDatas: number,
  WorkerGlobalScopes: number,
  UACSSResources: number,
  LayoutCount: number,
  RecalcStyleCount: number,
  LayoutDuration: number,
  RecalcStyleDuration: number,
  ScriptDuration: number,
  TaskDuration: number,
  JSHeapUsedSize: number,
  JSHeapTotalSize: number,
  FirstMeaningfulPaint: number,
  DomContentLoaded: number,
  NavigationStart: number
}

```

TaskDuration がJSの実行やCSSのLayoutにかかった時間の合計で、ここらへんも参考になります。
[Python]itertoolsでループのネストを回避する

何か良い書き方があったはずと思いつつ、なかなか思い出せず……
結構探してしまったのでメモ。

```python
for i in range(m):
    for j in range(n):
        # 何か処理
```

みたいなループは以下のように書ける。

```python
from itertools import product

for i, j in product(range(m), range(n)):
    # 何か処理
```

簡潔!!

複数のリストの全ての組み合わせを舐めたいときなどに。
IE11とEdgeでボタンの文字が改行しないときはbuttonタグを使うとよい

参考: [IE11でボタンのtextを改行するには](https://social.technet.microsoft.com/Forums/ja-JP/439ffb36-6969-4682-a474-c9d6c2ca1166/ie11text?forum=internetexplorerja)

## 現象

IE11やEdgeでは以下だとボタンの文字が改行しない。

```html
<input type="submit" value="push
me" />
```

## 回避方法

buttonタグを使う

```html
<button type="submit">push<br>me</button>
```
ramdaの関数合成によるデータとロジックの分離

以下の記事を読みました。

**[Proxy "it": アローすら面倒な怠惰JavaScripterのための遅延評価](https://qiita.com/tkynd/items/8ceb5c6461ac99a13908)** 

`arg => arg`のアロー関数部分がスマートでないことをProxyで解決するのは非常に面白いです。

別のアプローチとして、同じ処理をramdaで関数合成を使って書いてみます。
あまりramdaのヘビーユーザーではないので、間違っていたら教えて下さい。

https://github.com/ramda/ramda

```
yarn add ramda
```

```js
const R = require('ramda')

const fn = R.map(
  R.compose(
    R.prop(2),
    R.map(R.compose(parseFloat, R.trim())),
    R.split(','),
    R.prop('values')
  )
)

const data = [
  { id: 1, values: '3,  1,   4, 1, 5' },
  { id: 2, values: '2, 7, 1,   8, 2   ' },
]

console.log(fn(data))
// => [ 4, 1 ]
```

`args => args`のパターンはなく、データと処理も分離できました。
型的にも扱いやすいです。
少し冗長に感じるかも知れませんが、全てが関数で処理が分割可能なので、再利用性が高いです。
まあ、ちょっと関数脳過ぎるので普段使いはしていませんけれど。


## おわりに

さらに他の手段としては、pipelineオペレータの仕様が入れば、こういったものをスマートに書くことができそうで楽しみです。

https://github.com/tc39/proposal-pipeline-operator

<blockquote class="twitter-tweet" data-partner="tweetdeck"><p lang="ja" dir="ltr">ramdaのcomposeとpipeは言わずもがな便利で、R.pathや R.curryの便利さはわかるが、これをライブラリの依存にぶっこんでくるのはサイズ的に許しがたい <a href="https://t.co/8wUYV3S9Ad">pic.twitter.com/8wUYV3S9Ad</a></p>&mdash; あかめ@無職.js (@akameco) <a href="https://twitter.com/akameco/status/905395683909263360?ref_src=twsrc%5Etfw">September 6, 2017</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

<blockquote class="twitter-tweet" data-conversation="none" data-cards="hidden" data-partner="tweetdeck"><p lang="ja" dir="ltr">coolではある。coolではあるが、混乱せず使えるユーザがいるかというと <a href="https://t.co/WNtTjYuxz0">pic.twitter.com/WNtTjYuxz0</a></p>&mdash; あかめ@無職.js (@akameco) <a href="https://twitter.com/akameco/status/913723205759647745?ref_src=twsrc%5Etfw">September 29, 2017</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
Octave > コメント > Single Line Comments > # (%はエラー?)

```txt:動作環境
ideone > Octave (octave 4.0.3)
```

https://www.gnu.org/software/octave/doc/v4.2.1/Single-Line-Comments.html#Single-Line-Comments
> In the Octave language, a comment starts with either the sharp sign character, ‘#’, or the percent symbol ‘%’ and continues to the end of the line.

https://ideone.com/VRq0qe

```matlab
x = [ 3.141, 3.141, 3.141 ];
y = [ 1.0, 2.0, 3.0 ];
x
% rdivide(x, y)
```

```txt
compilation info
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/usr/lib/python2.7/py_compile.py", line 117, in compile
    raise py_exc
py_compile.PyCompileError:   File "prog.py", line 4
    % rdivide(x, y)
    ^
SyntaxError: invalid syntax
```

ideoneだと「%」ではエラーになり「#」はコメントとして認識される。
Octave > @ > Function Handles > x = bsxfun(@rdivide,x,sqrt(sum(x.^2,2)));

```txt:動作環境
ideone > Octave (octave 4.0.3)
```

https://github.com/gradywright/spherepts/blob/master/code/getIcosNodes.m

```matlab
x = bsxfun(@rdivide,x,sqrt(sum(x.^2,2)));
```

rdivideというのは関数。
https://www.gnu.org/software/octave/doc/interpreter/Arithmetic-Ops.html

~~rdivideの前に@をつける意味は未消化。~~

以下で見つけた。
https://www.gnu.org/software/octave/doc/v4.2.0/Function-Handles.html
> A function handle is a pointer to another function and is defined with the syntax

```
@function-name
```

Matlabの情報
https://jp.mathworks.com/help/matlab/matlab_prog/creating-a-function-handle.html
Gitコマンド早見表

[作業別Gitコマンド集](https://qiita.com/kohga/items/20819414da2972bc5e0d)の圧縮版

###### 初期設定を行う
```bash
$ git config --global user.name "XXXX"
$ git config --global user.email "XXXX@hogehoge.com"
```
###### ローカルにリポジトリを作成し、リモートにプッシュする
```bash
$ git init
$ git add .
$ git commit -m "Initial commit"
$ git remote add origin https://github.com/XXXX/XXXXXX.git
$ git push -u origin master
```
###### リモートからクローンする
```bash
$ git clone https://github.com/XXXX/XXXXXX.git
```
###### リモートから変更を取得する
```bash
$ git pull
or
$ git fetch
$ git merge origin/master
```
###### ファイルの登録（コミットするため）
```bash
$ git add <ファイル名>
```
###### ファイルの変更や追加をコミット
```bash
$ git commit -m "コミットメッセージ"
```
###### ローカルの変更を確認する
```bash
$ git status
```
###### リモートとローカルのファイルの差分を抽出する
```bash
$ git diff <ファイル名>
```
###### commitの変更履歴をみる
```bash
$ git log
```
###### 指定したcommitの変更点を見る
```bash
$ git show <コミットのハッシュ値>
```
###### リモートにプッシュ
```bash
$ git push origin <ブランチ名>
```
###### addの取り消し
```bash
$ git reset HEAD <ファイル名>
```
###### commitの取り消し
```bash
$ git reset --hard HEAD^
```
--hard：コミット取り消した上でワークディレクトリの内容も書き換えたい場合
--soft：ワークディレクトリの内容はそのままでコミットだけを取り消したい場合
HEAD^：直前のコミット
HEAD~{n} ：n個前のコミット

###### commitの打ち消し
```bash
$ git revert <コミットのハッシュ値>
```
###### コミットメッセージの修正
```bash
$ git commit --amend "新しいコミットメッセージ"
```
###### pushの取り消し
```bash
$ git reset --hard <戻したいコミットのハッシュ値>
$ git push -f
```
###### ローカルでブランチを作成
```bash
$ git branch <ブランチ名>
```
###### ローカルでブランチを切り替え
```bash
$ git checkout <ブランチ名>
```
###### ブランチ作成 & 切り替え
```bash
$ git checkout -b <ブランチ名>
```
###### ブランチ名の変更
```bash
$ git branch -m <古いブランチ名> <新しいブランチ名>
```
###### ブランチの削除
```bash
$ git branch -d <ブランチ名>
```
###### ローカルのブランチをリモートに反映
```bash
$ git push -u origin <ローカルのブランチ名>
```
###### リモートのブランチをローカル持ってくる
```bash
$ git branch <ブランチ名> origin/<ブランチ名>
```
###### リモートのブランチをローカル持ってくる & 切り替え
```bash
$ git checkout -b <ブランチ名> origin/<ブランチ名>
```
###### 全てのブランチを確認する
```bash
$ git branch -a
```
###### ブランチを比較する
```bash
$ git diff <ブランチ名> <ブランチ名>
```
###### ブランチをマージする
```bash
$ git merge <ブランチ名>
```
###### fast-forwardの関係であっても必ずマージコミットを作る

```bash
$ git merge --no-ff <ブランチ名>
```

###### ブランチをリベースする
```bash
$ git rebase <ブランチ名>
```
※ mergeの場合は分岐元、rebaseの場合は分岐先のブランチで実行するという点に注意してください。
###### 変更点を一旦退避させる
```bash
$ git stash save
```
###### 退避した作業の一覧を見る
```bash
$ git stash list
```
###### 退避した作業を戻す
```bash
$ git stash apply <stash名>
```
###### 退避した作業を消す
```bash
$ git stash drop <stash名>
```
###### 退避した作業をすべて消す

```bash
$ git stash clear
```
###### ファイル削除
```bash
$ git rm -f  <ファイル名>
```
###### ファイルリネーム
```bash
$ git mv <元のファイル名> <変えたいファイル名>
```
###### ファイルを最新のコミットの状態に戻す
```bash
$ git checkout HEAD <ファイル名>
```
###### ファイルを指定コミットまで戻す
```bash
$ git checkout <コミットのハッシュ値> <ファイル名>
```
###### .gitignore を無視して追加する
```bash
$ git add -f <ファイル名>
```
###### ディレクトリだけ登録(.gitkeepをディレクトリに作成する)
```bash
$ touch <ディレクトリ名>/.gitkeep
```

＜参考＞

- [Pro Git 第2版](https://git-scm.com/book/en/v2)
- [サルでもわかるGit入門](https://www.backlog.jp/git-guide)
macOSでコードリーディング向けneovim環境を手早く構築する

macOS High Sierra(10.13.1)上にNeovim(0.2.0)環境を整理したので手順を残します。「コードリーディング向け」環境を「手早く」ということで以下を前提にします。

　・Vim Bootstrapの利用してNeovimの設定ファイルを作成
　・タグジャンプ用にgtagsを追加
　・カーソル移動を快適にするeasymotionを追加

#neovimのインストール
Homebrewがすでにインストールされていることを前提にします。

```sh
$ brew install neovim
```

#Vim Bootstrap
[Vim Bootstrap](http://www.vim-bootstrap.com/)は，vimの設定ファイルを数クリックで生成してくれる便利なサイトです。私自身CとPythonのソースコードを扱う機会が多いため，その2つを選択して設定ファイルを生成しました。

中央の「Make your .vimrc now!」を押して，
![画面.png](https://qiita-image-store.s3.amazonaws.com/0/45990/8f12bb31-269b-4877-7e3e-2af0eccc25a8.png)

ターゲットとなるプログラミング言語を選択（複数可）して，
![言語選択.png](https://qiita-image-store.s3.amazonaws.com/0/45990/fa402943-c899-9c98-93cf-b6ddf9db2471.png)

vimとneovimのどちらかを選んで，「Generate!」ボタンをクリックすれば終了（簡単！）
![スクリーンショット 2017-11-07 6.16.27.png](https://qiita-image-store.s3.amazonaws.com/0/45990/08a5eb0d-62dc-6af7-ff43-fcdb732422f8.png)

#設定ファイルの登録

以後の操作は，基本的に[こちら](https://github.com/avelino/vim-bootstrap#installation)に書いてありますので，詳細はこちらを参考にしてください。

まず生成した設定ファイルをneovimの初期化ファイルとして配置します。すでにneovimをカスタマイズして利用している方は，事前にinit.vimファイルのバックアップを取得することをお勧めします。

```shell-session 
$ mv ~/Downloads/generate.vim $XDG_CONFIG_HOME/nvim/init.vim
```

ここで利用している環境変数`XDG_CONFIG_HOME`についてはこちらを参照してください。検証時の環境では，この環境変数が定義されておらず，init.vimが`~/.config/nvim`配下にあったため，こちらを指定しました。

```shell-session 
$ mv ~/Downloads/generate.vim ~/.config/nvim/init.vim
```

次にneovimのプラグインをインストールします。

```shell-session 
$ nvim +PlugInstall +qall
```

#カスタマイズ
Vim Bootstrapによって生成した設定ファイルは基本的に変更を加えないほうがよいです。このため，独自のカスタマイズを行う際は，同ディレクトリに`local_bundles.vim`と`local_init.vim`を作成し，こちらに記述します。

##local_bundle.vimの作成（プラグインの追加）
下記のように追加したいプラグインを列挙していくだけです。

```vim:$XDG_CONFIG_HOME/nvim/local_bundles.vim 
Plug 'easymotion/vim-easymotion'
Plug 'ghttiger2505/gtags.vim'
Plug 'vim-scripts/gtags.vim'
```

念のため，作成後にもプラグインの反映コマンドを実行します。

```shell-session 
$ nvim +PlugInstall +qall
```

##local_init.vimの作成（そのほかのカスタマイズ）
プラグイン以外の設定は`local_init.vim`に設定します。下記はあくまで参考です。お好みの設定をしてください。

```vim:$XDG_CONFIG_HOME/nvim/local_init.vim 
" for easy motion
let g:EasyMotion_do_mapping = 0 "Disable default mapping
nmap m <Plug>(easymotion-s2)

" for gtags
nnoremap <silent> <Space>g :Gtags<CR>
nnoremap <silent> <Space>j :GtagsCursor<CR>
nnoremap <silent> <Space>l :Gtags -f %<CR>
nnoremap <silent> <Space>n :cn<CR>
nnoremap <silent> <Space>p :cp<CR>

"mouse enable
set mouse=a
```

##参考：設定の適用順序
Vim bootstrapが生成した`init.vim`ファイルを見ると以下の流れで上記の設定が反映されることがわかります。

1. Vim bootstrapのデフォルトプラグインのロード
2. `local_bundles.vim`に記述したプラグインのロード
3. Vim bootstrapのデフォルトセットアップ
4. `local_init.vimに`記述したデフォルトセットアップ

#さいごに
Vim-bootstrapを利用すれば簡単にneovim(vim)の設定ファイルを作成することができ，それ以外のカスタマイズを別ファイルに分けることができるため設定情報もシンプルに扱うことができます。
[VBscript]公式が教えてくれないFilesystemobjectでファイル名を変更するときの注意点

#1.使うメソッド
[MoveFile メソッド](https://msdn.microsoft.com/ja-jp/library/cc428039.aspx)

```vbnet
object.MoveFile ( source, destination ); 
```

###引数
####object
必ず指定します。FileSystemObject オブジェクトの名前を指定します。
####source
必ず指定します。移動するファイルのパスを指定します。パスの最後の構成要素内ではワイルドカード文字を使用できます。
####destination
必ず指定します。ファイルの移動先のパスを指定します。ワイルドカード文字は使用できません。
###解説
引数 source にワイルドカード文字を使用したとき、および引数 destination がパスの区切り文字 (\) で終わるとき、引数 destination には既存フォルダを指定したと判断され、条件に一致するファイルがそのフォルダ内へ移動されます。それ以外のときは、引数 destination には作成するファイルの名前を指定したと判断されます。いずれの場合も、移動される各ファイルで発生する処理の実行は 3 種類あります。
引数 destination に指定したファイルが存在しない場合、ファイルが移動します。これが通常の場合です。
引数 destination に指定したファイルが存在する場合、エラーが発生します。
引数 destination がディレクトリの場合、エラーが発生します。
引数 source でワイルドカード文字を使用した指定がどのファイルとも一致しなかった場合も、エラーが発生します。MoveFile メソッドは、最初のエラーが発生した時点で処理を中止します。エラーが発生するまでに行った処理を取り消したり元に戻したりする処理は一切行われません。
###メモ
   このメソッドを使用してボリューム間でファイルを移動できるのは、オペレーティング システムでボリューム間のファイル移動がサポートされている場合だけです。

#2.公式が教えてくれないこと その1
##MoveFileメソッドがファイル名の変更と書いていないこと。
実際上記の公式の解説をファイルの移動以外に理解することは困難だ。
[Windows管理者のためのWindows Script Host入門：第10回　WSHスクリプトからのファイル操作（1）(2/3)](http://www.atmarkit.co.jp/ait/articles/0510/13/news111_2.html)

>　CopyFileメソッドと同じように、移動先にはファイル名ではなくフォルダ名を指定することができる。また、移動するファイルをワイルドカードで指定することも可能だ。移動先にすでにファイルがあった場合、CopyFileメソッドとは異なり、常にエラーが発生する。エラーを発生させずに、既存ファイルを上書きするには、あらかじめ移動先のファイルを削除しておくか、移動ではなくコピーした後で元のファイルを削除するようにする。
　ファイル名を変更したい場合にもMoveFileメソッドが利用できる。具体的には、移動先として、元と同じフォルダ内の新しいファイル名を指定することでファイル名を変更できる。

#3.公式が教えてくれないこと その2
##destinationとsourceはデータ型が決まっている
これはString(文字列)で、これ以外は実はエラーになります。
このためVBscriptでは変更前のファイル名のフルパスと変更後のファイル名のフルパス用の変数を用意し

```vbnet
'Same Name zip File name change
If fs.FileExists(objDocFol.Path & "\E.zip") Then
dt = fs.GetFile(objDocFol.Path & "\E.zip").DateLastModified
strOldfile = CStr(objDocFol.Path & "\E.zip") 'you must change String Datatype
strNewfile = CStr(objDocFol.Path & "\E" & Replace(Replace(Replace(dt, "/", "", 1, -1), ":", "", 1, -1), " ", "", 1, -1) & ".zip")
fs.MoveFile strOldfile, strNewfile 'Change filename with fso is Movefile method
End If
```

このようにCStr() で文字列型に変換して変数に代入します。
こうしなくても動く場合がありますが、たまにエラーで動かなくなります。
なので、かならず文字列型にした方が無難です。

#4.公式が教えてくれないこと その3
## ファイルをオブジェクトとして変数には代入していないこと
変更したいファイルを
Set tgFile =Fso.getfile(ファイル名) 
としていると変数に代入しているので変更できません。
変更する前に set tgfile = NothingのようにNothingで解放する必要があります。
ファイスサイズが重いときはWscript.Sleepをいれた方が良い時もあります。

#5.公式が教えてくれないこと その4
## ファイル名にはユニコード文字を使わない方が良いこと
代表的なものは〇つき数字です。
まずVBScriptないでユニコード文字を扱うとファイル形式がANSI形式のテキストファイルになりません。こうなるとVBEにする暗号化はできません。
次にDir命令でテキストにファイル名を出力しても文字化けします。
一応扱えないことはないのですが、そういう細かい欠点があり、使わない方がバグが起きません。
公式がFSOの解説を作ったときはユニコードが一般的ではなかったので、こうしたことが書いていないのだと思われます。
球の体積の積分でふざけてみる

球の体積は

```math
\frac{4}{3}πr^3
```
ですけども
例えば半径1の球の体積の積分で
通常はというか正しいのは
x=-1から1まで積分しますが
![無題.png](https://qiita-image-store.s3.amazonaws.com/0/207542/c07cf5e3-b300-164a-568f-cafece47c2d5.png)
参考
[球の体積と表面積を積分で証明](https://mathtrain.jp/ballsv)

これを
x=-2から2まで積分した場合

```math

4π-\frac{16}{3}π\\
=-\frac{4}{3}π
```
となります。

これは何か意味がありそうな気がしています。
球の半径rを越えたところに虚数半径とでもいいましょうか
人間の知覚を越えたものがあり
2乗すると負の面積として実数で現れていると考えていいものかどうか
ただの戯言なのか
IntelliJのLiveEditで404になるときの対処法

IntelliJはJetBrain社のIDEです。
**LiveEdit**というプラグインを使うことで、HTMLの変更をリアルタイムでブラウザに反映することが出来ます。
ファイルを更新した後、ブラウザに切り替えてF5を押す手間が不要なため、とても便利です。

普段開発に使っているPCとは別のPCでLiveEditを使ったところ、
404という表示が出てしまい、その対策を書きました。

<img width="417" alt="intellij_404.png" src="https://qiita-image-store.s3.amazonaws.com/0/101999/546ba26e-4909-da0b-3b85-00ff4b71222e.png">


# 環境

- Mac El Capitan
- IntelliJ 2017.2.5
- Chrome 62.0.3202.89

# ブラウザ拡張とプラグインの準備

Chromeに**JetBrains IDE Support**という拡張が必要になります。
https://chrome.google.com/webstore/detail/jetbrains-ide-support/hmhgeddbohgjknpmjagkdomcpobmllji?hl=ja

次にIntelliJの**Preferences**を開き、Pluginsから**LiveEdit**をインストールします。

# LiveEditの実行方法

HTMLファイルをIntelliJのエディタで開いている状態で、**Ctrl+Shift+D**のショートカットで実行することが出来ます。
ショートカットキーはキーマップによって異なるので、ファイルを右クリックして表示される、**Debug 'ファイル名'**という項目を参考にしてください。

この時、以下のようなダイアログが出る場合があります。
**Copy authorization URL to clipboard**をクリックして進めます。
<img width="438" alt="intellij_authrization.png" src="https://qiita-image-store.s3.amazonaws.com/0/101999/f9f7584c-9f12-7522-0f98-97020c51a3a8.png">

ここで自動でChromeに切り替わりますが、404が出てしまいました。
<img width="417" alt="intellij_404.png" src="https://qiita-image-store.s3.amazonaws.com/0/101999/546ba26e-4909-da0b-3b85-00ff4b71222e.png">


# 対策
IntelliJの**Preferences**を開き、**Build, Execution, Deproyment**の**Debugger**を展開します。
その中の**Allow unsigned requests**という項目にチェックが入っていなければ、チェックをします。

<img width="691" alt="intellij_debugger_setting.png" src="https://qiita-image-store.s3.amazonaws.com/0/101999/7a53f37c-e526-0ace-2ab8-6c1ec98417f1.png">

再度同じようにLiveEditを実行すれば、今度は404にならないと思います。
ページがブラウザで開いた状態において、IntelliJでHTMLを編集すれば、即座に変更が反映されるはずです。
【PHP】サバイバル性の高いログ関数

アプリケーションにエラーは付き物ですが、エラー調査のために処理途中の ***変数の内容をちょっとだけ覗き見たい！*** と思うことってよくありますよね。

開発中であれば `var_dump()` 関数や `print_r()` 関数などで画面に情報を出してしまえばいいですが、本番環境の場合はそうもいかないのでログ関数に頼ることになると思います。

しかし世の中は無数のサーバがあり、サーバの数だけ異なった環境があります。
またサーバに置いてある PHP ファイルの数だけ無数の世界があります。

そんな無数にある環境の中、必ずしもフレームワークで提供されているような便利なログ関数を呼び出せるわけではないですし、xdebug のステップ実行が出来るわけではないと思います。

そこで過酷な状況下でも使えるようなサバイバルなログ関数を一つ持っておくと何かと便利です。私が普段使っているものは以下のような感じです。

## サバイバルログ関数

```php
$log = function () {
    // ログの出力先ファイルパス (環境に合わせて適当に変更で)
    $path = '/tmp/debug.log';
    // この関数の呼び出し元情報を取得
    $caller = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1)[0];
    // 引数からログ内容を取得 (可変長引数に対応)
    $content = func_get_args();
    $output = json_encode([
        'datetime' => date('Y-m-d H:i:s'),
        'caller' => $caller,
        'content' => $content,
    ], JSON_UNESCAPED_UNICODE) . PHP_EOL;
    // ログを書き込み
    file_put_contents($path, $output, FILE_APPEND);
};
```

## 上記のサバイバルログ関数の短縮版

出来ることは上記の関数と同じですがワンライナーのため携帯性に優れます。
（可読性が損なわれるので使い捨てのログ関数以外の用途では避けたほうがいいです。）

```php
$log = function () { file_put_contents('/tmp/debug.log', json_encode(['datetime' => date('Y-m-d H:i:s'), 'caller' => debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1)[0]] + ['content' => func_get_args()], JSON_UNESCAPED_UNICODE) . PHP_EOL, FILE_APPEND); };
```

SSH で対象のアプリケーションに忍び寄り vim でサッと上記を貼り付けて保存すれば一瞬のうちにログを仕込めます。後は `tail -f debug.log` をしながら獲物がかかるのを待つだけです。

## 使用方法

```php
// 複数の引数の内容をロギングする場合
$log ('確認内容1', '確認内容2');

// 配列の内容をロギングする場合
$log (['hoge' => 'foo', 'bar' => 'piyo']);

// 任意の変数の内容をロギングする場合
$log ($hoge, $foo);
```

ログファイルへの出力内容は以下のような感じになります。
ただのインデントありの JSON です。

```json:/tmp/debug.log
{
    "datetime": "2018-02-23 09:35:41",
    "caller": {
        "file": "\/var\/www\/html\/survival.php",
        "line": 19,
        "function": "{closure}"
    },
    "content": [
        "確認内容1",
        "確認内容2"
    ]
}
```
## 関数について補足

- PHP 5.4 以上の環境であれば使えると思います。
- サバイバル性を高めるため関数は [クロージャ](http://php.net/manual/ja/functions.anonymous.php) で定義してます。スコープ汚染が最小限になり関数名の重複によるエラーなどは心配する必要がなくなります。
- 手軽ではありますが本番環境で使用される際はくれぐれも事故にお気をつけ下さい。
- ログローテーションはしないので確認が終わったら元に戻したほうがいいです。
- ログは `json_encode()` の結果を出力しているため、インスタンス変数に対して使う場合は全ての情報が出力されるとは限りません。

## 関連記事

- [秘伝の var_dump 関数を公開します。 - Qiita](https://qiita.com/ymm1x/items/8fb2c412b161f485b61b)