OmniAICreator/Qiita-1.07M huggingface dataset:
TensorFlowの学習済みモデルをKeras用に変換して使う

この記事は[TensorFlow Advent Calendar 2018](https://qiita.com/advent-calendar/2018/tensorflow)の10日目の記事です。

本記事では、[MMdnn](https://github.com/Microsoft/MMdnn)を使って、TensorFlowの学習済みモデルをKeras用に変換する方法を説明します。

# 準備

関連パッケージをインストールします。MMdnnは最新版ではやりたいことができなかったので、少し修正したものを使用します。

```bash
pip install tensorflow==1.12.0 keras==2.2.4 git+https://github.com/mktozk/MMdnn
```

今回は[ここ](https://github.com/tensorflow/models/blob/master/research/deeplab/g3doc/model_zoo.md)のモデルを変換してみます。

まず、TensorFlowの学習済みモデルをダウンロードして展開します。

```bash
wget http://download.tensorflow.org/models/deeplabv3_mnv2_dm05_pascal_trainaug_2018_10_01.tar.gz
tar xf deeplabv3_mnv2_dm05_pascal_trainaug_2018_10_01.tar.gz \
  deeplabv3_mnv2_dm05_pascal_trainaug/frozen_inference_graph.pb --strip-components 1
```

また、後ほどスクリプトを使用するので、TensorFlowのコードをクローンしておきます。

```bash
git clone https://github.com/tensorflow/tensorflow
cd tensorflow
git checkout v1.12.0
cd ../
```

# 変換

TensorFlowの学習済みモデルを変換するためには、入出力のノード名と入力のサイズを指定する必要があります。MMdnnには[ここ](https://github.com/Microsoft/MMdnn/tree/master/mmdnn/conversion/tensorflow#meta-file-graph-visualization)に書かれているように`mmvismeta`という可視化ツールがあるのですが、これを使うためには`.meta`ファイルが必要です。今回は`.meta`ファイルが手に入らなかったので、以下のようにしてTensorBoard上でノード名を確認しました。

ここでは[import_pb_to_tensorboard.py](https://github.com/tensorflow/tensorflow/blob/v1.12.0/tensorflow/python/tools/import_pb_to_tensorboard.py)を使用します。これは、`tf.GraphDef`からTensorBoard用のファイルを出力してくれるスクリプトです。これを実行した後、TensorBoardを起動します。

```bash
python tensorflow/tensorflow/python/tools/import_pb_to_tensorboard.py \
  --model_dir frozen_inference_graph.pb --log_dir logs

tensorboard --logdir=logs
```

ブラウザでlocalhost:6006にアクセスすると、以下のような図が確認できます。
![graph_run= (1).png](https://qiita-image-store.s3.amazonaws.com/0/309602/b32b380e-c82e-05e9-a626-c23ed3156e26.png)
今回、入力ノードを`MobilenetV2/MobilenetV2/input`、出力ノードを`logits/semantic/BiasAdd`としました。

最後に、以下のスクリプトを実行するとKerasのモデルが得られます。

```bash:convert_pretrained_model.sh
#!/bin/bash

INPUT_NAMES=MobilenetV2/MobilenetV2/input
OUTPUT_NAMES=logits/semantic/BiasAdd
TMP_MODEL=tmp_model

python tensorflow/tensorflow/python/tools/optimize_for_inference.py \
  --input=frozen_inference_graph.pb --output=optimized_graph.pb \
  --frozen_graph=True --input_names=${INPUT_NAMES} --output_names=${OUTPUT_NAMES}

mmtoir -f tensorflow -iw optimized_graph.pb \
  --inNodeName ${INPUT_NAMES} --inputShape 513,513,3 \
  --dstNodeName ${OUTPUT_NAMES} -o ${TMP_MODEL}

mmtocode -f keras -n ${TMP_MODEL}.pb -iw ${TMP_MODEL}.npy -o base_keras_model.py

mmtomodel -f keras -in base_keras_model.py -iw ${TMP_MODEL}.npy -o keras_model.h5
```

`mmconvert`コマンドでもKerasのモデルへ変換可能ですが、後述のようにモデル読み込み時に中間コードを使用したいため、このようにstep-by-stepで実行しています。

# 変換したモデルの読み込み方

変換したモデルは以下のようにして使うことが可能です。`resize_bilinear`はKerasのオブジェクトではないので、モデルを読み込む際に渡してあげる必要があります。

```python:model.py
import keras

from base_keras_model import resize_bilinear


def build_model():
    model = keras.models.load_model(
        'keras_model.h5', custom_objects={'resize_bilinear': resize_bilinear})
    return model
```

# おわりに

巨人の肩の上に立って楽をしていきましょう。
elm-liveで簡単開発サーバー構築

かいてあるないよう：[elm-live](https://github.com/wking-io/elm-live)使ってみた
> 注：普通に機能について知りたいならREADME読みに行ってください

[次の記事](https://qiita.com/miyamo_madoka/items/879a5fa6b5c0cb2b0215)

## webpack好きですか？

webpackが好き、webpack.config.jsを書くのに何の抵抗もない、大好き、という方はお帰りください。

[elm-live](https://github.com/wking-io/elm-live)はwebpack分からんさんに与えられたelm用のbuildツール、というわけではなくて[^build]、HMR（Hot Module Replacement: オートリロードみたいなの）ができる開発サーバーです

[^build]: elmコマンドはバンドルもoptimizeもするのでそもそもElmだけならwebpackは絶対にいらないと思うんです

## elm-liveはすごく簡単に開発環境が整うなー

開発するとき、動作確認とかするのにdev server建てますよね。JSだとwebpack-dev-serverしか知らないんですが一択なんですかね。Elmでの選択肢は：

1. `elm reactor`を使う
2. `webpack`系のものを使う
3. elm専用のものを使う

今回はelm専用のelm-liveを使うという話なんですが、普通にwebpackでいいという人はそれでいいですし、`elm reactor`もHMRはないですがelmいれればついてくるしそれなりにリッチなので悪くないです。

### create-elm-appと比べて

create-elm-appはcreate-react-appみたいなやつです。つまり、設定はいじれないし、`create-elm-app`したわけではない既存のプロジェクトにあとから入れるのは手間です

elm-liveはいつでも導入できるし、設定もある程度いじれます。そもそもやってることが少ないので設定も少ないです
ツールは単機能でいいんですよ

## 実際に使ってるとこを見てみよう

ここに[miyamoen/elm-local-packages](https://github.com/miyamoen/elm-local-packages)というリポジトリがあります
これは[carlo](https://github.com/GoogleChromeLabs/carlo)を使ったElm用の開発ツールなのですが、ローカルにキャッシュされたelm packageのドキュメントを読み込んでElmのパッケージサイトの見た目で見ることができます。キャッシュを読んでいるのでオフラインで動作します。
よかったら使ってみてください。ちなみに今日マルチカラムできるようになりました[^senden]

[^senden]: 自作ツールの宣伝でした

[package.jsonのこの行](https://github.com/miyamoen/elm-local-packages/blob/d90b34370cd474cb60771d6415cd3ce28f34215e/package.json#L10)を見てみましょう

```package.json
 "bib": "elm-live src/elm/Views/Bib.elm --open --pushstate --start-page=bib.html --dir=public -- --output=public/bib.js",
```

`bib`は[biblipola](https://github.com/miyamoen/bibliopola)の略で、biblipolaはelm版のstorybookです。つまり上記スクリプトはstorybookの起動コマンドですね[^senden2]

[^senden2]: 自作ツールの宣伝でした。2回目

細かい使い方はREADME見ればいいと思うんですが、まずmakeするElmファイルを指定して、オプションをいくつか指定して、`--`の後ろに`elm make`のオプションを指定するだけです

input, outputは`elm make`をそのまま叩いている感じなので分かりやすいです

`--start-page`でエントリーポイントを指定します（defaultはindex.html）。elm-liveはこのファイルにHMR用のコードを挿入してブラウザで開いてくれます。このHTMLとelmのbuild結果をバンドルなんてことはしません。HTML内で読み込むことを忘れずに

`--pushstate`はelmアプリケーションがルーティングしてたら付けるやつです。`Browser.application`を使ってたら付けてください

## 感想

かんたん
ちょっとREADME読んでinとout設定してちゃんと読み込むようにすればできるのでとてもよいです
create-elm-appはエントリーポイントが決まっちゃってるのでアプリケーション用とbibliopola用に分けて書けませんが、elm-liveなら複数書けるし
あとから簡単に導入できるし
JSのバンドルツール（とわたしは認識している）のwebpackさんを酷使しないで済むし

`elm reactor`でがんばってた人には特におすすめするので使ってみてください
【障害報告】ログイン直後APIを甘く見てたらアプリ利用不能な障害が起きた話

こんにちは。鹿島([@kashitaka](https://twitter.com/kashitaka1118))です。リクルートでサーバーサイドエンジニアをやってます。

今年も色々ありましたが、中でも社内向けのLT会で発表して、バックエンド・フロントエンド・ネイティブ関係なく面白いと好評だった**「ある障害の振り返りと学び」**をこの場にも書こうと思います。

# TL; DR

**ログイン直後に叩く状態取得系のAPIの設計に気をつけよう**

* ログイン直後APIはログインAPIと同じくらい重要
* ログイン直後APIに多くの処理、複雑なロジックは盛り込まない
* ログイン直後APIではトランザクションデータはなるべく扱わない

# 障害内容

## 一部ユーザーでアプリが全く利用できない

私が担当しているプロダクトで「あるユーザーがiOSアプリでログインするとフリーズして全く利用できないようだ」という報告を受けました。一部ユーザーとはいえアプリが完全に利用不能な状態というのは緊急事態です。

## システムについて

障害が起きたプロダクトは社外向けの有料サービスで、iOS・ブラウザアプリのクライアントアプリとAPIサーバーからなる一般的なアプリです。
コードの品質もよく、障害も軽微なものが年に数回起きる程度だったため「完全に利用できない」レベルの障害は意外でした。

## 原因の調査

調べると特定のユーザーで**ログイン直後にリクエストされる設定取得API(以下、ログイン直後APIと呼ぶ)**でエラーしていました。

また、このシステムでは`予約`というEntityを扱うのですが、障害が発生しているユーザーはその`予約`の登録件数が平均的なユーザーの数百倍という使われ方をしていました。

### 要因①: ログイン直後API

**ログイン直後API**は、クライアントアプリの初期化と初期画面をレンダリングするために必要な情報：

* ユーザーの設定状態
* ユーザーの権限
* 現在のユーザーの状態

などを返すAPIです。サーバーでHTMLをレンダリングしていた時代と違い、SPAやネイティブアプリのクライアントアプリとAPIサーバーからなる昨今のシステムでは、ログイン直後に設定取得系のAPIを叩いて情報を取得するのは一般的な作りだと思います。で、このログイン直後APIがコケると初期化処理に失敗して利用不能になるわけです。

![図1.png](https://qiita-image-store.s3.amazonaws.com/0/71836/fcf0b3b1-9e05-90dc-363f-d159ac63846a.png)

これは当然といえば当然なのですが意外と盲点でした。 ログインAPIは絶対にコケちゃいけないという認識があるので入念にテストしますが、ログイン直後APIは他APIと同じ扱いでアグレッシブに変更していました。

APIの名称も「ログイン直後API」などでは当然なく「ユーザー情報取得API」的なものなので、重要度は直感的に理解しにくいものでした。

### 要因②: 肥大化したログイン直後API

さらに調査のためにこのログイン直後APIの仕様を調べると、レスポンスパラメーターの項目数が30以上。オブジェクトの中の項目も含めると超膨大な数になっていました。

![図3.png](https://qiita-image-store.s3.amazonaws.com/0/71836/45602448-fedc-892f-a5e0-ed1ef7b342be.png)

度重なる機能追加で初期画面のレンダリングに必要な情報がどんどん増えてこうなったのだと思いますが、ここまで多くの情報を詰め込んでいると

* 影響範囲がわかりづらい・把握できない
* 多くの情報をかき集めるため、実行するコード行数が多い

となり、どこか1つでもエラーすると全部共倒れしてしまい、クライアントアプリに大きな影響を出してしまいます。

### 要因③： トランザクションデータを扱う複雑なロジック

また、今回の障害にエラーになった箇所を調べると、上記のパラメーターのうち

* `予約ステータス`が`タイプA かつ タイプB`となる`予約`Entityの配列

なるものを取得する箇所で`予約`レコードを数千件取得しようとしてタイムオーバーしていました。これは上の条件に一致する状態の`予約`レコードが大量に作られないと負荷がかからないので、簡単な負荷試験では気が付きにくいと思います。
少なくとも、使い方やレコード数による負荷が予測しにくいトランザクションデータは、ログイン直後APIに入れるべきではありませんでした。

悲しいことに、取得に失敗していたパラメーターは画面では割と目立たない位置に表示する情報で、「これがないとアプリのUXを大きく損なう！」というレベルの重要情報ではありませんでした。

# まとめと対策

* ログイン直後APIの重要性を軽んじた
* 情報が多すぎて影響範囲がわかりにくいAPIになっていた
* 使い方次第で負荷が予測できないトランザクションデータを使っていた

という地雷は想定しないレコード数で発動し、アプリ利用不能という重い障害が起きました。
もし、何か1つでもちゃんとやっていれば想定以上のレコード数だとしても軽い機能不備くらいの障害で済んだはずです。悔しい！！

対策としては下記を実施しました。

1. アプリで絶対使えて欲しい主要な機能を定義
2. その機能を動かすために最低限必要な情報を洗い出し
3. ログイン直後APIはその情報のみにスリム化する
4. その他の情報は別APIで取得。もしどれかが取得失敗しても主要機能が動くようにフロント実装する

で、見直してみると、主要機能を動かすために必要な最低限の情報って設定系のマスタデータくらいだったわけです。
マスタデータだと基本的にはDBから取得し、多少の加工をして返すだけの簡単な処理になるはずなのでテストも容易だし、レコード数の影響も受けにくくなります。

# 感想

* あまり知られてない（？）けど重要なAPI設計のアンチパターンを見つけられてよかったです。
* アプリによってはログイン直後APIが一つでなく、複数APIの結果が全て正常に揃わないと初期化できないケースがあるはずです。そのような場合には本当にその設計で良いのか見直した方がいいと思います。
* BFFでAPIをアグリゲーションするトレンドもありますが、アグリゲーションのしすぎは危険。APIの適切な情報量がありそうだなあと思いました。

そんなわけで、この失敗が読んでいただいた皆さんのシステム設計の参考になればと思います。参考になった方は👍を押していただけると。ではでは〜👋
【Python学習メモ】リストについて

これは、Pythonの学習メモです。

リストを使う場合には、注意しないといけない例があります。

```python
>>> a = [1,2,3]
>>> b = a
>>> print(a,b)
[1, 2, 3] [1, 2, 3]
>>> b[0] = 10
>>> print(a,b)
[10, 2, 3] [10, 2, 3]
```

リスト「b」で要素を変更する場合は、リスト「a」に該当する要素も同時に変わります。

先ず：
<img src="https://qiita-image-store.s3.amazonaws.com/0/194463/eaeb1826-5257-a54f-8602-220b85abced2.png" width="400">

次に：
<img src="https://qiita-image-store.s3.amazonaws.com/0/194463/53a0459e-0254-a19c-b177-0ff87dd2bdda.png" width="400">

リストはミュータブルであるため、`b[0] = 10`で要素を更新しますと：
<img src="https://qiita-image-store.s3.amazonaws.com/0/194463/c8af9a2e-5715-3033-cf8c-52a6cb59c807.png" width="400">

要素を変更しても、「a」で定義したリストとのオブジェクトそのものは変わりませんので、リスト「a」は前と同じ参照先へ参照します。つまり、「a」の値も`[10, 2, 3]`になっています。オブジェクトidで確認しますと、以下になります。

```python
>>> a = [1,2,3]
>>> b = a
>>> print(a,b)
[1, 2, 3] [1, 2, 3]
>>> print(id(a),id(b))
4516968584 4516968584
>>> b[0] = 10
>>> print(a,b)
[10, 2, 3] [10, 2, 3]
>>> print(id(a),id(b))
4516968584 4516968584
```
ターミナルで乃木坂のイベント情報を見る

みなさん乃木坂すきですか?
僕は半年前あたりから乃木坂にどハマりしてずっとなんかしたいなーって思って今にいたってしまったので何かしようとPCを開いた次第です。

# きっかけ
なにかやりたいといってもパッと何か思い浮かばなかったのですが
近日乃木坂ファンの大きなイベントがあります

そう、長年乃木坂を支え伊藤かりんちゃんが将棋盤で言う"王"と例えた
西野が卒業してしまう。。。

絶対に卒業ライブには行きたい。行かなければ。

情報のキャッチアップは遅れてはいけない。。

でも、個人的に乃木坂公式HPはめったに開かないしなんとか公式HPを開かずにどうにか情報をキャッチアップできる方法。。。

そうだ!
ということでタイトル回収に行き着くわけです

# 乃木坂HPのイベント情報をターミナルで確認しよう!  

ざっくりやったことは以下3つぐらいです。  

* curlで公式サイト情報の取得  
* 不要な情報の削除  
* fzf


ってことで、curlでHP情報を取得して見ます。
乃木坂のHPはpathによって"ブログ"や"ニュース"が分かれていたので今回は初めから以下のパスで打ち込みました
```curl -s nogizaka46.com/news/events/
```
<img width="947" alt="スクリーンショット 2018-12-09 20.54.28.png" src="https://qiita-image-store.s3.amazonaws.com/0/212395/4eabeb81-e50d-e151-4eb0-134169224cc6.png">
いろんな情報が取れました!

ただ、curlでサイトの情報を取得しただけでも乃木坂という存在が近くなれた気がします。

# 取得したい情報を絞る
今のままだとイベント情報以外のデータも取得してしまっているので絞り込もうと思います。
画面でいうとここだけ取得したい!
<img width="1246" alt="スクリーンショット 2018-12-09 21.02.40.png" src="https://qiita-image-store.s3.amazonaws.com/0/212395/1df729df-a64d-5da3-ae56-e660bae140c6.png">

取得した要素を確認したらどうやらイベント情報には全てにtitle要素とリンク先のpathを持っていそう
<img width="1189" alt="スクリーンショット 2018-12-09 21.21.19.png" src="https://qiita-image-store.s3.amazonaws.com/0/212395/a8c1b7f2-5c8d-0b2d-6faa-c95f1e1652be.png">

 ということで
```curl -s nogizaka46.com/news/events/ | grep title | grep .php 
```
<img width="1184" alt="スクリーンショット 2018-12-09 21.41.09.png" src="https://qiita-image-store.s3.amazonaws.com/0/212395/7613946d-7ecf-b5b4-95ee-aa59f39bdda8.png">
結構綺麗になったのでここまできたら、色々できそうな気がしてきます。
というか、イベント情報を取得できたのでここでしゅーりょー!
やったー!

# もうちょっと+αに
せっかくイベント情報と一緒に詳細ページのリンクも取得できているので、取得したイベント情報からタイトルを選択して詳細ページに飛ばしたいと思います。

ってことで、僕の大好きfzfに通してあげてみます。
```curl -s nogizaka46.com/news/events/ | grep title | grep .php | fzf
```
![乃木fzf2.gif](https://qiita-image-store.s3.amazonaws.com/0/212395/7c607d3e-bb8f-7829-ca5a-de0d909f4200.gif)

ここまでできればphpのパスだけ取得してopenコマンド飛ばしてあげて完成です

```
function nogieve (){
  pass=$(curl -s nogizaka46.com/news/events/ | grep title | grep .php | cut -c 38- | rev | cut -c 21- | rev | fzf | rev |  awk '{print substr($0, index($0,">"))}' | rev | tr -d '>"')
  if [ -n "$pass" ]; then
    open $pass
  fi
}
```  

![乃木open2.gif](https://qiita-image-store.s3.amazonaws.com/0/212395/1daed8b6-fe74-1f57-1d87-ccf2a8db9a69.gif)

。。。自分でも引きほどめちゃくちゃな方法で値を取り出してしまいました。。
ごめんなさい引かないできくださいm(_ _)m

# 終わりに
やったことはめちゃ単純でしたけど、久しぶりに趣味の拡張的なことができたので個人的には満足です。
本当にいつかLINEAPIとか使って乃木坂通知bot作ろうと思います。  

という
  
~~最速で情報をキャッチアップするだけなら乃木坂速報なるものや、そもそもツイッターが一番早そうですね!~~  

あと、自分でも調べてわからなくて最後まで理由がわからなかったのですがcurlで
```curl -s -L http://www.nogizaka46.com/
```
でリクエスト投げたら文字化けしてこれの理由が最後までわからなかったので知見のある方は教えていただたいです。。;_;
Go Web Examplesの和訳（JSON）

[Go勉強会 Webアプリケーション編 #3](https://go-golang.connpass.com/event/107509/) でやろうと思っている [Go Web Examples: JSON](https://gowebexamples.com/json/) の和訳です。これもほとんど解説文がないですけどねー

# JSON

この例では `encoding/json` パッケージを使って　JSON データをエンコードとデコードする方法を示します。

```golang
// json.go
package main

import (
	"encoding/json"
	"fmt"
	"net/http"
)

type User struct {
	Firstname string `json:"firstname"`
	Lastname  string `json:"lastname"`
	Age       int    `json:"age"`
}

func main() {
	http.HandleFunc("/decode", func(w http.ResponseWriter, r *http.Request) {
		var user User
		json.NewDecoder(r.Body).Decode(&user)

		fmt.Fprintf(w, "%s %s is %d years old!", user.Firstname, user.Lastname, user.Age)
	})

	http.HandleFunc("/encode", func(w http.ResponseWriter, r *http.Request) {
		peter := User{
			Firstname: "John",
			Lastname:  "Doe",
			Age:       25,
		}

		json.NewEncoder(w).Encode(peter)
	})

	http.ListenAndServe(":8080", nil)
}
```

```sh
$ go run json.go

$ curl -s -XPOST -d'{"firstname":"Donald","lastname":"Trump","age":70}' http://localhost:8080/decode
Donald Trump is 70 years old!

$ curl -s http://localhost:8080/encode
{"firstname":"John","lastname":"Doe","age":25}
```

# 補足

Go は標準ライブラリの `encoding/json` パッケージで JSON をサポートしています。JSON のオブジェクトは Go のマップと構造体にエンコード/デコードすることができます。JSON オブジェクトと Go の構造体のメンバの対応は構造体のフィールドタグ(`json:"firstname"` 等)によって指定します。フィールドタグは名前の他、JSON にエンコードする際の型、省略可能かどうか等も指定できます。

# 参照

- [json - The Go Programming Language#Marshal](http://golang.org/pkg/encoding/json/#Marshal)
- [golangのenconding/jsonのタグについて](https://qiita.com/pside/items/0fc7f85746211371b23e)
- [Real World HTTP](https://www.oreilly.co.jp/books/9784873118048/) 付録 A Go 言語の JSON のパース
Go Web Examplesの和訳（Sessions）

[Go勉強会 Webアプリケーション編 #3](https://go-golang.connpass.com/event/107509/) でやろうと思っている [Go Web Examples: Sessions](https://gowebexamples.com/sessions/) の和訳です。前の二つに比べればそんなに難しくないですね。

# Sessions

この例では人気のある [gorilla/sessions](https://github.com/gorilla/sessions) を使って Go でセッションクッキーにデータを保存する方法を見ていきましょう。

クッキーはユーザーのブラウザに保存され私たちのサーバーに送られてくる小さなデータです。クッキーの中には例えばユーザーが私たちのウェブサイトにログインしているかどうかを保存することができ、そのユーザーが(私たちのシステム内において)誰なのかわかります。

この例では認証済みのユーザーにだけ `/secret` にある秘密のメッセージを見ることを許可します。そこへアクセスしたいユーザーは初めに有効なセッションクッキーを取得するため `/login` にアクセスしなければなりません。セッションクッキーにはそのユーザーがログインしたことが記録されます。加えて、秘密のメッセージへのアクセスを無効にするため `/logout` にアクセスすることができます。

```golang
// sessions.go
package main

import (
	"fmt"
	"net/http"

	"github.com/gorilla/sessions"
)

var (
	// キーの長さは 16, 24, 32 バイトのいずれかでなければならない。
	// (AES-128, AES-192 or AES-256)
	key = []byte("super-secret-key")
	store = sessions.NewCookieStore(key)
)

func secret(w http.ResponseWriter, r *http.Request) {
	session, _ := store.Get(r, "cookie-name")

	// 認証済みかどうかチェックする。
	if auth, ok := session.Values["authenticated"].(bool); !ok || !auth {
		http.Error(w, "Forbidden", http.StatusForbidden)
		return
	}

	// 秘密のメッセージを表示する。
	fmt.Fprintln(w, "The cake is a lie!")
}

func login(w http.ResponseWriter, r *http.Request) {
	session, _ := store.Get(r, "cookie-name")

	// ここで認証を行う。
	// ...

	// ユーザーを認証済みに設定する。
	session.Values["authenticated"] = true
	session.Save(r, w)
}

func logout(w http.ResponseWriter, r *http.Request) {
	session, _ := store.Get(r, "cookie-name")

	// 認証を無効にする。
	session.Values["authenticated"] = false
	session.Save(r, w)
}

func main() {
	http.HandleFunc("/secret", secret)
	http.HandleFunc("/login", login)
	http.HandleFunc("/logout", logout)

	http.ListenAndServe(":8080", nil)
}
```

```sh
$ go run sessions.go

$ curl -s http://localhost:8080/secret
Forbidden

$ curl -s -I http://localhost:8080/login
Set-Cookie: cookie-name=MTQ4NzE5Mz...

$ curl -s --cookie "cookie-name=MTQ4NzE5Mz..." http://localhost:8080/secret
The cake is a lie!
```

# 参照

* [sessions - Gorilla, the golang web toolkit](http://www.gorillatoolkit.org/pkg/sessions)
Go Web Examplesの和訳（Middleware: Basic）

[Go勉強会 Webアプリケーション編 #3](https://go-golang.connpass.com/event/107509/) でやろうと思っている [Go Web Examples: Middleware (Basic)](https://gowebexamples.com/basic-middleware/)の和訳です。と言ってもほとんど解説文がないので訳するところもないのですけどねー

# Middleware: Basic

この例では Go で簡単なロギングのミドルウェアを作る方法を示します。

ミドルウェアは単に `http.HandlerFunc` を引数の一つとして受け取り、それをラップし、サーバーが呼び出すための新しい `httpHandlerFunc` を返します。

```golang
// basic-middleware.go
package main

import (
	"fmt"
	"log"
	"net/http"
)

func logging(f http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		log.Println(r.URL.Path)
		f(w, r)
	}
}

func foo(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintln(w, "foo")
}

func bar(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintln(w, "bar")
}

func main() {
	http.HandleFunc("/foo", logging(foo))
	http.HandleFunc("/bar", logging(bar))

	http.ListenAndServe(":8080", nil)
}
```

```sh
$ go run basic-middleware.go
2017/02/10 23:59:34 /foo
2017/02/10 23:59:35 /bar
2017/02/10 23:59:36 /foo?bar

$ curl -s http://localhost:8080/foo
$ curl -s http://localhost:8080/bar
$ curl -s http://localhost:8080/foo?bar
```

# 補足

駆け出し Gopher (私もですが)がこれを初見で理解するのはちょっときついと思います。

ミドルウェアとはなんでしょうか？ Wikipedia によると 

> コンピュータの基本的な制御を行うオペレーティングシステム(OS)と、各業務処理を行うアプリケーションソフトウェアとの中間に入るソフトウェアのこと。

とありますが、ここで言っているのはそんなたいそうなもののことではなく、HTTP ハンドラコードの前後に差し込んでなんかちょっとやらせるためのコードのことです。

この例のコードでミドルウェアを使う前のコードは次のようになっていたはずです。

```golang
package main

import (
	"fmt"
	"net/http"
)

func foo(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintln(w, "foo")
}

func bar(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintln(w, "bar")
}

func main() {
	http.HandleFunc("/foo", foo)
	http.HandleFunc("/bar", bar)

	http.ListenAndServe(":8080", nil)
}
```

単純に foo/bar をレスポンスとして返すだけのものです。

そこに登場するのが次のミドルウェアです。

```golang
func logging(f http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		log.Println(r.URL.Path)
		f(w, r)
	}
}
```

この `http.HandlerFunc` を受け取って新しい `http.HanlderFunc` を返す `logging` という関数がミドルウェアです。この関数はログを一行出力してから元々の `http.HandlerFunc` の `f` を実行する関数を新しく作って返すものです。

この `logging` ともともとの `foo` を組み合わせて

```golang
http.HandleFunc("/foo", foo)
```

となっていたところを

```golang
http.HandleFunc("/foo", logging(foo))
```

を書き換えてやるとログを一行出力してから `foo` を呼び出す関数を作って `http.HandleFunc` に渡してやることができ、クライアントからリクエストがあるたびにログを出力して `foo` というレスポンスを返すことができます。

このようにしてログの出力処理を差し込むということをやっています。
TERASOLUNAの覚え書き


# はじめに

業務でTERASOLUNAを使用することになったので軽くまとめていきます。

# TERASOLUNAとは
今回対象とするのは、
「TERASOLUNA Server Framework for Java (5.x) 」
「TERASOLUNA Batch Framework for Java (5.x)」
の2種類で、NTTデータが提供しているオープンソース群です。
NTTデータがドキュメントをきっちり作っていて、ネットに公開されています。
言語はjavaで、ビルドにはmavenを使用するとよいそうです。

## TERASOLUNA Server Framework for Java (5.x)
Springの4系をwrapしているみたいです。
RDBアクセスのO/RMは、「MyBatis」か「JPA」の選択式みたいです。
また、"dependencyManagement"を活用することにより、各種ライブラリのバージョンをある程度制御できるそうです。
Viewはjsp一択となります。

### 導入について
mavenとCLIにてブランクプロジェクトを生成し、
生成したpom.xmlに色々設定を書き足す順番となります。

### csvの返却
Controllerクラスには、@Controller
該当メソッドには、@ResponseBody
戻りの型をString
にて返却するようにすれば実装できるみたいです。

### svgの返却
こちらもcsvの返却同様の実装方法にて、文字列を返却すればOKです。

参考：[Spring MVC で CSV をダウンロードさせる](https://qiita.com/yo1000/items/050c5c47daabf7a10e10)


## TERASOLUNA Batch Framework for Java (5.x)
Server Framework同様の構成となっています。
バッチの起動方法は同期実行と非同期実行に分かれており、非同期実行についても2種類あります。

### DBポーリングによる周期起動
Springが提供する仕組みとは別に、TERASOLUNAが提供する仕組みのようです。
バッチ実行監視用のテーブルを作成し、一定周期で監視させジョブを実行させる。
注意点として、追加するテーブルが既存で動いているテーブルと命名規則等が衝突するかもれない。

# 関連リンク

[TERASOLUNA Server Framework for Java (5.x)]http://terasolunaorg.github.io

[TERASOLUNA Batch Framework for Java (5.x)]https://terasoluna-batch.github.io
React NativeにRealm JSをインストールしようとした時に発生する２つのエラー対処（macOS）

## 経緯
React Nativeを使う機会があり、macOS環境でRealm JSをインストールしたときに発生した２つのエラーへのわたしの対処を記載します（Windows環境ではエラーは発生しませんでした）。

### 開発環境
- macOS Version: 10.14.1

### ライブラリ
- Ract Native Version: 0.57
- Node Version: 11.2.0
- Realm JS SDK Version: 2.21.0

### エラーが発生する処理
1. npm install realmを実行時したとき
2. 上記を解消して、react-native run-iosを実行したとき

まず1.のエラー

```
$ npm install realm --save
:
In file included from ../src/node/node_init.hpp:25:
../src/node/node_function.hpp:41:19: error: no member named 'GetCallingContext' in 'v8::Isolate'; did you mean
      'GetCurrentContext'?
    if (!isolate->GetCallingContext().IsEmpty()) {
                  ^~~~~~~~~~~~~~~~~
                  GetCurrentContext
/Users/kin/.node-gyp/11.2.0/include/node/v8.h:7727:18: note: 'GetCurrentContext' declared here
  Local<Context> GetCurrentContext();
                 ^
1 error generated.
make: *** [Release/obj.target/realm/src/node/node_init.o] Error 1
:
```

[Issue](https://github.com/realm/realm-js/issues/2149)を読むと、Node11に未対応のために発生しているようです。現状で利用したいのでNodeのバージョンを10に落とすことにしました。

- nodeのバージョンを変更
わたしの環境では、nodeはHomebrewからインストールしたのでnodebrewを使ってバージョンを切り替えることにしました。

    https://github.com/hokaccha/nodebrew


    インストールされているnodeをアンインストール

    ```
$ brew uninstall node --force
    ```

    nodebrewをインストール

    ```
$ brew install nodebrew
$ nodebrew setup
$ nodebrew ls-remote
　インストール可能なバージョンを確認する
    ```

    現時点でv10の中で最も新しいバージョン10.14.1をインストール

    ```
$ nodebrew install v10.14.1
$ nodebrew ls
　インストールされたバージョンを確認する
$ nodebrew use v10.14.1
    ```

    ~/.bash_profile等で実行パスに、$HOME/.nodebrew/current/binを追加する

    ```
export PATH=$HOME/.nodebrew/current/bin:$PATH
    ```

    実行するNodeのバージョンを確認する

    ```
$ node -v
    ```

    この時点で以下を実行してエラーが出ないはず。

    ```
    $ npm install realm --save
    $ react-native link realm
    ```

- つぎは、2.のエラー

    上記まで対応して、react-native run-iosを実行するとコンソールに以下のエラーが表示されます。

    ```
    :
    RealmJS requires a node package manager (n or nvm).
    
    Command PhaseScriptExecution failed with a nonzero exit code
    
    ** BUILD FAILED **
    :
    ```

    今回は、nvmをインストールしました。

    ```
$ brew install nvm
    ```

    これで２つ目のエラーの原因が解消されたので以下を実行してエラーがなくなりiOSアプリを起動できるようになるはずです。

    ```
$ react-native run-ios
    ```
マインドマップの相互互換、「アウトライナー」を知らない人向けに紹介する

[「PORT」アドベントカレンダー](https://qiita.com/advent-calendar/2018/port)10日目。
マーケティング担当のたったです。


#マインドマップの相互互換としての「アウトライナー」
たったは、マインドマップに一瞬だけ触れて、挫折しました。
比べてアウトライナーが続いているのは、以下理由。

・マインドマップに比べ、長文で管理するのに向いている
・UIが整然としている
・動きがシンプルで、ショートカットが快適


#アウトライナーの見た目・機能色々
なにごとも画像で見るのが早いのでこちら。
![for calendar 01.PNG](https://qiita-image-store.s3.amazonaws.com/0/322452/a91d1f60-1d48-be79-bcff-4a6c8900dca3.png)

こんな感じで、階層状に文章を作っていけるものです。
アウトライナーとして用意されているアプリ、サービスは、
この**階層の順位変更**や、**任意のまとまりごとの上下移動**、**下位階層の折り畳み**がサクサクできるようになっています。

#####上の画像を、軽く折り畳むとこんな感じです　▼
![for calendar 2.PNG](https://qiita-image-store.s3.amazonaws.com/0/322452/fe63a8c4-0e7f-0704-8d2c-66e855462763.png)


また、最上位表示する見出しも自由に変えられます
#####「ログ」を最上位に移したパターン　▼
![for calendar 3.PNG](https://qiita-image-store.s3.amazonaws.com/0/322452/e22f7419-166e-ddfc-25ab-b55d9cfc578c.png)


#####「これまでに」と「これから」をまるごと入れ替える　▼

![for calendar 4.PNG](https://qiita-image-store.s3.amazonaws.com/0/322452/445fd73b-e980-6177-cdaf-0e77619baabc.png)


#何に使うの？　
アウトライナーとはその名の通り、アウトラインを作るものとして生まれました。レポートや論文のアウトラインを管理するために、上記の機能が活躍します。

言いたいことを列挙してカテゴリごとにまとめる、従属する関係を階層関係に落とし込む、話の流れを最適化するために位置を上下させる…、といった風に、アウトラインを拡張、ブラッシュアップしていくことができます。

##「文書作成」「思索ツール」「todoとログ」
しかしタイトルの通り、たったはアウトライナーを「マインドマップの相互互換」として捉えていて、今やアウトライナーの用途は使う人次第かと思います。

**◆文書作成**
使う人が使えば、アウトライナーだけで本を一冊書いてしまうのだとか。マインドマップに比べて長文が管理しやすいUIのため、見出しだけでなく本文の執筆も容易です。Wordなどに比べて文章の入れ替えがしやすいため、素案段階の文章をアウトライナーで調整し、推敲のみ文書作成ソフトを使う、という方法も。

**◆思索ツール**
マインドマップと同じく、思考法としての使い方です。ブレストのようにアイデアを書き連ねていき、後からカテゴライズ、ブラッシュアップ、従属関係の整理が可能です。


**◆todoとログ**
先の画像としてサンプルにしたのがこの使い方です。todoやプロジェクトを管理したり、気になっているものや体験したもののログを残すことができます。

たったは主にこの用途で使っていて、これまで体験したもの、これから体験したいことのすべてをアウトライナー上に吐き出して管理したいと思っています。

#有名ツールと参考文献
たったは、「アウトライナー実践入門」という本にてアウトライナーの概要を掴みました。とはいえ、web検索でもアウトライナーファンの方が各々の使い方を紹介されていますので、まずはそれがいいかと。

肝心のツールですが、「アウトライナー実践入門」では以下2つがおすすめされています。
windows向け：[WorkFrowy](https://workflowy.com/)
Mac向け：[OmniOutliner](https://www.omnigroup.com/omnioutliner/)

たったが現在使っているのは「WorkFrowy」で、クラウドツールです。windows向けにはこれが最も良さそうでした。しかし、これをアウトライナーとして活躍させるには月額5ドルの課金が必要（非課金だと、項目数が制限される）なので、これから導入する方は以下Dynalistも視野に入れてください。

このエントリを書くにあたって調べてみたら、[Dynalist](https://dynalist.io/)という新興勢力があるらしく、windows向けにも使えて、非課金でも項目数無制限ということなので、たったはこっちへの乗り換えを検討しているところです。

#最後に
アウトライナーという、マイナーなツールを紹介しました。

先のWorkFrowyも、Twitter公式アカウントのフォロワー数が「12,265」という数になっており、大手クラウドツールとは比べるべくもない数字です。たったがアウトライナーを使っている理由の7割くらいは、愛で占められてるなーと思ってます。

「アウトライナー実践入門」でコラムとして語られていた話ですが、当時のアウトライナーのスタンダードとなっていたツールの開発会社を、マイクロソフトが買収しようとしたのだとか。しかし最終的には代わりに、PowerPointを作った会社が買収されたそうです。

もう少しでwindowsのスタンダードとなりかけたツール、と聞くと、なんだか愛が湧いてこないでしょうか？

# ㅤㅤㅤ
最後になりますが、[PORT株式会社では自社サービスを支えてくれる優秀なRubyエンジニアを募集しています](https://www.theport.jp/)(Rubyエンジニア以外も)。
もくもく会も行なっていますので、ぜひもくもくしましょう！
[PORTもくもく会](https://freestyle-mokumoku.connpass.com/)
【設計時の見落とし】こんな基本設計はイヤだ！

## はじめに

[設計時の見落とし Advent Calendar 2018](https://qiita.com/advent-calendar/2018/overlook)という面白そうなカレンダーがあったので、基本設計について考えてみました。
こんな基本設計はイヤだ！

基本設計ではどういったことまでドキュメントに起こすの？という話があると思います。結構会社やプロジェクトでまちまちですよね。
ここではざっくりと「プロジェクトの要件をインプットにして、システム開発が開始できるレベルまで構造を決める」とさせてもらいます。

正直当たり前のことしか書いてないけど、どれも実際に私が出会ったことのあるケースです。

## 設計全体

### インプットとの紐づけがわからない

基本設計時のインプットならプロジェクトの要件になると思います。
この表現が要件定義書だったりただの機能要件・非機能要件の羅列だったりすると色々あると思いますが、いずれにせよ何かしらのインプットがあるはず。
その**インプットとその成果物である設計書の紐づけが分からないと、作成した設計書が正しいかどうかの評価が出来ません**。

またここを意識していないと要件変更時に追従するのも難しくなるので、出来るだけインプットと設計書が紐づくような構成にするなり、対応表を作るなりしたいです。

### やたら文章で書きたがる

図がほぼ皆無で文章しかない。**文章だけだとどうしても複数の意味に取れる言い回しになることがあります**。
例えば、モジュールAとモジュールBの管理するデータはモジュールCのデータと関連している。
⇒(モジュールA) && (モジュールBの管理するデータ) -> モジュールCのデータと関連
⇒(モジュールA && モジュールB) の管理するデータ -> モジュールCのデータと関連

みたいな

文章が多いと作る方は満足度が高いのですが、認識違いの元になるし、純粋に見にくいので図を利用しましょう。
後は文章を区切って簡単な文章にしましょう。

## 設計内容

### ユースケース（機能・モジュールの用途）がよく分からない

ユースケース図がないとか、図はあるんだけどそのモジュールの説明が無くてシステム目線でどのように機能を実現しようとしているのかよくわからない状態。
「結局最初にHTTP requestを受けるのは誰なの！？」とかが結局よくわからないと、基本設計ドキュメントを見ただけでは意識合わせもしにくい。
最低限チーム毎の役割は基本設計時点で分かるようにしたいです。

### 外部インターフェースとなる部分がなにかよくわからない

ユースケースはわかったし登場人物も書いてある。でも登場人物同士の繋がりがよくわからない！
この状態だとチーム毎の役割は決まったんだけど、どのチームと関わっているかわからないので影響範囲が見えず遅延の元となります。

そんな状況あり得ないですか？意外とあります、「役割は決めたから後は現場で良しなに決めて！」ってプロジェクト。怖い怖い

### シーケンスがど真ん中しか意識されていない

シーケンスは基本設計なのか？って話もありますが、インターフェースをある程度決める時点でざっくりシーケンスくらいは一緒に決めると思うので一緒に記載。
今まではどちらかというとタスクの抜け漏れという形で現れるようなものでしたが、この辺はシステム的な部分の設計漏れとして出てくる気がします。

#### エラー系

細かく洗い出すのは難しいかもしれませんが、エラー時の挙動については機能しようとして決めておく必要はありますよね。
例えばHTTPリクエストに対してだったらHTTP Statusで500 Internal Server Error辺りを返すのか、リクエストには200 OKを返すけど状態は変えないとか。

#### 複数機能の並行処理

よくハマるのがこの辺りだと思います。

- 機能Aと機能Bを同時に実行することが出来ないようにするのか？出来るようにするのか？
- 実際にAとBの為のリクエストが同時に来た場合にどのような挙動にするのか？
    - 後のリクエストはエラー？後で処理？後で処理する場合はブロッキングされるの？等

といった話。並行処理についてはシーケンス図を並べて「こっちのここにあっちの最初が重なったら？」みたいなことをやっていくとある程度潰せる気がします。セマフォやDBトランザクションのようなロックのある処理は特に。

### 性能周りの確認項目が洗い出せていない

この辺りはシステムがある程度出来てからでないと実際の確認は出来なかったりしますが、「検証出来るようになったらすぐ検証する」という状態にしてなっていないと痛い目見ることが多いので書いておきました。

#### 起動時間

矛盾の無い完璧なシーケンスが出来ました！となっても、その結果起動時間が遅すぎるとなったら見直しが入るかも。
起動時間がシビアなシステムでは確認必須だったりしますよね。

#### 通信性能

こちらは例えばHTTPリクエスト/レスポンスにどのくらいの時間まで許容するか？とか、動画配信するなら何fpsまで出すか？といった話。
スペックが出ないのでモジュール構成を見直すことになんてこともあり得るので、性能が決まっているなら早め早めに計測したいです。

#### 物理スペックと合わない仕様

知っていれば当たり前だけど、知らないとハマるかもしれない話。
ハード屋さんがいればケアしてくれるかもしれませんが、ソフト屋さんだけだと結構見落としがちだったりしますよね。

私が出くわしたことがあるのは、動画配信用組込ソフトのPCシミュレーターを作った際に「PCだからきっと数十台でも性能劣化しないよね？」と言われ限界スペックを検証した際。期待値よりも全然下の段階で性能が出なくなったと思って計算したら、普通にギガビットイーサの性能限界だったなんてことがありました。

## 最後に

今回は基本設計というくくりで書かせていただきましたが、設計全体の話はどのフェーズの設計書でも共通していると思います。
**設計漏れや認識違いを引き起こす設計書は、不具合を持っている**ようなものです。
設計書もコードと本質は同じで、**意図が分かりやすく、シンプルな方がバグも少ないはず**。

出来るだけ人にやさしい設計を行い、バグの少ないプロジェクトを作りましょう！
IPはもう古い、時代は情報指向ネットワーク

## 情報指向ネットワーク(Information Centric Network)って?
僕らが普段使っているインターネット。
世界中に割り当てられた IP という約43億の識別子を用いてインターネットは運営されています。
でも、、、**サーバの場所ってどうでもよくね???**

- Youtube をみるときにすぐにとってこれたらなんでもいい
- ニュースをみるのにわざわざ海外のサーバからとってくる必要なんてない
- なんならなるたけ近いほうがイイ!

**つまり** IP はホスト指向なのに使い方はデータ指向だよね、いろいろ無駄があるよねってこと。

そこで、宛先情報を IP とかいう今の使い方にあっていないモノじゃなくてデータそれぞれに固有の情報を割り当てようね、というのが情報指向ネットワークです。

## じゃあどうやってつくるの?
### 5つの要素

| 要素       |       役割 |
|:-----------------:|:------------------|
| Interest      | データ要求パケッット、データが欲しい人はこれにデータ名を書いて提出してね|
| Data          | ふつうのデータ |
|PIT|Data が Interest の辿ってきた道を戻るためのテーブル。Interest が通ったノードに記録される|
|FIB|Interest を隣接ノードへ案内するテーブル|
|CS|人気のデータは中継ノードがキャッシュしてみんなに配る|

### 中継ノードの仕事

Interest を受けると

同じ名前が CS にキャッシュされている**-no-\>** FIB に一致するものがある**-yes-\>** Data が帰りに迷わないように PIT に記録、転送

### データ配信ノードの仕事

Interest を受けると

同じ名前が CS にキャッシュされている->データを受信した隣接ノードへ返信

### 何が嬉しいのか

- CS によるキャッシュ機能により、たくさん利用者がいるデータほどすぐ手に入る
- サバクラ形式じゃないのでスケーラビリティがすごい
- クライアントもサーバもどっちもネットワーク上の場所に依存しないからモビリティがある
-　メッシュネットワークになるので遅延耐性がある

### どんなことができるのか

たとえば、スマホに Youtube アプリをインストールして、ヒカキンをチャンネル登録。
通勤途中ですれちがった、すでに今日のヒカキンの動画を持っている人から携帯回線を使わずにダウンロード

たとえば、自動運転で周辺の車と通信したいときにサーバを置かずにネットワークを構成できる。

## さいごに

> それって P2P じゃね?

そのとおりです。P2P の概念を焼き直してアプリケーションレイヤじゃなくてネットワークレイヤに組み込んで使おうとする動きです。

> ほんとにできるの?

わかりません。詳しい動向は https://named-data.net/ をチェックだ!
実際に動かしてみたければ NFD という転送デーモンの実装があるのでおためしあれ。

> どうやってルーティングテーブルを更新するの?

NLSR というのがあるそうです。詳しくはしらない。
MergeSort

今回は、MergeSort（マージソート）のプログラムを書いてみました。

マージソートは、数列を2つに分けて、
それぞれを再帰的にソートしてからくっつける分割統治法です。
計算量はO(nlogn)です。

再帰って、便利ですね！




```java:MergeSort.java

import java.util.*;
public class MergeSort {
    public static boolean debug = false;
    private static void mergeSort(int[] a,int low,int high){
	if(low >= high) return;
	int mid = (low + high) / 2;
	mergeSort(a,low,mid);
	mergeSort(a,mid+1,high);
	int[] b = new int[mid-low+1];
	for(int i = 0; i < b.length; i++) b[i] = a[low+i];
	int i = 0;
	int j = mid + 1;
	for(int idx = low; idx <= high; idx++) {
	    if(i >= b.length) a[idx] = a[j++];
	    else if(j > high) a[idx] = b[i++];
	    else if(b[i] < a[j]) a[idx] = b[i++];
	    else a[idx] = a[j++];
	}
	if(debug) System.out.println("low="+low+", high="+high+", mid="+mid+": "+toString(a));
	
    }
    public static void sort(int[] a){mergeSort(a,0,a.length-1);}
    public static String toString(int[] a) {
	StringBuffer sb = new StringBuffer();
	for(int i = 0; i < a.length; i++) sb.append(a[i]+" ");
	return sb.toString();
    }
    public static void main(String[] args) {
	if(args.length > 0 && args[0].equals("-d")) debug = true;
	Scanner sc = new Scanner(System.in);
	System.out.print("データの個数を入力してください ");
	int n = sc.nextInt();
	int[] a = new int[n];
	for (int i = 0; i < n; i++) a[i] = sc.nextInt();
	sort(a);
	System.out.println(toString(a));
    }
}

```
C# でフォルダ作成

# メインメソッド

```csharp
using System;
using System.IO;

namespace sample
{
    class Program
    {
        static void Main(string[] args)
        {
            string path = string.Empty;
            FileSearch fs = new FileSearch();

            Console.WriteLine("Enter file name ...");
            path = Console.ReadLine();

            fs.DirectoryExists(path);
        }
    }
}
```

# ファイルの存在確認と作成クラス

```csharp
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace sample
{
    class FileSearch
    {
        //フォルダの存在確認を行う
        public bool DirectoryExists(string Folderpath)
        {
            string DisideOfSelsct;
            Console.WriteLine("フォルダの存在チェック");

            if (!Directory.Exists(Folderpath))
            {
                Console.WriteLine("フォルダが存在しません。フォルダを作成しますか？");
                Console.WriteLine("作成：yes　作成しない：no");
                DisideOfSelsct = Console.ReadLine();

                CreateDirectory(Folderpath, DisideOfSelsct);
            }
            else
            {
                Console.WriteLine(Folderpath + "は存在します");
            }
            return true;
        }

        //フォルダの作成を行う
        private void CreateDirectory(string DirectoryFolder, string Answer)
        {
            if (!Directory.Exists(DirectoryFolder) && Answer.Equals("yes"))
            {
                Directory.CreateDirectory(DirectoryFolder);
            }else if(Directory.Exists(DirectoryFolder) && Answer.Equals("no"))
            {
                return;
            }
        }
    }
}

```

visual studio2017でC#コンソールアプリケーションを作成しました。

## プログラム内容
コンソールから絶対パスを入力します。
フォルダが存在していれば何もせずに終わります。
存在しない場合はコンソール上でyesと入力することでフォルダを入力したパスで作成しますが、
noの場合は作成せずに終了します。

## 感想
これをオブジェクト指向の理解と、メソッドの引数を理解するために作成しました。
それだけなら単純な入出力だけ行うコンソールアプリでも良かったと思いますががめ、今回はフォルダ作成の簡易アプリケーションを作成しました。
この手のサンプルはネット上にいくらでもありますが、理解するためには書いて覚えるのが良いので備忘録として残しておくことにしました。

ご指摘などございましたら、ご教示頂けると幸いです。
ディープラーニングを学び始めた

# はじめに

ハードウェアエンジニアとして前職ではCPUを作っていた。
大学の頃、ディープラーニングが流行る前は機械学習が使われており、
自分はk-NN、k meansをハードウェアで低電力・高速に動かすエッジ向けの専用SoCの研究をしていた。
興味はあったがディープラーニングについてはあまり知らないので、
この機会に勉強して個人的に満足するための記事を書く。 

業務とは全く関係ない^^
詳しい人と仲良くなりたい^^

参考資料：
[ゼロから作るDeep Learning](https://www.amazon.co.jp/%E3%82%BC%E3%83%AD%E3%81%8B%E3%82%89%E4%BD%9C%E3%82%8BDeep-Learning-%E2%80%95Python%E3%81%A7%E5%AD%A6%E3%81%B6%E3%83%87%E3%82%A3%E3%83%BC%E3%83%97%E3%83%A9%E3%83%BC%E3%83%8B%E3%83%B3%E3%82%B0%E3%81%AE%E7%90%86%E8%AB%96%E3%81%A8%E5%AE%9F%E8%A3%85-%E6%96%8E%E8%97%A4-%E5%BA%B7%E6%AF%85/dp/4873117585)

## 実装

参考資料を読んで章ごとに実装してみる。
手元で気軽に動かしたい人は[Colaboratory](https://colab.research.google.com/notebooks/welcome.ipynb#recent=true)を使ってみるといいかもしれない。

[1. イントロ](https://github.com/t-akzw/deep-learning/blob/master/ch001.introduction.ipynb)
[2. パーセプトロン](https://github.com/t-akzw/deep-learning/blob/master/ch002.perceptron.ipynb)
[3. ニューラルネットワーク](https://github.com/t-akzw/deep-learning/blob/master/ch003.neural_network.ipynb)
[4. ニューラルネットワークの学習](https://github.com/t-akzw/deep-learning/blob/master/ch004.neural_network_learning.ipynb)
[5. 誤差逆伝播法](https://github.com/t-akzw/deep-learning/blob/master/ch005.back_propagation.ipynb)
[6. 学習テクニック](https://github.com/t-akzw/deep-learning/blob/master/ch006.hyper_parameter.ipynb)
[7. CNN](https://github.com/t-akzw/deep-learning/blob/master/ch007_CNN.ipynb)
読み終わったが時間的にまとめるの間に合わず5章で力尽きた

# 今後やりたいこと

最後に、AI用のハードウェアに関する[余談](https://github.com/t-akzw/deep-learning/blob/master/hardware.ipynb)を書いてみた。

ただの趣味として今後やりたいこと(随時リンク追加していく)

- 残りの章、ハイパーパラメータの最適化について色々実験してみる
- ハードウェア化に関する論文を読む、なんなら自分でハードウェアアーキ考える
- GPUでNNを動かしてみる
- いろんなライブラリを使ってkaggleの問題解いてみる
- 最適化問題について、ハードウェア的なソリューション（DAU、D-WAVEなど）も含めて学ぶ
- 統計検定2級は受けたので、次は準1級を受ける
pre-commit時にformatterを実行する

# pre-commit時にformatterを実行する

## はじめに

チームでコーディングルールが決ってないので、システム的に解決したいと考えました。
Gitにはhookという機能があり、cimmit時にshellを実行することができます。
commit時にformatを実行することで、リポジトリに綺麗なコードしかアップロードされないようにしようという試みです。

他の方法として、Lint系CIやCIでLintを実行することも考えていますが、別途試してみる予定です。


## 環境

pipenv
python3.7.1

## 設定方法
https://github.com/ikura1/test-pre-commit

1. 環境のセットアップ
2. formatterのインストール
3. checkerのインストール
4. pre-commitの設定

**環境のセットアップ**

    pipenv --python 3.7.1
    pipenv shell

仮想環境を使用しない場合は、なくても良い

**formatterのインストール**

    pip install black

formatterの設定ファイルを作成

```toml:pyproject.toml
[tool.black]
line-length = 79
include = '\.pyi?$'
exclude = '''
/(
    \.git
  | \.hg
  | \.mypy_cache
  | \.tox
  | \.venv
  | _build
  | buck-out
  | build
  | dist
)/
'''
```

**checkerのインストール**

    pip install flake8

checkerの設定ファイルを作成

```configuration:.flake8
[flake8]
ignore = E203, E266, E501, W503, F403, F401
max-line-length = 79
max-complexity = 18
select = B,C,E,F,W,T4,B9
```
**pre-commitをインストール**

    pip install pre-commit

pre-commit時に実行する設定を作成

```yaml:.pre-commit-config.yaml
repos:
- repo: https://github.com/ambv/black
    rev: stable
    hooks:
    - id: black
      language_version: python3
- repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v1.2.3
    hooks:
    - id: flake8
```
**pre-commitの設定**

    pre-commit install


## 動作
**1.雑にダメなコードを書きます**

```python:hoge.py
    for i in range(1,10):
      text=''
      if i%3==0:
        text += 'Fizz'
      if i% 5== 0:
        text += "Buzz"
      print(text or i)
```

**2.commitします**

```shell-session
(Stady) bash-3.2$ git add hoge.py
(Stady) bash-3.2$ git commit -m'feat: add hoge.py'
black....................................................................Failed
hookid: black

Files were modified by this hook. Additional output:

reformatted hoge.py
All done! ✨ 🍰 ✨
1 file reformatted.

Flake8...................................................................Passed
(Stady) bash-3.2$
```
commitすると、blackとflake8が実行されます。blackのチェックが通らず、formatされることがあり、失敗しました。
ですが、blackでのformatが行われました。


**3.ファイルを再度確認してみます。**

```python:hoge.py
for i in range(1, 10):
    text = ""
    if i % 3 == 0:
        text += "Fizz"
    if i % 5 == 0:
        text += "Buzz"
    print(text or i)
```

ファイルを確認すると、各所のスペースがなかった部分やシングルクォートになっていた部分が修正されており、formatterが実行されたことが確認できます。


**4.もう一度addを実行後commitする**

```shell-session
(Stady) bash-3.2$ git add hoge.py
(Stady) bash-3.2$ git commit -m'feat: add hoge.py'
black....................................................................Passed
Flake8...................................................................Passed
[master 093697f] feat: add hoge.py
 1 file changed, 7 insertions(+)
 create mode 100644 hoge.py
(Stady) bash-3.2$
```
blackとflake8ともにチェックが通過し、commitできたことが確認できました。

## 所感

pre-commitの動作としては、非常におもしろいとは思います。
ですが、目的であるチームのコード修正という意味では、一人一人の環境に対して準備する必要があるので、望ましい方法であるとは言えません。
また別の方法を模索してみます。なにかいい方法があれば御教授ください。


## 参考サイト
[Automate Python workflow using pre-commits: black and flake8](https://ljvmiranda921.github.io/notebook/2018/06/21/precommits-using-black-and-flake8/)
Windowsからクライアント証明書をexportしてスクレイピングする

[justInCase](https://www.wantedly.com/companies/justincase)では保険業務の自動化を進めており、その中にはWindows端末が必須とされている業務もありました。
そこで、クライアント証明書&秘密鍵をexportしてプログラムからでもアクセスできるようにしてみたので共有します。

# TL;DR
* クライアント証明書&秘密鍵をexportし、pemファイルに変換する
* export不可の場合もjailbreak用のツールがある**（自己責任）**
* 想定と異なるクライアントを利用する点についてサーバー側の許可を得ること。
* スクレイピングは`robot.txt`の指示に従うこと

# 1. 秘密鍵をexport可能な場合
Windowsのcertmgrから証明書を選択し、全てのタスク > エクスポート、と進め、証明書と一緒に秘密鍵をエクスポートしますか？で"はい"を選択します。
ここで"はい"がグレーアウトしていたら、 certmgrを無視して秘密鍵をエクスポートできるツールを利用するしかないと思います。

証明書は暗号化された形式でエクスポートされるので、これを.pemファイルに変換する手間が必要です。
`openssl` コマンドで可能なので、詳しく知りたい方はリンク先をどうぞ。
[@IT ー Windows上で、証明書や秘密鍵をPEM形式に変換してエクスポートする (1/2)](http://www.atmarkit.co.jp/ait/articles/1602/05/news039.html)


# 2. 秘密鍵をexport不可能な場合
![image.png](https://qiita-image-store.s3.amazonaws.com/0/96286/0e58d27d-7416-fab4-c51c-4e3dd4bb3e8f.png)

cermgrで秘密鍵のエクスポートが不可能な場合は、アメリカのセキュリティ関連サービス企業が公開している秘密鍵のエクスポートツールがあるので、それを利用してエクスポートすることができます。
https://github.com/iSECPartners/jailbreak

jailbreak後は.pfx形式のファイルが得られるので、後は`openssl`を使って.pem形式に変換すればOKです。

# 3. クライアント証明書を用いたアクセス
業務でPythonを使っているので、HTTPリクエストには`requests`という定番ライブラリを用いています。ドキュメント読んだら想像以上にクライアント証明書を使ったアクセスが簡単でした。

```access.py
import requests
res = requests.post(url, cert="./certification.pem")
```

# まとめ
Windows端末が必須と思われる定常業務でも、その理由がわかれば自動化の対策が立てられます。
今回はSSLクライアント認証の設定ファイルを外だしする方法でした！

[justInCase](https://www.wantedly.com/companies/justincase)では自動化が大好きなあなたを求めてますので、ご興味があれば是非ご応募くださいね！以上、お役に立てば幸いです。
Riot.js をデイリーポータルZに導入した話

![riot960x.png](https://qiita-image-store.s3.amazonaws.com/0/8033/6c3ec74a-2239-d753-b4d3-2afaec82aba6.png)

表題ママになりますが、Riot.jsをデイリーポータルZのリニューアルに伴い採用しました。デイリーポータルZ（以下DPZ）って何？と言う方や、リニューアル全体の裏話を知りたい方は、[こちらの記事](https://dailyportalz.jp/kiji/hagemasu_kai-start-site-url)や[こちらの動画（長い）](https://www.youtube.com/watch?v=ybOHMarkb5U)を見ていただければ幸いです。

# なぜ Riot.js なのか？

これには大きく分けて2つの理由があります。

## DPZ はめちゃくちゃ人気がある老舗サイトである

DPZは、月間1500万PVの超人気サイト。1日に複数の記事更新があり、中にはTwitter参加型のリアルタイム性の高い企画もあります。トラフィックもすごいあります（転送量とかすごすぎて語彙力低下）。過去記事も万単位で存在し、それら全てのページのサイドバーにある新着記事や人気記事のパーツを更新していく必要があるわけです。要するに、キャッシュ（CDN）と相性が悪い。普通に考えると、サイドバーをAjaxで読み込んで来ようとなると思います。

## リニューアルだけど、デザインそのまま、HTML/CSSもそのまま

トラフィックのあるメディアなら、今流行りのシングルページアプリケーションにすればいいではないか、と思うかもしれません。しかし、今回のリニューアル要件は、インフラとCMSの変更のみ。デザインも変わらなければ、HTML/CSSもそのまま。厳密には、リニューアルと言って良いのかどうかも微妙なところです。

要するに、**古いjQueryが入ってるサイトで、HTML構造を変えず一部だけSPAっぽいことがしたい**と言うこと。この要件であれば、Riot.js が最適だと思います。

## それまでのHTMLをとりあえずそのままカスタムタグ化できる

難しいことは考えず、全く同じHTMLをカスタムタグにできる。学習曲線の小ささにも繋がっているので、新規開発の際にもおすすめできるポイントだと思います。

## 軽量でjQueryとの相性が良い

すでにあるサイトということは、多くの場合jQueryが入っていて、jQueryに依存するライブラリがあれこれと入っているわけです。ここに非jQuery世界観のライブラリを付け足すと、JSファイル全体の容量がえらいことになってしまいます。jQueryから離脱できない以上、jQueryと相性の良い軽量なライブラリというのはベターな選択肢ではないでしょうか。

# デザインそのままなら、別にRiot.jsを入れる必要すらなかったのでは？

という疑問ももっともだと思います。ちなみに、リニューアル前はどうなっていたのか？というと、同じくサイドバーはJavascriptで更新されていましたが、`document.write()`でHTMLソースをえいやっとDOMに挿入する方式でした。ただ、流石にこの仕組みは残したくなかった。この方式は**HTML構造の変更にめちゃくちゃ弱い**です。データソースはJSON形式で取得し、表示はカスタムタグに任せる。こうしてデータと構造を分離しておけば、CMSからのデータ出力部分にはなんの変更も加えず、カスタムタグのみ変更することでデザイン変更に対応できます。今回カスタムタグ化しておくことで、将来のデザインリニューアルの際の工数の大幅な削減が期待できると判断しました。

# Riot.js を導入してよかったこと

短期間のプロジェクトで期待通りに動作し、大量のトラフィックを最小構成のインフラでさばくのに貢献しています。これは大変すばらしい結果と満足しています。

# さらに改善したい点

APIのエンドポイントを再考し効率化したいと思っています。パーツごとにAPIのエンドポイントが存在するのですが、その分リクエスト数が増えてしまうのが気になっています。

```
// ヘッドラインパーツの読み込み
$.getJSON("/api/dpz/headline", function (data) {
    riot.mount('dpz-headline', { items: data }
});
```

SPAであれば必要なパーツのみ更新されるから良いのですが、DPZは全体としてはあくまで普通のサイト。リンクをクリックすればページ遷移してしまい、全てのパーツのAjaxリクエストからやり直しです。エンドポイント数を少なくするか、遅延読み込みするべきかと思っています。

# Riot.js に改善してほしい点

簡単に導入できるし、ドキュメントも最小限で必要なものが揃っているのは良いのですが、いざ導入した後の実践的な情報となるとなかなか見つからない。今後もDPZの保守改善を行っていく予定なので、勉強会などで情報が仕入れられると嬉しいのですが…。活性化を期待したいと思います！
[cocoa][swift]Cocoa.swift 2018-10 を振り返る

<p>Cocoaを一人で勉強するのはつらくて長い道のり...<br />
そんなあなたの<br />
Cocoa.swift</p>

# Cocoa.swift について
<ul>
<li>Cocoa勉強会 関東 Swift分科会 です。</li>
<li>ほぼ毎月、池袋コワーキングスペース OpenOffice FOREST で開催してます。</li>
<li>macOS/iOS/watchOS/tvOSプログラマーのための勉強会です。</li>
<li>プログラムに関する知識や経験を共有を目的としています。</li>
<li>会の活動内容や発表資料、サンプルコードは公開を前提としています。</li>
<li>申し込みは、connpassから。<br /><a href="https://cocoa-kanto.connpass.com/">https://cocoa-kanto.connpass.com/</a></li>
</ul>

# TabUIの実験
<p>macOSのウィンドウのTabについての発表です。</p>

# プライバシーとセキュリティ（リモート通知のデバイストークンの扱いなど）
<p>GDPRで話題になる頻度が上がったプライバシーとセキュリティ。対応は個々でだと思いますが、サーバを利用しないなんて考えられない今のスマートフォン・アプリケーション開発者にとって、何らかの対応が必要になる可能性があります。<br />
今回の発表では、iOSアプリケーション開発に関係がありそうな項目について、開発の現場で話題になっていることを取り上げてみました。</p>

# AppleEventなど
<p>MacintoshのSystem 7で登場したのがAppleイベント。Appleイベントはアプリケーション間コミュニケーション（IAC）のための仕組みです。<br />
また、アプリケーションがOSA (Open Scripting Architecture) に準拠していると、AppleScriptなどのOSA言語で記述されたスクリプトで操作できることになります。
今回の発表では、初期の頃のお話から、基礎的なこと、今のお話まで取り上げてみました。</p>

# MojaveのDark Mode
<p>Macintoshが革新的だったのは、白色背景に黒文字を表示したことです。これは、macOSのAquaにも受け継がれたのですが、MojaveのDark Mode登場により状況が変わりました。説明を信じれば集中したいときはDark Modeが適しているそうです。<br />
真偽はさておいて、Dark Modeに試してみて感じるのは、Dark Modeに完全対応していないアプリケーションが存在すると、画面が見苦しくなるということです。<br />
今回の発表では、Dark Modeへの対応方法を駆け足で紹介してみました。</p>

# え！それって参照渡し？
<p>とても違和感を感じる用語があります。それは、『参照渡し』です。
え！違うだろ？と感じていたのですが、いい機会なので調べてみました。</p>

【関連情報】
<a href="https://qiita.com/advent-calendar/2018/cocoa">Cocoa Advent Calendar 2018</a><br />
<a href="https://cocoa-kanto.connpass.com/event/101034/">Cocoa.swift 2018-10</a><br />
<a href="https://cocoa-kanto.connpass.com/">Cocoa.swift</a><br />
<a href="https://www.facebook.com/groups/cocoa.kanto/">Cocoa勉強会 関東</a><br />
<a href="http://www.bitz.co.jp/weblog/">Cocoa練習帳</a><br />
<a href="https://qiita.com/m_yukio">Qiita</a><br />
Blender で下絵が消えたときの対処法

この前blenderを使っていたらなぜか下絵が出てこなかったので復活したやり方（？）を共有

だいたいショートカットキーの１と3を押せば解決する問題のはずですが
今回できませんでした。（ショートカットキーはただキーを押すだけで起動します）

その時、画面右側にショートカットキー”N”で出てくるタブを出して
座標軸をすべての視点にします。
![sgfdgsdf.PNG](https://qiita-image-store.s3.amazonaws.com/0/262130/184d8576-8a15-9f8d-3946-f36d021497a3.png)

その時点でも出てこなかったので
ショートカットキー7
を押して上からの視点を見た時にいつの間にか復活しました。

そのあと何度か1や3を押しましたが現れなかったので、また7を押して1や3を何回か押したところ
下絵が戻ってきました！

ほかにも下絵が入っているフォルダを移動していないかや
不透明度が０になっていないか
画像がそもそも読み込まれているかほかの画像で試してみるとか

いろんな方法を試してみてできなかったときが私の場合でした。



もし役立ったらぐっとボタンを入れていただけると幸いです！
ghqを用いたgo言語のリポジトリ管理方法について考える

## はじめに
普段自分はmotemenさんの[ghq](https://github.com/motemen/ghq:embed:cite)を使ってリポジトリを管理しています．
これを用いた場合，通常は`~/.ghq`以下の適当な位置にリポジトリが配置されます．

ところで最近，go言語に手を出したのですが，はじめに`$GOPATH`を`~/.go`と設定して作業し始めました．
しかしこの場合，`ghq get`したリポジトリが`$GOPATH/src`以下に配置されないことから，importやdepを使う際にエラーが生じました．

そのとき，この問題について検索すると様々な解決方法がヒットし，どの方法が最適解なのかわからずややハマってしまいました．
そこで今回はgo言語のリポジトリを扱う上でどの方法が良いのかまとめてみようと思います．

# ghqを活用する上でgo言語のリポジトリをどのように扱うか
## 方法1 `$GOPATH`を複数設定する

まずは`$GOPATH`が設定されていないことが問題なのでそれを設定することを考えます．

以下のようにして`$GOPATH`は複数設定することができます

```
# 例: ~/.bashrcに以下を記述
export GOPATH=$HOME/.go:$HOME/.ghq
```

このように`$GOPATH`を複数指定した場合は，`go get`した際はプライマリのパスが採用され，importやdepの際はセカンダリ以降のパスも見る仕様のようです．
あとは`.ghq/github.com/...`となっている構造を`.ghq/src/github.com/...`とすることで冒頭の問題は解決できます．

### 問題点
#### `.ghq`以下が汚くなる
`.ghq/src/github.com/...`にリポジトリを移動させないといけないため`.ghq/`直下に`src/`というディレクトリが作られ，決してきれいな構造であるとは言えません（きれいな構造とは）．
また`dep ensure`を走らせると`.ghq/pkg/`も生成され，他の言語のリポジトリも管理している場合とても面倒です．`ghq get`したあとにその都度`.ghq/src/`に移動させるのも大変です．

## 方法2 `$GOPATH/src/`以下もghq rootに含める
この方法ではgo言語のリポジトリは全て`go get`で取得し`$GOPATH/src`以下で管理します．（`$GOPATH`は増やさない）
ただしこのままだと[peco](https://github.com/peco/peco)などを使っている人は`ghq list`としても対象のリポジトリが引っかからないため不都合が生じます．このため次の通りにします．

`ghq list`は`ghq root`以下のリポジトリを表示してくれますが，この`ghq root`は`.gitconfig`の記述に基づいて設定されています（何も記述しないと`~/.ghq`に設定される）．またこれは複数設定できるため以下のようにして`$GOPATH/src`もrootに設定します．

```
# プライマリパスに`ghq get`でもってきたいディレクトリのパスを設定
git config --global --add ghq.root $HOME/.ghq
# $GOPATH以下も管理対象にする
git config --global --add ghq.root $GOPATH/src

# 確認
git config --global --get-all ghq.root
```
.gitconfigはこのようになります

```
(省略)
[ghq]
	root = /home/{{your_name}}/.ghq
	root = /home/{{your_name}}/go/src
```

### 問題点
#### "go get" と "ghq get" を使い分ける必要がある
go言語のリポジトリは`go get`でそれ以外のリポジトリは`ghq get`を使う必要があります．誤って`go get`とするところを`ghq get`としてもcpを使えば大丈夫ですが，慣れるまでは使い分けが面倒に感じられるかもしれません．

#### リポジトリの位置が統一されない
go言語を用いたものは`.go/`以下にそれ以外は`.ghq/`以下になるため同一ディレクトリで管理したくてもそれができなくなります．しかしこの問題は普段，pecoを使ってディレクトリ移動をしている人には大した問題にはならないかと思われます．


## 方法3 ghq root を .go/src に設定する
この方法では`ghq root`を`.go/src`以下に設定することで解決を図ります．方法は2番目のとき同様に`.gitconfig`にrootの場所を`.go/src`として記述します．これにより`go get`，`ghq get`どちらにしても同一の場所にリポジトリがクローンされます．

### 問題点
#### .goの中身は決してgoだけではない...という状況になる
`go get`，`ghq get`どちらも.goディレクトリ以下に配置されるためにgo以外の言語で書かれたものも全て`,go/`内にあるという状況が生まれます．解決方法として`.go`ではなく`.repo`など（いい名前が思いつきませんでした...）に名前を変更してそれに応じてパスを書き換える手法が考えられますが，`.repo/bin/`はgoのソースから生成されたバイナリしか配置されないことなどに違和感を感じる人もいるかもしれません（自分は違和感を感じた）．

## 結局，自分はどうしたのか
自分は方法2を採用することにしました．"go言語はプログラムの管理方法を含めてgoである"と(勝手に)捉えた上でgoは`.go/`，それ以外は`.ghq/`以下に配置して作業しています．

ところでgo 1.11で試験導入，1.12からは正式採用予定のvgo(go.mod)では`$GOPATH`は不要になるようです．
将来的にはこのような問題も解消されるかもしれませんね．


# 参考
- https://qiita.com/chano2/items/ea76cc503e651f07bfb0
- https://blog.nishimu.land/entry/2015/05/14/140104
- 先輩とのおしゃべり
Web Bluetooth(Read/Write/Notifications)の使い方まとめ

公私共に年末に向けてバタバタしながらも[aptpod Advent Calendar 2018](https://qiita.com/advent-calendar/2018/aptpod)の9日目。

2018年もブラウザの進化が止まらない1年でしたね。その中でも`WebBluetoothがWindows 10のChromeでも使えるようになった`のはインパクトでかかったです。仕事でも実際に導入していろいろいじくり倒しました（その時の記事「[Web Bluetoothを実戦投入すると意外と使えたメモ](https://qiita.com/umi_kappa/items/da60e3c8cec19624df91)」）。

今回はWeb BluetoothでBLEデバイスとデータ通信する際のRead/Write/Notificationsをシンプルなコードで紹介します。

# ソースコード

## データ通信する前の下準備

BLEデバイスとデータ通信する前に、ブラウザからBLEデバイスをスキャンし接続する必要があります。スキャン時は、デバイス名・サービスUUIDでフィルタリングすることができます。

```js
// Service UUID
const SERVICE_UUID = 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'

// Characteristic UUID
const CHARACTERISTIC_UUID = 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'

// Scan
navigator.bluetooth.requestDevice({
  // 全てのBLEデバイスをスキャン対象とする場合はtrue
  // フィルタリングしたい場合はfalse
  acceptAllDevices: false,
  // デバイス名, デバイス名のプレフィックス, ServiceのUUID
  filters: [
    {name: 'デバイス名'},
    {namePrefix: 'デバイス名のプレフィックス'},
    {services: [SERVICE_UUID]}
  }],
  // 接続するService
  optionalServices: [SERVICE_UUID]
})
  .then(device => {
    // 接続
    return device.gatt.connect()
  }))
  .then(server => {
    // Service取得
    return server.getPrimaryService(SERVICE_UUID)
  })
  .then(service => {
    // Characteristic取得
    return service.getCharacteristic(CHARACTERISTIC_UUID)
  })
  .then(characteristic => {
    // characteristicに対してRead/Write/Notificationsの処理を記述
  })
  .catch(error => console.error(error))
```

## Read

```js
characteristic.readValue()
  .then(response => {
    // データがStringの場合
    const decoder = new TextDecoder('utf-8')
    const str = decoder.decode(response)
    console.log(str)

    // データがnumberの場合
    const num = getUintN(response)
    console.log(num)
  })
  .catch(error => console.error(error))

// 数値変換
const getUintN = (dataView) => {
  switch(dataView.byteLength) {
    case 0:
      return 0
    case 1:
      return dataView.getUint8(0)
    case 2:
      return dataView.getUint16(0)
    case 4:
      return dataView.getUint32(0)
    case 8: {
      const top = dataView.getUint32(0) * Math.pow(2, 32)
      const bottom = dataView.getUint32(4)
      return top + bottom
    }
    default:
      return 0
  }
}
```

## Write

```js
const num = 1
characteristic.writeValue(new Uint8Array([num]));
```

## Notifications

```js
// Add Event
characteristic.addEventListener('characteristicvaluechanged', handler)

characteristic.startNotifications()
  .catch(error => {
    // Remove Event
    characteristic.removeEventListener('characteristicvaluechanged', handler)
    console.error(error)
  })

const handler = (event) => {
  const value = event.target.value

  // データがStringの場合
  const decoder = new TextDecoder('utf-8')
  const str = decoder.decode(value)
  console.log(str)

  // データがnumberの場合
  const num = getUintN(value)
  console.log(num)
}
```

# 手元にBLEデバイスがないけど試してみたい場合は

iOSアプリ「[LightBlue® Explorer](https://itunes.apple.com/us/app/lightblue-explorer-bluetooth-low-energy/id557428110)」で仮想のBLEデバイスを作成して試してみてください。無料で使えるので気軽に雰囲気がつかめると思います。

# まとめ

普段の開発でWeb Bluetoothに触れる機会は少ないと思います。ですが、ブラウザの進化とともにJSでできることがこれからも広がっていくでしょう。ブラウザが限定されてしまうこともありますが、 `次のWebで何ができるのか` 積極的にキャッチアップしていければと思います。