OmniAICreator/Qiita-1.07M huggingface dataset:
ぼくのかんがえたさいきょうのWordpress@AWS環境(DNSの設定編)

# はじめに
当記事は[ぼくのかんがえたさいきょうのWordpress@AWS環境](https://qiita.com/Shi-nakaya/items/7fb6d16c0adb5c7b47fd)にて記載している[作成手順](https://qiita.com/Shi-nakaya/items/7fb6d16c0adb5c7b47fd#作成手順)の
1. [WordPress入りのLightSailを作成](https://qiita.com/Shi-nakaya/items/a882963cf14dcc64fcac) 
2. [Route53にてドメインを取得](https://qiita.com/Shi-nakaya/items/edcd86a3a8811654573b)
3. [取得したドメインを元にSSL証明書を発行](https://qiita.com/Shi-nakaya/items/d35b5a0f7fb7a7689fce)
4. [CloudFront構築](https://qiita.com/Shi-nakaya/items/b00a04e07ca6e24887ca)
5. [DNSの設定](https://qiita.com/Shi-nakaya/items/30d2339c3570d012ca62)← ここの手順の詳細です。
6. [セキュリティ対策](https://qiita.com/Shi-nakaya/items/8812da74f5dca200cf45)

手順2のRoute53にて取得した独自ドメイン
手順4のCloudFrontで構築したドメイン
これらをもとにDNSへレコードを登録します。

# 手順
AWSにログインし、サービスから「Route53」をクリックします。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/265300/520b42f3-526c-2dde-9457-018a1f87fca8.png" width=40%>

「ホストゾーン」をクリック
<img width=30% src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/265300/3354ce6b-ebcb-b856-9194-d02c232d421f.png">

手順2で取得したホストゾーンのレコードをクリックすると
<img width=70% alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/265300/48cac215-ded3-9152-da57-374c63e28d4c.png">
デフォルトの2件(ns~)とSSL証明書の取得時に登録(英数字の羅列)した1件の
計3件のレコードが登録されている
画像のように追加でレコード2件を登録したいので

レコードセットの作成をクリックする

「名前」には公開したいドメイン名を入力
「タイプ」は「CNAME」を選択
「エイリアス」は「いいえ」を選択
<img width=60% alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/265300/e37f100c-c025-33f0-c289-88edd8231b6c.png">
「値」には手順4構築したCloudFrontのドメイン名「〜.cloudfront.net」を入力する
<img width=70% alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/265300/4c2a37a3-b9d2-cd4f-5ef6-50398966fee5.png">
入力が完了したら「作成」をクリック

もう1件登録する為、レコードセットの作成をクリックする
「名前」には任意のドメイン名を入力(公開される名前ではないのでなんでも良い)
「タイプ」は「A」を選択
「エイリアス」は「いいえ」を選択
<img width=60% alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/265300/cd23c41d-58f8-c7f9-212f-bce7d75d63f3.png">
「値」には手順1で作成したLightsailに設定した固定のIPアドレスを入力する
<img width=60% alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/265300/69a28272-fb6a-c728-17a3-cb9156b8989c.png">
入力が完了したら「作成」をクリック

以上で、設定は完了

しばらく(5分くらい)してから
自分で登録した公開したいドメインである〜.com、net等にブラウザでアクセスしてみて
Wordpressのサイトが閲覧できればOK
VBAで重複のない配列(ユニーク,一意の配列)を作成する関数

適当に探してみても見つからなかったので、練習がてら初投稿させていただきます。

Scripting.Dictionaryを使用して重複を削除する方法です。
これはデータ数が極端に増えてもそれなりの速度で処理可能です。
Office製品はExcelしか使ったこと有りませんがおそらくVBA/VB6系では共通で使えるのかなと
(使えなくても責任は負いません)

以下の関数をモジュール等にコピペして使用してください。

```vb
Function Distinct(args As Variant) As Variant

    Dim dictionary   As Object 
    Set dictionary = CreateObject("scripting.dictionary")

   'microsoft scripting runtimeが参照設定されている場合は以下のほうが良い(補完が効く上に多少速い)
   'Dim dictionary   As Dictionary
   'set dictionary = new Dictionary

    Dim arg As Variant
    For Each arg In args
        If Not dictionary.Exists(arg) Then
            dictionary.Add arg, 0
        End If
    Next arg
    
    Distinct = dictionary.Keys

End Function
```
※ユーザー定義関数となるのでExcelワークシート上でも関数として使えますが
結果が配列として帰ってくるため余程トリッキーに使うのでもなければ使い所はないと思います。
また、この関数は2次元配列を引数に入れた場合も1次元配列となって帰ってきます。

# 使い方
以下は既存のhogeArrayから重複のない配列をuniqueArrayに代入します。

```vb
'hogeArrayにはあらかじめデータが入っているものとする。
 dim uniqueArray
 uniqueArray = Distinct(hogeArray)
```
また、Rangeオブジェクトは.valueプロパティで値を取得してくることでVariant配列を返すため、Excelでは以下の様な使い方もできます。
uniqueArrayには引数に入力した範囲の値を重複内配列として受け取ります。

```vb
 dim uniqueArray
 uniqueArray = Distinct(Range("a1:a100").value)
```

#速度測定
 テスト1:A1-A1,000,000のセルに1-100の整数(乱数)が入っている。
 テスト2:A1-A1,000,000のセルに1-100,000の整数(乱数)が入っている。
 それぞれ、セルの値を取得して新しい配列に代入するまでの時間を測定

```vb
Sub DistinctTest()

    Dim startDate As Date
    Dim buf As Variant
    Dim i As Long: i = 100

    Do
        startDate = timer
        buf = Distinct(Range(Cells(1, 1), Cells(i, 1)).Value)
        Debug.Print Format(timer - startDate, "0.000") & "sec データ数:" & i
        i = i * 10
    Loop Until i >= Rows.Count

End Sub
```
結果
テスト1(1-100までの数)
 0.000sec データ数:100
 0.000sec データ数:1000
 0.008sec データ数:10000
 0.109sec データ数:100000
 0.867sec データ数:1000000

テスト2(1-100000までの数)
 0.000sec データ数:100
 0.000sec データ数:1000
 0.023sec データ数:10000
 0.258sec データ数:100000
 2.141sec データ数:1000000

データ数に対してほぼ比例した速度を保っている(と思う)
Goでスターリンソート

#なぜやろうと思ったか
皆さんご存知のスターリンソートを止まっていたGoとdockerの勉強がてら作成してみます。
##ソースコード
```golang

package main

import(
  "fmt"
)
func unset(s []int, i int) []int {
  if i >= len(s) {
      return s
  }
  return append(s[:i], s[i+1:]...)
}

func main() {
  stalin := [] int{3, 6, 7, 1, 9, 7, 11, 2}
  fmt.Println(stalin)
  for i := 1; i < len(stalin); i++ {
    fmt.Println("対象:",stalin[i])
    if stalin[i] < stalin[i - 1] {
      stalin = unset(stalin, i)
      fmt.Println("有罪")
    } 
  }
  fmt.Println(stalin)
}
```
##結果
```
対象: 6
対象: 7
対象: 1
有罪
対象: 7
有罪
対象: 2
有罪
[3 6 7 9 11]
```
粛清されましたね。
スターリンソートって表現も面白いし、ソートを粛清って言うのも笑っちゃう。

追加
よく見たら全要素見ていないのでまた修正します
TOEIC800日記 Day1

渋谷三省堂にて金フレ購入。

まずは単語だよなー。
TOEICはまじで単語勝負だと思う。
あんまりよく見てないけど、難しい構文とかはあんまり見ない気がする。
普通に文法わかってれば700は行く。
実際俺がそんな感じ。
去年だか2年前だか忘れたけど、700とれた。
特にTOEIC対策はしなくても700はいける。
逆に700以上目指すなら単語覚えないとなーって思った気がする。

TOEICの単語帳といえば金のフレーズだよね。知らんけど。
悩んでてもしょうがないし悩むほど知識もないから売れてるものを買ってみた。

一日50単語ペースでやってこうと思う。
完全に皮算用でしかないけど、全部で1000語だから、20日で一周できる。
まぁ皮算用に過ぎないことは明白ではあるけども。
後半は前半ほど簡単じゃないし、多義語とか定型文パート含めたら1000語超えるし。
そもそも俺自身が毎日サボらずに続けられるのかって言う最大の問題もあるし。

前半の400語は一日50単語ペースでもそんなに負担にならなそうだから、とりあえずこのペースで行く。やばそうだったら考え直す。

目標は一応800点なんだけど、単語だけの勉強で取れんのかなー。流石に舐め過ぎだろうか。
2ヶ月後くらいに受けてみようかな。
2020年の3月には結果が欲しいから、2020年1月のテストで800点とりたいな。
いま9月だから、あと4ヶ月か。意外と少なかった…
結構頑張らないといけないな。

がんばろ。
？？？「Excelで簡単に行列計算？できるわけねーだろｗｗｗ」

## はじめに
できます。



## 行列の積
行列の積を求めるには`MMULT`関数を使います。
`MMULT`関数は2つの配列を引数に持ち, その配列の積を返す関数です。
具体的には以下のように操作します。
まず, 出力したい配列の領域, つまり, 行列の積のサイズを選択します。
<img width="540" alt="MMULT.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/342285/df1fd46d-d58c-653c-9e52-0021c6b649a2.png">
次に, `MMULT`関数に積を取りたい2つの配列を渡します。
<img width="541" alt="MMULT2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/342285/6fd5c805-0721-57f8-9f0f-bf46f22b8737.png">
そして, `Ctrl` + `Shift` + `Enter`を押すと結果が出力されます。
<img width="593" alt="MMULT3.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/342285/b7ba1d51-b03d-3ef5-04c5-1b87422b80dc.png">


## 逆行列
逆行列を求めるには`MINVERSE`関数を使います。
`MINVERSE`関数は1つの配列を引数に持ち, その配列を行列と見たときの逆行列にあたる配列を返す関数です。
具体的には以下のように操作します。
まず, 出力したい領域, つまり, 逆行列のサイズを選択します。
<img width="541" alt="MINVERSE１.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/342285/90af3ef9-1d73-40fc-32aa-d1d3986b5eb3.png">
次に, `MINVERSE`関数に逆行列を取りたい配列を渡します。
<img width="541" alt="MINVERSE2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/342285/732fa10c-6152-337c-f39c-32350392ece9.png">
そして, `Ctrl` + `Shift` + `Enter`を押すと結果が出力されます。
<img width="540" alt="MINVERSE3.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/342285/af1dd73e-e078-a1c9-8286-c2cf184b57d7.png">


## 行列式
行列式を求めるには`MDETERM`関数を用います。
`MDETERM`関数は1つの配列を引数に持ち, その配列を行列と見たときの行列式を返す関数です。
具体的には以下のように操作します。
出力したいセルを選択し, `MDETERM`関数に行列式を求めたい配列を渡します。
<img width="540" alt="MDETERM.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/342285/bc6a2fb8-ccf2-e07b-189c-ad247d513a19.png">
そして`Enter`を押すと結果が出力されます。
<img width="541" alt="MDETERM2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/342285/8d56287c-35d2-4e6f-4e31-515cd53ca07b.png">

## 連立方程式を解いてみよう
行列の積と逆行列を求めることができるので, n元1次連立方程式をExcelで解くことができます。
例えば次の連立方程式を解いてみましょう。

```math
\left\{
\begin{array}{ll}
2x + y - 5z = 1\\
- 3x + 3y + z = 2\\
x - 2y +z =3
\end{array}
\right.
```
まずこうして。
<img width="540" alt="RENRITSU.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/342285/8cf3b1b0-7ad2-0cfb-99bb-e29399b7c289.png">

はい, `Ctrl` + `Shift` + `Enter`。
<img width="540" alt="RENRITSU2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/342285/17736608-162d-0d76-92f1-a7c353c4d3fa.png">

$(x, y, z) = (-71, -57, -40)$ が解として得られました。




## おわりに
Excelで手軽に行列の計算を行うことができるというお話でした。
プログラムを書いたことがない, もしくはちょっとした行列の計算がしたい方々におすすめです。
~~大学時代の自分に教えてやりたい。~~
【Office365】メールが有効なセキュリティグループのメンバーを取得する

メールが有効なセキュリティグループに属しているメンバーを知りたい場合に使えます！

```powershell:qiita.ps1
Get-DistributionGroupMember -Identity "メンバー出力したいセキュリティグループのメールアドレス"
``` 
【出力結果】
Name      RecipientType
太郎      UserMailbox

のように出てきます。これじゃ正直情報は足りません。

```powershell:qiita.ps1
Get-DistributionGroupMember -Identity "メンバー出力したいセキュリティグループのメールアドレス" | select DisplayName,Department,PrimarySmtpAddress
```
と指定することで、ユーザー名、ユーザーの所属部署、ユーザーのメールアドレスを取得することが可能です。

配布リストのメンバー取得もいけます。
例えば、総務部グループ内のメンバーを知りたいとか、総務部グループ内に総務課グループがメンバーとして設定されている場合、総務課のメンバーは見えません。
PowerShellをもうちょっと頑張って書くか、今回のコマンドを1つ1つ実行する必要があります。
統計検定2級日記 Day1

渋谷三省堂でマセマの確率統計を買った。
仕事終わりにふらーっと寄っただけのつもりだったけど、気付いたら買ってた。
ついでにシャーペンのシャー芯とノートも買った。
勉強道具、エモい。

マセマの確率統計を買った理由はいくつかある。

- 数学のリハビリ
- 大学受験時代から確率苦手だった
- マセマ信仰

工学部卒業程度には数学できるんだけど、卒業してから5年くらい経つから、数学のリハビリが必要だなーと。
いきなりゴリゴリの本買ってやる気失せても仕方ないから、まずは場合の数とかその辺からざっと復習したい。

結構受験は真剣にやったタイプなんだけど、確率は苦手だった。めっちゃ苦手ってわけでもないけど、並だった。もしくは並ちょい下くらい。

マセマはよく聞くし、微分積分のやつやったことあるけど結構わかりやすかった気がするから、今回もマセマに頼ってみる。
あんまり分厚くないのもいい。

ちゃんと勉強すれば合格できると思うんだけど、ちゃんとできるかどうかが問題なんだよな。

がんばろ。
さくらサーバへのWebhookでのGit自動化の悪戦履歴(成功したので修正追記)

#目標　
LaravelでGit push をwebhookで自動化したい。
~~私は未解決です。が、一部解決したことだけ書いています。~~
#失敗1 webhook.phpへのパスが通らない


自動化phpの作り方は検索すると何件か出てきたので参考にやってみましたが、そのphpファイルをどこに置くか、URLはどうなるのかので苦戦しました。
みなさん、そこのところ黒塗りにして隠しているので困りました。
Webhookの設定欄の近くで以下のように404が出ている時はおそらくパスが通っていない。
<img width="445" alt="スクリーンショット 2019-09-04 21.24.54.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201982/e34ae070-627c-7392-4eec-1a7ef697c31e.png">

解決策
さくらサーバー側のディレクトリで、

```
~/home/ユーザー名/www/プロジェクト名
```

のプロジェクト名フォルダの直下にwebhookの書いてあるphpを置く。
(www/以下ならどこでも良さそうですがここではLaravel開発を前提にプロジェクトフォルダがあるものとしています。)

するとURLが

```
http://ユーザー名.sakura.ne.jp/プロジェクト名/deploy.php
```

になるので
<img width="734" alt="スクリーンショット 2019-09-04 21.42.05.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201982/9f6a89c6-3354-d69a-565b-a983466e9086.png">

Payload URL のところに記入して登録する。

するとエラーメッセージが
<img width="753" alt="スクリーンショット 2019-09-04 21.44.29.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201982/34c5c06e-353d-9f8a-e65a-f152e56169ee.png">
になった。

とりあえずこのファイルのパスは通ったようなので次はphpファイルの中身だろうか。
#解決法（2019/10/31追記) 

上記のタイムアウトが起きた原因は公開鍵をGithubに登録していなかったからでした。
今までシェルでsshログインしてターミナルでpullしていましたが、webhookで自動化する場合はユーザー名とパスワードが入力できない（できるかもしれないが現状、私はそのphpコマンドがわからない。)
そのため、githubがイベントを通知してさくらネットのdeploy.phpが起動してもパスワードがないのでpermission deniedになっていたようです。

さくらネットのサーバー内で公開鍵と秘密鍵のセットを作り、githubのsettingページの鍵登録欄に公開鍵（テキストベースの文字列)をコピペして登録することで、githubとさくらネットの間でパスワード入力が免除されます。

deploy.phpの何がおかしいかまではログで教えてもらえないのでハマりました。

公開鍵の設定のやり方はこのページの一番下に参考にしたページのリンクを貼っておきましたのでそちらをみてください。かなり詳しく書いておられます。

ちなみにphpコードが構文エラーなどでコケている場合は下のように500エラーが表示されます。
![スクリーンショット 2019-10-31 21.59.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201982/7feedbed-0d96-aa2a-929b-41862ee9b771.png)

なので、それが出ないでタイムアウトする場合はphp自体は反応しています。

deploy.phpの中身についてはサイトによって色々書かれていますが、

```php:deploy.php
<?
echo "<p>webhook start</p>";
exec('cd /home/アカウント名/www/gitpullしていたディレクトリ名/',$op);
print_r($op); 
exec('git pull');
echo "<p>webhook finish</p>";
?>

```

これだけで動きます。echoとprintは確認用にログ出してるだけなので実質二行です。
他の方は一行にまとめてる人が多いです。
exec()メソッドはクォーテーションの中の文字列をそのままターミナルに吐き出しているだけです。
つまり、１回目のexecで今までgit pullしてパスワード入力していたところに行って、
２回目のexecでプルしてるだけです。

上の内容で成功すると以下のログが出ます。
![スクリーンショット 2019-10-31 22.17.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201982/9de20044-2228-462b-f7c5-768e67a9e7f5.png)

もしコケる場合、execを消してechoの行だけにしてプッシュしてみてください。
ここのBody欄のログは自動プッシュに成功したかどうかじゃなくて、deploy.phpのprint系メソッドのログを出力しているだけなので、echoだけでテストするとイベントが通知、発火できているかどうかを確かめられます。

#参考にしたページ

[GitHubでssh接続する手順~公開鍵・秘密鍵の生成から~](https://qiita.com/shizuma/items/2b2f873a0034839e47ce)
[Golang]標準のsqlパッケージで、とりあえずMySQLを操作してみたサンプル

# いきなり結論のコード

```golang
package main

import (
	"database/sql"
	"fmt"
	"log"
	_ "github.com/go-sql-driver/mysql"
)

func main() {
	db, err := sql.Open("mysql", "root:password@/mydb")
	if err != nil {
		panic(err.Error())
	}

	defer db.Close()

	fmt.Println("接続成功")

	rows, err := db.Query("SELECT id, last_name, email FROM users limit 10")
	if err != nil {
		panic(err.Error())
	}

	for rows.Next() {
		var id int
		var last_name string
		var email string
		if err := rows.Scan(&id, &last_name, &email); err != nil {
			log.Fatal(err)
		}
		fmt.Println(id, last_name, email)
	}

}
```

```text:実行結果
接続成功
1 柴咲 shibasaki_asahi@example.com
2 沢村 sawamura_keisuke@example.com
3 阿部 abe_atsuko@example.com
4 佐古 sako_shouta@example.com
5 宮里 miyazato_hitori@example.com
6 梅沢 umezawa_kaori@example.com
7 松村 matsumura_tamaki@example.com
8 高岡 takaoka_houshi@example.com
9 大下 ooshita_yonezou@example.com
10 西岡 nishioka_masaya@example.com
```

DBにあらかじめ仕込んでおいた、データが取得できました。
（※データ自体はサンプルです。）

# 解説

## `github.com/go-sql-driver/mysql`でドライブをインポート

```golang:この部分
import (
	"database/sql"
	"fmt"
	"log"
	_ "github.com/go-sql-driver/mysql"
)
```

- インポートに、忘れてはならないのが`_ "github.com/go-sql-driver/mysql"`
- これはドライバなので、**ないとmysqlを取り扱えない**
    - 後日、`xorm`という便利なライブラリを使ってみたのですが、こういったライブラリを使った場合も必要だった

（xormを使ってみた記事は[こちら]()。）

また、このように`_`を書いてインポートする方法は、**ブランクインポート（blank import）と呼ばれ**るそうです。
今回のように、このドライバを**初期化させて使いたい**だけの場合、定番でこういった使われ方をしています。

## `sql.Open()`で接続

```golang:この部分
db, err := sql.Open("mysql", "root:password@/mydb")
```

- データベースに接続する関数
- エラーも返してくれる
- 接続して、変数に代入する。
- 引数に、データベースの種類とデータベース情報を渡す
    - データベース情報には、`user_name`、`password`、`host`か`port`、`db_name`が必要


今回は、ローカルホストへの接続だったので省略していますが、本来は
`sql.Open("mysql", "root:password@http://hoge.com/mydb")`
みたいな感じになります。

## 忘れずに`db.Close()`でクローズ

```golang:この部分
defer db.Close()
```

忘れる前に、クローズも書いておきます。
deferで最後に実行されます。

## `Query()`で生SQLクエリを実行

```golang:この部分
rows, err := db.Query("SELECT id, last_name, email FROM users limit 10")
```

- `db`変数には、先ほどの接続結果が入っている
- エラーを返してくれる
- 結果はさらに`rows`に代入
- 引数には、そのままの生SQL文でOK
- この関数で列ごとにデータを取ってきて、後に出てくる`Scan`関数でマッピングする


## `Next()`で行セットに対して繰り返し処理

```golang:この部分
for rows.Next() {
        var id int
        var last_name string
        var email string
        if err := rows.Scan(&id, &last_name, &email); err != nil {
            log.Fatal(err)
        }
```

- 行セットに対して繰り返し処理をしている

## `Scan()`取得してきたデータを変数へ

```golang:この部分
for rows.Next() {
        var id int
        var last_name string
        var email string
        if err := rows.Scan(&id, &last_name, &email); err != nil {
            log.Fatal(err)
        }
```

- `Query`関数で列ごとに取得してきたデータをこの関数でマッピングする
    - カラムを変数へ読み込んでいる

## `log.Fatal()`でエラーメッセージとともにプログラムを終了させる

```golang:この部分
for rows.Next() {
        var id int
        var last_name string
        var email string
        if err := rows.Scan(&id, &last_name, &email); err != nil {
            log.Fatal(err)
        }
```

- 詳しい説明は[この記事](https://waman.hatenablog.com/entry/2017/09/29/011614)を参照してみてください。
- ログメッセージを出力した後、os.Exit(1)を呼び出してプログラムを終了させるそうな


# さいごに

ながながと書いてしまいましたが、最期までありがとうございました。
また、何か間違い等あればツッコミ頂ければ幸いです！
Google Chromeだけでリモートデスクトップする

Google Chromeを使ってリモートデスクトップをする方法を紹介します。
#リモートデスクトップとは
離れた場所にあるPC（ホスト）を別のPC（ゲスト）から遠隔操作する技術
Winodwsなどでは標準機能として備わっていますが、ルーターの設定などが必要です。
#Chrome Remote Desktop
Googleのサーバーを経由して、リモートデスクトップを行える機能
え？セキュリティ大丈夫なの？って思いますが、
・同じGoogleアカウントにログイン
・ホストで設定した6桁以上のPINGコードを知っている
ことがリモート接続できる条件となるので、
ホスト設定したらセキュリティガバガバ！なんてことはないと思います。
#設定方法
##ホスト
 - まず、遠隔操作したいPC側（ホスト）で、[Chromeリモートデスクトップ](https://chrome.google.com/webstore/detail/chrome-remote-desktop/gbchcmhmhahfdphkhkmpfmihenigjmpp?hl=ja)の拡張機能をインストール
 - 次に、[https://remotedesktop.google.com/access/](https://remotedesktop.google.com/access/)にアクセスして、Chrome Remote Desktop Hostのクライアントソフトをインストール
 - インストールを完了後、ホストPC名とPINコードを設定
 - Chromeにアクセス権限付与が必要あれば与える
 
##ゲスト
 - 実際に操作するPC側（ゲスト）は、同じGoogleアカウントにログインする
 - [https://remotedesktop.google.com/access](https://remotedesktop.google.com/access)にアクセス
 - 設定時に決めたPC名をクリックするとリモートデスクトップが開始できる

#まとめ
簡単にリモデできる時代になりました。
犬でもわかる入門Rustのライフサイクル

## はじめに
これはRustのライフサイクルを犬でもわかるように纏めてみる試みである

## ライフサイクルとは
全ての変数にはライフサイクルがある
これは以下のようなダングリング参照を防ぐ為にある
これを防ぐと何が嬉しいかと言うと、解放済みオブジェクトに対してアクセスしてパニックになるような自体等を防げる

```rust
{
  let r;                // ---------+-- 'a
                        //          |
  {                     //          |
    let x = 5;          // -+-- 'b  |
    r = &x;             //  |       |
  }                     // -+       |
                        //          |
  println!("r: {}", r); //          |
}                       // ---------+
```

このコードがなんでいけないかというと、xの参照をrに入れているけど、xのライフタイムはlet xされたブロックの中だけである。
なので、rにxの参照を入れられてしまうと、printlnのタイミングで、解放済みのxへ参照をしようとしてランタイムエラーになる。
そのような事を防ぐために、ライフタイムという仕組みはある。

※ ちなみにライフタイムの仕組みによってそもそもこのコードはコンパイルエラーになる

## ライフタイム解説

ドキュメントにはこう書かれている。

> コンパイラはライフタイムに3つの規則しかない。

> コンパイラは3つの規則を活用し、明示的な注釈がない時に、参照がどんなライフタイムになるかを計算します。 最初の規則は入力ライフタイムに適用され、2番目と3番目の規則は出力ライフタイムに適用されます。 コンパイラが3つの規則の最後まで到達し、それでもライフタイムを割り出せない参照があったら、 コンパイラはエラーで停止します。

> 最初の規則は、参照である各引数は、独自のライフタイム引数を得るというものです。換言すれば、 1引数の関数は、1つのライフタイム引数を得るということです: fn foo<'a>(x: &'a i32); 2つ引数のある関数は、2つの個別のライフタイム引数を得ます: fn foo<'a, 'b>(x: &'a i32, y: &'b i32); 以下同様。

> 2番目の規則は、1つだけ入力ライフタイム引数があるなら、そのライフタイムが全ての出力ライフタイム引数に代入されるというものです: fn foo<'a>(x: &'a i32) -> &'a i32。

> 3番目の規則は、複数の入力ライフタイム引数があるけれども、メソッドなのでそのうちの一つが&selfや&mut selfだったら、 selfのライフタイムが全出力ライフタイム引数に代入されるというものです。 この3番目の規則により、必要なシンボルの数が減るので、メソッドが遥かに読み書きしやすくなります。


## ライフタイムの例

1つ目の規則の例が以下のコードだ。

```rust
fn first_word(s: &str) -> &str {
    let bytes = s.as_bytes();

    for (i, &item) in bytes.iter().enumerate() {
        if item == b' ' {
            return &s[0..i];
        }
    }

    &s[..]
}
```

これは返り値が受け取った引数と同じなのが明白だ。
これは以下のコードと等価である。

```rust
fn first_word<'a>(s: &'a str) -> &'a str {
    let bytes = s.as_bytes();

    for (i, &item) in bytes.iter().enumerate() {
        if item == b' ' {
            return &s[0..i];
        }
    }

    &s[..]
}
```

> この関数がライフタイム注釈なしでコンパイルできた理由は、歴史的なものです: 昔のバージョンのRust(1.0以前)では、 全参照に明示的なライフタイムが必要だったので、このコードはコンパイルできませんでした。 その頃、関数シグニチャはこのように記述されていたのです:

2つ目の規則の例がこれだ。

```rust
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
  if x.len() > y.len() {
      x
  } else {
      y
  }
}
```

これは、先程みたいにこうライフタイム注釈を省略して書けない。

```rust
fn longest(x: &str, y: &str) -> &str {
  if x.len() > y.len() {
      x
  } else {
      y
  }
}
```

この関数の戻り値のライフタイムはx、yどちらのライフタイムになるのでしょうか？
わかりません。
なので、明示的に同じライフサイクル注釈を使うことにより、xとyのうち、短い方のライフタイムに依存するようになります。

なので、以下のコードはコンパイルエラーになります

```rust
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
  if x.len() > y.len() {
      x
  } else {
      y
  }
}

fn main() {
  let a = String::from("hello world");
  let result;

  {
    let b = String::from("bye");
    result = longest(&a, &b);
  }

  println!("{}", result);
}
```

3つ目の規則は省略する。
selfに依存するのは、まぁどの言語もそうだし当たり前だよね。

## 参考リンク
* https://doc.rust-jp.rs/book/second-edition/ch10-03-lifetime-syntax.html
browserifyとdeamdifyをつかってjQuery UIをバンドルする


# 背景
[jQuery UI](https://jqueryui.com/)を使っているJavaScriptアプリケーションを[browserify](http://browserify.org/)をつかってバンドルにしたいことがあります。今どきありえないとは思うかもしれませんが、まれにあります。
jQuery UIは[npmパッケージ](https://www.npmjs.com/package/jquery-ui)をAMDモジュール形式で配布しています。

注意：jQuery UIの最新バージョンは２０１６年９月にリリースされました。新規の開発に使うのはオススメしません。

# 問題

browserifyはAMDモジュールそのものをバンドルすることはできますが、モジュールが依存するモジュールを解決できません。つまり次のように書くだけではjQuery UIのダイアログは使えません。

```js
require('jquery-ui/ui/widgets/dialog')
```


次のように依存するすべてのモジュールを列挙する必要があります。

```js
require('jquery-ui/ui/version')
require('jquery-ui/ui/data')
require('jquery-ui/ui/plugin')
require('jquery-ui/ui/unique-id')
require('jquery-ui/ui/tabbable')
require('jquery-ui/ui/focusable')
require('jquery-ui/ui/safe-blur')
require('jquery-ui/ui/keycode')
require('jquery-ui/ui/safe-active-element')
require('jquery-ui/ui/widget')
require('jquery-ui/ui/widgets/mouse')
require('jquery-ui/ui/widgets/button')
require('jquery-ui/ui/widgets/resizable')
require('jquery-ui/ui/widgets/draggable')
require('jquery-ui/ui/widgets/dialog')
```

実はこれで全部ではありません。しかも不足しているモジュールは実行するまでわかりません。

# 解法

[deamdify](https://github.com/jaredhanson/deamdify)というトランスフォームモジュールをつかいます。
deamdifyはその名の通り（？）AMDモジュールをNodeモジュールに変換します。
Nodeモジュールになってしまえばbrowserifyが依存関係を解決してくれます。

たとえば次のように`deamdify`を`global-transform`として指定します。

```sh
browserify -g deamdify index.js -o bundle.js
```

`deamdify`のREADMEでは

```
browserify -t deamdify main.js -o bundle.js
```

と書かれていますが、`-t`ではうまくいきませんでした。トランスフォームモジュールを指定しないときと同じように実行時にモジュールの不足が判明します。
代わりに`-g`を指定すると、期待通りに依存モジュールの取り込みに成功します。

## `-g`の謎

`-t`の代わりに`-g`を指定する必要があるのが、`jQuery UI`との組み合わせ問題か、`deamdify`のREADMEの問題かははわかりませんでした。
私は次のサンプルコードから、`-g`オプションの指定方法を発見しました。

https://github.com/au-phiware/deamdify-sample/blob/master/package.json#L8

> "prepublish": "browserify -g deamdify . > bundle.js"


# 参考情報

- [JavaScriptのモジュール管理(CommonJSとかAMDとかBrowserifyとかwebpack) | tsuchikazu blog](https://tsuchikazu.net/javascript-module/)
とりあえず覚えとけ git bash

## とりあえず覚えとけ

コマンドのコピペ用にメモ作っとこうな。
※TortoiseGitからコピペしたやつ。

```
【リポジトリへ移動】
cd フルパス

【フェッチ depth 10】※状況に応じて階層変えてください。depth 20とか。
git.exe fetch -v --progress --depth 10 "origin"

【プル depth 10】※フェッチした階層と同じにしような
git.exe pull --progress -v --no-rebase --depth 10 "origin"

【ローカルでの編集を全てなかったことにする】
git checkout .
```

---
以下、手打ちでやる場合の基本

---

git bashで作業するディレクトリに移動するじゃん

・まずはブランチの確認(ローカル)

```
git branch
```

・リモートのブランチが見たかったら

```
git branch -r
```

・全部見たかったら

```
git branch -a
```

・とりあえず確認。こまったらとりまこれ

```
git status
```

・修正ファイルをドラッグして選択すればコピー
・ステージング

```
git add 追加ファイルの絶対パスをShift+insertでペースト
```

・コミット

```
git commit -m コミットメッセージ
```

・プッシュ

```
git push originから始まるリモートのブランチ名
```

・プル

```
git pull
```

・フェッチ

```
git fetch
```

・コミットを一つにまとめて見やすくしたい→TortoisGitでログを表示
　→コミットを複数選択して、右クリックから、コミットを一つに集約

・ローカルブランチの削除

```
git branch -D ブランチ名
```

・リモートブランチの削除

```
git push --delete リモートブランチ名
```

・ローカルでの作業ブランチをかえる
　いまaブランチにいて、bに変えたかったら

```
git checkout 変えたいブランチb
```

・今リモートブランチaをローカルブランチaとして作業してて
　リモートブランチbを、ローカルに持ってきてbって名前にして
　ローカルブランチbに切り替えたいとき

```
git checkout -b ローカルブランチの名前を付ける　リモートブランチ名
```

・マージorリベース

```
git merge もしくはrebase
```

・コンフリクトを解消

```
git statusでコンフリクト箇所を見て
vim ファイル名　で開いて編集
改修して保存して閉じたら
git add ファイル名　でステージング
で
git rebase --continue
git merge --continue
どっちかで続けていく
コンフリクト全部解消したら強制プッシュ
git push -f リモートブランチ名
```


## 奥義
とても良い記事がありますので記載させていただきます
[Gitでやらかした時に使える19の奥義](https://qiita.com/muran001/items/dea2bbbaea1260098051)
[決算]1株当たり利益(EPS)を計算する機能を設計 & 実装してみた

# 1株当たり利益(EPS:Earnings Per Share)の計算方法

```
EPS（円） ＝ 当期純利益 ÷ 発行済株式数
```

# こうなった

生のデータや計算ロジックを外部に晒さないように気をつけて実装してみた

## 数値の基底クラス

```ruby:numerical_value.rb
require 'bigdecimal'

class NumericalValue
  # @param [BigDecimal, Integer] value
  def initialize(value)
    @value = value
    raise TypeError, '値をセットしてください' if @value.nil? # 値必須ということにするのでチェック

    post_initialize(@value) # 継承先での実装を強制し必要に応じてチェックを行う
  end

  # 計算に使う
  # 新しいオブジェクトを返すので@valueが変わってしまう心配は無い
  def to_d
    BigDecimal(@value.to_s)
  end
end
```

## 当期純利益クラス

```ruby:net_income.rb
class NetIncome < NumericalValue
  # @param [Integer] value (単位:百万円)
  def post_initialize(value)
    raise TypeError, '当期純利益を指定してください' if value.nil?
  end

  # EPSを計算して返す
  # @param [OutstandingShares] outstanding_shares
  def eps(outstanding_shares)
    raise TypeError, 'OutstandingSharesを指定してください' unless outstanding_shares.kind_of?(OutstandingShares)

    eps = to_d * 1_000_000 / outstanding_shares.to_d
    EPS.new(eps)
  end
end
```

## 発行済み株数

```ruby:outstanding_shares.rb
class OutstandingShares < NumericalValue
  # @param [Integer] value (単位:株)
  def post_initialize(value)
    raise TypeError, '発行済み株数は1以上で指定してください' unless value.positive?
  end
end
```

## 一株当たり純利益

```ruby:eps.rb
class EPS < NumericalValue
  # @param [BigDecimal] value (単位:円)
  def post_initialize(value)
    # 特に無し
  end
end
```

## テストコード

```ruby:net_income_spec.rb
require 'spec_helper'

RSpec.describe NetIncome do
  describe 'EPSを計算' do
    before do
      net_income = described_class.new(net_income_value)
      outstanding_shares = OutstandingShares.new(outstanding_shares_value)
      @eps = net_income.eps(outstanding_shares)
    end

    context '純資産がプラスの場合(Softbank:9984)' do
      let(:net_income_value) { 1_411_199 }
      let(:outstanding_shares_value) { 1_100_660_365 }
      it { expect(@eps.to_d).to be_within(0.01).of(1282.13) }
    end

    context '純資産がマイナスの場合(住石HD:1514)' do
      let(:net_income_value) { -3806 }
      let(:outstanding_shares_value) { 76_629_000 }
      it { expect(@eps.to_d).to be_within(0.01).of(-49.66) }
    end

    context '純資産が0の場合(新内外綿:3125)' do
      let(:net_income_value) { 0 }
      let(:outstanding_shares_value) { 1_955_569 }
      it { expect(@eps.to_d).to be_zero }
    end
  end

  describe 'EPSを計算(想定外)' do
    context '発行済み株式数オブジェクトでない場合' do
      before do
        @net_income = described_class.new(1)
        @dummy_outstanding_shares = BigDecimal('1')
      end

      it { expect { @net_income.eps(@dummy_outstanding_shares) }.to raise_error(TypeError) }
    end
  end
end
```

## 感想

まだそんなにメリットを感じてない、がIntegerやBigDecimalをそのまま扱うよりははるかにマシだとは思う

## 環境

Ruby 2.7.0-dev

## 補足

- 今回initialize時に下限のチェックだけ書いたが本来は上限も設定すべき
loopback4でREST APIをつくろうとしたが、今nestでGraphQLサーバをつくってる

タイトル、意味が通っているか心配。
GraphQL APIっていう言い方しないのだろうか。。。

# 要約
ここ１か月、外部とサーバ間連携するweb apiを作っている

最初restでいいかと思っていたが、レスポンスの項目は必要に応じて
取得したりしなかったりしたいという要望のためGraphQLで作ることに

そのため最初loopback4(日本語版のExpressのサイトに載っていたから)で作っていて、
GraphQLに変換しようと思ったけど、つらかったのでやめました。

それで今nestjsで作りなおしてます。

# loopback4でGraphQLは何がつらい？
- まずoasで考えてから、GraphQLに変換しないといけない

# nestjsは何がいい？
- 他のライブラリ（モジュール？）と簡単につなげられる。
  - apollo, prisma
plunkerでtensorflow.js その３

#概要

plunkerでtensorflow.jsやってみた。
xorやってみた。
tf.variableで書いてみた。

#サンプルコード


```
const xt = tf.tensor2d([[1, 0], [0, 1], [1, 1], [0, 0]], [4, 2]);
const yt = tf.tensor2d([[1], [1], [0], [0]], [4, 1]);
function func(x) {
	const h = tf.tanh(x.matMul(w1).add(b1));
  return tf.sigmoid(h.matMul(w2).add(b2));
}
function loss(pred, label) {
	return tf.losses.meanSquaredError(pred, label).mean();
}
const w1 = tf.variable(tf.randomNormal([2, 8]));
const b1 = tf.variable(tf.zeros([8]));
const w2 = tf.variable(tf.randomNormal([8, 1]));
const b2 = tf.variable(tf.zeros([1]));
const opti = tf.train.adam(0.01);
let cost = 0;
for (let i = 0; i < 1000; i++)
{
	cost = opti.minimize(() => loss(func(xt), yt), true);
}
let str = "loss = ";
str += cost; 
str += "<br><br>1, 0 = ";
let pre = func(xt);
pre = pre.dataSync();
str += pre[0] + "<br>0, 1 = ";
str += pre[1]+ "<br>1, 1 = ";
str += pre[2] + "<br>0, 0 = ";
str += pre[3] + "<br>";
document.write(str);

```

#成果物

https://embed.plnkr.co/H1wIXtxstRuE7BcI1D3p/

以上。
ActiveDirectoryのグループポリシーから「レジストリの追加設定」を削除する

# いきさつ

Windows 10の更新に合わせてADMXファイルを律儀に最新版にアップデートしていたら、気づいたらグループポリシーオブジェクトエディターに「レジストリの追加設定」という項目が増えていた。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197772/099f13b1-d7a0-edb4-0baa-1544209851ca.png)

要はADMXを更新したことで、古いポリシーのテンプレート部分が消えてしまった。
今ある環境には影響はないのだろうけど気持ち悪いし、今後追加するPCにとっては完全に要らないゴミデータが増えるだけなので、できれば消したい。

# Microsoft先生は・・・

「グループポリシー」「レジストリの追加設定」「削除」あたりをキーワードで検索すると、Microsoftのページがヒット。

https://support.microsoft.com/ja-jp/help/4015786/known-issues-managing-a-windows-10-group-policy-client-in-windows-serv
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197772/4ddbb7e0-24d6-1c73-35a7-5683f3deff7e.png)

> ***管理者はそれらの設定をオンにすることもオフにすることもできなくなります***

・・・無慈悲。

一応、古いADMXファイルがインストールされたマシンが他にあるなら、そのマシンから編集すれば良いらしい。
ただマシンも古いADMXファイルも用意できない。

その他、フォーラムには**「レジストリの追加設定以外同じ設定にした新しいGPOを作ってリンクすればいいよ」**という力技の提案もされていた・・・。

# 解決策

英語で調べて下記のページがヒット。
https://jocha.se/blog/tech/remove-orphaned-admx-gpo-values

PowerShellで解決できるとのことなので、上の画像中の「`Software\Policies\Microsoft\Windows\Skydrive\DisableFileSync`」を削除する場合は下記のようにする。

~~~PowerShell
PS > Remove-GPRegistryValue -Name "(GPOの名前)" -Key "HKLM\Software\Policies\Microsoft\Windows\Skydrive" -ValueName "DisableFileSync"


DisplayName      : (GPOの名前)
DomainName       : (ドメイン名)
Owner            : (ドメイン名)\Domain Admins
Id               : b2c365f8-9e30-461c-abbc-6c0607b002f7
GpoStatus        : AllSettingsEnabled
Description      : 
CreationTime     : 2015/06/25 18:30:11
ModificationTime : 2019/09/04 12:52:26
UserVersion      : AD Version: 0, SysVol Version: 0
ComputerVersion  : AD Version: 705, SysVol Version: 705
WmiFilter        : 
~~~

注意点としては次の2点。
* `-Key`の先頭には`HKLM`(コンピュータの構成)か`HKCU`(ユーザーの構成)をつける
* `-Key`の最後に`\`は不要(空白扱いとなって、「そんな名前のキーは無いよ」と怒られる)

上手くいったら、グループポリシーの設定を確認。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197772/f24fb53b-b5ab-7e99-64a5-1b30168fb0b0.png)

**消えた！！**

めでたしめでたし。
plunkerでtensorflow.js その２


#概要

plunkerでtensorflow.jsやってみた。
xorやってみた。
tf.modelで書いてみた。

#サンプルコード

```
const xs = tf.tensor2d([[1, 0], [0, 1], [1, 1], [0, 0]], [4, 2]);
const ys = tf.tensor2d([[1], [1], [0], [0]], [4, 1]);
const input = tf.input({
  shape: [2]
});
const layer1 = tf.layers.dense({
  units: 8, 
  activation: 'tanh'
});
const layer2 = tf.layers.dense({
  units: 1, 
  activation: 'sigmoid'
});
const output = layer2.apply(layer1.apply(input));
const model = tf.model({
  inputs: input, 
  outputs: output
});
const opti = tf.train.adam(0.01);
model.compile({
  optimizer: opti,
  loss: 'meanSquaredError'
});  
model.fit(xs, ys, {
  batchSize: 4,
  epochs: 1000,
}).then((d) => {
  var str = "loss = ";
  str += d.history.loss[0]; 
  str += "<br><br>1, 1 = ";
  var pre0 = model.predict(tf.tensor2d([1, 1], [1, 2]));
  str += pre0.dataSync() + "<br>0, 0 = ";
  var pre1 = model.predict(tf.tensor2d([0, 0], [1, 2]));
  str += pre1.dataSync() + "<br>0, 1 = ";
  var pre2 = model.predict(tf.tensor2d([0, 1], [1, 2]));
  str += pre2.dataSync() + "<br>1, 0 = ";
  var pre3 = model.predict(tf.tensor2d([1, 0], [1, 2]));
  str += pre3.dataSync() + "<br>";
  document.write(str);
});


```

#成果物

https://embed.plnkr.co/vGAxHwfaaPRx2dIgDrSh/


以上。
plunkerでtensorflow.js

#概要

plunkerでtensorflow.jsやってみた。
xorやってみた。
tf.sequentialで書いてみた。


#サンプルコード


```
const xs = tf.tensor2d([[1, 0], [0, 1], [1, 1], [0, 0]], [4, 2]);
const ys = tf.tensor2d([[1], [1], [0], [0]], [4, 1]);
const model = tf.sequential();
model.add(tf.layers.dense({
  units: 8,
  activation: 'tanh',
  inputShape: [2]
}));
model.add(tf.layers.dense({
  units: 1,
  activation: 'sigmoid'
}));　
model.compile({
  optimizer: 'Adam',
  loss: 'meanSquaredError',
});
model.fit(xs, ys, {
  batchSize: 4, 
  epochs: 1000
}).then((d) => {
  var str = "loss = ";
  str += d.history.loss[0]; 
  str += "<br><br>1, 1 = ";
  var pre0 = model.predict(tf.tensor2d([1, 1], [1, 2]));
  str += pre0.dataSync() + "<br>0, 0 = ";
  var pre1 = model.predict(tf.tensor2d([0, 0], [1, 2]));
  str += pre1.dataSync() + "<br>0, 1 = ";
  var pre2 = model.predict(tf.tensor2d([0, 1], [1, 2]));
  str += pre2.dataSync() + "<br>1, 0 = ";
  var pre3 = model.predict(tf.tensor2d([1, 0], [1, 2]));
  str += pre3.dataSync() + "<br>";
  document.write(str);
});
```

#成果物

https://embed.plnkr.co/BUWC5GGmtbnEI9Wdhd2L/

以上。
メモ：iCalendarのDESCRIPTIONで改行する

iCalendar(RFC 5545)のDESCRIPTIONは、文字列`\n`、printf的に言えば`"\\n"`によって改行される(RFC 5545 3.8.1.5による)。

RFC 5545 3.1によれば、1行の文字数は75文字以下にする必要がある。その際は任意の位置でCRLF+空白(`"\r\n "` or `"\r\n\t"`)で分割する。また、空白が複数回連続する場合(`"\r\n\t\t"`等)は、1つ目の空白が内部的な改行コードとして扱われ、以降の空白文字は文章の空白として処理される。
ripple-libでXRPを送金する

# 更新
- [xpring-jsで送る場合](https://qiita.com/yuki777/items/4998013fb4ad8608075e)

# XRPを送りたい
- プログラムからXRPを送金するには[ripple-lib](https://www.npmjs.com/package/ripple-lib)を使う
- サンプル、ドキュメントはここ
 - https://xrpl.org/send-xrp.html#interactive-check
 - https://xrpl.org/get-started-with-rippleapi-for-javascript.html#waiting-for-validation
- 手順は下記の通り
 - api.connect()
 - api.prepareTransaction()
 - api.sign()
 - api.submit()

# ソース
- 詳細は https://github.com/yuki777/send-xrp

```javascript

api.connect().then(() => {
  const preparedTx = await api.prepareTransaction({
    "TransactionType": "Payment",
    "Account": sender,
    "Amount": api.xrpToDrops(amount),
    "Destination": destination,
  }, {
    // Expire this transaction if it doesn't execute within ~5 minutes:
    "maxLedgerVersionOffset": 75
  })
  const maxLedgerVersion = preparedTx.instructions.maxLedgerVersion
  return preparedTx.txJSON
}).then(txJSON => {
  const response = api.sign(txJSON, secret)
  const txID = response.id
  const txBlob = response.signedTransaction
  return txBlob;
}).then(txBlob => {
  const latestLedgerVersion = await api.getLedgerVersion()
  const result = await api.submit(txBlob)
  return latestLedgerVersion + 1
}).then((earliestLedgerVersion) => {
  return api.disconnect();
}).then(() => {
  process.exit();
}).catch(console.error);
```
Azure Blockchain Serviceを試してみる4（コンソーシアム管理編）

# はじめに
[前回の記事](https://qiita.com/hayago/items/211f62ffbe7be5196bf1)では、構築したチェーンにブロックチェーンエクスプローラの導入を行いました。今回の記事では、コンソーシアムへのメンバの追加、削除といったコンソーシアム管理機能を試してみます。

# コンソーシアムにメンバを招待する
コンソーシアムのメンバ管理は、Azureのポータルからは行うことができず、PowerShellを使ってコマンドラインで行う必要があります（2019/9/4時点）。

PowerShellを起動して、以下の流れで招待を行います。

### Web3の接続確立

```
$Connection = New-Web3Connection -RemoteRPCEndpoint 'トランザクションノードが提供するエンドポイントURL'
$MemberAccount = Import-Web3Account -ManagedAccountAddress 'メンバアカウントのアドレス' -ManagedAccountPassword 'メンバアカウントに設定したパスワード'
$ContractConnection = Import-ConsortiumManagementContracts -RootContractAddress 'ルートコントラクトのアドレス' -Web3Client $Connection
```

### メンバの招待

```
$ContractConnection | New-BlockchainMemberInvitation -SubscriptionId '招待するメンバのサブスクリプションID' -Role USER -Web3Account $MemberAccount
```

招待が完了すると、ポータルのコンソーシアムメンバ一覧にステータスがInvitedのサブスクリプションIDが追加されます。
<img width="600" alt="スクリーンショット 2019-09-04 13.03.11.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16354/716c89f7-3b1f-afdd-93f7-e2af712fee15.png">

# コンソーシアムに参加する
招待されたコンソーシアムへの参加はメンバ作成画面から行います。コンソーシアムの選択欄で、招待されたコンソーシアムを選択します。
<img width="600" alt="スクリーンショット 2019-09-04 19.30.25.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16354/4fb09c9e-d422-c569-3638-e7998a21c77f.png">
必要情報を入力し、「Review + create」をクリックしてデプロイを行います。
デプロイを終えるとノードの同期が行われ、ブロックがノードに追加されます。
<img width="600" alt="スクリーンショット 2019-09-04 20.20.45.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16354/55553474-6151-d7ad-0c6f-50f0453a4f00.png">

# コンソーシアムからメンバを削除する

```
$ContractConnection | Remove-BlockchainMember -Name '削除するメンバ名' -Web3Account $MemberAccount
```
メンバを削除すると、ポータル上で該当メンバのアカウントアドレスが0x0に変わっている事が確認できます。

# おわりに
今回の記事では、コンソーシアム管理機能を使ってメンバの追加や削除を行いました。[次回の記事](https://qiita.com/hayago/items/d136f1e2d93ad1f51108)では、コンソーシアムの複数メンバ間におけるプライバシー関連の機能を試します。
Docusaurus2 がやってくる

Facebook 製のドキュメントサイト ジェネレータである [Docusaurus](https://docusaurus.io/) のバージョン2 (以下、Docusaurus2) が現在開発中のようです。（ [GitHubのissue](https://github.com/facebook/docusaurus/issues/789) ）

公式ドキュメント: https://v2.docusaurus.io/

詳細な内容は上記ドキュメントを見ていただくとして、個人的に嬉しい点は次の3点です。

1. MDX がかけるようになる
2. 必要なディレクトリが1つになる
3. docs 内にサブディレクトリを作成可能になる

以下で詳細に述べます

## 1. [MDX](https://mdxjs.com/) がかけるようになる

Markdown ファイルにJSX(React)が書けるようになります。これにより Markdown の書きやすさを保ちつつ、こだわって装飾したい箇所については柔軟に書きやすくなると思います。
ちなみに、Docusaurus2 ではプラグインシステムが導入されますが、MDXは追加プラグインは不要で、標準機能として使えます。

## 2. 必要なディレクトリが1つになる

Docusaurus1 ではプロジェクトディレクトリ内に `docs` と `website` の2ディレクトリがあって、好きではなかったのですが、 Docusaurus2 では `website` (名称は任意)の1ディレクトリだけとなり、スッキリしました。

```:Docusaurus1の構成
project
  ├── docs
  └── website
      ├── blog
```
↓

```:Docusaurus2の構成
project
  └── website
      ├── blog
      ├── docs
```

## 3. docs 内にサブディレクトリを作成可能になる

これが1番嬉しいポイントです。Docusaurus1 では `docs` 内にサブディレクトリを作ることができず、ファイルがフラットに羅列されていましたが Docusaurus2 ではサブディレクトリを作ることができ、ファイルのグループ化・階層化が行えます。
ただし、記事作成時点では公式ドキュメントにはそのような記述を見つけられず、正式にサポートされるのか、現在たまたまそのような挙動をしている（将来的に保証されない）のかは分かりません。
私も色々試していて偶然見つけただけです。

以下のような感じになります。

```md:website/docs/foo/hoge.md
---
id: hoge
title: ほげ
---

text
```

```md:website/docs/foo/fuga.md
---
id: fuga
title: ふが
---

text
```


```js:website/docusaurus.config.js
module.exports = {
  ...,
  themeConfig: {
    navbar: {
      links: [
        { label: "ほげ", to: "docs/foo/hoge", position: 'left'},
      ],
    },
    ...,
  },
  ...,
}
```

```js:website/sidebars.js
module.exports = {
  "docs": {
    "foo": ["foo/hoge", "foo/fuga"],
  },
};
```

`docs/` が必要だったり、不要だったりで気付くのに苦労しました。

# おまけ

scaffolded ツールは Docusaurus2 から scope 付き (@docusaurus/init) になっており、Docusaurus1 (docusaurus-init) とは棲み分けているようです。
これにより、Docusaurus2は記事作成時点ではまだアルファバージョンですが、あまり意識せずとも使用できます。（よくあるような バージョンタグを指定したり `@next` のようなエイリアスを指定する必要がない ）
単一障害点(SPOF)の作り方 その1

単一障害点(SPOF)の作り方を書いていきます。
システムに脆弱な部分を作りたい時には、これらの構成を参考にしていただければと思います。

書き出したら思った以上にあったので、今回はサーバ構成編、物理編のみにしたいと思います。

#サーバ構成編
インフラエンジニア向けです。
AWSやGCP等のクラウドサーバでも構成可能なものを記載しています。

##Webサーバを1台構成にする
よくある1台サーバ構成というやつ。
このWebサーバが落ちると、その配下にあるアプリケーションサーバへのアクセスも出来なくなるので、代表的なSPOFとして取り上げられます。

##Web、 AP, DB, Batchを1台のサーバにまとめる
こちらもよくある代表的な構成。
社内の誰かが作った自作アプリとかが置いてあるサーバによくある構成です。

##メモリを必要最低限だけ積む
メモリ不足にさせoom-killerを発生させることで、サーバのアプリケーションを殺します。
サービスを提供しているプロセスが落ちることでサービスを提供できなくなり、サーバの可用性を下げます。
LB配下にいくつかのWebAPサーバがいる場合、同じスペックと考えることができるので、全サーバで同じような現象が発生し、サービスの提供が難しくなります。

##Kubernetesのクラスターノードを1台にする
何がしたいのかがわからない構成ですが、Twitterとかでつぶやいている人がいたので記載しました。
GKEとかだとデフォルトでクラスターノード(ホストサーバ)は3台になるので、SPOFにしたい人向けではありません。

##静的ウェブホスティングを使用しない
AWSのS3やGCPのCloudStorageを使いオブジェクトストレージで静的ウェブホスティングが構成可能です。
これらはクラウドベンダー側がマネージドサービスとして実施しているため、基本的に落ちることがありません。
そのためSPOFという点でいうと、一番遠い位置にいるので実施しないでください。

##CDNは絶対に挟まない
LBの前にCDNを挟むことにより、WebAPサーバへの負荷が大幅に軽減されるため、望ましくありません。


#物理編
インフラエンジニア向けです。
データセンターに出入りする方や、社内にサーバルームがある方は必見です。

##サーバの電力を1箇所から取る
基本的にサーバには電源ケーブルが2箇所あります。
安定した電源供給を目的としているのですが、その電源ケーブルを同じ主電源から取るのがSPOFとしてのポイントです。
サーバの機種によると思いますが、電源2本中、1本あればサーバは稼働し続けられます。(電源電圧が正常なことが前提)
そのためどちらか片方から取ることで電源冗長化の意味を失わせることができるのです。

##サーバと同じ主電源を利用する
いわゆる同じ主電源からタコ足で片方をサーバ、片方をあなたのノートPCやプリンターに繋ぐ、という構成です。
主電源が同じ場合、クライアントが使う電源量にサーバの供給電力が左右されます。
通常ある一定基準の電圧を下回ると精密機器に悪影響を及ぼすと言われています。サーバ等の機器は起動時に通常の3倍程度の電力を消費すると言われているため、サーバとクライアントの電源供給元が同じ場合、この症状が起きる可能性があり、隠れSPOFとして実装することができます。
多くの場合、これらは忘れた頃に発生するため、気づきにくいです。


##自家発電設備の無いデータセンターを選ぶ
いまから物理DCを選ぶ方向けですが、ほぼ全てのデータセンターは数時間〜数日DC自体の電力を賄う自家発電設備があります。
こちらの設備がないDCを選ぶことで、停電時DCのサーバ群を電源断に追い込むことが可能になります。
また急な電力消失によるシャットダウンはデータ消失に繋がる可能性が高いため、SPOFとしておすすめです。

##UPSを使用しない
上記の自家発電設備の無いデータセンターと同じような内容ですが、UPSによりサーバに供給する電力の整形と予備バッテリーとしての役割を果たします。上位のUPSについては電源断時、自動的に接続先サーバへシャットダウンコマンドを送り、サーバを正常シャットダウンさせるものも存在します。
電源断したらアウトという意味ではSPOFですが、UPSを挟まないことで停電による機器の破壊が可能になります。

##サーバとのネットワーク接続を100均のLANケーブルで行う
LANケーブルのクロスケーブルとストレートケーブルが間違っていない前提ですが、100均のLANケーブルは業務用に比べると質が悪いです。(CAT5eなど)
SPOFまでなることは少ないですが、低品質なネットワークを提供してくれます。

##サーバルームの温度管理をしない
最近AWSの東京リージョンであったインシデントですが、サーバルームの温度管理をしないとサーバの温度が上昇し、ある一定以上の温度に到達するとサーバの自己防衛機能により、自動的にシャットダウンされます。
通常はデータセンター内はちょっと肌寒いレベルの室温になっています。

##ストレージはそのまま使う(RAIDを組まない)
データセンターの運用を使用している方は知っていると思いますが、月1-2本の速度でサーバのストレージは故障します。サーバでは複数のハードディスクが壊れてもデータが消失しないような構成をすることが多いです。その代表的なものとしてRAIDがあります。
市販のNASでもデータ消失を避けたいものはRAIDが組まれていますが、それを組まないのはとても良質なSPOFになります。
3-4年持てば良い方だと思われます。


この記事を書いていると、次から次へと思いつくので、今回はここまでにします。
【IntelliJ IDEA】 Database tool windowの色を環境ごとに変えてみる

IntelliJ IDEAのDatabase tool windowを普段からよく使っているのですが、本番環境のDBを参照しているつもりが、気づいたら開発環境のDBだったというケースがたびたび発生していて困っていました。

そんな中、IntelliJのドキュメントを読んでいると、Database tool windowの表示する色をDBごとに変えられるらしい！ということを知ったので、試してみます。

## 前提
- IntelliJ IDEA 2019.2.1 ULTIMATE EDITION

## 手順
色を変えたいDBを選択 → 右クリック → Color Settings...を右クリック
![スクリーンショット 2019-09-04 19.50.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/160829/3f51e0c5-ba6c-0ec7-75f9-9b3d5f211e23.png)

Colorから好きな色を選択。デフォルトでテーマに沿った色が表示されます。
また、Appearance Settingsでどこの色を変えるかが変更できます。
![スクリーンショット 2019-09-04 19.51.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/160829/3f23e1c3-f07f-8b90-3bd9-3980f870d1b9.png)

ちなみに、Customを押すとRGB値やColor Wheelで色を変更できたり、明度を調節できるなど、より柔軟に色を変更することができます。
![スクリーンショット 2019-09-04 19.52.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/160829/8d672ab1-83a0-3cd1-e549-2cb0fee5d2ec.png)

Chooseを選択すると、色の変更ができます。以下はdevをGreenに、prodをRoseに、testをBlueに変更した例です。
![スクリーンショット 2019-09-04 19.55.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/160829/97b4e121-53a5-19cf-2072-1436f2bd1e73.png)

今回の例では、prodを選択すると、console画面のツールバーの色が赤く表示され、
![スクリーンショット 2019-09-04 19.55.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/160829/bd7f5196-c9e6-74f1-4bb1-c97106a47bc7.png)

devを選択するとツールバーが緑色に表示されます。
![スクリーンショット 2019-09-04 19.55.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/160829/279dbd93-0912-5268-d0b3-f87119645df3.png)

## 参考
https://www.jetbrains.com/help/idea/database-tool-window.html
【GCP】CloudBuildトリガーをgcloudコマンドで実行させる

# 概要
GCPのCloudBuildに設定したトリガーをgcloudコマンドだけで実行する手順を紹介します。

## 対象読者
- [ ]  GCPを触ったことがある
- [ ]  CI/CDに興味がある、または実践している
- [ ]  CloudBuildを活用している
- [ ]  CloudBuildのトリガーを任意のタイミングで叩きたい

## 前提
なんらかの方法で既に任意実行したいCloudBuildトリガーが設定されている必要があります。

## 注意点
下記の実行手順を見ていただければ分かりますが、 `gcloud alpha` コマンドを使用します。
これはGCP側の判断で突然コマンドの挙動が変更されたり、実行できなくなる可能性があるフェーズということです。
ですので本番環境などでワークフローに組み込む場合は十分注意した上で運用することをおすすめします。

## 実行手順
トリガーのIDを取得するために `list` を実行します。

```
$ gcloud alpha builds triggers list --project=[GCPプロジェクトID]
```

このようにトリガー情報が列挙されます。

```
createTime: '2019-01-01T01:00:00.9999999999Z'
description: ""
filename: cloudbuild.yaml
id: [トリガー固有のID]
name: [IDと同じ値]
substitutions:
  [環境変数のKey/Value]
triggerTemplate:
  projectId: [トリガーが設定されているGCPプロジェクトID]
  repoName: [トリガーが参照するリポジトリ名]
  tagName: [トリガーを走らせるための正規表現]
```

対象のトリガー情報からIDを抜き出します。

`id: [トリガー固有のID]`

`run` コマンドを実行します。

```
$ gcloud alpha builds triggers run [トリガー固有のID] --branch [ブランチ名] --project=[GCPプロジェクトID]
```

トリガーの実行が成功すると、トリガーを実行するためのキューを入れたことを表すメタデータが表示されます。

## まとめ
このようにAlphaであることを許容できれば実行することができます。
Betaに進むまではクリティカルな環境に適用するのは難しいかもしれませんが
CloudBuildトリガーでDataflow Jobをデプロイする、というような作り込みができていれば、オートリカバリの一手目として使えるかもしれません。

## 参考リンク
[Cloud SDK - gcloud alpha builds triggers run](https://cloud.google.com/sdk/gcloud/reference/alpha/builds/triggers/run)
Macで Read-only file systemとエラーが出て書き込みができない時の対処[フォーマットの変更]

# きっかけ
ローカルのデータをHDDに保存しようと思った時に、Read-only file systemとエラーが出て、コピーができなかった。

ネットで調べると、https://zaka-think.com/linux/linux-mint/%E3%80%90ubuntu%E3%80%91%E5%A4%96%E4%BB%98%E3%81%91%E3%83%8F%E3%83%BC%E3%83%89%E3%83%87%E3%82%A3%E3%82%B9%E3%82%AF%E3%81%8C%E8%AA%AD%E3%81%BF%E8%BE%BC%E3%81%BF%E5%B0%82%E7%94%A8%E3%81%AB%E3%81%AA/
この記事のように、ジャーナリングの問題や、前回のアンマウントが正常でなかったケースなどの対処策が多かった。

そのため、自分のケースでの原因がファイルフォーマットのエラーという単純なものであったことに気づくのが時間がかかってしまったので、メモ。


## MacのターミナルからのHDDへのアクセス
```
diskutil list # で今アクセスしたいものが何番のディスクかを確認する
mount # マウントする
$ mount
/dev/disk2s1 on / (apfs, local, journaled)
devfs on /dev (devfs, local, nobrowse)
/dev/disk2s4 on /private/var/vm (apfs, local, noexec, journaled, noatime, nobrowse)
map -hosts on /net (autofs, nosuid, automounted, nobrowse)
map auto_home on /home (autofs, automounted, nobrowse)
/dev/disk3s2 on /Volumes/HDPT-UT (ntfs, local, nodev, nosuid, read-only, noowners) 
# となり、どんな名前でフォルダができたか確認できるので
cd /Volumes/HDPT-UT #のように移動したいファイルに移動できる。
```

##　フォーマットの変更
### 現在のフォーマットの確認 
ファインダー -> 目的のHDD　を右クリック -> 情報をみる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253261/9b6647b6-4932-362e-4bb7-738bb7af5368.png)

一般情報のフォーマットから、フォーマットを確認
NTFS Windowsのみ
FAT32,exFAT　Windows,Mac両方OK
HFS+ Macのみ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253261/522ecc1a-86f0-cd22-37a6-b9c91da2dd80.png)

### フォーマットの変更
ファインダーから目的のHDDを選択した状態で、
上部のメニューから、 移動 -> ユーティリティ -> ディスクユーティリティを選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253261/1eaa9f58-e462-6d79-2bfa-f1530e5caa62.png)

目的のHDDを選び、上部の　パーティション作成　をクリック


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253261/ddb69cae-1f38-3194-7bf4-cb87b8b9204f.png)

自分のOSにあったフォーマットに変更して、適用をクリックしてフォーマットを実行する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253261/56ce986b-58c8-35c4-f0e0-f995ea5d08a2.png)

これで書き込みができるようになりました。
JavaアプリケーションのJMX監視を有効にしたらデプロイが稀にコケるようになった

# 事象

Datadog にJVM のメトリクスをレポートするためにアプリケーション起動時に JMX 監視を有効にするようにしたら3回に1回くらいの確率でデプロイが失敗するようになった。

デプロイガチャ😂

# 状況整理

### エラーメッセージ

`Error: JMX connector server communication error: service:jmx:rmi://ip-xxx-xxx-xxx-xxx:7199`

7199 はJMX用に割り当てたポート。

### JMXの設定

デプロイはシェルスクリプトで Java プロセスを kill してから再起動している。
JMXの設定は再起動時に Java オプションから。

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

set -ue

service_restart() {
  ssh "$DEPLOY_HOST" 'pkill java; test $? -le 1'
  echo "java process stopped"
  START_JAVA_COMMAND=$(cat << EOS
    nohup /path/to/app_start_script \
      -Dconfig.file=/path/to/stage/conf/application.conf \
      -Dcom.sun.management.jmxremote \
      -Dcom.sun.management.jmxremote.port=7199 \
      -Dcom.sun.management.jmxremote.rmi.port=7199 \
      -Dcom.sun.management.jmxremote.authenticate=false \
      -Dcom.sun.management.jmxremote.ssl=false \
      > /var/log/nohup.out \
      2>&1 &
EOS
)
  ssh "$DEPLOY_HOST" "$START_JAVA_COMMAND"
  echo "java process started"
}

service_restart
```

`app_start_script` は単に  Java オプションを受け取ってアプリケーションを起動するスクリプト。

# 調査

調べてみたところ jmxremote が有効になっているとアプリケーションの再起動に失敗するという事例は結構あるみたいだった。

- [jmxremote が有効になっていると Tomcat VM がシャットダウンしない](https://bz.apache.org/bugzilla/show_bug.cgi?id=36976)
- [JMX監視をすぐに有効にしてJavaアプリケーションの再起動を許可する
](https://kotaeta.com/58599216)

# 原因

どうやら Java プロセスを kill した後もしばらくの間、JMXに指定ポートを掴まれてしまっていることが原因みたいだった。

具体的には、再起動の時点でJMXに割り当てたいポートが **LISTEN** もしくは **TIME_WAIT** の状態なってしまっていた。

# 対策

ということなので netstat で JMXのプロセスを監視して解放されたことを確認してから Java アプリケーションを再起動させるようにシェルを改修した。

```sh
#!/bin/bash

set -ue

# JMXのポートが空くまで待機する関数
wait_until_port_opened() {
  while :
  do
    if ! ssh "$DEPLOY_HOST" "netstat -an | grep 7199" > /dev/null
    then
      break
    fi
    sleep 1
  done
}

service_restart() {
  ssh "$DEPLOY_HOST" 'pkill java; test $? -le 1'
  # JMXのポートが空くまで待機
  wait_until_port_opened
  echo "java process stopped"
  START_JAVA_COMMAND=$(cat << EOS
    nohup /path/to/app_start_script \
      -Dconfig.file=/path/to/stage/conf/application.conf \
      -Dcom.sun.management.jmxremote \
      -Dcom.sun.management.jmxremote.port=7199 \
      -Dcom.sun.management.jmxremote.rmi.port=7199 \
      -Dcom.sun.management.jmxremote.authenticate=false \
      -Dcom.sun.management.jmxremote.ssl=false \
      > /var/log/nohup.out \
      2>&1 &
EOS
)
  ssh "$DEPLOY_HOST" "$START_JAVA_COMMAND"
  echo "java process started"
}

service_restart
```

# 他の解決策

いろいろ調べてる時に教えてもらったことだけれども、ライブラリを利用してJMXの設定にポートを利用しないというアプローチもあるようだった。

- https://github.com/kamon-io/kamon-jmx
- https://github.com/micrometer-metrics/micrometer

こちらはまたの機会に。

# おしまい
if文の波括弧{}を省略したら分岐処理が変わる原因と対策

#近況報告

エンジニア転職成功しました。YouTubeでエンジニア転職したい方向けに情報発信しています。

https://www.youtube.com/channel/UCcXQG8lu_EdyP2Cbhtz1bcA



便利な書き方を知ればすぐに使いたくなりますが、用法を正しく守らないと予期せぬ挙動を行なってしまう可能性あり。
今回は、条件分岐をネスト構造で書く際、
**ブロック(if ~ elseで使われる波括弧{}のこと)を省略すると戻り値が変わるパターンについてまとめます。**

##if文のブロックは省略できる

分岐処理を書く場合のif 〜　elseは定番ですが、
結果処理{}は省略できます。

例えば、以下のように書いても分岐は正しく処理されます。

```php
$x = 10;

if($x === 10)
  print '$変数xは10です';
else
  print '$変数xは10ではありません';

// 結果　$xは10です
```

##ネストされたif文の場合

では、ネストされたif文でブロックを外すとどうなるでしょう？
試しに、下記のように書いてみます

```php:ブロックを省略
$x = 10;
$y = 5;

if($x === 10)
  if($y > 10) //ifのネスト
    print '変数$xが10かつ変数$yは10より大きい数値です';
  
else
  print '変数$xは10ではありません';


//結果 変数$xは10ではありません
```


上記では$xは10、$yは5なので、$x === 10はtrueとなるも$yは10より大きくない為、falseとなり、$y > 10のfalseの結果は何も表示されないことを期待していますが、なぜか「変数$xは10ではありません」という結果が出力されています。

その理由として、
**分岐処理でブロック{}を外すと、elseブロックは直近のif命令に対応するとみなされることが挙げられます。**

試しに、上記の分岐処理にブロックを加えてみましょう。


```php:ブロックを省略しない
$x = 10;
$y = 5;

if($x === 10){
  if($y > 10){ //ifのネスト
    print '変数$xが10かつ変数$yは10より大きい数値です';
  }
}else{
  print '変数$xは10ではありません';
}

//結果 何も表示されない
```

何も表示されないことが確認できました。
つまり、**「$x === 10」はtrueだが、$yは10より大きくない為falseとなり、「$y > 10」がfalseの時の結果処理はない為、何も表示されない、という事になります。**

##if文のブロック{}はどんな条件の場合に省略してよい？

結論は**「if　〜　else」がネスト構造になってない場合のみ省略可能です。**

ネストされていると、elseは直近のifに対応する為、{}を省略した場合は意図しない動作をする可能性があるので要注意です。
virtualenvを始める(Windows)

とりあえず最初の一歩です。

## virtualenvをインストール

```
$pip install virtualenv
```

## 仮想環境を作る

### 仮想環境を入れるフォルダを作成
```
$python -m virtualenv py37(任意の名前)
```

### 仮想環境を作る
ここではpython3.7でやってます。

```
$python -m virtualenv --python=C:\"pythonのあるディレクトリ"\python.exe py37
```

## 仮想環境の起動・停止

↓起動

```
py37\Scripts\activate
```

↓停止

```
py37\Scripts\deactivate
```