OmniAICreator/Qiita-1.07M huggingface dataset:
Cloud9でGAE/p開発環境を構築する

サーバサイドアプリを作るのに、久々に **GAE** (Google App Engine) をやろうと手を動かしてみようとしたものの、環境構築が面倒すぎてやる気がなくなった。

ところが、調べ物してる最中に **Web IDE** なる分野があることを知り、ここ数年で実用に耐えうる飛躍を遂げていることにびびった。

というわけで、Web IDEでも高機能だと言われる **Cloud9** を使って GAE/p (Google App Engine for Python) の開発環境を構築するところまでまとめる。なんかニーズが多そうだけど、特に日本語のTipsサイトがほとんど見つからなかった。

## Cloud9の準備

準備もなにも、サイトにアクセスしてログインすればOK。
なお、Githubアカウントがあれば、すぐにログインして使える。

　**Cloud9**
　https://c9.io/

ちなみに、制限付きだが、現状は期限なしでFreeで使える ([こちらを参照](https://c9.io/pricing/webide))。

とりあえず適当にWorkspaceを作っておく。
なお、_Choose a template_ では _Custom_ を選んでおく。

Workspaceを作ったあとIDEが起動する。
こんな感じ↓

![cloud9_ide0.jpg](https://qiita-image-store.s3.amazonaws.com/0/56966/a3d295d8-59da-a4d9-310e-2e255b2539c9.jpeg)


Cloud9ではLinux Terminalが使える。
これが非常にありがたい。
IDEの下部に _bash_ タブがあるのでここでコマンドが叩ける。

## GAE SDKのインストール

bash Terminal 上でSDKをダウンロードする。
ダウンロードやzipの展開場所はどこでもよいが、以下のコマンド例では_sdk_ フォルダを作って、その下に展開している。

```bash
$ mkdir sdk
$ cd sdk
$ wget https://storage.googleapis.com/appengine-sdks/featured/google_appengine_1.9.30.zip
$ unzip google_appengine_1.9.30.zip
```

なお、上記は2016/01/10時点での最新バージョン。
取得前に最新バージョンを[チェック](https://cloud.google.com/appengine/downloads)しておくのがよい。

PATHを通す。

```bash
$ vi ~/.bashrc

(末尾に追記)
PATH=$PATH:/home/ubuntu/workspace/sdk/google_appengine/
```

読み込んでおく。

```bash
$ source ~/.bashrc
```

Pythonのバージョンを調べる。
GAEはPython2.7を要求しているが、Cloud9環境も何もしなくても2.7系になっていたのでこのままでOK。

```bash
$ /usr/bin/env python -V
Python 2.7.6
```

インストールはここまで。


## Hello World を動かす

Hello World (サーバアプリ) をつくり、GAEの開発用ランタイムをCloud9上で起動して、動作確認をする。この投稿のキモ。

まずはHello Worldなサンプルコード。
workspace直下だとあれなので、_app1_ フォルダを作ってそこに置くことにする。
 
```py:app1/hw.py
print 'Content-Type: text/plain'
print ''
print 'Hello, world!'
```

続いてアプリのConfigファイルを用意する。先のapp1フォルダ上に置く。

```yaml:app1/app.yaml
application: app1
version: 1
runtime: python
api_version: 1
handlers:
- url: /.*
  script: hw.py
```

いざ、Cloud9上でGAE開発用ランタイムを起動する。
一般的なGAE環境だと、localhost:8080などでアクセスできるが、Cloud9だとそうもいかず。
Cloud9 IDE上では使えるポートが限られている ([こちら参照](https://docs.c9.io/v1.0/docs/multiple-ports))。

以下のようにhostとportを指定して起動する。

```bash
$ dev_appserver.py app1 --host $IP --port $PORT --admin_host $IP --admin_port 8082
```

このとき、$IPには `0.0.0.0` が、$PORTには `8080` が入っている。

うまく起動すると、以下のようなCloud9のメッセージが表示される。

![cloud9_ok.jpg](https://qiita-image-store.s3.amazonaws.com/0/56966/9690fad6-8310-5321-3bd8-614615912a92.jpeg)


ちなみにダメだった場合はこんな感じ↓
--hostと--port指定がうまくいっていないとこうなる。

![cloud9_ng.jpg](https://qiita-image-store.s3.amazonaws.com/0/56966/a54f8206-707f-94ae-31f9-9c444d9ae4c5.jpeg)

起動したランライム上のサンプルアプリにアクセスする。
Cloud9上で開いたPortとURLの関係は[ここ](https://docs.c9.io/v1.0/docs/multiple-ports)に説明がある。

--port で $PORT (=8080) を指定しているので、以下のURLにアクセスすればOK。

https://`<workspace-name>`-`<username>`.c9users.io/ 

`<workspace-name>`と`<username>`はそれぞれの環境で置き換える。(ex. test-yamadataro.c9users.io)
なお、先の[説明ページ](https://docs.c9.io/v1.0/docs/multiple-ports)では、URLは _https_ のように見えるが、実際には _http_ でもアクセスできた。

以下のように表示されればOK。

![cloud9_sample.jpg](https://qiita-image-store.s3.amazonaws.com/0/56966/c59e6b83-0b05-e4b7-3f0d-71ee16b64706.jpeg)

こうしてまとめてみるとなんてことないが、情報が少なくとっかかりにくかった。
皆さまの環境構築の一助になれば幸い。
FsUnitを使うとアセンブリの競合が出る場合の対処


# 現象

Visual Studio 2015のF#プロジェクト（F#ランタイムバージョン：4.4.0.0）でNuGetからFsUnit(1.4.1)をインストールすると、一緒にFSharp.Core(3.1.2.5)とNUnit(2.6.4)もインストールされる。
このプロジェクトをビルドすると次のような警告が出た。

    同じ依存アセンブリの異なるバージョン間で、解決できない競合が見つかりました。 これらの参照上の競合は、ログの詳細度が詳細に設定されている場合にビルドログにリストされます。

これは警告なのでビルドは成功するけれど、テストを実行しても次のようなエラーが発生してテストが失敗する。

    System.MissingMethodException : メソッドが見つかりません: 'ParserResult`2<System.String,Microsoft.FSharp.Core.Unit> Test.test(System.String)'

# 解決方法

まずはNuGet パッケージマネージャーでFSharp.Coreのバージョンを4.0.0.1に更新する。

次にプロジェクトのApp.configを次のようにする（ない場合はVisual Studioの新しい項目の追加から"アプリケーション構成ファイル"を追加する）。
もし既に他の要素が定義されている場合は&lt;dependentAssembly&gt;の部分を追加すればよいと思う。

```xml
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <runtime>
        <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
            <dependentAssembly>
                <assemblyIdentity name="FSharp.Core" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
                <bindingRedirect oldVersion="0.0.0.0-4.4.0.0" newVersion="4.4.0.0" />
            </dependentAssembly>
        </assemblyBinding>
    </runtime>
</configuration>
```

これで警告が消えてテストも成功するようになった。

# 参考にしたサイト
・[FsUnit and Visual Studio 2013 &ldquo;Could not load file or assembly &#8216;FSharp.Core, Version=4.0.0.0&hellip;&rdquo; | Cyan By Fuchsia](https://cyanbyfuchsia.wordpress.com/2013/11/23/fsunit-and-visual-studio-2013-could-not-load-file-or-assembly-fsharp-core-version4-0-0-0/)
【Macの動画プレイヤー決定版】mpvの導入

Macでの動画再生といえば、QuickTimePlayerとかMplayerXとか一応選択肢がありますが、なんかどんくさいし、重たい。いいのないかなと探していたら見つけたのがmpv。これは、mplayer2をベースに開発されたシンプルな動画プレイヤーで、実際に触ってみると分かるんですが、とにかく軽い。動画再生ができればいいというあなたにオススメなプレイヤーです。導入方法も簡単です。

2018.1.15追記：[iina](https://lhc70000.github.io/iina/)のほうがいいです。`brew cask install iina`で入ります。

#mpvのインストール

```bash
brew install --with-bundle --HEAD mpv
```

 * -with-bundleは、GUIの.appを一緒にインストールしてくれます。幸せ。
 * HEADは開発バージョンですが、こっちの方が安定していたりするらしいのでつけておく。お好みかな。
 * brew command not foundとか言われたら、`ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"`を叩いてからもう一度。
 
これだけですね。。。簡単すぎてキレそうです
動画をctr+クリックでmpvが選択出来るはずです。

#ショートカットの作成
お好みですが、下のコマンドでmpvの場所が開くので、エイリアスを作って/Applicationなどに入れて安心します。

```
open /usr/local/Cellar/mpv/HEAD
```

#便利設定
設定ファイルを作ります。
まずフォルダ作成`mkdir ~/.config/mpv/`
あとはファイルをお好みでファイルを作る。

```bash:~/.config/mpv/input.conf
UP seek 85 
DOWN seek -85 
```

```bash:~/.config/mpv/mpv.conf
vo=opengl-hq >> 
screenshot-template=~Desktop/mpv_ss_%n
save-position-on-quit
```


 * `save-position-on-quit`は、以前閉じた時のシークバーの位置を記憶してくれます。
 * `UP seek 85`は、↑ボタンで85秒シークします。これはアニメとかのオープニングを飛ばすためですね
 * `vo=opengl-hq`はビデオ出力にopenglを使った高解像モードを設定します。
 * `screenshot-template`は好きな場所にスクリーンショットを置けます。

#おまけ
リアルタイムのフレーム補間により60fpsで再生することもできるらしいです。マシンのスペックに依存するので試せてないですが、スペックに自信ニキはぜひ。。
https://gist.github.com/phiresky/4bfcfbbd05b3c2ed8645
Zybo > JTAG-HS2 > いらなかったかも

ZyboでのFPGA開発用にDigilentのJTAG-HS2 Programming Cableを購入したが、実はいらなかったかもしれない。

http://www.tokudenkairo.co.jp/jtag/tutorial/tutorial4-9.html
> このボードにはオンボードでUSB-JTAGがのっているので、

USBケーブルをZyboのJ11に接続して
http://keitetsu.blogspot.jp/2015/01/zybo-base-system-design-vivado-20144-3.html
に従いXSDKからProgram FPGAを実行したらFPGA書き込みできた。

その後、base_demoの実行まで問題なく実行できた。
Google Maps API warning: SensorNotRequired

#はじめに
Google Maps JavaScript APIを使っていたら、なんかエラーが出ていたのでメモ。
Google Maps API warning: SensorNotRequired　ってエラーの対処法。

#GoogleMaps表示コード
Google Maps JavaScript APIを使うとき、下記スクリプトを書くと思います。

```html:index.html
<script src="https://maps.googleapis.com/maps/api/js?sensor=(false or true)"></script>
```

それで、実際にGoogleMapを表示するサンプルコードがこれ。（何でもいいのですが一応）

```html:index.html
<!DOCTYPE html>
<html>
<head>
    <title>Simple Map</title>
    <meta name="viewport" content="initial-scale=1.0">
    <meta charset="utf-8">
    <style>
        html, body {
            height: 100%;
            margin: 0;
            padding: 0;
        }
        #map {
            height: 500px;
            width: 50%;
        }
    </style>
</head>
<body>
<div id="map"></div>
<script src="https://maps.googleapis.com/maps/api/js?sensor=false"></script>
<script>

    function initMap() {
        var myLatLng = {lat: 35.658581, lng: 139.745433};

        var map = new google.maps.Map(document.getElementById('map'), {
            zoom: 14,
            center: myLatLng
        });

        var marker = new google.maps.Marker({
            position: myLatLng,
            map: map,
        });
    }
    initMap();

</script>
</body>
</html>
```

そして、実際にマップを表示させてみると、コンソールログになんだかエラーが出てるではありませんか。

#Google Maps API warning: SensorNotRequired
**Google Maps API warning: SensorNotRequired: https://developers.google.com/maps/documentation/javascript/error-messages**


ほー。

色々調べたら、[公式ドキュメント](https://developers.google.com/maps/documentation/javascript/error-messages)に載っているではありませんか！！！

>The sensor parameter is no longer required for the Google Maps JavaScript API. It won't prevent the Google Maps JavaScript API from working correctly, but we recommend that you remove the sensor parameter from the script element.

パラメータでつけていた **`sensor=(false or true)`** が必要なくなっているみたいです。 

ということで、これを

```html:index.html
<script src="https://maps.googleapis.com/maps/api/js?sensor=(false or true)"></script>
```

こうすれば

```html:index.html
<script src="https://maps.googleapis.com/maps/api/js"></script>
```

エラーが消えます！

Google Maps JavaScript APIの使い方を紹介している記事は大体 **`sensor=(false or true)`**を付けてるのが多いですから引っ掛かりますね。~~いや、ドキュメント読めよとか言わないで~~


ということで、一件落着！！！！

#おわりに
先日記事にしました　[Google Maps API の基本的な使い方](http://qiita.com/Arashi/items/2aa756c942e0de323a97)　ではエラーが出ることは無かったのですが、違う案件でGoogle Maps JavaScript APIを書いていたらなぜか **`sensor=(false or true)`** を付けてました。。。

人間、すぐ忘れる生き物ですから。~~気をつけます。。。~~
ActiveRecordでMySQLのviewに対してinsertする

# はじめに
ActiveRecordでMySQLのviewにinsertをかけようとした時に困ったのでメモ

# viewを使うように設定する
`users` テーブルから `view_users` というviewを作り、ActiveRecordから参照するように設定する

```sql
CREATE VIEW view_users AS SELECT * from users;
```

```rb
class User < ActiveRecord::Base
  self.primary_key = :id
  self.table_name = "view_users"
end
```

# createしたinstanceのidが0になる

```rb
pry(main) > User.create(name: 'hoge')
=> #<User: 0x007fc91201c150
 id: 0,
 name: "hoge",
 created_at: Sun, 10 Jan 2016 13:23:03 UTC +00:00,
 updated_at: Sun, 10 Jan 2016 13:23:03 UTC +00:00>
```

# どこでidを設定しているか
```rb
def _create_record(attribute_names = self.attribute_names)
  attributes_values = arel_attributes_with_values_for_create(attribute_names)

  new_id = self.class.unscoped.insert attributes_values
  self.id ||= new_id if self.class.primary_key

  @new_record = false
  id
end
```
https://github.com/rails/rails/blob/master/activerecord/lib/active_record/persistence.rb#L554

`primary_key` が存在する、かつ `self.id` がセットされていない場合に `id` が設定される
この `id` は、 `LAST_INSERT_ID()` が設定される

# そもそもインスタンス初期化時に `id = 0` となっている

```rb
pry(main) > User.new(name: 'hoge')
=> #<User: 0x007fc90f201db0
 id: 0,
 name: "hoge",
 created_at: Sun, 10 Jan 2016 13:23:03 UTC +00:00,
 updated_at: Sun, 10 Jan 2016 13:23:03 UTC +00:00>
```

# MySQLのデフォルト値が0になっている
オリジナルのテーブルの `id` の定義は `default null` となっているが、viewでは `default 0` となっている

```
root@localhost [paynote_development] > desc users;
+--------------------+--------------+------+-----+---------+----------------+
| Field              | Type         | Null | Key | Default | Extra          |
+--------------------+--------------+------+-----+---------+----------------+
| id                 | int(11)      | NO   | PRI | NULL    | auto_increment |
| name               | varchar(255) | YES  |     | NULL    |                |
| created_at         | datetime     | NO   |     | NULL    |                |
| updated_at         | datetime     | NO   |     | NULL    |                |
+--------------------+--------------+------+-----+---------+----------------+
10 rows in set (0.00 sec)
```

```
root@localhost [paynote_development] > desc view_users;
+--------------------+--------------+------+-----+---------+-------+
| Field              | Type         | Null | Key | Default | Extra |
+--------------------+--------------+------+-----+---------+-------+
| id                 | int(11)      | NO   |     | 0       |       |
| name               | varchar(255) | YES  |     | NULL    |       |
| created_at         | datetime     | NO   |     | NULL    |       |
| updated_at         | datetime     | NO   |     | NULL    |       |
+--------------------+--------------+------+-----+---------+-------+
10 rows in set (0.00 sec)
```

# 解決法
綺麗な解決法か分からないが、インスタンス生成時に `id` を修正すれば良い

```rb
class User < ActiveRecord::Base
  self.primary_key = :id
  self.table_name = "view_users"
  after_initialize :fix_id

  def fix_id
    self.id = nil if self.id == 0
  end
end
```
Raspberry PiにOpenCVを導入してキャプチャするまでと、トラブルシューティング

Raspberry piにOpenCVを導入した時のメモ...
#環境
<ul>
<li>Raspberry Pi B</li>
<li>Rasbian</li>
<li>Logicoolのwebカメラ</li>
</ul>

#準備
※ある程度の環境構築は終わっているものとする...
pythonのnumpyなどの計算ライブラリを入れておく

```shell-session
$ sudo apt-get install python python-dev
$ sudo apt-get install python-numpy python-scipy python-matplotlib
```

#OpenCVの導入
ビルドするのは面倒だし、時間がかかるのでapt-getで
この辺を参考にした
<a href="http://qiita.com/jh3rox/items/be803f9171db8fe737de">Raspberry Pi B+にOpenCV-Python環境を構築する</a>
<a href="http://www.pyimagesearch.com/2015/02/23/install-opencv-and-python-on-your-raspberry-pi-2-and-b/">Install OpenCV and Python on your Raspberry Pi 2 and B+</a>

```shell-session
$ sudo apt-get install libopencv-dev
```
Pythonのパッケージをapt-get

```shell-session
$ sudo apt-get install python-opencv
```

5分くらいで終わると思います。

#キャプチャのソース
このソースで試した。

```python:capture.py
#coding:utf-8
import cv2
color = (0, 2, 2)

def capture_camera(mirror=True, size=None):
    cap = cv2.VideoCapture(1)
    while True:
        ret, frame = cap.read()

        if mirror is True:
            frame = frame[:,::-1]

        if size is not None and len(size) == 2:
            frame = cv2.resize(frame, size)

        cv2.imshow('camera capture', frame)
        k = cv2.waitKey(1)
        if k == 27:
            break
        elif k== 'q':
        	break

    cap.release()

    cv2.destroyAllWindows()

capture_camera()
```

#さて動かそう
と思ったら

```shell-session
GdkGLExt-WARNING **: Window system doesn't support OpenGL.
```
のエラーメッセージ！
vncが原因かと思ったら違うらしい。

#Fix
 とりあえずこれで解決した。

```shell-session
sudo apt-get install libgl1-mesa-dri
```
そして

```shell-session
sudo reboot
```

無事動きました。
vnc上でも動作しました。

#最後に
この辺を参考にしました。
RaspberryPiのカメラやOpenCVのトラブルについて
<a href="https://github.com/braincorp/brainos_wiki/wiki/Troubleshooting">Troubleshooting</a>
WordPressをLinuxへCLIインストールする



WordPressの導入の省力化のため、コマンドラインツールWP-CLIを試してみた。

- http://wp-cli.org/

## 環境
- EC2(Amazon Linux AMI 2015.09.1 x86_64 HVM GP2)
- PHP 5.3.29

## PHP導入

```
$ sudo yum install php php-mysql
```

## WP-CLI導入


```console:
$ curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
```

(もしくはnightlyを使う場合は以下)

```console:
$ curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli-nightly.phar
```

あとはパスを通して実行可能にするだけ

```console:
$ chmod +x wp-cli.phar 
$ sudo mv wp-cli.phar /usr/local/bin/wp
```


## WordPressをダウンロード

参考

- https://blog.sucuri.net/2015/08/wp-cli-guide-installing-wordpress.html

4.3.2をバージョン指定して入れてみる。

```console:
$ cd /var/www/html
$ mkdir blog
$ cd blog

$ wp core download  --version=4.3.2
```



## DB設定

空っぽのDBを同一ホストなりRDSなりに作成した後、接続設定

```console:
$ wp core config --dbhost=host.db --dbname=prefix_db --dbuser=username --dbpass=password
$ chmod 644 wp-config.php
```



## WordPress導入

```console:
$ wp core install --url=yourwebsite.com --title="Your Blog Title" --admin_name=wordpress_admin --admin_password=password --admin_email=you@example.com
```
ここで設定したドメインへはhostsファイルなりDNSなりでアクセスできないといけない。

確認

```console:
mysql> show tables;
```







## Apache設定

```console:
$ sudo chown -R apache:apache .
```

適当にバーチャルホスト追加

```console:
$ sudo vim /etc/httpd/conf/httpd.conf


<VirtualHost *:80>
    ServerAdmin webmaster@dummy-host.example.com
    DocumentRoot /var/www/html/blog
    ServerName yourwebsite.com
    ErrorLog logs/dummy-host.example.com-error_log
    CustomLog logs/dummy-host.example.com-access_log common
</VirtualHost>

$ sudo service httpd restart
```

確認

```console:
$ curl localhost
```
ブラウザでも確認。


## バージョンアップ（バージョンにより失敗）
ところで、4.4.1へのバージョンアップを試そうとしたが、失敗した。



```console:
$  wp core update --version=4.4.1 --force
Updating to version 4.4.1 (ja)...
Using cached file '/home/ec2-user/.wp-cli/cache/core/wordpress-4.4.1-ja-ja.zip'...
更新を展開しています…
Error: パッケージをインストールできませんでした。 PCLZIP_ERR_BAD_FORMAT (-10) : Unable to find End of Central Dir Record signature
```

- 4.3.1へのダウンや4.4へのアップは成功
- 最初に入れた4.3.2に戻すのは失敗
- 画面からだと4.4.1も4.3.2も問題ない

CLIで失敗したバージョンはどれもリリースが4日ほど前だが、新しすぎるとダメ？

リリース履歴:

- https://codex.wordpress.org/WordPress_Versions
bash でゼロパディングされた数字列を作成する

ゼロパディングとは、数字の頭を `0` で詰めて、桁数を調整することです。

linux や mac os のターミナルで、数字の列を作成したい場合、`seq`コマンドが便利です。

```
$ seq 10
1
2
3
4
5
6
7
8
9
10
```
`seq` コマンド自身にもゼロパディングするオプションがあります。

```
$ seq -w 10
01
02
03
04
05
06
07
08
09
10
```

パディングの 0 の個数を増やしたい(桁数を増やしたい場合は)`-f`オプションを使います。

```
$ seq -f %03g 10
001
002
003
004
005
006
007
008
009
010
```

`-f` のフォーマットは

```
$ man printf 3`
```

で調べられます。

`-f` オプションを知るまでは

```
$ seq 10 | xargs -P1 printf '%03g\n'
001
002
003
004
005
006
007
008
009
010
```

とか、

```
$ seq -w 100 | head -n 10
001
002
003
004
005
006
007
008
009
010
```

とかやっていた時代もありました。

やはり `man` を読めば、大体やりたいことは出来るようになっているものですね。
optionに対してのメソッド(forallとexists)の動き

scala初心者の自分が、自分で書いていてわからなくなりそうなのでメモ。
表題の通り対象のメソッドは以下

- forall
- exists

環境は
java version 1.8.0_45
scala 2.11.7

# forall
```scala
  println(Some(1).forall(r => r.equals(1))) // true
  println(Some(2).forall(r => r.equals(1))) // false
  println(None.forall(r => r.equals(1))) // true
```
まぁそういうものかと言われれば、そうだが、Noneの時は式を評価せずにtrueを返すのか。
一瞬違和感あったが、自分で実装するとしたらそうなるよなぁって感じ。でもforallって名前かぁ。（うるさい

# exists
```scala
  println(Some(1).exists(r => r.equals(1))) // true
  println(Some(2).exists(r => r.equals(1))) // false
  println(None.exists(r => r.equals(1))) // false
```
exsitsっていう単語から考えればその通りだなという感じ。
UE4 でレンダリングへの長い道のりーシェーディングについてー

# 環境
UE 4.10.0

# 概要
Unreal Engine 4 のレンダリングの初歩を学ぶ
今回はシェーディングに関してのメモ

# 本文
## UE4 の描画周りを確認してみた
ゲームエンジンやライブラリで描画周りを確認するには、何か適当なものを描画するのが早い。
とりあえず HLSL で軽くシェーダでも書いてみるかと思ってサンプルを探してみるが、見当た
らない。UE4 では、ノードベースでマテリアルを構築していくらしい。と言っても、その構築
したマテリアルが最終的にシェーダコードに変換され、それがクロスコンパイルされる事でマル
チプラットフォームに対応するようだ。

## マテリアルを理解する者は描画を制す
UE4 のレンダリングのドキュメントを見てみると「物理ベースレンダリング」「ディファード
シェーディング」｢グローバル イルミネーション」など難しそうな単語が並ぶ。しかしゲーム
エンジンやライブラリがどんな描画システムになっていようが、要はシェーダに「どんなパラ
メータ」を渡し、「どんな計算をしている」か？に尽きる。最近のゲームエンジンやライブラ
リでは、シェーダパラメータをマテリアルに格納して、レンダリングスレッドに渡す事でプリ
ミティブを描画している。UE4 でもそれは同じだ。即ち UE4 の描画を理解するにはマテリアル
への理解を深めていくのが良い。

## シェーディングとは？
シェーディングは、シェーダの「どんな計算をしている」の部分を指している。
もう少し詳しく言えば、ライティングをマテリアルが反射する際の計算式を指している。
昔の Direct3D では、シェーディングにフラットシェーディングとグーローシェーディングが
あり SetRenderState 関数で切り替えていたが、それと似たようなものだ。

UE4 ではマテリアルに格納した情報でシェーディングを切り替える。
UE4 のシェーディングは、目的別にいくつか存在する。物理ベースレンダリングなのだから、
パラメータを適切に設定すれば、どんなものでも表現できるのでは？と思うかもしれない。
たしかに、パラメータを適切に設定すればかなりのものをそれっぽく表現できる。しかし、レン
ダリングするものによっては無駄が非常に多い場合もある。例えば、ライティングを必要としな
い物体を計算する場合、ライティングに関係するパラメータを全てデフォルト(計算結果が変化
しない値)に設定して計算するより、マテリアルからライティングに関係のあるパラメータを省き
計算式も省略したもので計算する方が高速な計算が行える。
また、物理ベースの計算ではうまく表現ができないものも存在する。そういった物体を計算する
には別の計算式を使用した方が、計算が高速に行えたりレンダリング結果が適切になったりする。

## UE4 のシェーディング
UE4 のシェーディングは、私は 3 種類に大別している。

+ 物理ベースレンダリング
ここに分類できるのは、以下のシェーディングだ。
[Default Lit]
このシェーディングは、ライティング計算ありの通常の物理ベースのレンダリングを行う
[Unlit]
このシェーディングは、ライティング計算なしの物理ベースのレンダリングを行う

+ サブサーフェススキャッタリング( SSS )
サブサーフェススキャッタリングとは、光が半透明な物体の表面を透過し、物体の内部で散乱した
した光が表面から出て行く仕組みの事を指す。”半透明な物体”と聞くと、半透明描画に使用する
ものかと思うが、そういうわけではない。描画の扱いで不透明な物体としてレンダリングするオブ
ジェクトも、マテリアルの性質に合わせてこのシェーディングを選択した方が、よりクオリティの
高いレンダリングができる。
[Subsurface]
このシェーディングは SSS の汎用的な計算を行う場合に使用する
[Preintegrated Skin]
このシェーディングは、人間などの肌のシェーディングを行う場合に使用する。
直訳すると「事前積分計算による肌シェーディング」という事だろうか。
事前計算とあるように SSS 計算にルックアップテーブルを使用する為高速に計算が可能なようだ
[Subsurface プロファイル]
このシェーディングは、人間などの肌や滑らかな表面を持つものに使用する。
UE 4.5 にて実装された、スクリーン空間でのフィルタリングを用いた SSS の計算を行う。
スクリーン空間のフィルタリングを行うという計算の性質上、他の SSS のようにライティング時
に計算は行わず、ポストプロセスにて計算を行う。その際にサブサーフェスプロファイルアセット
というアセットを使用する。アセットを準備しておく必要があるが、その分高品質なレンダリング
が可能になる
[Two Sided Foliage]
このシェーディングは、樹木の葉や紙などの薄い形状を持つものに使用する。
フォリッジとは茂っている木の葉全体の事を指し、その名の通り Epic のサンプルでは木の葉に
使用されている。UE 4.7 にて実装され、SSS とは透過した光に対する計算が異なる。木の葉など
の薄い形状を持つ物体は薄い面に光が出やすい性質があり、このシェーディングではそういう性質
を上手く表現する計算を行う

+ その他
[Clear Coat]
このシェーディングは、アクリルやラッカーのコーティング素材やカーペイントなど
に使用する。UE4 のドキュメントによると半透明層のフィルムを持つマルチレイヤー
のマテリアルをより適切にシミュレーションするのに使用できるとある。要するに、
サーフェスに適用するマテリアルのブレンドを行う際に使用するのだろう。
重みをつけてランダムに何か出したい

広告とかガチャとか色々なところで重みをつけてランダムに何か出したいというときがあります。こういうのを『<strong>重み付き乱択アルゴリズム</strong>』とかって言うらしいです。

こういうときによくやるのは重みの分だけ要素を用意して、配列にいれておき、要素数未満の乱数をインデックスにしてアクセスするみたいなこともよく見ます。しかしこの方法では重みは整数しか指定できません。実数で重みを指定したい場合はどうすればいいのでしょうか。

今回実装としてCPANモジュールの[Data::WeightedRoundRobin](https://metacpan.org/source/XAICRON/Data-WeightedRoundRobin-0.06)を参考にしました。

[lib/Data/WeightedRoundRobin.pm - metacpan.org](https://metacpan.org/source/XAICRON/Data-WeightedRoundRobin-0.06/lib/Data/WeightedRoundRobin.pm)

参考にした実装では重みの合計が1である必要はありません。しかし結局重みの合計値を計算する必要があるので、合計値が1という前提にして説明します。合計値が1でない場合は重みの合計値倍すれば大丈夫です。実数値の場合、合計値が正確に1になることはほぼない（すべて2進数で表現できて、かつ極端に小さいものがない場合は大丈夫）ですが、特に問題ありません。

今回はしきい値となる値を用意します。しきい値として最初の要素に0、その後の要素のしきい値には今までの要素の重みの和を与えます。

具体的に説明します。重みを0.2,0.3,0.4,0.1とします。その場合しきい値は下のようになります。

| 重み | しきい値 |
| --- | ------- |
| 0.2 | 0 |
| 0.3 | 0.2 |
| 0.4 | 0.5 |
| 0.1 | 0.9 |

![スクリーンショット 2016-01-10 20.39.57.png](https://qiita-image-store.s3.amazonaws.com/0/9930/dbe02218-e00e-13cf-847b-6c6384ce7abd.png)

[0,1)の間の乱数を出力して、しきい値が大きい順に見ていって、用意した乱数がしきい値以上かどうかを判定します。しきい値以上ならその要素を選択するようにします。Goなら`rand.Float64()`を使うと[0,1)の間の乱数を出力できます。

```go:randomized_test.go
package randomized

import (
	"math/rand"
	"testing"
	"time"
)

type weight struct {
	weight    float64
	threshold float64
	count     int
}

func BenchmarkRandomized(b *testing.B) {
	b.StopTimer()

	lists := []*weight{&weight{weight: 0.2}, &weight{weight: 0.3}, &weight{weight: 0.4}, &weight{weight: 0.1}}

	totalW := 0.0
	for _, v := range lists {
		(*v).threshold = totalW
		totalW += v.weight
	}

	rand.Seed(time.Now().UnixNano())

	b.StartTimer()

	for i := 0; i < b.N; i++ {
		random := rand.Float64()
		for i := len(lists) - 1; i >= 0; i-- {
			if lists[i].threshold <= random {
				lists[i].count++
				break
			}
		}
	}
}
```

一応最初に説明した重みを整数にして重みの分だけ要素を用意する実装との速度比較をしたかったのでGoで用意してみました。

https://github.com/catatsuy/randomized/blob/master/randomized_test.go

`go test -bench .`と実行すると比較することができます。

また要素数が増えたときは2分木探索をした方が速いです。今回参考にしたCPANモジュールのData::WeightedRoundRobinではデフォルトで要素数が10以上なら2分木探索になります。そこでどれくらいのサイズで速度は逆転するのか以前に調べました。

[golang - 線形探索ではなく2分木探索した方がいいサイズってどれくらいなのか - Qiita](http://qiita.com/catatsuy/items/920598627f7070a3de60)

記事にも書いたように実際には線形探索だと最悪実行時間が長いです。2分木探索がいいのか線形探索がいいのかはアプリケーションの仕様から考えましょう。
railsにおいて、多対多な関連の表示を行う

# 編集の続き

さっき書いた、多対多な関係のものを表示したいときどうするか？って話。

http://qiita.com/rojiuratech/items/0487105994d9281221d4

## 実現したいこと

投稿：タグが　多：多な関連付けになっていて、間に関連付け用のモデルを挟んだ状態と仮定した上で

1. 投稿の詳細を閲覧したときに、当該投稿に関連するタグが一括表示されること。
2. 特定のタグを選択したときに、そのタグに関連する投稿一覧が表示されること。

# 実装前に検証

参考文献によると、

- まず、投稿を取得する。
- 投稿に関連するタグをeachで取得する
- タグを一つ一つ表示する

という流れになるので、コンソール上で試す。
試してみたらうまくいきそうだ！

```bash:terminal
$ rails c
[4] pry(main)> @post = Post.find_by(id: 3)
  Post Load (0.1ms)  SELECT  "posts".* FROM "posts" WHERE "posts"."id" = ? LIMIT 1  [["id", 3]]
=> #<Post:0x007fe42897a1a8 id: 3, name: "テスト登録２", mode: 1, desc: "テストです", created_at: Sun, 10 Jan 2016 10:20:47 UTC +00:00, updated_at: Sun, 10 Jan 2016 10:20:47 UTC +00:00>
[5] pry(main)> @post.tags.each do |tag|
[5] pry(main)*   puts tag
[5] pry(main)* end  
  Tag Load (0.2ms)  SELECT "tags".* FROM "tags" INNER JOIN "post_tags" ON "tags"."id" = "post_tags"."tag_id" WHERE "post_tags"."post_id" = ?  [["post_id", 3]]
#<Tag:0x007fe427e95cb0>
#<Tag:0x007fe427e95ad0>
=> [#<Tag:0x007fe427e95cb0 id: 1, label: "登録たぐ１", created_at: Sun, 10 Jan 2016 04:17:06 UTC +00:00, updated_at: Sun, 10 Jan 2016 04:17:06 UTC +00:00>,
 #<Tag:0x007fe427e95ad0 id: 2, label: "登録たぐ２", created_at: Sun, 10 Jan 2016 04:17:19 UTC +00:00, updated_at: Sun, 10 Jan 2016 04:17:19 UTC +00:00>]
```

# コントローラ　ビューの改修

## コントローラ（べつにこれ、敢えて書かなくともよかった）

```ruby:app/controllers/post_controller.rb
  # GET /posts
  # GET /posts.json
  def index
    @posts = Post.all
  end

  # GET /posts/1
  # GET /posts/1.json
  def show
    # これは、あえて書かなくとも良い
    @post = Post.find_by(id: params[:id])
  end
```

注：コントローラに関しては、indexとかshowに関しては、デフォルトで対応するモデルのすべて、または各指定idのものを取得するようになっているので、記述しなくとも良かった。


## ビュー(showのケース）

（主要部だけ抜粋）

```ruby:app/views/posts/show.html.erb
<p>
  <strong>関連タグ</strong>
  <br>
  <% unless @post.tags.empty? %>
  	<ul>
  	<% @post.tags.each do |tag| %>
  		<li><%= tag.label %></li>
  	<% end %>
  	</ul>
  <% else %>
  		たぐありません
  <% end %>
</p>
```

```ruby:抜粋
unless @post.tags.empty?
```
これ、postに関連するタグがないかどうかの確認。あればtrue なければfalse

falseのときに

```ruby:抜粋
<% @post.tags.each do |tag| %>
  		<li><%= tag.label %></li>
  	<% end %>
```

１つ１つeachで取得し、表示処理を実施。

# 参考

山田祥寛　Ruby on Rails4 アプリケーションプログラミング　２０１４年４月　技術評論社

http://www.amazon.co.jp/Ruby-Rails-アプリケーションプログラミング-山田-祥寛/dp/4774164100
UbuntuにMySQLを入れる

#対象
* **個人用**RDBMSが必要
* Linuxの操作はまぁそれなり
* phpMyAdminで操作したいんですが？？？
* build-essentialとかはいれてある
* apache2もインストール済み

正直Ubuntuは初期インストール時にLAMPをインストールできるので、MySQLを手で入れたいユーザは多くないと思う。
最近のはやりはMongoDBとかってのもあるし。

あと基本は[ここ](http://qiita.com/kojionilk/items/bdace886c3664d75c5f7)を参照すればいいと思う。
ただPHPMyAdminの設定（というかapahce）だけは間違っている気がするので改めて書いた次第。

#mysqlのインストール
```bash
$ sudo aptitude install -y mysql-server 
```
途中でrootのパスワードを聞いてくるので、適当にパスワードを設定する

#phpmyadminのインストール
```bash
$ sudo aptitude install -y php5-mysql phpmyadmin
```
途中でphpmyadminがphpmyadminのアカウント設定とrootのパスワードをきいてくるので先ほどと同様に適用にいれる。

#phpmyadminにアクセスできるようにする
phpmyadminの設定ファイルを読み込み対象にするのだが、**Ubuntu（っていうかDebian?)にインストールされたApacheはsites-availableとmods-availableに設定ファイルを置き、それをコマンドで有効化する**という作法がある（っぽい）。
また**phpmyadminはモジュールではなくページなのでmodsではなくsitesに設定ファイルを置くべき**(だとおもう）。
[最初に書いた参照元](http://qiita.com/kojionilk/items/bdace886c3664d75c5f7)が間違ってると思った部分はここである。
なんで自分なりに正しいと思う方法を記す。


まずはphpmyadminをインストールした際に作られる設定ファイルを**`sites-available`に配備**する。

```bash
$ sudo ln -s /etc/phpmyadmin/apache.conf /etc/apache2/sites-available/phpmyadmin.conf
```
ここではシンボリックリンクを作成している。

次に、それを有効化する。

```bash
$ sudo a2ensite phpmyadmin.conf
$ sudo service apache2 reload
```
こうすることで、`sites-enabled`にシンボリックリンクが作成され、Apacheが設定ファイルを読み込むようになる。ただしリロードもしくは再起動しないと有効化されないので注意。

#phpmyadminから設定する
`http://サーバのIP/phpmyadmin`にアクセスし、rootでログインしてユーザの作成やらDBの作成やらはphpmyadminからやればOK。デフォルトの文字コードとかも多分phpmyadminでできる
ただしそんな運用はあくまで個人レベルに留めましょう。
プログラマでも必要なプレゼン能力

## 参考動画

もっと伝わるコミュニケーション術 -プレゼン編-

http://schoo.jp/class/2967/room?view=1&token=e3b62800f92813ba6115290ff4d23dc4

上記見て学んだもの
備忘録として、（）内は主観



## (認識していなかった大事なこと)
・プレゼンは、何のためか、何を伝えるか、どうやって伝えるかの3層がある。
・ビジョンは確定しぶれないことが大事→「プレゼン終了後、聴衆にどうなってほしい？」
・プレゼンは相手に行動させるためにするべし（未来を語る）
　→資料は過去のものが多く、「これを聞いたあとに、何をすれば良いのか」が欠けやすい
　→報告であればメールで十分
・プレゼンの「核」は、聴衆がプレゼンの後で、他の人にワンセンテンスで内容を説明出来るもの
　→聴衆がプレゼンの後で、他の人にどうしても教えたくなってしまうもの
・自分ならではの「核」を作ること
・フィラーと呼ばれる口癖には気を付ける。
　→「えーっと」の多用や
　→「基本的に」のあとに続く言葉のほうが複雑な話をしていたり
　→「要するに」のあとのほうが要していない長い話だったり
　→→口癖を気にする余裕を持つ


## (認識していた大事なこと)
・伝達しやすいよう、とにかくシンプルであること
・言葉のバリエーションを増やす
　→「簡単に」という言葉を、「少ないステップで」「ワンクリックで」「この画面だけで」「シンプルに」と



## (難しかったところ)
・アクションを明確にする
　→「誰が、何を、いつまでに」
　→求められる結果、効果を示す
　→「当事者意識」を持たせる表現を使う


## (スライドの作り方で)
・スライドでのアニメーションは、必要以上にはせず、視点誘導に。
・色遣いはシンプルに。（赤や黄色は、警告色でもあるので強い意味合いとして感じられてしまう）
・文字を「閉じ込める」ことでインパクトを増す。→windows 10のタイルアイコンのように
・視点誘導は、→か↓が見やすい。（ピラミッド型など、↑に視点が行く例外ケースもある）
・スライド作成で詰まったら、画像検索をするとイメージが膨らみやすい。英単語だとよりキーワードに近くなる。
・最後に「トドメ」のスライドで印象づけ。
　→時間調整のためや、途中から来た人にも伝えられる。

## (初めて顔を合わせる方へのプレゼン・・)
・ここらは省略・・。
・何もしていない時の手のポジションを決めておく
・口角を下げるのはダメ絶対。
・手の動きは重要

## (面白かった知識)
・ヒトラーはプレゼンがすごくうまい人。「労働者に仕事とパンを」を言い続けた。
　→彼についていくと仕事があり、食事がもらえる状態になる。
Zybo > Link > Digilent > Base System Designなど

ZyboのBase System Designなどのリンク

~~http://www.digilentinc.com/Support/Support.cfm?ProdCat=ZYBO&DocType=~~
もしくは
http://www.digilentinc.com/
から Support を選択、Product Name に Zyboを選択 (ZYまで入力したらZYBOになる)。



他の人のblog記事を見ているとリンクが断絶していた。digilentの方でページ構成を変えたのだろう。
こういうことの対応のためにリンク直接のほかにたどる方法を掲載しておいたほうがいいかもしれない。

<hr>
(2016年6月11日追記)

上記１つ目のリンクはリンク切れになっていた。
以下のリンクを貼っておく。

https://reference.digilentinc.com/zybo:zybo
3次元描画の流れとその知識

# 3次元描画の流れ
３次元描画の流れは、３点座標を持つ対象物を２次元座標の仮想スクリーン上に投影することで描画される。

# 3次元描画の方法の概要
もう少し具体的にいうと、
①描画対象物の頂点の座標を計算する。
②データをピクセルの列に変換する。
③実際に表示する色を計算する。
これらによって、3次元描画ができるようになる

# ①描画対象物の頂点の座標を計算する。
描画対象物は三角形の面をいくつも組み合わせて対象物の形(=ポリゴン)が決まります。
これらの主に座標を計算することを頂点シェーダーという。

# ②データをピクセルの列に変換する。
これらの座標データは3次元での対象物の位置を表現するのに適しているが、
これらの座標データだと実際に描画することはできない。
理由は、画面の表示には、ピクセルの表示を並べることが必要になるからである。
この処理をラスタライズという。

# ③実際に表示する色を計算する。
ピクセルデータが並んだところで、次に色を決める必要がある。
この処理をピクセルシェータという。

# 上記に付随する3d描画に関する内容

パーティクル
人間や犬などはポリゴンで表現することに適していますが、泡や花火などポリゴンで表現するのに適していない対象も存在します＞点(=パーティクル)たちが確率的な挙動によって動くことで、表現ができるようになります。

マテリアルとテクスチャ
マテリアル＞マテリアルを設定すれば、ガラスの質感や、石のようなぼこぼことした質感を表現することができます。
テクスチャ＞テクスチャを設定すれば、例えばphotoshopで作成した絵を組み合わせて新しい3次元画像を表現することができます。

ポリゴンメッシュ
多面体オブジェクトの形状を定義する頂点、辺、面の集合のこと

レンダリング
描画に必要なデータから実際に描画することをいう
なので、①＋②＋③

トランスフォーム
描画対象を変形(移動、回転、伸縮、傾斜)すること。

＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊

レンダリングにおけるポリゴンメッシュとの関連性がいまいちわかっていない＞　next
概要を書いただけ、具体的な方法＞　next 
毎年アメリカでCGの祭典シーグラフというものがあるらしい＞　next
PythonでOpenCVを使う（Windows版）

OpenCV3.1.0が出ていたので、久しぶりに画像解析をやってみました。マシンスペック上の都合と環境に慣れているという理由でWindows環境を使います。
# 環境・ソフトウェアなど
- Windows10（64bit）
- WinPython
    ※Pythonは2.7系を利用。
- OpenCV3.1.0

# 環境構築
## WinPython

WinPythonを使うとWindows上でPython環境をまるっと一式構築できます。Spyderという強力なエディタ（IDE）がついていて、便利なインタラクティブシェル（IPython）があるので初心者でもおすすめ。

ダウンロードは以下のサイトから

http://winpython.sourceforge.net/

今回はPython2.7系を使うんでダウンロードページからWinPython-64bit-2.7.10.3.exe（2016年1月8日時点）をダウンロードします。
32bitを使ってる場合は32bit版を落としましょう。
インストールはインストーラの導く通りに。構築はCドライブ直下に置いとくといいかと思います。。

## OpenCV

公式サイトからダウンロードします。
http://opencv.org/
OpenCV for Windowsを落としてきます。これもインストーラに従って導入。環境はCドライブ直下に格納。

## OpenCVとWinPythonの連携

Pythonでは追加されたモジュールをsite-packageというフォルダ（ディレクトリ）で管理しています。OpenCVのインストールフォルダから必要な管理ファイルをとってきます。

OpenCVをインストールしたフォルダを開き
build→python→2.7の順にフォルダを開いていきます。opencv/build/python/2.7/以下には32bit版と64bit版の二種類の管理ファイルがあります。今回は64bit版を使うので
opencv/build/python/2.7/x64/以下にあるcv2.pydファイルをクリップボードにコピーします。このファイルをWinPythonのモジュール管理フォルダに格納します。

WinPythonをインストールしたフォルダを開き
python-2.7.10.amd64→Lib→site-packageの順に進み、先ほどのcv2.pydを貼り付けます。

これで準備は完了。

# 画像の読み込みと表示

WinPythonのインストールフォルダでSpyderを起動します。
![Spyder.PNG](https://qiita-image-store.s3.amazonaws.com/0/27432/31bf6e70-6d90-15cb-ec42-26d25aa11994.png)

右下にIPythonコンソールがあるので、ここでインストールできてるか確認しましょう。In[1]:のところでcv2モジュールをインポートします。

```py
import cv2
```

エラーが出なければOK。WinPythonの3系をインストールしているとエラーが出てモジュールの読み込みはできません。

ここからcv2を使って画像を読み込んだり、切り出したりをやっていきます。作業フォルダに手ごろな画像を格納しておきます。今回はmusume.jpgを使いました。

```py
import cv2
image = cv2.imread('musume.jpg', 1)
cv2.imshow('musume_photo', image)
cv2.waitKey()
```
これで別ウィンドウが開き写真が表示されます。
cv2.imreadは第一引数に画像のパス、第二引数は0～の数値をとります。0はグレー、1以上で3チャンネルカラー画像になるらしいです。

# 画像の切り出し

なんとなくの使い方が分かったところで今度は画像の切り出しをやってみます。娘の写真から顔の部分だけを取り出します。インタラクティブシェルを使ってテストしながら進めていきます。

```py
import cv2
image = cv2.imread('musume.jpg', 1)
cascade_path =  'C:\opencv\sources\data\haarcascades\haarcascade_frontalface_default.xml'
cascade = cv2.CascadeClassifier(cascade_path)
face_cascade = cascade.detectMultiScale(image, 1.1, 3)
```
OpenCVをインストールすると、正面からの顔を抽出できるXMLファイルが入ってます。ファイルの場所をcascade_pathで指定し分類器に読み込んでいます。
face_cascade以下で使用する画像を分類器に読み込ませ、該当する画像上の位置を取り出しています。face_cascadeを呼び出してみると

```py
print(face_cascade)
```

画像の中で顔と思わしき場所が出力されます。

```py
[[1517 1865   94   94]
 [1114 1762  119  119]
 [1319 1263  118  118]
 [1392  843  863  863]
 [ 964 1590   69   69]
 [1974 1809   73   73]
 [2151 1760   73   73]
 [2112 1764   57   57]
 [1949 1866   72   72]]
```
 
9個顔があるらしい。娘が増えた。
このリストは画像中の顔の位置を示しています。これを使って画像を切り出していきます。

```py
i = 0
for rect in face_cascade:
    x = rect[0]
    y = rect[1]
    w = rect[2]
    h = rect[3]
    img = image[y:y+h, x:x+w]
    cv2.imwrite('musume_face_' + str(i) + '.png', img)
    i += 1
```

さっきの9個のリストを上から順に読み込みます。んで一つづつ画像として保存（cv2.imwrite）します。

![sample.PNG](https://qiita-image-store.s3.amazonaws.com/0/27432/60c15499-3d3c-9b78-af40-d58f733952ee.png)

左上の画像がもともとの写真。顔の抽出もできていますが、なんか3個の点があれば全部顔と認識してるっぽいですね。

この結果を使ってCaffeなんかで学習させると娘を識別させることもできるかも。
cocos2d-jsでproject.jsonを使わずに初期化する

##project.json
cocos2d-jsを使ってみようと[Cocos2d-JS Download Builder](http://www.cocos2d-x.org/filecenter/jsbuilder)からファイルをダウンロードすると、project.jsonというファイルが入っている。中身は

```json:project.json
{
    "debugMode"     : 1,
    "frameRate"     : 60,
    "id"            : "gameCanvas",
    "renderMode"    : 1,
    "jsList"        : []
}
```
こうなっている筈。
調べてみればそれぞれが何の設定なのかは[公式に書いてある](http://www.cocos2d-x.org/docs/tutorial/framework/html5/parkour-game-with-javascript-v3.0/chapter2/en#sample-game-template-code-analysis)のだが、ブラウザゲームを作ろうとした場合、通常は何かしらのサーバサイドのフレームワークと組み合わせることが多く、「エントリーポイントと同一ディレクトリにproject.jsonを置いておく」というのは運用しづらい。直接初期化したいが、その方法は書いていない。

##直接初期化したい
困ったときにはソースコードを見よう。ということでcocos2d-js-v3.8.jsを```project.json```で検索すると、この辺りで読み込みを行っているようだ。

```js:cocos2d-js-v3.8.js
if (document["ccConfig"]) {
    self.config = _init(document["ccConfig"]);
} else {
    try {
        var cocos_script = document.getElementsByTagName('script');
        for(var i=0;i<cocos_script.length;i++){
            var _t = cocos_script[i].getAttribute('cocos');
            if(_t === '' || _t){break;}
        }
        var _src, txt, _resPath;
        if(i < cocos_script.length){
            _src = cocos_script[i].src;
            if(_src){
                _resPath = /(.*)\//.exec(_src)[0];
                cc.loader.resPath = _resPath;
                _src = cc.path.join(_resPath, 'project.json');
            }
            txt = cc.loader._loadTxtSync(_src);
        }
        if(!txt){
            txt = cc.loader._loadTxtSync("project.json");
        }
        var data = JSON.parse(txt);
        self.config = _init(data || {});
    } catch (e) {
        cc.log("Failed to read or parse project.json");
        self.config = _init({});
    }
}
```
これはわかりやすい。```document```に```ccConfig```があればそっちを使うようになっている。

##project.jsonを使わずに初期化
cocos2d-jsの読み込み前に```document.ccConfig```を定義すればよいのだから、エントリーポイントがindex.phpなら

```php:index.php
<script>
document.ccConfig = {
    "debugMode"     : 1,
    "showFPS" : true,
    "frameRate"     : 60,
    "id"            : "gameCanvas",
    "renderMode"    : 0,
    "jsList"        : []
}
</script>
<script src="./cocos2d-js-v3.8.js" charset="UTF-8"></script>
```
こんな感じにすれば良い。
ruby on rails のデータの扱い

# ruby on railsでのデータの取り扱い
ruby on rails では、ActiveRecordクラスがデータベースとモデルのデータの扱いを取り持ってくれる

その中で、データベースとの関係によって、記述が異なってくる

例えば、
Userモデルで
①has_many booksと書けば、ユーザーは複数のbookデータを持つことができる
②has_one bookと書けば、ユーザーは一つのbookデータのみ持つことができる

そして、上記の記述によって、Userモデル内で、Bookテーブルのデータを扱うことができる。
①self.booksと記述することで、そのユーザーのbookのデータを配列でもらうことができる
＞[データ１、データ２、データ３、データ４]

②self.bookと記述することで、そのユーザーのbookデータをもらうことができる
＞データ１

※　①の場合、条件に合うデータ１つのみを抽出したい場合、self.books.where(条件).firstなどととする。もしfirstがなかったら、[データ]などとなって、データとしてではなく配列を取り出すことと同等となる。
予定

#模擬試験調査
　調査済
#1月中旬まで
本ベースでAWSを使い、基礎のおさらい
　使用する本は「Amazon Web Services パターン別構築・運用ガイド 　一番大切な知識と技術が身につく」
##Chapter1 AWSの基本
 読書済み
##Chapter2 AWSを利用する
　読書済み
##Chapter3 パターン別構築例
　読書中
##Chapter4 AWSのセキュリティ
##Chapter5 管理と運用
#1月中旬から3月上旬まで
公式ドキュメント（AWS ホワイトペーパー、AWS ドキュメント、活用資料集など）を読む
また、理解した内容をAWSを使って確認

#3月上旬　
模擬試験を実施し、弱点の把握

#3月上旬から3月下旬
模擬試験の結果の弱点を克服する

#3月27日 
受験
Unity&iOS9&IPv6ネットワークでホスト名のないIPv4アドレスにSocketを使って接続する

**こちらの情報は2016/7/11時点のものです。現在の最新版では状況が変わっている可能性がありますのでご注意ください。**

## 問題
2016/06/01からiOSアプリでのIPv6(NAT64)ネットワーク対応が義務化されましたが、
UnityでSocketを使って下記のようなコードを書いていた場合、NAT64ネットワークで接続に失敗してしまいます。

```csharp
var addresses = Dns.GetHostAddresses(hostnameOrIP);
if (addresses.Length > 0) {
    var address = addresses[0];
    var socket = new Socket(address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
    var endPoint = new IPEndPoint(address, port);
    socket.Connect(endPoint);

    // socketを使った処理...
}
```

このプログラムをNAT64ネットワークで動かしてみると、

- ホスト名を指定した場合（eg. `hostnameOrIP="google.com"`）→ 問題なく動作する
- IPv4アドレスを直接指定した場合（eg. `hostnameOrIP = "216.58.220.206"`）→ エラーが発生する

ホスト名でしかサーバへ接続しない場合は問題ないのですが、いろいろな事情によりホスト名のないサーバへ接続しなければならない場合はなにか対処を行う必要があります。

https://developer.apple.com/library/ios/documentation/NetworkingInternetWeb/Conceptual/NetworkingOverview/UnderstandingandPreparingfortheIPv6Transition/UnderstandingandPreparingfortheIPv6Transition.html

Appleの上記リンクでの説明のよれば`getaddrinfo`関数をを使ってIPv4アドレスからIPv6アドレスをsynthesizeできるとのことです。しかしUnity C#上からはこの関数を直接呼び出すことができません。

## 対処

とりあえずなんらかの方法で`getaddrinfo`関数を呼び出す必要があります。

### 方法1. `getaddrinfo`を呼び出すプラグインを作成する

Forumでプラグインを公開されてる方がいました。

https://community.unity.com/t5/iOS-tvOS/Unity-iOS-and-IPv6-support/m-p/2618073/highlight/true#M213473

これを使うことでC#上から間接的に`getaddrinfo`を呼び出し、IPv6アドレスを得ることができます。

### 方法2. `Dns.GetHostAddresses`の代わりに`Dns.GetHostEntry`や`Dns.GetHostByName`などのメソッドを使う

`Dns.GetHostEntry`や`Dns.GetHostByName`は内部で`getaddrinfo`を呼び出しているため、これらのメソッドを使うことでIPv6アドレスを得ることができます。
ただしこれについては下記のようなリスク・デメリットがあります。

- 公式に保証された動作ではないため将来的に予期せず変更の可能性がある
- `Dns.GetHostEntry`を呼び出すとDNS逆引処理が行われ、不要なオーバーヘッドが発生してしまう
- `Dns.GetHostByName`は現在Obsoleteである

そのため基本的には方法1を使うようにし、方法2については個人での開発でアップデートの予定がないときなど極めて限定的なケースでのみの使用にとどめておいたほうが良さそうです。

### `64:ff9b::/96`をつける方法は駄目
なおMacのインターネット共有機能を使って作成したNAT64ネットワークでは、IPv4アドレスにプレフィックス`64:ff9b::/96`をつける方法でもうまく動作させることができます。
ただしこのプレフィックスはネットワークによっては異なる可能性があり、推奨されていません。

詳しくはApple Developer Forumsの下記ページの#4を参照してください。

https://forums.developer.apple.com/message/136166

## はい

ところでiOS9環境にてC#上でIPv4アドレスからIPv6アドレスへ変換する方法について、Xamarinが何か言ってないか/公式で用意していないかと探したんですが見つけられませんでした。Xamarin.iOSのアプリも`Socket`使っていれば同じような問題に直面すると思うのですがどうなんでしょう？（試してない）（何か情報があれば教えてください）

Xamarinのアップデートで何か対応があったとしても、Unity側でそれが取り込まれるのははるか先のことだと思うのでおそらく意味ないのですが。

## 追記（2016/06/23）

Xamarinより言及がありました。

https://blog.xamarin.com/making-your-ios-apps-ipv6-ready/

……が、言及されているMapToIPv6()が返すのは"IPv4-mapped address"で、Apple指定のNAT64環境で使える"synthesis"されたアドレスとは別のような？ ちょっとよくわからないです。

どちらにしろUnityではMapToIPv6()は使えないのですが。
RICOH THETA S用のnode.jsモジュールを公開しました

# はじめに
表題の通りです。npmに公開しました。
https://www.npmjs.com/package/osc-client-theta_s

と言っても、ゼロから作ったわけではありません。
RICOH THETA S用のAPI（[RICOH THETA API v2](https://developers.theta360.com/ja/docs/v2/api_reference/)）は、Google社の[Open Spherical Camera API Version 1.0（OSC）](https://developers.google.com/streetview/open-spherical-camera/)に準拠していますが、このOSC用のクライアントモジュールは[osc-client](https://www.npmjs.com/package/osc-client)として既に公開されているので、大部分はそれを使っています。

```
npm install osc-client-theta_s
```
でインストールできます。

# 使い方
上記の通り、大部分は[osc-client](https://www.npmjs.com/package/osc-client)をそのまま使っているので、静止画撮影やオプションの取得／設定は[osc-client](https://www.npmjs.com/package/osc-client)と全く同じです。

一方、動画撮影などは[osc-client](https://www.npmjs.com/package/osc-client)にはないTHETA API v2の独自拡張なので、それに対応する形で[osc-client](https://www.npmjs.com/package/osc-client)を拡張して作っています。
使い方は、下記のような手順です。

THETA API v2の独自拡張コマンドは、コマンド名の先頭に"\_"（アンダースコア）が付いていますが、このモジュールのメソッド名には必要ありません。
一方、オプション名前/値は、"\_"をつける必要があります。
ご注意ください。

```
var ThetaSOscClient = require('osc-client-theta_s').ThetaSOscClient;
 
var _thetaClient = new ThetaSOscClient();
var sessionId;

// 動画撮影開始
// 1. セッションIDの取得
// 2. キャプチャモードを「動画」に変更
// 3. 撮影開始
_thetaClient.startSession().then(function(res){
  sessionId = res.body.results.sessionId;
  return _thetaClient.setOptions(_sessionId, {captureMode:"_video"})
}).then(function(res){
  return _thetaClient.startCapture(_sessionId);
}).catch(function (error) {
  console.log(error);
});



// 動画撮影終了
// 1. 撮影終了
// 2. 最新撮影動画の情報を取得
// 3. 動画データの取得
// 4. 動画データの保存
// 5. セッションの終了
_thetaClient.stopCapture(_sessionId)
.then(function(res){
  return _thetaClient.listAll({entryCount:1, sort:"newest"});
}).then(function(res){
  return _thetaClient.getVideo(res.body.results.entries[0], "full");
}).then(function(res){
  fs.writeFile(filename, res.body);
}).then(function(err){
  return client.closeSession(sessionId);
}).catch(function (error) {
  console.log(error);
});
```

# 開発秘話

[osc-client](https://www.npmjs.com/package/osc-client)（というか、その下位モジュールの[superagent](https://www.npmjs.com/package/superagent)）では、バイナリーデータのダウンロードが画像（ContentTypeがimage/***のもの）だけしか対応しておらず、そのままではgetVideoメソッドには対応できませんでした。
なので、このTHETA S用モジュールは、少しトリッキーな方法で動画ダウンロード対応しています。
具体的には、getVideoメソッド開始時に[superagent](https://www.npmjs.com/package/superagent)のprototypeから該当処理を一時的に差し替えています。getVideo終了時に元に戻していますが、もしかしたら、他でも[superagent](https://www.npmjs.com/package/superagent)を使用していた場合、悪影響があるかもしれません。ご注意ください。
Amazone Machine Learningで取引価格予測

Amazon Machine Learningを使って、手軽に機械学習を試してみました。
十分な予測の精度がでたとは言いがたいので、参考までにどうぞ。

## 利用データと目的
データ
・ある商材の2010-2015までの取引データ約4万件
・商材の属性情報は位置情報など含め約20カラム
目的
・先月分までのデータを元にモデルを作成し、今月の取引価格を予測する

## Amazon Machine Learningの基本の流れ
### DataSoucreとML model作成
ダッシュボードから、「Create new...Data Souce and ML model」を選択し、作成を開始します。
データはS3か、Redshiftから投入することができます。

今回は、DBのダンプからcsvを作成し、webコンソールからS3にアップロードし、データを作成しました。
使用するデータを選択すると、各カラムのデータタイプを選択します。

![スクリーンショット 2016-01-10 18.17.53.png](https://qiita-image-store.s3.amazonaws.com/0/66072/cedf3ef8-b4ec-c20e-69f0-627e0c491793.png)

データタイプは
・Binary
・Categorical
・Numeric
・Text
の4種類から選択します
(モデルの精度に関わってくるようです、実際にid値をNumericじゃなくてCategoricalに変更したら精度が上がったりしました。Textがどう使われるかは不明です。。)

予測をするターゲットを選択すると自動的に利用するアルゴリズムが選択されます。
今回はNumericを予測するので、線形回帰が自動選択されました。
![スクリーンショット 2016-01-10 18.30.02.png](https://qiita-image-store.s3.amazonaws.com/0/66072/0b87a835-9843-0ad7-3c18-52b9f4da2257.png)


### Model作成
投入データのうち何％を学習に使い、何％を評価に使うかなど、Modelの設定をすることができます。defaultの設定を使うという選択肢があったので、今回はdefaultでやってみました。

![スクリーンショット 2016-01-10 18.36.49.png](https://qiita-image-store.s3.amazonaws.com/0/66072/0fee9b65-2ce0-d9d3-e8b6-06eb43fe58b6.png)

設定がおわると、モデルの作成が始まります。
投入データ量によるのでしょうが、今回は10分ほどで作成が終わりました。


### Modelの評価
モデルを作成すると、自動的に評価も実行してくれます。
実際の値からの外れ具合をプロットしてくれます
![スクリーンショット 2016-01-10 18.43.51.png](https://qiita-image-store.s3.amazonaws.com/0/66072/ca3c5a70-70b2-69a3-539f-33e3c8106d78.png)


### 予測の実行
1データずつ与える方法（リアルタイム予測）と複数データをバッチで処理する方法（バッチ予測）があります。
今回はバッチ予測を使用しました。
バッチ予測は、S3やRedshiftからのデータをもとにDatasourceを作りそれを使用して予測をするという流れになります。
モデルの作成時に使わなかった今月分の取引データ約1000件をバッチで処理し、
価格を予測しました。

## 結果
実際の取引価格との平均誤差が30%とあまり有用なモデルにはなりませんでした、
一応精度向上に効果があったこととしては、
・DataSource作成時のデータタイプを適切に設定する（id系はnumericじゃなくてclass）
・投入するデータを選定する（取引希望価格が価格予測の参考になるかもと思い、投入してみたことがありましたが、実取引価格のみのほうが精度が高かったです。）
などが有りました。

## 感想
スクリプトを1行も書かなくていいので、手軽に開始するには良いなと思いました。
下に記載しますが料金も手軽で、とりあえずやってみるのには最適化と思います。
一方でちゃんとした精度を出すためには、そもそもアルゴリズムの選定(Amazon Machine Learnigでは対応していないアルゴリズムが多数あります）やパラメータの設定など手がかかりそうだなと思いました。


## （参考）料金
アルゴリズム生成：0.42 USD/時
バッチ予測：予測 1,000 件当たり 0.10 USD
リアルタイム予測：予測 1 件当たり 0.0001 USD
※ご利用の際はAWSの料金説明をご確認ください
Swiftはじめたい...その５ 辞書型


# 今回は辞書型です。
## ふつーに使えそうですね。

```swift:辞書型設定と変更
var dic = ["a":1,"b":2,"c":3]
print(dic)	// ["b": 2, "a": 1, "c": 3]
dic["b"]=4
print(dic) // ["b": 4, "a": 1, "c": 3]
```

+ そのまんまです。

## 変数宣言のみの時は型を明示する。

```swift:型の明示
var dic2 : [String:Int] = [:]
dic2["A"] = 1
dic2["B"] = 2
print(dic2)	// ["B": 2, "A": 1]
```

+ ``var dic2 = [:]``だと型不明なのでエラーになりました。

## 辞書の操作など

```swift:辞書の操作など
// 辞書のキーの数
print(dic.count)    // 3

// 指定の要素のみ削除
dic2["B"] = nil
print(dic2) // ["A": 1]

// ごっそり初期化
dic2 = [:]
print(dic2) // [:]
print(dic2.count) // 0
```

+ 素直に使えると想います。
+ ``dic.count``だかで要素数がわかるのはちょっと便利かも。

## keys

+ keysを試してみます。

```swift:keys
let dic = ["a":1,"b":2,"c":3]
print(dic.keys)
```

+ あれ？配列返ってきませんでした。

```shell:LazyMapCollectionとは?
LazyMapCollection<Dictionary<String, Int>, String>(_base: ["b": 2, "a": 1, "c": 3], _transform: (Function))
```

+ なんだかArrayじゃなくてLazyMapCollection型というのが返ってきました。
+ ソートすると中身だけも取り出せるようです。

```swift:ソートされちゃうけど
print(dic.keys.sort())	// ["a", "b", "c"]
```
+ ...配列で返ってくりゃそれでいいのに...

## values

+ こんどはvaluesを試してみます。

```swift:values
let dic = ["a":1,"b":2,"c":3]
print(dic.values)
print(dic.values.sort())
```

+ keysとおなじくLazyMapCollectionが返ってきました。

```shell:LazyMapCollectionとは?
LazyMapCollection<Dictionary<String, Int>, String>(_base: ["b": 2, "a": 1, "c": 3], _transform: (Function))
[1, 2, 3]
```

+ なんだかkeyだと``<Dictionary<String, Int>, Int>``だったのが``<Dictionary<String, Int>, Int>``になりました。
+ ソートすると中身だけも取り出せるようです。

## 入れ子を試す

+ 辞書の値を配列にしたり辞書にしたりしてみます。

```swift
let dic = ["a":1,"b":2,"c":3]
let arr1 = [1,2,3]
let arr2 = ["a","b","c","d"]
let dic3 = ["a":arr1,"b":arr2,"c":dic]
print(dic3)
```

+ 結果はこんな感じ

```shell:まんまNSDictionaryです。
{
    a =     (
        1,
        2,
        3
    );
    b =     (
        a,
        b,
        c,
        d
    );
    c =     {
        a = 1;
        b = 2;
        c = 3;
    };
}
```

+ これも普通にできますね。表示はNSDictionaryです。

## JSONから辞書に変換とか

+  NSJSONSerialization.dataWithJSONObject()というのを使うらしいのでこれは後で...


## まとめ

+ これも普通に使えそうです。
+ ただし、keysやvaluesではLazyMapCollection型ってのが返ってきました。
+ LazyMapCollection型ってのが宿題になりました。

# 今日はここまで

+ 次回はifとかforとかを試したいと思います。
GitLab7系から8系にあげるときのポイントと、Apacheだとソケットをhttpにしないとハマる話

今回ソースからゴリゴリとインストールをしたGitLab7.2.1を8.3.2にアップデートしたので、その手順と、推奨されているNginxではなくApacheを使っててハマった部分を書く。

## アップデートの概要

大きな変更点として、GitLab8系から、リポジトリ操作をするhttpリクエストはgitlab-workhorse（8.1まではgitlab-git-http-serverという名前）という別のものを利用するようになった。

> GitLab 8.0 released with new looks and integrated CI! | GitLab
> https://about.gitlab.com/2015/09/22/gitlab-8-0-released/

アップデートの手順は[こちら](https://gitlab.com/gitlab-org/gitlab-ce/tree/master/doc/update)にかいてある。8.0に一度上げてから8.3.2にする必要があるので、以下の２つを主に見る。

> doc/update/7.14-to-8.0.md · master · GitLab.org / GitLab Community Edition · GitLab
> https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/update/7.14-to-8.0.md

> doc/update/8.2-to-8.3.md · master · GitLab.org / GitLab Community Edition · GitLab
> https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/update/8.2-to-8.3.md

ただし、8.1から8.2の段階でgitlab-git-http-serverがgitlab-workhorseと名前が変更されているので、このアップデート手順も必ず確認する必要がある。

> doc/update/8.1-to-8.2.md · master · GitLab.org / GitLab Community Edition · GitLab
> https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/update/8.1-to-8.2.md

## ハマった

手順に従ってアップデートしたところ、Webインターフェースはほぼほぼ問題ないが、httpでgit pullとかするときに接続を拒否される。


```
$ git pull origin master
Unable to connect ... connection refused 503（うろ覚え）
```

正しい状態なら、Apacheがリバースプロキシとして127.0.0.1:8181にフォワーディングし、8181ポート待ち受けているgitlab-workhorseがレスポンスを返すはず。
だがログを見るとどうやらgitlab-workhorseが8181番ポートで待ちけていないようだ。

よく読むべきだったのは以下の部分。

> If you are using Apache instead of NGINX please see the updated Apache templates. Also note that because Apache does not support upstreams behind Unix sockets you will need to let gitlab-workhorse listen on a TCP port. You can do this via /etc/default/gitlab.
> https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/update/8.2-to-8.3.md

Apacheだとunixソケットサポートしてないからtcpで受ける必要あって、`/etc/default/gitlab`で治す必要あるよーとのこと。

起動スクリプト`/etc/init.d/gitlab`（手順に従うとただコピーするだけ）のオプションに高書いてある。

```bash:
...（省略）...
gitlab_workhorse_options="-listenUmask 0 -listenNetwork unix -listenAddr $socket_path/gitlab-workhorse.socket -authBackend http://127.0.0.1:8080 -authSocket $rails_socket -documentRoot $app_root/public"
gitlab_workhorse_log="$app_root/log/gitlab-workhorse.log"
shell_path="/bin/bash"

# Read configuration variable file if it is present
test -f /etc/default/gitlab && . /etc/default/gitlab
...（省略）...
```

デフォルトだとunixソケットで待ち受けることとそのファイルパスが書いてある。そしてそれを`/etc/default/gitlab`で上書きしている。

なので該当する部分を以下のようにして、tcpで待ち受けるように書きなおす必要がある。

```bash:/etc/default/gitlab
gitlab_workhorse_options="-listenUmask 0 -listenNetwork tcp -listenAddr localhost:8181 -authBackend http://127.0.0.1:8080 -authSocket $socket_path/gitlab.socket -documentRoot $app_root/public"
```

これで治りました。無事HTTPでも通信が可能に。
アップデート手順にかなりさり気なく書かれていて読み飛ばしてしまっていたのと、具体的な手順が書かれていなかったのでここでかなり時間を時間を使ってしまった・・・。

## 終わりに

UIが大きく変わったのですこし慣れるのに時間がかかるかもしれないが、いろいろとかゆいところに手が届くようになっていまのところ快適です。不具合等が今後出なければいいな。

8系からCIが統合されたりアプリケーション連携が容易になっているようなので、楽しみ。
ImageLayersを使って、DockerHubにサイズのバッジを表示

[ImageLayers](https://imagelayers.io/)でDockerHubのバッジを作れます。
[他の紹介記事](http://qiita.com/DQNEO/items/495ea422b97bd2a734e9)

# やり方
- [ImageLayers](https://imagelayers.io/)にアクセス。
- [Get an Embed Badge]をクリック。
- [Search for an image on the Docker Hub]にイメージ名(例: tsutomu7/jupyter)を入力し、プルダウンから選ぶ。
![image](https://qiita-image-store.s3.amazonaws.com/0/13955/63c48e45-b9a4-ec95-5335-f1a969e69034.png)
- 右のプルダウンからタグ(例: latest)を選ぶ。
- 下の[Copy to Clipboard]を押して、コピーし、好きなところに張り付ける。

![image](https://qiita-image-store.s3.amazonaws.com/0/13955/b3b7d78d-4ee3-922e-ab6a-0bee19bafbce.png)

つけてみました。
https://hub.docker.com/r/tsutomu7/jupyter/

以上