OmniAICreator/Qiita-1.07M huggingface dataset:
HLSLをVulkan向けにSPIR-Vへ変換するには

この記事にかかれていることは2017年12月24日に調べました。  
  
## 結論
　[DirectXShaderCompiler](https://github.com/Microsoft/DirectXShaderCompiler)を使いましょう。SPIR-Vエミッタが実用一歩手前くらいのレベルになっています。
[Googleのfork版](https://github.com/google/DirectXShaderCompiler)を追いかけると楽しいです。

## 導入
　VulkanのシェーダーバイナリはSPIR-V形式です。これはGLSLでシェーダーを記述し、それをSDK同梱のglslang/glslangValidatorを用いることで出力することができます。  

　でもみなさん、HLSLでシェーダー書きたいですよね。  
  
　[hlsl2glsl](https://sourceforge.net/projects/hlsl2glsl/),  [HLSLParser](https://github.com/Thekla/hlslparser),  [HLSLcc](https://github.com/James-Jones/HLSLCrossCompiler) [(Unity版)](https://github.com/Unity-Technologies/HLSLcc) のような、何らかの形でHLSLをGLSLへ変換する手法には多くの実績があります。しかしながら、生成されたコードにかかる最適化が十分でないケースがあるという問題も残されています。 
さらに、これらのソリューションは時代の最先端である[Shader Model 6](https://msdn.microsoft.com/ja-jp/library/windows/desktop/mt733232(v=vs.85).aspx)と[DXIL](https://github.com/Microsoft/DirectXShaderCompiler/blob/master/docs/DXIL.rst)に対応していません。  
  
　その最先端の仕様、つまりShader Model 6のオフィシャルなコンパイラが[DirectXShaderCompiler](https://github.com/Microsoft/DirectXShaderCompiler)です。  

## DirectXShaderCompilerの実装
　LLVM/clangの上に実装されており、このことがShader Model 6以降のHLSLの将来性を約束してくれています。そして、従来のHLSLパーサーを書いていたプログラマを泣かせているものでもあります。  

## SPIR-Vエミッタ
　Googleのエンジニアが中心となってSPIR-Vエミッタを実装しています。[リポジトリはこちら](https://github.com/google/DirectXShaderCompiler)です。
成果は本家DirectXShaderCompilerにも随時反映されています。  
  
少し前まではcbufferすら使えない（コンパイルが通らない）状態だったのですが、[最近](https://github.com/google/DirectXShaderCompiler/commit/1d92f9a1293dac9426a89d2f646e9794a14de2d8)では（私が試した範囲の話ですが）まともに動くようになってきています。  

## おわりに
　かなり端折りました。  
気が向いたら具体的な変換結果を交えたサンプルプログラムを上げます。
gnuplotのforループ　列を使った演算


gnuplot 4.6以降で効率よくプロットするtip

ーーー結論ーーー
```plot for [col=1:5] 'band.dat' using 1:(column(col)-1.121995) w l  lw 2 lc rgb "#ff0000" notitle```
ーーーーーーーー

以前は以下のようにいちいち書いててメンドくさかった。。

```
plot "band.dat" u 1:5 w l lw 2  lc rgb "#ff0000"  notitle , "band.dat" u 1:6 w l lw 2 lc rgb "#ff    0000" notitle, "band.dat" u 1:7 w l  lw 2 lc rgb "#ff0000"  notitle 
```
バージョン4.6以降はfor loopでスッキリ

```
plot for [col=1:5] 'band.dat' using 1:col w l  lw 2 lc rgb "#ff0000" notitle
```
列の演算で```using 1:(col+1)　```だと上手くいかないので調べたところ```column(col)```と書けばよいみたい。

```
plot for [col=1:5] 'band.dat' using 1:(column(col)-1.121995) w l  lw 2 lc rgb "#ff0000" notitle
```

以上、今回の備忘録。

Ref.
https://stackoverflow.com/questions/25380929/loops-in-gnuplot-inside-the-plot-command
robot-detect インストール

#robot-detect install

https://robotattack.org/
https://github.com/robotattackorg/robot-detect
http://blog.differentpla.net/blog/2017/12/13/robot-detect

Pythonモジュールをインストールする際に gcc と関連ライブラリが必要なので事前にインストール

```
yum install -y gcc libmpc libmpc-devel mpfr mpfr-devel
```

IUSリポジトリを追加後、Python関連のrpmをインストール

```
yum install -y https://centos7.iuscommunity.org/ius-release.rpm
yum install -y python34 python34-pip python34-devel
```

pipで必要なモジュールをインストール

```
pip3 install gmpy2 cryptography
```

gitからスクリプトファイルをダウンロード

```
curl -OL https://raw.githubusercontent.com/robotattackorg/robot-detect/master/robot-detect
chmod +x robot-detect
```

TCP fast open を使用していなければコードを書き換える
/proc/sys/net/ipv4/tcp_fastopenファイルの有無で TCP fastopen を使用するかを判定しているが、接続先が使用していなければコネクションエラーが発生するため。

```
vi robot-detect

144行目
# We only enable TCP fast open if the Linux proc interface exists
# enable_fastopen = os.path.exists("/proc/sys/net/ipv4/tcp_fastopen") #コメントアウト
enable_fastopen = False　＃追記
```

実行

```
./robot-detect [hostname] -p [port number]
```
BigQueryのSQL入門 ~データ参照する上で押さえておきたい3つの基本+α~

ペタバイト級のデータでも数分でスキャンができるBigQueryは広告ツール、解析ツール、GEO情報を扱うツールなどいわゆるビッグデータを扱う時によく使われます。
「うちはビッグデータを使ったサービスは今の所ないからいいかなぁ」と思っていたら、アプリ用のGoogleAnalyticsであるFirebase AnalyticsはクエリAPIがなく、BigQuery経由でデータを取るしかない仕様でして、急に向き合う羽目に。。。
各人それぞれ理由はあると思いますが、突然BigQueryを使わなければいけなくなった人のために概要とデータを参照する上での基本をまとめてみました。

## BigQueryの概要
[Tomohiro Shindenさんのスライド](https://www.slideshare.net/newta/bigquery-56438380)がよくまとまっていますので、そちらを参照ください
列指向型のデータベースで、コンテナをどかっと立ち上げて分散してぶん回すのでペタバイト級のデータも数分で処理できるのが特徴です。

## BigQueryでSQLを書く前に知っておきたいこと
### 1. 関数がたくさんある
[BigQuery公式サイト:クエリリファレンス](https://cloud.google.com/bigquery/query-reference?hl=ja)
[BigQuery公式サイト:関数と演算子](https://cloud.google.com/bigquery/sql-reference/functions-and-operators?hl=ja)
上記2つをみていただければわかりますが、関数がたくさんあります。mysqlなどでもよく使う `count`などの他に、数学・分析系の関数やtimestampに関わる関数が充実しており、テーブルワイルドカード関数など独特なものも存在します

### 2. テーブルが分割されている！テーブルワイルドカード関数が必須
BigQueryのテーブルは1日ごとなどでテーブルが分割（シャーディング）されていることが多いです。これはスキャン容量を抑えるためです。firebase analyticsをexportしたデータも日時で分割されていました。
よって、スキャンするテーブルを複数指定する必要があります。その時に使えるのがテーブルワイルドカード関数です。
例えば`TABLE_DATE_RANGE`関数を使って、以下のようなクエリを書くと、`mydata.people20140325`、`mydata.people20140326`、`mydata.people20140327`がスキャン対象範囲になります。

```
SELECT
  name
FROM
  TABLE_DATE_RANGE(mydata.people,
                    TIMESTAMP('2014-03-25'),
                    TIMESTAMP('2014-03-27'))
```

### 3. legacySQLとstandardSQLがあるので、コピペ注意！
何かやりたいことがあるとき、stackoverflowで見つけたコードをコピペすることもあるかと思いますが、それをするとsyntax errorになることがあります。
これは、現状BigQueryがlegacySQLとstandardSQLという二つの構文をサポートしていることが原因です。
例えば、legacySQLではテーブル名を[]で囲いますが、standardSQLでは`で囲います。
詳しいことは [BigQuery公式サイト:標準 SQL への移行](https://cloud.google.com/bigquery/docs/reference/standard-sql/migrating-from-legacy-sql?hl=ja)に載っていますが、一番わかりやすいのがテーブル指定方法変更だと思うので以下に記載しておきます。もはや別物です。

```
# legacySQL
SELECT COUNT(*)
FROM TABLE_QUERY([bigquery-public-data:noaa_gsod],
                 'table_id IN ("gsod2010", "gsod2011")');
# standardSQL
SELECT COUNT(*)
FROM `bigquery-public-data.noaa_gsod.*`
WHERE _TABLE_SUFFIX IN ("gsod2010", "gsod2011");
```

### +α クエリの定期実行はGAS（google apps script）が便利
クエリを定期的に実行したい場合、Google Cloud SDKをセットアップして `bq` コマンドなどを使って行うかと思いますが、SDKのセットアップが結構めんどくさいです。 
最初aws lambdaでやろうとしましたが、sdkのセットアップがめんどくさすぎてやめました。
しかし、BigQueryの定期実行のためだけに、サーバーにsdkいれるのか？という抵抗感もあります。
そこで、提案したいのがGoogle Apps Scriptです。
ヘッダーメニューの　`リソース > Googleの拡張サービス` からBigQueryを有効にすることですぐに使えるようになります。
GASには定期実行の仕組みもついてるので、日時KPIなど取得するくらいならこれで十分です。
![gas.png](https://qiita-image-store.s3.amazonaws.com/0/68146/afc4189c-6feb-4e3b-1d58-a36e6c9a407f.png "gas.png")
![Google拡張サービス.png](https://qiita-image-store.s3.amazonaws.com/0/68146/cdb61a76-d7ab-cd5b-8c87-966f4b6ef220.png "Google拡張サービス.png")


## 最後に
Googleのサービスを使っているといつかはBigQueryを使う場面に直面すると思うので、先に知っておいた方がいいことをまとめてみました。
これから使い始める方の、少しでもお役に立てれば幸いです。
pythonで説明するキャッシュの凄さ

今回のキャッシュとは、再帰計算等を行うときの無駄な計算をpythonに存在するデコレータを使用して簡単に高速化できる、と言ったようなもの。

# キャッシュについて
計算や処理によって出された結果を一時的に保存することをキャッシュという。
そのキャッシュを利用し、同じ結果を2度目以降求める場合は処理をする必要なく、保存した内容をそのまま出す。
それによって同じ処理の複数回実行がなくなり、処理の手間が減ったり、場合によってはインターネットリソースの消費を減らしたり(本記事には出てこない)できる。

# 再帰処理をやってみる
今回はフィボナッチ数列の計算を例に説明する。
数式にすればなんか難しい感じがするが、プログラムでアルゴリズム的に書いてしまえばそれほど難しいものではないので問題ない。

早速だが、フィボナッチ数列をプログラムで書くと以下の様になる。

```py
    def fib(n):
        print(n, end=' ') # 計算を可視化するためのprint
        if n < 2:
            return n
        return fib(n - 1) + fib(n - 2)
```

これを実行してみよう。すると

```py
    fib(8)
    #=>8 7 6 5 4 3 2 1 0 1 2 1 0 3 2 1 0 1 4 3 2 1 0 1 2 1 0 5 4 3 2 1 0 1 2 1 0 3 2 1 0 1 6 5 4 3 2 1 0 1 2 1 0 3 2 1 0 1 4 3 2 1 0 1 2 1 0
```
なんだかいろいろと同じような数字が大量に出力された。
`fib(8)`の値を増やしてみると、もっと凄いことになる。

# フィボナッチ数列をキャッシュで最適化
心配せずとも、全く難しいことはしない。
何故なら、**筆者の頭でそんな難しいことは出来ないからだ。**
以下の2行を、先程のプログラムの先頭に追加するだけ。

```py
    from functools import lru_cache
    @lru_cache(maxsize = None)
```

これでメソッドを実行してみると......

```py
    fib(8)
    #=>8 7 6 5 4 3 2 1 0
```

同じ数字が出力されていない......
`@lru_cache(maxsize = None)`というデコレータをつけることによって、1度実行したメソッドと引数と戻り値をキャッシュし、2度目以降の同じ呼び出しはメソッドを呼び出さずキャッシュを使用する。

# 結果
使いどころを考える必要はあれど、結果を見ただけでそれなりの有用性がありそうだと言うことは分かるだろう。

付け足しではあるが、これによってキャッシュの有用性は理解出来たかと思う。
これ以外もキャッシュには様々な種類が存在し、現在多く使われている。
プロジェクトの規模や速度を求めるなら、やはりキャッシュを使うということは大なり小なり有利に働く(事が多い)。
これを機に、他のキャッシュについても調べてみると良いかも。


# (補足)
個人的に解釈しやすいようにまとめたものの為、簡単な付け足し程度。

### lru_cacheを使用したときの利点
fibを呼び出すときの引数と最終的な戻り値を内部でキャッシュ。
例えば`fib(10)`が何度も呼ばれる環境だとしたら、`fib(10)`を呼び出したときの戻り値をキャッシュしておく。
次に`fib(10)`が呼ばれた時に、前回の戻り値をそのまま返すことで内部で走る何重もの再帰をパスし、関数の呼び出しもパスする。
その結果、同じ処理が多く走る再帰計算などで使用すると圧倒的な速さの処理が可能になる。
最も使われるUNIXコマンドTop15

UNIXコマンド学習者のため(自分も含め)，
[ 50 Most Frequently Used UNIX / Linux Commands (With Examples) ](https://doclegend.com/download/50-most-frequently-used-unix-linux-commands-with-examples_59ddfe1ad64ab2e01dce3eab_pdf)
を参考として，最も使われるUNIXコマンドのTop15をまとめます．

### 1. 圧縮(tar) 
dirnameを名前archive_nameを指定して圧縮ファイルを作成します．
`$ tar cvf archive_name.tar dirname/`
archive_nameを取り除きます．
`$ tar xvf archive_name.tar`
圧縮ファイルの中身を出力させます．
`$ tar tvf archive_name.tar`
### 2. 文字列の検索(grep) 
指定された文字列を探索する(大小文字区別しない)．
`$ grep -i "the" demo_file`
一致した行から3行後まで出力します．
`$ grep -A 3 -i "example" demo_text`
すべてのファイルで指定された文字列を再帰的に検索します．
Search for a given string in all files recursively
`$ grep -r "ramesh" *`
### 3. ファイルの検索(find) 
filenameを使用してファイルを検索します(大小文字区別しない)．
`$ find -iname "MyCProgram.c"`
findコマンドで見つかったファイルに対してコマンドを実行します．
`$ find -iname "MyCProgram.c" -exec md5sum {} \;`
ホームディレクトリ内のすべての空のファイルを検索します．
`$ find ~ -empty`
### 4. リモートログイン(ssh)
リモートホストにログインします．
`$ ssh -l jsmith remotehost.example.com`
sshクライアントをデバッグします．
`$ ssh -v -l jsmith remotehost.example.com`
sshクライアントのバージョンを表示します．
`$ ssh -V`
### 5. ファイル形式の変換(sed)
DOSファイルをUnixにコピーすると、各行の最後に\r\nがあります。 この例では、sedコマンドを使用してDOSファイル形式をUnixファイル形式に変換します。
`$sed 's/.$//' filename`
ファイル内容を逆順に出力する
`$ sed -n '1!G;h;$p' thegeekstuff.txt`
ファイル内の空でないすべての行に行番号を追加する
`$ sed '/./=' thegeekstuff.txt | sed 'N; s/\n/ /'`
### 6.データファイルの処理(awk)
awkを使って重複する行を削除します．
`$ awk '!($0 in array) { array[$0]; print }' temp`
同じuidとgidを持つすべての行を/etc/passwdから出力します．
`$awk -F ':' '$3==$4' passwd.txt`
ファイルから特定のフィールドのみを出力します．
`$ awk '{print $2,$5;}' employee.txt`
### 7. テキストエディタ(vim)
ファイルの143行目に行きます．
`$ vim +143 filename.txt`
最初の指定されたものにマッチングしたところに行きます．
`$ vim +/search-term filename.txt`
読み取り専用モードでファイルを開きます．
`$ vim -R /etc/passwd`
### 8. ファイルの差異の出力(diff)
Ignore white space while comparing.
比較するときに空白を無視します．
`$ diff -w name_list.txt name_list_new.txt`
### 9. ファイルの並び替え(sort)
ファイルを昇順にソートします．
`$ sort names.txt`
ファイルを降順でソートします．
`$ sort -r names.txt`
passwdを3番目のフィールドでソートします．
`$ sort -t: -k 3n /etc/passwd | more`
### 10. 環境変数の定義・リスト表示(export)
Oracle関連の環境変数を表示します．
`$ export | grep ORACLE`
環境変数をエクスポートします．
`$ export ORACLE_HOME=/u01/app/oracle/product/10.2.0`
### 11. 標準入力から生成したコマンドラインの実行(xargs)
すべてのイメージを外付けハードドライブにコピーします．
`$ ls *.jpg | xargs -n1 -i cp {} /external-hard-drive/directory`
システム内のすべてのjpgイメージを検索し、圧縮します．
`$ find / -name *.jpg -type f -print | xargs tar -cvzf images.tar.gz`
urllist.txtファイルに記載されているすべてのURLをダウンロードします．
`$ cat url-list.txt | xargs wget –c`
### 12. ファイルやディレクトリの情報の表示(ls)
ファイルサイズを人間が判読可能な形式（KB、MBなど）で表示します．
`$ ls -lh`
-rw-r----- 1 ramesh team-dev 8.9M Jun 12 15:27 arch-linux.txt.gz
最後の変更時刻に基づいてファイルを並び替えます（逆順）．
`$ ls -ltr`
特殊文字によるファイルを視覚的に分類します．
`$ ls -F`
### 13. 作業ディレクトリの出力(pwd)
`$ pwd`
### 14. ディレクトリの切り替え(cd)
"shopt s cdspell"は自動的に誤ったディレクトリ名を修正できます．
### 15. (gzip)
*.gz圧縮ファイルを作成します
`$ gzip test.txt`
*.gzファイルを解凍します．
`$ gzip -d test.txt.gz`
圧縮ファイルの圧縮率の表示します．
`$ gzip -l *.gz`
Visual Studio for MacのソリューションをFinderから新規ウィンドウで開くスクリプトを書いてみた

## はじめに

t-miyakeさんの[Visual Studio for Macで簡単に複数ウインドウを開けるようにする](https://qiita.com/t-miyake/items/b4e4b0c8a9264ea4be6c)を見て，もっと簡単にできないかなぁ，もしかしたらコンテキストメニューのサービス化してしまえば簡単なんじゃないかなぁと思ったので作ってみました．

## 作り方

### Automatorからサービスを作成する

ApplicationからAutomatorを開き，新規から"サービス"を選択します．

<img width="500" alt="スクリーンショット 2017-12-28 0.05.12.png" src="https://qiita-image-store.s3.amazonaws.com/0/104085/f4e3a4ad-6279-762a-8097-64e3cc7def74.png">

### コンテキストの対象を設定する

slnファイルのようなファイルを対象としたときにコンテキストメニューが表れてほしいので，対象を ファイルまたはフォルダ に設定し，検索対象をFinderに設定します．

<img width="620" alt="スクリーンショット 2017-12-28 0.07.14.png" src="https://qiita-image-store.s3.amazonaws.com/0/104085/99cc8c9b-8f2c-a2a2-a645-47071d901a3a.png">

### アクションを指定する

今回は簡単にダイアログが表示できるAppleScriptを使ってみましょう．

<img width="380" alt="スクリーンショット 2017-12-28 0.12.33.png" src="https://qiita-image-store.s3.amazonaws.com/0/104085/9e67e655-08a6-e423-38ae-35a48834aeb0.png">


### コードを書く

Apple Scriptを初めて触った人間のコードなのでひどいですが，こんな感じのものを書きます．

```applescript
on run {input, parameters}
	set theDialogText to "Open in a new window?"
	display dialog theDialogText
	set button_result to result
	set file_path to quoted form of POSIX path of input as string
	
	if (button returned of button_result) as text = "OK" then
		set scr to "open -n " & file_path
		do shell script scr
	end if
	
	return input
end run
```

もう新しいウィンドウで最初っから開く気があるのでdisplay関連は正直いらない気がします（

### 保存していい感じの名前をつける

ここで保存したファイルの名前がコンテキストメニューに表示されます．
私は"新しいウィンドウで開く"みたいにしてみました．

## 出来たもの

![open_newwindow.gif](https://qiita-image-store.s3.amazonaws.com/0/104085/fdd7e5d4-eb8a-296a-ed16-786e8031c9ad.gif)

上のgifのように，Finderからソリューションファイルを右クリして，コンテキストメニューから"新しいウィンドウで開く"をクリックするだけで新規ウィンドウでVisual Studio for Macを開くことが出来ました．

## まとめ

* Automatorでサービス化すればアプリケーションの不満点を補い使うことが出来る
* スクリプト内で使った `open -n`が実際最強
CoreOSにdocker-composeをインストール

```
cd /tmp/
wget https://github.com/docker/compose/releases/download/1.18.0/docker-compose-Linux-x86_64
mkdir -p /opt/bin
mv docker-compose-Linux-x86_64 /opt/bin/docker-compose
chmod 755 /opt/bin/docker-compose
```

TODO：パスを通す
【VRTK x PUN x Vive】Transformを同期させたい


## 前提
Viveは一台のみ。PC1はViveに接続してSteamVR SDKを使用、PC2は何も接続せずにSimulator SDKを使用する。

## 目的
CameraRigのTransformを同期させたい。
SDKのスイッチは自動的に行いたい。

## 問題
[【PUN】アバター生成・同期](https://qiita.com/mo4_9/items/75324cc31709ec329d26)で、Avatarを同期させようとしたらうまくいかなかった。

SteamVRの[CameraRig]の子要素にAvatarを生成しても、Transformは0のまま。そりゃそうだ、動いているのは[CameraRig]だから。

しかし[CameraRig]にPhotonViewをつけてPhotonNetwork.Instantiateに渡すわけにはいかない。シーンに複数カメラが存在してしまうし、SDKの自動スイッチを使えなくなるのもつらい。

## 解決

似たような問題に直面している人を発見！
でもコレじゃない感が。。。
[Spawn / Sync existing game object (Player)?](https://forum.photonengine.com/discussion/10097/spawn-sync-existing-game-object-player)

デモがあった！
[PlayoVR, a VRTK-PUN-Voice Demo](https://github.com/quintesse/PlayoVR)
こちらのコードを拝借してうまくいったので、ざっくり解説。

一言で言うと __Avatarはヒエラルキーの直下に生成して、CameraRigのTransformをAvatarにリンクさせる__方法。

`AvatarCameraRigSync.cs`でアバターのHead, LeftHand, RightHandを設定する。内部ではアクティブなCameraRigにリンク用のコンポーネント(`PhotonViewLink `)をアタッチして、`photonView.isMine`で自分のアバターのみに紐づけている(`VRTK_TransformFollow `)。
Amazon Linux にNode-REDを入れる手順

#あえてのAmazon Linux
IoTやデータ連携でお馴染みになった「Node-RED」、チュートリアルではAWS上ではUbuntu Serverを使用する方法が紹介されています。AWSなので、Amazon Linux上にNode-REDを入れる手順を確認しましたので書き記しておきます。
EC2上のAmazon Linuxを使う理由は、独自にシェルスクリプトやPythonで作ったプログラムをNode-REDで呼び出したり、API Gateway以外のトリガーを使用したいためです。


#導入手順

EC2で、t2.microまたはt2.smallでインスタンスを作成します。Amazon Linux AMI 2017.09.1 (HVM), SSD Volume Type - ami-da9e2cbcを使用しました。セキュリティグループでは、ポート 1880を開放します。Node-REDは、ポート1880を利用します。
ユーザー名 ec2-userでSSH接続後、下記コマンドを実行していきます。

```
$ sudo su

# yum update && yum upgrade
# curl -sL https://rpm.nodesource.com/setup_8.x | bash -
# yum install nodejs
# npm install -g --unsafe-perm node-red
```

この時点でNode-REDを起動することができました。EC2のパブリック DNS (IPv4)に、:1880をつけてアクセスすればNode-REDが起動しますが、ログイン機能が有効になっていません。このままでは外から丸見えです。

次は、ログイン機能を有効にします。

```
# nano /usr/lib/node_modules/node-red/settings.js
```   
adminAuth のコメントを解除し、認証機能を使用可能にします。
デフォルトのユーザー名は、admin。パスワードはハッシュ化されており、デフォルトは、password です。変更するには、[公式サイトのSecurity](https://nodered.org/docs/security)のページを確認してください。

#自動化
サーバー再起動時にNode-REDを自動起動させるために、PM2をインストールします。
下記を実行することで、再起動時にNode-REDが自動起動し、EC2のパブリック DNS (IPv4)に、:1880をつけてアクセス可能です。

```
# npm install -g pm2
# exit

$ pm2 start /usr/bin/node-red
$ pm2 startup amazon
[PM2] To setup the Startup Script, copy/paste the following command:
sudo env PATH=$PATH:/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup amazon -u ec2-user --hp /home/ec2-user

$ sudo env PATH=$PATH:/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup amazon -u ec2-user --hp /home/ec2-user
$ pm2 save

```

#Node-REDログイン
EC2のパブリック DNS (IPv4)に、:1880をつけてアクセスすると、Node-REDのログイン画面が表示されます。
先ほど、adminAuthで設定したユーザー名とパスワードでログインします。
![node-red_login.PNG](https://qiita-image-store.s3.amazonaws.com/0/41414/8cfd1edd-dc75-4052-9ab2-b88d66e2cd8a.png)

ログイン後、何も無いNode-REDのフロー定義画面が表示されますので、フローを作り、画面右上の「デプロイ」を実行することで、フローが作動します。デプロイすればNode-REDの画面が閉じていてもフローは動作し続けます。

たとえば、以下はオープンソースマーケティングオートメーション Mauticで新規顧客が登録されたときにWebhookを使ってSlack通知するフローです。[こちらの記事](https://qiita.com/kolinz/items/605c685603dea73a49ce)にサンプルがあります。
![node-red_mautic2slack.PNG](https://qiita-image-store.s3.amazonaws.com/0/41414/522ebe0f-1fc8-85bd-4ae8-4a857546adb7.png)

# ノードの追加
Node-REDは、画面左側のメニューにあるノードと呼ばれる箱を配置することでフローを定義し、Slack通知のようなデータ連携やIoTデバイスのデータを呼び出すことができます。
ノードの追加は、画面右上の「三」→「パレットの管理」→「ノードを追加」にて、ノードを検索、検索後「ノードを追加」をクリックすると追加できます。
もしくは、SSH接続し、npm install でも追加可能です。

確認できたノード

- iont-node-red-contrib-aws-iot-hub
    - AWS IoTと接続し、読み書きするためのノード
- node-red-contrib-ibm-watson-iot
    - IBM Watson IoT Platformと接続
- node-red-node-watson
    - IBM CloudのWatsonサービスを呼び出す
- node-red-contrib-slack
    - Slackとの連携
- node-red-contrib-play-audio
    - Webブラウザ経由で音声データの読み上げ
- node-red-contrib-browser-utils
    - Webブラウザ経由でマイクが使用可能

[Node-RED Library](https://flows.nodered.org) からノードやサンプルフローを検索することもできます。

#まとめ
Node-REDはNode.js上でどこでも動かせるのが強み。ということで、IBM Cloud以外、AWSでも容易に動かすことができます。ビジネスでデータ連携を行う場合、何度も試行錯誤を繰り返しますし、その度にスクリプトやプログラムを作り直すことは非現実的です。
Node-REDを使うことで何度もトライし、データ連携やIoTデバイスとの連携を行うことができます。
ブランチを切り替えずにfast-forwardマージする


複数人開発中にremoteで進んだブランチにHEADを切り替えずにfast-forwardマージしたかったけど，
やり方がわからなかったので無理やり実行した話．

~~コマンド知ってる人教えてください．~~

----
# gitコマンド
コメントでコマンド教えてもらいました．

`$ git fetch github develop:develop`


----

# やりたいこと

![スクリーンショット 2017-12-27 17.10.16.png](https://qiita-image-store.s3.amazonaws.com/0/58048/e7935275-600d-00a3-a68f-209cb86e0533.png "スクリーンショット 2017-12-27 17.10.16.png")

こんな感じでremoteの `develop` ブランチがコミットされたのでlocalの `develop` ブランチをfast-forwordマージしたい．
でも今は別のブランチで作業中なので，ブランチの切り替えはしたくない．
fast-forwardマージはマージ時に新しいコミットを作らず，ブランチのポインタの移動だけを行っているはずなので，
どうにかして `develop`ブランチ（図の青色の矢印）を指しているポインタを`github/develop`ブランチ（図の赤色の矢印）に移動させたい．


# やったこと

git関連のファイルはリポジトリ内の `.git` ディレクトリ以下にある．
ブランチの位置はこの中の `refs` ディレクトリで管理されている．
`refs`ディレクトリの構成はこんな感じ．

```bash
$ tree . 
 .
├── heads
│   ├── develop
│   ├── feature
│   │   ├── admin_faq
│   │   └── admin_car_option
│   └── master
├── remotes
│   └── github
│       ├── develop
│       ├── feature
│       │   ├── admin_faq
│       │   └── admin_car_option
│       └── selling-car-api
└── tags
```

gitのブランチに対応するファイルがある．
ファイルの中身は以下のような感じでコミットのSHA-1が保存されている．

```bash
$ cat refs/heads/develop
fe98e89d39747474e969131dac97bbb0dfe9427f
```

`github/develop` と同じ所を指すようにすればいいので
`heads/develop` ファイルを `remotes/github/develop` ファイルで上書き．

```bash
cp refs/remotes/github/develop refs/heads/develop
```

無事同じ位置に移動されました．
![Kobito.cvgrv0.png](https://qiita-image-store.s3.amazonaws.com/0/58048/f63dd1f7-5ecc-c4f8-ed60-f368a66855e0.png "Kobito.cvgrv0.png")
音声認識API　料金比較

なにをするにもまずは料金から。
個人でも、使えるかどうか調べてみた。
（20171228現在の情報。料金例は実際の請求料金と異なる可能性あります。）

#4大API情報
巨人の肩に乗りたい。
##google Cloud Platform
[Speech API 料金情報含む](https://cloud.google.com/speech/)
まずはgoogleが提供するSeech API。
###料金体系
| 時間       |       料金 |
|:-----------------|:-----------------:|
| 最初の60min      |           無料 |
|以後|0.006$/15sec|

##IBM
[IBM watson speech to text](https://www.ibm.com/watson/services/speech-to-text/#pricing-block)

###料金体系
| 時間       |       料金 |
|:-----------------|:-----------------:|
| 最初の1000min      |           無料 |
|1001minから250,000min|0.02$/min|
|250,001minから500,000min|0.015$/min|
|500,000minから1,000,000min|0.0125$/min|
|1,000,000min以後|0.01$/min|

##AWS
[AWS transcribe 料金](https://aws.amazon.com/jp/transcribe/pricing/)

###料金体系
| 時間       |       料金 |
|:-----------------|:-----------------:|
| 最初の60min      |           無料(利用開始の12か月間) |
|以後|0.0004$/sec|

##Microsoft
[Azure Bing Speech API 料金](https://azure.microsoft.com/ja-jp/pricing/details/cognitive-services/speech-api/)

###料金体系
| 時間       |       料金 |
|:-----------------|:-----------------:|
| 最初の5000トランザクション      |           無料 |
|以後|4$/1000トランザクション|
1トランザクションは最大15秒の音声データのリクエストの事のようです。

###料金体系2
比較のため、アプリにおいて1トランザクションあたり平均で12秒音声を詰め込めると仮定。

| 時間       |       料金 |
|:-----------------|:-----------------:|
| 最初の1000min      |           無料 |
|以後|4$/200min|

#結局いくらくらいかシミュレーション
(単位:$)

| 時間      |    Google |IBM|AWS|MS|
|:---------|:---------|:-----|:-----|:-----|
|  1,000     |    23 |     0|23| 0 |
|100,000      |    2,399 |   1,980|2,399|594|
|1,000,000      |    23,999 |   14,980|23,999|5,994   |
| 10,000,000      |    239,999 |   104,980| 239,999|59,994|

#まとめ
あくまで料金のみについて、

- ユーザー数が少ないチャレンジフェーズでは無料枠が大きいIBMかMS、
- 規模が大きくなってくるとMS、
- GoogleとAWSは料金に大差ないだろう

- ただし、MSはトランザクション単位の課金なのでアプリで1トランザクション15secをどれだけ有効に使えるかがポイントだと思われます。

以上！私はまずMSにトライしてみようとおもいます。
rails学習・・・これにピンとこなきゃ、出直しな・・・(学習中に出てくる障壁)


今現在、学習している人の為、これからやろうと思っている人の為言っておこう。
これにピンとこなきゃ、出直しな・・・

#**テーブル、フィールド、主キー、リレーション**
リレーショナルデータベースに関係する単語・・・ほぼ間違いなく、アプリを作るならデータベースが必要になるわけで。悪いことは言わない・・・出直そう。

#**\<h1>,属性,タグ**
HTMLに関係する単語・・・いや私も全然知らなかったよ・・・でも絶対必要だ。だってwebは全部HTMLで表現されているんだ・・・悪いことは言わない・・・出直そう。

#**シンボル、ハッシュ、メソッド**
汗・・・全然わからん。そもそもRubyを知らんからな　笑
railsはRubyで書くから、そもそも基本構文とか、言語の思想が分かってないと、つらすぎる。
悪いことはいわない。・・・出直そう。

#対策
一歩ずつ焦らず行こうよ。って言い聞かせてる・・・・
⇒出直すってそんな悪い事じゃないよね・・・毎回新しい知識が増えていくし。
回り道してもいいからわからんことが出たらそのたびに調べること。その時にググるのはある意味で正解だけど、情報は選ばなきゃいけない。有名なサイトでＱ＆Ａみたいな形式があるけど、回答者が必ずしも正しいことを言っているわけじゃなかったりする。それは環境によって生じる問題だったり、バージョンによるものだったり単にタイプミスの時だってある。**解決できればラッキー**ぐらいに考えておいて、ほかの方法も持ってないときつい。**公式ドキュメントは基本**だなって感じてる。**英語**だけどね!!笑。でも**避けて通れない・・・**いずれ頼ることになる。
それと先駆者たちが残してくれた情報。これはほんとにありがたい。
よくある〇〇入門とかいうサイトは、入り口としてはとても助かる。でも一つのサイトの情報を鵜呑みにして間違ったこと覚えたりするから、よーく**見比べる**と間違いが入り込まなくて済むかな。

まあ・・・悪いことはいわない・・・出直そうよ・・・
RxJava2 の disposable の管理をいともたやすく行うための LifecycleObserver を実装した Delegate 用クラス

https://gist.github.com/shikajiro/13d8104683e8db2f7a4c6178e8775e73

RxJava での subscribe の管理ってまじ大変ですよね。CompositeDisposable を使うと思うのですが、Activityのソースがその処理ばかりになって読みづらくなりますよね。

そこで、[KotlinでAndroidのRxJavaをちょっと便利に \- Qiita](https://qiita.com/boohbah/items/c18b74b7bfe72c1e3aa9) を参考に AutoUnSubscribable を使うと思うのですが、 onResume onPause の呼び出しを忘れがちだったりしますよね。よね。

んで最近 Android Architecture Component が出てきて LifecycleObserver を使えばライフサイクルを簡単に管理できるようになりました。

これらを組み合わせて、RxJava2 の disposable の管理をいともたやすく行うための LifecycleObserver を実装した Delegate 用クラスを作りました。

RxJava2慣れてなくて自信が無いのでだれかなじってください。
修正すると思うので gist の方を信じてください。

[RxJava2LifecycleObserver.kt](https://gist.github.com/shikajiro/13d8104683e8db2f7a4c6178e8775e73)

```kotlin
/* Interface is necessary for Delegate */
interface RxJava2LifecycleDelegate {
  fun Disposable.autoDispose(): Disposable
  fun Lifecycle.setupRxJava2Observer(func: () -> Unit)
}

/* Class for Delegate implementing LifecycleObserver */
class RxJava2LifecycleDelegateImpl : RxJava2LifecycleDelegate {
  private var composite = CompositeDisposable()

  /**
   * Extension function for registering LifecycleObserver and subscribe method
   * @func: This lambda calls subscription processing
   */
  override fun Lifecycle.setupRxJava2Observer(func: () -> Unit) {
    addObserver(RxJava2LifecycleObserver(composite, func))
  }

  private fun check() {
    if (composite.isDisposed) {
      composite = CompositeDisposable()
    }
  }

  /* Extension function for composite management of Disposable  */
  override fun Disposable.autoDispose(): Disposable {
    check()
    composite.add(this)
    return this
  }
}

class RxJava2LifecycleObserver(private val composite: CompositeDisposable,
                               private val subscribeCallback: () -> Unit)
  : LifecycleObserver {

  /* It is automatically called at onResume timing and sets up subscription processing. */
  @OnLifecycleEvent(Lifecycle.Event.ON_START)
  fun subscribe() {
    subscribeCallback()
  }

  /* It is automatically called at the timing of onPause and releases subscription processing. */
  @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
  fun dispose() {
    composite.dispose()
  }
}
```

上記のクラスを使った実装例

```kotlin
/* Example Implementation */
class ExampleActivity : AppCompatActivity(), RxJava2LifecycleDelegate by RxJava2LifecycleDelegateImpl() {

  override fun onCreate(savedInstanceState: Bundle?) {
    ...
    // Register the Observer to subscribe onResume and dispose with onPause
    lifecycle. setupRxJava2Observer(this::subscribes)
  }
  
  /* subscribe method */
  private fun subscribes() {
    //subscribe example
    vm.progress.subscribe {
      if (it) showProgress() else dismissProgress()
    }.autoDispose() //Monitor disposable
   ...
  }
}
```
Xcode SceneKitとTinkercadの座標対応

#課題
Tinkercadで作成した3Dモデルをstlでexportし、Matchintosh SceneKitに取り込むと座標系が合わない

#座標系の対応
対応関係は次の通り。Tinkercadで作成したモデルをSceneKitのx軸周りに-90度回転させると面の位置関係が一致する。Tinkercadでモデルを作るときにあらかじめ考慮しておくことが望ましい。
また、TinkercadのWorkplaneの中心位置が、SCNNodeのpivotの初期値になる。

| SceneKit  |Tinkercad|
|-----------|---------|
| Front (y) |Top      |
| Right (x) |Right    |
| Top   (z) |Back     |

<img width="762" alt="scenekit.png" src="https://qiita-image-store.s3.amazonaws.com/0/187104/dc11c96c-f974-1043-03e5-40ea78a8dfc7.png">
SceneKit

<img width="556" alt="tinkercad.png" src="https://qiita-image-store.s3.amazonaws.com/0/187104/1e7ecb1f-e0d8-a2a8-78fd-f31fab806542.png">
Tinkercad
（RGBの矢印はSceneKitとの対応を表すために追記しました）
OneNoteにCOMアドインを追加する

OneNoteを使って高度なことをしたいが、諸事情によりOnetasticが使えない。
ちょっとググった感じVSTOも対応していないっぽい。
そんな時はファイルタブ＞オプション＞アドイン　から自作COMアドインを追加するしかない。しかし、COMアドインの追加方法に関してググっても見つからず嵌った。解決方法を記録しておく。
**まぁ、結構ググっても出てこない感じ需要がない気もするが、、、**

# 導入
[このサイト](http://artfulplace.hatenablog.com/entry/2015/09/08/151205)にOneNoteのCOMアドインの詳しい説明が書かれている。
しかし、実際どのように公開するかの方法が書かれていない泣
(GitHubのプロジェクトでは*.vdprojをデバッグして実行すればおkとか書いてあるけどVS２０１０までしか対応してないらしいし開けすらしなかった)

# ゴール
[このサイト](https://social.msdn.microsoft.com/Forums/office/en-US/3570a4cf-aec1-4ff7-8547-e40bf8816dd0/onenote-programming?forum=appsforoffice)の手順でCOMアドインの追加が可能な状態にする。
ソースコードはhttps://skydrive.live.com/redir?resid=99C161754C5A699%21505
からダウンロード**（クリックすると勝手にダウンロードが始まるので注意）**。

# 環境
Windows 10 Pro
Visual Studio 2015 express
OneNote2016

# ステップ１〜Regasm.exeでdllをCOMコンポーネントとして登録〜
* "C:\Windows\WinSxS\amd64_regasm_b03f5f7f11d50a3a_4.0.14320.17035_none_373bc35825466c51\RegAsm.exe" /codebase OneNote2013AddIn.dll(※注)上記ソースコードをVSからビルドした時にできたdllのフルパス

* 署名がないので怒られる

# ステップ２〜署名して検証を突破〜
* プロジェクトのプロパティを開く
* 署名タブを開く
* アセンブリ署名をするにチェック
* キーファイルを新規作成する
* ビルドする
Sn.exeから署名検証をかっ飛ばそうとするも失敗。
おとなしく.snkを作成しました。
完了後、ステップ１を流すと無事に成功するはず。

# ステップ３〜レジストリを書き換える〜
* 導入で紹介したURLでの手順に従い、レジストリを登録。
* OneNoteからアドイン追加画面にいくとＣＯＭアドインが追加できるようになっている。

# 最後に
「EXCEL　COMアドイン　追加」のキーワードでググれば一発だった
ググる力とWindowsに関する基礎知識が足りてないのを実感しました泣
C#を使ってのOneNoteのCOMアドインの開発についてもゆくゆくまとめたいな
OneNote APIも早く触りたい

# 追記
勉強を進めるうちに気付いたけど、タイトルが間違ってるような気がします。
「COMのデプロイ方法（OneNoteアドインを例として）」が正しいです。


# 参考
* http://tech.nitoyon.com/ja/blog/2008/07/31/c-sharp-com/
goのversion管理について

この記事はSmartDrive Advent Calendar 2017の8日目の記事です。

バックエンドのエンジニアをしております @astronoka です。
golang を使った時系列データの解析について書こうとおもったのですが、まとまらず。。
自分の昔書いた記事の焼き直しでお茶を濁そうとおもいます。。


弊社ではgolangで書かれたプログラムのビルドはdockerコンテナを使っております。
そして、クロスコンパイルした成果物のバイナリ１個を、aplineのコンテナに放り込んで動かすというよく見かけるやつです。
開発中もコンテナの中で　[reflex](https://github.com/cespare/reflex)　をつかうことで
エディタさえあればなんとかなる状態ではあります。

でも

`delve`とか使いたいですよね、、 `GoLand`とか使いたいですよね、、
やはり、macにgolangをインストールすることになります。
そこで自分は下記のようなツールを作って環境を管理しています。

https://github.com/astronoka/glen

名前は　`Plan 9`　にかぶれて、エド・ウッドの[映画](https://www.allmovie.com/movie/v19952) から取ったのと
`GoLang ENvironment manager` をかけています。


使い方は下記の通り


# install

``` bash
$ git clone https://github.com/astronoka/glen.git ~/.glen

# PATHが通っているところにおく
$ ln -s ~/.glen/glen.sh ~/bin/glen

$ glen version
0.２.0
```

# usage

``` bash
$ glen help

Usage: glen <cmd>

Commands:

version                         Print glen version
help                            Output help text
install <version>               Install the version passed (ex: go1.5.3)
uninstall <version>             Delete the install for <version>
use <version>                   Activate specified <version>
list                            List installed versions
tags                            List available versions (tags)

env list                        List environments
env create <envname> <version>  Create environment
env delete <envname>            Delete environment
env use    <envname>            Activate environment

vendor init <version>           Initialize current directory as workspace
vendor use                      Activate current directory as workspace

tools                           Install develop tools (goimports,gorename...)
```

# 例

``` bash
# 使えるバージョン(タグ)を確認
# リポジトリをクローンするのでちょっと時間がかかります。
$ glen tags
  ... 
go1.8rc3
go1.9
go1.9.1
go1.9.2
go1.9beta1
go1.9beta2
go1.9rc1
go1.9rc2

# 適当なバージョンをインストールする
$ glen install go1.9.2
######################################################################## 100.0%
installed from binary
successfully installed: go1.9.2

# インストールされたのを確認
$ glen list
go1.9.2

# GOPATHを通す (あたらしくシェルを立ち上げています)
$ glen use go1.9.2

# .glenの下に配置されています
(glen:go1.9.2)　$ echo $GOPATH
/Users/astronoka/.glen/installed/go1.9.2/glen

# exit で抜けると、当然ながら$GOPATHはなくなります
(glen:go1.9.2)　$ exit
$

# 続いて環境を用意してみます

# 環境一覧
$ glen env list

# 導入済みのversionで環境を用意します
$ glen env create foo go1.9.2

# foo ができる
$ glen env list
foo

# 環境を有効化する
$ glen env use foo

# goのバイナリパスはこの辺
(foo:go1.９.2) $ type go
go is /Users/astronoka/.glen/installed/go1.9.2/bin/go

# $GOPATH は .glen の下に配置されます。
(foo:go1.9.2) $ echo $GOPATH
/Users/astronoka/.glen/env/foo

# vendor サブコマンドは、作ってみたものの使いみちがなかったので使い方は省略します。
```

これで好きなだけ沢山のバージョンを入れて、好きなだけ環境を作って開発ができますやったね！

しかしこうも思うのです。
そんなに複数のversionが入り乱れた状態を保守するのは嫌だと。

完


----

環境情報

```
$ sw_vers
ProductName:	Mac OS X
ProductVersion:	10.11.6
BuildVersion:	15G1217
```
(うわっ…私のMacOS Version低すぎ…?)
IE11でblobがダウンロードできないの回避


`window.navigator.msSaveBlob `を見てあげる。
あったらIE11？


```javascript
		var file_data_uint8 = new Uint8Array(file_data);
		var blob = new Blob([file_data_uint8.buffer], { type: "application/zip" });
		var url = window.URL.createObjectURL(blob);
        var a = $('<a>').attr({href:url, download:name}).text(name);
```

aタグとURL作成したところIE11が反応しないので下記追加してあげる

```javascript
		a.click(function(){
			if(window.navigator.msSaveBlob){
				console.log('IE11?');
				window.navigator.msSaveBlob(blob, name);
		  }
        }
```

おまけ　file_dataデータがbase64の場合の変換

```javascript
// base64 -> url || blob
function base642url(base64, opt){
	opt = opt ? opt : {type:'url'};
	var type = base64.match(/^data:(.*);base64,/, function(){return RegExp.$1;})[1];
	var bin  = atob(base64.replace(/^.*,/, ''));
	var ary  = new Uint8Array(bin.length);
	for (var i = 0; i < bin.length; i++) {
		ary[i] = bin.charCodeAt(i);
	}
	var blob = new Blob([ary.buffer], {type:type});
	var url  = window.URL.createObjectURL(blob);
	if(opt.type == 'blob') return blob;
	return url;
}
```
CoreOSのStorage Driverをdevicemapperに変更する

## 経緯

CoreOSのデフォルトのStorage Driverはoverlayですが、最近、overlayだとmysqlが起動しなくなったので、Storage Driverを変更することにしました。

## 手順

以下のツールを実行し、CoreOSで利用できるStorage Driverを探します。
https://github.com/docker/docker/blob/master/contrib/check-config.sh 

```
...
- Storage Drivers:
  - "aufs":
    - CONFIG_AUFS_FS: missing
  - "btrfs":
    - CONFIG_BTRFS_FS: enabled (as module)
    - CONFIG_BTRFS_FS_POSIX_ACL: enabled
  - "devicemapper":
    - CONFIG_BLK_DEV_DM: enabled (as module)
    - CONFIG_DM_THIN_PROVISIONING: enabled (as module)
  - "overlay":
    - CONFIG_OVERLAY_FS: enabled (as module)
  - "zfs":
    - /dev/zfs: missing
    - zfs command: missing
    - zpool command: missing
...
```
aufs、devicemapperならMySQLが起動するという情報がありましたが、CoreOSはaufsをサポートしていないので、devicemapperを利用することにしました。

cloud-config.ymlで以下のように設定します

```
coreos:
  units:
    - name: docker.service
      drop-ins:
        - name: 10-devicemapper-storage-driver.conf
          content: |
            [Service]
            Environment="DOCKER_OPTS=--storage-driver=devicemapper"
      command: start
```

設定したcloud-configを適用します

```
# coreos-cloudinit -from-file=./cloud-config.yml
```

適用すると、
/etc/systemd/system/docker.service.d/10-devicemapper-storage-driver.conf
が以下の内容で配置されます

```
[Service]
Environment="DOCKER_OPTS=--storage-driver=devicemapper"
```

Dockerを再起動します

```
systemctl restart docker
```

Storage Driverがdevicemapperに変更されたことを確認

```
# docker info | grep "Storage Driver"
Storage Driver: devicemapper                                                                                                                                
WARNING: devicemapper: usage of loopback devices is strongly discouraged for production use.
         Use `--storage-opt dm.thinpooldev` to specify a custom block storage device.
```

※警告については対応したら追記予定。

## 参考にした記事

https://github.com/coreos/bugs/issues/1142

https://qiita.com/Hige-Moja/items/7b1208f16997e2aa9028
https://qiita.com/dtan4/items/2212607d13ad7c81120e
https://qiita.com/ngyuki/items/a6ef879a285573efd59f

https://groups.google.com/forum/#!topic/coreos-user/AwXlnXNUT1Y
getDeliveredNotificationsでは位置情報のNotificationを取得できない



小さなことですが、軽く躓いたのでメモしておきます。

`UNUserNotificationCenter`には`getDeliveredNotifications`というメソッドがあります。これは通知センターにある通知のうち、自分のアプリが発行した通知を取得することができます。

自分は位置情報をトリガにしてLocal通知を発行し、同じ通知を2度発行しないために発行済の通知を取得してアプリ内部でID保持しようと考え、この`getDeliveredNotifications`を実行しました。しかし何度やっても空の配列が返ってくるだけで、発行済通知が取得できませんでした。
調べてみても[ドキュメント](https://developer.apple.com/documentation/usernotifications/unusernotificationcenter/1649520-getdeliverednotifications)にはそれらしいことは書いていません。

色々探しているうちに、Jump to Defineでコードを定義されているコードを見てみたらこのようなコメントを見つけました。


```
Notifiations triggered by location cannot be retrieved, but can be removed.
```

_場所によってトリガされた通知は取得できませんが、削除できます。_


## 回避法

というわけで、位置情報をトリガにしたNotificationは通知センターから削除することはできても、通知されたのか、されていないのかを取得することはできません。
一応 `getPendingNotificationRequests`では位置情報をトリガにしたNotificationも取得できるので、発行時に発行済IDを保存し、`getPendingNotificationRequests`からIDが消えたら発行されたとみなしてもよさそうです。

ややこしいですけど・・・。
nowで、LineBotのチャンネルアクセストークンとチャンネルシークレットを隠蔽する

#はじめに
 私はLineBotを作った後、nowを使ってデプロイしていましたが、無料のプランを使用しているとコードの中身が全て見えてしまうので隠蔽する方法をメモしておきます。

#1. 隠蔽したい情報を定義
 `now secret` コマンドで隠蔽したい情報を登録

```
now secret add access-token XXXXXXXXXXXXX
now secret add channel-secret yyyyyyyyyyyyy
```
これで、アクセストークンが `access-token`として登録され、
チャンネルシークレットが `channel-secret`として登録される。


#2. 秘密にしたいコード部分を修正
 js側のアクセストークンとシークレットを直書きしている部分を下記のようにする

```js
const config = {
    channelAccessToken: process.env.ACCESS_TOKEN,
    channelSecret: process.env.CHANNEL_SECRET
};
```

最初に設定した名前を違うと思うかもしれませんが、そこら辺の結び付けはデプロイする時に行いますのでご安心を。

#3. デプロイ
いつもなら `now` を打ってデプロイしているかもしれませんが、一手間加えます。

```
now -e ACCESS_TOKEN=@access-token -e CHANNEL_SECRET=@channel-secret
```

1. と 2.で記述したことを結び付けてデプロイします
これで、秘密にしておきたいアクセストークンやチャンネルシークレットをコードに直書きしなくても大丈夫です。
array sample

```python
Z = np.zeros(10, [ ('position', [ ('x', float, 1),
                                  ('y', float, 1)]),
                   ('color',    [ ('r', float, [1,3]),
                                  ('g', float, 2),
                                  ('b', float, 1)])])
print(Z)
print(Z[0]['position'])
print(Z[0]['color']['g'])
```
```
[(( 0.,  0.), ([[ 0.,  0.,  0.]], [ 0.,  0.],  0.))
 (( 0.,  0.), ([[ 0.,  0.,  0.]], [ 0.,  0.],  0.))
 (( 0.,  0.), ([[ 0.,  0.,  0.]], [ 0.,  0.],  0.))
 (( 0.,  0.), ([[ 0.,  0.,  0.]], [ 0.,  0.],  0.))
 (( 0.,  0.), ([[ 0.,  0.,  0.]], [ 0.,  0.],  0.))
 (( 0.,  0.), ([[ 0.,  0.,  0.]], [ 0.,  0.],  0.))
 (( 0.,  0.), ([[ 0.,  0.,  0.]], [ 0.,  0.],  0.))
 (( 0.,  0.), ([[ 0.,  0.,  0.]], [ 0.,  0.],  0.))
 (( 0.,  0.), ([[ 0.,  0.,  0.]], [ 0.,  0.],  0.))
 (( 0.,  0.), ([[ 0.,  0.,  0.]], [ 0.,  0.],  0.))]
( 0.,  0.)
[ 0.  0.]
```
Pythonのrequestsを利用してmultipart/form-dataのFormにファイルアップロードする方法

## 1. はじめに

[前回の記事](https://qiita.com/5zm/items/8dc6189940b42e241210)で予告した通り、今回はHTTPクライアントライブラリである`requests`を利用した`multipart/form-data`によるファイルアップロードの方法について説明したいと思います。

* [Pythonのrequestsを利用してRest API(json形式)にファイルアップロードする方法](https://qiita.com/5zm/items/8dc6189940b42e241210)（前回の記事）

## 2. ソースコード

```python:multipartFileUploadApp.py
# -*- coding: utf-8 -*-
import requests

# ★ポイント1
XLSX_MIMETYPE = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'

# <form action="/data/upload" method="post" enctype="multipart/form-data">
#   <input type="file" name="uploadFile"/>
#   <input type="submit" value="submit"/>
# </form>

# main
if __name__ == "__main__":

    # ★ポイント2
    fileName = 'demo01.xlsx'
    fileDataBinary = open(fileName, 'rb').read()
    files = {'uploadFile': (fileName, fileDataBinary, XLSX_MIMETYPE)}
    
    # ★ポイント3
    url = 'http://localhost:3000/data/upload'
    response = requests.post(url, files=files)
    
    print(response.status_code)
    print(response.content)
```

**★ポイント1**
ファイルをアップロードする場合、ファイルフォーマットをサーバに知らせるため、MIMEタイプ（コンテントタイプ）を利用するのが一般的です。
サンプルでアップロードするxlsxのMIMEタイプは「[2007 Office system ファイル形式の MIME タイプをサーバーで登録する](https://technet.microsoft.com/ja-jp/library/ee309278(v=office.12).aspx)」を参考にしました。

**★ポイント2**
今回の記事の最大ポイントです。といっても特別なことはなくrequestsの[公式ガイドライン](http://docs.python-requests.org/en/master/user/quickstart/#post-a-multipart-encoded-file)にしっかりと書かれています。
アップロードファイルの情報をタプルで定義するだけです。タプルの内容は以下の通りです。

* 第１引数　：　アップロードファイルのファイル名
* 第２引数　：　アップロードファイルのファイルデータ
* 第３引数　：　アップロードファイルのMIMEタイプ

一般的に１つのFormに複数の`<input type="file">`を定義することができます。`requests`ではアップロードファイルの情報をDictで定義し、複数のファイルに対応します。Dictのキーと値は以下の通りです。

* キー　：　Formの`<input type="file">`のname属性の値
* 値　：　アップロードファイルのタプル

**★ポイント3**
`requests`の`post()`でHTTPリクエストを発行します。この際、`files`パラメータに★ポイント2で定義したアップロードファイルのDictを設定します。これだけで`maltipart/form-data`によるファイルアップロードが実現できます。

## 3. サーバでHTTPリクエストヘッダを確認してみる

```console:サーバでHTTPリクエストヘッダを確認
127.0.0.1 - - [26/Dec/2017 19:48:00] "POST /data/json/upload HTTP/1.1" 200 -
Content-Length: 9309
User-Agent: python-requests/2.18.3
Connection: keep-alive
Host: localhost:3000
Accept: */*
Content-Type: multipart/form-data; boundary=61a154f4eef94f87ac7062e266cc000a
Accept-Encoding: gzip, deflate
```

コンテントタイプが`multipart/form-data`になっていることが分かるかと思います。
`Content-Length`も`requests`が自動で設定してくれるのでありがたいですね。

## 4. さいごに

今回は`requests`を利用した`maltipart/form-data`によるファイルアップロードについて説明しました。[前回](https://qiita.com/5zm/items/8dc6189940b42e241210)はRest API（json形式）によるファイルアップロードについて説明しました。
Web APIによるファイルアップロードについては、ほとんどのケースで`maltipart/form-data`かRest API（json形式）のどちらかで実現できるかと思います。
次回はFlaskにおけるファイルアップロードについて説明する予定です。
wpa_supplicant.conf に書く PSK を wpa_passphrase コマンドで暗号化する意味はあんまし無い

#はじめに
Linuxで無線LANの設定をするときに、以下のように wpa_passphrase コマンドを使うと思います。

```
pi@raspberrypi:~ $ wpa_passphrase ssid01 passwordofssdi01
network={
        ssid="ssid01"
        #psk="passwordofssdi01"
        psk=ba5354bc7fada71ea01250be88bf5c75a5e806bce7a617a5671a14f5b84bb0ef
}
```

これってあんまし意味無いよねというお話をします。

#設定ファイルに書かれるパスワードを暗号化することの意義

まず一般論から。

設定ファイルにパスワードが平文で書いてあると不安になります。

そこで、暗号化しようと思います。

暗号化する場合、それのための「鍵」が必要になります。

しかしながら、鍵を用意したらそれをどこに保存するのか？ という問題が発生します。

よくあるのは、「複雑なアルゴリズムで暗号化すること」を鍵とするものです。

そうすれば、鍵の保存が必要ありません。

しかし！そうするとアルゴリズムを知っている者なら誰でも復号化できてしまいます。オープンソースならだれでも知れることになります。ソースが無くても、バイナリから解析されるのは時間の問題です。

さらに、利用者に「暗号化されてて安心」という印象を与えてしまい、設定ファイルの保護に意識が向かなくなるので、そこが運用上のセキュリティ脆弱性となってしまいます。

[伽藍とバザール](http://cruel.org/freeware/cathedral.html) ([The Cathedral and the Bazaar](http://www.catb.org/~esr/writings/cathedral-bazaar/))にも同じようなことが書いてあります。

> 　別の教訓は、隠すことでセキュリティを高めるという点についてのものだった。Fetchmail ユーザの一部は、ソフトの仕様を変えて、パスワードを暗号化して rc ファイルに保存するようにしてくれと要求してきた。のぞき屋たちが気軽にそれをのぞいたりできないようにしてほしいから、と言って。
> 
> 　これはやらなかった。これでは実は、セキュリティはぜんぜん高まらないからだ。rc ファイルを読む許可を与えられている人間なら、だれでも fetchmail をどのみちあなたと同じように好き勝手に動かせてしまうんだから――そしてそいつがあなたのパスワード目当てなら、fetchmail のコードそのものから必要なデコーダをぬきだして、ファイルを解読して盗むことができてしまう。
> 
> 　だから .fetchmailrc パスワード暗号化なんかしても、ものごとをつきつめて考えない人たちに、セキュリティが高まったかのようなまちがった幻想を与えるだけだ。ここでの一般原則は以下の通り：
> 
> 17. セキュリティシステムのセキュリティは、そこで使われてる秘密の安全性にかかっている。見かけだけの秘密は要注意。

あと、解析しなくても設定ファイルをコピーするだけで同じソフトからは利用できてしまう点でも、暗号化の意義が薄いです。

#wpa_passphrase ってどんな暗号化してるの？

まずここで用いる用語の整理をしておきます。
無線アクセスポイントに設定したパスワードを ASCII passphrase とします。
wpa_passphrase で生成されたものを 256bit key とします。

ASCII passphrase から 256bit key への変換は「暗号化」しているものだと思っていました。初期化時に、それを読み取って、「復号化」して使用しているのだと。

この変換は具体的に何をやっているのかを調べてみると、PBKDF2を用いていました。これは一方向ハッシュ関数です。ということは、元のASCII passphraseに戻すことができません。。。

どーゆーことなんだー！？と思って調べてみると、

**実は、WPA-PSK は 256bit key のほうを用いているのです。**

ということは、**我々が暗号化して保存していると思っていたものは、実はモロ平文だった。**というオチです。

例えば Windows 10 の無線LANの設定で、普通は ASCII passphrase を入力すると思いますが、256bit key の方を入力しても設定出来ちゃいます。

macOSでも同様です。

**マジ卍** ←言ってみたかっただけ

wpa_supplicant.conf に ASCII passphrase を書いても 256bit key を書いても本質的な違いはありません。

強いてセキュリティ的意味を考えてみると、ショルダーハックでハッカーの脳ミソに記憶されてしまうリスクが減ることぐらいでしょうか。

#じゃあどうしたらいいの？

wpa_supplicant.conf を、第三者に見られないようにする。それに尽きます。

シングルユーザーで使用している場合は、ログインパスワードを知られないようにすること。また、ストレージを物理的にアクセスされないようにすることでしょうか。

マルチユーザーで使用している場合は、ファイルのパーミッションを適切にすることぐらいしかないかもしれません。厳しめの運用なら、起動の度に手動で無線LANを有効にするという手段もあります。（無線LANにぶら下がってるコンピュータをマルチユーザーで使用するのはレアケースだと思いますが。）

#おわりに

無線LANパスワードの漏洩は、AWSの認証情報をうっかり漏らして採掘にでも使われてしまうケースよりは被害が少ないかもしれないけれども、被害に気づきにくい点や、漏れたデータによってはプライスレスな点で、より気を付けなければならないかもしれません。

ここは怖いインターネッツ。十分注意しましょう！
numpy finfo eps

```python
for dtype in [np.int8, np.int32, np.int64]:
   print(np.iinfo(dtype).min)
   print(np.iinfo(dtype).max)
for dtype in [np.float32, np.float64]:
   print(np.finfo(dtype).min)
   print(np.finfo(dtype).max)
   print(np.finfo(dtype).eps)
```
```
-128
127
-2147483648
2147483647
-9223372036854775808
9223372036854775807
-3.40282e+38
3.40282e+38
1.19209e-07
-1.79769313486e+308
1.79769313486e+308
2.22044604925e-16
```
# Refs.
* [マシンイプシロン](http://jn1inl.blog77.fc2.com/blog-entry-2002.html?sp)
* [指数表記](https://ja.wikipedia.org/wiki/%E6%8C%87%E6%95%B0%E8%A1%A8%E8%A8%98)
Google App Maker ー Resources の使い方

App Maker は`RESOURCES`というファイルをアップロードする機能がある。
アップロードしたファイルは Web サイトの Favicon や画像として使用できる。

`RESOURCES`については公式サイトでも触れられてないのでとっつきにくい部分でもある。
機能自体は大したことないけど、メモがてら記載しておく。

## ファイルをアップロード
設定画面の`RESOURCES`からアップロードを行う。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/35595/a804d146-b254-3a54-a068-9ff0ccc85e21.png)



## 最大ファイルサイズは16MB
それ以上だとエラーが出る。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/35595/584c9828-d019-956a-8cc2-7aa2406253f8.png)



## ファイル数の制限はなし？
とりあえず30ぐらいまではアップロードできることを確認。
どこかで制限はあるかもしれないが、普通に利用している限りは気にする必要はないだろう。



## アップロード後に出来ること
![image.png](https://qiita-image-store.s3.amazonaws.com/0/35595/34a21788-1ae7-5f0f-8854-70a4f932d20d.png)

1. リンクをコピー（`resources/〜`という App Maker 専用のリンク文字列)
2. 実際にアップロードしたファイルを表示（これは期限付きのURLになるのでこのURLを直接使うことはできない）
3. 削除



# 登録したリソースを使う
登録したリソースの使用例を記述する。

## 画像として使う
基本的な用途はこれ。

Image ウィジェットの URL に`resources/〜`の URL を設定すればOK。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/35595/ae98d2cd-442f-e808-96ef-4667fb0c480d.png)

ウィジェット一覧の一番下に URL 設定済みの Image ウィジェットがあるのでそっちからドラッグしたほうが早い。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/35595/767385a0-7d40-1f6d-646e-b1ebd5a03c9a.png)


### Favicon
`APP SETTINGS`の`Favicon URL`で指定する。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/35595/676f22e0-e3b3-8df3-119f-6217956eee9c.png)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/35595/b77c25f7-1670-249c-92c1-feb346ffd3e5.png)


## ダウンロードファイルとして使う
マニュアルを PDF にしてダウンロードさせる。みたいな用途でも使える。[^1]
[^1]: 普通に Drive の URL を別タブで開かせれば良さそうだが



## External resources として使う
External resources を使うと、JavaScript と CSS を外部のURLから登録することが出来る。

URL は CDN に登録されているような通常の`https://〜`でもいいし、Resource にアップした`resources/〜`を指定しても OK。

### 順番に注意
External resources は、画面で表示されているのがそのまま読み込まれる順番になる。[^2]
[^2]: 順番は変更することはできないので、間違えるとちょっと面倒
Go言語でファイルをコピーするコマンドを作成する


普段はPHPばかり書いているのだが，
多少なりとも低レイヤーなことがやりたかったのでGoで簡単なコマンドをつくってみました。

まず，以下のようなcp.goというソースを作成して
go build cp.go
を実行。


```cp.go
// 指定したファイルをコピーする実行ファイル


package main;

//import "bufio";
import "os";
//import "io";
//import "io/ioutil";
import "flag";
import f  "fmt";

    // グローバル空間で変数を宣言
    var sourceFile *string = new (string);
    var destinationFile *string = new (string);
    var e error;
    var capacity *int = new(int);
// main関数(エントリポイント)
func main () {
    // コマンドライン引数を取得
    flag . StringVar(sourceFile, "s", "-", "-s コピーしたいファイルを指定");
    flag . StringVar(destinationFile, "d", "-", "-d コピー後のファイルパスを指定");
    flag . IntVar(capacity, "c", 1, "どの程度の容量でコピーを進めるか")
    flag . Parse();

    // コピー元ファイルの存在チェックを行う
    if _, e = os.Stat(*sourceFile); e != nil {
        f.Printf("sourceFileが存在しません。");
        os.Exit(1);
    }
    if _, e = os.Stat(*destinationFile); e == nil {
        f.Printf("destinationFileが既に存在します。");
        os.Exit(1);
    }

    // まず読み込み元のファイルのサイズを取得する
    var size int = 0;
    var temp int = 0;
    var ensureSize int = 4096 * (*capacity); // 読み込んだ一時的なバイトを保持する
    tempArray := make([]byte, ensureSize);
    var d []byte;
    // プログラム終了時に実行
    var fp *os.File;
    fp, e = os.Open(*sourceFile);
    if (e != nil) {
        f.Printf("ファイルの読み込みに失敗しました。");
        os.Exit(1);
    }

    var newFp *os.File;
    newFp, e := os.Create(*destinationFile);
    if (e != nil) {
        f.Printf("読み込み失敗");
        os.Exit(1);
    }
    defer fp.Close();
    defer newFp.Close();
    for
    {
        // 指定したサイズ分ずつファイルポインタから読み込んでいく。
        temp , e = fp.Read(tempArray);
        d = tempArray[0:temp];
        if (temp == 0) {
            // 読み込みが完了後，ループを抜ける
            break;
        }
        newFp . WriteAt(d, int64(size));
        // 次から書き込むオフセット値を設定
        size = size + temp;
    }
    os . Exit(0);
}
```

今回はwindows上で実行したので
できあがったバイナリはcp.exeというファイル。

コマンドプロンプト上で
cp -s source.mp4 -d desitnation.mp4 -c 10などと行ったコマンドを叩くと
ファイルをコピーします。

ただそれだけなのですが，

```cp.go

        // 指定したサイズ分ずつファイルポインタから読み込んでいく。
        temp , e = fp.Read(tempArray);
        d = tempArray[0:temp];
        if (temp == 0) {
            // 読み込みが完了後，ループを抜ける
            break;
        }
        newFp . WriteAt(d, int64(size));
        // 次から書き込むオフセット値を設定
        size = size + temp;
```
上記の箇所で読み取ったバイト数を正確なバイト数をコピーするため

```go
        temp , e = fp.Read(tempArray);
```
戻り値のtempというint型が読み取ったバイト数となりますが

読み取ったバイト数分以上のキャパシティのスライスにならないように
スライス式で必要な長さにカットしたものをWriteAtメソッドの第一引数に渡しています。
ちょっとずつ読むドメイン駆動設計 第四部 戦略的設計 第十四章 モデルの整合性を維持する11 パターンを選択する

# これまでの十四章
- [第四部 戦略的設計 第一四章 モデルの整合性を維持する](https://qiita.com/YasuhiroKimesawa/items/6e8e5503a05ce9515a79)
- [境界づけられたコンテキスト](https://qiita.com/YasuhiroKimesawa/items/901ac764340275b93d61)
- [継続的な統合](https://qiita.com/YasuhiroKimesawa/items/6a58743c90c5b707c29d)
- [コンテキストマップ](https://qiita.com/YasuhiroKimesawa/items/626384c84145870ec5af)

##  
- [共有カーネル](https://qiita.com/YasuhiroKimesawa/items/7895d8c28137bd34008a) 
- [顧客/供給者の開発チーム](https://qiita.com/YasuhiroKimesawa/items/c9668a437499897fa9d5)
- [順応者](https://qiita.com/YasuhiroKimesawa/items/ab4782d5e727075e2d87)
- [腐敗防止層](https://qiita.com/YasuhiroKimesawa/items/bf22f7a970d5ee29a111)
- [別々の道](https://qiita.com/YasuhiroKimesawa/items/259cff6e393d5d03e274)

##
- [公開ホストサービス/公表された言語](https://qiita.com/YasuhiroKimesawa/items/bfec2a083483d348dc9c)


# パターンを選択する
ここまで、統合パターンを幾つか見てきましたが、実際どう選択していくのかがテーマ

## 1. なにはなくとも、コンテキストに境界を引き、コンテキストマップを描くこと

この意思決定はチーム全体が理解をするようにすることが大事。
意思決定自体は、政治的な都合、運用の都合、費用対効果の都合もあるので、現実的に選択することです。

## 2. コンテキストの中にいること

自らがコンテキストの一部であることを意識し設計すること。それをコンテキストマップに反映することです。

## 3. 境界の大きさを意識する

### 大きな境界
モデルが一貫性を持つようになるので理解しやすく、コミュニケーションも取りやすい反面、変換が難しい可能性があります。かつ、モデルが大きい分用途の広いモデルを必要とされることがありますが、そのためのスキルが必要になってきます。

### 小さな境界
モデルが小さくなるので開発者間のコミュニケーションオーバーヘッドは減少し、継続的な統合もしやすくなります。一方で、ユビキタス言語の方言が増えるので注意。

このバランスを取るのは苦労するとのことです。あっ実際苦労してますね。。。自分の場合。。。

## 4. 変更できないシステムから線を引く
最も簡単に意識決定できるのは、置き換え予定のないレガシーシステムや外部システムですね。ここはまずコンテキスト外になるでしょうから簡単に線が引けます。

レガシーシステムが変更してくれる、統合を促してくれる場合もありますが、それは当然と思ってはいけないと言っていますね。

## 5. 外部システムとの関係

### まずは**別々の道**
統合が必要なければそれにこしたことはないですよね。
ユーザーが両方のシステムをいじればいい場合もありますし、そこは慎重に検討すべきところです。

### **順応者**か**腐敗防止層**か
統合が必要であれば、どちらかをまず考えます。

順応者は、楽しくないですよね。特に新システムの場合はなぜ作るのかという疑問が出てきてしまいます。
それでも順応者を選択できる場合としては、Excelや単純なツールでレガシーで巨大システムの拡張をするような場合。。。こんなケースありそうですね。。。

そうでなければ、腐敗防止層を選択します。

### 継続的な統合が困難になってきたら**共有カーネル**を探す

チームが大きくなり、継続的な統合が困難になったら、共有カーネルを探して境界づけられたコンテキストに切り離して、そこに開発者を割り当てましょう。

また、依存関係が一方向であれば、**顧客/供給者の開発チーム**を選択します。

##　6. デプロイ

デプロイはコンテキスト間の統合が絡むと大変な作業になるのは目に見えていますね。
逆に言えば、統合で危険な箇所がデプロイによってわかるというものです。

デプロイの計画をコンテキスト境界の引き方にフィードバックすることで調整しやすくなるでしょう。
もちろん別々の道であれば作業は楽になりますね。


明日は、プロジェクトの途中で統合のパターンを変更する場合について読んでいきます。