OmniAICreator/Qiita-1.07M huggingface dataset:
[Firebase] 2分58秒で画像自動リサイズ機能を導入した話

アドベントカレンダー6日目!(遅刻!!!)

## 内容

Firebaseにて、storageへの画像アップロード時に、自動リサイズ機能を**2分58秒**で導入した話です。
firebaseはandroidやweb,iOSなど、複数のアプリケーションに接続することができます。uploadする画像をリサイズしたい、となった場合、それぞれでリサイズ処理を作成するのは少々骨が折れますよね。。。**それ、カップラーメン作る間に解決できます。**

## 前提

storageに画像をアップロードできる。

本記事では、upload先のpathは`images/photos/`とします。
普通にアップロードした場合は、以下のようになっています。
![スクリーンショット 2020-12-07 0.28.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266081/c7edbf0d-eae6-b66b-d464-05acc5dccf7c.png)


## どうやって

Firebaseに用意されている、Extensions機能を利用！！！！！！！
Extensionsについては、[この記事](https://qiita.com/ryo2132/items/5e102136a1d7ad5d5e43)がいろいろ解説してくれています。 

## 実際にやってみる

Extensionsはすっっっっごく簡単に便利な機能をFirebaseに導入できると聞いています。
どのくらい便利なのかみてみるために、導入にかかる時間を測ってやりましょう。

**スタート!!!!**
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266081/1ebc2b86-514d-2ccc-8921-d8d6c5917bae.png" width="300px" />

**FirebaseコンソールのメニューにあるExtensionsをクリック!**
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266081/b7fc3a60-a9b0-e267-ecae-49f623d70e56.png" width="300px" />


**利用したいExtensionの選択!**
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266081/1775cb19-b0be-9cf8-561b-919811c814cd.png" width="300px" />

**設定の確認!**
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266081/9dfc091c-fe23-896f-2837-216c69520422.png" width="300px" />

**リサイズ先とかの設定!**
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266081/337958ec-7afa-e901-62a1-b4478bf71533.png" width="300px" />

```
Functions置き場: Storageが存在するRegionか、アクセスが多いRegionを指定します。
切り取りサイズ: コンマ区切りで、縦横それぞれが許容する最大値を入力します。
resizeした画像の保存先: 元画像からの相対パスを記載します。上画像の場合、`{元画像のフォルダー}/resized`に保存されます
resize対象の画像が保存されるpath: ここで指定したパスへのアップロード時に、resize処理が走ります。今回は`images/photos/`を指定しました。
画像の拡張子の設定: jpegやpngに変換するかを選択できます。
```

**インストール!!** (待ち時間は5分くらいかかります)
![スクリーンショット 2020-12-07 1.44.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266081/4c57b8d5-18d9-9967-4386-e8b211488143.png)

**タイマーストップ!!!**
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266081/e5ddd9af-8041-866e-bde9-7f8e6e8c5739.png" width="300px" />

**動作確認**

さて、インストールが終わるまで待ったら、実際に動作確認をしてみます。

storageは、以下のようになっていました。先ほど指定したように、`resized`が作成されていますね！
![スクリーンショット 2020-12-07 1.27.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266081/4c2a2703-418e-b622-29cb-e58e1aaa37b2.png)

`resized`の中身はこのようになっています。`サイズ`をみてみても、リサイズされていることが明白です。
![スクリーンショット 2020-12-07 1.27.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266081/b6baa44d-05bf-c075-2b00-3a2ce81332b0.png)

**終わり！！！！！**

という感じで、`2分58秒で画像自動リサイズ機能を導入`することができました!!! :clap: :clap: :clap: :clap: :clap: 
firebaseをandroidやweb,iOSなど、複数のアプリケーションに接続している場合、それぞれでリサイズを実装するより`圧倒的に`簡単ですね。
他のExtensionsも触る機会あり次第触ってみたいな。。。

ありがとうございました！！！！！


## 余談
**もう一個同じExtensionを追加してみる**
Storageの他のpathに対する画像の追加についても、resize処理を走らせたい、とかもちろんあると思います。
その場合も、単純にもう一つResizeImagesを追加するだけです。
初めのInstanceIDを設定したら、あとは同様に...
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266081/12a070d0-c7e6-9485-e7f9-84c51fb2164e.png" width="300px" />
.NETCoreで画像をピクセル単位で扱う(SixLabors.ImageSharp)

.NETCoreで画像編集するときの定番ImageSharp、たまにしか使わないせいか、使い方を忘れていることがしばしばあるので備忘録として。
公式リポジトリ：[GitHub: SixLabors/ImageSharp](https://github.com/SixLabors/ImageSharp)
動作確認：Version 1.0.2

##1. ImageSharpの導入
nugetを使って導入します。WindowsでVisual Studio使っているならGUIで特に困らず導入できますが、
Linuxで.NETCoreで開発するときに困るのでコマンドラインも書いておきます。

```sh
dotnet add package SixLabors.ImageSharp
```

##2. サンプルコード

###2.1 画像の読み込み
```c#:C#
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;

string path = "filepath.jpg"
Image<Rgba32> img = Image.Load<Rgba32>(path);
```

###2.2 画像のサイズを変更
```c#:C#
using SixLabors.ImageSharp.Processing;
using SixLabors.ImageSharp.Processing.Processors.Transforms;

img.Mutate(x =>
  x.Resize(targetSize.Width, targetSize.Height, new BicubicResampler(), false)
);
```

###2.3 (複数処理)画像のサイズを変更してから画像を水平反転する
```c#:C#
using SixLabors.ImageSharp.Processing;
using SixLabors.ImageSharp.Processing.Processors.Transforms;

img.Mutate(x =>
  x.Resize(targetSize.Width, targetSize.Height, new BicubicResampler(), false).Flip(FlipMode.Horizontal)
);
```

###2.4 ピクセル単位でアクセス
```c#:C#
using SixLabors.ImageSharp.PixelFormats;

Rgba32 px = img[x, y]
byte r = img[x, y].R
byte g = img[x, y].G
byte b = img[x, y].B
byte a = img[x, y].A
```
get / set 両方可能

##3. 最後に
昔はこのライブラリを使ってピクセル単位のデータアクセスとか苦労しましたが、今はかなり楽になりました。
ライセンスもApache2.0ですし、色々な意味で使いやすいライブラリだと思います。
長らくalpha版として公開されていたこのライブラリ、リリースのたびに破壊的変更が入っている印象があります。
今後も破壊的変更がないという保証は無いので、使うときはバージョンに注意した方が良いかも知れないですね。
ラビットチャレンジ - 深層学習 Day4 Section1 強化学習

# 0．概要
本記事は日本ディープラーニング協会認定の講座プログラムである「ラビット・チャレンジ」が提供している科目の1つである深層学習のレポートである。
記事タイトルに記載のとおり、Day4 Section1 強化学習について以下にまとめる。

# 1．強化学習
教師あり学習、教師なし学習と並ぶ学習手法の大きな分類の1つ。

教師あり学習は教師の有無の違いはあるもののデータからなんらかの特徴を学習していっていたが、強化学習はなんらかの目的を設定し、それを達成できるように学習する。

長期的に報酬を最大化できるように環境の中で行動を選択できるエージェントを作ることを目標とする。
行動の結果として与えられる報酬をもとに行動を決定する原理を改善していく。

エージェントは方策に基づいて行動することでその結果に応じた報酬を環境から得られる。
また、行動の結果、環境の状態が変化する。
強化学習はこのエージェントがうまく目的に向かって動くよう方策を学習する。

既知のデータを利用すること、未知のデータを探索することいずれも大切ではあるが、トレードオフの関係にあるため調整する必要がある。
既知のデータの利用ばかりではそれ以上よりよい行動にはならず、未知のデータの探索ばかりでは既知のデータを活かせない。

参考：
https://qiita.com/ikeyasu/items/67dcddce088849078b85
https://blog.brainpad.co.jp/entry/2017/02/24/121500

## 1.1．Q学習
行動価値関数を行動するごとに更新することによって学習を進める方法。

## 1.2．関数近似法
価値関数や方策関数を関数近似する手法。

## 1.3．価値関数
エージェントが目的にゴールするまで今の方策を続けた場合の報酬の予測値を得る関数。

### 1.3.1．行動価値関数
環境の状態と価値を組み合わせた価値に注目する場合に使用される。
ある環境の状態である行動を取った時の価値。

状態$s$+行動$a$

```math
Q^{\pi}(s,a)
```

### 1.3.2．状態価値関数
環境の状態の価値に注目する場合に使用される。
環境の状態が良ければ価値が上がる。

```math
V^{\pi}(s)
```

## 1.4．方策関数
ある環境の状態においてどのような行動をとるのか確率を与える関数。
価値関数の値(価値)を最大化する行動をとるようにする。

状態価値関数$V$、行動価値関数$Q$を元にどういう行動をするか。

```math
\pi(s)=a
```

## 1.5．方策勾配法
方策をモデルにすることで最適化(学習)する手法。
NNの重みの更新式と同じイメージだが、強化学習ではより報酬を得られる行動をする(最大化)ため第1項と第2項を加算している。

方策関数の重みの更新

```math
\theta^{(t+1)}=\theta^{(t)}+\epsilon\nabla J(\theta)
```

$t$：時間
$\theta$：重み
$\epsilon$：学習率
$J$：誤差関数

```math
\begin{eqnarray}
\nabla_{\theta}J(\theta)&=&\nabla_{\theta}\sum_{a\in A}{\pi_{\theta}(a|s)Q^{\pi}(s,a)} \\
\nabla_{\theta}J(\theta)&=&\mathbb{E}_{\pi_{\theta}}[(\nabla_{\theta}log\pi_{\theta}(a|s)Q^{\pi}(s,a))]
\end{eqnarray}
```

$\pi_{\theta}(a|s)$：エージェントが取る行動の確率(方策関数)
$Q^{\pi}(s,a)$：ある状態で撮ったある行動から得られる報酬(行動価値関数)
$\pi_{\theta}(a|s)Q^{\pi}(s,a)$：ある行動をとる時の報酬

取れる行動は複数あるため、総和となっている。

参考：https://blog.syundo.org/post/20171117-reinforcement-learning-policy-gradient/#:~:text=方策勾配法は、方策,ていくアプローチである。&text=などの利点がある,的なものを扱う。

# X．ラビットチャレンジとは
ラビットチャレンジとは、日本ディープラーニング協会認定の講座プログラムの1つ。
E資格を受験するためにはこのラビットチャレンジ等、いずれかの講座プログラムを修了しなければならない。

ラビットチャレンジの特徴は「現場で潰しが効くディープラーニング講座」の通学講座録画ビデオを編集した教材を使用した自習スタイルであるという点。
サポートは他の講座より少なく、受け身ではなく自主的に学んでいく姿勢でなければ進められないが、その分、他の講座に比べると安価であり、手が出しやすい。
ある程度知識がある人、自力で頑張るぞというガッツのある人向けではないかと感じる。

![bnr_jdla.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/389699/bce66671-a2f5-a7f9-de6f-3f87e15c253b.png)
【Python】Flask で自作WEB APIにクエリパラメータを渡す

## 目的

自分で WEB API を提供するサーバを立てたい。そのときに、

> http://myserver:5000/sometask&key1=str1&key2=12.34

のように渡す、普通の形で提供したい。

### 情報源

- WEB API を実装するには、Flask で直接書く方法もありますが、[Flask-RESTful](https://flask-restful.readthedocs.io/en/latest/index.html) というライブラリがあります。チュートリアルもシンプルです。
- 日本語の記事は探したところ見つかりませんでしたが、StackOverflow に投稿があり解決しました。
  - [flask restful: passing parameters to GET request](https://stackoverflow.com/questions/30779584/flask-restful-passing-parameters-to-get-request) では、Flask-RESTfulを使っています。
  - 後日調査し、[How do you get a query string on Flask?
](https://stackoverflow.com/questions/11774265/how-do-you-get-a-query-string-on-flask) で、Flask でも普通にquery parameters を取得できることを知りました。(^^)/
- そのほか、にも記事はいくつかあります。
 - https://qiita.com/tchnkmr/items/26d271886b46c4e52dc1
 - https://note.com/navitime_tech/n/nc0381517d067

## 実装(その１:Flask-RESTfulを使用)

以下で動かしました。flask-restful は pip でインストールしました。

```python:myapi.py
from flask import Flask
from flask_restful import Resource, Api, reqparse

app = Flask(__name__)
api = Api(app)

class TaskAPI(Resource):
    def get(self):

        parser = reqparse.RequestParser()
        parser.add_argument('key1', type=str)
        parser.add_argument('key2', type=float)

        query_data = parser.parse_args()
        print("input_data={}".format(query_data))
        return query_data
api.add_resource(TaskAPI, '/bar', endpoint='bar')

if __name__ == '__main__':
    app.run(debug=True)
```

Flask-RESTful　では、Resource を継承したクラスにgetやpost を実装します。
Flask では返り値をjsonify(data) としましたが、ここでは必要ありません。
実装したクラスをapi に route と共に登録します。
(と、コードを見て理解しています。^^;)

### 動作確認

まず、上記のコードを動かします。

```terminal
$ python3 myapi.py
```

(1) curl で。＆の前にバックスラッシュを入れよう。

```
$  curl http://localhost:5000/bar?key1=val1\&key2=12.34
{
    "key1": "val1",
    "key2": "12.34"
}
```

(2) ipython で

```
In [1]: from requests import put, get
In [2]: get('http://localhost:5000/bar?key1=val1&key2=12.34').json()
Out[2]: {'key1': 'val1', 'key2': '12.34'}
```
(3) ブラウザに入れるとjson が返っているのが分かります。

api.add_resource(TaskAPI, '/bar', endpoint='bar')

## 実装(その２:Flaskを使用)

じ、実はFlask だけでも同じことができました。m(__)m 

```python

from flask import request, Flask, jsonify

app = Flask(__name__)

@app.route('/bar')
def data():
    return jsonify( request.args.to_dict())

if __name__ == '__main__':
    app.run(debug=True)
```

全て```request```に入れられているんですね。（という解釈^^;)

- ```request.args``` には ```ImmutableMultiDict([('val1', 'key1'), ('val2', '12.34')])```が入っています。
- ```request.query_string ```とすると、```b'val1=key1&val2=12.34'```が返ってきます。

自分の場合、なんとなくFlaskだけで良いかも。

## まとめ

とりあえず、目的は達成できた。REST API とはそもそも何か、HTTPとは何か、とか、エラー処理や型の確認とか、よりコードを頑健にするなど、残課題はありますが、まずはここまでとする。
　これで明日の仕事は乗り切れるかな。深夜、日付が変わってしまったが。今日はこの辺りで。
(2020/12/06)

### 追記：

- Flask だけでもquery parameters を辞書として取得できることを知り、追記。(2020/12/07)
1103515245

# LCG

この記事はkb Advent Calendar 2020 5日目の記事です。 https://adventar.org/calendars/5280

## rand()

C言語の`rand()`は[線形合同法(LCG)](https://ja.wikipedia.org/wiki/%E7%B7%9A%E5%BD%A2%E5%90%88%E5%90%8C%E6%B3%95)が用いられていると書かれていることがあるが、BSD libcやglibcの`rand()`の内部で使われている`random()`では、線形合同法を用いた`TYPE_0`、及び[線形帰還シフトレジスタ](https://ja.wikipedia.org/wiki/%E7%B7%9A%E5%BD%A2%E5%B8%B0%E9%82%84%E3%82%B7%E3%83%95%E3%83%88%E3%83%AC%E3%82%B8%E3%82%B9%E3%82%BF)を用いた内部状態のサイズごと`TYPE_1~TYPE_4`の計5タイプの乱数生成器が存在する。

この乱数生成器のタイプは、`initstate()`で設定された初期状態のサイズによって決まり、状態が8/32/64/128/256byteごとに`TYPE_0`~`TYPE_4`の乱数生成器が用いられる。

`initstate()`の結果が32未満の場合、つまり`TYPE_0`の場合は線形合同法が用いられる。(glibcの場合は3回行い全ビット、ANCI Cなどでは上位16ビットが出力される)

それ以外の場合は`random()`は線形帰還シフトレジスタが用いられる。

`srand()`を実行してシードを設定した状態ではデフォルトで128byteとなるため`TYPE_3`が用いられることになる。

`TYPE_3`ではサイズが31の内部状態を用いて線形帰還シフトレジスタを用い、下位1ビットを右シフトで捨てたものが取得できる。また、その内部状態はrandの出力を観測することによって予測が可能である。参考: [Z3Pyでglibc rand(3)の出力を推測してみる](http://inaz2.hatenablog.com/entry/2016/03/07/194000)

また、glibcで用いられている線形帰還シフトレジスタの解説は以下が詳しい。
[The GLIBC random number generator](https://www.mscs.dal.ca/~selinger/random/)


今回はこちらではなく、TYPE_0の実装に用いられている線形合同法の初期パラメータとして使用されている`1103515245`という数字についてである。

## 線形合同法

線形合同法は漸化式 

$xn+1=(A×xn+C)modM$

で表され、定数 $A,C,M$ 、及び $x0$ を設定し疑似乱数を生成出来るというものである。

ここで、周期性が大きくランダム性のある乱数生成器を生成するためには、上記の定数を注意深く選ぶ必要があり、歴史的にはAの選択があまり良くなかったためにLCGの実装であまり効果が良くなかったケースが多く、計算速度は相当速いが精度の悪いIBM社の[RANDU](https://en.wikipedia.org/wiki/RANDU)というサブルーチンなどが有名である。


パラメータの選択の方法は大まかにc=0以下の3パターンがある。

- c = 0、Mが素数
- c = 0、Mが2の累乗
- c != 0 かつ以下をすべて満たす
    - CとMが互いに素(最大公約数が11)
    - A−1がMの全ての素因数で割り切れる
    - Mが4の倍数ならばA−1も4の倍数

### c = 0、Mが素数

これは1948年に[レーマーが発表した乗算合同法](https://en.wikipedia.org/wiki/Lehmer_random_number_generator)である。`minstd_rand`などはこちらで実装されている。


### c = 0、Mが2の累乗

割り算をシフトレジスタのみで出来るのでパフォーマンスに優れるが、下位ビットの周期が上位ビットよりも短いことが欠点である。
[RANDU](https://en.wikipedia.org/wiki/RANDU)や、古い実装ではこちらで実装されていた。


### c != 0 かつ条件をすべて満たす

- CとMが互いに素(最大公約数が11)
- A−1がMの全ての素因数で割り切れる
- Mが4の倍数ならばA−1も4の倍数


Hull-Dobell定理として知られる上記の条件を満たすことで、すべてのシード値(!=0)において、最大値Mの周期を得ることが可能となる。 

参考:[疑似乱数について その1 線型合同法の最大周期条件
](https://arxiv.hatenablog.com/entry/2017/01/20/011046)


## パラメータ選び

コンピュータで線形合同法を用いる場合、前述のHull-Dobell定理を満たすパラメータの中で乗数$A$・加数$C$の選び方として、乗数$A$のコストがなるべく少なく(係数の平方根に近い乗数)、かつ統計的に優れた乗数を選ぶ必要がある。[効果的なパラメータの例](https://arxiv.org/abs/2001.05304)


### 1103515245

libcやglibcなど、色んな場所で使用されているa=`1103515245`/c=`12345`という数字がいつ現れたかについて分からなかったが(色々調べたけど)、Version 7 Unixから既に存在している。この値は他の値に比べてあまり乱数的に優れてはおらず、ビットごとに周期性があり、最下位ビットは周期2、次のビットは周期4という規則性があるため、[実質$2^8$程度くらい(らしい)](http://inst.eecs.berkeley.edu/~cs161/fa08/Notes/random.pdf)


参考

- https://stackoverflow.com/questions/8569113/why-1103515245-is-used-in-rand
- https://www.redhat.com/en/blog/understanding-random-number-generators-and-their-limitations-linux
- https://stackoverflow.com/questions/40107575/the-fastest-random-number-generator
- https://www.quantstart.com/articles/Random-Number-Generation-via-Linear-Congruential-Generators-in-C/#numericalrecipes
- http://www.eglibc.org/cgi-bin/viewvc.cgi/branches/eglibc-2_19/libc/stdlib/random_r.c?view=markup
【GAS】LINEbotで画像やテキストを受け取ったりメッセージを送信したりする

##概要
[【GAS】画像を送ると文字に起こすLINEbot【OCR】](https://qiita.com/YasumiYasumi/items/49479bfaa683fefd09c5)の補足記事。

LINEの投稿から画像を受け取り、ドキュメントのOCR機能で文字に起こし、LINEへ返信する。そんなLINEBotを作成した記事の補足で、その際使用したAPIについて記載。

##JSON形式で受け取るLINEの投稿
WebhookでGASが受け取るLINEの投稿はJSON形式になっている。

「Hello, world!」ってテキストならこんな感じ。

```javascript
{
  "replyToken": "××××××××××××××××××××××",
  "type": "message",
  "timestamp": 1234567890,
  "source": {
    "type": "user",
    "userId": "××××××××××..."
  },
  "message": {
    "id": "3456789",
    "type": "text",
    "text": "Hello, world!"
  }
}
```

ここからメッセージのタイプが欲しければ

```javascript
var type = JSON.parse(event.postData.contents).events[0].message.type;
```

で取得でき、この場合のタイプは「text」となる。

メッセージそのものが欲しければ

```javascript
var message = JSON.parse(event.postData.contents).events[0].message.text;
```

で、「Hello, world!」が抽出される。

##画像を取得する
LINEの投稿から画像などのコンテンツを取得する場合、[LINEデベロッパーズのガイド]
(https://developers.line.biz/ja/reference/messaging-api/#get-content)によれば、HTTPリクエストは`GET https://api-data.line.me/v2/bot/message/{messageId}/content`。ヘッダーなどもガイドに従う。

```javascript
var messageId = JSON.parse(event.postData.contents).events[0].message.id;
var URL = "https://api-data.line.me/v2/bot/message/" + messageId + "/content/";
var image = UrlFetchApp.fetch(URL, {
              "headers": {
                "Content-Type": "application/json; charset=UTF-8",
                "Authorization": "Bearer " + ACCESS_TOKEN,
              },
              "method": "get"
            });
```

メッセージIDから画像のURLを生成し、アクセストークンを使って`"method": "get"`で画像を取得している。

ちなみに、このままドライブに保存すればjpg形式で保存されるし、最後の`)`の後ろに`.getBlob()`を付け加えれば、そのまま`image`を使いまわせる。

##メッセージを送信する
LINEへメッセージを送信する場合、[LINEデベロッパーズのガイド](https://developers.line.biz/ja/reference/messaging-api/#get-content)によれば、応答メッセージを送る際のHTTPリクエストは`POST https://api.line.me/v2/bot/message/reply`。ヘッダーは画像取得の時と同じ。

```javascript
var replyURL = "https://api.line.me/v2/bot/message/reply";

//メッセージ作成
var botMessage = "メッセージ";
var payload = JSON.stringify({
  "replyToken": replyToken,
  "messages": [{
    "type": "text",
    "text": botMessage
  }]
});

//メッセージ送信
UrlFetchApp.fetch(replyURL, {
  "headers": {
    "Content-Type": "application/json; charset=UTF-8",
    "Authorization": "Bearer " + ACCESS_TOKEN,
  },
  "method": "post",
  "payload": payload
});
```

`payload`にメッセージを定義して、アクセストークンを使って`"method": "post"`でメッセージを送信している。

##たったこれだけ
LINEに画像を投稿したら、それを文字に起こして返信するBotを作る上で必要なLINEデベロッパーズAPIはこれだけ。

###おしまい
SuicaとPasmoをモバイルSuicaとモバイルPasmoに移行してみた際の試行錯誤

# 移行の経緯
NFC対応のiPhoneを持っていたが、物理カードで事足りていたので、ずっとモバイルSuica/モバイルPASMOを登録していなかった。しかし、たまにカードを忘れて切符を買ったり、チャージし忘れて改札機で引き返したりを何とかするべく、物理カードをiPhoneに登録することにした。

試行錯誤の結果、最終的にはモバイルSuicaとモバイルPasmoをiPhoneに登録することができた。

# モバイルSuica/モバイルPASMOへの移行

## 現状と登録前の下調べ

まず、持っていたカードは以下の2つである。過去に定期で使っていた関係で、PASMOカードをメインで使っていた。

- PASMOカード（メイン利用）
    - 補足 : 過去に定期で使っていた、定期の印字が薄く残っている、スマートEXに登録している）
- SUICAカード
    - 補足 : 定期で使っていない、表面に何も印字されていない

PASMOカードは、名前や電話番号を登録している関係で、三度紛失しても持ち主の元に戻ってきた。非常に優秀なので、このまま物理カードとして残そうかと思っていたが、残すとか残さないとか考えるのが面倒くさくなって、最終的にiPhoneに登録してハサミで切断した。

SUICAカードは、iPhoneに登録できなかった。何とモバイルSUICAに移行できるのはSUICA定期券のみである。そのため、この無記名＆定期利用経験なしのこのSUICAカードはiPhoneに登録できなかった。しょうがないので、こいつはJRの窓口で記名して、財布に入れて持ち歩くことにした。記名するのは、忘れた時に財布ごと戻って来れるようにするためである。と思っていたら、iPhoneに登録して、モバイルSuica化できてしまったので、Apple Watchに登録した。
> JRや東急の駅に電話番号登録済のSuicaカードやPASMOカードが届けられた場合、駅員さんが電話で連絡してくれる。そのため、カードには必ず記名しましょう！

ちなみに、モバイルSuicaに移行できるSuicaカード、移行できる PASMOカードは以下である。後発の分、PASMOの方が登録できるカードの範囲が広い。

- モバイルSuica/モバイルPASMOに移行できるカード（ref1、ref2）
    - Suicaカード
        - 大人用の有効なSuica定期券
    - PASMOカード
        - 記名PASMO
        - PASMO定期券
- モバイルに移行不可能なカード
    - Suicaカード
        - Suica付ビューカード
        - 高校生以下のSuica通学定期券
        - 割引定期券（障害者、特定者、普通職業訓練）
        - 特殊な区間／券種のSuica定期券（通勤と通学が混在した2区間定期券など）
        - 多機能Suica（学生証や社員証などと一体化されたカード）
        - りんかいSuica（りんかい線発行）
        - モノレールSuica（東京モノレール発行）
    - PASMOカード
        - 無記名PASMO
        - 小児用PASMO
        - 一体型PASMO
        - PASMO定期券（モバイルPASMOでの定期券発行に対応していない事業者が発行するPASMO定期券）
        - 企画券や乗車証を搭載したPASMO
        - 通学定期券（18歳未満）が付加されたPASMO定期券

## PASMOカードの移行

iPhone標準のwａｌｌｅｔアプリを利用して移行した。しかし、オートチャージ設定をするため、移行後にPASMOアプリを利用した。最初からPASMOアプリで移行すれば良かった。
移行後、勝手に+500円（デポジット分）されていた。

## Suicaカードの移行

SuicaカードはモバイルSuicaに登録できないらしいので、登録できないのか確かめてみることにした（バカ）。そしたら、登録できた......。どうも、モバイルSuicaとしては登録できないらしいが、Suicaカードとして登録できるらしかった。物理カードとして持ち歩こうと思っていたのに...計画が崩れる...。

その後、Suicaアプリで情報を登録したら、モバイルSuicaになってしまったので、Apple Watchに転送した（使わないかも）。念のため、オートチャージ設定するべく、クレジットカードを登録したけど、オートチャージで使えるクレジットカードはViewカードのみらしく、オートチャージは設定できなかった。つら。なお、残金0円なら、払い戻し手数料0円なので、無駄にならないらしい。そして、登録してしまったこのSuicaカードもハサミで切断破棄した。

# 移行結果

移行結果は、以下の通りである。

- PASMOカード : 定期カードだったためモバイルPASMOに移行成功、オートチャージも設定。
- Suicaカード : 定期カードではなかったためモバイルSuica移行できない、となる予定だったが、walletアプリに登録し、名前とか設定して、モバイルSuica化して、Apple Watchに設定した。

モバイルSuicaもモバイルPASMOも色々制限があり、難しかった。でも、ドキュメントは比較的まとまっていた気がす。この試行錯誤メモが、これから誰かの役に立てたら、言うことは何も無いのである。

## 参考情報
- ref1 : [モバイルSuicaに移行できるSuicaカードを知りたい。](http://mobilesuica.okbiz.okwave.jp/faq/show/100?category_id=16&site_domain=default)
- ref2 : [モバイルPASMOへの移行ができるPASMO・できないPASMO
](https://www.pasmo.co.jp/mp/and/start/transfer/process/#availableCards)
外部ネットワークから家のiMACに繋ぐ方法

####内容
外出先MacBoook,Windows等から自宅iMacへ接続方法になります。
(ローカルネットワーク上の画面共有でなく、外部ネットワークからの接続を想定)

####接続方法
接続方法は調べた限り２つあるかと思います。
・ssh接続(ターミナルからの接続になります。Lunuxからでも入れます。)
・リモートログイン(WindowsのRDPみたいな感じです。Windowsからでも入れます。)

####iMac側の設定
どちらの接続方法もiMAC(自宅)側で以下２つの設定をします。
・リモートログインの許可
・ルータファイヤーウォールの許可
それぞれ設定値を見ていきます。

####1.SSH接続
#####・リモートログインの許可
Mac側でリモート接続の許可をします。
システム環境設定＞共有＞リモートログインをオンにします。

#####・ルータファイヤーウォールの接続許可
接続元から接続先(iMac)へ22番ポートへの接続許可をします。

#####・接続方法
ssh接続を行います。
コマンドプロンプトで以下のコマンドを入力します。

```ssh
ssh 接続先ユーザ名@ホスト名orIPアドレス
```

####2.リモートログイン
#####・リモートログインの許可
システム環境設定＞共有＞リ画面共有をオンにします。
＊Windowsなどから接続する場合は、
「コンピュータ設定」「VNC使用者が画面を操作することを許可」を設定します。

#####・ルータファイヤーウォールの接続許可
接続元から接続先(iMac)へ5900番ポートへの接続許可をします。

#####・接続方法
VNC接続を行います。
Finderから移動＞サーバへ接続で接続先のグローバルIPを入力し、「接続」をクリックします。

![スクリーンショット 2020-12-07 0.33.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/645781/657ccd53-140b-633f-d197-ecbbb30ac484.png)

VNC接続の場合、そのままだと暗号化されないため、
SSHでポートフォワーディングするのがいいかなと思います。
次回そちらの記事書こうかと思います・・・
コントローラーが故障したraid5ディスク上のDBバックアップはどこに格納されていたか 

# 赤きLEDの明滅とビープ音
とある20世紀末の夏。

「データセンタ」を謳う19インチラック7台ほどのサーバルームの中で、DELLやCompaqのLEDが明け方の空に瞬く星々のように明滅を繰り返していた。
そろそろメジャーになりつつあった青色LEDが、緑やオレンジの輝きの中に混ざり、冷涼な室内をさらに涼しく彩る。

しかし、赤色LED。お前はダメだ。
サーバ機器、ネットワーク機器に光る赤色LEDは、ハードウエアの不具合を示す。

俺はクライアントから、顧客管理システムでエラーが出ている、との連絡を受けた。
クライアントのシステムが収められた「データセンタ」に入室すると、甲高いビープ音が室内に鳴り響いているのに気づく。「データセンタ」は稼働したばかりで運用経験が浅く、俺にはどの機器が泣いているのか、音だけで聞き分けることはできなかった。が、幸い、ラック7台に過ぎない小さな「データセンタ」は、程よく全体への見通しが良いため、すぐに赤いLEDが明滅する機器に目が行く。

DELL PowerVault、3.5インチのHDDが多数搭載されたストレージ機器だ。

そうだ、こいつだ。こいつは今回連絡を頂いたクライアントが保持する大容量データの為に最近購入し、最新鋭のMicrosoft SQL Server 7.0 用のストレージとしてセットアップしたヤツだ。

# Raid5は最強

ディスクの故障だろうか。

しかし心配無用。ディスクの故障に備え、こいつはRaid5とRaid1で組んである。Raid5なら、ディスクが1台や2台故障しても、故障したディスクを交換すれば問題なく復帰できる。おまけにこいつはホットスワップ対応、電源を落とさずにディスクの交換をすることができる。予備のディスクも用意してある。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12857/f5342951-bc2a-bcd9-5bd9-b3d5e1704c92.png)
ディスクの故障は初めての経験だった。本当に復帰するんだろうか、という心配も多少あったが、DELL PowerVaultのRaid5は最強、と、根拠のない安心感が心配を払拭し始める。俺は赤く光るディスクを引き抜き、予備のディスクを挿し込んだ。

# ビープ音再び
新しいディスクを挿し込むと、直ぐに挿し込んだ新品のディスク以外も含め、全ディスクの緑色LEDが瞬きはじめた。
再構築が始まる。再構築が終わるまで、いかほどの時間が必要なのだろう。
外は暑い。俺は再構築完了まで、「データセンタ」の中でのんびり涼むことにした。


数分後、再びビープ音が鳴り響いた。

交換したディスクも壊れていたのか。俺は別の予備ディスクを手に取り、つい数分前に交換したディスクを抜き、差し替える。


しかし、ストレージが復旧することはなかった。

# バックアップからの復旧
涼しいはずのデータセンタが少しも涼しくない。
額からは汗が吹き出し、手のひらは湿り気を増す。
相変わらずSQL Server から、ストレージへのアクセスは復帰しない。幸い、リアルタイムのアクセスを要求されるシステムではなかった為、クライアントからの催促はまだない。数時間のうちに復旧し、「直りました。ディスクにエラーが出てましたよ。幸い、交換可能な構成にしといたので、大事には至りませんでした。」と報告すればいいはずだ。

そうだ、DBデータはD:ドライブ、バックアップをE:ドライブに取るよう設定していた筈だ。
まずはバックアップデータをサルベージの上、PowerVaultを切り離してPowerEdgeサーバにディスクを足して単体でSQL Server を稼働させよう。PowerVaultの問題解決は後回しだ。

# バックアップの保存先
さて、E:ドライブからDBバックアップファイルをサルベージしようか、というところで俺は思い出した。
Raid5で構成された仮想ディスクをパーティションでD:ドライブとE:ドライブに分けていた事実を。

いや、本当は最初から気づいていたのだろう。
Raid5で組まれたディスクにアクセスできなかった時から、DBデータは永久に失われていた事を。

# 土下座による再構築
クライアントへは何をどのように報告したか、記憶が定かではない。
数千件の顧客情報を含むDBが破壊され、「ハードウエアのトラブル」によりデータが永遠に失われてしまった事実を伝えたことは確かだ。
憶えているのは、クライアントが大変寛大であり、全く怒ることも、騒ぐこともなく、冷静に聞いてくれた事だ。

後日、DBサーバは別の機器で再構築され、バックアップはDATドライブへ取るよう、再構築。
データは「クライアント自ら」「紙情報から再入力」することにより復旧を遂げた。
俺は、このクライアントの為ならたとえ深夜2時だろうが駆けつけて対応しよう、と、心に誓った。

# 後日譚
後日、調査により、ディスクではなく、「Raidコントローラ」が故障していたことが判明した。
どのような挙動があったのか不明だが、全てのディスクに「正しくない」情報が書き込まれ、ストレージとして機能していなかった、との事。
Raid1で組まれていた別ドライブも、使い物にならなくなっていた。確かRaid1のドライブにも、時折バックアップファイルをコピーしていた筈だが、それも失われていた…ことはあとになって気づいた。

この物語に教訓なんてものは何も無い。単に、何も考えずにシステム構成を考えたクソなエンジニアが、寛大なクライアントに心を救われた、というだけの話だ。
…それだけではクソすぎるので教訓じみた事を書き殴ろう。

### 惨劇の根本的原因
1. リスク分析が十分ではなかった。Raidコントローラーだって壊れる。壊れた際の影響度は計り知れない。
2. raid に対する本質的理解が足りなかった。Raid5のパリティによる冗長化を、データが消えない魔法の呪文と思っていた。
3. システム設計のレビューが十分ではなかった。同じ環境・デバイスへのバックアップは無意味。

### 教訓
<dl>
<dt>万物は壊れる</dt>
<dd>すべての構成要素は必ず不具合を生じる前提で物事に当たれ。</dd>
<dt>自分を信じるな</dt>
<dd>いい感じで設計できた、実装できたと思っても、必ず自分以外にレビューをしてもらうべきだ。</dd>
<dt>クライアントとは常にいい関係を維持しろ</dt>
<dd>もしクライアントが普段から嫌な思いをしていたら、と思うとゾッとする。人間関係は良好に保とう。</dd>
<dt>真実は友達</dt>
<dd>不都合な事実であろうとも、誠意を持って伝えよう。伝える深度は調整してもいいかもしれない…<dd>
</dl>




※このポエムはほぼ100%の事実をもとにしたフィクションです。製品名、製品仕様については20年以上前ということもあり、曖昧で適当です。
Actions CIでSlack通知にコンソール出力の一部を混ぜる話

そういや今年こんなことをやりましたということで一つ

https://github.com/Pctg-x8/peridot では、GitHub Actionsを使用してCI/CDを組んでいます。元はTravis CIを使用していたんですが、ジョブ構成の柔軟さやCI以外の手順自動化に使えそうという点から今年の3月[^migration-pr]に一気に移行しました。
そこで、Travis CI時代から使用しているCI結果のSlack通知もActionsに移植しまして、今現在ではこんな感じのAttachmentがついたメッセージが届くようになっています。

![スクリーンショット 2020-12-05 16.30.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94115/5cc05b8a-7e9d-36f7-81ce-30e4a1cd8eab.png)

このAttachmentの本文には、エラーとなったジョブのコンソール出力の末尾20行が入っています。
この記事では、この出力を混ぜ込むまでにやったことを解説します。

## 要件と使えそうなコマンド

この機能の要件としては以下の通りです。

* rustcのエラーメッセージの最後の数行をAttachmentに取り込みたい
* ただし、Actionsの画面でもリアルタイムにメッセージが流れた方が楽しいので、メッセージの出力をブロックしたくはない

出力をブロックせずにコンソールの出力をとるとなると使えるのは `tee` くらいですかね。
というわけで、teeで出力をしれっと横取りして何らかの形で通知アクションに引き渡せればOKとなります。

といったことを https://github.com/Pctg-x8/peridot/blob/4f59042a29cda434354e8e3f76c303719e90a337/.github/workflows/integrity-test.yml#L76 のあたりでやっています。

...人が書いたyamlファイルのように見えないですか？
そう思った人はすごく鋭くて、PeridotではGitHub Actionsのワークフローファイルを記述するのに `Dhall` という別の設定記述言語を使用しています。
詳しい説明は省きますが、500行近いyamlはもはや人間が書くような物ではないので、より高級かつ型安全なDhallを使用するとワークフローの記述でかなり幸せになれます。
オフィシャルなDhallの型定義は存在しませんが、今回のワークフローを書くためにある程度の物を用意したので、よろしければ参考にしてください。
https://github.com/Pctg-x8/gha-schemas

## Stepの出力を他Stepに渡す

Stepの出力を他のStepから参照するには、一般的にはGitHub Actionsに備え付けの機能で行えます。
https://docs.github.com/ja/free-pro-team@latest/actions/creating-actions/metadata-syntax-for-github-actions#outputs
一般的にはこれで行えますが、今回はteeで拾ったものを渡す形になります。teeの出力はファイルになっているため `steps.<step id>.outputs` を使って内容を渡すことはできません。
そこで、今回はSlack通知Actionで直接teeの出力ファイルを読む形にしました。

PeridotのSlack通知Actionは、個人の他のリポジトリでも使用したいためリポジトリが分けられています。
https://github.com/Pctg-x8/ci-notifications-post-invoker
このアクションはあまり汎用的には作っていないため[^restriction]Marketplaceには出していませんが、Marketplaceに出さなくてもgitリポジトリのレベルでこういった機能の共有を行うことができるのはActionsの強い利点だと思います。
このリポジトリのREADMEを読めばわかると思いますが、 `.buildlog` および `.rawbuildlog` といったファイルを `$GITHUB_WORKSPACE` に配置することで、その内容をAttachmentの本文として埋め込むようになっています。ファイルが二つ分かれているのは、ファイルの中身をコードブロックにするか否かを簡単に切り分けるためです。

### Slack通知Actionについて

このSlack通知ActionはTypeScriptで書かれています。
GitHub ActionsではアクションのランナーとしてDockerかJavaScript(Node.js 10/12系)を使用することができます。Dockerにすると適切なイメージを選択することで任意の言語を使用することができるのですが、Dockerの場合は初回のイメージビルドに時間がかかるのと、今回のように「Payloadを用意してAPIを叩く」だけであればJavaScript（TypeScript）でも全然問題ないのでJavaScriptランナーを選択しました。
TypeScriptはそのままではActionとして動かすことはできないので、JavaScriptにトランスパイルしてからpushしています。本来であればGit Hooksとか導入してコミット時 or push時に自動でトランスパイルできると大変良いのですが、準備がちょっと面倒なので今は `yarn build` でトランスパイルできるようにして、必要なタイミングでコマンドを発行する形にしています。

## おしまい

かなりざっくりなお話ですが、Slack通知にコンソール出力を混ぜるのは以上が全部となります。
Actionsは実際触っててかなり楽しくて、workflow_dispatchとかを組み合わせれば簡易的なLambdaやCloud FunctionsみたいなこともできてChatOpsとの相性も抜群だと思います。

teeで出力を拾うためにいろいろビルドスクリプトで苦労したお話もあるんですが、あまり覚えていないのとGitHub Actionsの話からは逸れるのでここでは割愛します。

[^migration-pr]: https://github.com/Pctg-x8/peridot/pull/124
[^restriction]: 内部で呼び出しているプライベートのLambda関数の仕様に激しく依存しているので、そもそも汎用的に作れないです......
自分(ちゅらデータCTO)がPMするときに気をつけていること

この記事は[ちゅらデータアドベントカレンダー](https://qiita.com/advent-calendar/2020/churadata)の7日目の記事になります。

# どっちのPM

プロジェクトマネージャのほうです。
最近は**プロダクト**マネージャを指すことも増えてきてますが、今回は**プロジェクト**マネージャです。

今日は自分がPMをするときに気をつけていることを共有しようと思います。

ちなみにPMがマネージするのはプロジェクト（目的があって有期性のある活動）です。
無限に続くかもしれない運用業務や、ルーチンワークはすこし違うかなって感じです。

ちゅらデータではお客様へデータ分析した結果やモデルなどの成果物を納めることが多々あるので、PMスキルの高い人は重宝がられます。

# 最初に制約事項の確認

プリセールス段階から絡むことがよくあり、自明なことも多いのですが、たまにそうでないこともあり、そういうときは最初に制約事項の確認を行います。
よくある制約事項は下記のようなものがあります。

- 見積り金額や発注金額
- スケジュール
- 使えるデータや環境などのリソース
- 成果に求められているフォーマットや諸条件
- 契約内容

この辺は慣れたPMなら自然に確認するようになっていますかね。

# ステークホルダの確認

制約事項がわかったら、次はステークホルダを確認しておきましょう。
このときに意味不明だった制約事項が、ステークホルダを見たらわかったりします。
「あー、この製品つかうのってこれが理由だったのか〜」とか

# 背景と目的の確認

次は背景と目的の確認です。
おそらくプロジェクトになる前の段階で、背景や目的などは決まっているかもしれませんが、たまにそのあたりがまだふわっとしたままのプロジェクトもあります。
もしふわっとしたままだったら、きちんと明文化しましょう。
教科書的にはプロジェクト憲章などを作ることになりますが、プロジェクトの規模によってはそこまで作り込まなくても、背景と目的を自然文で書いて列挙するだけでも十分かなと思います。

背景と目的というのはたとえば、

- 今の業務はこう、でもホントはこういう姿を目指したい。だから我々はこういう取り組みをするんだ！
- 今こういうデータが集まっている。たぶんこういう事ができるはずだ。だから我々はこういう技術を開発するぞ！

こんな感じです。

目的はPoCをすすめると変わってきたりするのですが、それに比べて背景はそれほど変わらない事が多いです。
とはいえ新しい情報が判明して、背景と目的をまとめて変更したほうが良くなるケースが無いわけじゃありません。
プロジェクト進行中にそういった事が起こる場合は、プロジェクトマネージャの腕の見せ所です。
残りのスケジュールや残されたリソースを鑑みて、ベストを尽くしましょう。

# 社会的な位置づけの確認

エンジニアやデータサイエンティストの一部の方は気にしない方もいるかも知れません。
けれど私は自分の仕事の社会的な位置づけを確認することにしています。

どんなインパクトを世の中に与えられるのか、それは良いことなのか、あまり意味のないことなのか。
そして考えた内容をプロジェクトのメンバーと共有するようにしています。

取り組むべき価値があるプロジェクトは楽しいものです。
楽しさは成果物の品質に影響を与えます。
取り組む意味がわからない、楽しくない、無意味なプロジェクトで高い品質を上げらると考えるPMはメンバーの力を最大化することをサボってると言えます。
すなわち自らリソースを食いつぶしてる悪いPMと言えます。

この社会的位置づけの確認は大事です。

# 勝ちパターンの確認

お客様が悩んでいることって、お客様目線ではすごく重要なことです。
だから複雑怪奇で特異な問題に見えてしまう。
けれど世の中にすでにある教科書的アプローチで十分に解決可能なケースがいくらかはあります。

そのため勝ちパターンがないか探して見ることが必要です。
私達の仕事はお客様に価値を提供することであって、闇雲に技術や知識を振り回すのではないので、既存の勝ちパターンがある場合は、そちらを提案する場合があります。

もちろんお客様の中にはそれをわかっているけど、社内の説得ができないから証拠固めをして、次につなげていきたいみたいな複雑な背景を持っているケースもあるので、その場合は一緒に汗を流します。
世の中の勝ちパターン的アプローチが実際にお客様の持っているデータだと当てはまらないケースも多くありますから。


# あとは

**あとはPMBOKにあるようなテクニックや知識、各種アジャイルの実践方法を通じで普通にプロジェクトを進めましょう。**
PMBOKには「PMこんな時どうする？」みたいなのがだいたい公開されてるので学んでつかうだけで良い。簡単です。

# 終わりに

実はPM領域の仕事は簡単です。
覚えるだけだしコミュニケーションするだけだし機械的にアプローチするだけでいいところがほとんどです。
PM領域の知識が多いのがPMの価値ではあるのですが、それってどの専門職にも言えることですから…。

だからPMのアートなところは限られていて、メンバーや顧客と雑談するところとか、ねじ込む力とか魔法みたいなムーブとか、そのあたりに個人ごとの価値がでるのかなって思ってます。

ちゅらデータではデータサイエンスプロジェクトを引っ張るPMをいつでも募集しています。
気になっている方はぜひご連絡ください。

あと**オンライン忘年会**やります。
https://churadata.connpass.com/event/196682/

きてね〜。
react-dndのimportで起こった事

#react-dndのimport時にエラーが出た
「react-dnd」を利用してサンプルを作ろうと思った時に「import」でエラーが出たので対処方を書こうと思います。
大したものではないです。

###import { DragDropContext } from 'react-dnd'がない

``` javascript
import { DragDropContext } from "react-dnd"
```
**DragDropContext**が見つからないと言われてしまいます。
最新ではこれが変わっていて…

``` javascript
import { DndProvider } from 'react-dnd';
```

になっています。

###import ReactDnDHTML5Backend from 'react-dnd-html5-backend'がない

``` javascript
import ReactDnDHTML5Backend from "react-dnd-html5-backend"
```
**ReactDnDHTML5Backend**が見つからないと言われてしまいます。
最新ではこれが変わっていて…

``` javascript
import { HTML5Backend } from 'react-dnd-html5-backend';
```
になっています。

---

調べても意外とスンナリ見つからなかったので、参考になれば嬉しいです。
ありがとうございました。
NSX-T 3.1 の世界観を理解する   ②

[前回](https://qiita.com/smzn_h/items/442be1912a45a7674e75)に引き続き、NSX-T 3.1 について解説していく。


##構築全体の流れ
今回は ESXi ホストのみの環境を想定している。
1. [NSX-T の機能を各ホストに追加する。](https://qiita.com/smzn_h/items/442be1912a45a7674e75)
2. セグメントを作成し、そこに仮想マシンを接続する。（本記事）
3. Edge Cluster を展開
4. Tier1 Gateway を構成する。
5. Tier0 Gateway を展開する。
（本記事執筆時想定。）

## セグメントの作成
###セグメントとは
セグメントとは、NSX-T における、仮想的な L2 ネットワークである。物理ネットワークでは別のホストかもしれないし、別のデータセンターかもしれない。L3 を超える場合であっても、仮想マシン自身は L2 の通信として認識している。
NSX-V においてはLogical Switch (LS) と呼ばれていて、vDSのポートグループとして作成されていた。

それではセグメントの作成を行っていく。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/552541/a0b8fb8a-1aa6-6990-3d78-43e147dda5a9.png)

###設定項目
**セグメント名**はそのまま名称である。
**接続されたゲートウェイ**は、後に出てくる Gateway を接続することで、セグメント間のルーティングが行われる様になる。この時点ではまだゲートウェイを作成していないため、何も選択することはできない。Gatewayを作成してからセグメントを作成、という順序ですすめることも可能である。

なお、ゲートウェイを「なし」とすることもできる。
これはセグメントがルータをもたない状態になるので、他のサブネットとの通信をしない場合などに用いるものである。

**トランスポートゾーン**では、セグメントを適用するトランスポートゾーンを選択することができる。

```
ホスト : 1, 2, 3 と トランスポートゾーン : A, B と、それに対応したセグメント : a, b が存在してA∋{1, 2} B∋{2, 3} とすると、
1にはbの、3にはaのセグメントのポートグループが存在せず、仮想マシンを接続することができない、ということになる。
```

**サブネット**ではセグメントと接続されているルータ（ Gateway ）の IP アドレスを指定すると同時に、セグメントのサブネット（ネットワークの範囲）を定義することになる。ここでセグメントにDHCPの機能をもたせることも可能である。構成は一般的なDHCPの設定項目と遜色ないため説明は割愛する。

**VLAN**ではセグメントのVLANを作成することができる。ここで設定するVLANとは、あくまでNSX-Tのセグメントの中で使用されるVLANである。

以上のような設定を行いセグメントを作成すると、トランスポートゾーンに対応するvDS もしくは N-vDS上にポートグループ 作成される。

実際にセグメントとして seg-01, 02を作成すると、以下の通りvSphere Client からも 確認できる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/552541/86bd07ec-1db8-63bc-bb6c-4924a5c00648.png)

###仮想マシンとセグメントの接続

ここに、vCenter 上の仮想マシンを接続していく。
細かな手順は省略するが、仮想マシンの仮想nicの接続先のポートグループを変更するだけである。

以下のスクリーンショットではSeg-01, 02 にそれぞれCent OSを配置している。
（NSX-T コンソール > ネットワーク > ネットワークトポロジ）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/552541/3c2f3aaa-3939-4624-cd8f-b2bbe0e29acd.png)


ということで、前回の記事と合わせて、NSX-Tの導入からセグメントに仮想マシンを配置するところまでを解説した。

なぞればできるような記事にしたくなかったので、あまり具体的なパラメータのスクリーンショットなどは載せてきていない。しかしやはり想像がつきづらいのも事実かと思うので、次回はここまでの手順を改めて具体的なパラメータを交えながら解説していく。
sv-parser: SystemVerilogパーサライブラリ

# はじめに

この記事は[SystemVerilog Advent Calendar 2020](https://qiita.com/advent-calendar/2020/systemverilog)の7日目です。

sv-parserは自作のSystemVerilogパーサライブラリです。2019年9月ごろにリリースしたのですが、よく考えると日本語で紹介記事を書いたことがなかったので、ここで紹介しようと思います。

# sv-parser

https://github.com/dalance/sv-parser

sv-parserは以下のような特徴を持つSystemVerilogパーサライブラリです。

* Rust製
* IEEE Std 1800-2017準拠

SystemVerilogは言語仕様が膨大（BNF定義が44ページあります）で、ちょっとしたツールを作るのも簡単ではありません。OSSでSystemVerilogのパーサはいくつかありましたが、規格を完全に満たしたものはなかったので自分で作ることにしました。

# sv-parser と sv-tests

https://github.com/SymbiFlow/sv-tests

sv-testsはOSSのツールに対してSystemVerilogのコンプライアンステストをするプロジェクトです。
言語仕様書に載っているような構文単体のテストケースからRISC-Vコアのような実プロジェクトまで、様々なテストケースを各OSSに対して実行し、結果を公開しています。
この1年間でsv-testsのFailから見つかったパーサのバグもいくつかあり、大変助かっています。

2020/12/6時点でのsv-parserの結果は 4416/4532(97%) がPassということで、全ツール中トップのPass率となっています。Failしている3%についてもテストケース側の問題であることは確認済みなので、正規の構文でFailするケースは（現時点では）見つかっていない状態です。

# sv-parserを使ったツール

sv-parserを使ったツールとしては現時点で以下のものが確認できています。

* [morty](https://github.com/zarubaf/morty): A SystemVerilog source file pickler
* [svinst](https://github.com/sgherbst/svinst): Determines the modules declared and instantiated in a SystemVerilog file
* [svlint](https://github.com/dalance/svlint): SystemVerilog linter
* [svls](https://github.com/dalance/svls): SystemVerilog language server

このうちsvlintとsvlsは自作なので、sv-parserをライブラリとして使ってくれているユーザは2名ということになります。
これ以外にもメールで直接問い合わせて来る方も何人かいました。
公開当初は「SystemVerilogとRustという組み合わせで開発者は存在するのか？」という疑問がありましたが、意外といるようですね。
この調子でSystemVerilog向けのOSSが増えていくと嬉しいです。
新しいマシンにVue.js Reactの環境をインストールする方法

自分用に新しいマシンにVue.jsやReactをインストールする方法をメモとして残す
マニュアルインストールの方法は別にまとめる（予定）

## Macに『HomeBrew』をインストールする
- 何故インストールするのか？
  - CUIベースで環境構築がしやすくなる
  - 『$ brew install xxx』でCUIツールをインストールできる
  - 『$ brew cask install xxx』でGUIツールをインストールできる

### HomeBrewインストール手順
  - 1. [HomeBrew](https://brew.sh/index_ja)のHPを開く
  - 2. Terminalを開く
  - 3. インストールコマンドを実行する

```
$ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"
```

## brewコマンドでMacの開発環境を構築していく
  - Google Chrome

```
$ brew cask install google-chrome
```

  - VSCode

```
$ brew cask install visual-studio-code
```
  - [IntelliJ](https://www.jetbrains.com/ja-jp/idea/)
    - IntelliJのHPを開く (Ultimate版は有料なので、適宜検討する)

```
https://www.jetbrains.com/ja-jp/idea/download/#section=mac
```

## Node.jsをインストールする
  - 1. Terminalを開く
  - 2. 下記コマンドを実行する (この時は最新のnodeのバージョンがインストールされる)

```
$ brew install node
```

  - 3. インストールされたNodeのバージョンを確認する

```
$ node -v
ex). v12.14.1
```

  - 4. npmコマンドが実行できるか確認する (試しにバージョン情報を確認する)

```
$ npm -v
ex). 6.14.8
```

  - 5. nodeのバージョン管理コマンドをインストールする (今回は『n』を使用する)

```
$ npm install -g n
```

  - 6. nコマンドが実行できるか確認する (試しにバージョン情報を確認する)

```
$ n -V
ex). 6.7.0
```

### nについて
  - Nodeのバージョンを管理することができる
    - Nodeのバージョンを確認する
    - https://nodejs.org/ja/download/releases/
  - nodeの最新バージョンをインストールする

```
$ n latest
```

  - インストール済みのNodeのバージョンを確認する

```
$ n ls
```

  - Nodeのバージョンを切り替える
      - 実行後にインストール済みのNodeのバージョンが表示されるので変更したいバージョンを選択する

```
$ n
```


## Vue.jsの環境構築方法

### vue/cliコマンドを実行できるようにする
  - 1. [@vue/cli](https://www.npmjs.com/package/@vue/cli)のHPを開く
  - 2. Terminalを開く
  - 3. @vue/cliをインストールする

```
$ npm install -g @vue/cli
```

  - ※1 バージョンを指定してインストールする場合は『@』をつける (Version 4.5.7をインストールする場合)

```
$ npm install -g @vue/cli@4.5.7
```

  - ※2 updateの仕方 (updateするときもinstallを実行することにより最新バージョンを取得できる)

```
$ npm install -g @vue/cli
```

  4. インストール済みの@vue/cliのバージョンを確認する

```
$ npm -g ls | grep @vue/cli
ex). @vue/cli@4.5.7
```

### Vueのプロジェクトを作成する
  - 1. Terminalを開く
  - 2. プロジェクトを新規に作成する (今回はプロジェクト名を『sample』とする)

```
$ vue create sample
```

## Reactの環境構築方法

### create-react-appコマンドを実行できるようにする
  - 1. [create-react-app](https://www.npmjs.com/package/create-react-app)のHPを開く
  - 2. Terminalを開く
  - 3. create-react-appをインストールする

```
$ npm install -g create-react-app
```

  - ※1 バージョンを指定してインストールする場合は『@』をつける (Version 3.4.1をインストール)

```
$ npm install -g create-react-app@3.4.1
```

  - ※2 updateの仕方 (updateするときもinstallを実行することにより最新バージョンを取得できる)

```
$ npm install -g create-react-app
```

  - 4. インストール済みのcreate-react-appのバージョンを確認する

```
$ npm -g ls | grep create-react-app
ex). create-react-app@3.4.1
```

### Reactのプロジェクトを作成する
  - 1. Terminalを開く
  - 2. プロジェクトを新規に作成する (今回はプロジェクト名を『sample』とする)

```
$ create-react-app sample
```
仮説検定とは



##仮設検定とは
仮設検定とは、「統計的に結論づけること」
つまり、「仮設検定」を用いると、差異が偶然生じたのか、そうではないのかを結論付けることができる

YouTubeのサムネイル（YouTubeで最初に表示される画像のこと）の例

某YouTube担当者のとある会話
「サムネイルの背景は青の方が赤よりクリック率が高い、だから青の背景で作ろう」
「サムネイルの背景色は赤も青も変わらないよ」

これどっちが正しいのか・・・

そんなときに使えるのが、仮設検定
統計的に上記の対立構造を決着つけることである

そこで対立に関して、帰無仮説と対立仮説と名をつける。イメージは、赤コーナーと青コーナー的なものかな

今回の場合であると
帰無仮説・・・「サムネイルの背景色は赤も青も変わらない」
対立仮説・・・「サムネイルの背景は青の方が赤よりクリック率が高い」


##棄却とは
仮設検定で使う棄却
仮説検定の目的は、帰無仮説を棄却するために行うこと
棄却・・・「これは間違っている！！」つまり否定する

どうやってこれを棄却するのか

「p値」
→ 有意確率は帰無仮説が正しい確率のことをいう。
だいたい5%が多い
つまり帰無仮説が5%正しい＝対立仮説が95%正しい

この値が前もって定めた水準より大きい場合は、帰無仮説を採択
水準より小さい場合は、帰無仮説を棄却する


##どのように仮設検定を行うのか
① 帰無仮説と対立仮説の設定
② 帰無仮説と対立仮説の数字の差分の平均と標準偏差を算出
③ 基本統計量tの計算
　 t分布の計算（サンプルの平均-真の平均）/（サンプルの標準偏差/√n）
④ 帰無仮説が正しいとした場合のt分布において③で計算したt値は棄却域に入る
⑤ ①で設定した帰無仮説は棄却できた場合は、対立仮説が正しいと言える
libfieldFunctionObjectsのageを使った解析例

#はじめに
計算領域内での流れの滞在時間や、流体の混合の程度を評価できないか、と調べていたところ、`libfieldFunctionObjects`の`age`というのがあるのを見つけ、ここにそのメモを残しておきます。

#使用環境
- OpenFOAM-8 (Fundation版)
- Ubuntu 20 LTS

#ageとは
`foamInfo age`によると
>Solves a transport equation to determine the time taken for a particle to convect from an inlet to the location in the flow.

粒子が流れているとして、流入口からの移動時間を計算してくれるようです（単位は時間になっています）。

また、`/opt/openfoam8/src/functionObjects/field/age/age.H`をチェックすると、

```
Description
    Calculates and writes out the time taken for a particle to travel from an
    inlet to the location. Solves the following equation when incompressible:
    \f[
        \div (\phi t) = 1
    \f]
    where:
    \vartable
        t    | Age [s]
        \phi | Volumetric flux [m^3/s]
    \endvartable
    Boundary conditions are generated automatically as zeroGradient on all
    walls and inletOutlet everywhere else.

Usage
    \table
        Property  | Description                   | Required | Default value
        phi       | The name of the flux field    | no       | phi
        rho       | The name of the density field | no       | rho
        nCorr     | The maximum number of correctors | no       | 5
        schemesField | The name of the field from which schemes are taken | \\
        no | age
        diffusion | Switch to turn on/off the diffusion term | no | off
        tolerance  | Solver residual control       | no       | 1e-5
    \endtable

    \verbatim
    age1
    {
        type            age;
        libs            ("libsolverFunctionObjects.so");

        executeControl  writeTime;
        writeControl    writeTime;

        schemesField    k;
    }
    \endverbatim
```
のように解説がでてきます。

ここでは`age`という変数を追加し、

```math
div (\phi t) = 1
```
という方程式を説いてくれるようです。式中、___t___ が`age`、$\phi$は流束を表しています。
ここで、fvSchemesにおいて`age`に対して`div`を設定しなければならないこと、壁面境界条件には`zeroGradient`、その他の境界は`inletOutlet`が自動設定されていることに注意が必要です。

#設定方法
```bash
foamGet age
```
により、system/以下に`age`ファイルがコピーされます。

```c++:system/age
type            age;
libs            ("libfieldFunctionObjects.so");

diffusion       false;
schemesField  U;
//diffusion       true;

executeControl  writeTime;
writeControl    writeTime;
```

先の支配方程式の説明と矛盾していますが、デフォルトでは`diffusion true`となっていて、拡散項が有効になっています。これを`false`にすると、支配方程式通りの拡散項を無視した解析をしてくれます。schemeFieldは、指定した変数と同じスキームを`age`にも適用することを意味しています。

#使用方法
simpleFoam等を走らせたあとに、

```bash
simpleFoam -latestTime -postProcess -func age
```

とすることにより、最終時刻に対しての`age`の計算をしてくれます。

#使用例
以下は`simpleFoam/roomResidenceTime`の結果例になります。


|![Screen Shot 2020-12-06 at 23.54.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227359/2d8a9b48-aad6-753b-036f-bedb3ff7e364.png)|
|:---:|
|*diffusion true*|


|![Screen Shot 2020-12-06 at 23.53.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227359/ce672d8d-50ed-a1bd-67aa-d92aacad9ac0.png)|
|:---:|
|*diffusion false*|


#まとめ
`age`を使うことにより、流入口からの移動時間を計算することが可能です。
支配方程式で拡散項を考慮していないはずが、設定では拡散項を含めており、ここの確認については今後の課題になります。
JavaScript　ランダムに文字を表示させる(乱数）


<p>
<p>
JSでランダムに文字や数字を表示させるには

```Math.floor(Math.random()　* ○○○.length```

を使います。
<p>

```javascript:qiita.js
const omikuji = ["大吉","小吉","吉","凶"];
const rnd = Math.floor(Math.random() * omikuji.length);
```

上記を実行するとランダムに、　大吉　小吉　吉　凶　と表示されます。

色々応用効きそうです。


<p>
<p>
<p>




ちなみに、JSの実行コードは

 ```console.log(○○○); ```

です。


<p>
<p>
android:windowLightStatusBarを動的に変更する

XMLで静的に設定する場合は以下のように書く。

```xml
<item name="android:windowLightStatusBar">true</item>
```

コード上で動的に変更する場合は以下のように書く。

```kotlin
// Light
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
    window.insetsController?.setSystemBarsAppearance(
        WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS,
        WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS
    )
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    window.decorView.systemUiVisibility =
        window.decorView.systemUiVisibility or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
}

// Dark
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
    window.insetsController?.setSystemBarsAppearance(
        0,
        WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS
    )
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    window.decorView.systemUiVisibility =
        window.decorView.systemUiVisibility and View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.inv()
}
```
let's encrypt + certbotで自宅鯖(Nginx on Ubuntu20.04)にTLSを導入しよう

# はじめに
なんとなく、TLSの導入って面倒の割にリターンが少ないような印象を抱いていたのですが、certbotというツールのおかげで2020/12/06現在驚くべきほどに簡単になっていたので共有しておきます。

あんまりしっかりした記事じゃないですが、とりあえず防備録として書いておきます。

[certbot](https://certbot.eff.org/)
[let's encrypt](https://letsencrypt.org/)

# 環境
- OS: Ubuntu 20.04
- nginx

# 準備・前提
前提として、httpでurlを使ってアクセス出来るwebサービスが自宅サーバーで可動してる状況を想定しています。これはちなみにDDNSとかでも大丈夫でした。私が実験をしたときには、いくつかのサービスがdockerコンテナ上で可動しており、Nginxがドメイン名を見て、適切なportにアクセスをフォワードするような構成になっていました。

また、webサービスを提供中のサーバーにはsshでアクセスできるものとします。また、各webサービスにはポート80で接続できるものとします。

# 手順

- webサービスを提供している自鯖にsshで接続
- snapdのインストール[参考](https://snapcraft.io/docs/installing-snap-on-ubuntu)

```bash
$ sudo apt update
$ sudo apt install snapd
```

- certbotのインストール

```bash
sudo snap install --classic certbot
```

- コマンド実行用のシンボリックリンクの作成

```bash
sudo ln -s /snap/bin/certbot /usr/bin/certbot
```

- certbotコマンドの実行

```bash
sudo certbot --nginx
```

なんと、これで終わりです。後は、certbotがメールアドレスの入力や、各種規約への同意を促して来ますが、聞かれたとおりに返信していくだけで、なんとNginx上の設定まで自動的に行ってくれます。

ただし、一点だけ注意として、ポートの80と443は開放しておいてください。私はこの443の開け忘れに気が付かず、少し時間を無駄にしてしまいました。
自宅サーバなどで、ルータからポートフォワーディングをしている場合には、443についての設定を追加することもお忘れなく。

また、今回は、Nginx on Ubuntu20.04のケースでしたが、それ以外の場合にも、公式で以下のようにして、手順の説明を見ることができます：

1. certbotの公式サイトメニューから[certbot instruction](https://certbot.eff.org/instructions)にアクセス
2. My HTTP website is running ... の部分でお使いのツールを選択
Pythonで簡単なライフゲームアニメーション

#はじめに
jupyter notebook上で、できるだけシンプルにライフゲームを再現してみる。

#下準備
%matplotlib notebookはjupyter notebookにアニメーションを描画するためのおまじない。（%matplotlib nbaggでもできそう）

```
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
%matplotlib notebook
```

#フィールド
最初にサイズheight×widthのランダムな01領域を作る。今回は50×50領域で作成。

```
height=50
width=50
fig=plt.figure() #figオブジェクト作成
ims=[]
field=np.random.randint(0,2,(height,width))
```

初期状態の例
![ランダム.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593049/e90100c3-e1f2-076a-a19e-6bca7ff49a88.png)

#状態の更新
100回更新する。

```
for i in range(100):
    im=plt.imshow(field)
    ims.append([im]) #リストに突っ込んでいく
    field=update(field) #更新
```
#update関数
見ているマスが生存している場合、
隣接するマスの2または3つが生きている→生存

見ているマスが生存していない場合、
隣接しているマスの3つが生きている→生存
と遷移させていく。

```
def update(field):
    field2=np.zeros((height,width))
    dx=[1,1,1,0,0,-1,-1,-1]
    dy=[1,0,-1,1,-1,1,0,-1]
    for i in range(height):
        for j in range(width):
            count=0
            for k in range(8):
                count+=field[(i+dx[k])%height][(j+dy[k])%width]
            if(field[i][j]==1):
                if(count==2 or count==3):
                    field2[i][j]=1
            else:
                if(count==3):
                    field2[i][j]=1
    return field2
```

#アニメーション描画
0.1秒ごとに切り替わる。

```
ani=animation.ArtistAnimation(fig,ims,interval=100)
plt.show()
```

#コード全体

```
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
%matplotlib nbagg

def update(field):
    field2=np.zeros((height,width))
    dx=[1,1,1,0,0,-1,-1,-1]
    dy=[1,0,-1,1,-1,1,0,-1]
    for i in range(height):
        for j in range(width):
            count=0
            for k in range(8):
                count+=field[(i+dx[k])%height][(j+dy[k])%width]
            if(field[i][j]==1):
                if(count==3 or count==2):
                    field2[i][j]=1
            else:
                if(count==3):
                    field2[i][j]=1
    return field2

height=50
width=50
fig=plt.figure()
ims=[]
field=np.random.randint(0,2,(height,width))

for i in range(100):
    im=plt.imshow(field)
    ims.append([im])
    field=update(field)
    
ani=animation.ArtistAnimation(fig,ims,interval=100)
plt.show()
```


![test.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593049/ae7da44f-793f-7586-835a-72f958bd300c.gif)

良さげ。一瞬グライダーがいる。
Mochaのdescribe()をネストしたときにhook関数が実行される順番

# 概要
describe()をネストしたときの before(), after(), beforeEach(), afterEach() が呼ばれる順番を確かめた結果について述べる。 ([Mocha公式のhook関数についての説明はこちら](https://mochajs.org/#hooks))

# 結論
ネストしても各itで一番外のbeforeEach()、afterEach()が毎回呼ばれてる。
リトライした場合も同じく、一番外のbeforeEach()～afterEach()をやり直している。

# 実験１
describeをネストし、外・内それぞれのbefore,after,beforeEach,afterEachでログを出してそれらの実行タイミングを確認する。

```typescript:入力
describe("describe(外)", () => {
  before(() => console.log("外-before"));
  beforeEach(() => console.log("外-beforeEach"));
  after(() => console.log("外-after"));
  afterEach(() => console.log("外-afterEach"));
  describe("describe(内)", () => {
    before(() => console.log("内-before"));
    beforeEach(() => console.log("内-beforeEach"));
    after(() => console.log("内-after"));
    afterEach(() => console.log("内-afterEact"));
    it("it-1", () => console.log("it(1)"));
    it("it-2", () => console.log("it(2)"));
  });
});
```

```text:出力結果（実行順に出力）
    外-before
        内-before
            外-beforeEach
                内-beforeEach
                        it(1)
                内-afterEact
            外-afterEach
            外-beforeEach
                内-beforeEach
                        it(2)
                内-afterEact
            外-afterEach
        内-after
    外-after
```

# 実験２
さらにリトライ入れたらどうなるか。

```typescript:入力
import { assert } from "chai";

describe("describe(外)", () => {
  before(() => console.log("外-before"));
  beforeEach(() => console.log("外-beforeEach"));
  after(() => console.log("外-after"));
  afterEach(() => console.log("外-afterEach"));
  describe("describe(内)", () => {
    before(() => console.log("内-before"));
    beforeEach(() => console.log("内-beforeEach"));
    after(() => console.log("内-after"));
    afterEach(() => console.log("内-afterEact"));
    it("it-1", function () {
      this.retries(1);
      console.log("it(1) failing");
      assert.fail("it(1)");
    });
    it("it-2", () => console.log("it(2)"));
  });
});

```

```text:出力結果（実行順に出力）
    外-before
        内-before
            外-beforeEach
                内-beforeEach
                        it(1) failing
                内-afterEact
            外-afterEach
            外-beforeEach
                内-beforeEach
                        it(1) failing
                内-afterEact
            外-afterEach
            外-beforeEach
                内-beforeEach
                        it(2)
                内-afterEact
            外-afterEach
        内-after
    外-after
```
メッセージが投稿されたときに、一時的に「成功しました」的な表示をさせたい

#はじめに
　メッセージが投稿されたときに、ちゃんと投稿できたか、ユーザーに知らせた方が、使い勝手がよい思い、調べた。

##コントローラー側の記述

```ruby:controllers
def create
  @post = Post.new(post_params)
  if @post.save
    flash[:success] = '送信されました'
    redirect_to root_path
  else
    render :new
  end
end
```

##ビュー側の記述

```erb:views

<%= flash[:success] %>
```

##最後に
　成功したときだけじゃなく、失敗したときにもメッセージを表示できるようにしよう！
WSL2で仮想ディスクイメージをマウントする

ツールとしては `qemu-nbd` を使うのですが、WSL2のデフォルトではカーネルモジュール `nbd` が有効になっていないので、カーネルを自分でビルドします。

## カーネルビルド

方法は [WSL2でカスタムカーネルをビルドして使う](https://qiita.com/matarillo/items/bcae7e61ada3d1a7f9a4) に書きました。

ただし、ビルドする前にカーネルパラメータを変更します。

```./Microsoft/config-wsl
# CONFIG_BLK_DEV_NBD is not set
CONFIG_BLK_DEV_NBD=y
```

## コマンドインストール

```
$ sudo apt install qemu-nbd
```

## ネットワークブロックデバイス(nbd)の接続

```
$ ls -l /dev/nbd*
/dev/nbd0  /dev/nbd10  /dev/nbd12  /dev/nbd14  /dev/nbd2  /dev/nbd4  /dev/nbd6  /dev/nbd8
/dev/nbd1  /dev/nbd11  /dev/nbd13  /dev/nbd15  /dev/nbd3  /dev/nbd5  /dev/nbd7  /dev/nbd9

$ sudo qemu-nbd -c /dev/nbd0 /mnt/c/<path>/<to>/virtualbox.vdi

$ sudo sfdisk -d /dev/nbd0
label: dos
label-id: 0x9719b922
device: /dev/nbd0
unit: sectors
/dev/nbd0p1 : start=        2048, size=      204800, type=83, bootable
/dev/nbd0p2 : start=      206848, size=     4022272, type=82
/dev/nbd0p3 : start=     4229120, size=    12548096, type=83
```

## マウントする

下の例では パーティション `/dev/nbd0p3` をマウントしてますが、パーティションは環境によって変えてくださいね。

```
$ sudo mkdir /mnt/virtualbox

$ sudo mount /dev/nbd0p3 /mnt/virtualbox
```

## アンマウントして、nbdも切断する

```
$ sudo umount /mnt/virtualbox

$ sudo qemu-nbd -d /dev/nbd3
```
AWS ソリューションアーキテクトアソシエイト 問題 IAM編

## 概要

今回は会社の後輩向けにAWS ソリューションアーキテクトアソシエイト向けの問題を作成したのでそちらの公開を。
元ネタは公式の問題、BlackBeltなどからとっております
今回はIAMをみようと思います。


## IAM関係

* EC2インスタンス（AWSアカウントをAとする)上で実行されるアプリケーションで別のAWSアカウント(Bとする)のS3のバケットへアクセスする実行したところ、アクセスできない問題が発生している。AのアプリからBのS3バケットへアクセスできるように対応する方法を以下から2つ選択してください。EC2インスタンスからは自分のAWSアカウントのS3バケットにはアクセスできるとする。
    1. BのアカウントにAのアカウントのIAMロールと同名のロールを作成しS3FullAccessの権限を付与する。
    1. AのアカウントのS3にBのアカウントと同名のバケットを作成しバケットポリシーにBのアカウントのアカウントからのprincipalを指定する。
    1. BのアカウントのS3バケットポリシーにAのアカウントのIAMロールをprincipalに指定する。
    1. AのアカウントのIAMロールにS3へのアクセス権を付与するリソースとしてBアカウントのバケットにアクセスできるように指定する。

<details><summary>回答</summary><div>

* 正解は

    3. BのアカウントのS3バケットポリシーにAのアカウントのIAMロールをprincipalに指定する。
    4. AのアカウントのIAMロールにS3へのアクセス権を付与するリソースとしてBアカウントのバケットにアクセスできるように指定する。
        * アクセス先のS3バケットのprincipalにアクセス元のアカウントのIAMを許可するように記述しますこれはS3以外でも同様です。
        * アクセス元のユーザはアクセス先のバケットへのアクセスできるように設定が必要です。

* 以下不正解の理由

    1. 同名のロールを作成しても意味がありません。またS3FullAccessは権限が広すぎるので必要に応じて狭めるべきです。
    2. まったく意味がありません。


</div></details>

* IAMのベストプラクティスではないものを以下から選択してください。
    1. AWS アカウントのルートユーザーアクセスキーをロックする。
    1. 認証情報を定期的にローテーションする。
    1. インラインポリシーを使用して権限を制御する。
    1. プログラムでAWSの各サービスにアクセスする場合ロールを使用する。
    1. IPアドレスや日付、MFA使用などを条件に追加する。

<details><summary>回答</summary><div>

* 正解は

    3. インラインポリシーを使用して権限を制御する。
        * インラインポリシーは個別に条件を設定できるが個別に設定することになるため管理ができなくなるのでカスタマー管理ポリシーを使用することが推奨されている。
        * 個別に条件を設定したい場合(一次的に使わせるときなど)には有効

* 以下不正解の理由
    * 他はすべてベストプラクティスとして推奨されています。


</div></details>