OmniAICreator/Qiita-1.07M huggingface dataset:
テキストエディタ開発で学ぶソフトウェアアーキテクチャ設計

## 対象読者
* ソフトウェア開発者全般

## ゴール
* ソフトウェアアーキテクチャの概要がわかる
* レイヤーモデルがどのようなものかわかる
* ソフトウェアアーキテクチャ設計の実例を知ることができる

## 背景
筆者は趣味でテキストエディタ開発をしています。 
今、開発を初めて1年半程度で、基礎的な動作の設計と実装ができた段階です。 
最初はスクラップアンドビルドにより、ボトムアップでソフトを作成しました。 
そしてその後、品質の高い設計とするために、トップダウンで再設計を実施しました。
その際に、今作っているソフトをどのようなアーキテクチャで作って行くかについての設計を行いました。
よって、その体験を通じて、知ったこと、考えたことや実践したことを紹介したいと思います。

## ソフトウェアアーキテクチャとは
> ソフトウェアアーキテクチャ（Software Architecture）は、ソフトウェアコンポーネント、それらの外部特性、またそれらの相互関係から構成される。
> また、この用語はシステムのソフトウェアアーキテクチャの文書化を意味することもある。
> ソフトウェアアーキテクチャの文書は開発依頼主とのコミュニケーションを容易にするもので、
> 概要レベルの設計に関する早期の決定を促し、プロジェクト間でのコンポーネントとパターンの設計を再利用することを可能にする。
(https://ja.wikipedia.org/wiki/ソフトウェアアーキテクチャ)

## 今回のアーキテクチャ設計のスコープ
* テキストエディタ全体の設計を対象とする
* 一般的なユーザインタフェーズのテキストエディタを開発することを想定する
   * 例えば、Vim や notepad など
* もっとも抽象的なレベルの設計を実施する
   * 後からはそれより具体的なレベルしか出てこないようにするため

## 再利用するアーキテクチャモデルの選定
アーキテクチャ設計を実施するにあたり、まず、再利用するアーキテクチャモデルの選定を行いました。 
ソフトウェアアーキテクチャには例えば以下のような代表的なモデルがあります。  

* MVC モデル
* レイヤモデル
    * 具体例 : OSI 参照モデル
* クライアントサーバモデル
* データフローモデル

今回、筆者は以下のポリシーによってアーキテクチャのモデル選択を行いました。

* テキストエディタの構造を表現するのに適している
* 筆者自身がそのモデルに知見がある

よって、そのポリシーに従い今回の設計は「レイヤモデル」を採用することとしました。  
理由は以下です。  

* テキストエディタの主な構成要素であるバッファ、ウィンドウなどは階層的に表現しやすい
* 筆者がレイヤーモデルに基づく通信プロトコルを適用したソフトウェア開発の経験がある

## 設計したアーキテクチャ
今回、設計したテキストエディタのアーキテクチャは下図のようになりました。 
![test_editor_arch.png](https://qiita-image-store.s3.amazonaws.com/0/143910/cb95096d-29cf-b84b-3288-c202bbfa141b.png)

Input はユーザの操作またはファイルによる入力で、 
Output はユーザへ表示される、またはファイルなどで返される出力を示します。

以下が各レイヤの説明です。

* User Interface Layer
    * ユーザ入力を抽象的な単位で受け取るレイヤ
    * ユーザの入力はかならずこのレイヤをじてこれより下の層へと通じる
* Buffer Layer
    * 編集しているテキスト全体の情報を保持するレイヤ
    * テキスト、テキスト編集位置、などを情報をして持つ
* Window Layer
    * ユーザへ表示するウィンドウの情報を保持するレイヤ
    * ユーザから見えるテキスト、カーソル位置などを情報として持つ
* File I/O Layer
    * ファイルの入出力を行うレイヤ
* Debug I/F Layer
    * デバッグ用のインターフェースを持つレイヤ
    * テキストエディタ機能により占有されたターミナルのバッファに代わりファイルなどにデバッグ出力を行う

今後は、追加していく機能や、実装規模の拡大に合わせて、層を追加したり、分割したりなどの追加設計は必要になる見込みです。

## アーキテクチャから実装レベルへの表現
さて、アーキテクチャの設計ができました。 
では、最後にその設計をもとにソフトウェアの実装へはどのように表現できるかを検討します。 
筆者は、以下のパターンを検討しました。

* クラス、パッケージなどをコンポーネント(レイヤ)ごとに分割し namespace として表現する
* ファイルをコンポーネント(レイヤ)ごとに分割することにより表現する

筆者は、今回はプログラム言語の都合などから、ファイル分割による表現を選択しました。 
(その理由については今回の記事のスコープではないため割愛します)

## ソフトウェアアーキテクチャ設計を行うことにより得られたもの
アーキテクチャの設計を実施することにより得られたものは、今回は以下のようなものがありました。

* 機能が分割単位(ファイル)ごとに整理されるため、可読性が向上する
* 各層のつながりやデータフローを意識した API 設計ができるため、設計の品質が向上する
* ↑のようなメリットにより、機能を追加するときも適切な層に適切な I/F を追加することにより実現できるようになる

## まとめ
ソフトウェアアーキテクチャというと大規模なプロジェクトなどのもの、と思ってしまうようなところもあったりしますが、
今回のような小規模なソフトウェア開発でも効果があることがわかりました。 
また、それは今回のような組織の規模が小さい(今回は1人)開発でも有効であることもわかりました。 

この記事を読んでくださった方で、まだ自分のためのプロジェクトでソフトウェアアーキテクチャを設計したことがない方は、 
一度設計にトライしてみてはいかがでしょうか。

## 参考文献/ウェブサイト
* [ソフトウェアアーキテクチャ(ウェブサイトの pdf 資料)](http://kussharo.complex.eng.hokudai.ac.jp/~kurihara/classes/SE/12-architecture.pdf)
ChromeOSからcrostini使ってGCPにgcloudでsshしようとしたけどできなかった記録

# はじめに

crostiniからGCEにsshしようとしたけど、うまくいかん・・・。

# gcloudのインストール

ここのサイトに従った。
[Cloud SDK のインストール  |  Cloud SDK のドキュメント  |  Google Cloud](https://cloud.google.com/sdk/downloads)

```
curl https://sdk.cloud.google.com | bash
exec -l $SHELL
gcloud init
```
これをやって、ポチポチすすめた。defaultのzone?とか聞かれた気がする。GCEのんに揃えた。

ここらも参考
[Google Compute Engine のSSH接続 - Qiita](https://qiita.com/NewGyu/items/3a65e837519297951e79)

```
$ gcloud compute ssh instance-1
WARNING: The private SSH key file for gcloud does not exist.
WARNING: The public SSH key file for gcloud does not exist.
WARNING: You do not have an SSH key for gcloud.
WARNING: SSH keygen will be executed to generate a key.
Generating public/private rsa key pair.
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /home/xxx/.ssh/google_compute_engine.
Your public key has been saved in /home/xxx/.ssh/google_compute_engine.pub.
The key fingerprint is:
SHA256:yyy xxx@penguin
The key's randomart image is:
+---[RSA 2048]----+
+----[SHA256]-----+
Updating project ssh metadata...⠧Updated [https://www.googleapis.com/compute/v1/projects/zzz].
Updating project ssh metadata...done.                                                              
Waiting for SSH key to propagate.
Warning: Permanently added 'compute.zzz' (ECDSA) to the list of known hosts.
Permission denied (publickey).
ERROR: (gcloud.compute.ssh) Could not SSH into the instance.  It is possible that your SSH key has not propagated to the instance yet. Try running this command again.  If you still cannot connect, verify that the firewall and instance are set to accept ssh traffic.
```

よくわからんけど、`.ssh/google_compute_engine.pub`をVMのssh鍵登録するとこにコピペしてみたけど、駄目やった。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/184221/450b0fa9-528a-a77f-172f-754d7df5f88e.png)


`.ssh/google_compute_engine`のパーミッションみてもリードできそうやった。

firewallも確認したけど、大丈夫そう。

```
$ gcloud compute firewall-rules list
default-allow-ssh       default  INGRESS    65534     tcp:22                              False
```

telnetでポートの確認した。大丈夫そう。

```
$ telnet IP 22
Trying IP...
Connected to IP.
Escape character is '^]'.
SSH-2.0-OpenSSH_7.2p2 Ubuntu-4ubuntu2.6
^[
Protocol mismatch.
Connection closed by foreign host.
```

いろいろやったけど、エラー出る。

```
$ gcloud compute ssh instance-1 
Permission denied (publickey).
ERROR: (gcloud.compute.ssh) [/usr/bin/ssh] exited with return code [255].
```

ここらも参考にした。
[GCEで事前準備（SSHでサーバー接続するまで編） - ゼロからWeb開発](https://muzirushi78.hateblo.jp/entry/2018/04/05/233045)

# おわりに
よくわからん。
インスタンスが容量いっぱいいっぱいなのも関係してるんかなー。
変な設定になってるんかなー。
教えて、詳しい人。
そろそろインスタンス一度消して、設定しなおそかな・・・。
RでExcelのシリアル値と戦う

# Excelからデータをインポートする
ExcelからRにデータをインポートするには複数のパッケージが考えられますが、今回はインポートしようとするファイルの関係も考慮してopenxlsxを用いました。openxlsxでは以下のコードでデータのインポートができます。

xlsx.df <- read.xlsx(<インポート元パス>)

# シリアル値のRでの日時型への変換
[エクセルの日時変数をRで扱う](https://qiita.com/kota9/items/a15afff5291332611aeb)から拝借すると以下の式でExcelのシリアル値を変換できる。中途半端な日付が起点になっているのは、歴史的経緯があり[Microsoft Excel の 1900 年 2 月 29 日問題　まとめ](http://d.hatena.ne.jp/hebikuzure/20100423/1272037288)などに記載がある。

t <- as.POSIXct('1899-12-30') + as.difftime(serial.datetime, units = 'days')

# 演算誤差への対応
今回、用いたデータは区切りのよい時刻で取得されたはずだが、実際に変換した日時を観察すると演算誤差と思われるものがあったため、xtsパッケージのalign.time関数で丸めを行った。

t <- align.time(t - 2.5, 5)

この処理は[時刻を5分間隔でまるめる](https://qiita.com/tktz/items/733c37b1d6102ae52120)を参照した。
初めてのAndroidアプリ＆Kotlinでハマった点の技術的原因と対応方法

# はじめに
*Qiita*初投稿のシェンリー（*@schenlybiz*）です。現在、フリーランスで活動しています。
*Android*アプリを初めて開発して、2018年11月上旬に[シームレス・コラージュ](https://play.google.com/store/apps/details?id=app.schenlybiz.seamlesscollage.freeAd)（以降は本アプリとします）をリリースすることができました。
*OpenCV*を利用したシームレス画像合成の*Android*アプリで、2018年8月中旬頃に開始しましたが、技術不足と*Android*の画面遷移（フラグメント）、カメラ機能に関する処理、画像に関する処理などでハマった点が多くありました。（開発期間は学習コスト含む）
これらのハマった点を共有することで、多くの開発者の時間短縮に貢献できたらと思い公開することにしました。

# 技術不足
*Android*アプリ及び*OpenCV*が初めてだったこともあり、*Android Studio*の新規プロジェクトとして*OpenCV*のサンプルをビルドしようとした際はエラーの連続でした。
リリース直前では、*Gradle*のビルド・バリアントやプロダクトフレーバーの設定でデバッグ（テスト）用とリリース用のリソースやビルドを簡単に切り替えられることを覚えました。
これらは、同様のトラブルを経験した人が、*Qiita*を筆頭に情報を公開しているおかげでハマることはありませんでした。

*Android*アプリは初めてとはいえ、*Java 1.2*の時代から経験している私としては、*Java*で開発するよりも互換性のある*Kotlin*で開発する方が何倍もメリットを感じました。
*Kotlin*に関しても公式ドキュメント、書籍やサイトの技術情報が公開されているおかげで*Java*よりもコーディングの効率が向上しています。

公式ドキュメントといえば、*Android*の公式ドキュメントは古い情報が混じっていたため、多少混乱しました。

# 対象者
* *Android*アプリに興味がある方
* *Android*の画面遷移（フラグメント）処理を組み込む方
* *Android*のカメラ機能に関する処理を組み込む方
* *Android*の画像に関する処理を組み込む方
* *Android*の画面遷移（フラグメント）処理でハマっている方
* *Android*のカメラ機能に関する処理でハマっている方
* *Android*の画像に関する処理でハマっている方
  
# 実行環境
### 【課題発生時の実行環境】
*Android Studio 3.1.4*

[*build.gradle*]（プロジェクト）
*com.android.tools.build:gradle:3.1.4
org.jetbrains.kotlin:kotlin-gradle-plugin:1.2.61*

[*build.gradle*]（モジュール：*app*）
*minSdkVersion 19（API 19/Android 4.4/KitKat）*
（保持している端末のバージョンが*Android 4.4*のため）
*compileSdkVersion 27（API 27/Android 8.1/Oreo）
targetSdkVersion 27*

### 【リリース時の実行環境】
*Android Studio 3.2.1*

[*build.gradle*]（プロジェクト）
*com.android.tools.build:gradle:3.2.1
org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.0*

[*build.gradle*]（モジュール：*app*）
*minSdkVersion 19（API 19/Android 4.4/KitKat）*
（保持している端末のバージョンが*Android 4.4*のため）
*compileSdkVersion 28（API 28/Android 9.0/Pie）
targetSdkVersion 28（API 28/Android 9.0/Pie）*

### 【利用した*OpenSource*】
*Android-Image-Cropper 2.7.0
lottie-android 2.5.0
OpenCV 3.4.3*

# 前提条件
今回の開発中の調査で*Android*のマテリアルデザイン、*Android Jetpack*、*ReactiveX/RxJava/RxAndroid*の存在を知りましたが、本アプリ（*Fragment*除く）では利用していません。（本アプリのリリースを優先したのと余裕がなかったことが要因です）

# 目次
### [１．*Android*の画面遷移（フラグメント）処理](https://qiita.com/schenlybiz/items/2aa4d4d2420ea73bef50)
- １．１ 画面遷移後のイメージ画像を貼り付ける処理
- １．２ 画面遷移後のシームレス画像合成中のアニメーション画像表示処理
- １．３ シームレス合成結果画面上のバックスタック処理
  
### [２．*Android*のカメラ機能に関する処理](https://qiita.com/schenlybiz/items/65e60ed39331e494ee23)
- ２．１ 画像選択時のギャラリー又はカメラ機能を選択する*Chooser*処理
- ２．２ *Chooser*のカメラ機能に他カメラアプリを除外する処理
- ２．３ カメラ撮影時の*onActivityResult()*の*Intent*パラメータ処理
  
### [３．*Android*の画像に関する処理](https://qiita.com/schenlybiz/items/b72c2106d7eadf2c1582)
- ３．１ *File*クラスの*createTempFile*(一意なファイル名)処理
- ３．２ *OpenCV*を利用したイメージ画像のミラー処理
- ３．３ *OpenCV*を利用したシームレス合成処理
- ３．４ シームレス合成画像のギャラリー登録処理
Flask 体験記 vol.2 ~ディレクトリ構成、ファイル同士の関係~

# 活動予定

* Paiza の「[Flask入門講座](https://paiza.jp/works/search_courses/2115)」を受講する. **←イマココ**
* 書籍で学習する
    * [ゼロからFlaskがよくわかる本](https://www.amazon.co.jp/ゼロからFlaskがよくわかる本-本田崇智-ebook/dp/B07F2X9GRQ)をやってみる**←イマココ**
    * [PythonでWebサービスを作る 1](https://www.amazon.co.jp/PythonでWebサービスを作る-Python3-Flaskで作るWebアプリケーション開発入門-中野-仁-ebook/dp/B07B2LFGH2/ref=pd_sim_351_1?_encoding=UTF8&pd_rd_i=B07B2LFGH2&pd_rd_r=6b1f6575-e874-11e8-bac0-4528c1c3ea39&pd_rd_w=pLGSb&pd_rd_wg=NY8RL&pf_rd_i=desktop-dp-sims&pf_rd_m=AN1VRQENFRJN5&pf_rd_p=b79503b3-46ea-4244-8b06-2f14c40a97b1&pf_rd_r=G4W1P8DXXQ3N72RHRK4H&pf_rd_s=desktop-dp-sims&pf_rd_t=40701&psc=1&refRID=G4W1P8DXXQ3N72RHRK4H)をやってみる
    * [PythonでWebサービスを作る 2](https://www.amazon.co.jp/PythonでWebサービスを作る-Python3-Flaskで作るWebアプリケーション開発入門-中野-仁-ebook/dp/B07C8KT3FS/ref=pd_sim_351_1?_encoding=UTF8&pd_rd_i=B07C8KT3FS&pd_rd_r=6fbc1ebb-e874-11e8-8f15-4353527dc78c&pd_rd_w=3NP81&pd_rd_wg=c1ORS&pf_rd_i=desktop-dp-sims&pf_rd_m=AN1VRQENFRJN5&pf_rd_p=b79503b3-46ea-4244-8b06-2f14c40a97b1&pf_rd_r=6AXHJBZYTYS3ZD9118ZW&pf_rd_s=desktop-dp-sims&pf_rd_t=40701&psc=1&refRID=6AXHJBZYTYS3ZD9118ZW)をやってみる
    * [PythonでWebサービスを作る 3](https://www.amazon.co.jp/PythonでWebサービスを作る-Python3-Flaskで作るWebアプリケーション開発入門-中野-仁-ebook/dp/B07BPBNH27/ref=pd_sim_351_2?_encoding=UTF8&pd_rd_i=B07BPBNH27&pd_rd_r=8da9b65b-e874-11e8-9351-635a7a6b78d5&pd_rd_w=9XGz4&pd_rd_wg=QHhvu&pf_rd_i=desktop-dp-sims&pf_rd_m=AN1VRQENFRJN5&pf_rd_p=b79503b3-46ea-4244-8b06-2f14c40a97b1&pf_rd_r=JHBAZ5ABR287DX9M6F04&pf_rd_s=desktop-dp-sims&pf_rd_t=40701&psc=1&refRID=JHBAZ5ABR287DX9M6F04)をやってみる
* 書籍で学習しつつ, 思い立ったら何かしらの Web アプリを作ってみる.

# 今日のおはなし
アプリを作るために必要なディレクトリ構成, 個々のファイルの役割を理解する.

# 結論
ディレクトリ構成や個々のファイルの役割を理解した.

### ディレクトリ構成
```
application/
　　|- server.py
　　|- flask_blog/
　　　　|- __ init __.py
　　　　|- views.py
　　　　|- templates/
　　　　　　|- entries/
　　　　　　　　|- index.html
```
#### ディレクトリ
* application/ : このディレクトリ以下に, アプリに必要なものが置かれる
* flask_blog/ : 今回作るアプリの本体が置かれる
* templates/ : html テンプレートが置かれる場所
* entries/ : よくわかってないけど, たぶんトップページのテンプレ

#### ファイル
* server.py : web アプリサーバを起動するファイル. __ init __.py 内のアプリ本体を呼んでくる
* __ init __.py : Flask アプリの本体
* views.py : URL にアクセスがあったときの処理が書かれたファイル. __ init __.py から呼ばれる.
* index.html : web アプリのテンプレートファイル

図示したらこんな感じという理解.  間違ってたらご指摘ください.
![Flask アプリの構成図.png](https://qiita-image-store.s3.amazonaws.com/0/284026/a42a6e24-d8db-e0d4-247f-630b42e64732.png)


# むすび
各ファイルの基本的な関係を理解できたつもり.  今後迷子になることはないはず.
1つのファイルにバッチ処理とシェルスクリプトを記述する

# バッチとシェルスクリプトの共存
MSBuildのビルドイベントを書いていた時に，WindowsでもLinuxでもビルドイベントが動作してほしかったので考えた。

```shell
: <<END_OF_BATCH
@ECHO OFF
REM batch file
ECHO BATCH FILE !!

EXIT /B
REM end of batch
END_OF_BATCH
#
# shell script
echo "SHELL SCRIPT!!" #
#
# end of shell script
#
```


上のようなコードを改行コードLFで保存する。コマンドプロンプトで実行すると `BATCH FILE !!`，シェルで実行すると `SHELL SCRIPT!!`と表示される。

# 解説
カギを握るのは1行目の `:` である。バッチファイルではラベルの定義が行われ，シェルでは終了コード0を返すコマンドが実行される。

ヒアドキュメント`<<`を用いて，シェルでのみ，`END_OF_BATCH`までをコマンドとして読まないようにして，バッチファイルとして実行したときにだけ実行されるようにしている。

バッチファイルの内容の最後で`EXIT /B`を行い，`END_OF_BATCH`でヒアドキュメントを終了している。

Visual Studio のビルドイベントの設定からは，改行コードをLFにできないため，コマンドあるいは引数の末尾にCRが付け加えられてしまい，エラーの原因になる？ [^1]
~~行末に `;: ` (セミコロン コロン スペース) を挿入することでエラーを回避できる。(空行は `: `(コロン スペース))~~ [^2]
行末に` #` (スペース ナンバー) を挿入することでエラーの回避ができる。(空行は`#` (ナンバー))
# 思ったこと

日本語を含めるとどうあがいても苦しかった。つらい。 → 部分的にShift-JISとUTF-8を組み合わせれば，表示できなくもない。
コマンドプロンプトが#をコメントとして扱ってくれさえすれば，shebangを書けるのに。
Qiita初めてなのでよくわからん。

[^1]: 少なくともWSLのUbuntu 18.04.1，dotnet 2.1.500でdotnet buildしたとき，CRLFであることを意識した記述をしなくてもエラーにならないっぽい？
[^2]: `;: `の場合，複雑なことをやろうとしたら，そのものがエラーの原因になってしまった
Koto2.0.0以降(Block高474420)のCPUでのマイニング方法

#Koto2.0.0

Koto2.0.0からSapling対応になります。
Block高474420(2019年1月5日ごろ)以降はブロックサイズの変更により現在のcpuminerではマイニングができません。

2019年1月5日までにマイニングソフトをアップグレードしてください。

#アップグレード方法

リリースファイルは下記にあります。

https://github.com/KotoDevelopers/cpuminer-yescrypt/releases

ソースからビルドする場合は

`git clone https://github.com/KotoDevelopers/cpuminer-yescrypt.git`
`cd  cpuminer-yescrypt`
`./autogen.sh`
`./configure`
`make`

minerd
が実行ファイルになります。
LaravelでReactを試す

LaravelのフロントエンドにReactを使ってみようと思い、環境を構築した

## 環境
- Laravel 5.5

## 手順

### Reactの導入

```bash
# フロントエンドをreactに変更
php artisan preset react
React scaffolding installed successfully.
Please run "npm install && npm run dev" to compile your fresh scaffolding.
```
```
# Reactを追加
$ yarn install
yarn install v1.12.1
info No lockfile found.
[1/4] 🔍  Resolving packages...
warning laravel-mix > autoprefixer > browserslist@2.11.3: Browserslist 2 could fail on reading Browserslist >3.0 config used in other tools.
warning laravel-mix > css-loader > cssnano > autoprefixer > browserslist@1.7.7: Browserslist 2 could fail on reading Browserslist >3.0 config used in other tools.
warning laravel-mix > css-loader > cssnano > postcss-merge-rules > browserslist@1.7.7: Browserslist 2 could fail on reading Browserslist >3.0 config used in other tools.
warning laravel-mix > css-loader > cssnano > postcss-merge-rules > caniuse-api > browserslist@1.7.7: Browserslist 2 could fail on reading Browserslist >3.0 config used in other tools.
[2/4] 🚚  Fetching packages...
[3/4] 🔗  Linking dependencies...
warning "laravel-mix > img-loader@3.0.1" has unmet peer dependency "imagemin@^5.0.0 || ^6.0.0".
[4/4] 📃  Building fresh packages...
success Saved lockfile.
✨  Done in 435.92s.
```

めっちゃwarning出ているが、一旦進める。

resources/assets/js/components/にあるReactのサンプルを確認。
exampleのidに対しレンダリングしているようなので、対応する画面を作る。

```Example.js
# 一部抜粋
if (document.getElementById('example')) {
    ReactDOM.render(<Example />, document.getElementById('example'));
}
```

/resources/views配下にreact.blade.phpを作成
herokuにアップした時、jsが読み込めなくてエラーになったので、
local環境とheroku上の環境を分けて、herokuではsecure_assetで読み込む。

```react.blade.php
<!doctype html>
<html lang="{{ app()->getLocale() }}">
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Laravel</title>
        @if(app('env')=='local')
            <link href="{{asset('css/app.css')}}" rel="stylesheet" type="text/css">
        @endif
        @if(app('env')=='production')
            <link href="{{secure_asset('css/app.css')}}" rel="stylesheet" type="text/css">
        @endif
    </head>
    <body>
        <div id="example"></div>
        @if(app('env')=='local')
            <script src="{{asset('js/app.js')}}" ></script>
        @endif
        @if(app('env')=='production')
            <script src="{{secure_asset('js/app.js')}}" ></script>
        @endif
    </body>
</html>
```

routes/web.phpを編集。以下を追加。

```web.php
Route::get('/react', function () {
    return view('react');
});
```

```
yarn run dev
php artisan serve
```

http://localhost:8000/react
を確認すれば、Reactで作成された画面が表示された！

### 参考
https://www.ritolab.com/entry/34
https://qiita.com/sakuraya/items/411dbc2e1e633928340e
Ansibleでraspberry piの設定を自動化しよう [2.7対応]

![ansible-282283.png](https://qiita-image-store.s3.amazonaws.com/0/258841/13747825-f3a3-07ef-70c7-3c55333cfaaf.png)

# 背景

RaspberryPiを2台をものの弾みで処分し再度購入しました。
その際に設定が面倒だしまたいつか処分して再購入する際に設定が発生する可能性があるので
せっかくなので自動化しておこうと思い使ってみました。

[ansible/ansible](https://github.com/ansible/ansible)

今回はインストールから動作確認までと概要を記載

具体的な使用と実践は次回以降から記載していきます。

書く予定のこと

* Ansible概要
* Ansibleを試す
* Ansibleの実践的な利用 (次回)

# Ansible？

> Ansible（アンシブル）は、レッドハットが開発するオープンソースの構成管理ツールである。サーバを立ち上げる際、あらかじめ用意した設定ファイルに従って、ソフトウェアのインストールや設定を自動的に実行する事が出来る[1]。特に大規模なコンピュータ・クラスターを構築する時に、時間の短縮やミスの削減に有用である。構成管理に加え、オーケストレーションやソフトウェアデプロイメントの機能を持つ[2]。

[wiki](https://ja.wikipedia.org/wiki/Ansible_(%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2))より引用

ansibleは簡単に言えばサーバー構成自動化ツールです。
構成管理ツールといえばChef, Puppetを想像しますがその一角といった認識で間違いないはずです。
_Infrastructure as a Code_ってやつです

Ansible は端的に言えば

* hostsファイル
* playbook
* モジュール

の、3点で成り立っている。
ちなみに読み方は「アンシブル」

# 環境

■Ansiblesサーバ
Ubuntu(18.04)

■Ansibleホスト
raspberry pi * 2

AnsibleはSSH接続したサーバに対して、ミドルウェアのインストールや設定ファイルの更新を行うツールです。なのでsshはパス無し必須なので設定を行っておいてください。

# 導入手順

### インストール

サーバに下記をインストール

``` bash
$ apt install -y epel-release
$ apt install -y ansible
```

インストールが正しく行われたかを確認
指定してホストへpingを実行する

``` bash
$ ansible --version
ansible 2.7.2

# SUCCESSが出ればインストールは成功
$ ansible -m ping 192.168.1.136
192.168.1.136 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}
```

|オプション|説明|
----------|----
|-i INVENTORY|インベントリファイルのパスを指定。デフォルトは「/etc/ansible/hosts」|
|--help|ansibleコマンドのヘルプを表示|
|-m MODULE_NAME|モジュールを指定|

モジュールはたくさんある。
よく使うのはここらへん

* file
* copy
* template
* service
* lineinfile

### ディレクトリ構成

ベストプラクティスは公式より下記のようになっている
特別特殊なことをやりたい訳ではないのでとりあえずこちらを使用する

https://docs.ansible.com/ansible/latest/user_guide/playbooks_best_practices.html

```
playbooks
├── development
├── others.yml
├── production
├── roles
│   ├── common
│   │   ├── handlers
│   │   │   └── main.yml
│   │   └── templates
│   │       └── ntp.conf.j2
│   └── nginx
│       ├── handlers
│       │   └── main.yml
│       └── templates
│           └── default.j2
├── site.yml
├── staging
└── webservers.yml
```

### hostsを編集

今回使用するhostを記載する

``` 
[webservers]
raspberrpi01
raspberrpi02

[dbservers]
raspberrpi03
```

### Playbookを編集

```
---
- hosts: webservers
roles:
  - common
  - webapp

- hosts: dbservers
roles:
  - common
  - db_middleware
```

## 実際に使ってみる

上まででとりあえず導入は完了。

# 参考URL

[Ansibleの基本的な使い方](http://www.dn-web64.com/archives/web/ansible_how_to_use/)
[CNN] Global Average Pooling 層のすすめ


###Global Average Pooling 層の良いポイント

<b>パラメーター数を非常に少なくすることができる</b>

→　モデルが単純になり、過学習をしにくくなる


# Flatten 層と Global Average Pooling 層の比較
####Flatten 層

```python


model = models.Sequential()
model.add(layers.Conv2D(32, (3, 3), activation='relu',
                        input_shape=(150, 150, 3)))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(128, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(256, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Flatten())
model.add(layers.Dense(512, activation='relu'))
model.add(layers.Dense(1, activation='sigmoid'))

model.summary()

```
>Total params: 6,811,969
Trainable params: 6,811,969
Non-trainable params: 0

####Global Average Pooling 層
<b>Flatten層をGlobal Average Pooling層にしたこと以外はすべて同じ</b>

```python


model = models.Sequential()
model.add(layers.Conv2D(32, (3, 3), activation='relu',
                        input_shape=(150, 150, 3)))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(128, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(256, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(GlobalAveragePooling2D())
model.add(layers.Dense(512, activation='relu'))
model.add(layers.Dense(1, activation='sigmoid'))

model.summary()

```

>
Total params: 520,513
Trainable params: 520,513
Non-trainable params: 0

##結果
・Flatten層 : 6,811,969
・Global Average Pooling層 : 520,513
Kali Linuxによるセキュリティテスト環境構築

### やったこと
- Virtual Box上に以下の環境を構築
    - KaliLinux
    - Metasploitable2
- nmapによるポートスキャニング
オプションいっぱい。

- metasploit frameworkによる侵入
攻撃対象サーバの既知の脆弱性であるvsftpdから侵入

- rootパスワード解析
John the ripperを使用したものの、10分たっても終わらないため断念。

- バックドア設置
rootの.sshフォルダ内に公開鍵を配置し、いつでもSSHでアクセスできるようバックドア設置

- アクセスログの消去

参考になったサイト
[ちょこっとホワイトハッカーになった気持ちになって、VirtualBox上にKali Linuxをインストールし、Metasploitを使ったペネトレーションテスト（脆弱性診断）をやってみた](https://qiita.com/fs-rd-takuya-takeda/items/33dedf3d007b9b3bde28)
主にこちらのサイトの手順を実施した。

[攻撃者が侵入後に行うバックドアの設置例](http://www.atmarkit.co.jp/ait/articles/0212/25/news001.html)
[アクセスログの改ざんと検出方法](http://www.atmarkit.co.jp/ait/articles/0302/22/news002.html)
GJKアルゴリズムについて調べたことのまとめ

物体の衝突判定を高速に行いたい物理エンジン界隈の人たちは，GJKアルゴリズムというのを使っているらしく，調べたのでメモする．

![anim.gif](https://qiita-image-store.s3.amazonaws.com/0/25325/59acaff4-e008-81e6-87db-56ea30cec306.gif)

名前はいかついものの，実は簡単なアルゴリズムになっている．
分かりやすい記事は以下．

- http://www.dyn4j.org/2010/04/gjk-gilbert-johnson-keerthi/
- https://caseymuratori.com/blog_0003
   - ここの人は従来の説明は無駄が多いことを主張してくれている（サポート写像の計算対象について）が，ググッて出てくるのはこの人と同じ考え方でのサポート写像の計算対象を減らしているので，2018年の段階では浸透済みの考え方なのかもしれない．


## ミンコフスキー和（差という人もいる）
- ミンコフスキー和という，形状同士の足し算の概念がまずある
- 形状Aと形状Bが接触している場合は，AとBは少なくとも内部の1点を共有している
- つまり，Aと-Bのミンコフスキー和が原点を含んでいることになる

形状Aと形状Bが接触しているかどうか，つまり，
True / Falseの情報は，A-Bのミンコフスキー和が原点を含むか否かという話と等価であることになる．
そして，ミンコフスキー和が原点を含むかどうかは，高速に判定するアルゴリズムがあって，それがGJKアルゴリズム．

ただし，実際にミンコフスキー和は求めない！というのがポイント．
ここでは，形状AとBを凸であるとする．
Aを構成するvertexが$n_A$個，Bを構成するvertexが$n_B$個であるとすると，A-Bのミンコフスキー和を構成するvertexは$n_A \times n_B$個ある．（実際はそのconvex hullとなる）
これは計算量が多いということで，サポート写像という考え方をして，実際にミンコフスキー和を求めること無く話を進めることができるというからくりになっている．

以上のことは https://www.youtube.com/watch?v=Qupqu1xe7Io を見ればすぐ分かる．

## simplex: 単体
simplexは2Dなら三角形，3Dなら四角錐のことを指していて，ミンコフスキー和が原点を含むかどうかを考える際にsimplexが原点を含むかどうかという捉え方をする．


## GJKアルゴリズム
http://www.dyn4j.org/2010/04/gjk-gilbert-johnson-keerthi/ に載っている説明を可視化してみた．
一番最初のサポート写像の方向は，AとBの中心を結ぶ方向ベクトルが良いらしいので，そうした．

![anim.gif](https://qiita-image-store.s3.amazonaws.com/0/25325/59acaff4-e008-81e6-87db-56ea30cec306.gif)

上のブログのコメントにも書いてあるが，サポート写像の求め方は，形状Aのvertex$n_A$個のそれぞれの内積の最大値と形状Bのvertex$n_B$個のそれぞれの内積の最小値の差分となって，$n_A + n_B$回の計算が必要となる．
もし，形状がprimitiveの場合，例えば円の場合はサポート写像は自明に求まることを利用すると，計算が早くなるのもポイント．
なので，URDFとかではvisualize用のモデルとcollision用のモデルが分かれているのかなと思う．

https://www.medien.ifi.lmu.de/lehre/ss10/ps/Ausarbeitung_Beispiel.pdf の3.3を読むと納得できる．

## 距離を計算するのはGJKアルゴリズムの外側の話になる

- http://www.dyn4j.org/2010/04/gjk-distance-closest-points/
ココらへんが詳しそう．
DjangoでDBから取得したオブジェクトのnull判定をやりたかった話

普段仕事でSeasar2という化石を扱っている人間がDjangoで遊んでる際、findByIdで取得したentityのnull判定を実装するときにとても悩んだからメモを残す

Seasar2のこんな感じの処理をDjangoで書きたかった。

```java:hoge.java
entity = XXXService.findById(param1);
if (entity == null) {
    return false;
}
```

最初にDjangoのDBからの取得方法としてgetを使った実装をしていた。

```python:hoge.py
entity = models.Entity.objects.get(colA == param1)
```

しかしこの方法では colA == param となるレコードがDBに存在しない場合にDoesNotExistが発生してしまう。
例外をキャッチして処理しても良いのだが、それはそれで何か個人的には好かない。


webでいろいろ調べていたら先人がいた
[Djangoで空のクエリーセットをチェックする](https://code.i-harness.com/ja/q/152ccf)

ということは次のようにすればいけるのではとおもってやってみた

```python:hoge2.py
querySet = models.Entity.objects.filter(colA == param)
if querySet.first() is None:
	return False
```


filterでQuerySetを取得した上で、単体ならfirst()とか複数ならlistに変換して処理するとよさそうだ。
JRA公開の重賞スケジュールを「予定なし」でGoogleカレンダーに取り込む

# はじめにの前に
※今年(2018年)1月に自分のブログに公開した内容ですが、2019年カレンダーがJRAから公開されていましたので、それに合わせてこちらでも加筆した上で、記事を載せさせていただきます。

[iCalendar形式ファイルのイベントを「予定なし」にする](https://masaminh.oumanoshasin.com/post-774/)

# はじめに

皆さん、競馬、楽しんでますか?(笑)

中央競馬の重賞日程と開催日程に関して、日本中央競馬会(JRA)が、Googleカレンダー等に取り込めるようにiCalendar形式でカレンダーを提供してくれています。

[他のカレンダーと連携する：レーシングカレンダー　JRA](http://jra.jp/keiba/common/calendar/ics2019.html)

ありがたく使わせていただこうとしていたのですが、実際にGoogleカレンダーに取り込んでみると「予定あり」として取り込まれてしまいます。

どうでもいいと言えばいいのですが、「予定なし」で取り込みたかったため、ちょっと公開されているファイルを書き直すツールを作ってみました。

# 「予定あり」となってしまう理由

これは各イベントで「TRANSP:OPAQUE」という指定がされているため。
ここを「TRANSP:TRANSPARENT」に書き換えてあげると「予定なし」として取り込むことができます。

ということで、この書き換えをするプログラムを作ってみました。

※なお、iCalendar形式の内容は[こちら](http://www.asahi-net.or.jp/~CI5M-NMR/iCal/ref.html)の説明がわかりやすかったです。

# 実装内容

説明するよりソースを見てもらう方がわかりやすいと思うので、いきなり実装内容です。
ちなみに[github](https://github.com/masaminh/ics_tofree)にもソースは置いてあります。

ソースを見ていただければわかるように[icalendar](https://pypi.org/project/icalendar/)というライブラリを使っていますが、これはpipでインストール可能です。

```python:ics_tofree.py
"""Calendarファイル(.ics)内のイベントをすべて「予定なし」に書き換える."""
import argparse
from icalendar import Calendar
import sys


def update_transp(cal, transp):
    """VEVENTコンポーネントのTRANSPプロパティを指定のものに書き換える."""
    for ev in cal.walk():
        if ev.name == 'VEVENT':
            ev['TRANSP'] = transp


def main():
    """メイン関数."""
    parser = argparse.ArgumentParser()
    parser.add_argument('input', nargs='?',
                        type=argparse.FileType(mode='r'), default=sys.stdin)
    parser.add_argument('-o', '--output', nargs='?',
                        type=argparse.FileType(mode='w'), default=sys.stdout)
    args = parser.parse_args()

    cal = Calendar.from_ical(args.input.read())
    update_transp(cal, 'TRANSPARENT')

    args.output.write(cal.to_ical().decode('utf-8'))


if __name__ == '__main__':
    main()
```

# 動作確認環境
Python 3.6.4
iCalendar 4.0.0
(2018年1月時点)

Python 3.7.1
iCalendar 4.0.3
(2018年11月時点)

# 最後に
競馬もコンピュータを使って快適に楽しみましょう！(笑)
webpack初心者の導入記録（個人的備忘録）

フロント歴がもうすぐ2年になるのに
webpackってなんぞ・・・？
状態だった僕が業務で導入しなければいけなくなったので
少し実装記録を残したいと思いたった。

# webpackのインストール
グローバルにはインストールしていません。
```
npm install webpack webpack webpack-cli
```

# やりたきこと
ディレクトリ構造を変えず、一つのjsファイルにバンドルする

現構造は
src
├ dir1
│ └ dir1-1
│ 　 ├ pc
│ 　 │ └ common.js
│ 　 └ sp
├ dir2
│ └ dir2-1
├ dir3
└ ・・・

common.js内に
名前空間から関数処理、実行まですべてが書かれている。とてつもない行数だ。

改善①
src
├ dir1
│ └ dir1-1
│ 　 ├ pc
│ 　 │ ├ aaa.js
│ 　 │ ├ bbb.js
│ 　 │ └ ccc.js
│ 　 │ └ main.js
│ 　 └ sp
├ dir2
│ └ dir2-1
├ dir3
└ ・・・
aaa.js、bbb.jsは
元common.js内のオブジェクト。
機能ごとにモジュール化した。
exportやimportを使い、main.jsに読み込ませる。
webpackのおかげでie11でも動いた。

```.js
// aaa.js

var CHANGE_LANGUAGE = { // 適当
  init: function() {
　　　　　・・・
 }
}

export default CHANGE_LANGUAGE {
  return CHANGE_LANGUAGE();
}
```

```.js
// main.js
var NAMESPACE = NAMESPACE || {};
・・・
import CHANGE_LANGUAGE from "./aaa.js";
NAMESPACE.CHANGE_LANGUAGE = CHANGE_LANGUAGE();
・・・
// 実行する
if(NAMESPACE.DETECT.isActive) { // 適当な時に実行
  NAMESPACE.CHANGE_LANGUAGE.init();
}
```

main.js内を実質common.jsと同じ内容にする。
main.jsをwebpackでビルドして吐き出す。


# webpack.config.js
ニュアンスコード。

```.js
const glob = require('glob');
const path = require('path');
const dir_path = '/js/';
const entry_point = path.resolve(__dirname, dir_path + 'src'); // src内対象
const dir = ['dir1', 'dir2', 'dir3'];
const separation = ['pc', 'sp'];
const targets = glob.sync(`${entry_point}/+(${dir.join('|')})` + "/**/" + `+(${separation.join('|')})/main.js`); // main.jsのみ
const entries = {};
const keys = [];

function findSeparation(element) {
  for(var i=0; i<=separation.length; i++) {
    if(element === separation[i]) {
      return separation[i];
    }
  }
}

targets.forEach(value => {
  const re = new RegExp(`${entry_point.replace(/\\/g, '/')}/`); // Windowsで'\'を'/'に直す処理
  const path = value.replace(re, '');
  const split_array = path.split('/'); // pathを/区切りで配列化
  const separation_point_num = split_array.findIndex(findSeparation) + 1; // separationの次の位置
  split_array.splice(separation_point_num, split_array.length);
  const newPath = split_array.join('/') + '/common';
  var matchPath = keys.find(function(element) {
    return element === newPath;
  });

  if(matchPath) {
    entries[matchPath].push(value);
  }
  else {
    keys.push(newPath);
    entries[newPath] = [value];
  }
});

module.exports = {
  mode: 'production',  // モードの指定（[development],[production],[none]）
  entry: entries,
  output: {
    path: path.join(__dirname, dir_path + '/public/'),
    filename: '[name].js'
  },
}
```
やっていることは結局
key:生成したい構造のpathとファイル名
value:対象ファイルのpathが入る配列
という形のentriesというオブジェクトを生成している。

この組み合わせでディレクトリ構造およびバンドルされたjsファイルが生成される。
ちなみにwindowsだと/は\にしないといけないようのでdir_pathに文字列で/と書いてしまっているのは改善したほうがいいかもしれない。一応途中で変換処理をしているので動く。



# お世話になったサイト
https://codogue.com/asciitree/
ディレクトリ構造を生成してくれる。
メンバーや環境を共有している他領域に共有する上でとても役立ちました。
treeコマンドでわざわざディレクトリを生成するなんてことはしたくなかったので。
centOS7のapache2.4.6を削除して最新版をインストールしよう

CentOS7にデフォで入っているapache2.4.6(httpd)はちょっと古いので、なるべく最新版にしましょう。特にhttp2とかやりたい人は**必須**らしいです！

ただ、バイナリからインストールするのはちょっと怖いし、バージョンアップもお手軽なパッケージからインストールしたいのが人の子の性...。なので、以下の手順でインストールします。

1. [IUSリポジトリ](https://centos7.iuscommunity.org/ius-release.rpm)をインストール
2. 現在のhttpdの削除
3. IUSリポジトリから、apache2.4.35のインストールをする

# IUSリポジトリのインストール

centOS7の方は最初から入っているかもしれません...

```bash
sudo yum install https://centos7.iuscommunity.org/ius-release.rpm
```

# 現在のhttpdの削除と、IUSからapache2.4の最新版をインストールする

ここで、依存関係のあるパッケージが削除されますので、メモっておきます。私の場合は`httpd-tools`と`python36u-mod_wsgi`が依存関係にあったため削除しました。

```bash
sudo yum remove httpd

kiwi@118-27-32-60:~$ sudo yum install httpd --disablerepo=base --disablerepo=updates --enablerepo=ius
読み込んだプラグイン:fastestmirror, langpacks
Loading mirror speeds from cached hostfile
 * epel: ftp.riken.jp
 * epel-debuginfo: ftp.riken.jp
 * epel-source: ftp.riken.jp
 * extras: ftp.iij.ad.jp
 * ius: mirrors.kernel.org
依存性の解決をしています
--> トランザクションの確認を実行しています。
---> パッケージ httpd24u.x86_64 0:2.4.35-1.ius.centos7 を インストール
--> 依存性の処理をしています: httpd24u-tools = 2.4.35-1.ius.centos7 のパッケージ: httpd24u-2.4.35-1.ius.centos7.x86_64
--> 依存性の処理をしています: httpd24u-filesystem = 2.4.35-1.ius.centos7 のパッケージ: httpd24u-2.4.35-1.ius.centos7.x86_64
--> 依存性の処理をしています: httpd24u-filesystem = 2.4.35-1.ius.centos7 のパッケージ: httpd24u-2.4.35-1.ius.centos7.x86_64
--> 依存性の処理をしています: libapr15u-1.so.0()(64bit) のパッケージ: httpd24u-2.4.35-1.ius.centos7.x86_64
--> 依存性の処理をしています: libapr15uutil-1.so.0()(64bit) のパッケージ: httpd24u-2.4.35-1.ius.centos7.x86_64
--> 依存性の処理をしています: libnghttp2.so.14()(64bit) のパッケージ: httpd24u-2.4.35-1.ius.centos7.x86_64
--> トランザクションの確認を実行しています。
---> パッケージ apr15u.x86_64 0:1.5.2-2.ius.centos7 を インストール
---> パッケージ apr15u-util.x86_64 0:1.5.4-3.ius.centos7 を インストール
---> パッケージ httpd24u-filesystem.noarch 0:2.4.35-1.ius.centos7 を インストール
---> パッケージ httpd24u-tools.x86_64 0:2.4.35-1.ius.centos7 を インストール
---> パッケージ libnghttp2.x86_64 0:1.31.1-1.el7 を インストール
--> 衝突を処理しています: httpd24u-tools-2.4.35-1.ius.centos7.x86_64 は httpd-tools < 2.4.35 と衝突しています
--> 依存性解決を終了しました。
エラー: httpd24u-tools conflicts with httpd-tools-2.4.6-80.el7.centos.1.x86_64
 問題を回避するために --skip-broken を用いることができます。
 これらを試行できます: rpm -Va --nofiles --nodigest

# 依存関係のエラーが出た場合、解決する
sudo yum remove httpd-tools python36u-mod_wsgi
sudo yum remove httpd
```

デフォルトだと`base`や`updates`を参照してしまうので、`--disablerepo`のオプションで無効化します。

また、IUSの利用を強制する場合、`--enablerepo`オプションで有効化します。

```bash
sudo yum install httpd --disablerepo=base --disablerepo=updates --enablerepo=ius
```

# httpd.conf

初期設定では新しい`httpd.conf`に置き換わっているので、前まで使っていた`httpd.conf`に戻しましょう。
`httpd`の削除時だかインストール時に(適当)`yum`が`/etc/httpd/conf/httpd.conf`をバックアップしておいてくれるので、それに戻しておきます。

```bash
cd /etc/httpd/conf
sudo mv httpd.conf.rpmsave httpd.conf
```

# httpdの起動

自動起動とデーモンの起動を設定します。失敗した場合、ログを確認するなり、`systemctl status httpd`で調べましょう

```bash
sudo systemctl enable httpd
sudo systemctl start httpd
```

終わり！
dockerによるお手軽jupyter環境構築

jupyter環境の構築をdockerによってお手軽に作成します
これからデータサイエンス初めてみたい、docker使ってみたいって方向けです。

##注意
- dockerは入っている前提【参考】　[DockerをMacにインストールする](https://qiita.com/kurkuru/items/127fa99ef5b2f0288b81)
- 環境はMAC + Docker for MAC　

###1, データ分析様のDockerイメージを取得する

```
$ docker pull jupyter/scipy-notebook
```

jupyterのDockerイメージが使えるのでそれをそのままインストールしてくる
今回はjupyter、pandas、scikit-learn など基本的なPython データ分析ライブラリが
同梱されているscipy-notebookを使用する
他にもRやtensorflow、Hadoop等いろいろ同梱されているイメージもあるので
用途にあったものを使ってみてください
【参考】 [JupyterのDockerイメージまとめ](https://qiita.com/kshigeru/items/ea174d6bcacc474f2a51)

###2, イメージがダウンロードされているか確認する

```
$ docker images jupyter/scipy-notebook
```

```
REPOSITORY TAG IMAGE ID CREATED SIZE
jupyter/scipy-notebook latest ********** 1 months ago 4.56GB
```

上記のように出力されたらOK
必要最小限のイメージを選んだのにSIZE=4.56GB、、、

### 3, Dockerコンテナを起動して、同時にjupyterlabを起動する

```
$ docker run -d —name scipynb -p 8888:8888 -e JUPYTER_ENABLE_LAB=yes jupyter/scipy-notebook
```

### 4, jupyter認証用のトークンを取得する

```
$ docker exec scipynb jupyter notebook list
```

```
http://localhost:8888/?token=************************* :: /home/jovyan
```

このコマンドでjupyterの認証に使うトークンを取得できる
*****の部分がこの後でつかう認証用のトークンなのでメモ帳とかにコピペしておく

### 5, jupyterにアクセスする

ブラウザを開いて、jupyterのurlへアクセスする
http://localhost:8888
アクセスしたら認証トークンを要求されるので4でコピペしたのを貼り付ける
ひとまずこれでローカルDocker上でjupyterが使えます。

これで完了です！
ことりんと一緒 - 6. Kotlin/Native

## 概要 / 説明
**Kotlin 1.3** のリリースには、ベータ版となった **Kotlin/Native** が含まれています。
簡単に IntelliJ から Kotlin/Native を使ってみたいと思います。

### Kotlin/Native
Kotlin は Java や Scala 同様に JVM 言語として設計されています。そのため、実行するには 仮想マシン(JVM) が必要となります。ところが、この Kotolin/Native は 仮想マシンを必要せずに動作するように ネイティブバイナリとしてコンパイルする技術です。

## 前提 / 環境
### ランタイムバージョン
- Kotlin : 1.3.0

### 開発環境
- OS : Mac
- IDE : IntelliJ IDEA
- Build : Gradle

## 手順 / 解説
### 1. Kotlin/Native プロジェクトの作成
<img width="954" alt="image.png" src="https://qiita-image-store.s3.amazonaws.com/0/127983/95cf33fc-2c6d-7348-611a-58f4191e26e6.png">

新規プロジェクトを作成する時に選択するプロジェクトタイプとして、Kotlin カテゴリの中に含まれている、Kotlin/Native を選択します。
プロジェクトの構成はデフォルトのままで問題なしです。

### 2. プロジェクト構成
<img width="1280" alt="image.png" src="https://qiita-image-store.s3.amazonaws.com/0/127983/b48a20fc-b09b-7962-9c61-bdb3584997a8.png">

ソースコードディレクトリが自動で作られています。環境の OS が MacOS だからか、ディレクトリ名が **macosMain** となっています。

### 3. ソースコード
#### build.gradle
```gradle
plugins {
    id 'kotlin-multiplatform' version '1.3.0'
}
repositories {
    mavenCentral()
}
kotlin {
    targets {
        fromPreset(presets.macosX64, 'macos')

        configure([macos]) {
            compilations.main.outputKinds('EXECUTABLE')
            compilations.main.entryPoint = 'sample.main'
        }
    }
    sourceSets {
        macosMain {
        }
        macosTest {
        }
    }
}

task runProgram {
    def buildType = 'release'
    dependsOn "link${buildType.capitalize()}ExecutableMacos"
    doLast {
        def programFile = kotlin.targets.macos.compilations.main.getBinary('EXECUTABLE', buildType)
        exec {
            executable programFile
            args ''
        }
    }
}
```

#### アプリケーション
```kotlin
package sample

fun hello(): String = "Hello, Kotlin/Native!\n"

fun main(args: Array<String>) {
    println(hello())
    platform.posix.system("date")
    platform.posix.system("ls -la")
}
```

基本に忠実に HelloWorld の標準出力と、外部コマンドの実行を入れてみました。

### 4. ビルド
<img width="358" alt="image.png" src="https://qiita-image-store.s3.amazonaws.com/0/127983/b544078c-cd13-ae74-a5c7-a9e6c52316ca.png">

Gradle タスクの **build** を実行します。

<img width="1209" alt="image.png" src="https://qiita-image-store.s3.amazonaws.com/0/127983/fe9b9e42-4484-2fa5-1a8b-010b83e291cc.png">

ネイティブバイナリを生成するためか、少し時間がかかるようです。

### 5. 実行
**build/bin/macos/main/release/executable** ディレクトリの配下にネイティブバイナリが生成されます。
このバイナリファイルは、MacOS上で直接どこでも実行できます。

```bash
build/bin/macos/main/release/executable $ ./HelloKotlinNative.kexe
Hello, Kotlin/Native!

2018年 11月18日 日曜日 21時01分51秒 JST
total 1984
drwxr-xr-x  3 shinyay  staff       96 11 18 20:36 .
drwxr-xr-x  3 shinyay  staff       96 11 18 20:35 ..
-rwxr-xr-x  1 shinyay  staff  1013336 11 18 20:36 HelloKotlinNative.kexe
```

## まとめ / 振り返り
Kotlin/Native は、まだベータ版の扱いですが十分に楽しめそうです。
今回は外部コマンドの呼び出しとしてお試しに作ってみましたが、次はコマンドラインツールを作ってみようかなと思います。

### 今回のソース
- [kotlin-native-hello](https://github.com/shinyay/kotlin-native-hello)
GameAWeek２週間目

Game A Week２週間目です！
=
二週間目はまずはいろんな作業とかコードなどunityでできることを学ぶためにサンプルコードをもとに作って勉強させていただきました。
https://codegenius.org/open/courses/24/sections/104
このサイトを参考にさせていただきました！
とても分かりやすく説明されておりとても作りやすかったです！
パクだけでは勉強にならないので一個一個コードを勉強していきました。
今週作ったのはシューティンゲームですダウンロードしてぜひコメントでアドバイスなどください！
https://www.dropbox.com/s/3h54cf3bptykfaf/week2.zip?dl=0

今回の二週間目で学んだこと＝＝＝＝＝＝＝
================
forward : TransformのZ軸
Input.GetAxis : float形で代入する
vector3 : x,y,zの値を取得する
time.deltaTime : １秒当たりの加算合計
Quaternion : 回転を表す
MoveRotation : オブジェクトを指定した方向に回転
Instantiate : オブジェクトを生成する
OnTriggerEnter : ぶつかる
CompareTag : 相手のTag
identity : メソッドではなくStatic、回転させないようにする
root : 情報を取得
LookAt : 指定した方向に向きを変える
NavMeshAgent : 追いかけてくるようにする
screenLoad : スクリーンをロードする
＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝

今回の感想
=
今回のシューティングゲームでたくさんのことを学ぶことができた。
いろんな技術を得ることができたので次作るときに生かしたい
また、今回作るのに少々時間がかかってしまい終わるか心配でしたが何とか終わらすことができてよかった。

プレイした感想、アドバイスなどぜひぜひ書いていただけると今後の学びにつながります！
=
ライブラリの作り方

Azure Sphereでライブラリを作成する手順です。
Azure Sphere SDKのバージョンは`18.11`で確認しました。（`TP4.2.1`はダメです。アップデートしましょう。）

# プロジェクトを作る

新しいソリューションに、ライブラリを呼び出すアプリケーションのプロジェクトと、呼び出されるライブラリのプロジェクトを作成します。

* MT3620App1 ... アプリケーションのプロジェクト。Blank Application for MT3620 RDB。
* Library1 ... ライブラリのプロジェクト。Blank Static Library。

**ファイル > 新規作成 > プロジェクト**
![image.png](https://qiita-image-store.s3.amazonaws.com/0/109634/b3422a72-1012-8942-cd8d-698a6f3fcf58.png)

**ソリューションを右クリック > 追加 > 新しいプロジェクト**
![image.png](https://qiita-image-store.s3.amazonaws.com/0/109634/4f6ccb74-4b5e-594e-a87c-164af1c69790.png)

ソリューションエクスプローラーがこのようになっていれば正常です。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/109634/e022be38-689c-eace-109b-ca2854b55c49.png)

# ライブラリにコードを追加

ライブラリのプロジェクトに含まれているLibrary1.hに宣言、Library1.cに定義を追記します。

```c:Library1.h
#pragma once

int pow2(int a);
```

```c:Library1.c
#include <Library1.h>

int pow2(int a)
{
	return a * a;
}
```

# アプリケーションにライブラリ参照を追加

アプリケーションのプロジェクトに、ライブラリの参照を追加します。

**参照を右クリック > 参照の追加 > Library1をチェック**
![image.png](https://qiita-image-store.s3.amazonaws.com/0/109634/f93e530d-2fbc-b113-fb8a-b256e38f159d.png)

参照にLibrary1が追加されていれば正常です。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/109634/7dccad6e-8343-6112-7387-ee7544329809.png)

# アプリケーションからライブラリを呼び出す

```c:main.c(断片)
...
#include <Library1.h>
...
int main(int argc, char *argv[])
{
...
    // Main loop
    const struct timespec sleepTime = {1, 0};
	int val = 0;
    while (!terminationRequired) {
        Log_Debug("%d %d\n", val, pow2(val));
		val++;
        nanosleep(&sleepTime, NULL);
    }
...
}
```

# 実行結果

![image.png](https://qiita-image-store.s3.amazonaws.com/0/109634/a5f07c59-b662-ebb1-5f96-058eb3f05aa9.png)

# 配布するライブラリのファイル

> 2018/11/23追記

ライブラリを他者に配布するときのファイルは、ヘッダファイルとアーカイブファイル（ライブラリファイル）ですが、どちらもプロジェクトフォルダ配下にあります。

* ヘッダーファイル ... Inc\Public\Library1.h
* アーカイブファイル（Debugビルド） ... bin\ARM\Debug\libLibrary1.a
* アーカイブファイル（Releaseビルド） ... bin\ARM\Release\libLibrary1.a

![image.png](https://qiita-image-store.s3.amazonaws.com/0/109634/79d12c61-4b21-7c34-33b5-6889e816454b.png)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/109634/72f85469-43ed-b1fa-698e-8590e210553f.png)
wekanのdocker-compose起動でコケたメモ

かんばん管理のwekan(https://wekan.github.io/) をdockerで動かそうとしたときに思ったよりコケたのでそのメモ。


- port nunberそのままだとエラー
    - wekan dockerは`8080`で受け付けているので、ローカルでcurlしてもエラーになる
- `ROOT_URL`はlocalhostのままだとダメ
    - 挙動的にレスポンス情報にURLを返却している？
    - そのため、ここには**外からアクセスされるURLを書かなきゃいけない**
    - 上記対応をしない場合、カードの詳細が正しく遷移しない
- 自動起動
    - `restart: always` 追記
- 初回ログイン
    - 自己登録が有効化（メールアドレス、パスワード設定で入れる）なので、作ったあと、自己登録を無効化する
- Wiki見る
    - 公式を見ること。ネットの記事丸コピでコケまくる（ただ、ここもポートはミスっている）
    - https://github.com/wekan/wekan/wiki/Install-Wekan-Docker-for-testing

- 上記を踏まえた`docker-compose.yml`

```
version: '2'
services:
  wekan:
    image: wekanteam/wekan:latest
    links:
      - wekandb
    environment:
      - MONGO_URL=mongodb://wekandb/wekan
      # !! 外部からのアクセスURLにする（リバプロなど挟んでる場合） !!
      #- ROOT_URL=http://localhost:80
      - ROOT_URL=https://XXX
    ports:
      # !! portが違う !!
      # - 80:80
      - 80:8080
    # 自動起動
    restart: always


  wekandb:
    image: mongo:3.2.14
    volumes:
      - /home/johndoe/wekan/data:/data/db
    # 自動起動
    restart: always
```
awkを使ってテキストファイルから効率的にデータを集計する

# 利用シーン

- テキストファイルの1列だけ取り出して新たなファイルを作り加工しやすくしたい!
- でもPython開くのは億劫!`source activate ENV`してウンタラカンタラとかしてられない！

## awkを使おう

awkっていうコマンドがbash, csh, zshなどシェルには存在して、それを使うと非常に便利です。

記述が大変なので導入しか書きませんが、色々出来て奥深いです、awk。

## できること

- 行の要素の数を取り出す
- 特定の列の平均、標準偏差を計算できる
- シートの特定の列が特定の値である行を取り出せる
- っていうか多分PandasとかExcelでやっていることの大半を、コマンド一行で完結できそう

## 大雑把な文法

`awk (オプション) (命令) (ファイル名)`と書きます。こちらは、シェル上で1行で書く場合です。

`awk (オプション) -f (awkファイル名) (ファイル名)`とも書きます。awkコマンドが長くなったり使い回すことになったら、awkファイルに命令を書きだしましょう。

### awkの命令

```awk:example.awk
BEGIN{
    #各行を読む前に実行する命令を書く。
    # 変数を定義したりする。
}
{
    #各行で実行する命令を書く
}
END{
    # 全行読んだあとに実効する命令を書く
}
```

### 例

```shell-session
$ awk -F\, '{ print $2 }' FILE_NAME # カンマ区切りして各行2列目を出力。FILE_NAMEにcsvファイルが来る場合など。
$ awk '{ print $2, $3 }' FILE_NAME # スペース区切りして各行2, 3列目を出力
$ awk '{ print $NF }' FILE_NAME # 最終列を表示
```

NFは予約語で、number of fieldかなんかです。$NFは最終列のセル、NFは要素の数を返します。

NRはnumber of rowです。まあ普通に`wc -l FILE_NAME`でファイルの行数は出ますがね。

### SQL的な使用方法

```shell-session
$ cat cols.txt
abc	1	2	3
def	4	5	6
ga	7	9	10
hij	1	5	99

$ awk '$2 == "1" { print $4 }' cols.txt
abc	1	2	3
hij	1	5	99
```

## 参考文献

1. [A github gist](https://gist.github.com/0/5486125)
ISO/IEC JTC1 Public Available Standard

ISO/IEC JTC1 Public Available Standardを確認した。

https://standards.iso.org/ittf/PubliclyAvailableStandards/

主にSC22

1) 誤植
 ISO/IEC 9899:1999/Cor.1:2001  1st  Programming languages -- C -- Technical Corrigendum 1 JTC1/SC22

HTTP Status 404 – Not Found

すでにISO/IEC 9899:1999が改定済み。Corrigendumの意味がない。結果、リンク切れ。

Corrigendumは、本体が有償であっても、少量の訂正版は無償公開することがある。


2) 他団体規格が先行して利用可能

ECMA 規格
http://www.ecma-international.org/publications/standards/Stnindex.htm

C#
 ISO/IEC 23270:2006  2nd  Information technology - Programming languages -C#  JTC1/SC22 

 ECMA-334 5th Edition / December 2017
C# Language Specification
http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-334.pdf
ET & IoT Technology 2018からIoTの新潮流エッジコンピューティングの流れをみる

IoTは多種多量なデータを大量に処理することが必要とされます。基本的にクラウドのコンピューティング資源を利用して対応するわけですが、その場合に問題となるのがデータ処理の遅延（レイテンシ）。その解決策として、俄然注目されているのが「エッジコンピューティング」です。ET/IoT Technology 2018は、そのIoTの新潮流であるエッジコンピューティングをいち早くキャッチアップしフォーカスをあて、その最先端情報を一望できる展示会です。キャッチフレーズは＜ET×ET（エッジテクノロジー）＞。組込みとつなげる技術を背景に「エッジ領域でどこまでのことができ、どんなもの（新たな価値）を生み出せるのか」をテーマに置いた展示会です。ET/IoT Technology 2018からIoTの新潮流となりつつあるエッジコンピューティングのいまをみていきます。

※下記サイトからの転載。ビッグデータ・AIなどに関するトピックを毎週取り上げています。
[TechCrowd: https://www.techcrowd.jp/related/](https://www.techcrowd.jp/related/)


#[ET×ET(エッジテクノロジー)が新コンセプト、ET/IoT展は、IoT/AI時代に“エッジテクノロジー総合展”として進化する] (https://iotnews.jp/archives/110998)

IoTNEWSのET & IoT Technolog 2018のレポート記事です。

ET & IoT Technology展は、主要メーカ・ベンダから勢いのあるスタートアップ企業まで410社を超える企業が出展、3万人近くが来場。高度なデバイス開発技術(Embedded Technology)と、つなげるIoT技術(IoT Technology)の最新情報を発信してきましたが、双方の視点から“エッジ”にフォーカスし、最新の技術動向からデータの利活用におけるソリューションまであらゆる情報を発信、新たなIoTサービスを創出する「エッジテクノロジー総合展」として進化しようとしています。

新たな企画のひとつが、エッジの最先端を体験し、その先のトレンドや世界観を紹介する「主催者テーマパビリオン」。「次世代モビリティ」「エッジAI」「エッジコンピューティング」「ハプティクス」の4テーマの動向をキャッチアップしたもので、アセントロボティクス、NVIDIA、デンシー、フォグホーン システムズ、LeapMind、Re-alの5社による最新技術から、“エッジテクノロジーがいまどうなっているのか、今後どういうことが起きるのか”を実際に
感じることができるエリア。

展示のひとつが、世界が注目する自動運転AI技術を持つアセントロボティクスの自動運転車。クラウドと連携し機能するのではなく、ほとんどすべてをエッジのみで完結している点が大きな特徴。運転中、周囲の環境がどのように見えているのかがわかり、エッジコンピューティング環境下で動く様を目の当たりにできる。

また、ハプティクスのデモンストレーションはRe-alがリアルハプティクス技術を用い開発した「Real AVATAR」による「遠隔釣りシステム」で、ANA（全日空）が進めるAVATAR事業と提携しているもの。大分県のテーマパークに提供されているものだが、ここでは大分の海で釣りをしている感覚をリアルに体験できる。

同じく新設となる「スタートアップ＆グローバルパビリオン」も見どころのひとつ。国内企業に加え、スタートアップ企業の活躍が目覚しい海外企業も出展。またカンファレンスのトピックスのひとつが、スタートアップ企画との連動で実現した、米シリコンバレー投資ファンド代表のアニス・ウッザマン氏による講演。投資家の目線でシリコンバレーの現状や技術動向を紹介する。本展示会のなかでも特徴的なプログラムで、おおいに注目が集まったようです。


#[ET&IoT Technology 2018 - ロボットを活用したSmart Industryソリューション] (https://news.mynavi.jp/article/20181115-et2018_st/)

マイナビニュースのET & IoT Technologyのレポート記事です。「ET&IoT Technology 2018」で行われていた、STマイクロエレクトロニクスによる人型ロボットと連携したスマートインダストリ(Smart Industry)ソリューションのデモを紹介しています。

人型ロボットと、ST製品24個を組み合わせることでスマートセンシングを可能とした工場の設備(ライン)を連動させたもの。ロボットがオペレータの顔を認識し起動、オペレータが音声でロボットに作業指示を出すと、設備が稼動し、指示されたとおりにラインでの作業を現場のロボットアームなどを通して実行、もし振動などの異常を検知した場合は、緊急停止を自動で行なうなど、被害を抑制することも可能となっている。

このほか、同社ブースでは、さまざまなIoT関連のデモを見ることができるほか、開発体験コーナーも用意してあったようです。


#[ET&IoT Technology 2018 - 組込みコンピュータの機能拡張を進めるPFU] (https://news.nicovideo.jp/watch/nw4194532)

「ニコニコニュース」のET & IoT Technologyのレポート記事です。さまざまな産業分野で活用可能な組込みコンピュータの紹介のほか、車載グレード対応組み込みコンピュータを用いたデモや、組込みコンピュータの機能を拡張させることを可能とする拡張カードAIシリーズの紹介などを行なっていたPFUブースの紹介をしています。

車載グレード対応のデモは、車載組込みシステム開発用コントローラを実際に稼動させ、走行するラジコンから送られてくる映像を処理、表示させるというもの。

また、機能拡張カードは、すでに提供を開始しているEtherCATカードやディープラーニングアクセラレータカードなどの紹介のほか、参考出展として映像系のカードの展示も複数行なわれていたようです。


#[ET&IoT Technology 2018 - クラウドへの接続までサポートするON Semi] (https://news.nicovideo.jp/watch/nw4194420)

こちらも「ニコニコニュース」のET & IoT Technologyのレポート記事です。

オン・セミコンダクターのブースの紹介をしています。自社デバイスを搭載したIoT開発キットの紹介や、どうやって得たデータをクラウドに接続させるのか、といったことまで踏まえたソリューションのデモの紹介などについて紹介しています。

同社はIoT向け半導体の提供とともにそこからさらに一歩踏み込んで、クラウドにつながるところまでをソリューションとして提供しています。同社ブースでも、それを意識したデモとして、IoT開発キット(IDK)のデータとIBM cloudを連動させるといったことが行なわれていたようです。
【PHP】DMM_APIを使ったフルオートアフィリエイトを作ってみた

##試してみた事
TwitterAPIとDMM APIを合体させてTwitterに毎時AV動画のパッケージをアフィリエイトリンク付きでツイートしてみた
##知りたかった事
DMMのパケ写とアフィリンクのツイートだけでAV動画が売れるのかどうかが知りたかった。
##技術的な要素
Cowitterを使って画像付きツイート + アフィリンク
DMM APIを使った商品抽出
###ランダムツイート
同じ作品ばかりのツイートに成らないように色んな作品をツイート出来るようキーワードをランダム化してみた。

```PHP:dmm_api_tweet.php
function keys(){
	$key[] = '女子高生';
	$key[] = 'ロリ';
	$key[] = 'アナル';
	$key[] = '複数';
	$key[] = '三上悠亜';
	$key[] = '熟女';
	$key[] = '高橋しょう子';
	$key[] = 'ゲーム';
	$key[] = '若妻';
	$key[] = 'パンスト';
	$key[] = '親子';
	$key[] = '妹';
	$key[] = 'つるぺた';
	$key[] = 'SOD女子社員';
	$key[] = 'マジックミラー号';
	$key[] = 'マッサージ';

	$cn = count($key)-1;
	$rz = rand(0,$cn);
	$word = urlencode($key[$rz]);
	return $word;
}
```

DMM APIのフロアコードとサンプル一覧はこちら
[【DMMアフィリエイト】DMM-APIの使い方とフロア情報一覧【サンプルコード】](https://dstrikes.net/2018/01/09/post-139/"【DMMアフィリエイト】DMM-APIの使い方とフロア情報一覧【サンプルコード】")
##結果として売り上げが少しだけ上がった
![76adcdef3ab4740b33b5503899d0824c.png](https://qiita-image-store.s3.amazonaws.com/0/21151/9de86a52-86a4-f03a-710a-063ab2425371.png)
上記画像は9か月運用した結果です。
D友とは、DMM新規ユーザー登録で貰える報酬が一撃1000円貰えます。
##サンプルコードのダウンロード先
サンプルコードはこちらに掲載しています。
更に売上を獲得する為のフォロワーを集める立ち回りや、凍結防止対策についても言及しています。

[DMM_APIを使ったフルオートアフィリエイトを作ってみた【サンプルコード付き】](https://note.mu/debikingz/n/n89b720a8aa76)
Reactのパッケージをunpkgから拾う

Reactを入れたプロジェクトを回していた所、煩雑になってきたのでReact本体はCDNから参照させることにしました。

## うまくいかない、リモートサーバの開発環境

Reactのパッケージは、`process.env.NODE_ENV`をみて振り分けるようになっています。

```index.js
if (process.env.NODE_ENV === 'production') {
  module.exports = require('./cjs/react.production.min.js');
} else {
  module.exports = require('./cjs/react.development.js');
}
```

ただ、`development`のほうは、TerserやUglifierで圧縮してしまうと警告が出ます。ややこしいのが、「開発環境をリモートに置く場合」です。

リモートにミニファイしないまま置いておいては、いくら開発用といっても容量や通信時間がかさむので、ミニファイしたいのですが、

* `develop`版→上述のように、ミニファイすると警告される上にビルド時間がかかる
* `production`版→Reactのデバッグがやりづらい

ということで、どちらも困難な選択肢となってしまいます。

## unpkgというCDN

パブリックなCDNはいろいろ設置されていますが、その中でも注目したいのが[unpkg](https://unpkg.com/)です。unpkgは、**npmに上がったものをすべて公開する**という形で運営されているため、JavaScript系のライブラリは（npm登録すらない昔のものを除けば）ほぼ完璧に揃います。そして、`/react@16.6.3/`のような固定バージョン指定だけでなく、`/react@^16.6/`のような範囲指定や、`/react/`のような形での最新版指定にも対応しています[^1]。

ということで、以下のような形で、HTMLにReactを読み込めます。

```html
<!-- 開発用 -->
<script src="https://unpkg.com/react@xx.y.z/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@xx.y.z/umd/react-dom.development.js"></script>
<!-- 本番用 -->
<script src="https://unpkg.com/react@xx.y.z/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@xx.y.z/umd/react-dom.production.min.js"></script>
```

## バンドルから外す

あとは、`import React`などがあってもバンドルに`react`を読み込ませず、HTMLでグローバルに供給したものを読ませるようにするだけです。Webpackであれば[以前まとめた](https://qiita.com/jkr_2255/items/5bff71d71286979e8a4e#webpack%E7%AE%A1%E7%90%86%E5%A4%96%E3%81%AE%E3%83%A9%E3%82%A4%E3%83%96%E3%83%A9%E3%83%AA%E3%82%92%E4%BD%BF%E3%81%86)ように、`config.externals`で指定できます。

```webpack.config.js
// 一部のみ
externals: {
  react: 'React',
  'react-dom': 'ReactDOM'
}

```

[^1]: 固定バージョンは`Cache-control: immutable`になるなどしっかりキャッシュされますが、バージョン指定が決めうちにならないものはリダイレクトされて、リダイレクトは時限キャッシュとなります。