OmniAICreator/Qiita-1.07M huggingface dataset:
[memo]AWSへの入門以前に知りたいIAMまわり



# AWSのサービス

## 誰向け？

たったいまAWSで苦しんでいる自分から、明日の自分と機能の自分へのメモです。
内容に間違いがあればぜひ教えてください。。。！

## はじめに

AWSはたくさんのサービスがあり、
特にインフラに不慣れな僕なんかはどこから触ったらよいのか、
むしろどこに触ったらいけないのかもわからず、色々困っています。

世の中にはありがたいことに「AWS 入門」あたりでググると、
それなりの数のページが出てきてくれますが、
「こういう事をやりたいんだけど」という目的が先にあったりすると、
関連性がわからないものも含めた全体の入門記事はちょっと重いもの。

とりあえずそういうせっかちな自分に向けて、
 **絶 対 に** 押さえておきたい知識について。

## 三種類のセキュリティ

AWSにおけるセキュリティは、大きく分けて三つに分類できます。

一つ目は秘密鍵などを利用した、暗号化によるセキュリティ。
こちらは今回は扱いません。

二つ目は「操作の権限」によるセキュリティ。
誰が何をできるのかを、AWSはかなり細かく制限できるようにしています。
具体的にいうとメソッド単位くらいまでです。
この部分を軽視していると「動くはずのサンプルが動かない」になります。

三つめは「アクセスの権限」によるセキュリティ。
誰が何にアクセスできるのかを制限します。
こちらは分かりやすいですが、個人でちょっと開発しようというくらいなら、問題になるタイミングはそう多くありません。

というわけで、操作の権限と、アクセスの権限についてさらっと紹介していきます。



### IAM (Security, Identity, & Compliance)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/222816/5090c27c-5bbe-d3d8-e063-4b5bd01d47e8.png) ![image.png](https://qiita-image-store.s3.amazonaws.com/0/222816/836761f7-64fb-600c-7261-957b53724ec3.png)



AWSでは何をするにもIAM関連は避けて通れません。
「Identyty（自己証明）」という言葉の通り、
どのサービスを使うとしても、このIAMの設定に従うことになります。

IAMはそれぞれの権限について、以下のような構造で管理します

- アカウント = 特権、全部できる、AWSのアカウントのこと、ユーザーとは別
- ポリシー = 各種の権限
- ロール = 権限をまとめて表現された役割
- グループ = ポリシーとロールをまとめたもの
- ユーザー = 操作の実行者

ちょっと混乱しそうですが、以下の図を見るとなんとなーくわかる、かも。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/222816/229e6f89-c6c4-1615-ec3b-22a80a728911.png)

以下のようなコンセプトのために、
単語があてはめられたと言ったほうがよいかもしれません。

- 権限を細分化したもの => ポリシー
- 役割がもつべき権限の塊 => ロール
- 開発チームなどの単位で持つべき権限の塊 => グループ
- 作業者ごとの権限 => ユーザー


基本的にはこれで「操作の権限」を設定します。


### VPC (Virtual Private Cloud) & ACL (Access control list)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/222816/96918952-4143-883b-df8f-1b90c7187c89.png) ![image.png](https://qiita-image-store.s3.amazonaws.com/0/222816/8f888249-2402-c5d4-dd67-87de317980f8.png)

こちらはあまり詳しく説明しませんが、
AWSの中に、もう一つ自分専用のAWSを作れるようなサービスです。

VPCを使うことで、わりと簡単に、そこそこ強固なセキュリティを確保できます。

ただ、一部のサービス（S3など）はこの中に置くことができないため、
窓口としてエンドポイントを用意し、それを経由してアクセスするなどの段取りが必要になります。


----


ということで、自分が整理するためのメモとしてここにアウトプットを残しておきました。

あと個人的に先に知りたかったなーと思うこととして、
いま自分が触っているlambdaまわりについて、
わりと挙動がセンシティブなので、まずは以下の公式リファレンスをもとに、
そのサンプルをコピペしただけのラムダを作って、
それをもとに作っていくのをおすすめします。

AWSやAzureがデファクトになっている状況なので、
ググれば大体なんとかなりそうな気もしていたのですが、
フロントエンドの開発のつもりでいるとかなり痛い目を見ます。

AWSはあくまでインフラをラッピングしているだけなので、
問題の原因が「権限」なのか「アクセス」なのか「ソースコード」なのかなど、
切り分けが必要な部分が普通の開発よりも多い＋根深いため、
わりとググってもアテにできる回答は少ないのが、いまのところの雑感です。

https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/_index.html


## 終わりに

上記記事で間違っている点などは指摘いただけると助かります。
あと、一人で悩んでもよくわかんないなーというときは、僕のTwitterに相談くれても大丈夫です。一緒に悩むくらいしかできませんが（笑）

また遠からず、できる範囲で入門記事を書いていきたいと思います。
javascriptでオブジェクトを使ったらsetTimeout関数のthis問題に遭遇

# setTimeout関数の失敗例

```html
<script src="jquery-3.3.1.min.js"></script><!-- jQueryをロード -->
<script>
$(function(){
	'use strict';
	class Test{
		constructor(){this.v="成功";}
		alert(){
			alert(this.v);
		}
	}

	const t=new Test(); //オブジェクトを作成

	$(test01).click(function(e){
		setTimeout(t.alert, 100);//失敗例
	});
});
</script>
<button id="test01">test01</button>
```

このプログラムを実行すると

