OmniAICreator/Qiita-1.07M huggingface dataset:
ReduxとMobXの選定観点


[この記事](https://qiita.com/Takepepe/items/8172333655442314eb55)を書いた当時、MobXは余計な複雑さが隠蔽され、とても良く目に映りました。何よりReduxにはOOPが可能なモデルが無い、という当時のReduxに対する不満を解決してくれました。(今はReduxにもモデルを持ち込む手法を選んでいるので不満はありませんが)

直近、同僚に「Redux と MobX の選択はどうすれば？」と相談されたので、その日の返答内容をまとめてみました。


## TODOサンプルだけでは測れない現実の課題

ライブラリのキャッチアップに、TODOや「+1」するカウンターで検証することはよくあると思います。ただし、これだけでは長期運用するプロダクトの検証には不十分です。 MobXは便利で簡単に始めることが出来るため、Storeを無作為に参照しあってエンバグしやすいコードが出来てしまいがちです。

Storeが数えるほどしかなく、機能も単純であれば原因を突き止めるのは容易です。しかしながら、現実は技術要件とビジネス要件が入り組みます。Store 同士のロジックが密結合してしまい、そこに依存するアプリケーションを組んでしまうと、技術負債の出来上がりです。



## Storeが密結合してきた場合

Storeが密結合してきたら、Storeの結合点を外に逃すのが得策かと思います。複数の reaction を用意して、Storeとは切り離されたレイヤーで Observable な値に対してマッピングを行います。こうすることで、各々の Store は疎結合になり、ユニットテストも容易になります。

```entry_point.js
const storeA = new StoreA()
const storeB = new StoreB()
const storeC = new StoreC()

reactions({ storeA, storeB, storeC })

```

```reactions.js
export default function ({ storeA, storeB, storeC }) {
  reaction(
    () => storeA.value,
    value => { storeC.value = value * storeB.value }
  )
  reaction(
    () => storeB.value,
    value => { storeC.value = value * storeA.value }
  )
}
```

難点は、Store が増えるほどトランザクションが追い辛くなることです。リファクタ・スケールにおいては、簡単な部類ではないと思います。普段から出来ることといえば、他の Store が別の Store の状態を直接参照しないようにすることぐらいです。

## MobXにする境界

#### 1.異なるプラットフォームでドメインモデルを共有したい

React + MobX と紹介されることが多々ありますが、両者は疎結合で MobX をドメインモデルとすることが可能です。別の view で再利用可能で、データバインディングフレームワークと比べ、ドメインモデルが切り離されています。

そのため react-dom・ReactNative でドメインモデルを共有することもなども容易です。もしこの点に魅力がなければ、Reactに固執する必要もないかもしれません。

#### 2.Storeの密結合が起こりえない

json を取ってきて SPA で記事を表示するだけ、というユースケースの場合は、Store の結合は問題にならないかと思います。非SPAの場合も同様で、MobX が最適解だと思います。

#### 3.とにかく早く ReactComponent を書き上げたい

Redux もそうですが、React とは疎結合なため、状態管理は変更可能です。ReactComponent はそのままで、状態管理だけ差し替えることが出来ます。「Store結合が複雑な大型改修が必要になったら、Reduxに乗り換える」ぐらいの心意気があれば、最初は MobX の方がシンプルに目指しているものが作れるかと思います。

### 【こんな案件だったら自分はMobXを選ぶ】

- エンドポイントによっては部分的にSPA
- メディア媒体・シンプルな投稿機能サイト
- 期間限定のプロモーションサイト
- 個人のブログ


## Reduxにする境界

#### 1.異なるプラットフォームでドメインモデルを共有したい

こちらもまた、Reactとは疎結合なのでドメインを切り離すことが出来ます。普通の使い方をすると、Reduxはデータソースの保持のみでドメインモデル不在ですが、immutable.js を導入すればOOPが可能なドメインモデルを持ち込めます。Reducer の switch 文 やボイラープレートが辛いと感じる方は、[こちら](https://qiita.com/Takepepe/items/1ce54a9564d5a6d4939d)を参考にしてみてください。私自身の直近業務では、よく見る3種のボイラープレートは一切 git commit していません。(それ相当のものはもちろんcommitしています)

#### 2.モデル同士の複雑な密結合が予想される

redux-saga は複雑だと敬遠されがちですが、非同期処理だけのものではありません。上記の様な MobXStore 密結合問題と同様に、redux-saga上でモデル間のマッピングが行えます。

一番の特徴は、そのトランザクションの組み替えが容易なこと。async/await と使い勝手が同じなので、学習コストが無駄になることが無いです。

ActionType名称を変更しても、Objectでマッピングされているため、悩み事は最小限で済みます。（redux-saga 以外に redux-observable でも可能です）

#### 3.書き捨てではなく、長期的に保守していきたい

先に述べたとおり、リファクタに強いです。後々の保守工数を鑑みても、長期運用やスケーラビリティはこちらに分があります。

### 【こんな案件だったら自分はReduxを選ぶ】

- 全エンドポイント SPA
- 機能豊富な WebBrowser アプリ
- 機能各種が密結合する ReactNative アプリ
- 複数人でのフロントエンドコード長期保守



## 最後に

- 作るもの・締め切りなどによって最適解は変わります。
- ボイラープレートが辛い、という消去法で MobX にするのはやめましょう。
- 少し工夫でボイラープレートは気にならなくなります。
- Store や Model が純粋であることは尊いです。テストが書きづらく感じたら、赤信号です。
- 両者のpros/cons を理解して最適解を選びましょう。
- もしかしたら、React以外の選択もあるかもしれません。
[memo] Windows10 のアップデート後にWifi接続が不安定になる場合の対応


# Windowsアップデート後にWifi接続が不安定になる

Windows10 にアップグレードした直後に、Wifi接続が不安定になる現象に見舞われました。
とりあえず対策をしてしばらく問題がなかったのですが、大規模なWindowsアップデートがあったあとに、同じ事象が再現することが（２回ほど）あったので、念のため対処方法の個人的なメモを残します。

## 無線LANのアダプターの詳細設定で「WMM」を無効に

おそらく不安定になるのは、該当マシンのNIC（orドライバ）が「WMM」に対応していないためだったと思われます。
ワイヤレスネットワークのアダプタオプションで「構成」→「詳細設定」で、「WMM」を無効にしました。

![adapter-setting.png](https://qiita-image-store.s3.amazonaws.com/0/97350/b24e6e21-cbeb-18b7-7d29-158069f0df7a.png)

関係ないかもしれないけど、ついでに「電力消費の最小化」も無効化しておきます。

このあたりは、違うマシンであれば異なる原因・対処方法が必要だろうと思われますが。

# VirtualBox のホストオンリーネットワークの再作成

ちなみに、Windows10へのアップグレードや、大規模Windowsアップデートの直後には、Wifiが不安定になるだけではなくなぜか VirtualBox で仮想マシンが立ち上がらなくなりました。

理由は、作成してあった「ホストオンリーネットワーク」用の仮想アダプタが削除されてしまっているかららしい。

基本は、再度ホストオンリーネットワークを作成すればよいはず。

VirtualBox の「ファイル」メニューから「環境設定」→「ネットワーク」→「ホストオンリーネットワーク」を追加（右側の「＋」ボタンのようなアイコンをクリック）。

![host-only-network.png](https://qiita-image-store.s3.amazonaws.com/0/97350/54006b6e-6d72-b416-3721-7e6a78588f83.png)

さらに、仮想マシンを選択して「設定」アイコンか、「仮想マシン」メニューから「設定」で、「ネットワーク」で「ホストオンリーネットワーク」を再登録すればよいはず。

## ホストオンリーネットワークが作れない場合

さらに「ホストオンリーネットワーク」を追加しようとしたら、しばらく時間がかかってからエラーになってしまうケースもあった（以前、１回だけ発生。直近のアップデートでは発生しなかった）。

その時には、ホストオンリーネットワーク用のアダプタ以外の、有線・無線LANのアダプタのプロパティの「ネットワーク」タブで「VirtualBox NDIS6 Bridged Networking Driver」みたいな項目がチェックされていた。

本来は、VirtualBox 用の仮想アダプタにだけチェックが入っており、有線・無線LAN用のアダプタにはチェックが入っていないのが正しいはずなので、チェックを外してから、ホストオンリーネットワークを追加できれば大丈夫だろうと思われます。

![VirtualBox-NDIS6.png](https://qiita-image-store.s3.amazonaws.com/0/97350/3ec5f730-931c-6b4b-9404-a345b2baba27.png)

（上記イメージは、ホストオンリーネットワーク用なので、チェックがついていてＯＫ。それ以外の普通のアダプタにはついていないのが正しい）

最近は発生していないので、対策されたのかもしれないですが、念のため。
Visual Studio 2017の.NET Framework を確認・追加する


# 確認・追加方法
* 「Visual Studio 2017 Installer」を起動

![image.png](https://qiita-image-store.s3.amazonaws.com/0/155206/4a7228fe-fa48-4fa7-b976-6a9c55f5017f.png)


「個別のコンポーネント」を選択

![image.png](https://qiita-image-store.s3.amazonaws.com/0/155206/0df79ca3-a7a5-5ac3-ef0e-be499f55f3bc.png)

3.5以外をすべてチェックする

![image.png](https://qiita-image-store.s3.amazonaws.com/0/155206/2330309d-72b8-2630-99d9-14fae44e01d1.png)

インストール
![image.png](https://qiita-image-store.s3.amazonaws.com/0/155206/dfe922fe-28c0-9210-683d-8734f52a4b5c.png)

新しいプロジェクトを作成し、該当の.NET Frameworkが利用できることを確認
![image.png](https://qiita-image-store.s3.amazonaws.com/0/155206/bb2f9ca1-879f-71f2-2fe0-e27a5dc06c8f.png)
[PUSH通知]APNS TokenをFCM(Firebase Cloud Messaging)のTokenに変換

iOSアプリのAPNSTokenをFCM(Firebase Cloud Messaging）のToken(registrationID)に変換するツールを作ったので公開してみます。ニッチなニーズかもしれないが、、、

https://hikarusato.github.io/apnstoken-to-fcmtoken/
[![APNS TO FCM TOKEN](https://qiita-image-store.s3.amazonaws.com/0/37373/aa46cb31-57c1-b981-ca4d-f129b2dc00cf.png)](https://hikarusato.github.io/apnstoken-to-fcmtoken/)

#作った経緯
iOSアプリのPUSH通知をFCMで行うようにするとAndroidアプリと一緒にPUSH通知関連の管理ができるし１リクエストで複数人にプッシュ通知できるし、かなり便利だと思います。しかも、iOSアプリにFirebaseのSDKを組み込む前にできてしまう。
でも、それ（iOSアプリにFirebaseのSDKを組み込む前にFCMでプッシュ通知）をやるためには下記のAPIを利用する必要があり、次のような制限があります。
https://developers.google.com/instance-id/reference/server#create_registration_tokens_for_apns_tokens

* GUIで変換するツールが無い（もしかしたら、私の探し方が悪いだけ存在しているのかもしれませんが）ので、エンジニア以外に変換をお願いできない。
* 1度のAPIリクエストにのせられるAPNS Tokenは100個まで。

これらを解消するため作成しました。

#利用対象
ニッチだと思いますが、下記のいずれかだと思います。

* iOSアプリにFirebaseのSDKを組み込む前にFCMでプッシュ通知がしたい。
* あるいは、FirebaseのSDKを組み込んだがFCMのToken(registrationID)をサーバーのDBに保存できていない。

#使い方
１. FCM Server KeyのところにFirebaseのプロジェクトの設定->クラウドメッセージング->サーバーキーを入力。
２. iOSアプリのBundleIDを入力。
３. Sandboxの場合チェックオンする。よくわからない時はチェックオフが大体正しいです。
４. APNSTokenが改行区切りで入ったUTF8のcsvファイルをドラッグ&ドロップする。

```csv:APNSTokenリスト内容例:
test001a775fa3f12d4c714058a799f47ca5aa1028839e874f1080ceb8c4fe3b
test002cc4d396422d1a257b93f3bc0584de40fa961f4cfff09112a6f89890c9
test0037f30c67ce13756b28c90b2a2a2c4f4602a6032c4c58ec494112e8c3b7
test00470cc1c7885356c22ee185dba8c4c292906fb2652a1a0c09a0bae26119
test005a5378d2e78268e4a2975a9e166b137f8dd757b9f52130edeb1fc766a1

```
５. [START CONVERT]ボタンをクリックする。下記のような感じでLogの部分に進捗が表示されて、終わったらファイル保存ダイアログが開きます。
![apns_to_fcm.gif](https://qiita-image-store.s3.amazonaws.com/0/37373/72dd92be-9a83-742c-1810-2753fe66c0fe.gif)
作成されるcsvファイルには、

 * １カラム目には変換後のFCMToken(RegistrationID)
 * 2カラム目には変換前のAPNSToken

が入っています。
テキストボックスでの検索機能


Private Sub 抽出_Click()
Dim fstr, flg
    
    fstr = ""
    flg = 0
    
    If Len([Forms]![F案件管理]![会社名テキスト]) > 0 Then
        If flg = 1 Then fstr = fstr & " and "
        fstr = "会社名 Like '*" & [Forms]![F案件管理]![会社名テキスト] & "*'"
        flg = 1
    End If
    
    If Len([Forms]![F案件管理]![担当者名テキスト]) > 0 Then
        If flg = 1 Then fstr = fstr & " and "
        fstr = "担当者名 Like '" & [Forms]![F案件管理]![担当者名テキスト] & "*'"
        flg = 1
    End If
    
    If Len([Forms]![F案件管理]![紹介者名テキスト]) > 0 Then
        If flg = 1 Then fstr = fstr & " and "
        fstr = "紹介者名 Like '*" & [Forms]![F案件管理]![紹介者名テキスト] & "*'"
        flg = 1
    End If


    If flg = 1 Then
        Forms!F案件管理.Filter = fstr
        Forms!F案件管理.FilterOn = True
    End If
End Sub
tensorflow1.4.1 を可能な最適化をオンにしてMacにインストールする

# TLDR
ソースから更の(NVIDIA-GPU等のない)Macにビルドする
https://www.tensorflow.org/install/install_sources を参考のこと
keras がそのうちにmacのGPUで動く何かのエンジンに対応するらしいの楽しみだけどエンジンの名前忘れた…。

# commands
```
# ソース取得
git clone https://github.com/tensorflow/tensorflow && cd tensorflow

# ビルドに先立って必要なツールのインストール
brew cask install caskroom/versions/java8
brew install bazel coreutils
pip3 install numpy six wheel

# `which python3` / 選択肢は XLA-JIT 以外デフォルトでは {No,<default>} でよさそう
#                 / 数十分立ってからビルド失敗とかされてきつい
./configure 
bazel build --config=opt //tensorflow/tools/pip_package:build_pip_package

# ビルドしたものを pip で入れる
bazel-bin/tensorflow/tools/pip_package/build_pip_package /tmp/tensorflow_pkg
pip install /tmp/tensorflow_pkg/tensorflow*.whl
```

# `./configure` 時のログ

```
You have bazel 0.9.0-homebrew installed.
Please specify the location of python. [Default is /usr/bin/python]: /usr/local/bin/python3


Found possible Python library paths:
  /usr/local/Cellar/python3/3.6.4/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages
  /Users/murata/.homesick/repos/dotfiles/module/python3
Please input the desired Python library path to use.  Default is [/usr/local/Cellar/python3/3.6.4/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages]

Do you wish to build TensorFlow with Google Cloud Platform support? [Y/n]: n
No Google Cloud Platform support will be enabled for TensorFlow.

Do you wish to build TensorFlow with Hadoop File System support? [Y/n]: n
No Hadoop File System support will be enabled for TensorFlow.

Do you wish to build TensorFlow with Amazon S3 File System support? [Y/n]: n
No Amazon S3 File System support will be enabled for TensorFlow.

Do you wish to build TensorFlow with XLA JIT support? [y/N]: y
XLA JIT support will be enabled for TensorFlow.

Do you wish to build TensorFlow with GDR support? [y/N]: n
No GDR support will be enabled for TensorFlow.

Do you wish to build TensorFlow with VERBS support? [y/N]: n
No VERBS support will be enabled for TensorFlow.

Do you wish to build TensorFlow with OpenCL SYCL support? [y/N]: N
No OpenCL SYCL support will be enabled for TensorFlow.

Do you wish to build TensorFlow with CUDA support? [y/N]: N
No CUDA support will be enabled for TensorFlow.

Do you wish to build TensorFlow with MPI support? [y/N]: N
No MPI support will be enabled for TensorFlow.

Please specify optimization flags to use during compilation when bazel option "--config=opt" is specified [Default is -march=native]:


Add "--config=mkl" to your bazel command to build with MKL support.
Please note that MKL on MacOS or windows is still not supported.
If you would like to use a local MKL instead of downloading, please set the environment variable "TF_MKL_ROOT" every time before build.

Would you like to interactively configure ./WORKSPACE for Android builds? [y/N]: N
Not configuring the WORKSPACE for Android builds.
```
Railsのmigrateファイルの名前を連番値に変更

#変更方法

```diff:config/application.rb
+ config.active_record.timestamped_migrations = false
```

20130603012345_create_hoge.rbではなく
001_create_hoge.rbの様なファイルが作成される

#警告

Rails 2.1 以前のバージョンでは、マイグレーションファイルは「001_create_hoge.rb」のように単純な連番で管理されており、現在のマイグレーション番号については schema_info というテーブルで最後に実行された数値だけを管理していました。
そのため、リポジトリ等を用いて複数の開発者が作業を行う場合、簡単にバージョンの衝突が発生しました
...
現在のマイグレーションファイルはどのように管理されているのか。
まずネーミングですが「20130603012345_create_hoge.rb」のようにタイムスタンプを用いるように変更されています。
秒数まで同じタイミングでマイグレーションが作成された場合は相変わらず衝突しますが、以前の数字を用いる方式と比べればずっと可能性は低くなっています。
...
過去のバージョン管理を使いたい場合 config/application.rb で次のように記載すればいいようです。
config.active_record.timestamped_migrations = false
上で述べたようにデメリットの多い方式であるため、できる限り使わない方がいい事は重ねて述べておきます。
glsl 色々なハートの描き方

# はじめに
glslでハートを描くには沢山のアプローチがあります。
この記事ではglslでの色々なハートの描き方の紹介と、自分で作ったハートの描画方法を紹介したいと思います。

# オリジナルハート1

![hart.png](https://qiita-image-store.s3.amazonaws.com/0/135381/b7ba986f-a310-8593-4c3b-8eadbafbafc9.png)


```glsl
precision mediump float;
uniform vec2  m;       // mouse
uniform float t;       // time
uniform vec2  r;       // resolution
uniform sampler2D smp; // prev scene

void main(void){
	vec2 p = (gl_FragCoord.xy * 2.0 - r) / min(r.x, r.y);
	p.x-=sign(p.x)*p.y*.4;
	float l = length(p);
	l=step(0.,.8-l);
	gl_FragColor = vec4(vec3(l), 1.0);
}
```

https://goo.gl/TzbPuQ

glslで遊んでいて偶然発見したハートで式は割とシンプルです。
ちゃんと、座標の中心から等間隔になっています。

![dheart.png](https://qiita-image-store.s3.amazonaws.com/0/135381/60db635f-e0bc-d30f-6831-b8866f846247.png)

 ハートのくぼみ部分を調整できないのが難点ですね。

# オリジナルハート2

* [GLSLレイマーチング研究_距離関数について勉強してみた16(Heartの関数を作ってみた_その2)](https://qiita.com/muripo_life/items/f24408ca1d06eb0658e3)
* [美しすぎるハートの数式](http://itchyny.hatenablog.com/entry/20130214/1360847516)

の記事を参考に2Dのハートを描いてみたのがこちらです。

![heart2.png](https://qiita-image-store.s3.amazonaws.com/0/135381/afe297cf-ea9e-492d-a3a4-d8bf06ca317c.png)

https://goo.gl/LYDJxm

```glsl
precision mediump float;
uniform vec2  m;       // mouse
uniform float t;       // time
uniform vec2  r;       // resolution
uniform sampler2D smp; // prev scene

float heart(vec2 p){
 return pow(p.x*p.x+p.y*p.y-1.,3.)-p.x*p.x*p.y*p.y*p.y;
}

void main(void){
 vec2 p = (gl_FragCoord.xy * 2.0 - r) / min(r.x, r.y); // 正規化
 float l = 1.-step(0.,heart(p*1.3));
 gl_FragColor = vec4(vec3(.95,.4,.4)*l, 1.0);
}
```
数式を直接ぶち込んで無理やり作った為、疑似ディスタンスフィールドになります。

(x^2+y^2-1)^3 - x^2*y^3 = 0

として左辺だけを持って来れば作れるので、数式からのコンバートは非常に楽です。

疑似ディスタンスフィールドは距離を変えると大きく図形を歪めます。
ディスタンスフィールドを塗りに使えないのと拡大縮小が出来ないのが難点です。(pによる図形の拡大縮小は出来る)
ただ、疑似ディスタンスフィールドをディスタンスフィールドに変換できそうな気がしています。

![dheart2.png](https://qiita-image-store.s3.amazonaws.com/0/135381/05ab3175-6459-dde7-5317-5197eaa47b95.png)

https://goo.gl/TeS2jv

(x^2+y^2-1)^3 - x^2*y^3が作り出すディスタンスフィールドは、ハートとは似てもつかない形に見えるのですが、値が0の境界がハート型になっています。その代わり、通常のディスタンスフィールドと違って0から急激に1に変化していうので、塗りに活用することができません。

# 色々なハートの描き方
* [GLSLレイマーチング研究_距離関数について勉強してみた16(Heartの関数を作ってみた_その2)](https://qiita.com/muripo_life/items/f24408ca1d06eb0658e3)
* [iqさんの3Dのハート](https://www.shadertoy.com/view/4lK3Rc)
* http://glslsandbox.com/e#38545.0
* http://glslsandbox.com/e#42120.0

# 参考
* [美しすぎるハートの数式](http://itchyny.hatenablog.com/entry/20130214/1360847516)
ブラウザからAmazon Cognitoのユーザーを切り替えるとLogins don't matchと怒られた

# 経緯

`amazon-cognito-identity-js`を使いブラウザからAmazon Cognitoで認証してDynamoDBにアクセスできるところまでを確認。
その後ログアウトして、別のユーザーでログインしようとしたところ次のエラーが発生した。

```
Logins don't match. Please include at least one valid login for this identity or identity pool
```


# 原因

AWS認証情報取得が成功する時のシーケンスはこんな感じ。ユーザー認証(Login)あたりは簡略化している。

![Cognito Seq.png](https://qiita-image-store.s3.amazonaws.com/0/219274/da996149-6a8a-6ea1-ad6b-9570993cb10a.png)

エラーが発生した際はLoginの後にGetIdを行わずにGetCredentialsForIdentityを行って400(Bad Request)が返ってくる。

ではなぜGetIdが省略されてしまったのか？

`amazon-cognito-identity-js`を使うと`CognitoUser`の`signOut()`を呼び出してもローカルストレージにはIdentityIdが残ったままである。そのため別ユーザーでLoginしてもIdentityIdが残っていると判断されて`GetId`が省略されてしまう。


# 対処方法その１

http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/CognitoIdentityCredentials.html#constructor-property

`AWS.CognitoIdentityCredentials`のコンストラクタの説明を見ると`Examples`の中に次の記述がある。

> // optional, only necessary when application runs in a browser
> // and multiple users are signed in at once, used for caching
> LoginId: 'example@gmail.com'

ブラウザで複数ユーザーがサインインする場合は必要だと書いている。。。

というわけで早速`AWS.CognitoIdentityCredentials`の作成時に`LoginId`を指定できるようにしてみる。

```js
function createCognitoIdentityCredentials(session, loginId) {
    var params = {
        IdentityPoolId: 'ap-northeast-1:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
        LoginId: (loginId) ? loginId : undefined,
        Logins: {
            'cognito-idp.ap-northeast-1.amazonaws.com/ap-northeast-1_xxxxxxxxx': session.getIdToken().getJwtToken();
        },
    };
    return new AWS.CognitoIdentityCredentials(params);
}
```

実際に動かすと`LoginId`の有無でIdentityIdをローカルストレージに保存する際のKeyが変化する。

|LoginId|key                                                 |
|:-----:|:----------------------------------------------------|
|なし   |`aws.cognito.identity-id.<identity_pool_id>`         |
|あり   |`aws.cognito.identity-id.<identity_pool_id><LoginId>`|

IdentityIdを保存するKeyがユーザーごとにユニークになるため、ログインするユーザーが変わっても他人のIdentityIdを間違って使ってしまうことがなくなる。

例ではメールアドレスになっているけれど、ユーザーごとにユニークな値であれば問題ないと思われる。


# 対処方法その２

サインアウトしたのにローカルストレージにIdentityIdが残っているのが悪い！！！

ということで、`CognitoIdentityCredentials`の`clearCachedId()`をサインアウト時に呼び出すことでローカルストレージを綺麗にする。

```js
function signOut() {
    var cognitoUser = userPool.getCurrentUser();
    if (cognitoUser != null) {
        if (AWS.config.credentials && AWS.config.credentials.clearCachedId) {
            AWS.config.credentials.clearCachedId();
        }
        cognitoUser.signOut();
    }
}
```

その1、その2のどちらかを行えばよい。両方を行ってもよい。


# ライブラリのバージョン

ライブラリのバージョンによって差があるかもしれないので覚え書き。

```
    "amazon-cognito-identity-js": "^1.28.0",
    "aws-sdk": "^2.171.0",
```
ろんりについてまとめる

## はじめに

この記事は「ろんりと集合」という中内伸光さんの本を参考に記述しています．
この本で勉強をしていて、大事なことをまとめようとしています．
この本の引用を多少用いています．
この本の本質的なことはこの記事からは確認できません．

$ \lnot (完成) \lor \lnot \lnot (未完成) $

## ろんり

### 文の構造を記号化すると、文の構造を把握しやすくなる

* 思考の節約
  
### 記号論理学

* 命題論理学
    * 「〜である．」
* 述語論理学 
    * 「すべての〜、ある〜」

### 論理について

* 「対象としての『論理』」
* 「『論理』を議論するための『論理』」（メタ論理）
   
### 命題

* 「客観的に正しいか正しくないかが判断できる主張」
    * 誰が見ても「正しい」と判断できる主張
    * 誰が見ても「正しくない」と判断できる主張

### 真理値

* 「正しい」ことを「真(1)である」
* 「正しくない」ことを「偽(0)である」

## 真理値表

### NOT
$ \lnot p $

$p$|$ \lnot p $
:-:|:-:
1|0
0|1

### AND

$ p \land q $

$p$|$q$|$ p \land q $
:-:|:-:|:-:
1|1|1
1|0|0
0|1|0
0|0|0

### OR

$ p \lor q $

$p$|$q$|$ p \lor q $
:-:|:-:|:-:
1|1|1
1|0|1
0|1|1
0|0|0

### 同値

同じものではないけれど、同じと見なしたい動機がある

$ p \equiv q$

### 反射法則

二重否定は元の命題と同値

$ \lnot \lnot p \equiv p $

### 結合法則

どこから計算しても同じ

p|q|r|$ p \land q $|$ (p \land q) \land r $|$ q \land r $|$ p \land (q \land r) $
:-:|:-:|:-:|:-:|:-:|:-:|:-:
1|1|1|1|1|1|1
1|1|0|1|0|0|0
1|0|1|0|0|0|0
1|0|0|0|0|0|0
0|1|1|0|0|1|0
0|1|0|0|0|0|0
0|0|1|0|0|0|0
0|0|0|0|0|0|0


ANDだけでなく、ORについても結合法則が成り立つ．
* $ (p \land q) \land r \equiv p \land (q \land r) $
* $ (p \lor q) \lor r \equiv p \lor (q \lor r) $

記号論理では、ある法則が成り立つとき、
「その法則の$\land$を$\lor$に、そして、$\lor$を$\land$に置き換えた法則が成り立つ」
原理、これが双対性．（２つのことがら・概念が互いに鏡で映し合っている対称性がある状況）


## 命題論理の7つの法則

### 1. 反射法則

二重否定は元の命題と同値

$ \lnot \lnot p \equiv p $

### 2. ベキ等法則

AND、ORを何回繰り返しても同値

1. $ p \land p \equiv p $
2. $ p \lor p  \equiv p $

### 3. 交換法則

ひっくり返しても同値

1. $ p \land q \equiv q \land p $
2. $ p \lor  q \equiv q \lor  p $

交換法則が成り立つ場合の方が少数
* 爪を切って、爪を研ぐ．
* 爪を研いで、爪を切る．

### 4. 結合法則

どこから計算しても同値

$ (p \land q) \land r \equiv p \land (q \land r) $
$ (p \lor q) \lor r \equiv p \lor (q \lor r) $


### 5. 分配法則

分配しても同値

1. $ p \land (q \lor  r) \equiv (p \land q) \lor  (p \land r) $
2. $ p \lor  (q \land r) \equiv (p \lor  q) \land (p \lor  r) $

左からも右からも分配できる．
$ (p \lor q) \land r $

### 6. 吸収法則

同値変形の小道具

1. $ p \land (p \lor  q) \equiv p $
2. $ p \lor  (p \land q) \equiv p $

p|q|$ p \lor q $|$ p \land (p \lor q) $|$ p \land q $|$ p \lor (p \land q) $
:-:|:-:|:-:|:-:|:-:|:-:
1|1|1|1|1|1
1|0|1|1|0|1
0|1|1|0|0|0
0|0|0|0|0|0

吸収法則を用いいなければ、簡単な式にできないものもある．
(分配法則、ベキ当法則)
$ p \land (p \lor q) \equiv (p \land p) \lor (p \land q) \equiv p \lor (p \land q) $ 
じつはこれはPと同値ですけどね．

### 7. ド・モルガンの法則

「否定の必須道具」

1. $ \lnot(p \land q) \equiv \lnot p \lor \lnot q $
2. $ \lnot(p \lor q) \equiv \lnot p \land \lnot q $

## 同値変形

- 恒真命題 : $I$
    - 真理値を1しか取らない命題
- 恒偽命題 : $O$
    - 真理値を0しか取らない命題

$\lnot I = O$
$\lnot O = I$

### 恒真命題の性質

1. $ p \land I \equiv p $
2. $ p \lor  I \equiv I $

### 恒偽命題の性質

1. $ p \land O \equiv O $
2. $ p \lor  O \equiv p $

恒真命題と恒偽命題は双対的

### 矛盾法則

$ p \land \lnot p \equiv O $

### 拝中法則

$ p \lor \lnot p \equiv I $



継続中ですー．

## 参考資料さん
[「ろんりと集合」　著:中内伸光](https://www.amazon.co.jp/%E3%82%8D%E3%82%93%E3%82%8A%E3%81%A8%E9%9B%86%E5%90%88-%E4%B8%AD%E5%86%85-%E4%BC%B8%E5%85%89/dp/4535786410)
pythonでポアソン関数の実装

#ポアソン分布とは

**CVなど一定の時間内(1週間や1ヶ月)に起こるイベントについての分布です！
ごく稀に起こる事象の確率分布を示します**

#pythonによるポアソン分布を作る関数の実装


ある一定の時間で平均avg回起こる事象があって、それがevent回起こる可能性を調べる関数を書きます！

```py3

#自然対数の底eをmathライブラリから呼ぶため、importします！
import math

#使いやすいように、どういった関数か表記します。
print("このファイルはポアソン関数を使って特定のイベントが起こる可能性をパーセントで示します。")

#標準入力を使います。
avg, event = map(float, input().split())

def poisson(avg, event):

    # ポアソン関数の実装と、パーセント表記にするために100を書けます
    x = ((avg ** event)*(math.e ** -(avg))) / math.factorial(event)*100

    #パーセントを文字列に直して、小数点以下2桁まで表示します。
    #x自体をstringにすると、"怒らない確率"を計算できないので、それはやめました！
    # math.factorialは階乗を求める関数です！
    print( str("{0:.2f}".format(x)) + "パーセントの確率で起こります!")

    #怒らない確率
    print("おこらない確率も表示しますか? y/n")

    ans = input()
    if ans == 'y':
        x = 100 - x
        print(str("{0:.2f}".format(x)) + "パーセントの確率で起こりません!")

poisson(avg, event)


```

#早速計算してみます！


####**震度7以上の自身は21年間で5回起きています。(一年で平均5/21回 = 0.2380...)1年間で起こる確率は？**

```py3

yossyMBP:Python yossy$ python poisson.py
このファイルはポアソン関数を使って特定のイベントが起こる可能性をパーセントで示します。
0.2380 1
18.76パーセントの確率で起こります!
おこらない確率も表示しますか? y/n
n
```

####**明日震度7以上の地震が起こる確率は？**

```py3

#21年に365を掛けることで日にち換算にする
>>>5/(21*365)
0.00065231...
yossyMBP:Python yossy$ python poisson.py
このファイルはポアソン関数を使って特定のイベントが起こる可能性を示します。
0.00065231 1
0.07パーセントの確率で起こります!
おこらない確率も表示しますか? y/n
y
99.93パーセントの確率で起こりません!
```

####**10年間で7回雷が落ちた地域で明日雷が落ちる確率**

```py3

365を掛けることで日にち換算にする
>>> 7/(10*356)
0.001966...
yossyMBP:Python yossy$ python poisson.py
このファイルはポアソン関数を使って特定のイベントが起こる可能性をパーセントで示します。
0.001966 1
0.20パーセントの確率で起こります!
おこらない確率も表示しますか? y/n
n
```

#おわりに

もっと綺麗に書くことが出来る点があればおしえていただけますと幸いですm(__)m！
Wildfly10でShift_JISが意図せず文字化けする

POSTリクエストを投げると意図せず特定の文字が文字化けする事象が発生したので備忘録として残しておきます。

## 参考記事
http://odasusu.hatenablog.com/entry/20071016/1192537675
https://issues.jboss.org/browse/JBEAP-5852?_sscc=t
##問題事象
POSTリクエストのボディ内部や、クエリ文字列付きのGETリクエストなどブラウザからURIエンコードされた文字列をJava側でデコードする際、一部の文字列が適切にデコードできない。Wildfly（Undertow）はservletのAPIでgetParameterなどから値を取得した場合、URIデコードにJDKの標準API（java.net. URLDecoder）を利用していて、Shift_JISでデコードした場合にブラウザのエンコード内容と整合性が取れておらず、意図した通りにデコードできないという事象です。

デコード部分を制御可能であれば問題ありませんが、Strutsや派生FWなど自動的にデコードしてくれるような仕組みとなっている場合、ライブラリ（Jarファイル）部分に修正をいれる必要があります。

##解決案
UndertowのURLデコード部分をApache Commons Codecなど、別ライブラリのURLデコードに書き換える
##事象例
1."テストアイウエオ"文字列をPOSTリクエストで送付する
2.エンコードされて受け取った文字列を2種類のAPIでデコードして結果を見てみる
3.以下の通り、一方はエンコード前とは異なる文字列となっています

```html:HTMLソースとPOST内容
<form name="postForm" method="post" action="" accept-charset="Shift_JIS">
    <input type="text" name="test" value="テストアイウエオ" />
    <input type="submit" value="submit" />
</form>
```

エンコードした文字列
![post.png](https://qiita-image-store.s3.amazonaws.com/0/110457/d54b147d-91ad-cc82-0b19-d248133cd78b.png)
test=%83e%83X%83g%83A%83C%83E%83G%83I


```java:NGケース（java.net.URLDecoder）
import java.net.URLDecoder;
System.out.println(URLDecoder.decode("%83e%83X%83g%83A%83C%83E%83G%83I","Shift_JIS"));
// 出力「�e�X�g�A�C�E�G�I」
```

```java:OKケース（org.apache.commons.codec.net.URLCodec）
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.net.URLCodec;
try {
    URLCodec codec = new URLCodec("Shift_JIS");
    System.out.println(codec.decode("%83e%83X%83g%83A%83C%83E%83G%83I", "Shift_JIS"));
} catch (DecoderException e) {
    e.printStackTrace();
}
// 出力「テストアイウエオ」
```
## 修正対象クラス
WildflyのURLデコードは、Undertowで実装されていてjavaソースは公式のgithubにあります。POSTリクエスト受け取り時の処理に対して（影響調査は別途必要ですが）デコード部分を修正、ビルド＆Jarファイルを差し替えることで回避できます。ライブラリを書き換えることで別の問題が出る危険性もありますよね。。
修正対象クラス：[FormEncodedDataDefinition ](https://github.com/undertow-io/undertow/blob/master/core/src/main/java/io/undertow/server/handlers/form/FormEncodedDataDefinition.java)

追記
Undertowのバージョンを1.4.0（wildfly10バンドル版）からバージョンアップすれば修正済みの既知問題でした。
https://issues.jboss.org/browse/UNDERTOW-818?_sscc=t
ReactNativeの基礎基本


## このまとめを作ったモチベーション
他の言語など平行で作業をしていると、ReactNativeに戻って来たときに忘れてしまっていて、いろいろな概念を何度も調べて、思い出しながら進める羽目になったため

## このまとめでやりたいこと
何もかも忘れて呆けた状態でReactNativeに戻って来たとしても、1ページで基本概念を思い出せるようにしたい

## Component

### Componentとは
状態(state)を持ったビュー(View)のこと。Reactの基本単位であり、Reactでは複数のComponentを組み合わせてUIを作成する

### Componentのライフサイクルとは
全てのComponentが持っている、生成から破棄までの一連のサイクル

### なぜComponent単位で扱うのか
JQueryなど従来のJavaScriptフレームワークのように、部分的な変更だけで全ての画面を破棄し、生成し直すのは高コストだから（これを従来のDOMと区別して、仮想DOMという)

##propsとstate
### propsとstateとは
それぞれ役割の異なるオブジェクト
### なぜpropsとstateを使うのか
Component間で値のやり取りをするため
### propsとstateの違いとは
#### props
+ 主にComponentの外部から渡された初期値を受け持つオブジェクト
+ 一度渡された値は内部から変更はできない定数
+ Componentを呼び出す時にJSXの属性値として渡す
+ 通常Componentが生成されてから破棄されるまで一貫した値を持つ
+ 別の値を代入したい場合は、一度Componentを破棄して再生成するか、親要素から新しい値を与えることになる

#### state
+ Component内部で管理される変数
+ Component内外でのアクションに応じて頻繁に変更される
+ ES6の文法ではコンストラクタの内部で初期値を設定し、以後専用の関数を通じて変更される
+ 初期値はプログラマが事前にハードコードすることもあれば、propsを通じて外部から与えられることもある
+ 一度Componentが作成されたあとは、stateの変化に応じてDOM要素が生成・破棄される
+ ReactのViewは基本的にstateに依存している
モノリスの分割

# 第5章　モノリスの分割
## 接合部:境界づけられたコンテキスト
- 接合部(seem)
    - [レガシーコード改善ガイド]( https://www.amazon.co.jp/%E3%83%AC%E3%82%AC%E3%82%B7%E3%83%BC%E3%82%B3%E3%83%BC%E3%83%89%E6%94%B9%E5%96%84%E3%82%AC%E3%82%A4%E3%83%89-%E3%83%9E%E3%82%A4%E3%82%B1%E3%83%AB%E3%83%BBC%E3%83%BB%E3%83%95%E3%82%A7%E3%82%B6%E3%83%BC%E3%82%BA-ebook/dp/B01AN97W08)
- 組織に存在する、高水準の「境界づけられたコンテキスト」を特定する
    - 例：カタログ、経理、倉庫、レコメンデーション
- 上記のコンテキストに従いコードを分割していく
    - 小規模なコードベースで半日、１００万行を超えるコードベースでは数週間から数ヶ月かかることも

## データベースの分割
- 外部キー関係の削除
    - クエリの呼び出しが増加する懸念
        - その箇所をどの程度高速にする必要があるのか
    - 外部キー制約は、データベースレベルでなくサービスが管理する制約になる
- 共有静的データ
    - データベースに格納されたマスタ系のデータ
        - 国コードなど、都道府県もこれに当たる
    - このレコードのためにDBで結合するよりも、サービスごとに静的な列挙型データをコードとして持つほうが理にかなっている
    - 共有データを1つの独立したサービスとする選択肢もあるが、多少やり過ぎ
- 共有データ
    - 顧客など
    - 共有される別個のサービスにしてしまう
- 共有テーブル
    - 在庫など
    - カタログ品目と在庫を別テーブルにする
        - カタログサービスと倉庫サービスでそれぞれを管理できるようになる
- [データベースリフファクタリング](https://www.amazon.co.jp/%E3%83%87%E3%83%BC%E3%82%BF%E3%83%99%E3%83%BC%E3%82%B9%E3%83%BB%E3%83%AA%E3%83%95%E3%82%A1%E3%82%AF%E3%82%BF%E3%83%AA%E3%83%B3%E3%82%B0-%E3%82%B9%E3%82%B3%E3%83%83%E3%83%88-W-%E3%82%A2%E3%83%B3%E3%83%96%E3%83%A9%E3%83%BC/dp/4894715007/ref=sr_1_1?s=digital-text&ie=UTF8&qid=1514546986&sr=8-1&keywords=%E3%83%87%E3%83%BC%E3%82%BF%E3%83%99%E3%83%BC%E3%82%B9%E3%83%AA%E3%83%95%E3%82%A1%E3%82%AF%E3%82%BF%E3%83%AA%E3%83%B3%E3%82%B0)
    - 下記の順序でサービスを分割していく
        - モノリシックサービス、単一スキーマ
        - モノリシックサービス、スキーマ分割
        - サービス分割、スキーマ分割
    - スキーマ分割が妥当だと判断できた段階でサービスを分割できる
        - 妥当でないと判断された場合でも、コードならより簡単に切り戻すことができる

## トランザクション境界
- サービス分割により、たとえば発注プロセスが単一トランザクションで処理できなくなる
    - いかに一貫性の保たれた状態とするか
- あとでリトライ
    - 将来的に結果整合性を担保する
- 操作全体の中止
    - 補正トランザクション（補償トランザクション）
        - 補正トランザクションが失敗したときを考慮する必要がある
            - 補正トランザクションのリトライ
            - 管理者による保守画面、自動化プロセス
            - 監視
        - 一貫性を保つべき操作が増えるごとに把握が困難になっていく
- 分散トランザクション
    - トランザクションマネージャによりオーケストレーションする
    - 2フェーズコミット
        - 投票フェーズ
            - 分散トランザクションの参加者（コホート）が、トランザクションマネージャにローカルトランザクションを進められるか投票する
            - 全参加者「はい」の場合は、トランザクションマネージャがコミットの指示
            - ひとつでも「いいえ」であれば、全参加者にロールバックの指示
        - コミットフェーズ
    - トランザクションマネージャがダウンしたら、保留中のトランザクションは決して完了しない
    - 保留中のトランザクションはロックを保持する
        - スケーリングが困難
    - アルゴリズムが複雑になるので、独自のアルゴリズムを実装することは勧めません（！）
    - おそらく使わない方がいい
- どうしたらいいか
    - 分割しなくていい方法を考える
    - 本当に同一トランザクションにする必要があるか
        - 結果整合性の概念で対応できれば、構築やスケーリングが簡単になる場合が多い
    - 難しいから、本当に精一杯やれ
    - 技術的視点でなく、具体的な概念（処理中の注文、のような）を作成して管理することを考える

## レポート
- スキーマが分割されてしまうと、レポートの作成が難しくなる
- 目的に適った方法で対応することが必要になる
- ※細かくは割愛

## 変更のコスト
- 小さな変更を漸進的にやる
- コードベース内のコードの移動：コスト小
- データベースの分割
    - 作業量大
    - ロールバックも複雑
- サービス間の結合を解く変更
    - 作業量大

## まとめ
- コンテキスト境界を見定める
- コンテキスト境界に従ってDBの結合を解いていく
- DBの分割、サービスの分割の順に進める
- トランザクションの分割は、特に影響が大きい
    - 結果整合性を担保できる程度の分割にする
    - 担保できる範囲から漸進的にすすめる
VRでルームスケールに縛られない移動方法を色々考えた

VR機器側で設定したルームスケールを超えての移動や、立位モードでシーン内での連続的な移動をしたい場合の移動方法を考えて作ってみたものが溜まってきたのでまとめた。

結局は視点を安定させて移動することが大切だという当たり前の結論になった。

※画像クリックで動作中の動画に飛べます


##Wiiボードを使って重心を使っての移動
Wiiボードをコントローラーに、重心方向に移動するものを最初に作った。
360度すべての方向に移動するもの、スケボーのように左右に動き、前後で曲がる角度の決まるものの2種類を作った。

[![重心方向に移動するVR-360度の移動](http://img.youtube.com/vi/Ei1YynfgMPg/0.jpg)](http://www.youtube.com/watch?v=Ei1YynfgMPg)

360度全ての方向に移動するようにすると視点が安定しないため、酔いが激しい。


[![重心方向に移動するVR-スケボー型の移動](http://img.youtube.com/vi/e0zbk-73_ZU/0.jpg)](http://www.youtube.com/watch?v=e0zbk-73_ZU)

スケボーと同じように左右でで曲がる角度、前後で進む方向を決めるようにし、視点全体がスケボーと一緒に動くようにした。
こちらは友人数人に体験してもらい、感想を聞いた。実物のスケボーのように台が傾くことがないため違和感を感じたり、倒れかけたりしていた。



##椅子に座り、Viveコントローラーを使った移動
上記二つから視点が安定することを大前提に、安定する体勢で移動を実装できたらよいと考えたため、イスに座って移動できるものを作った。

[![コントローラー方向に移動するVR](http://img.youtube.com/vi/r7Ew80hjopg/0.jpg)](http://www.youtube.com/watch?v=r7Ew80hjopg)

左手のコントローラーのトリガーを引くとコントローラーの向きに進む。
こちらも友人数人に体験してもらい、感想を聞いた。
操作系が直感的だったのかVR体験を初めてした人でも動き回ることが出来ていた。
酔いも感じていないようだったが、壁にぶつかった際に急停止すると酔うとのことであった。


##まとめ
* 視点を安定させることが重要(ちなみにOculusのガイドラインにも書いてある)
* 重心での移動は現実的なフィードバックが出せないと転倒の危険性がある
* やっぱり座っていると安定する
Hyperapp, React, Vue.jsで同じサンプルアプリを作ってサイズを比較してみた

私は脱[jQuery](https://jquery.com/)(脱DOM操作)したい系の者で、 [React](https://reactjs.org/), [Vue.js](https://jp.vuejs.org/index.html), [Hyperapp](https://hyperapp.js.org/) については初心者です。サンプルコードは公開しておりますが、正確さは保証いたしません。この記事は参考程度に読んで頂ければと思います。

# 作ったもの
以前に React, Vue.js で製作した[Raspberry Piの無線LANをmicroSDで簡単に設定するためのツール](https://qiita.com/mascii/items/a43d71572e1919e56398)を Hyperapp でも作ってみました

<img width="480" alt="wpa-supplicant-conf-tool.png" src="https://qiita-image-store.s3.amazonaws.com/0/137045/67e67a87-27f1-2aef-43a5-739d6e0755d7.png">

ツールへのリンク: https://mascii.github.io/wpa-supplicant-conf-tool/

このツールはブラウザ上でSSIDとパスフレーズを入力してリストに追加するだけで簡単にRaspberry Piの無線LAN設定ファイル(`wpa_supplicant.conf`)を作成でき、これをPCでRaspbianの入ったMicroSDに書き込んでおくことでRaspberry Pi起動前から無線LANの設定ができるものです。

(Raspberry Piをお持ちの方には、一応実用的なツールとして使えるものとなっており、「サンプルアプリ」ではないのかもしれませんが、ToDoリストに毛が生えた程度のアプリのため、タイトルに「サンプルアプリ」というキーワードを入れております)

## リポジトリ
https://github.com/mascii/hyperapp-wpa-supplicant-conf
https://github.com/mascii/react-wpa-supplicant-conf
https://github.com/mascii/vue-wpa-supplicant-conf

# 比較対象
* サンプルアプリのソース(JavaScript)を[webpack](https://webpack.js.org/)でバンドルしたJSファイルのファイルサイズ
    * プロダクションビルド
    * UglifyJS による minify あり

## バンドルするnpmパッケージ
* React or Vue.js or Hyperapp
* [crypto-js](https://www.npmjs.com/package/crypto-js) の `crypto-js/pbkdf2`

# サイズを比較してみた
|          | サイズ(Bytes) |
|----------|---------------|
| React    | 110293        |
| Vue.js   | 76012         |
| Hyperapp | 12026         |

React と Hyperapp とで98KBも違いが出ました。

# Hyperapp を使ってみた感想
* Hyperappで作るとかなりサイズが小さくなることを確認できた
* JSXが使えるため、Reactに慣れている方は苦労しないと思った(`onclick` のように camelCase でないといった違いはある)
* 情報は少ないので大きな規模のプロダクトには不向きだと思うが、個人で小さなものを作るのには良いと思った
* Flash領域が限られていたり、電池持ちなどの考慮が必要なIoT機器(Wi-Fiアクセスポイントとして機能できるESP32など)をWebサーバーとして機能させるといった使い方とは相性が良いのではないかと思った
GASのコードをGithub管理するChrome拡張が便利

# 紹介するもの

[Google Apps Script Github アシスタント - Chrome ウェブストア](https://chrome.google.com/webstore/detail/google-apps-script-github/lfjcgcmkmjjlieihflfhjopckgpelofo)

開発者の方のブログ:
[手軽にGoogle Apps ScriptのコードをGithubで管理する | Recruit Jobs TECHBLOG](https://techblog.recruitjobs.net/development/maneged_google-apps-script_by_github)

# 背景

Google Apps Script(GAS)はウェブIDE上で完結するサーバレスにスクリプトを書けるサービスですが、ソースコードの管理ができない問題があります。(スナップショットの管理は可能みたいです)

# できること

IDEにGithub関連のメニューが追加され、基本的な操作を行うことができます。

![aaaaasfds.png](https://qiita-image-store.s3.amazonaws.com/0/55365/ce2960d5-b870-bafe-73c8-f1470543c042.png)
glsl デバック

# 色デバック
数値を色として出力することで、簡単にざっくり状態を確認できる常套手段ですが、0.0 ～ 1.0の範囲でしか見えないので注意が必要です。例えばマイナスの数値や1.0を超える数値を認識できません。また、浮動小数点の精度落ちも判別しずらいです。

下の例では、半径1の円のディスタンスフィールドを描画していますが円の外周は0ではなく
![circle.png](https://qiita-image-store.s3.amazonaws.com/0/135381/115f2cab-411b-026c-42ca-49532184fd28.png)

https://goo.gl/iUsxs6

```glsl
precision mediump float;
uniform vec2  m;       // mouse
uniform float t;       // time
uniform vec2  r;       // resolution
uniform sampler2D smp; // prev scene

void main(void){
	vec2 p = (gl_FragCoord.xy * 2.0 - r) / min(r.x, r.y);
	float l= 1.-length(p);
	gl_FragColor = vec4(vec3(l), 1.0);
}
```

出力値をマイナスにして出力するとマイナスの領域が見えてきます。

![minus.png](https://qiita-image-store.s3.amazonaws.com/0/135381/baba490e-469f-f4b0-6cb0-059f3ff7fad9.png)

https://goo.gl/eR1M7B

```glsl
	gl_FragColor = vec4(vec3(-l), 1.0);
```

半径1の円のディスタンスフィールドを描画するだけで終わるのであれば問題ないのですが、このあとに複数の図形を合成する場合には、このマイナス値が大きく影響します。色デバックで正常そうに見えているからやっかいです。色デバックで正常そうに見えるのに不具合が解消されない場合は、マイナス値や1以上の値を疑ってみましょう。出力値をマイナスにして確認するくせをつけておくと良いと思います。または、以下のように赤をプラス領域、緑をマイナス領域に分けて表示する方法もおすすめです。

![rg.png](https://qiita-image-store.s3.amazonaws.com/0/135381/50a52692-ab48-1579-65e1-0723d1309abf.png)

https://goo.gl/VSSrUD

```glsl
	gl_FragColor = vec4(vec3(l,-l,0.), 1.0);
```

参考、さらに1以上の値をピンクに振ったバージョン

![rgb.png](https://qiita-image-store.s3.amazonaws.com/0/135381/8656a7aa-cb34-7830-3d86-0ccbf0d693d3.png)

https://goo.gl/Ls4Sd8

```glsl
	float l= 1.5-length(p);
        vec3 color = vec3(-l,max(l-1.,0.),l*step(l,1.));
	gl_FragColor = vec4(color 1.0);
```

# glslでprintデバック
glslで、ビットマップデータで数字を作り、数値を確認する方法です。

* http://jsdo.it/cx20/Amgk

小数点以下の数値を確認するのに大変便利です。

# プロット関数
```glsl
float plot(vec2 p, float v){
  return  smoothstep( v-0.02, v, p.y) -
          smoothstep( v, v+0.02, p.y);
}
```
https://goo.gl/RUJW27

グラフ化して関数などを可視化します。

# glsl デバック

各種ブラウザ用デバッカーの拡張を入れると捗ります。

* [WebGL Inspector](https://chrome.google.com/webstore/detail/webgl-inspector/ogkcjmbhnfmlnielkjhedpcjomeaghda/related?hl=ja)

* [Shader Editor](https://chrome.google.com/webstore/detail/shader-editor/ggeaidddejpbakgafapihjbgdlbbbpob)

# ソースレベルデバッカー

リアルタイムで値の確認をしたいのであれば、これで出来そうなのですが
Windows Linux用でソースのコンパイルが必要です。

* http://glsl-debugger.github.io/

# 参考
* [シェーダエディタを利用してシェーダをリアルタイムデバッグしたいことがもしかしたらあるかもしれない人向けの無駄に長い文章](https://qiita.com/doxas/items/fa31a8d8ed13a01ac4e4)
* [WebGLの開発やデバッグに便利なブラウザ拡張機能をつかってみよう](https://qiita.com/rootx/items/4f7401d1a6d22cb589c9)
dockerfileとdocker-compose.ymlのファイル名を変える方法

# 概要
コンテナの構成内容を記述するdockerfileや、コンテナの構築手順を記述するdocker-compose.ymlファイルは、デフォルトのファイル名が決まっており、それぞれ`dockerfile`、`docker-compose.yml`となっています。

しかし、開発環境と実環境で構成を変えるため、それぞれの環境での構成方法を、ファイル名を変えたかったので、両ファイルにおいてデフォルトのファイル名以外のファイル名を指定する方法をメモ。


<img src="https://qiita-image-store.s3.amazonaws.com/0/176262/1f4cc587-2b49-4a6c-1b82-4e4d4c651691.png" width="400">


# dockerfile
dockerfileからイメージを作るとき、ファイル名を指定する方法。
`docker build -t [イメージ名] -f [ファイル名] .`

```:例
$ docker build -t user/test -f Dockerfile_PRO .
```

# docker-compose.yml
どのymlファイルを使用するかは以下のようにオプションを指定することで指定可能。
`docker-compose.exe -f [ymlファイル名] [オプション] [コマンド] [引数]`

```:例
$ docker-compose.exe -f docker-compose_PRO.yml up -d
```

# docker-compose.ymlでdockerfileを指定するとき
docker-compose.ymlでdockerfileを指定してビルドするとき、
以下のように指定することでdockerfileのファイル名を変更可能。

* context : ディレクトリパス（dockerfileがあるディレクトリパス）
* dockerfile : dockerfileとして扱うファイルのファイル名

```:docker-compose.yml
container1:
  build:
    context: "./container1_Dir"
    dockerfile: "Dockerfile_PRO"
```

上記の例では、`./container1_Dir/Dockerfile_PRO`がdockerfileとして認識され、ビルドされる。
Windows10のストアアプリUbuntuでgoogle-home-notifierを使う

windowsに直接入れる方法を最初試してみたのですが正常に動作しなかったので
windows10のストアアプリUbuntu内で動作させてみたときの手順

# 使用デバイス情報

・Windows 10 64bit
・Google Home


# Windows10のMicrosoftストアから‎Ubuntuをインストール

## インストール手順
1. Windowsのバージョンを最新にする
2. Microsoftストアから‎Ubuntuをインストール
![1.jpg](https://qiita-image-store.s3.amazonaws.com/0/223901/a43cf338-3870-6e57-3332-c8cb1034da30.jpeg)

3. [設定]->[アプリ]->[アプリと機能]->[関連設定]のプログラムと機能を表示
![2.jpg](https://qiita-image-store.s3.amazonaws.com/0/223901/94574df6-9110-2cff-f2a4-07bad7bb5837.jpeg)

4. Windowsの機能の有効化または無効化を表示し[Windows Subsystem for linux]を有効にする
![3.jpg](https://qiita-image-store.s3.amazonaws.com/0/223901/0857af53-e438-f357-5eab-3c733a0a8771.jpeg)
![6.jpg](https://qiita-image-store.s3.amazonaws.com/0/223901/4d91a354-3e4d-16b1-6539-0b62da967ae3.jpeg)


上記手順でUbuntuが起動できます
初回起動時はユーザー名・パスワードを設定する必要があります


# Ubuntuでの作業

## 1. nodejs npm を apt-get でインストール

```
$ sudo apt-get update
$ sudo apt-get install -y nodejs npm
```

##  2. n をインストール

```
$ sudo npm cache clean
$ sudo npm install n -g
```

## 3. node.jsを最新にアップデートする

```
$ sudo n stable
$ sudo ln -sf /usr/local/bin/node /usr/bin/node
```

## 4. node.js npm が正常にインストールされているか確認

```
$ node -v
$ npm -v
```

最新バージョンがインストールされていることを確認

## 5. apt-get でインストールした node.js npm を削除

```
$ sudo apt-get purge -y nodejs npm
```


## 6. google-home-notifierインストールに必要なものを先にインストール

```
$ sudo apt install -y avahi-daemon libnss-mdns libavahi-compat-libdnssd-dev
```

## 7. google-home-notifierのインストール

```
$ npm install google-home-notifier
```

## 8. 必要なサービスの起動

```
$ sudo service dbus start
$ sudo service avahi-daemon start
$ sudo systemctl enable dbus
$ sudo systemctl enable avahi-daemon
```

どちらも起動できたことを確認する。
起動できていない場合は

**Error: dns service error: unknown**

というエラーが表示されます
※これで半日ほどハマりました・・・


## 9. js内に記載した文章を再生させる

```js:test.js
const googlehome = require('google-home-notifier');
const message = "接続確認";

googlehome.device('Google Home', 'ja');
googlehome.ip('GoogleHomeのIP'); // (例:192.168.1.20)
googlehome.accent('ja');
googlehome.notify(message, res => console.log(res));
```

```
$ node test.js
```

これで音声が再生されたら設定周りは問題なし


## 10. example.js の起動

example.js の内容を一部変更する必要があるかも・・
test.jsの内容を参考に調整を行ってください。

```
$ cd /home/ユーザー名/node_modules/google-home-notifier
$ node example.js
```

cdをせずにpathを通してもOK。


これでコメントに表示される方法で通信を行うと任意のメッセージを話すようになります。

# まとめ

Raspberry Piを購入するか迷っていたのですが今回の環境構築を行ったことで常駐化させるともっと面白いことができそうだなということがわかりました。

Raspberry Piの購入を検討している人も余っているパソコンがあればWindows上で動かしてみるのも有りかもしれません。

今まで任意のメッセージを話すことがなかったGoogle Homeですが、パソコンからのメッセージを送信して子供と対話できるようになっただけでも可能性を感じました。
Swiftのfirst(where:)のパフォーマンスについて

Array操作におけるfirst(where:)のパフォーマンスについてです。
Arrayを操作して、条件に合致する一番最初の要素を取得したいとします。

# 例題
例題として以下のようなArrayの**最初に出現する2**を取得することを考えます。

1, **2**, 3, 1, 2, 3, 1, 2, 3, ...

## filterとfirstを使う

単純に記述すると以下のようなコードになるのではないでしょうか。

```swift:filterとfirst
// 0, 1, 2, 0, 1, 2, ...と繰り返すArray
let array = (0..<100000).map { $0 % 3 }

// filterとfirst
let result = array.filter { $0 == 2 }.first!
```

上記のコードは問題なく動作しますが、**実際は10万回Arrayの各要素をチェックしている**ため、パフォーマンスの悪いコードとなります。

## first(where:)を使う

この場合、`first(where:)`を利用するとパフォーマンスが改善されます。`first(where:)`を利用した場合、**条件に一致する最初の要素を取得した後は、それ以降の要素をチェックしません**。

```swift:first(where:)
// 0, 1, 2, 0, 1, 2, ...と繰り返すArray
let array = (0..<100000).map { $0 % 3 }

// first(where:)
let result = array.first(where: { $0 == 2 })!
// trailing closureを用いた記法
let result = array.first { $0 == 2 }!
```

## lazyを使う

また遅延評価を行う`lazy`プロパティを利用しても`first(where:)`と同様のパフォーマンスが得られます。

```swift:lazy
// 0, 1, 2, 0, 1, 2, ...と繰り返すArray
let array = (0..<100000).map { $0 % 3 }

// lazy
let result = array.lazy.filter { $0 == 2 }.first!
```

# まとめ

 - filterとfirstの場合はArrayの全要素を評価するため、パフォーマンスに注意が必要
 - first(where:)もしくはlazyを利用すると良い
Windowsローカル開発環境からgit commitする時にはパーミッションに気を付けること

## 背景

`rails`で`delay_job`や`whenever`を実装し、ローカル開発環境では問題なくジョブが走った。

しかし本番環境にデプロイ後、ジョブが走らなかった。

エラーログを確認したところ`rails`の`bin`ディレクトリ以下の各ファイルの権限が`644`となっており、実行権限がないことが判明。

だとしたら、ローカル開発環境でも動かないはずだろ？？
そんな思いからいろいろ調べてみた。

## windows環境でのgitbashはchmodが効かない！！

`chmod 777 ファイル名`しても`chmod 644 ファイル名`しても`chmod o+w ファイル名`しても何しようが権限が変更されない。
大丈夫！
これは`windows`の仕様の問題らしい。
なのでスッキリあきらめよう！

[![https://gyazo.com/f912264b59cdfac8862cc6436272b47e](https://i.gyazo.com/f912264b59cdfac8862cc6436272b47e.png)](https://gyazo.com/f912264b59cdfac8862cc6436272b47e)

## git addするとパーミッションが自動的に変更され644になってしまう！！

これは`git`の仕様。
おそらくですが、大規模開発を想定し、ファイルパーミッション管理の保守性を向上させているのでは？と自分なりに理解してみる。。

以下のように`.git/config`の`filemode`がデフォルトで`false`になっていると、パーミッションを変更しても`git add`すると`644`になってしまうのです。

[![https://gyazo.com/83a6ef8926aa054ecdc96fb2a8ea59a4](https://i.gyazo.com/83a6ef8926aa054ecdc96fb2a8ea59a4.png)](https://gyazo.com/83a6ef8926aa054ecdc96fb2a8ea59a4)

## では、どうやってパーミッションを変更するのか？

例えば、`test.rb`に実行権限を付与したいときは以下のコマンドを実行する必要があります。

```
git update-index --add --chmod=+x test.rb
```

## update-indexのインデックスってなんだ？

ここで`git update-index`の`index（インデックス）`ってなんだ？という疑問が沸きます。

インデックスは`git add`した時にファイル状況が保存される領域のことです。

- `git add` ワーキングツリー → インデックス
- `git commit` インデックス → ローカルリポジトリ
- `git push` ローカルリポジトリ → リモートリポジトリ

という感じです。
つまり、インデックス領域に対して権限変更処理を実行しておけばコミット先で`644`に変更されないという`git`の仕様が存在しているのです。

## ではインデックス上での権限変化をどのようにして確認するのか

残念ながら`windows`環境だと、`ls -la`しても変化は確認できません。
（chmodが機能しないので、権限を変更させられないという方が正しい言い回しかもしれないです。）
（Windowsの仕様なので、ここはあきらめましょう！）

[![https://gyazo.com/40e3f6959139f93a1a0ee0aa2ff1e48b](https://i.gyazo.com/40e3f6959139f93a1a0ee0aa2ff1e48b.png)](https://gyazo.com/40e3f6959139f93a1a0ee0aa2ff1e48b)

ではどうやって権限変化を確認するのか？
以下のような流れで確認します。

1. 該当ファイルを`git add`してインデックス領域に入れて置く。
2. `1.`を実行すると`git ls-files -s`でインデックス内のファイルの権限を確認できます。実行してみるとこの時点では`644`になっています。
3. `git update-index --add --chmod=+x test.rb`して実行権限を付与。
4. 改めて`git ls-files -s`でインデックス内のファイルの権限を確認。
5. しっかりと`644`→`755`になっていることがわかります。（さらに`git update-index --add`では所有者、グループ、ユーザすべてに働きかけていることも分かります！）

[![https://gyazo.com/7075169d6c852f03092aab1ff70447b5](https://i.gyazo.com/7075169d6c852f03092aab1ff70447b5.png)](https://gyazo.com/7075169d6c852f03092aab1ff70447b5)

## まとめ

つまりローカル開発環境でジョブの実行がうまくいったのは、ワーキングツリー上で確認できるよう、実行権限が付与されているため。
その後`git add`することでパーミッションが`644`に変更してしまったので、それをもとにコミット、デプロイしている本番環境ではジョブが実行されなかったという事なのです。

長々と話しましたが、実行権限をつけておくべきファイルに対しては、`git update-index --add --chmod=+x ファイル名`を忘れないようにしましょう。

特に本番環境適用時には注意しましょう！
ホスト名変更によるGitにおけるPermission deniedの回避

# はじめに

Git｢リポジトリに繋がせてください｣
ssh｢お前はダメだ｣

ここから始まりました．

# エラー内容

先日から筆者がGitの初歩に戻ろうと思い，以前に立ち上げていたGit練習用のリポジトリにアクセスしようとしました．
しかし，

```shell-session:Terminal
> git pull
Permission denied (publickey).
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.
```

怒られてしまいました．

# エラー原因調査
自分の場合はホスト名の整合性が取れていないことでエラーが発生していました．
それもそのはず，以下の記事に魅了され以前にsshのホスト名を変更していたことをすっかり忘れていました……
> [[Qiita] ~/.ssh/configについて](https://qiita.com/passol78/items/2ad123e39efeb1a5286b)

.sshディレクトリ配下に存在するconfigファイルですが，  
これが，
<img width="462" alt="スクリーンショット 2017-12-29 18.37.59.png" src="https://qiita-image-store.s3.amazonaws.com/0/143895/1225141b-b4aa-efe9-a00c-e004187d09d7.png">

こう!
<img width="462" alt="スクリーンショット 2017-12-29 18.35.34.png" src="https://qiita-image-store.s3.amazonaws.com/0/143895/3aeff845-3abb-c608-7e2a-89d8b4bbbdfc.png">  

ホスト名の先頭に見事アンダースコアがついていますね．

さて，ここで各リポジトリに生成されている.gitディレクトリ配下のconfigファイルを覗いてみましょう．(Bitbucketのユーザ名は伏せさせて頂きます)

![achacha.png](https://qiita-image-store.s3.amazonaws.com/0/143895/35027c91-fd97-271b-d8ce-c7a85b0acdaf.png)

うわーやらかしてますわーこれ．
やっぱり.gitのconfigとsshのホスト名の整合が取れていませんね?
何やってるんでしょうかね私は……

# 解決方法
至って単純です．

**.ssh/configのホスト名と.git/configのurl部分におけるホスト名を統一させる**

上記で完了です．

私の場合では，

<img width="528" alt="スクリーンショット 2017-12-29 19.29.51.png" src="https://qiita-image-store.s3.amazonaws.com/0/143895/f6b7e840-9b1c-b4f8-7ac8-193b704bb62f.png">

urlのgit@に続くホスト名をssh configと同じホスト名にすることで解決しました．


# おわりに
sshホスト名のアンダースコア消そうかしら……
他にもコンフリクト起きてそうで怖いです(笑)
[Swift] Processを使おう！(3)

### Processってなに？
ちょっと前までNSTaskと呼ばれていた、主にコマンドラインツールを実行してデータのやり取りを行うためのクラスです。
SwiftでできることはSwiftでやってしまってもいいのですが、swiftcを呼びたいとかそういう時に使います。

の3回目。

[第１回](https://qiita.com/masakihori/items/0639526a3baf0d6cb621)
[第２回](https://qiita.com/masakihori/items/a85d1667b0af86d6f6e7)
[第３回](https://qiita.com/masakihori/items/fe094ca1f66d56f38d92)
[第４回](https://qiita.com/masakihori/items/3d6a2c083182076f2e0f)

### 振り返り
前回出力を表す型を追加して下のようになりました。

```swift;Output.swift
struct Output {
    
    private let fileHandle: FileHandle
    
    init(fileHandle: FileHandle) {
        self.fileHandle = fileHandle
    }
    
    var data: Data {
        return fileHandle.readDataToEndOfFile()
    }
    
    var string: String? {
        return String(data: data, encoding: .utf8)
    }
    
    var lines: [String] {
        return string?.components(separatedBy: "\n") ?? []
    }
}
```
```swift:Operations.swift
precedencegroup ArgumentPrecedence {
    associativity: left
    higherThan: AdditionPrecedence
}
func <<< (lhs: Process, rhs: String) -> Process {
    
    lhs.executableURL = URL(fileURLWithPath: rhs)
    return lhs
}

func <<< (lhs: Process, rhs: [String]) -> Process {
    
    lhs.arguments = rhs
    return lhs
}
```
```swift
let echo = Process() <<< "/bin/echo" <<< ["Hello, World."]

let pipe = Pipe()
echo.standardOutput = pipe

echo.launch()

let output = Output(pipe.fileHandleForReading)
if let string = output.string {
    print(string)
}
```

**まだ長いわ――！！！！**

`Pipe`とかいう途中経過にしか使わない何かがあるし、`launch()`を使う位置を気をつけなくてはならないし、面倒です。

## もっと出力の取得を簡単に

出力を得るカスタムオペレーションを追加します。

```swift
precedencegroup RedirectPrecedence {
    associativity: left
    lowerThan: LogicalDisjunctionPrecedence
}
infix operator >>> : RedirectPrecedence

func >>> <T>(lhs: Process, rhs: (Output) -> T) -> T {
    
    let pipe = Pipe()
    lhs.standardOutput = pipe
    lhs.launch()
    
    return rhs(Output(fileHandle: pipe.fileHandleForReading))
}
```

`Process`と関数を結合して関数で値を得ます。
`launch()`をこのオペレータで行いますので`launch()`の位置を気にする必要がなくなりました。

### 使用法

```swift
Process() <<< "/bin/echo" <<< ["Hello, World."] >>> { output in
    
    output.string.map { print($0) }
}
```
あるいは

```swift
let outputString = Process() <<< "/bin/echo" <<< ["Hello, World."] >>> { $0.string }
outputString.map { print($0) }
```

短い！　わかりやすい！

[第４回](https://qiita.com/masakihori/items/3d6a2c083182076f2e0f)
Go言語事始め

Go言語始めてみようと思い、先日下記の参考書をポチりました。

[スターティングGo言語 (松尾愛賀 著)](http://www.shoeisha.co.jp/book/detail/9784798142418)

まず手始めに基本的なシンタックスとGo言語特有のイディオムを洗っていこうと思い打鍵確認したところ、いきなり取っつきにくい考え方に直面したのです。。
折角なので自身の理解を深めるために頑張って記事にまとめてみようと思います！！


## クロージャとしての無名関数
(参考書引用)
Goの無名関数は「クロージャ」です。クロージャは日本語では「関数閉包」と呼ばれ、関数と関数の処理に関係する「関数外」の環境をセットにして「閉じ込めた(閉包)」ものです。

なるほど、わからん。サンプルがあったのでみてみることにします。

```go:クロージャの動作例
package main

import "fmt"

// laterは「引数に文字列を取り、戻り値に文字列を返す関数」を返す関数
func later() func(string) string {	
	// storeはクロージャ内で使われている変数と結び付いた変数
	// クロージャと結びついている限り破棄されない
	var store string
	fmt.Println("store: " + store) // debug
	
	return func(next string) string { // F1(クロージャ)
		fmt.Println("next: " + next) //debug
		s := store // storeから一つ前に呼び出された文字列を取り出す
		store = next // 今受け取っている文字列をstoreに格納
		return s // 一つ前の文字列を返す
	}
}

func main() {
	f := later()
	fmt.Println("a: " + f("Golang"))
	fmt.Println("b: " + f("is"))
	fmt.Println("c: " + f("awesome!"))
}

/* 出力
> store: 
> next: Golang
> a: 
> next: is
> b: Golang
> next: awesome!
> c:is
*/
```
引数として渡した文字列が、次の関数呼び出しのタイミングで返ってきていることがわかりますね。
なぜこのような動作になるのかを丁寧に追ってみたいと思います。

#### `f := later()`の挙動
まず`f := later()`で`f`が受けるのは`later()`の戻り値である。つまり「引数に文字列を取り、戻り値に文字列を返す関数」(以降F1と呼ぶこととする)を受け取る。ここでF1の関数内では変数`store`が使用されているが、これは`later()`関数のローカル変数として定義されたものである。通常、ローカル変数は関数の実行が終了した後は破棄されるはずである。しかし、本ケースのようにクロージャ内部で変数が使用される場合、内部的にはクロージャに属する変数として機能する。具体的には、クロージャが参照されている限り変数`store`は破棄されない。(`f := later()`の`f`を使用している限り`store`の状態は保持される)

#### `f("Golang")`の挙動
1. はじめにF1の引数`next`に`"Golang"`が渡される。
2. `s := store`は`store`が空なので`s`には""が返る。
3. `store = next`で`store`に`"Golang"`が渡られる。
4. 戻り値は空。

#### `f("is")`の挙動
1. `s := store`で`store`に格納されているのは`f("Golang")`時に渡された`"Golang"`であるから、`s`には`"Golang"`が格納される。ここがポイント。
2. `store = next`で`store`に`"is"`が渡される。
3. 戻り値は`"Golang"`

このように、クロージャの機能によって、確かに`store`内の状態が保持されていることがわかります。

この機能の何が嬉しいのかはまた今度調べてまとめてみよう、、今回はここまで！
Eureka で設定画面を作りたい Swift

# 概要
基本的には、[Swift×Eurekaで簡単に設定画面を作る](https://qiita.com/seiya_orz/items/4a6884eb8ad9b7a61f2b)を参考にして、一部Swift4(Swift3)に対応させました。
UserDefaultsのメソッド名が大きく変更されたので、その対応のみです。

# ライブラリ
https://github.com/xmartlabs/Eureka

# コード

```swift
import UIKit
import Eureka

class SettingsViewController : FormViewController {

    // インスタンスの作成
    let userDefault = UserDefaults.standard
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        form +++ Section("通知時刻の設定")
            <<< SwitchRow("switchRowTag") {
                $0.title = "通知時刻の設定"
                // 読み込み
                let temp:Bool = self.userDefault.bool(forKey: "Notify")
                $0.value = temp
                }.onChange{row in
                    self.userDefault.set(row.value, forKey: "Notify")
            }
            
            <<< TimeRow(){
                $0.hidden = Condition.function(["switchRowTag"], { form in
                    return !((form.rowBy(tag: "switchRowTag") as? SwitchRow)?.value ?? false)
                })
                $0.title = "通知時刻"
                // 読み込み
                if let temp:Any = self.userDefault.object(forKey: "Time") {
                    $0.value = temp as? Date
                }
                }.onChange{row in
                    // 保存
                    self.userDefault.set(row.value, forKey: "Time")
        }
    }
}
```


# 参考文献
[[Swift 3.0] Swift3.0で、NSUserDefaultsはUserDefaultsになった](https://dev.classmethod.jp/smartphone/swift-3-0-userdefaults/)
[【iOS】UserDefaultsをSwiftらしく使う](https://qiita.com/KokiEnomoto/items/c79c7f3793a244246fcf)