OmniAICreator/Qiita-1.07M huggingface dataset:
Quantum Chemistry - 3-D Particle in a Box

関連 http://qiita.com/7of9/items/d3a1799928734375f34f

CG分野で使われるSpherical Harmonics。自分の数値シミュレーション計算に用いたいと思い調べると、量子化学の講義にたどり着く。

短く分かりやすそうな159本のビデオを少しずつ消化中。

Quantum Chemistry - 3-D Particle in a Box
https://www.youtube.com/watch?v=aXiyOUxUJAA&index=22&list=PLm8ZSArAXicL3jKr_0nHHs5TwfhdkMFhh

- 3次元で考える
  - Box内: wave function プサイn(x) = 0 (box modelによる)
  - Box外: プサイn(x) = 無限大 (box modelによる)
- 緑の式
  - Schrodinger Equationの3次元版
  - [以前のビデオ](https://www.youtube.com/watch?v=CSCSGFbt_Y0&list=PLm8ZSArAXicL3jKr_0nHHs5TwfhdkMFhh&index=12)の右中央の黄色の式
  - ただし、Box modelによりV(x)は0となり2つ目の項が消えている
- 紫の式
  - 2階の偏微分のshorthand notation
  - デル・スクエアード
      - ナブラは英語ではDelとも言うようだ [Qiita記事](http://qiita.com/7of9/items/3077b21ab658188fae5b)
  - ラプラシアン・オペレータ(ラプラス演算子)とも言う
- 黄色
  - iの範囲は0からエル
  - iというのはx, y, zのこと
- 水色の式から緑の式まで
  - boundary condition (境界条件)
  - x=0, x=エルといった、端っこではプサイ(x)は0となる (box model)
  - 水色の右側は(y,z)がR(実数)であることを示す (工学における特殊関数 p10)
- 緑の式
  - 式を解くときのトリックとして変数分離する
  - xの関数、yの関数、zの関数、の積
- ピンクの式
  - 全エネルギーはそれぞれの方向のエネルギーの和
- 右上黄色の式
  - 左上緑の式のx成分だけの式
  - 偏微分から全微分(xだけの微分)の式になった
  - この式の解については[こちらのビデオ](https://www.youtube.com/watch?v=uK60QAKooyM&list=PLm8ZSArAXicL3jKr_0nHHs5TwfhdkMFhh&index=16)の右中央水色の式で求まっている  
  - 水色の式: yに関する式
  - オレンジの式: zに関する式
- 緑の式
  - プサイ*(x)とプサイ(x)の積を積分した
     - プサイ*(x)とプサイ(x)の積
          - probability density function
          - 粒子の位置xの存在確率
     - 存在確率を全空間で積分するので1となる (全確率 = 100%)
- 紫の式
  - 3次元の係数A
  - それはAx, Ay, Azの積
  - Ax, Ay, Azの値は[このビデオ](https://www.youtube.com/watch?v=EK6C6mpxP-g&index=17&list=PLm8ZSArAXicL3jKr_0nHHs5TwfhdkMFhh)の右下ピンクの式の係数として求められている
- 黄色の式
  - total wave function
  - 以下の式から求まった
      - 左下の緑の式
      - 右上黄色、水色、オレンジの式
      - 右下紫の式
  - 3次元でのwave function
- 水色の式
  - エネルギーの式
  - x,y,z各方向のエネルギーの式を足したもの
  - 各方向のエネルギーの式は[このビデオ](https://www.youtube.com/watch?v=uK60QAKooyM&index=16&list=PLm8ZSArAXicL3jKr_0nHHs5TwfhdkMFhh)の右下緑の式として導出されている
技術英語 > When the routine in the middle of the call chain doesn't use the object, the object is called "tramp data".

@ Code Complete (No. 11377 / 36077)

技術英語というよりはコーディング用語?。

> When the routine in the middle of the call chain doesn't use the object, the object is called <font color=red>"tramp data"</font>.

http://ejje.weblio.jp/content/tramp
> 浮浪者，放浪者; 渡りこじき.

- function main()
- function sub(float pi)
- function subsub(float pi)
- function subsubsub(float pi)

mainからsubsubsubまでの経路において、piが途中の関数(sub, subsub)で使われない状況でpiのことをtramp dataと呼ぶ、という理解。
[Elixir] ユニットテストの書き方

## ユニットテストの書き方
mixを使うまでの間、１本のプログラムでユニットテストを書いてゆくには、たとえば以下のように書きます。

```elixir:add_test.exs
ExUnit.start()

defmodule AddTest do
  use ExUnit.Case
  test "add test" do
    assert 1+1==2
    assert 1+2==2
  end
end
```
実行すると、

```elixir:
$ elixir add_test.exs 


  1) test add test (AddTest)
     add_test.exs:4
     Assertion with == failed
     code: 1 + 2 == 2
     lhs:  3
     rhs:  2
     stacktrace:
       add_test.exs:6: (test)



Finished in 0.03 seconds (0.03s on load, 0.00s on tests)
1 test, 1 failure

Randomized with seed 375518
```
ユニットテスト１日目のコードです。

```elixir:first_test.exs
ExUnit.start()

defmodule StringTest do
  use ExUnit.Case
  test "basic" do
    assert "abc"<>"def" === "abcdef"
    assert String.length("abc") === 3
    assert String.slice("abcdef",2..3) === "cd"
    assert String.split("abc def"," ") === ["abc","def"]
    assert Enum.join(["abc","def"],",") === "abc,def"

    assert String.at("abcdef",0) === "a"
    assert String.at("abcdef",1) === "b"
    assert String.starts_with?("abcdef","abc")
    assert String.ends_with?("abcdef","def")
    assert String.trim("  abc  \n") == "abc"
    assert String.upcase("aBc") == "ABC"
    assert String.downcase("AbC") == "abc"
    assert String.to_integer("16") == 16
    assert String.to_integer("1E",16) == 30
  end
  test "complex" do
    assert(Enum.map(["abc","def"],&String.upcase(&1)) == ["ABC","DEF"])
    assert Enum.map(["10","20"],&(String.to_integer(&1))) == [10,20]
    assert Enum.map(["10","20"],&String.to_integer/1) == [10,20]

    with to_i = &(String.to_integer(&1))
    do
      assert to_i.("10") == 10
      assert Enum.map(["10","20"], to_i) == [10,20]
    end

    with line = "100 200\n"
    do
      result = line 
               |> String.trim 
               |> String.split 
               |> (Enum.map &String.to_integer(&1))  # to_integer/1
      assert result == [100,200]
    end
        
  end
  test "embed" do
    num = 123
    assert "num=#{num}" === "num=123"    
    name = "foo"
    assert "name=#{name}" === "name=foo"    
    assert 'name=#{name}' === 'name=foo'    
  end
  test "regex" do
    assert String.to_integer("1E",16) == 30
  end
end

defmodule ListTest do
  use ExUnit.Case
  test "list" do
    assert Enum.to_list(1..3) == [1,2,3]
    assert [1,2,3]++[4,5,6] == [1,2,3,4,5,6]
    assert Enum.concat([1,2,3],[4,5,6]) == [1,2,3,4,5,6]
 	
    with n=1,
  	 list=[2,3]
    do
      assert [n|list] === [1,2,3]
    end
    
    with list = [1,2,3]
    do
      assert (hd list) === 1
      assert (tl list) === [2,3]
    end
  	
    with list = [1,2,3]
    do
      [head|tail] = list
      assert head === 1
      assert tail === [2,3]
    end
  	
    with [first,second] = [1,2]
    do
      assert first == 1
      assert second == 2
    end
  end
end

```

その実行結果

```elixir:
$ elixir first_test.exs 
.....

Finished in 0.09 seconds (0.08s on load, 0.01s on tests)
5 tests, 0 failures

Randomized with seed 703309
```

楽しんでね！
aws ubuntu s3マウント

#awsのEC2インスタンスにs3をマウント

## 環境
- ubuntu 14.04
- s3fsを利用
- IAM Userで構築

##参考:
http://qiita.com/monry/items/fa3bebd69e04a08ae12f
http://qiita.com/Yuki_BB3/items/9f5eb233b152be1c4bc9

## IAM UserでIAM作成

IAM Roleでの作成方法もあるが、
IAM Userの場合はEC2インスタンスを再立ち上げする必要がない。
今回はIAM Userを採用。

IAM作成は
http://qiita.com/monry/items/fa3bebd69e04a08ae12f
を参考。

Access Key IDおよびSecret Access Keyを用意しておく。


## s3fsインストール
s3fs git:
https://github.com/s3fs-fuse/s3fs-fuse

ubuntuなのでapt-getで必要なものをインストール

```
$ sudo apt-get install automake autotools-dev g++ git libcurl4-gnutls-dev libfuse-dev libssl-dev libxml2-dev make pkg-config
```

s3fsをインストール

```
$ git clone https://github.com/s3fs-fuse/s3fs-fuse.git
$ cd s3fs-fuse
$ ./autogen.sh
$ ./configure
$ make
$ sudo make install
```

s3fsが/usr/local/bin下におかれる。
/usr/bin下に置きたい場合は上記コマンド実行時に`--prefix=/usr`オプションを`./configure`につける。

```
$ ./configure --prefix=/usr
```


## マウントポイント作成

```
$ sudo mkdir /mnt/s3
```

## IAM access keyを保存

```
$ echo <Access Key ID>:<Secret Access Key> | sudo tee -a /etc/passwd-s3fs
$ sudo chmod 640 /etc/passwd-s3fs
```

## マウント
マウント時のownerのuid, gidを確認。

```
$ id <User Name>
```

マウント

```
$ sudo s3fs <Bucket Name> <Mount Point> -o rw,allow_other,uid=<UID>,gid=<GID>,default_acl=public-read
```
XAMPP環境でPHPとMySQL

MySQLの勉強始めた人間です。

ドットインストールにある「[PHPデータベース入門](http://dotinstall.com/lessons/basic_php_db)」をやろうとしたのですが、動画での環境が恐らくvgrantとcyberduck？だったため、ターミナル上のCUIのVimでは動かせませんでした。

どうしてもVimを使いたかったので、あらかじめ入れてた「XAMPPでPHPとMySQLの勉強をしたい」と思い、挑戦しました。

セキュリティ関係などの丁寧な記事ばかりで、ただ環境に関するものだけというのがどうしても見つからなく苦労したので、せっかくなので記録しておきます。

XAMPPだと動画の「IPアドレスこれですね〜」、とか意味分からへん(´；ω；｀)



ちなみにMac環境のXAMPPです。



#準備

XAMPPが入っているという前提でお願いします。
普通にインストールしておいて下さいな。


#manager-osxを起動

XAMPPファイルに入ってるアプリケーションです。（多分Windowsでも似たようなの入ってるはず）
それを起動したら、Manage ServersからStart Allしてください。

慣れないうちは普通に忘れますが、大事な起動作業です。
PHPファイル使う時も忘れずやりましょう。


#ファイルの場所

Applicationに作られたXAMPPフォルダの中にある**htdocs**というフォルダが作業する場になります。
ManagerのGo folderみたいなのクリックしたら開いてくれますね。

ブラウザでlocalhostと打ち込んで来る場所がここになります。お気に入りして来やすくするといいかも。

最初に入ってる**index.php**は消しちゃいましょう。
もし初期設定画面？みたいなのにまたアクセスしたくなったらlocalhost/xamppとするだけで同じことになります。

このhtdocsの下に入れておけばlocalhost/test/insert.phpみたいにブラウザから自由にファイルアクセス出来るので、大事な所です。

余談になりますが、index.phpっていうファイルは逆に作らないほうがいいですね。それさえ無ければファイル一覧を表示してくれるのでクリッククリックで好きなディレクトリ行けます。頭の片隅に入れておくといいかも？


#MySQL起動

動画や参考書で言われてる通り、ターミナルから**mysql -u root**とかで起動します。

ちょっと気になったのですが、「PHPファイルと同じ場所じゃないとダメなのかな？」なんて思って試しましたが、全く関係なかったです。どうでもいいみたいですね。


#注意点！！！！！

簡単なことなのですが **test_db** というデータベースは作っちゃいけないみたいです。
恐らく**testで始まるデータベースは特別な処理されてるみたい**です。
なぜかアクセス出来ず、phpMyAdminで確認してやっと分かりました。

こんなことで２,３時間くらい無駄にしました！！！


あと、普通にdropでデータベース消しまくるのは辞めましょう。
**mysqlという名前のデータベース**があって、「なんだこれ。昔の俺、名前迷ってアホみたいな名前にしとるなｗ」と思って消したらMySQLが起動しなくなり、再インストールする羽目になりました。

カッコつけずにaiueoとか日本語にした方がいいのかも、と思った悲しい事件でした。

こんなバカなことしないようにしましょう！





ってな訳で、超超超基本かもしれませんが、自分は困ったので記事にしました。

参考になれば幸いです。


終わり
AndroidおよびiOSでの端末識別子について


スマホのアプリを開発する上で端末を識別するのに何が使用できるのか調べたのでまとめておきます。

## 各識別子

### **Android/iOS共通**

#### ・MACアドレス
　ネットワーク機器に一意に割り当てられるアドレス。
　通常変更はできないが、脱獄などしている場合はできる模様。
　ネットワークアダプタが搭載されてない場合や無効になっている場合は取得できない。

#### ・IMEI(International Mobile Equioment Identity、国際移動体装置識別番号)
　携帯電話など通信端末に付与される番号。15桁の数字。
　通常変更はできるものではないが、もし変更すると違法となる。
　端末を一意に識別できる。

#### ・MEID(Mobile Equipment Identifier)
　IMEIと同じで携帯電話に付与される番号。15桁の数字。
　フォーマットもIMEIと同じだがコチラは16進数になっている。

#### ・ICCID(IC Card Identifier)
　ICカードごとに固有の番号。最大19桁の数字。
　スマートフォンではSIMカードに付与されている。

#### ・IMSI(International Mobile Subscriber Identity)
　携帯電話加入者に対して発行される識別番号。通常は15桁の数字。
　携帯電話に直接あるいはSIMカードに記録されている

#### ・シリアル番号
　端末のシリアル番号
　携帯電話ではない端末は一意な番号を取得できる
　携帯電話によっては取得できるものもある

### **Androidのみ**

#### ・Android_ID
　端末の初期化時にランダム生成される文字列。16進数の16桁の数字
　初期化以外では変更されない。

#### ・AdvertisingID
　広告での使用を目的とした永続ID。
　広告目的でしか使用できない。
　ユーザの設定により取得できないようにしたり、リセットして新しいIDに変更したりできる。

### **iOSのみ**

#### ・UDID(Unique Device Identifier)
　端末ごとに一意の識別子
　ただし、iOS5で非推奨、iOS6でリジェクト対象、iOS7で無効な値を返すようになっている

#### ・IDFV(Identifier For Vender)
　UDIDの替わりの端末識別子
　IDFAと違い広告目的に限定されていない
　ベンダー毎に一意のUUIDが取得できる、端末に入れた同じベンダーのアプリすべてから同じUUIDが返ってくる
　端末からそのベンダーのアプリがすべてアンインストールされるとリセットされるらしい

#### ・IDFA(Identification For Advertisers)
　広告での使用を目的とした永続ID
　ユーザが設定からリセットできる、端末初期化でもリセットされる
　広告目的以外での使用はリジェクト対象になる

## 使用可能か＆使用方法

### **Android**

#### ・Macアドレス
　・使用不可
　・以前はAPIから取得できたが、Android6.0からは該当のAPIは常に02:00:00:00:00:00を返すように変更された。　

#### ・IMEI
　・可能
　・パーミッション必要：READ_PHONE_STATE
　・TelephonyManager getDeviceId

#### ・MEID
　・可能
　・方法はIMEIと同じ

#### ・ICCID
　・可能
　・パーミッション必要　READ_PHONE_STATE
　・TelephonyManager getSimSerialNumber

#### ・IMSI
　・可能
　・パーミッション必要　READ_PHONE_STATE
　・TelephonyManager getSubscriberId

#### ・シリアル番号
　・可能（携帯電話以外）
　・パーミッション不要
　・android.os.Build.SERIAL

#### ・Android_ID
　・可能
　・パーミッション不要
　・Settings.Secure.getString(this.getContentResolver(), Settings.System.ANDROID_ID)

#### ・AdvertisingID
　・可能
　・パーミッション不要
　・AdvertisingIdClient.getAdvertisingIdInfo(mContext).getId();

### **iOS**

#### ・Macアドレス
　・不可能
　・非公式な方法はあるが、取得できたとしてiOS8からMacアドレスがランダム生成されているらしいので端末の識別には使用できない

#### ・IMEI
　・不可能
　・iOS3までは取得できたようだが現在は無理

#### ・MEID
　・不可能

#### ・ICCID
　・不可能

#### ・IMSI
　・不可能

#### ・シリアル番号
　・不可能

#### ・UDID
　・不可能
　・実はAPIは残っているが、無効な値しか返ってこない、そもそも使用しているだけでリジェクト対象になる

#### ・IDFV
　・可能
　・UIDevice identifierForVender

#### ・IDFA
　・可能
　・広告目的限定、それ以外に使用するとリジェクト対象
　・ASIdentifierManager AdvertisingIdentifier
Windows内のファイル操作でBash使って効率よく行きましょ！！

# Windowsのファイル操作にお悩みではありませんか？（広告じゃないよ）


### ***findコマンドのListを参照したい方は色々すっ飛ばして下の方へGO***
## フォルダ分けされた中に楽曲ファイルなどが存在して取り出すのが面倒くさい
`Music`フォルダの中に、`Anime`や`VOCALOID`などのフォルダに分けてミュージックデータを入れてませんか？？

こうすると、例えば`カラオケ音源だけWalkmanに入れたい！`って思った時にいろんなフォルダを巡らないとコピーできず、しかも、Windowsの検索が何故か行われなかったり、　検索するフォルダの中に楽曲以外のファイルが入ってるためそれを取り除くのが面倒だったりしますよね。

そこで`Bash`の出番です。
せっかく導入されたのですから使いましょうよ！
>検索で `OR` とか `AND`とか使えばヒットして普通にコピーできます。
>ただ、今回はコマンドでコピーまで自動なので楽です。

## findコマンドを使う

findコマンドをご存知でしょうか。
いろんなファイルをパス情報込みで検索してくれる便利なコマンドです。（他にも使い方は様々）

まずはfindを使って検索をしてみましょう。

`$ find`

これを実行すると、大量のファイル内ではずっと実行しっぱなしになります。
`Ctrl+C`終了しましょう。

`$ find ./ anime`

これで`anime`という文字列がどこかに含まれていたら検索でヒットします。
これはフォルダの名前も含みますので、`anime`フォルダに格納されているファイルをすべて参照します。
今回はファイル名だけほしいのでオプションをつけましょう。

`$ find ./ -name anime`

どうでしょうか。これは`anime`というファイル名の一致したものを表示します。
多分何も出ないと思います。　ここであいまい検索にしましょう。

`$ find ./ -name ¥*anime*`

`*`がどの文字でもOKという意味を表します。文字数も指定されていません。とにかくファイル名に`anime`という文字が含まれていたらヒットします。ここで、カラオケ音源を検索してみましょう。

`$ find ./ -name ¥*inst*`

これでカラオケ音源がヒットされますね。
ただ、これだと大文字小文字の区別がされていますので、`Inst`や`INST`などは検索されません。
大文字小文字の区別をなくしてみましょう。

`$ find ./ -iname ¥*inst*`

`iname`に変えると大文字小文字の区別がなくなります。
カラオケ音源も`inst`だけではなく`offvocal`なんてのもよく使われますよね。
では`inst`または`off`が含まれていた場合を検索しましょう。

`$ find ./ ¥( -iname ¥*inst* -o -iname ¥*off* ¥) -print`

これでOR検索が出来ました。
あとはここで検索したファイルをコピーするだけです。
コピーは`cp`コマンドです。

`$ find ./ ¥( -iname ¥*inst* -o -iname ¥*off* ¥) -print -exec cp {} ./{コピー先フォルダ} ¥;`

これでコピーが始まります。
楽ですね。

## findコマンドまとめ

```bash
#どこかに含まれてる文字を検索
$ find ./ anime 
anime/music/a.mp3
anime/music/an(inst).mp3
anime/movie/anime(INST).mp4


#ファイル名全件一致
$ find ./ -name anime
anime/music/anime
VOLACOLD/music/anime


#ファイル名部分一致
$ find ./ -name ¥*anime*
anime/music/aanimee.mp3
anime/music/anime(inst).mp3


#ファイル名部分一致＆大小文字区別なし
$ find ./ -iname ¥*inst*
anime/music/anime(inst).mp3
anime/music/tarou(INST).mp3


#OR検索
$ find ./ ¥( -iname ¥*inst* -o -iname ¥*off* ¥) -print
anime/music/anime(inst).mp3
anime/music/tarou(INST).mp3
anime/music/animal(off vocal).mp3
anime/music/zirou(Off Vocal).mp3


#出力をコピー
$ find ./ ¥( -iname ¥*inst* -o -iname ¥*off* ¥) -print -exec cp {} ./{コピー先フォルダ} ¥;
上記のデータがコピーされる。


```

WindowsだけでなくLinuxでもMacでも使えます。
RailsのローカルでSQLiteを使う時

#RailsのローカルでSQLiteを使う

Railsアプリケーションを触っている時に本番環境はPostgreSQLだけど
ローカルはSQLiteだったって時に

##接続する
```cl
$ sqlite3 db/development.sqlite3
```
もしくは

```cl
$ rails db
```
で接続できます！

##データベース一覧
```sql
sqlite> .databases
```
これでデータベースの一覧を確認

##テーブル一覧
```sql
sqlite> .tables
```
これでテーブル一覧を取得

##SQL文
```sql
sqlite> select * from user;
```
もちろんSQL文もそのまま打てます！

##スキーマ表示
```sql
sqlite> .schema users 
```
スキーマのデーブルも確認できます！

##テーブルの中のカラム確認
```sql
sqlite> PRAGMA TABLE_INFO(TABLE_NAME); 
```
テーブルのカラムを確認できます！

##終了
```sql
sqlite> .exit
```
これで終了
安定マッチング for PHP

- php >= 5.4

```php:GSMatch.php
<?php

$boysPrefers = [
 'b1' => [ 'g1','g2','g3','g4' ],
 'b2' => [ 'g3','g2','g1','g4' ],
 'b3' => [ 'g1','g2','g4','g3' ],
 'b4' => [ 'g3','g1','g4','g2' ],
];

$girlsPrefers = [
 'g1' => [ 'b1','b2','b3','b4' ],
 'g2' => [ 'b2','b1','b4','b3' ],
 'g3' => [ 'b2','b3','b1','b4' ],
 'g4' => [ 'b1','b4','b3','b2' ],
];

/**
 * 入力：n人の男性とk人の女性、および、各人の異性全員に対する選好順序のリスト
 * 出力：安定マッチング（つまり、男女 min{n,k} 組以下のペア）
 * 
 * @see https://ja.wikipedia.org/wiki/安定結婚問題
 * @param array $boysPrefers
 * @param array $girlsPrefers
 * @return array 
 */
function GSMatch($boysPrefers, $girlsPrefers) {

    // ステップ 0 [初期設定] 全員の状態は独身とする（全ての男性はどの女性にもプロポーズを行っていない）。
    $pairs = [];
    $boys = array_keys($boysPrefers);
    $girls = array_keys($girlsPrefers);

    // ステップ 1　独身の男性 h が存在する限り、以下の操作を繰り返す。
    while(!empty($boys)) {

        // 1-1 男性 h はまだプロポーズしていない女性の中で、最も好きな（つまり、希望リストの最高位の）相手女性 d にプロポーズする
        $boy = array_shift($boys);
        $girl = array_shift($boysPrefers[$boy]);

        // 1-2 (a) d が独身ならば、d は h と婚約する
        if(empty($pairs[$girl])) {
            $pairs[$girl] = $boy;
        } else {
            // (b) d がすでに h' と婚約している場合
            $girlsFlip = array_flip($girlsPrefers[$girl]);

            // (b-1) d にとって h' のほうが好ましい希望順位が上( h' > h ) ならば、h からのプロポーズを断る
            if($girlsFlip[$pairs[$girl]] < $girlsFlip[$boy]) {
                $boys[] = $boy;
            } else {
                // (b-2) d にとって h のほうが好ましい( h > h' )ならば、h' との婚約を解消し h と婚約する
                $boys[] = $pairs[$girl];
                unset($pairs[$girl]);
                $pairs[$girl] = $boy;
            }
        }
    }

    // ステップ 2　現在婚約しているペアの集合を安定マッチングとして出力する。（終了）
    // 男性最良安定マッチング
    return array_flip($pairs);
}

$result = GSMatch($boysPrefers, $girlsPrefers);
var_dump($result);
```
Notepad++からsshしてraspberrypiに書き込む

自分の備忘録程度で投稿します．

notepad++をサイトからダウンロードする
https://notepad-plus-plus.org/download/v6.9.2.html

インストールしたら，Notepad++を開く．
プラグイン→Plugin Manager→Show Plugin Managerから
NppFTPをインストール

インストールが終わったら再起動される．
メニューにNppFTPのアイコンが表示されるのでクリック．

右にタブ（？）がでてくるのでSettingをクリック「Profile Setting」

Add newを押して，名前をいれる　例：raspberrypi b+
HostnameにIPアドレス，Username，Passwordをいれて，Connection TypeをSFTPに変更．closeして閉じる．

先ほどのSettingを押したところにあるConnectを押して，先ほど作った設定を選んでログインする．

また必要になったら情報を追加します．
EHCache + PlayのdevでClassNotFoundExceptionが出るときの解決方法

前はこの記事の方法で解決していたのだが、今は解決できなくなったので参考程度にどうぞ。

## 概要
EHCacheをPlayで使っていると、dev-modeでreloadが掛かったときにClassNotFoundExceptionが出るという問題がある。

## 原因
Playの特殊なClassLoaderの使い方にある。

http://tototoshi.hatenablog.com/entry/2016/09/04/012126

が詳しい。

## 解決方法
Cache生成時に使用するClassLoaderが渡せる。

```scala
val conf = new CacheConfiguration(cacheName, maxEntries)
  .setClassLoader(env.classLoader)
val cache = new Cache(conf)
```

渡すClassLoaderは`play.api.Environment`をDIから持ってきてclassLoaderを呼べばいい。
blank appプロジェクトが作成できなくなった時の対処

[（メモ）UWPプロジェクトが作成できない](http://coelacanth.jp.net/uwp_applicationinsights_error/)

ここに記載された対処をしてもなぜか自分の環境では現象が回避できず。
修正したテンプレートが読み込まれてないのかと思い、試しに開発者コマンド プロンプトを管理者で

> devenv /installvstemplates

を実行すると、テンプレートが適用されたのか、無事プロジェクトが作成できた。
※プロジェクトが作成できたのを確認しただけなので、問題が何かあるかもしれません。
※対処は自己責任でお願いします！

[追記]
複数バージョンのVisual Studioをインストールしている環境ではUAPテンプレートすら出てこない現象が…対策わかり次第追記予定。
→とりあえず解決 [その２](http://qiita.com/meganesan/items/caab6b6d386a1ecb97bb)へ
proxy型脆弱性診断ツール参考リンク集


動的解析系の脆弱性診断ツールのうち、proxy型のツールについての紹介から活用事例まで、参考リンクをまとめてみます。

### 診断ツール比較

LocalProxy型診断ツールの紹介と比較が分かりやすい資料。今回は、この資料で登場するツールに絞ってまとめてみます。

- [Proxy War](http://www.slideshare.net/zaki4649/proxy-war-42161988)
- [Proxy War EPISODEⅡ](http://www.slideshare.net/zaki4649/proxy-war-episode)

### OWASP ZAP

**公式サイト**
[OWASP Zed Attack Proxy Project - OWASP](https://www.owasp.org/index.php/OWASP_Zed_Attack_Proxy_Project)

**User Guide**

- [Home · zaproxy/zap-core-help Wiki](https://github.com/zaproxy/zap-core-help/wiki)

**参考資料**

- [フリーでやろうぜ！セキュリティチェック！](http://www.slideshare.net/zaki4649/free-securitycheck)
  - 後半のアプリケーションの診断でZAPが紹介されています
- [OWASP ZAP-API #OWASP Night 21th // Speaker Deck](https://speakerdeck.com/owaspjapan/owasp-zap-api-number-owasp-night-21th)
  - APIを活用してHubot駆動で脆弱性診断の自動化、素敵です
- [Jenkins と owasp zap で自動診断](http://www.slideshare.net/OWASPOkinawa/jenkins-owasp-zap)
  - こちらはJenkins駆動でAPIを叩いての自動診断ですな
- [OWASP Zed Attack Proxy 運用マニュアル](https://docs.google.com/file/d/0B1e1Cma1GUllazNUNVp6OWdGYzg/edit)
  - ジャパニーズ大助かりの日本語マニュアル、素敵です！

### Burp Suite

**公式サイト**
[Burp Suite](https://portswigger.net/burp/)

**参考資料**

- [burpsuitejapan/startup](https://github.com/burpsuitejapan/startup)
  - Burp Suiteのスタートアップ用ドキュメント (by Burp Suite Japan User Group)
- [SSTなるほど！コーナー　HTTP通信の中身を覗いてみよう！Burp Suite Free Edition 1.6編【前編】| SST 株式会社セキュアスカイ・テクノロジー](https://www.securesky-tech.com/images/column/naruhodo_01_title.gif)
  - 比較的丁寧に、基本的な使い方から応用までを複数回に分けて説明してくれているサイト
- [Burp番外編～バープ、チョトニホンゴデキル～](http://www.slideshare.net/abend_cve_9999_0001/burp-42662026)
  - Burp Suite が日本語弱いのは有名な話らしいですが、それに関連したネタ資料
- [フリーでできるWebセキュリティ（burp編）](http://www.slideshare.net/abend_cve_9999_0001/webburp)
  - こちらは真面目にセッション管理補助機能（Macro, Cookie jar, Session Handling Rules）を説明した資料です
- [サイバーセキュリティプログラミング ―Pythonで学ぶハッカーの思考 : Amazon.co.jp](https://www.amazon.co.jp/%E3%82%B5%E3%82%A4%E3%83%90%E3%83%BC%E3%82%BB%E3%82%AD%E3%83%A5%E3%83%AA%E3%83%86%E3%82%A3%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0-%E2%80%95Python%E3%81%A7%E5%AD%A6%E3%81%B6%E3%83%8F%E3%83%83%E3%82%AB%E3%83%BC%E3%81%AE%E6%80%9D%E8%80%83-Justin-Seitz/dp/4873117313)
  - 脆弱性診断の自動化ツールとしてBurp Suiteの拡張機能をPython(Jython経由)で実装するサンプルあり

### Fiddler

**公式サイト**
[Fiddler free web debugging proxy](http://www.telerik.com/fiddler)

**参考資料**

- [はぐれSEのやさぐれ日記](http://www.hagurese.net/blog/default.aspx?pn=Fiddler%E3%81%A8%E3%81%AF)
  - Fiddler徹底解剖ということで、インストール、基本操作から幾つかの応用的な使い方を紹介
- [【レビュー】Webアプリのデバッグに最適。HTTPに特化したネットワークキャプチャーツール「Fiddler」 - 窓の杜](http://forest.watch.impress.co.jp/docs/review/617843.html)
  - 何故ここに来て窓の杜なのか、大人なら黙って理解してくれるはず（ネタ切れ）

### さいごに

他に、有用なサイトなどありましたら是非コメントください。
RESTful APIのHTTPステータスコード設計

# HTTPステータスコード設計

RESTfulなAPIでは、以下の理由によりAPIの処理結果は適切なHTTPステータスコードを利用することが推奨されている。

* 適切なHTTPステータスコードを返さないと、レスポンスボディの中身を解析して処理結果を判定する必要がある
* HTTPの標準仕様を使うことで、HTTPステータスコードから処理結果を判定することができる
* HTTPの標準仕様を使うことで、APIを利用する第三者にとっても理解しやすくなりバグの混入を減らすことができる
* ほとんどのHTTPクライアントライブラリはHTTPステータスコードを見てリクエストが成功したか、失敗したかを判別している

※ステータスコードは一律200で処理結果をレスポンスボディで表現するようなことはしてはいけない。例えば、API側で内部エラーが発生し本来であれば500(INTERNAL SERVER ERROR)を返さなければいけないところを、200で返して内部エラーが発生したという結果をレスポンスボディで表現するようなことはしてはいけない。

そのため、どのような場合にどのようなステータスコードを返すかを検討する必要がある。

# よく使われるHTTPステータスコード

一般的に以下のようなステータスコードがよく利用される。実際に設計する際は、APIが提供する機能によってどのようなステータスコードを利用するかを検討する(例えば、提供するAPIがPOSTリクエストを提供しないのであれば201を利用する必要はない、、等)。また、仕様が煩雑になるのを防ぐためにも、極力必要最低限のステータスコードを利用する。

|ステータスコード|名前|説明|
|:--|:--|:--|
|200|OK|リクエストは成功しレスポンスとともに要求に応じたリソースが返される。|
|201|CREATED|リクエストは完了し新たにリソースが作成された。Locationヘッダには新たに作成されたリソースのURIが含まれる。POSTで利用される。|
|204|NO CONTENT|内容なし。リクエストを受理したが、返すべきレスポンスエンティティが存在しない場合に返される。PUT、POST、DELETE等で利用される。|
|303|SEE OTHER|他を参照せよ。リクエストに対するレスポンスが他のURIとして存在するときに返される。Locationヘッダに移動先のURIが示されている。|
|400|BAD REQUEST|リクエストが不正である。定義されていないメソッドを使うなど、クライアントのリクエストがおかしい場合に返される。|
|401|UNAUTHORIZED|認証が必要である。Basic認証やDigest認証などを行うときに使用される。|
|404|NOT FOUND|未検出。リソースが見つからなかった。|
|405|METHOD NOT ALLOWED|許可されていないメソッド。許可されていないメソッドを使用しようとした。|
|409|CONFLICT|競合。リクエストは現在のリソースと競合するので完了出来ない。|
|500|INTERNAL SERVER ERROR|サーバ内部エラー。サーバ内部にエラーが発生した場合に返される。|
|503|SERVICE UNAVAILABLE|サービス利用不可。サービスが一時的に過負荷やメンテナンスで使用不可能である。|


# HTTPステータスコード一覧

https://tools.ietf.org/html/rfc7231#page-50
https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
Crowiをdocker-nodeで動かすまでのメモ


## 目的
研究室内の情報共有用にいい感じで使えるmarkdown形式のwikiがほしい。
ついでにdockerでデプロイ出来ると楽だしいいな。

## Crowiとは
markdown表記のwiki
ref: http://site.crowi.wiki/

## 構成
* docker
* node:4.5-slim
* mongodb
* redis
* crowi v1.5.0

※追記 2016/09/09
最初crowiのmasterブランチからcloneしてましたが、公式によるとmasterは非推奨でした。
ご指摘してくださった方ありがとうございます。

## セットアップ

### nodeの設定

nodeコンテナの用意

```shell-session
$ docker run -dit --name crowi -p 80:80 node:4.5-slim
```

以下コンテナ内での作業

```shell-session
# aptのupdateとcrowiに必要なバイナリのインストール
$ apt-get update
$ apt-get -y install git python g++ make mongodb redis-server

# crowiのクローン
$ git clone -b v1.5.0 https://github.com/crowi/crowi.git
$ cd crowi
$ npm install
```

なんかエラー出た...

```shell-session
npm ERR! Linux 4.4.12-boot2docker
npm ERR! argv "/usr/local/bin/node" "/usr/local/bin/npm" "install"
npm ERR! node v4.5.0
npm ERR! npm  v2.15.9
npm ERR! code ELIFECYCLE

npm ERR! time@0.11.4 install: `node-gyp rebuild`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the time@0.11.4 install script 'node-gyp rebuild'.
npm ERR! This is most likely a problem with the time package,
npm ERR! not with npm itself.
npm ERR! Tell the author that this fails on your system:
npm ERR!     node-gyp rebuild
npm ERR! You can get information on how to open an issue for this project with:
npm ERR!     npm bugs time
npm ERR! Or if that isn't available, you can get their info via:
npm ERR!
npm ERR!     npm owner ls time
npm ERR! There is likely additional logging output above.
```


c++やpythonが入っていないとエラーがnode-gypのbuildで失敗する模様。

> ref: https://github.com/nodejs/node-gyp
> If node-gyp is called by way of npm and you have multiple versions of Python installed, then you can set npm's 'python' config key to the appropriate value:
 
>> $ npm config set python /path/to/executable/python2.7

npmにpythonのpathを教えてあげる

```shell-session
$ npm config set `which python`
```

再度 `npm install` を実行

### mongodb起動

```shell-session
$ mongod --dbpath /var/lib/mongodb --logpath /var/log/mongodb.log
```

### redis起動
```shell-session
$ redis-server
```

### crowi起動
```shell-session
$ PORT=80 MONGO_URI=mongodb://localhost/var/lib/mongodb REDIS_URL=redis://localhost:6379 node app.js
```

buildに失敗しているとjsやcssが読み込まれない。その場合は手動でbuildしなおす。

```shell-session
$ npm run build
```

`http://localhost`にアクセスし次の画面が表示されたらok
<div style="text-align: center;">
<img src="https://i.gyazo.com/fee0a121dd57258c345e6cdbe2a44853.png" alt="crowiセットアップ画面" width=480px>
</div>



## さいごに
とりあえず使っみてどんな感じか把握したいなー
pukiwikiを使うかこちらを使うか...


## 追記 2016/09/11

DockerfileでCrowiをビルドする記事を書きました
-> [DockerfileでCrowiのビルドとDocker ComposeでCrowiの実行](http://qiita.com/nooby/items/1a176b43a72905b9f93c)
素人の言語処理100本ノック:01


[言語処理100本ノック 2015](http://www.cl.ecei.tohoku.ac.jp/nlp100/)の挑戦記録です。一覧は[こちら](http://qiita.com/segavvy/items/fb50ba8097d59475f760)からどうぞ。

## 環境の変更について
まだ1問しかやっていませんが、環境を少し変更することにしました。

- Ubuntu 14.04 LTS　→　16.04 LTS
- Python 2.7.6　→　2.7.12
- gedit 3.10.4　→　3.18.3

Ubuntuを現時点で最新の16.04 LTSにしました。Pythonとgeditは、このUbuntuに標準で含まれているものです。

なお、私のパソコン本体はMac mini(Late 2012)で、Parallels Desktop 12を使ってUbuntuを仮想化しています。Ubuntuのインストール手順は[Parallels Desktop 12でUbuntu 16.04 LTSを使っています](http://d.hatena.ne.jp/segavvy/20160906/1473177229
)にまとめましたので、興味のある方はどうぞ。

## 第1章: 準備運動
###01.「パタトクカシーー」
>「パタトクカシーー」という文字列の1,3,5,7文字目を取り出して連結した文字列を得よ．

出来上がったコード：

```python:main.py
# coding: utf-8
target = u'パタトクカシーー'
result = target[::2]
print(result)
```

実行結果：

```python:端末
パトカー
```

***

前回同様、`[start:stop:step]`で指定するスライスを使いました。全部を対象にするのでstartとstopは省略しています。
startを1（=2文字目）にすれば'タクシー'も取り出せます。

```python:インタプリタ
>>> target = u'パタトクカシーー'
>>> print(target[1::2])
タクシー
```

2本目のノックは以上です。誤りなどありましたら、ご指摘いただけますと幸いです。
環境マッピング


r78

デモ：https://mo49.github.io/qiita/20160908/envmap.html

skyboxをつくって、その中にオブジェクトを2つ配置。
sphereは他のオブジェクトも反射する動的環境マッピングをやってみる。


## CubeMapオブジェクトをつくる

まず、サイコロの展開図みたいな6面の画像を用意する

CubeMap用の画像を配布しているサイト
http://www.humus.name/index.php?page=Textures

360度画像をCubeMap用に変換してくれるサイト
http://gonchar.me/panorama/

THETAの画像をCubeMap用に変換してくれるサイト
https://sites.google.com/site/ge56web/software/p2cc


```javascript:画像をロードする
// cube texturesをロードする
createCubeMap (geom, imageFile) {
  const PATH = './img/envmap/';
  const FORMAT = '.jpg';
  const URLS = [
    PATH + 'posx' + FORMAT, PATH + 'negx' + FORMAT,
    PATH + 'posy' + FORMAT, PATH + 'negy' + FORMAT,
    PATH + 'posz' + FORMAT, PATH + 'negz' + FORMAT
  ];

  const cubeTextureLoader = new THREE.CubeTextureLoader();
  const textureCube = cubeTextureLoader.load(URLS);
  return textureCube;
}
```

## skyboxをつくる

shaderにCubeMapオブジェクトを渡す

```javascript:skyboxをつくる
this.textureCube = this.createCubeMap();
this.textureCube.format = THREE.RGBFormat;
this.textureCube.mapping = THREE.CubeReflectionMapping; // 屈折
// CubeMapに基づいて環境を作成できる特殊なshader
const shader = THREE.ShaderLib["cube"];
shader.uniforms["tCube"].value = this.textureCube;

const material = new THREE.ShaderMaterial({
  fragmentShader: shader.fragmentShader,
  vertexShader: shader.vertexShader,
  uniforms: shader.uniforms,
  depthWrite: false,
  side: THREE.DoubleSide
});

const skybox = new THREE.Mesh(new THREE.BoxGeometry(10000, 10000, 10000), material);
this.scene.add(skybox);
```

## CubeCameraを使う

動的な環境マッピングには必須なcamera

```javascript:カメラを用意
this.cubeCamera = new THREE.CubeCamera(0.1, 20000, 256);
this.scene.add(this.cubeCamera);
```

毎フレームごとに更新することも忘れずに。

```javascript:カメラを更新する
render() {

  ・・・（中略）・・・

  // 一度sphereを消してCubeMapを更新してから表示する
  this.sphere.visible = false;
  this.cubeCamera.updateCubeMap(this.renderer, this.scene);
  this.sphere.visible = true;
}
```


## Sphere, TorusKnotを追加

envMapにどのように環境を反射するか記述
sphere -> 動的環境マッピング
torusknot -> 静的環境マッピング

```javascript:オブジェクトを追加
const sphereGeometry = new THREE.SphereGeometry(20, 15, 15);
const torusGeometry = new THREE.TorusKnotGeometry(60, 2, 256, 8, 4, 3, 1);
const torusGeometry2 = new THREE.TorusKnotGeometry(150, 2, 512, 8, 6, 4, 1);

const dynamicEnvMaterial = new THREE.MeshBasicMaterial({
  envMap: this.cubeCamera.renderTarget, // cubeCameraを設定、シーン内の他のオブジェクトも反射
  side: THREE.DoubleSide
});
const envMaterial = new THREE.MeshBasicMaterial({
  envMap: this.textureCube, // 作成したcubeMapオブジェクトを設定することで、meshはその環境を反射
  side: THREE.DoubleSide
});

this.sphere = new THREE.Mesh(sphereGeometry, dynamicEnvMaterial);
this.scene.add(this.sphere);

const torus = new THREE.Mesh(torusGeometry, envMaterial);
const torus2 = new THREE.Mesh(torusGeometry2, envMaterial);
torus.material.reflectivity = 1.0; // 反射率 (同じマテリアルを適応しているのでtorus2も影響を受けるのに注意)
this.scene.add(torus, torus2);
```

> 参考
[初めてのThree.js 第2版――WebGLのためのJavaScript 3Dライブラリ](https://www.oreilly.co.jp/books/9784873117706/)
pythonでキー入力を検出する(tty)

前回termiosを使って同じことをしたんだけど、ttyでもやってみた。
[前回]http://qiita.com/tortuepin/items/9ede6ca603ddc74f91ba


```
import sys
import termios
import tty

#標準入力のファイルディスクプリタを取得
fd = sys.stdin.fileno()

#fdの端末属性をゲットする
old = termios.tcgetattr(fd)

try:
    #標準入力のモードを切り替える
    #cbreakとrawのどっちもエンターいらなくなるけど、rawはctrl-cとかもきかなくなる??
    tty.setcbreak(sys.stdin.fileno())
    #tty.setraw(sys.stdin.fileno())
    ch = sys.stdin.read(1)
    
finally:
    # fdの属性を元に戻す
    termios.tcsetattr(fd, termios.TCSANOW, old)

print(ch)
```

こっちのほうが前回よりも自由度は低いけど簡単です。


### cbreakとrawの違い

https://utcc.utoronto.ca/~cks/space/blog/unix/CBreakAndRaw
rootユーザでログインしたことが分かるようにする。


## rootユーザでログインした時に、プロンプトの文字列を赤くする。

rootユーザの.profileに以下を記載。

```bash:.profile
export PS1="\e[31m\e[40m\][\u@\h \t]\\$\[\e[0m\] "
```

## rootユーザでログインした時に、メッセージを表示する。

rootユーザの.profileに以下を記載。

```bash:.profile
msg='\e[31m------
警告!
------
rootユーザでログインしています。
操作には十分注意してください。
必要のない場合は、すぐにログアウトしてください。
\e[0m'
echo -e "$msg"
unset msg
```

以上
Macでデータマインニングする下準備


売上データ分析とか、アクセス解析、コンサル的な統計学の世界を自宅でも体験してみたいと思ったので準備だけしてみる。ゲーム屋さんや運用フェーズに入ったサービスを持ってる人は色々とRで遊べるんだろうな・・・。

ビジテクの分析シリーズ並みにわかりやすい、ビジネスに特化した初心者向けR分析本はないかしらん？？
[ロースハラミ現象](http://careerhack.en-japan.com/report/detail/352)とか、面白そうだ♪


##Rのインストール
事前に[Homebrew](http://brew.sh/index_ja.html)と[cask](https://caskroom.github.io)を入れておくこと。
テスト用DBとして[MySQL](http://qiita.com/hkusu/items/cda3e8461e7a46ecf25d)がインストイールされていること。

>$brew install r

>$brew cask install rstudio


アプリケーションからRStudioをクリックしR起動。
もしくはターミナルから"r"でRターミナル起動。


##DBIパッケージのインストール
>$install.packages("DBI")

>$install.packages("RPostgreSQL")

>$install.packages("RMySQL")

>$install.packages("RSQLite")

取り敢えずPostgreSQL、MySQL、SQLiteを、それぞれ入れとく。



##接続テスト(MySQL編)

> \>par(family="HiraKakuProN-W3")
※Font指定(Macで日本語を使うためには必要らしい)

>\>library(DBI)

>\>library(RMySQL)

> \>dataset <- dbGetQuery(dbConnect(dbDriver("MySQL"), dbname="データベース名", user="ユーザー名", password="パスワード"), "select * from データベース名.テーブル名;")

> \>View(dataset)

> \>dbDisconnect(dataset)

当たり前だけど、テスト前にMySQLを立ち上げとかないと繋がりません。
> \>$ mysql.server start


##RMySQLのverが0.10.9だと以下の警告が出るかも・・・

警告メッセージ: 
1:  .local(conn, statement, ...) で: 
  Unsigned INTEGER in col 1 imported as numeric
2:  .local(conn, statement, ...) で: 
  Unsigned INTEGER in col 3 imported as numeric

[対策](https://github.com/rstats-db/RMySQL/issues/69)  

> \>remove.packages('RMySQL')

> \>install.packages('devtools')

> \>devtools::install_github("rstats-db/RMySQL")
verが0.11.3以上になっているはず。

> \>q()
再度RStudioを起動し、接続テストしてみる。


##絶対に入れといたほうがいいパッケージ
[ggplot2](http://stat.biopapyrus.net/ggplot/)


##Rでは無いけどmコマンドが速くて軽いらしい。
[mコマンドで数億行を高速集計](http://blog.howtelevision.co.jp/entry/2015/02/06/154048)
[NYSOL](http://www.nysol.jp)


##参考にさせて頂いたサイト
[データマイニング講座](http://careerhack.en-japan.com/report/detail/382)
[RからDBに接続する方法](http://www.task-notes.com/entry/20150825/1440471600)

[RからAPI経由でGoogleアナリティクス](http://abrahamcow.hatenablog.com/entry/2015/01/02/215112)
[初心者でもできる｜RでGoogle Analytics解析](https://www.karada-good.net/rgoogleanalyticsindex/)

[文系がゼロから統計を勉強するときに最初の１年で読むべき本](http://statsbeginner.hatenablog.com/entry/2014/09/27/194747)
[R言語を使うときの資料](http://matome.naver.jp/odai/2135003580165010301)
[R情報検索](http://seekr.jp)

[データマイ二ング コンテスト](https://www.kaggle.com)
[データマイ二ング　コンペ(日本)](https://deepanalytics.jp/?tc=menu)
[総務省統計局データ](http://www.stat.go.jp/data/guide/2.htm)

[(スライド)データビジュアライゼーション事始め](http://www.slideshare.net/yasuyukisugai/r-28544592)
[(スライド)相関分析による需要予測](http://www.slideshare.net/yasuyukisugai/2-r-34017181)
[(スライド)競争ポジショニング戦略](http://www.slideshare.net/yokkuns/r-22276096?next_slideshow=1)

[(スライド)RユーザーのためのMコマンド](http://www.slideshare.net/weda654/m-40991284)
[(スライド)日本発の大規模データ解析用OSS](http://www.slideshare.net/NYSOL/nysoloss)
TechFeed Live#2 「React vs Angular2」覚書

[TechFeed Live#2 「React vs Angular2」](http://techfeed.connpass.com/event/38582/)に参加登録したところ、定員オーバーによる抽選落ちからのキャンセル待ち繰り上がりで参加できたので、自分がうといWeb系技術の勉強がてら拝聴してまいりました。RC版のライブラリをものともせずガッツリと使い込んでいらっしゃる方々のアツいトークの中、初めて聞く単語をググりながら何とか自分なりに情報を拾えるだけ拾ってきました。

以下、覚書です。不勉強なため、間違い(解釈違い)な点もあると思いますが。。。

# React

- Viewのライブラリ
- 状態・イベントの管理をするデザインパターンがある(オブザーバルパターン、Flux, Redux)
    - これを組み合わせてもAngularエコシステム規模にはならない(足りない)
- 初期学習コストが高い
    - 中級者になるまでの敷居が高い
- Javascript上級者が好む
    - 好きにライブラリを組み合わせられる

# Angular2

- "One Framework"、フルスタック
- RxJSとの組み合わせもあり？
- DI機能あり。ReactにはDIの考え方はない
    - Angular2をReduxと組み合わせるとこの旨味がなくなる
    - テストしやすい設計
- RCがRCじゃない。。。
    - RC4 > RC5 > RC6, とAPIの変更が激しい
    - 早ければ今月末にFinallyが出る
- minify前提(サイズが大きい)


# 比較観点から

## 開発言語

- ReactはJSXがないとつらい
- Angular2はTypeScript, ReactはBabel、というすみ分けはできている感じがする
    - 開発者の慣れ、FW開発言語など
- どちらもDOMを直接いじらない
- React, Angular2問わず、開発規模が大きければTypeScriptが便利(静的型)。
    - Javascriptを生で書くことはない。何らかのコンパイルは必須。

# ビルドツール

- webpack,...
- どちらも違いはない

# ルーティング

- Angular2のルーティング機能はよくできてきた
    - ここ2-3ヶ月くらいの話。その前はひどかった
- 現状、汎用ルーティングライブラリのデファクトスタンダードというものがない

# テンプレート

- Angular2はhtml寄り。
- ReactのJSXは文字列なのでコンパイル時チェックができない

# XSS対策

- Angular2の圧勝
    - ReactはURLを注入する場合など、開発者がちゃんとチェックする必要あり
    - Angular2は厳しいほどチェックしてくれる

# ツール

- WebStorm(IDE)
    - React, Angular双方に力を入れている
        - 固有記法のシンタックスハイライトなど

# テスト

- Angularはテストフレームワークが内包されている
- Reactはコンポーネントに状態を持たせないスタイルなのでテストしやすい
    - コンポーネントが関数ベース
    - DOMを管理するでかいシングルトンオブジェクトがある
    - Angularはコンポーネントにステートを持たせる

# パフォーマンス

- Angular2になってからReactと同等の速度になった
    - Angular1は遅い。パフォーマンスが出ない場合はAngular1のせいにできた

# サーバサイドレンダリング

- どちらもパフォーマンスは変わらない？

# その他

- SWAGGER
    - RESTFul APIを記述するための仕様
    - yaml/jsonからコード生成
jekinsにttyなしかつパスワードなしのsudo権限を与える

アクセス権の問題でjenkinsのジョブが安定しないのを、sudoで強引に解決させたいときの設定です。
visudoで以下を追記するだけです。

```
Defaults:jenkins !requiretty
jenkins ALL=NOPASSWD: ALL
```

あなたのjenkinsに大いなる力を授けましょう。

# 参考

* http://qiita.com/yuku_t/items/0f15d487ed6232d21410
* http://qiita.com/ryo0301/items/4daf5a6d22f16193410f
* http://www.hachim.jp/study-by-incident/tty-cron-sudo.html
* http://qiita.com/RyodoTanaka/items/e9b15d579d17651650b7
Pythonでキー入力を検出する(Enter無しで)

[追記]
[tty版](http://qiita.com/tortuepin/items/e6c72f48115f20744ace)

input()とか、sys.stdin.read()とかを普通に使うと、

1. 文字を入力する

2. エンターを押す

の2ステップが必要となる。

エンターを押さなくても、キーを入力した瞬間に何かして欲しい。
と思って調べてみたんだけどなかなか見つからなかったのでメモ.

macとubuntuでは動作確認できてます。
windowsでは動きませんが、msvcrtモジュールがあると同じことが簡単にできるようです。

 
```python
import sys
import termios

#標準入力のファイルディスクリプタを取得
fd = sys.stdin.fileno()

#fdの端末属性をゲットする
#oldとnewには同じものが入る。
#newに変更を加えて、適応する
#oldは、後で元に戻すため
old = termios.tcgetattr(fd)
new = termios.tcgetattr(fd)

#new[3]はlflags
#ICANON(カノニカルモードのフラグ)を外す
new[3] &= ~termios.ICANON
#ECHO(入力された文字を表示するか否かのフラグ)を外す
new[3] &= ~termios.ECHO


try:
    # 書き換えたnewをfdに適応する
    termios.tcsetattr(fd, termios.TCSANOW, new)
    # キーボードから入力を受ける。
    # lfalgsが書き換えられているので、エンターを押さなくても次に進む。echoもしない
    ch = sys.stdin.read(1)
    
finally:
    # fdの属性を元に戻す
    # 具体的にはICANONとECHOが元に戻る
    termios.tcsetattr(fd, termios.TCSANOW, old)

print(ch)
```

## ファイルディスクリプタ
そもそも、入出力はファイルディスクリプタという識別子を用いて管理されている。
http://qiita.com/toshihirock/items/78286fccf07dbe6df38f

ファイルディスクリプタをOSと各プログラム間でやりとりすることで、標準の入出力なのか、あるいはエラー出力なのか、はたまたファイルからの入出力なのかってのをお互いに判断する。




## termios
ファイルディスクリプタ使って実際にOSとデータのやりとりをする窓口になってるのが、termiosってやつ。
termiosは、プログラムとOS間で、どうやってデータをやりとりするかって情報を持ってる。
https://linuxjm.osdn.jp/html/LDP_man-pages/man3/termios.3.html

その情報の中に、エンターを押すまで入力を待つか、キーが押されたらすぐに入力とするかを決めるフラグ(カノニカルモード,ICANON)もある。
それをいじればキー入力の検出ができるって寸法。

ちなみに、上の例では入力した文字を表示するかどうかを決めるフラグ(ECHO)もいじってる。


###参考
termiosについて。カノニカルモードとかも詳しい。
https://linuxjm.osdn.jp/html/LDP_man-pages/man3/termios.3.html

pythonにおけるtermios
http://docs.python.jp/2/library/termios.html#module-termios

ttyというtermiosより高レベルで似たようなことができる。というかこっちのほうが簡単。Unixでしか使えない。
http://docs.python.jp/2/library/tty.html#module-tty

ttyを利用していい感じのモジュールにしてる
http://code.activestate.com/recipes/134892/
人工知能パーツ Microsoft Cognitive Services を使った表情分析アプリを作ろう！[サブスクリプション準備編]

Microsoft Cognitive Services は 画像、文章、言語、情報を処理する機能を API 経由で利用できるサービスです。
Cognitive Services は無料で試用できますが、予めサブスクリプション申し込みが必要です。以下、Cognitive Services のサブスクリプションの申し込み手順を紹介します。

【2017/6/3追記】
2017/5 より 30 日間の無償試用版となりました。申し込み方法は [サブスクリプション準備編 2017年5月版](http://qiita.com/annie/items/251d4b85c86aa9321665) をご覧ください。

##Microsoft アカウント
サブスクリプションの申し込みに必要となりますので、持っていない場合は取得しておきます。
>[Microsoft アカウント登録手続き](https://www.microsoft.com/ja-jp/msaccount/signup/default.aspx)

#Cognitive Services サブスクリプション申し込み
Cognitive Services の [Pricing ページ](https://www.microsoft.com/cognitive-services/en-us/pricing) を開きます。
>以下、Emotion API を例として手順を進めますが、他の API でも同じです。

Emotion API の行にある *Try for Free* をクリックします。
![](https://msdnshared.blob.core.windows.net/media/2016/09/bluesky_20160907_01.png)

Microsoft アカウントでサインインします。
![](https://msdnshared.blob.core.windows.net/media/2016/09/bluesky_20160907_02.png)

>サブスクリプション申し込み前に以下のように Email Verification (認証) が必要になる場合があります。[Send Verification] をクリックすると、表示されている Email に認証用のメールが送られます。
メールに記載されている URL をクリックして認証が完了すると、サブスクリプションの申し込みに進めるようになります。
<img width="300" src="https://msdnshared.blob.core.windows.net/media/2016/12/bluesky_20161203_01.png"> <img width="300" src="https://msdnshared.blob.core.windows.net/media/2016/12/bluesky_20161203_02.png">

*Emotion - Preview* の行が選択されている (☑) のを確認して、ページ下部までスクロールし、Privacy Statement に合意 (チェックボックスをクリック) して、*Subscribe* をクリックします。
![](https://msdnshared.blob.core.windows.net/media/2016/09/bluesky_20160907_03.png)

*My free subscriptions* に *Emotion - Preview* が表示されていれば、申し込み完了です。
*Key 1* に記載されている文字列がサブスクリプションキーになります。*Copy* をクリックするとコピーできます。
![](https://msdnshared.blob.core.windows.net/media/2016/09/bluesky_20160907_04.png)
Win、Mac、Linux で使えるコードエディタ、Visual Studio Code のインストール

#Visual Studio Code
マイクロソフトが提供する無料のコーディングツールで、Windows、MacOSX および Linux 版が用意されています。こちらでは Visual Studio Code のダウンロードからインストールまでの方法を紹介します。

#Visual Studio Code のダウンロード
[Visual Studio 製品サイト](https://www.visualstudio.com/) を開きます。
右の列にある **Visual Studio Code** のうち、Window版、MacOSX版、Linux 版 のいずれかをお手持ちの OS に合わせてダウンロードします。
![](https://msdnshared.blob.core.windows.net/media/2016/09/bluesky_20160907_11.png)

>以下の手順では Windows版を例として進めますが、他でもほぼ同じです。

#Visual Studio Code のインストール
ダウンロードした exe を起動してインストールを行います。

*Visual Studio Code セットアップウィザードの開始* の画面で *次へ* をクリックします。
![](https://msdnshared.blob.core.windows.net/media/2016/09/bluesky_20160907_12.png)

*Visual Stuido Code セットアップ* の画面で マイクロソフト ソフトウェア ライセンス条項を確認します。*同意する* をクリックして選択し、*次へ* をクリックします。
![](https://msdnshared.blob.core.windows.net/media/2016/09/bluesky_20160907_13.png)

次の画面で Visual Stuido Code のインストール先を指定します。特に変更する必要がなければデフォルトのまま、*次へ* をクリックします。
![](https://msdnshared.blob.core.windows.net/media/2016/09/bluesky_20160907_14.png)

次の画面で プログラムグループの指定を行います。特に変更する必要がなければデフォルトのまま、*次へ* をクリックします。
![](https://msdnshared.blob.core.windows.net/media/2016/09/bluesky_20160907_15.png)

次の画面で インストール時に実行する追加タスクの選択を行います。特に変更する必要がなければデフォルトのまま、*次へ* をクリックします。
![](https://msdnshared.blob.core.windows.net/media/2016/09/bluesky_20160907_16.png)

*インストール準備完了* の画面で *次へ* をクリックすると、インストールが始まります。
![](https://msdnshared.blob.core.windows.net/media/2016/09/bluesky_20160907_17.png)

インストールが完了するのを待ちます。
![](https://msdnshared.blob.core.windows.net/media/2016/09/bluesky_20160907_18.png)

*Visual Studio Code セットアップウィザードの完了* 画面が表示されたら、終了です。
![](https://msdnshared.blob.core.windows.net/media/2016/09/bluesky_20160907_19.png)
FactoryGirlの遅延評価でハマったメモ


都道府県ランキングみたいなものを持っているモデルのファクトリでハマったのでメモ。

以下のように都道府県ランキング属性の生成を、配列からの`shift`で書いていたら、48回目の呼び出しから`Field 'ranking' doesn't have a default value`と落ちるようになった。

```ruby
FactoryGirl.define do
  nums = (1..47).to_a.shuffle
  factory :hoge do
    ranking { nums.shift }
  end
end
```

FactoryGirlの属性にブロックを渡すと動的に評価される。
どうやらファクトリがロードされた時に確保されるであろう`nums`をファクトリが保持していて、48回目以降は空配列からの`shift`になっている模様。
sequenceの番号保持するのと同じイメージ？

ブロックを外すと、テストは落ちないけど、`nums`が同じ内容を返すようになった。これはまあ同じ配列から`shift`しているから。

この挙動をちゃんと調べようと思ったけどコード読むパワーが無かった。
（多分このへん？→https://github.com/thoughtbot/factory_girl/blob/master/lib/factory_girl/attribute/dynamic.rb)


結果根本的な解決にはなっていないけど、uniqueは気にしないことにして`Random.rand(1..47)`にした。
uniqueな乱数入れるにはどうしたものか...
Unityアプリからテレビの電源を付ける(IRKitをUnityから扱う話)

IRKitをUnityから扱いたい気持ちの人が自分以外にいるとは思えませんが、結果としてIRKitを操作することができたので知見を紹介します。
いろいろハマるところがあったのでそれもメモしておきます。

#この記事の前提：
・IRKitのIPアドレスはわかっている。
・UnityアプリとIRKitは同じWifiにつながっている。
・Windowsでの開発のためコマンドプロンプトを使っている

##IPアドレスを知るには：

```(ex).cmd
% dns-sd -B _irkit._tcp

% dns-sd -G v4 irkitd2a4.local
```

これで知ることができます。詳しくは http://getirkit.com/ に書いてあるとおり。

#テレビの電源を付ける
まずテレビの電源ボタンの赤外線信号はわかっている必要があります。

##電源ボタンの赤外線信号を知る
やり方：
①IRKitにリモコンを向けてテレビの電源ボタンを押す
②IRKitが青点滅したら取得完了
③`curl -i "http://10.0.1.2/messages" -H "X-Requested-With: curl"`をコマンドプロンプトで行う。
↓
{"format":"raw","freq":38,"data":[4713,1150,2368,1150,1150,1150,2368,1150,1150,1150,2368,1150,1150,1150,1150,1150,2368,1150,1150,1150,1150,1150,1150,1150,1150,50610,4713,…,1150,1150]}
と言った感じで取得することができます。
これを控えておきます。


##IRKitに向けてUnityからPOSTして信号を送る。


```IRKitTest.cs
public class IRKitTest : MonoBehaviour{
    void Start() {

        StartCoroutine(POST());
        
    }

    IEnumerator POST() {
        var url = Settings.iRKitLocalURL;
        var json = "{\"format\":\"raw\",\"freq\":xx,\"data\":[4713,1150,2368...(ここは前章で取得した信号を貼り付けて下さい。人それぞれなので省略)}";
        var dat = System.Text.Encoding.UTF8.GetBytes(json);
        WWWForm form = new WWWForm();
        var headers = form.headers;

        headers["Content-Length"] = dat.Length.ToString();
        headers["X-Requested-With"] = "irkit-unity";//irkit-unityというヘッダでなくても良いです。hogeでも良い。

        WWW www = new WWW(url, dat,headers);
        yield return www;
        if (www.error == null)
        {
            Debug.Log(www.text);
        }
        foreach (var kv in www.responseHeaders)
        {
            Debug.Log(kv.Key.ToString() + " -> " + kv.Value.ToString());
        }
    }

```

コードで見ると簡単ですが、

```
        headers["Content-Length"] = dat.Length.ToString();
        headers["X-Requested-With"] = "irkit-unity";
```
がないと、400 BadRequestとして処理されてしまいます。


公式のお知らせ http://maaash.jp/2015/09/irkit-firmware-update/ では
>それ以外のアプリやご自身で作成されたスクリプトで、IRKit Device HTTP API を利用している場合には、以下のように修正を行ってください。
>ブラウザ以外から IRKit Device HTTP API を利用する場合、HTTPリクエストには X-Requested-With: curl のようにヘッダをつけてください。

ということが書いてあったのでそれに則りました。
それだけだと400が返ってきてしまうので悩んでいましたが、Content-Lengthが0として送信されていたので、それを解消しようとContent-Lengthを追加したらうまくいきました。

以上です。
【高速化】CSSをPHP化、画像をBASE64化してリクエスト数を減らしつつキャッシュ利用

#概要
・PHPファイルをCSSとして読み込み
・CSS内部で画像をBASE64エンコードして変数化
・変数化した画像をCSSで描写
・拡張子がPHPファイルとなったCSSをキャッシュ化・圧縮転送


#最初はHTMLに埋め込みしようと思ったけど
メリット：
・リクエスト数が減る

デメリット：
・通信量は期待するほど変わらない
※BASE64エンコードで35%増、圧縮で30%削減、最終的にトントン（らしい）
・キャッシュされない

画像がキャッシュされないのはよろしくない。

#解決策
キャッシュされないデメリットは
CSSに画像を書き込むことで対処。
CSSはキャッシュされるようにしておけば安心。

#実例

```index.php
<!-- PHPファイルをCSSとして読み込む -->
<link rel="stylesheet" type="text/css" href="css.php" /> 

~~

<!-- 画像表示領域 -->
<figure id="profile">
</figure>

```

```css.php
/* リクエストヘッダー */
<?php header('Content-Type: text/css; charset=utf-8'); ?>
@charset "UTF-8";

/* BASE64化 */
<?php $img_profile_png = base64_encode(file_get_contents('profile.png')); ?>

/* 画像出力 */
#profile_img{
    background-image: url('data:image/png;base64,<?= $img_profile_png?>');
}
```

```apache:.htaccess
# 拡張子がPHPでもキャッシュさせる（個別表記）
<Files ~ ".(php)$">
	Header set Cache-Control "max-age=2592000, public"
</Files>

# CSSファイルの圧縮（個別表記）
<ifmodule mod_deflate.c>
 AddOutputFilterByType DEFLATE text/css 
 </ifmodule>
```
コミットのつまみ食い git cherry-pick 事例と共に

#概要
git cherry-pickコマンドは特定のコミットだけを任意のブランチに適応できるコマンド．

#使用場面
masterからブランチを切って新しくbranchAを切った．

branchAでは新しくfileAを追加してコミットをした．
ところが，masterに余計なコミット「1eda36164ff248ffa35f93767cf20518d4dc6ce0」が混ざっていた．

```
commit 344b2dee3bb00044e42176e4596d969331d995b1
Author: moroku0519
Date:   Mon May 23 01:53:06 2016 +0900

    add fileA

commit 1eda36164ff248ffa35f93767cf20518d4dc6ce0
Author: moroku0519
Date:   Sun May 22 19:02:01 2016 +0900

   delete fileB

commit 3c80596997aca4db7dc8b417ada3a56cb1b38f77
Author: moroku0519
Date:   Fri May 20 18:45:27 2016 +0900

   fix fileC

```
ブランチを見てみる．

```
$ git branch
*branchA
 master
 branchB
```

branchBを見てみると

```
$ git checkout branchB
Switched to branch 'branchB'
$ git log

commit 1eda36164ff248ffa35f93767cf20518d4dc6ce0
Author: moroku0519
Date:   Sun May 22 19:02:01 2016 +0900

   delete fileB

commit 3c80596997aca4db7dc8b417ada3a56cb1b38f77
Author: moroku0519
Date:   Fri May 20 18:45:27 2016 +0900

   fix fileC

```

どうやらmasterのままでfileBを消して，その後branchBを切ってしまったらしい．
つまり，今masterとbranchBが同じ．

そこで，歴史を正しくしてあげるためにgit cherry-pickを使う．
まずはmasterを正しくしてあげるために
正しかったコミット「3c80596997aca4db7dc8b417ada3a56cb1b38f77」まで戻す．

```
$ git reset --hard 3c80596997aca4db7dc8b417ada3a56cb1b38f77
$ git log

commit 3c80596997aca4db7dc8b417ada3a56cb1b38f77
Author: moroku0519
Date:   Fri May 20 18:45:27 2016 +0900

   fix fileC
```

これでmasterが正しくなる．
そして，正しいbranchAとなる新しいブランチを作る．

```
$ git checkout -b new_branchA
Switched to a new branch 'new_branchA'
```

ここでgit cherry-pick
抽出したいコミットIDを引数として渡す．

```
$ git cherry-pick 344b2dee3bb00044e42176e4596d969331d995b1
$ git log

commit 344b2dee3bb00044e42176e4596d969331d995b1
Author: moroku0519
Date:   Mon May 23 01:53:06 2016 +0900

    add fileA

commit 3c80596997aca4db7dc8b417ada3a56cb1b38f77
Author: moroku0519
Date:   Fri May 20 18:45:27 2016 +0900

   fix fileC

```

fileBを消した歴史がなくなり，正しいbranchAの歴史ができる．
名前が気になるならばgit branch の-mオプションでrenameしてあげればいい．

#参考
公式ドキュメント
https://git-scm.com/docs/git-cherry-pick

あのコミットのファイルだけこのブランチ取り込みたいときは git cherry-pick
http://nakagaw.hateblo.jp/entry/2015/10/27/154441

git cherry-pickで特定のコミットのみを適用する| Gitテックラボ | [Smart]
http://rfs.jp/server/git/gite-lab/git-cherry-pick.html
fishシェルを試す

シェルといえばshまたはbashで
bashで不満がある人はzshを使っていたりする。
でも、設定が難しい？zshを使わないできたパンピーにはfishがいいらしい。

はてなブックマーク - fishシェル普及計画 
http://b.hatena.ne.jp/entry/fish.rubikitch.com/

# インストールと設定

標準のレポジトリには入っていないのでepelを追加する

```txt
# yum install -y epel-release
```

依存パッケージはbcだけのようなので
http://ftp.riken.jp/Linux/fedora/epel/7Server/x86_64/f/fish-2.3.1-1.el7.x86_64.rpm
これ一本DLしてインストールするだけでも良さそうです。

```txt
# yum search fish
fish.x86_64 : A friendly interactive shell
# yum install -y fish
Dependencies Resolved

============================================================================================================================================================
 Package                           Arch                                Version                                      Repository                         Size
============================================================================================================================================================
Installing:
 fish                              x86_64                              2.3.1-1.el7                                  epel                              1.5 M
Installing for dependencies:
 bc                                x86_64                              1.06.95-13.el7                               base                              115 k
```

シェルを変更する

```txt
$ cat /etc/shells <- 使えるシェルの一覧が書かれている
/usr/bin/fish
$ chsh
Changing shell for ymko.
New shell [/bin/bash]: /usr/bin/fish
Password: <- パスワードを聞かれるので入力
Shell changed.
```

ログオフして入り直す

```txt
Last login: Wed Sep  7 14:00:47 UTC 2016 on console
Welcome to fish, the friendly interactive shell
Type help for instructions on how to use fish
ymko@707a4619a402 ~>
```



# 感想

なんか近未来的なかんじがするシェルですね。
タブ補完がzsh風で便利っぽい？（zsh使ってないけど・・・）
しばらく使って見るかも

# 参考

fishシェル普及計画
http://fish.rubikitch.com/

fish-shellを使ってみませんか
Qiita http://qiita.com/mtwtk_man/items/dde92d0a6024bc61fa58

シェルにあんまりこだわりのなかった僕がfishを使ってかんじたこと
http://www.slideshare.net/TakuyaTokuyama/ss-48876269
gimli gem を使ってMarkdown形式のファイルからPDFファイルを生成する

## <i class='fa fa-download'></i> インストール
```bash
$ gem install gimli
```

## <i class='fa fa-flask'></i> デモ
### <i class='fa fa-file-text'></i> 対象マークダウン
* cover.md (表紙)

```markdown
<br><br><br><br><br><br><br><br><br><br><br>
# 表紙
```

* contents.md (中身)

```markdown
## 鼻毛とは？
鼻からでている毛のことである

## 耳毛とは？
耳からでている毛のことである

<div style="page-break-after: always;"></div>

## 表
|--|鼻毛|耳毛|
|---|:---:|:---:|
|田中|◯|☓|
|鈴木|☓|☓|
|ボーボボ|◯|☓|
|ドアラ|☓|◯|
```

`<div style="page-break-after: always;"></div>` の部分は改ページ

### <i class='fa fa-play'></i> 変換実行
```bash
$ gimli -f contents.md -cover cover.md
```

### <i class='fa fa-file-pdf-o'></i> PDF
![pdf1.png](https://qiita-image-store.s3.amazonaws.com/0/43480/c696f65a-e4de-5db1-61a5-c81e42bdd741.png)
![pdf2.png](https://qiita-image-store.s3.amazonaws.com/0/43480/0bf692e7-5de2-21bc-93a4-e06e01331934.png)
![pdf3.png](https://qiita-image-store.s3.amazonaws.com/0/43480/50e132fd-254e-e406-ce6e-2fbf037d117d.png)

## <i class="fa fa-book" style="font-size:1em;"></i> 外部資料
* <i class="fa fa-external-link" style="font-size:1em;"></i> [walle/gimli - GitHub](https://github.com/walle/gimli)