![undefined.png](https://qiita-image-store.s3.amazonaws.com/0/311399/d1f19213-b79a-a235-87d6-09876afbc847.png)

undefinedが返ってきた。[^1]

# 原因はthis問題

>
> setTimeout() にメソッドを渡すとき、コードが実行される際の this の値が想定とは異なるかもしれません。
>
> setTimeout() によって実行されるコードは、setTimeout が呼び出された関数とは別の実行コンテキスト内から呼び出されます。呼び出された関数に this キーワードを設定する通常の規則を適用して、呼び出しあるいは bind で this を設定しなければ、非 strict モードでは global (または window)、strict モードでは undefined になります。
>
>注記: setTimeout コールバックの既定の this の値は、strict モードであっても undefined ではなく、window オブジェクトです。
>
> 出典: [MDN Web Docs WindowOrWorkerGlobalScope.setTimeout() "this" 問題](https://developer.mozilla.org/ja/docs/Web/API/WindowTimers/setTimeout#The_this_problem)

試したら非 strict モードでも strict モード[^2]でも setTimeout コールバックの既定の this の値は、 window オブジェクトだった。 `setTimeout(callback)` は内部で `callback.call(window)` を呼んでるようだ。

# javascriptのオブジェクトの挙動が怪しい！

どのように書けばいいかというと、`setTimeout(function(){t.alert()}, 100)`と書けば成功。
`t.alert`なら関数扱いで`t.alert()`ならオブジェクトのメソッド扱いになるようだ。括弧があるかないかの違いで挙動が変わる。

`fun=t.alert; fun();`とやれば`t.alert`内の`this`の値が`undefined`になった。
`t.alert`がオブジェクトのメソッドなので明示的に書かなくても`fun=t.alert; fun.call(t)`を呼べばいいのに。:disappointed_relieved:

`setTimeout(t.alert.bind(t), 100)`と書いても`setTimeout(function(){t.alert.call(t)}, 100)`と書いても`setTimeout($.proxy(t.alert,t), 100)`と書いても成功。
`t.alert.bind(t)`や`$.proxy(t.alert,t)`の内部を見てないが`function(){t.alert.call(t)}`を返す動きをしてるようだ。

怪しいとはいえ、javascriptのオブジェクトは便利。thisの値[^3]を気にしながらオブジェクトを使えばいい。:blush:

[^1]: IEではclassもアロー関数も動かなかった。FirefoxかGoogle Chromeで動いた。
[^2]: 'use strict'; を書けば strict モードになる。
[^3]: この問題とは別だが、アロー関数にすればそれが定義されている場所でのthisになるようだ([参考](https://qiita.com/yoichiro6642/items/0e494dc4875396ba2204#もうbindは必要ない))。
コーディングの手が止まってしまう方へ(ビギナー寄り対象)

# この記事の対象
* railsといったフレームワークに頼り切っており、コーディングの手が度々止まってしまう。
* 設計ってよくわからない。
* テストめんどい
* 1つアプリケーションを作ったけど、レベルアップするにはどうすればいいかわからない。

という方対象。僕がインターンを通して上司から教えていただいたことに関してメモがわりにまとめました。

# MVCからDDDへ
railsでもサービス層を実装することでビジネスロジックの場所が明確になり、コントローラの肥大化を防ぎます。これから規模が少し大きいアプリケーションを作る場合、既存のMVCよりもサービス層をとりいれたものを使ってみましょう。

DDDの詳しい解説やrailsでの実装はこちらのサイトがとても参考になります。
[Rails：Service層を運用して良かったところ、悪かったところ](https://qiita.com/joooee0000/items/369fd4676cd9dfb1f6eb)

# 設計の仕方
1. 登場人物を書く。
2. シーケンス図を書く。
3. コントローラやバッチにロジックを落とし込む。(サービス層はあとから分離していく)
4. このときコメントを書いていき、おおざっぱなコードを書いていく。
5. 実装どうすればと手が止まればロジックを再考する。

## まず登場人物を整理
例えばdddにでてくる登場人物

* db
* dao
* model
* service
* controller
* view

やサーバー単位での登場人物

* 外部api
* awsの各機能
* フロント
* apiを提供するエンド

などの登場人物を洗い出し、すぐに実装できるものであればモックでもいいのでとりあえず生成します。railsでいうところのとりあえず``rails generate``する感じです。これらの登場人物は次のシーケンスで関連性を書いていきます。

## シーケンス図を書く
シーケンス図を使って各登場人物の役回りを整理します。まず最初は手書きで大雑把に書いていきましょう。シーケンス図はこちらを参考に。

[シーケンス図(Sequence Diagram) - UML入門 - IT専科](http://www.itsenka.com/contents/development/uml/sequence.html)

## コントローラやバッチなどロジックにおとしこむ。
上で書いたシーケンス図を今度はコントローラもしくはバッチに書いていきます。サービス層はのちのち分離して行く想定です。

## コメントを描き、おおざっぱなコードを描いていく。
詳細な関数やライブラリモジュールなどは後から実装していく。とりあえずあたかも存在するように書く。以下はあくまでも一例です。フラグ立っているかどうかはwhereで取得しろよとかのツッコミはなしで。

```ruby
class HogeHoge

# data 全件取得

# data 加工

# フラグがたっていないデータは無視

# フラグが立っている場合、なにかする。

# data 保存

end
```

```ruby
class HogeHoge

 # dataを全件取得
 hoges = Hoge.all

 # dataを加工する
 res_hoge = []
 hoges.each do |h|
   res_hoge << do_something(h)
 end

 # dataを保存する
 ResHoge.import res_hoge 
 
 private 

 # 加工の中身
 def do_something()
　# フラグがたっていないデータは無視

　# フラグが立っている場合、なにかする。

 end 
 
end
```

## 実装中に手が止まってしまった場合
コメントでロジックを先に書いた後に、手がとまるということはロジックが破綻している可能性がある。この場合は一旦エディターから手を止めてロジックを考え直したりするとよい。

# 設計にかんして
設計はまずは、ノートにざっと描いて登場人物が増えていった場合やドキュメントとして残したい場合は、[draw.io](https://www.draw.io)などのものを使う。

# テストめんどうだな、書いたことないっていう方へ
テスト書くときの心持ち。

テストコードちゃんと書くかどうかが、職業プログラマーと趣味プログラマーの分かれ道みたいです。製品としてちゃんとしたプログラムを書く場合、品質を担保しなければなりません。なるべく、メンテナンス性やバグの早期発見をするにはテストは必須です。

しかし、趣味プログラマーからプログラミングの世界に入ったひとなどは、テストコード書くのはめんどいですよね。そこでテストコード書くときの心持ちと、テストの意味に関して説明します。

## テストコードはケアレスミスを防ぐもの
例えば割り算する関数をかいていて、このようにifの中で代入演算子を書いてしまうことも。この時この関数をテストするコードを書いておけば、ちゃんと動くかどうかの保証ができます。テストを書くことでこの関数に対して正しい実装であるという自信がもてるのです。プログラマー歴何年経ってもケアレスミスはなくならないらしいので、テストを書くことは身につけておいて損はないかも。

```ruby
def devide(a, b)

 # まちがって比較演算子を代入演算子にしてしまった。
 if(b = 0)
  return 0
 end

 return a / b

 end
```
## 実装と同時平行で書く
ロジックを書いて関数化して行くと同時に、テストも生成してしまいます。こうするとテストとセットでコーディングする流れが身につきます。テストを書くのが面倒なのはテストがプラスαのものだと捉えてしまっているからかもしれません。

## 実装してすぐできた、ではなく見直しをする
実装が完了したらすぐに完成した、というのはよくありません。学校のテストでもそうであるように、一度自分のコード(解答)を見直します。この見直しを保証するのがテストコードのように思っていただいても構いません。

## どこまでテストをするか
どこまでテストするかの答えは、自分たちのプロダクトの責任の及ぶ範囲です。たとえば外部で公開されているapiやライブラリは信頼できるものであればテストはやらなくても良いです。だからできる限りメンテされているライブラリなどを使うことが推薦されます。

## テストの優先順位
テストの優先順位はサービス＞モデル＞Dao＞コントローラの順です。コントローラはviewもからんでくる分、一般的にテストはしにくいです。しかしビジネスロジックの部分は、そのアプリの心臓そのもの。テストする必要があります。ここでサービスとコントローラを分離してあるおかげでテストがしやすくなってます。
Did you forget to register or load this tag? というDjangoのエラー

## 修正 (18/11/17/19:30)
以下の文章はただのタイポ(Type miss)によるものです。

```html
<!-- 修正前:entends -->
{% entends 'base.html' %}
<!-- 修正後;extends -->
{% extends 'base.html' %}
```

ですので、以下ただの駄文です。
ご指摘ありがとうございます。

消すのもあれなので、暇な方はお読みください。
## エラーログ
```
Invalid block tag on line 1: 'entends'. Did you forget to register or load this tag?
```
## 状況
Djangoにおいてhtmlファイルを作成中に、最初のbasefileを読み込む一行を記述したら出たエラー

## エラーの原因コード
```html
{% entends 'base.html' %} <=not working code
```
## 原因
タグのスペースが不正。タグ<enteds>と、読み込み元<base.html>と、basetagなどに空白スペースが必要。

>Djangoはタグを1つのトークンとして解釈する。可読性を高めるために、開始タグの後と終了タグの前にスペースを使用するのも慣例。

## 対処:空白をきちんと整備
```html
{% extends 'base.html' %} <=working code!
```

## 結果
エラーが出なくなった
### 参考ページ
https://stackoverflow.com/questions/44215817/did-you-forget-to-register-or-load-this-tag-django?rq=1
vbsの作法 その10

#概要

vbsの作法、調べてみた。
日能研やってみた。

#サンプルコード

```
Dim i
For i = 0 To 654321 step 6
	s = CStr(i)
	if instr(s, "1") > 0 And instr(s, "2") > 0 And instr(s, "3") > 0 And instr(s, "4") > 0 And instr(s, "5") > 0 And instr(s, "6") > 0 then
		i5 = Fix(i / 10)
		if i5 mod 5 = 0 then
			i4 = Fix(i / 100)
			if i4 mod 4 = 0 then
				i3 = Fix(i / 1000)
				if i3 mod 3 = 0 then
					i2 = Fix(i / 10000)
					if i2 mod 2 = 0 then
						msgbox i
					End if
				End if
			End if
		End if
	End if
Next
```


以上。
React Native で Storybook を利用する

# はじめに
[storybook](https://github.com/storybooks/storybook) を用いると UI Component の色やサイズの変化をチェックできます。
デザイナーや非エンジニアの人たちと、プロダクトのイメージを合わせながら作業するのに便利です。

私の場合、 React + Storybook のセッティングはすんなりできたのですが、 React Native + Storybook で少し詰まることがあったので、その内容を記事にしました。

# 環境を構築する
基本的には[ガイド](https://storybook.js.org/basics/guide-react-native/)にしたがって進めます。
まずは React Native のプロジェクトを開始します。

```
$ react-native init APP_NAME
$ cd APP_NAME
```

プロジェクトに `@storybook/react-native` を追加します。

```
$ yarn add -D @storybook/react-native
```

ディレクトリを作成します。（stories には ***.stories.js ファイルを格納します。)

```
$ mkdir -p storybook/stories
```

エントリーファイルを作成します。

```
$ touch storybook/index.js
```

`storybook/index.js` は以下のようにしてみました。(ガイドとは違います)

```javascript
import React from 'react';
import { Platform, StyleSheet, View } from 'react-native';
import { addDecorator, getStorybookUI, configure } from '@storybook/react-native';
import { loadStories } from './storyLoader';

addDecorator((storyFn) => <View style={styles.container}>{storyFn()}</View>);
configure(loadStories, module);

const StorybookUI = getStorybookUI({});

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
  },
});

const StorybookUIRoot = StorybookUI;

export default StorybookUIRoot;
```

`storybook/stories/***.stories.js` に、作成する story の内容を追加します。(ここでは割愛)

次に story を自動で読み込むために `storyLoader` の設定をします。

```
$ yarn add -D react-native-storybook-loader
```

`package.json` に下記の設定を追加します。

```json
  "scripts": {
    ~~~ 略 ~~~
    "prestorybook": "rnstl",
    "storybook": "storybook start -c ./storybook",
    ~~~ 略 ~~~
  },
  "config": {
    "react-native-storybook-loader": {
      "searchDir": [
        "./storybook/stories"
      ],
      "pattern": "**/*.stories.js",
      "outputFile": "./storybook/storyLoader.js"
    }
  },
```

これにより、 `storyLoader.js` を自動生成できます。

ルートディレクトリにある index.js も修正します。
Storybook を開きたいときは `isUsingStorybook` を `true` に、アプリを開きたいときは `false` に設定します。

```javascript
import { AppRegistry } from 'react-native';
import App from './App';
import { name as appName } from './app.json';

import StorybookUIRoot from './storybook';

const isUsingStorybook = true;
// const isUsingStorybook = false;
const rootComponent = isUsingStorybook ? StorybookUIRoot : App;
AppRegistry.registerComponent(appName, () => rootComponent);
```

ボタンでトグルして呼び出すコンポーネントを変えるようにすれば、手動で切り替える必要性はなくなります。(今回は割愛)

# Storybook を起動する
metro bundler を起動します。

```
$ yarn storybook
```

その状態で、エミュレータを起動します。

```
$ react-native run-ios
```

起動したら localhost:7007 にアクセスして、 Storybook を確認します。
私のケースでは、エミュレータが起動するまで、左パネルに story の一覧が表示されませんでした。

エミュレータ起動後は story の一覧が表示され、選択した内容がエミュレータに表示されるようになりました。


# おわりに
通常の React Project の場合は、 `yarn storybook` コマンドだけで story の一覧が表示されました。
そのため、はじめて React Native で起動した際、表示されないのは設定ミスがあるのでは？と試行錯誤しました。

エミュレータを起動してあげて初めて利用可能とわかるまで、ちょっとハマって悩んでしまったので備忘録も兼ねて記事にしました。
[開発者用]Vegewel /Vegewel Style URL命名規則

#URL命名規則

###[Vegewel Styleトップページ](https://style.vegewel.com/)

**[基本URL]**
https://style.vegewel.com/(国名)/

###[Vegewelトップページ](https://vegewel.com/ja/)

**[基本URL]**
https://vegewel.com/(国名)/

|国名|言語|
|:---|:---|
|ja|日本語|
|en|English|
|tw|中文 (台灣)|

例) 日本語
https://style.vegewel.com/ja/
https://vegewel.com/ja/

###[レストラン検索結果](https://vegewel.com/ja?utm_source=style&utm_medium=menu&utm_campaign=stylemenu)

**[基本URL]**
https://vegewel.com/(国名)/search?utf8=%E2%9C%93&utm_source=style&utm_medium=sidebar&utm_campaign=stylesidebar&q%5Bg%5D%5B1%5D%5Brestaurant_search_prefstate_or_restaurant_search_station_or_restaurant_search_cuisine_or_restaurant_search_restaurantname_or_restaurant_search_restaurant_alias_cont%5D=(地名or店名)(絞込み条件)&q%5Bg%5D%5B0%5D%5Bm%5D=or&commit=Search

|絞込み条件|Code|
|:---|:---|
|(なし)||
|ベジタリアン（肉・魚介なし）|&q%5Bg%5D%5B0%5D%5Bvegetarianmenu_eq%5D=o |
|ビーガン（肉・魚介・乳・卵なし）|&q%5Bg%5D%5B0%5D%5Bveganmenu_eq%5D=o |
|オーガニック|&q%5Bg%5D%5B0%5D%5Borganicfoods_eq%5D=o |
|マクロビオティック|&q%5Bg%5D%5B0%5D%5Bmacrobioticmenu_eq%5D=o |
|低糖質・ローカーボ|&q%5Bg%5D%5B0%5D%5Blowcarb_eq%5D=o |
|グルテンフリー|&q%5Bg%5D%5B0%5D%5Bglutenfreemenu_eq%5D=o |


例) 英語 shibuyaGluten-free menu
https://vegewel.com/en/search?utf8=%E2%9C%93&utm_source=style&utm_medium=sidebar&utm_campaign=stylesidebar&q%5Bg%5D%5B1%5D%5Brestaurant_search_prefstate_or_restaurant_search_station_or_restaurant_search_cuisine_or_restaurant_search_restaurantname_or_restaurant_search_restaurant_alias_cont%5D=shibuya&q%5Bg%5D%5B0%5D%5Bglutenfreemenu_eq%5D=o&q%5Bg%5D%5B0%5D%5Bm%5D=or&commit=Search
Scalaのdef mainについて仕様を詳しく調べてみた

Scalaのエントリポイント(`def main`)についてよくわからず機械的にコピペしていたので、ふと思い立って仕様を調べてみた。

## 言語仕様

[Top\-Level Definitions \| Scala 2\.12](https://www.scala-lang.org/files/archive/spec/2.12/09-top-level-definitions.html#programs)

### 翻訳

#### 9.5 プログラム

*プログラム* とは `(Array[String])Unit` 型の *main* メンバーメソッドを持つトップレベルオブジェクトである。
プログラムはコマンドシェルから実行可能である。
このプログラムのコマンド引数は main メソッドへ `Array[String]` 型のパラメータとして渡される。

プログラムのこの main メソッドはオブジェクト内で直接定義することもできるが、継承することもできる。
scalaライブラリが定義する特殊なクラス scala.App のボディは main メソッドと同様に機能する。
このクラスを継承するオブジェクト `m` は、それ故オブジェクト `m` の初期化コードを実行するプログラムである。

#### 例

以下の例は test.HelloWorldモジュール内で main メソッドを定義することにより hello world プログラムを作成している。

```scala
package test
object HelloWorld {
  def main(args: Array[String]) { println("Hello World") }
}
```

このプログラムはこのコマンドで開始できる

```scala
scala test.HelloWorld
```

Java環境では、このコマンドでも動くだろう。

```scala
java test.HelloWorld
```

HelloWorld は App を継承することで `main` メソッドなしに定義することもできる:

```scala
package test
object HelloWorld extends App {
  println("Hello World")
}
```

## わかったこと

* いつの間にかScalaの言語仕様はすごくアクセスしやすくなっていた
* 引数の型として`Seq[String]`などは依然使えない
* Appはほとんど使われなくなったよう感じるがまだ仕様としては残っている
複数GPUの簡単切り替え法

# 使用するGPUを指定する3つの方法
複数のGPUを利用する時に、どのGPUを使うか指定しないと、全てを占領してしまう。
そこで、使うGPUを指定する方法を調べたら3つあることがわかった。

## 1. Python コード内

```python
import os

os.environ['CUDA_VISIBLE_DEVICES'] = '1'
```

## 2. スクリプト実行時
コード内に書くより、こっちの方が個人的にオススメ

```
$ env CUDA_VISIBLE_DEVICES=0,1 python train.py
```

## 3. configに登録

### fishの場合

```~/.config/fish/config.fish
function pyconda0
    nohup env CUDA_VISIBLE_DEVICES=0 python $argv &
end

function pyconda1
    nohup env CUDA_VISIBLE_DEVICES=1 python $argv &
end

function pyconda2
    nohup env CUDA_VISIBLE_DEVICES=2 python $argv &
end
```
```
# GPU:2を使って学習する時
$ pyconda2 mnist.py
``` 

### bashの場合

```~/.bash_aliases
pyconda () {
    env CUDA_VISIBLE_DEVICES=$1 python $2
}
```
```
# GPU:1 と GPU:2を使って学習する時
$ pyconda 1,2 mnist.py
``` 

良いGPUライフを！！
大きなCSVをMySQLからActiveRecord経由で出力する方法

RubyからMySQLへの接続は、多くの場合はActiveRecordを使ってるかと思います。

たくさんのレコードを出力際にはfind_eachを使うケースが多いですが、これは並び順を指定できません。最後のidから次の100件みたいに小分けにSQLが流れています。

それはそれで素晴らしいのですが、大きなCSVを出したい時って、SQLでJOINした結果を出したいのではないでしょうか。

そうなるとActiveRecordのリレーションを使ったfind_eachではなく、生のSQLを流したい。しかし自力でSQLを作ってしまうとメモリがあふれる。さぁどうしようというわけです。

そして答えはこちら。

- mysql2resultsetを戻り値でもらうようにする
- mysqlのコネクションに、以下のオプションを追加する
  - stream:true
  - cache_rows: false

これだけです。

逆にこれがないとメモリ不足で処理が落ちます。

負荷テストをしてみると、7,000,000レコードもほとんどメモリを使用せずに出力できました。3.4Gのテキストファイルをメモリ1Gのマシンで出力できています。

以下サンプルコード

```ruby
require 'active_record'

ActiveRecord::Base.establish_connection(
  adapter:   'mysql2',
  charset:   'utf8mb4',
  encoding:  'utf8mb4',
  collation: 'utf8mb4_general_ci',
  database:  'sample',
  host:      'samplehost',
  username:  'sample',
  password:  'sample!',
  stream:     true,  #　これが徐々に結果を書き出すパラメータ
  cache_rows: false  #  stream が trueだと cache_rows は強制的にfalseになる
)

# ここに巨大な結果を返すSQLを記述。CSVのカラム名を指定したかったら、as で別名を指定
sql = <<'EOS'
select * from  samples limit 1000000
EOS

# executeを使って結果をmysql2 resultset で結果を受け取る
results = ActiveRecord::Base.connection.execute(sql)

# CSV出力。BOMをつけることでエクセルで開きやすくしている。
open("csv/sample.csv","w") do |f|
  f.print("\uFEFF" + results.fields.join(',') + "\r\n")
  results.each do |fields|
    fields.map! { |field| '"' + field.to_s.gsub('"', '""') + '"' }
    f.print(fields.join(',') + "\r\n")
  end
end

```

ちなみに、`show processlist` のSQLを流すと、この時間のかかるSQLのステータスは Writing to net がずーっと続くことになります。
unexpected end of dataを対処

## 状況
自然言語処理のモデル投入において、
inputDataになにがしかの原因があってエラーがはかれたこと。

model:keras(Tensorflow)
言語:python
## エラー
```
UnicodeDecodeError: 'utf-8' codec can't decode bytes in position 4093-4094: unexpected end of data
```
## 原因
unicode sequence が、インプットデータに含まれていた。

## 対処
今回は、カンマ=,が大量の文字列中に含まれていたので、それを削除したら動いた。

## Unicode
マルチバイト文字->日本語の文字列。Ex「ありがとう」
ユニコード文字列->¥uXXXX形式の文字列。Ex「\u3042\u308a\u304c\u3068\u3046」
[AWS SDK for PHP] S3へ一括でコマンドを実行したい場合はCommandPoolを使えという話

開発しているサービスで、添付画像付きの投稿処理がやたら遅く、Travis CIで実行しているE2Eテストが必ずタイムアウトするという問題が発生しました。

原因としてはS3に対して１ファイルずつputObjectコマンドを順次行ってアップロードしていたことです。

※記事に記載しているコードはあくまでどのように改善したかを理解してもらう為の簡単なサンプルです。本来はtry-catchやその他の処理が必要になりますので悪しからず。

■修正前コードサンプル

```php
foreach ($uploadFiles as $uploadFile) {
    // 1ファイルずつs3->putObjectでS3にアップロード
    $response = $this->s3Instance->putObject([
        'Bucket' => ****,
        'Key' => $uploadFile['key'],
        'Body' => $uploadFile['body'],
        'ContentType' => ****,
//        ....
   ]);
}
```

お分かりだと思いますが、もし10ファイルをアップロードするとしたら10回分putObjectの処理時間がかかってしまいます汗

もしオリジナルの画像ファイルとは別にサイズごとの画像もS3に保管していたとしたら、さらに遅くなります。(あ、それうちのサービスだった・・)

なのでこういった場合は、複数のAWSコマンドを同時実行できる[CommandPool](https://docs.aws.amazon.com/ja_jp/sdk-for-php/v3/developer-guide/guide_commands.html#command-pool)クラスを使いましょう。

■修正後コードサンプル

```php
$commands = [];
foreach ($uploadFiles as $uploadFile) {
    // putObject用のコマンドを生成して配列に格納
    $commands[] = $this->s3Instance->getCommand('PutObject', [
        'Bucket' => ***,
        'Key' => $uploadFile['key'],
        'Body' => $uploadFile['body'],
        'ContentType' => ***,
//        ....
    ]);
}

// 同時コマンド実行！
CommandPool::batch($this->s3Instance, $commands);
```

まずputObjectコマンドをループの中では実行せず、getCommandでputObject用のコマンドを生成して配列に格納します。
あとはCommandPool::batchメソッドにs3インスタンスと生成したコマンド群を渡してあげれば簡単にコマンドを同時実行出来ます。

batchの中身を見ると、やってるのは単純にPromise処理です。

```php
    public static function batch(
        AwsClientInterface $client,
        $commands,
        array $config = []
    ) {
        $results = [];
        self::cmpCallback($config, 'fulfilled', $results);
        self::cmpCallback($config, 'rejected', $results);

        return (new self($client, $commands, $config))
            ->promise()
            ->then(static function () use (&$results) {
                ksort($results);
                return $results;
            })
            ->wait();
    }

```



もちろんS3からファイルを取得する時なども同様に使えます。

```php
$commands = [];
foreach ($keys as $key) {
    // 取得なのでGetObjectになる
    $commands[] = $this->s3Instance->getCommand('GetObject', [
        'Bucket'      => ****,
        'Key'         => $key,
    ]);
}
// S3からファイルをまとめて取得だ！
$responses = CommandPool::batch($this->s3Instance, $commands);

$fileContents = [];
// あとは順次各ファイルの中身を取り出すだけ
foreach ($responses as $response) {
    $data = $response['Body'];
    $fileContents[] = $data->getContents();
}
return $fileContents;

```


結果、S3オブジェクトの取得・アップロードをCommandPoolクラスを活用することによって処理時間が5倍以上高速になりました。
利用は非常にシンプルで使わない手はないと思いますので、ぜひ使ってみてください。
なにもしらない初心者が Unity チュートリアルをやってみた

【作者ステータス】：
・一般の業務系プログラマー
・ゲームはまともに作ったことがない
（作れない）
・以前からゲーム作りに興味があった
・今回、とある会にてUNITYのチュートリアルを実施してみた

* * *
このサイトです：
http://tutorial.unity3d.jp/

* * *
【発生したバグ】：
・NULL参照
・オブジェクト未定義
・アタッチ忘れ
（全て、参照漏れ系・・・）

* * *
【実施中の感想】：
・ゲームロジックが丁寧に解説されていて助かった。

* * *

【結果】：
・UNITYに関する理解が深まった！
・ゲーム作りは、業務システム作りより難しい！
（少なくとも、自分の業務よりは、ですが）
https://gyazo.com/4da914b8807607248224141909babb3e

以上です
Vagrant+Docker+Jekyll+GitHubPagesを使ってポートフォリオ作成

ポートフォリオを作ってみようと思い、以下を参考にやってみたらいろいろはまったのでメモ
[[GitHubPages + Jekyll] 無料でWebページを作ってみた](https://qiita.com/koyo-miyamura/items/5ec89ac9689be49a55f6)


# ローカル(Windows)にJekyll環境構築 -> 失敗

Rubyのインストールはできたものの、gemでJekyllを入れようとした際に失敗。
`MSYS2`が必要だということなので入れてみたがそれでもダメ。
ログを追っていけば何とかなりそうな感じはしたが、ドツボにはまりそうな予感がしたので
別の方法に変更。

```console:makeのPATH通せば行けそうな気がするが、他にも罠がありそう。。。
>gem install jekyll
Temporarily enhancing PATH for MSYS/MINGW...
Building native extensions. This could take a while...
ERROR:  Error installing jekyll:
        ERROR: Failed to build gem native extension.

    current directory: C:/tools/ruby25/lib/ruby/gems/2.5.0/gems/http_parser.rb-0.6.0/ext/ruby_http_parser
C:/tools/ruby25/bin/ruby.exe -r ./siteconf20181117-9632-11acpda.rb extconf.rb
creating Makefile

current directory: C:/tools/ruby25/lib/ruby/gems/2.5.0/gems/http_parser.rb-0.6.0/ext/ruby_http_parser
make "DESTDIR=" clean
'make' は、内部コマンドまたは外部コマンド、
操作可能なプログラムまたはバッチ ファイルとして認識されていません。

current directory: C:/tools/ruby25/lib/ruby/gems/2.5.0/gems/http_parser.rb-0.6.0/ext/ruby_http_parser
make "DESTDIR="
'make' は、内部コマンドまたは外部コマンド、
操作可能なプログラムまたはバッチ ファイルとして認識されていません。

make failed, exit code 1

Gem files will remain installed in C:/tools/ruby25/lib/ruby/gems/2.5.0/gems/http_parser.rb-0.6.0 for inspection.
Results logged to C:/tools/ruby25/lib/ruby/gems/2.5.0/extensions/x64-mingw32/2.5.0/http_parser.rb-0.6.0/gem_make.out

```

# Vagrant(Ubuntu)にJekyll環境構築 -> 失敗

Windowsだからアカンかったんやと思い、Linux(Ubuntu)でやってみるも失敗。
そもそも、Rubyのインストールで無駄にはまってしまった。
最初は`apt-get`でインストールしたRubyを使おうとしたがgem実行時にバージョンが古くてダメっぽい。
`rbenv`を使ってインストールしてみるも、これでもバージョンが違うといわれてダメ。
これはログを追っても何とかなりそうな気がしなかったので断念。


# Vagrant(Ubuntu + Docker)にJekyll環境構築 -> 成功

[JekylのDockerイメージ](https://hub.docker.com/r/jekyll/jekyll/)があったのでそれを使ってみた。
が、最初はうまくいかなかった。
というのもGitHubPages用の`pages`というイメージタグがあり、そちらを使う必要があったためだった。
以下の2ファイルをリポジトリ直下において `vagrant up`すればローカル環境の出来上がり。
ただ、この方法だと`--watch`オプション付けても変更が反映されないので注意。おそらく、`_site`フォルダのほうに実体ができてるからだと思う。

```ruby:Vagrantfile

# -*- mode: ruby -*-
# vi: set ft=ruby :
unless Vagrant.has_plugin?("vagrant-docker-compose")
  system("vagrant plugin install vagrant-docker-compose")
end

Vagrant.configure("2") do |config|
  config.vm.box = "ubuntu/trusty64"
  config.vm.network "forwarded_port", guest: 4000, host: 4000
  config.vm.provision :docker
  config.vm.provision :docker_compose, yml: "/vagrant/docker-compose.yml"
end
```

```yml:docker-compose.yml
version: '2'

services:
  jekyll:
    image: jekyll/jekyll:pages
    ports:
      - "4000:4000"
    command: "jekyll serve"
    volumes:
      - /vagrant:/srv/jekyll
```



# まとめ
Dockerは神
vbsの作法 その9

#概要

vbsの作法、調べてみた。
ズンドコやってみた。

#写真

![image](https://qiita-image-store.s3.amazonaws.com/0/18104/7f8e1ff5-cec8-62db-a196-25132932a4f0.png)


#サンプルコード

```
Dim zundoko, loopCnt, result, tempResults

loopCnt = 0
Set zundoko = CreateObject("System.Collections.ArrayList")
Do While True
	If loopCnt > 5 Then
		loopCnt = 0
	End If
	If Rnd < 0.5 Then
		zundoko.add "ズン"
	Else
		zundoko.add "ドコ"
	End If
	If loopCnt = 4 Then
		result = zundoko(zundoko.Count - 5) & zundoko(zundoko.Count - 4) & zundoko(zundoko.Count - 3) & zundoko(zundoko.Count - 2) & zundoko(zundoko.Count - 1)
		If result = "ズンズンズンズンドコ" Then
			Exit Do
		End If
	End If
	loopCnt = loopCnt + 1
Loop
result = ""
For Each item In zundoko
	result = result & item
Next
MsgBox result & " キ・ヨ・シ！"


```


以上。
vbsの作法 その8


#概要

vbsの作法、調べてみた。
fizzbuzzやってみた。

#写真

![image](https://qiita-image-store.s3.amazonaws.com/0/18104/92234d06-6431-47ce-125b-bc7bad903a50.png)


#サンプルコード

```
Dim i
Dim str
str = ""
For i = 1 To 100
	If i Mod 15 = 0 Then
		str = str & "FizzBuzz "
	ElseIf i Mod 3 = 0 Then
		str = str &  "Fizz "
	ElseIf i Mod 5 = 0 Then
		str = str &  "Buzz "
	Else
		str = str & CStr(i) & " "
	End If
Next
msgbox str

```

以上。
Firebase hostingとCloudflareの連携がうまくいかないときはCloud flareのSSLの設定を見直してみる

## 連携しようとしても保留中や、処理が必要などと出て設定が反映されない

### 解決法その1 Cloudflareのプロキシを無効にする(間違い)


![Screenshot from Gyazo](https://gyazo.com/471020b58631c5b8f9ebd06eaff41ad4/raw)

CloudflareのDNSのこのオレンジ色の雲をクリックして灰色にする。
Stackoverflowなどをみるとこの回答が一番出てくるが、これだとCloudflareを挟む利点を失ってしまうのでこれは誤り。


### 解決法その2 Flexible SSLをFull SSLにする

[![Screenshot from Gyazo](https://gyazo.com/32a8c9df8b4221606175931b805e5236/raw)](https://gyazo.com/32a8c9df8b4221606175931b805e5236)

最初はこの項目がFlexibleになっているので、Fullにすれば良い。
AndroidのPermissions Policy 強化対応（Call Log and SMS)

Google Play から以下のタイトルのメールが来た。
「Action required: Update your app to comply with Google PlayPermissions policy」

私はベータ版のSIP通話アプリを開発しているので、それに対しての通知のようだ。
どうやら見逃していたが、SMS や通話履歴に関する権限グループを使用しているアプリは、申請を行う必要があるらしい。
　　[ユーザーに安全で安全な体験を提供する](https://android-developers.googleblog.com/2018/10/providing-safe-and-secure-experience.html)

>2019年1月9日までにポリシーの要件を満たしていない、または許可申請書を送信できないアプリは、Google Playから削除される可能性があります。

とのことなので、メールを受け取った開発者は対応する必要があるようだ。

対応方法は以下のリンクに記述してある。
　　[SMS や通話履歴に関する権限グループの使用](https://support.google.com/googleplay/android-developer/answer/9047303)

このページに書かれている「アクセス権限申告フォーム」から申請を行う。
５ページ構成となっている。


## １ページ目
「デベロッパー登録トランザクションID」がわかりにくいが、書かれている payments.google.com からIDを見つけることができる。
１．「ご利用内容」を開く
　　開発者であれば、開発者トークンを購入しているはずなので、利用履歴として表示される。
２．履歴の一つを選択する
　　私の場合「開発者トークン」の履歴を選択
３．右側に詳細内容が表示される
　　その中の「取引ID」がそれ。

その他は、迷う内容はなさそう
##２ページ目
１ページ目の選択内容から省略されているようだ。
「開発者タイプ」によっては２ページ目が表示されるのかもしれない。
##３ページ目
私のアプリは SIP電話アプリなので、中核機能は VoIP Call として、以下の項目を選択。
　■プロキシ呼び出し[READ_CALL_LOG、WRITE_CALL_LOG、PROCESS_OUTGOING_CALLS]

その他の許可されない使い方は無いので　N/A を選択。
##４ページ目
確認するための追加情報の入力。
サインインが必要ならアカウントを、それが提供できないのであれば画像や動画をアップロードする必要があるらしい。
##５ページ目
最後の確認。
基本すべて「認める」しかない。
「送信」ボタンを押して完了。

#結果
後日報告

#・・・
Android も iOS も、最新SDKが必須になったり、プライバシー関連の強化がされたり、利用する側からすると安全性向上でうれしいですが、開発者としては負担がどんどん増えてつらいですね。
多くの場合、アプリ提出時に対応されているかのチェックを受けますが、今回のようにすでにストアに登録済みのアプリに対してアクションが必要な場合、気づかない可能性があるので要注意です。
英語のメールはスルーしがちなので、重要なことは日本語で送ってほしいと思ってしまいます。。。
golang codewalk「Share Memory by Communicating 」の図を書いてみた

golang 公式サイトにこの https://golang.org/doc/codewalk/sharemem/ コードを理解するため、graphviz で図を書きました。

参考までです

![Alt text](http://g.gravizo.com/g?
    digraph g {
        node [
            fontsize = "16"
            shape = "ellipse"
        ];
        edge [];
        subgraph cluster_main {
            style=filled;
            color=lightgrey;
            node [style=filled,color=white];
            make_chan -> go_StateMonitor
            go_StateMonitor -> go_Poller 
            go_Poller-> go_init_Resource 
            go_init_Resource-> for_range_complete 
            for_range_complete-> go_sleep ;
            label = "main goroutine";
        }
        subgraph cluster_Poller1 {
            node [style=filled];
            for_range_pending -> Poll
            Poll -> send_to_status
            Poll -> send_to_complete
            label = "Poller1..2 goroutine";
            color=blue
        }
        go_Poller -> for_range_pending
        { rank=same; go_Poller for_range_pending }
        subgraph cluster_StateMonitor {
            node [style=filled];
            for_loop -> select
            select -> case_ticker 
            case_ticker -> logState
            select -> case_status
            case_status -> update_urlStatus;
            label = "StateMonitor goroutine";
            color=blue
            urlStatus [label = "<f0> urlStatus map | url : status";shape = "record"]
        }
        go_StateMonitor -> for_loop
        { rank=same; go_StateMonitor for_loop }
        pending [label = "<f0> pending chan * Resource | url string | errCount int";shape = "record"]
        complete [label = "<f0>complete chan * Resource | url string | errCount int";shape = "record"]
status [label = "<f0> status chan * State | url string | status string";shape = "record"]
go_init_Resource -> pending [label = "init", color=gold, style=dashed];
complete -> for_range_complete [label = "receive ", color=forestgreen, style=dashed];
go_sleep -> pending [label = "sleep and push", color=forestgreen, style=dashed];
status -> case_status[label = "receive status", color=forestgreen, style=dashed];
update_urlStatus -> urlStatus[label = "update", color=forestgreen, style=dashed];
logState -> urlStatus [ label = "for range", color=forestgreen, style=dashed]
pending -> for_range_pending [label = "in queue", color=forestgreen, style=dashed]
send_to_complete -> complete [label = "out queue", color=forestgreen, style=dashed]
send_to_status -> status [label = "out queue", color=forestgreen, style=dashed]
}
)
【Ruby on Rails】アプリケーションをGitHubへ上げるまで

#はじめに
GitHubアカウントを登録していることが前提。

#GitHubにリポジトリ作成
まず、GitHubにリポジトリを作成。
画面右上「 + 」の横にある▽をクリックし、「New repository」を選択。

必要項目を入力、選択した後「Create repository」ボタンを押下。

# 公開鍵・秘密鍵の作成
鍵を入れるフォルダに移動。

```
$cd ~/.ssh
```

鍵を生成。

```
$ssh-keygen -t rsa
```


# 公開鍵をGitHubへ登録
GitHubの[SSH and GPG keys](https://github.com/settings/ssh)の画面を開く。

画面右上の「New SSH key」のボタンを押下。

「Title」に公開鍵名、「Key」に公開鍵の内容を入れる。
・公開鍵名
・公開鍵の内容
　下記のコマンドにて公開鍵の全取得が可能。クリップボードへコピー。

```
$ cat ~/.ssh/id_rsa.pub
```

#接続確認
下記のコマンドを打って、接続が上手くいっているか確認。

```
$ ssh -T git@github.com

~省略~

Hi (account名)! You've successfully authenticated, but GitHub does not provide shell access.
```
上記の文言が返ってきたら接続完了。

#GitHubに上げる
Railsアプリケーションのルートディレクトリに移動。
下記のコマンドで、新しいリポジトリの初期化。

```
$ git init
```

下記コマンドを実行し、プロジェクトのファイルをリポジトリに追加。

```
$ git add -A
```

GitHubをリポジトリのoriginとしてGitの設定ファイルに追加。
GiitHubのユーザー名、対象となるアプリケーション名で置き換え。


```
$ git remote add origin git@github.com:ユーザー名/アプリケーション名.git
```

GitHubへプッシュ。

```
$ git push
```

GitHubで修正がプッシュされているか確認。
nvprof と NVIDIA Visual Profiler でGPUの使用状況を確認する

こんにちは、chlochanです。今日は "NVIDIA Visual Profiler" を使ってGPUの使用状況を確認してみます。以下のコマンドを実行[^1]してjupyter labを起動します。

~~~bash
$ nvprof -o pid%p.nvvp --profile-child-processes jupyter lab
~~~
オプション "--profile-child-processes" をつけると、nvprof はすべての子プロセスのプロファイルを取るモードになって、jupyter lab 上で起動されたすべてのCUDAプロセス (つまりpythonのプロセス) のプロファイルを取得します。なお、"%p" は、 process ID に置き換えられます。目的のプログラムが終了したら、"Ctrl-c"　をタイプして nvprof を終了します。その後、NVIDIA Visual Profiler で上記で生成された pidxxxx.nvp を開いて見てみます。なお、nvprofのオプションについて詳しくは、以下に記載されています。
https://docs.nvidia.com/cuda/profiler-users-guide/index.html#nvprof-overview
実行してみたところ、jupyter lab で以下の様なプロセスIDの python3 カーネルが生成され、

~~~
  PID TTY          TIME CMD
 6795 ?        00:36:28 python3
~~~
以下の様なログが生成されました。

~~~
pid6795.nvvp
~~~

[^1]: ここを参考にさせていただきました。 ⇒ https://qiita.com/Hiroki11x/items/3737e4e267c1035a4b55
Introduction to docker kubernetes and redhat openshift

redhat社によるIntroduction to docker,kubernetes and RedHat openshiftという研修を受けてきたので内容のまとめ

# 研修概要
研修環境ではクローズドな環境でopenshiftが構築されており、
ハンズオン形式で手順に沿ってコマンドをうっていくと
docker,kubernetes,openshiftの基本について確認できる研修でした

以下研修で学んだことをまとめていきます。

## コンテナ
プロセスを仮想OSっぽく動かす技術

OSの上にコンテナ基盤が動作し、その上でコンテナプロセスが起動する
コンテナプロセスにはNICと仮想DISKが紐付けられ、普通のOSのようにログインもできる

仮想OSから無駄な機能を切り離し、必要な機能だけ残して取り回しを良くした感じ

物理環境や仮想OSに比べて以下の利点がある

- ライブラリの更新が他コンテナ、基盤OSに影響を与えない
- 仮想OSに比べオーバヘッドが少ない
- コンテナイメージのエコシステムがあり、目的にあったコンテナイメージ(webコンテナ、dbコンテナ)が公開されているリポジトリからダウンロードしてすぐに利用することができる

## Docker
Docker社が開発したコンテナエンジン
コンテナエンジンのデファクトスタンダード

### アーキテクチャ
DockerサーバはOS上でデーモンとして実行される
Dockerサーバに対してRESTful APIを発行することでコンテナイメージのビルド、起動、ダウンロードを行える

RESTful APIを解析すれば独自のツールをつくれる
それを行ってるのがkubernetesやopenshift

### コンテナとLinuxカーネル
以下のカーネル標準機能を用い、コンテナプロセスがアクセスできるリソースを制限し、コンテナを形成する

- 名前空間
- 制御グループ
- SELinux

### Dockerコンテナイメージ
アプリケーションライブラリとアプリケーションを含むランタイム環境から構成される、読み取り専用のテンプレート
コンテナの作成に使用される
イメージは作成、更新、ダウンロードしてすぐに使用できる

Dockerコンテナイメージは複数の層で構成される
コンテナを変更する際は既存の層を変更することなく、新しい層が追加される
追加された層は、変更を実施した実施中のコンテナから新規イメージを生成しない限り破棄される

### 新規イメージの作成方法
作成方法は以下の2つ

- 実行中のコンテナに変更を行い、変更したコンテナからコンテナイメージを作成する
- Dockerfileからビルドする

コンテナを直接変更する手段を取るとレイヤが増加し、コンテナイメージのサイズが大きくなってしまうため、非推奨とされる
Dockerfileではレイヤ数をコントロールできるため、こちらが推奨

## kubernetes
複数のノードによってクラスタを構成し、その上でコンテナを動作させるためのマネジメントツール
分散キーバリューストアのEtcdにより構成情報と状態情報を保存し、コンテナやその他リソースを管理する
docker

###　構成要素

#### マスター
kubernetesクラスタ内の作業負荷と通信を管理するサーバー

#### ノード
kubernetesクラスタを構成するサーバー

#### ラベル
任意のkubernetesリソースに割り当てることができるキー/値のペア

#### ポッド
リソースを共有するコンテナの集合

#### サービス
ポッドプールにアクセスするためのIPとポートの組み合わせ

#### レプリケーションコントローラ
ポッドの水平方向へのスケールをコントロールする定義
AWSでいうAuto Scailing のルール

#### 永続ボリューム(PV)
ポッドに割り当てるネットワークストレージ
コンテナは停止すると削除されるため、永続データはポッドに割り当てた永続ボリュームに保存する

## OpenShift
RedHat社製
Docker + kubernetesのコンテナインフラストラクチャに機能を追加し、本番PaaSプラットフォームを提供する
WebUIやCI/CDのための機能がkubernetesに追加される

###　構成要素

#### デプロイ設定
複数のポッドをデプロイするための設定
ローリングアップデートなどを制御する

#### ビルド設定
Gitサーバ上のソースコードからコンテナをビルドするための設定
デプロイ設定と合わせてCI/CDを提供する

#### ルート
OpenShiftで構成されるアプリケーションに対してアクセスするためのアクセスポイントDNSホスト名

### ネットワーキング
OpenShiftではネットワークがSDNで制御され、ポッドから外へのアクセスやポッドの外からのアクセスがポッドの内部のコンテナが増減しても割り当てた静的なIPアドレスでアクセスできる

# ハンズオン
docker,kubernetes,openshiftの基本事項をおさえたあと
ハンズオンで実際にコマンドを打たせてもらえました

RedHat社の研修でしたが、dockerやkubernetesの操作についても基本から実施でき、
dockerに触ったことがない人がイメージを掴むにはとてもよい研修でした
R/RStudio をインストールする

こんにちは、chlochanです。いつの日か仕事に生かせる事を目指して、休日とかにDeep Learning の勉強をしています。教科書は、以下の２つを使っています。

[PythonとKerasによるディープラーニング](https://book.mynavi.jp/ec/products/detail/id=90124)

内容は同じで、上記のR版
[RとKerasによるディープラーニング](https://www.oreilly.co.jp/books/9784873118574/)

R/RStudio をインストールして上の２つの教科書の下側の方の教科書のサンプルコードを実行します。

#必要条件
CUDA 9.0 がインストールされている必要があります。

# R、RStudioをインストールする
まず、VMにブラウザで接続できるように ”VMインスタンスの詳細” で以下のチェックをいれます。VMをデプロイする時のgcloudコマンドで、”--tags=http-server” のオプションをいれてあれば、すでにチェックが入っていると思います。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/307576/16745259-e196-f8fe-36e6-a8782aa4a48a.png)
RとRStudioのインストール方法は以下のRStudio社のサイトのページに書いてあります。
[Download RStudio Server](https://www.rstudio.com/products/rstudio/download-server/)
まずは R をインストールします。以下でインストールできます。

```bash
$ sudo apt-get update
$ sudo apt-get install r-base r-base-dev -y
$ sudo apt-get install python-pip -y
$ sudo apt-get install python-virtualenv -y

```
サンプルコードを実行するためには、以下もインストールが必要でした。

```bash
$ sudo apt-get install libssl-dev libcurl4-openssl-dev -y
```

次に RStudioをインストールします。以下でインストールできます。 [y/N] 聞いてきたら y で答えます。バージョンは2018年11月25日現在のものです。最新のバージョンは上記のRStudio社のサイトのページで確認してください。

```bash
$ sudo apt-get install gdebi-core -y
$ wget https://download2.rstudio.org/rstudio-server-1.1.463-amd64.deb
$ sudo gdebi rstudio-server-1.1.463-amd64.deb
```
インストールすると、最後に自動的に rstudio-server が起動されます。また init.d あたりの初期設定もしてくれるみたいで、次回から VM を起動したら rstudio-server が最初から起動されています。次に、RStudioにログインするユーザーを追加します。（理由はわかりませんが追加したユーザーでないとRStudioにログインできませんでしたので追加します。）

```bash
$ sudo adduser <username>
```

インストールすると rstudio-server は起動されているので、ユーザー追加したあとで再起動する必要があります。再起動するには以下のコマンドを実行します。

```bash
$ sudo rstudio-server stop
$ sudo rstudio-server start
```
以下でもよいです。

```bash
$ sudo rstudio-server restart
```
これですでに外部から接続できる様になっています。ファイアウォールでポート8787を開けます。
 `http://外部IPアドレス:8787`
で、手元のブラウザからアクセスすると RStudioに接続できます。RStudioのログイン画面がでたら、ログインします。追加したユーザー名でログインします。

# RStudioで、Kerasをインストールする。
RStudioにログインして、サンプルコードを実行する時に必要なライブラリをまずインストールします。

```R
install.packages("tidyverse")
install.packages("knitr")
install.packages("ggplot2")
install.packages("tidyr")
install.packages("gridExtra")
install.packages("magick")
install.packages("viridis")
```
次にKerasをインストールします。以下を実行します。

~~~R
install.packages('devtools')
library('devtools')
devtools::install_github("rstudio/keras")
library(keras)
install_keras(tensorflow = "gpu")
~~~
上記の実行後、2018/11月時点の RStudio の Packages には、以下が表示されました。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/307576/3a73466d-ef07-c69c-708d-0c28635cf720.png)
ここまでくれば RStudio でもDeep Learning の勉強を開始できる状態になっています。教科書は以下です。
[RとKerasによるディープラーニング](https://www.oreilly.co.jp/books/9784873118574/)
GitHubから上記の教科書のサンプルプログラムをダウンロードして実行します。

```bash
$ git clone https://github.com/jjallaire/deep-learning-with-r-notebooks.git
```
現在自分もサンプルを勉強しながら実行しています。5-3章のサンプルコードまで問題なく実行できています。
運用保守とは何かを概要で考える

## 運用保守とは、100 を継続すること

* 0 から 1 を作る
* 1 から 100 を作る
* 100 を継続する << ココ

![ope_and_maint.001.png](https://qiita-image-store.s3.amazonaws.com/0/31223/7352a01f-cdff-a68a-73d4-7c1c13e64777.png)


## 運用とは何かを考える

**サービスを使える状態にする事**。英語だと `operation`

こんな経験ないだろうか。

```
「お金払ってるのに、まともに『応対』してくれない！
マニュアルもトリセツ(最近聞かない)もないなんておかしい！
こんなん使えんやろ！もういい、他のに変える！」
```

いわば『応対』が運用に近しい。もう少し砕くと次の 2 つ。

* 顧客がサービスを継続して使える状態にする事
* 提供者たちがサービスを把握している事

#### 顧客がサービスを継続して使える状態にする事

モノは作ったら終わり、売って終わり、ではない。継続利用してもらって初めてモノになる。

きちんとお金をかける会社は、例えばコールセンターを用意する。

![ope_and_maint.003.png](https://qiita-image-store.s3.amazonaws.com/0/31223/a7a5c909-db77-10f2-84f2-28cd90a9f323.png)


#### 提供者たちがサービスを把握している事

仕様・操作方法をきちんと把握しているか、知見あるかどうか。

* 「その挙動が仕様なのか、不具合なのか」
* 「どういう操作をしたら NG なのか」

を把握できる組織(仕組み)が必要になる。無いとどうなるか。

顧客に「ごめんなさい」または「その操作はお控え頂きたいです、理由は...」の応答ができない。

![ope_and_maint.004.png](https://qiita-image-store.s3.amazonaws.com/0/31223/a184b2a5-4f09-d692-6eed-c133a13bf273.png)

## 保守とは何かを考える

**サービスを魅力ある状態にする事**。英語にすると `maintenance`

```
 「このライブラリ、来年以降『メンテ』されないんだって。別のに変えようか」
```

そう、「メンテ」のこと。大きく 4 つある。

* 障碍対応
  * (障碍 = 障害。読みは同じで、表記が違うだけです)
* 環境更新
* 機能追加・削除
* 諸改善

![ope_and_maint.005.png](https://qiita-image-store.s3.amazonaws.com/0/31223/4d2816b7-4fe1-8dc5-2b0b-84bc99ea5445.png)

### 障碍対応(緊急度：高 / 重要度：高)

* クレーム応対
* 市場障碍(バグ対応)
* サーバーダウンからの復旧
* etc.

原因を突き止め、再発防止の為に恒久対応を実施する。恒久対応がすぐ難しいならば

早急に暫定対応を実施する。初動が遅いと、顧客減少に直結する。

### 環境更新(緊急度：高 / 重要度：低)

* フレームワーク、ライブラリの脆弱性対応
* 最新 OS への対応、サポート切れが近い OS の対応方針を立てる
* etc.

作った時の状態、デプロイした時の状態がいつまでも正しい状態ではない。

初動を早める必要性は場合によるが、放っておく期間の長さと、市場へのインパクトは比例する。

### 機能追加・削除(緊急度：低 / 重要度：高)

市場に出して初めて、顧客のリアクションから気づきを得られる。

* 実はこういう機能を作った方が良かったんじゃないか
* この機能要らなかった(利用頻度が極端に低いなど)

それぞれ整理してサービスをアップデートをする。

### 諸改善(緊急度：低 / 重要度：低)

* 性能向上(特定機能の実行時間短縮、ビルドマシン最新化、etc)
* 作業自動化(テスト、デプロイ作業、etc)
* etc.

どれだけ人・モノ・時間(カネ)をかけられるかでやる事、セクション(緊急度・重要度)は変わると思う。

(ここはプロジェクトによっていくらでも流動するだろう)

# あとがき

突っ込んだ話は別記事に書く予定。時期は未定。

* 運用で大事なことは何か
* 保守で大事なことは何か

といった感じ。

# モチベーション

運用保守でググってもピンとこない記事が多かったので、自分なりに書いた。
TensorFlowのsessionの種類（メモ）

目に止まった分だけ。

* tf.Session() と tf.InteractiveSession()
違いがわからなかったが、[こちら](https://qiita.com/7of9/items/59205fdca2d1ac861075)が解決してくれた。

* tf.train.Supervisorのmanaged_session()
公式によると、`tf.train.Supervisor`は
モデルのチェックポイントとサマリ計算のためのヘルパークラスで、
訓練に必要な面倒をみてくれるCoordinator, Saver, SessionManagerなどのラッパー。
1.12ではdeprecatedなので代わりに`tf.train.MonitoredTrainingSession` を使えとのこと。

* tf.train.MonitoredTrainingSession
`MonitoredSession`を作る

* tf.train.MonitoredSession
公式によると、
初期化、リカバリ、フックを扱うセッションライクオブジェクト、とのこと。
初期化、実行、終了のタイミングで、それぞれチェックポイントから値をリストアしたり、フック関数を呼んだりしてくれるらしい。
tf.Sessionとは違って、
    * デフォルトセッションとしてセットしたり
    * saver.saveに送ったり、
    * tf.train.start_queue_runnersに送ったりできない


## 参考：

* [TensorFlow > link > tf.InteractiveSession() > tf.Session()との違い](https://qiita.com/7of9/items/59205fdca2d1ac861075)
* [tf.train.Supervisor](https://www.tensorflow.org/api_docs/python/tf/train/Supervisor)
* [tf.train.MonitoredTrainingSession](https://www.tensorflow.org/api_docs/python/tf/train/MonitoredTrainingSession)
* [tf.train.MonitoredSession](https://www.tensorflow.org/api_docs/python/tf/train/MonitoredSession)
UDP通信のリバースプロキシサーバを立てる

こんにちは、[しんた(@trajanme)](https://twitter.com/trajanme)です。 

今回、UDP通信のリバースプロキシサーバを立てることになってちょっと色々調べてます。
とりあえず、もう少ししっかり調べないとQiita記事としては残せないのですが、いったんアウトプットとして投稿します。

認識誤りや誤字などありましたら、随時ご指摘くださいませ。
アドバイスも大歓迎でございます(๑•̀ㅂ•́)و✧

## 要件
- client1/2からproxyにきたリクエストを特定のwebserverに対して中継する。
- 負荷分散はなし。
- UDP(53)で双方向の通信(client→webserver、webserver→client)がある
- clientは直接webserverにアクセスできない

- client1: `192.168.0.11`
- client2: `192.168.0.12`
- proxy: `192.168.0.101` / `192.100.110.101`
- webserver: `192.100.100.101`
- client1/2 <-|`udp(53)`|-> proxy <-|`udp(53)`|-> webserver

## Nginxを使う
NginxがUDPのロードバランシングに対応しているようなので、これができないかやってみた。
(というか、他があまりでてこない。。)

Nginxを使う場合は、`--with-stream`オプションをつけて`make`しなければいけないらしい。

```/usr/local/nginx/conf/nginx.conf
user  nginx;
worker_processes  1;
pid logs/nginx.pid;

events {
  worker_connections  1024;
}

http {
  include mime.types;
  default_type  application/octet-stream;

  log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for"';
  access_log  logs/access.log  main;
  sendfile  on;
  keepalive_timeout 65;

  include /usr/local/nginx/conf.d/*.http.conf;
}

stream {
  include /usr/local/nginx/conf.d/*.stream.conf;
}
```

```/usr/local/nginx/conf.d/backend.steram.conf
upstream backend {
  server webserver:53 udp;
  proxy_pass backend-server;
}

backend-server {
  listen WEBSERVER_HOSTNAME:53;  
}
```

これで、クライアントから`WEBSERVER_HOSTNAME`に`53`ポートのUDPでアクセスできた。
ただ、今回はやりたい環境に`--with-stream`つきのNginxを入れられないという制約なので、別プランを考えなければいけない。

## ルーティングテーブルでそれっぽくやる
リバプロサーバが`WEBSERVER_HOSTNAME`を受け取ったり、クライアントのIPアドレスを受け取ったときに、自動で転送するようにルーティングテーブルに細工する方法、というのも考えてみている。

## 参考
- [ルーティングの基本動作を見てみよう
](http://ascii.jp/elem/000/000/592/592307/)
- [NGINX に追加された UDP ロードバランシングを試してみた](https://tatsushid.github.io/blog/2016/03/tried-udp-load-balancing-added-to-nginx/)
- [nginxをリバースプロキシサーバとして使う[nginx + apache]](https://access-jp.co.jp/blogs/development/142)
NoSQLとRDBMSの違いが分かる3分Q&A

技術選定のためNoSQLデータベースについて調査しました。

**2019年加筆
**NoSQLと一括りに書いてしまっていましたが、調査したのはRedisなどKeyValue系のNoSQLではなく、MongoDBなどDocument指向系のDBです。

MySQLなどのRDBMSとどちらを選ぶかにあたっての主な疑問点に関しての回答をまとめます。

##NoSQLとRDBMSどっちがいいの？
よほどスケールするのでなければRDMBSが良い。

##NoSQLのメリットは？
1. 水平分散が可能でスケールする。
2. スキーマを定義せず柔軟にデータを入れられる。

##NoSQLのデメリットは？
1. RDBMSに比べてアプリケーションレイヤーの複雑さが桁違いに上がる。
2. データの整合性を保証できない。
3. スキーマを定義できない。

##RDBMSだと何故水平分散ができないのか？
データの整合性を取る必要があるため。複数のサーバー間で同時に同じデータへの書き込み処理があった場合にデータが矛盾してしまうので、書き込みを許可できるのはマスターサーバー一つのみ。読み取りは分散できる。

##何故NoSQLでは水平分散が可能か？
データの整合性を諦めたためどのサーバーも書き込み可能。データがコンフリクトしようがデータをサーバー間で同期する。

##NoSQLを使うと複雑になる要因は？
1. データの整合性が取れない可能性を考慮したアプリケーション設計。
2. RDMBSでは決してしないデータの二重管理の考慮。
3. DBではなくアプリケーションレベルでのValidation考慮。
4. スキーマレスなデータに対する適切な処理の考慮。

##NoSQLはどう設計するの？
NoSQLのコレクション-ドキュメント志向に沿うなら以下の3ポイント。
1. ジョインリクエストができないので一度にデータを取得できるようにデータを持つ。
2. データを重複して持つことを許容する。
3. データを更新する場合は重複したデータに対してそれぞれ更新リクエストをかける。

##NoSQLは何故早い？
1. 水平分散ができるため
2. トランザクション、バリデーション、JOINなどの便利な処理を全て捨てたため。

2に関してはアプリケーションレイヤーで捨てた機能を考慮した処理を書き直す必要があるのであまり意味がない。

##NoSQLとRDBMSの技術的トレードオフは何？
データの整合性とスケーラビリティー(水平分散)

##トレードオフは乗り越えられないの？
Googleが去年[Clound Spanner](https://cloud.google.com/spanner/)というトレードオフを乗り越えたRDBMSを出した。

##NoSQLで使えるDBは？
Googleの[firestore](https://firebase.google.com/docs/firestore/)(まだβ版)がデータの整合性を取れるNoSQL。

##リアルタイムデータベースはどうなん？
データの整合性には少し不安があるようだが、優れた点が多い。
Firestoreの方が値段高い場合があるけど基本良さげ。
[詳細比較](https://firebase.google.com/docs/database/rtdb-vs-firestore)

##MongoDBはどうなの？
個人的には選択肢には入らない。

##結局あんたどのDB使うん？
Firestoreをメインに部分的にMySQLを活用する予定。

##終わりに
誤りやより深い議論があればコメントいただけると助かります。


###参考文献
[F1: A Distributed SQL Database That Scales](https://storage.googleapis.com/pub-tools-public-publication-data/pdf/41344.pdf
)

[Consistency Issues on NoSQL Databases: Problems with Current Approaches and Possible Solution(s)](https://pdfs.semanticscholar.org/5a7e/d7e308348faaad2f587f2cc86e111f645c2c.pdf)
[Clound Firestore](https://firebase.google.com/docs/firestore/)
[Clound Firestore vs Realtime Database](https://firebase.google.com/docs/database/rtdb-vs-firestore)
php-master-changes 2018-11-16

今日はオブジェクト破棄時の処理の最適化、mb_check_encoding() の修正、拡張から $this を参照するためのマクロ ZEND_THIS の導入、SplPriorityQueue の最適化と修正、テストの修正があった！

# 2018-11-16
## dstogov: micro-optimization
- https://github.com/php/php-src/commit/71d6899e535d960d9b43d75ed2b7073288c13b59
- オブジェクト破棄時の処理を最適化

## nikic: Fixed bug [#77165](https://bugs.php.net/bug.php?id=77165)
- https://github.com/php/php-src/commit/dee5a450d9b7f7b03f012dd1912cc0a3dcb0482c
- [7.3~]
- ext/mbstring で、[mb_check_encoding()](http://php.net/manual/ja/function.mb-check-encoding.php) の引数を空配列を渡すとクラッシュする問題の修正
- slack の [phpusers-ja](https://www.msng.info/archives/2016/02/phpusers-ja-on-slack.php) でチラっと話が出ていた奴

## dstogov: Use ZEND_THIS macro to hide implementation details in extensions code.
- https://github.com/php/php-src/commit/0f7f1498be549f5988bf9d8150f35bedf70741c5
- 拡張から $this へアクセスするためのマクロ ZEND_THIS の導入
- [14 日のコミット](https://qiita.com/sj-i/items/ab45c1f959651da19ed5#dstogov-replace-getthis-by-exthis-when-additional-check-is-not-necessary)に対する[コメントで話されていた](https://github.com/php/php-src/commit/c6ad0b92b7d8e66a07cf75ed4abc39fe3e13e00d#commitcomment-31300726)奴

## nikic: Optimize SplPriorityQueue implementation
- https://github.com/php/php-src/commit/e965fee90464e58263291c4774514e4687b8b34c
- ext/spl で、SplPriorityQueue の実装の最適化
- 全要素について 2 キーの配列を持つのをやめ、構造体を使うようにした

## nikic: Check for zero SplPriorityQueue extract flags earlier
- https://github.com/php/php-src/commit/022eea8be1d0a49446b1b52c3f4719717234ccd8
- ext/spl で、[SplPriorityQueue::setExtractFlags()](http://php.net/manual/ja/splpriorityqueue.setextractflags.php) が 0 で呼ばれた際に例外を投げるようにした

## nikic: Fix leaks
- https://github.com/php/php-src/commit/2766a8e66bb6bb9baa3ac5da276bcf995101a50c
- ext/spl のメモリリークの修正

## nikic: Remove some mentions of RECOVERABLE_ERROR in tests
- https://github.com/php/php-src/commit/2fac9d9ec1168b3345e024150ed75aeb748c8361
- テストの幾つかの箇所で E_RECOVERABLE_ERROR がありえるような記述になっている箇所を（実際現状ではありえない箇所なので）修正
リフレッシュの準備（Macbook Pro 13inch 2018）

###### 1.リフレッシュ用パーティションの作成
1. ディスクユーティリティを起動します。

<img width="170" alt="" src="https://qiita-image-store.s3.amazonaws.com/0/312275/fb74c519-56e1-9b92-3aea-d0acdafd1f8a.png">&nbsp;<img  width="170" alt="" src="https://qiita-image-store.s3.amazonaws.com/0/312275/8a390f5d-12a4-d878-33f7-1d54ce03d7df.png">&nbsp;<img  width="170" alt="" src="https://qiita-image-store.s3.amazonaws.com/0/312275/d9972c65-9628-afb3-1297-b2ed402d51d3.png">
2. パーティションを作成します。
<img width="240" alt="" src="https://qiita-image-store.s3.amazonaws.com/0/312275/e28d3c2e-51b1-7d33-74fd-4a449df5c997.png">&nbsp;<img width="240" alt="" src="https://qiita-image-store.s3.amazonaws.com/0/312275/54c323de-f7ac-b1fc-c513-4fd7f6910016.png">

###### 2. MacOSのインストール（オプション）
1. App Storeからインストールします。

<img width="170" alt="" src="https://qiita-image-store.s3.amazonaws.com/0/312275/751f987f-130a-ddab-e0f7-b47c2950b8fb.png">&nbsp;<img width="170" alt="" src="https://qiita-image-store.s3.amazonaws.com/0/312275/4fa4eda9-2a79-ee02-4681-349907371252.png">

###### 3.初期設定（オプション）
1. システム環境設定を起動して、一般、Dock等を設定します。

<img width="240" alt="" src="https://qiita-image-store.s3.amazonaws.com/0/312275/66174a58-d0e8-19a9-6d06-eb719d49023f.png"><br>
<img width="170" alt="" src="https://qiita-image-store.s3.amazonaws.com/0/312275/9b4ee9cc-fe1d-00e3-e780-87688feec7a3.png">&nbsp;<img width="170" alt="" src="https://qiita-image-store.s3.amazonaws.com/0/312275/50c5ba72-cee6-2987-a39b-c40532e9892f.png">&nbsp;<img width="170" alt="" src="https://qiita-image-store.s3.amazonaws.com/0/312275/b238b5cf-917b-21df-14c0-4a35719985a0.png"><br>
<img width="170" alt="" src="https://qiita-image-store.s3.amazonaws.com/0/312275/6714c470-047d-881b-b7bf-95024b00ef4e.png">&nbsp;<img width="170" alt="" src="https://qiita-image-store.s3.amazonaws.com/0/312275/9fa1253e-dc10-d62a-64cd-94ac853c30a7.png">&nbsp;<img width="170" alt="" src="https://qiita-image-store.s3.amazonaws.com/0/312275/a9fd5c66-c76a-29c7-af30-aa3cdbf165d5.png">

###### 4.セキュリティソフトのインストール（オプション）

###### 5.パッケージ管理ソフトのインストール（オプション）
* Homebrew
* Nodebrew
* npm

*手順は別ページ記載の予定*

###### 6.Time Machineでバックアップを作成
1. システム環境設定から、Time Machineを起動する。

<img width="240" alt="" src="https://qiita-image-store.s3.amazonaws.com/0/312275/77675a90-c682-e4bd-68f2-e664562faa64.png">&nbsp;<img width="240" alt="" src="https://qiita-image-store.s3.amazonaws.com/0/312275/9bf54dce-2992-52b4-9320-2d07dd454736.png">
* ディスク選択後はバックアップが開始します。バックアップ完了後、[バックアップ自動作成]のチェックを外します。

###### 7.TimeMachineでリストア
1. リストア後の確認用として、デスクトップに新規フォルダを作成しておきます。
2. Mac再起動します。
3. 再起動時は[ command (⌘) ]+[ R ]を押したままにして、「Mac OS Xユーティリティ」を起動します。
4. 「Time Machiuneバックアップから復元」メニューを選択後、リストアします。
5. 先程の新規フォルダが、デスクトップから消えている事を確認します。
KotlinでTDDするためのお手軽Docker環境を作った

# KotlinでTDDするためのお手軽Docker環境を作った

タイトルの通り。KotlinでTDDするための実行環境やエディタをDockerに突っ込みました。
[Visual Studio Live Share](https://visualstudio.microsoft.com/ja/services/live-share/) 付きなのでペアプロ/モブプロもできるよ！

## とりあえず使いたい人へ

https://github.com/spinylobster/docker-gradle-kotlin-vscode
に使い方が書いてあります。
Docker内のVSCodeを使いたい場合はX11サーバを起動する必要があるので注意。

## 経緯

普段Kotlinは書かないんだけど、TDDとモブプロで自動販売機のお題をKotlinでやろうとした時に、CyberDojoを使ったら全然テストの書き方が分からなくて進まなかった。
どうもKotlinやテストフレームワークのKotlintestのバージョンが最新じゃないみたいだったので、最新のものが使える環境が欲しかった。
ただJDKを自分のPCにインストールしたくなかったので、Docker内で済ませられるように頑張った。

## 中に入っているもの

### 環境

Gradle 5.0-rc3 + Kotlin 1.3.0 + VSCode 1.29.1
です。お手軽にTDDできる環境が欲しかったので、エディタ(VSCode)入り。
バージョンは今日の時点なのでその内更新するかもしれないけど、ちゃんとメンテしていくつもりはないので、最新バージョン使いたかったらfork推奨。

### VSCode with Visual Studio Live Share

VSCodeには予めKotlin用の拡張と [Visual Studio Live Share](https://visualstudio.microsoft.com/ja/services/live-share/) を入れている。
VSLS のおかげで、それぞれのPCにKotlin開発環境がなくてもそれぞれのマシンのVSCodeでコードを書けるし、Kotlin拡張が入ってるので「定義に飛ぶ」機能とかも使えて便利。

IDEAに比べれば足りない機能も多いけど、TDDとモブプロは楽しくできました。
良かったら使ってください。
マサカリも歓迎。