OmniAICreator/Qiita-1.07M huggingface dataset:
Gitコマンドの備忘録

# commit
- `git commit`
    - コミット
- `git commit -m "[commit_message]"`
    - コミットメッセージを指定してコミット
- `git commit -a`
    - 追跡中のファイルの変更を全てコミット
- `git commit --allow-empty`
    - 空のコミット

# push
- `git push`
    - ローカルのブランチの情報をリモートに反映（事前に設定が必要）
- `git push origin [local_branch]`
    - ローカルのブランチの情報をリモートに反映
- `git push -u origin [local_branch]`
    - 次回以降のためにローカルとリモートのブランチの紐付けを行い、ローカルのブランチの情報をリモートに反映
- `git push --delete origin [remote_branch]`
    - リモートに存在するブランチを削除

# pull
- `git pull`
    - リモートのブランチの情報を取得してマージ

# fetch
- `git fetch`
    - リモートのブランチの情報を取得

# merge
- `git merge`
    - リモートのブランチをローカルにマージ
- `git merge [other_branch]`
    - 他のブランチを現在のブランチにマージ
- `git merge --squash [other_branch]`
    - 他のブランチの変更を一つにまとめて現在のブランチにマージ

# checkout
- `git checkout [local_branch]`
    - ローカルに存在するブランチにチェックアウト
- `git checkout -b [local_branch] origin/[remote_branch]`
    - リモートに存在するブランチをローカルに新規作成してチェックアウト
- `git checkout -b [local_branch-2] [local_branch-1]`
    - ブランチ1をブランチ2として新規作成してチェックアウト

# branch
- `git branch`
    - ローカルに存在するブランチを表示
- `git branch -a`
    - ローカルとリモートに存在するブランチを表示
- `git branch --color`
    - ブランチを色を付けて表示
- `git branch -D [local_branch]`
    - ローカルに存在するブランチの削除

# reset
- `git reset --soft HEAD^`
    - ファイルの内容はそのまま、直前のコミットを取り消す
- `git reset --hard HEAD^`
    - ファイルの内容も含めて、直前のコミットを取り消す


# 追記
## コマンドの追加
作業フォルダ内に、`.git`という隠しフォルダがあると思います。
このフォルダの中に、`config`というファイルがあります。
このファイルが、その名の通り設定ファイルです。
このファイル内に、`[alias]`と書いて、その後に`git`の後に続くコマンドを書けば、そのコマンドを使うことができるようになります。

```
[alias]
  graph = log --graph --date-order -C -M --pretty=format:\"<%h> %ad [%an] %Cgreen%d%Creset %s\" --all --date=short
```

因みに、上のはgitのツリー構造を表示するためのコマンドです。

## `dev`の変更を`master`に反映
```
git checkout master
git merge --squash dev
git commit -m "[commit_message]"
git push
```
`master`ブランチに **コミットの数を増やしたくない場合** はこう？
まぁ、普通は別ブランチにダウンロード用のものを作成して行うかな？
その場合は、`master`を`[download_branch]`に変更！
けど、これだとgitのツリー構造が繋がってくれないんだよなー。
誰かツリー構造が繋がってくれる、もっと良い方法を教えてください！
gitのブランチをきれいにしたい。


# はじめに

[gitに関するメモ](https://qiita.com/k3nNy_51rcy/items/2e89a1e590875b26c1c3)の中で触れた、git-flowについてのメモです。
これも眠ってたので記事にしてみることにします。

## git-flowの概要

git-flowの概要は[このページ](http://danielkummer.github.io/git-flow-cheatsheet/index.ja_JP.html)に簡単な説明がある。

Git for windowsには初めから付属されているので特になにも考えずともgit flowコマンドが使えるようになっている。
Linuxとかだと別途インストールが必要になるようだ。具体的なインストール方法は[このページ](https://github.com/petervanderdoes/gitflow-avh/wiki/Installation)を参照。

git-flowでは以下のブランチを使用して開発を進める。

* master: 常にデプロイ可能なブランチ。
* develop: 開発用ブランチ。開発中の最新の状態が保管されている。
* feature: 機能追加などの新規開発用ブランチ。開発する機能ごとに作る。`feature/`というプレフィックスを付ける。
* release: リリース用ブランチ。
* hotfix: 緊急を要するバグフィックス用ブランチ。

主な作業はfeatureブランチ上で行う。
以下では、機能追加を行う流れに沿ってgit-flowの使い方を説明する。

## git-flow開始時の設定

1. git-flowで使用する各ブランチを設定する。
    * `git flow init`
    * いくつか質問されるが、基本的に全てそのままEnterキーで良い。
    * ローカルにmaster以外のブランチがあり、developブランチがない場合、デフォルトの設定ではうまくいかない。
        * ローカルにmasterとdevelopのブランチが両方ある状態(他のブランチがあっても良い)か、ローカルがmasterブランチだけの状態になってから`git flow init`を行うこと。


## git-flowの流れ

### 機能追加を行う

新しい機能を開発するときなどは、新しくfeatureブランチを作成して作業する。

1. 新しくfeatureブランチを作成する。
    * `git flow feature start <feature name>`
    * featureの単位はDevOpsのTrack And Planに作成されているStoryが適正。
    * すでにあるfeatureブランチから子featureを作るときは以下のようにする。
        * `git flow feature start <new feature> <base branch name>`
1. featureブランチで作業を行う。
    1. featureブランチの作業をリモートに公開するとき
        * `git flow feature publish <feature name>`
        * 同じfeatureを複数人で開発する際には定期的に`publish/pull`する必要がある。
    1. 現在のfeatureブランチがリモート側で更新されているとき
        * `git flow feature pull <feature name>`
1. featureブランチでの作業が終わったとき
    * `git flow feature finish <feature name>`

featureがfinishされると、featureブランチの内容がdevelopブランチにマージされ、featureブランチが削除される。
また、`feature name`はブランチ名の`feature/`以降の名前なので注意。

### すでにリモートに存在するfeatureブランチをローカルに取得してくる場合

方法はふたつ

1. `git flow feature track <feature name>`
2. `git checkout -b <local branch> <remote branch>`

2.の方法だとローカルブランチに好きな名前をつけることが出来るが、`git flow feature finish`したときのマージ先がdevelopになると思われるので注意。

### masterブランチにリリースする

いくつかのfeatureブランチがfinishし、developの内容をmasterブランチに反映させるためには次の手順を行う。

1. releaseブランチを作成する。
    * `git flow release start <release name>`
1. (必要なら)releaseブランチで調整やバグフィックスを行う。
    * 修正があった場合、`git flow release publish <release name>`で変更を公開できる。
1. 準備ができたらリリースする。
    * `git flow release finish <release name>`
    * releaseブランチの内容がmasterブランチに反映される。さらに、リリースタグが付けられる。
    * releaseブランチに修正があった場合、developブランチにも反映される。
1. developブランチに反映された修正は、必要であれば各自featureブランチに反映させる。
    * `git rebase`などで対応可
    * あるいは`git merge`や`git cherry-pick <commit hash>`などを使う

# あとがき

git-flowは分かりやすくて好きなんですけど、例えばVSCodeに付属しているgitの機能をGUIから使おうとすると、結構めんどくさくなるんですよね…。
SourceTreeならgit-flowをサポートしてるとか書いてますけどね。
でもやっぱりbashが好き。
Macでpythonの仮想環境を構築するまとめ

python3のバージョンをMacで使えるのは現在絶対必須なものです。
はじめて記事を書くのですが、昔は苦労したpythonの環境構築も今はすっきりしたものとなっているのでそれについてまとめてみます。

##python3のインストール

pythonは私の先輩から教わったときはpyenvを使うことが推奨されていました。
器用に使うバージョンを管理する方がよかったとされていましたが、現在はその必要性もなくなってきました。

[python3のインストールはここから](https://www.python.org/downloads/)
バージョンは2と3がありますが、これからは3が主流になるといわれています。よって2018年3月現在3.64をインストールしましょう。
(バージョンは何度も変わります)
またMacOSであることにも注意しそこからダウンロードして下さい。

以下を打ち込むことでどこにインストールされたかを確認できます。
```$which python
　　/usr/bin/python
```
このように出る場合、～/.bash_profileに以下の文を追記します。
```export PATH=/usr/local/bin:/usr/local/sbin:$PATH```
PATH設定がおわったら、確認しましょう。
```$source ~/.bash_profile
   $which python```
で確認しましょう。

##pipとその使い方
pipはpythonのパッケージ管理ツールです。
pythonをダウンロードすると付属しており、別でインストールする必要はありません。
2系はpipで3系はpip3です。間違えないようにしましょう。
以下にpipの使い方をまとめます。

###pip自体のアップグレード
```$pip3 install -U pip```

###~のパッケージをアップグレード
```$pip3 install -U　~```

###~のパッケージのアンインストール
```$pip3 list -y ~```

###パッケージ一覧
```$pip3 list ```

###更新可能なパッケージ一覧
```$pip3 list -o```

###パッケージの検索
```$pip3 search <package>```

##pythonの開発環境を作るのに必要なvenv
venvはpipを使用してインストールします。
```$pip3 install virtualenv```
次のコマンドを実行すると正しくインストールされたかとバージョンを確認できます。
```$virtualenv --version```


##python仮想環境(venv)の構築
system環境を汚さずにライブラリなど自由に入れられるように仮想環境を構築するには、
以下のコードをコマンドプロンプトにいって実行する。
```$python3 -m venv env```

###作成した仮想環境envを有効にする
```$source env/bin/activate (env)```

###仮想環境の無効化
``(env)$deactivate``
C#でフォームのtextbox等に紐づけてinifileの書込/読込を勝手にやってくれるライブラリ

Inifileは未だに結構使われている。
つかいやすいのが一番の理由。
XMLとか、直接開いて使うのは結構大変なので。

自分のソフトはこんなのを使っています。
ソースは以下。
https://github.com/kumokumocc/WORK_/tree/master/classlib/cs/IniFile


使い方はこんな感じ。

        /// <summary>
        /// 名称と、保存用フォームを設定します。フォームは、アプリケーション終了時、Form_Closedイベントが呼ばれるフォームである必要があります。
        /// そうでない場合は、IPアドレス、ポートの値が保存されません。
        /// </summary>
        /// <param name="name"></param>
        /// <param name="form"></param>
        public void InputData(string name, Form form)
        {
            this.Text = name;
            m_Form = form;
            new inifile.CInifile_Form(IniFileSection, "IpAddress", "0.0.0.0", form, textBox_IP, false);
            new inifile.CInifile_Form(IniFileSection, "Port", "81", form, textBox_PORT, false);
            new inifile.CInifile_Form(IniFileSection, "IpAddress_Bind", "0.0.0.0", form, textBox_BindIp, false);
            new inifile.CInifile_Form(IniFileSection, "Port_Bind", "81", form, textBox_BindPort,false);
            new inifile.CInifile_CheckBox(IniFileSection, "IsBind", false, form, checkBox_Bind, false);
            new inifile.CInifile_CheckBox(IniFileSection, "IsSndCRLF", false, form, checkBox_CRLF, false);
            m_Socket = new MySocket(this, label_SocketStatusSend,textBox_Log);

            m_StatusCtrl = new global::Status.StatusCtrl(textBox_Status);
            m_StatusCtrl.Start(new Status.Closed(this));

            timer_Update.Enabled = true;


        }

自分の書くコードにはこんな感じで使っています。

>new inifile.CInifile_Form(IniFileSection, "IpAddress", "0.0.0.0", form, textBox_IP, false);

なんだこれ、って感じですが、意外と簡単。

inifile.CInifile_Formというのは、Form上のオブジェクトとinifileの設定値を紐づけるクラスです。
第1引数のIniFileSectionは、セクション名。固定値でconst宣言されています。

第2引数はKey。"IpAddress"は文字通りIPアドレスです。

第3引数はデフォルト値。inifile中に指定する項目がなかったときの値です。

第4引数は基本的にはメインの×を押されるフォームです。
このフォームがクリエイトされたときにinifileにアクセスしてデータを読込、クローズされたときにinifileにデータを書き込みます。

第5引数は値を書き込むオブジェクトです。
IP表示用のテキストボックスです。
起動中に書き換えられた場合は、書き換わったアドレスをクローズ時に保存します。

第6引数は、ReadOnlyです。
読み取り専用ならtrueを入れます。trueが入っていたらクローズ時に値を書き込みません。

起動時と終了時しかチェックしていないので、強制終了するとinifileの値は変わりませんが、それ以外はほぼ問題なく使えます。

見えない設定値は危険なので、もしinifileに値が書き込まれていなかった場合にもクローズ時にはデフォルト値を書き込みます。

inifileはexeと同じディレクトリのinifile.iniに書き込まれます。
中身はこんな感じ。

>[Sock_Client]
>IpAddress=192.168.0.12
>Port=8802
>IpAddress_Bind=192.168.0.16
>Port_Bind=49317

inifile.CInifile_CheckBoxも基本全く同じで、チェックボックスだと値がtrueかfalseかなのでそれに合わせて作っているだけです。
他にコンボボックスもあります。（前回の値を保持して入れているだけですが）

複数コントロールを配列のように扱うものもありますね。さすがにこれはそんなに使ったことないので、ちゃんと動くかな。

次はシリアル通信でも。
RPi3用CentOS 7でのyumの初期接続エラー

#**はじめに**
　**初投稿の初心者**になります。
あくまで、**参考程度に**よろしくお願いします。
また、なにかご指摘がありましたら、コメントのほうによろしくお願いします。
#**使用環境**
　使用環境は以下の通りです。(Windows-10はあくまで、リンク先確認用です。)

- Raspberry-Pi-3 Model B(日本製)

- CentOS-7
詳細バージョン(CentOS-Userland-7-armv7hl-Minimal-1611-test-RaspberryPi3)
[CentOSのリンクはこちら](https://buildlogs.centos.org/centos/7/isos/armhfp/)

- Windows-10

#**症状**
　初期状態で、yumを実行した際にエラーが起こり、正常に動作しない。

```terminal:yum実行例
yum update
```


```terminal:エラーメッセージ
Loaded plugins: fastestmirror
base
http://mirror.centos.org/altarch/7/kernel/armhfp/kernel-%24kvariant/repodata/repomd.xml: [Errno 14] HTTP Error 404 - Not Found
~~以下略~~
```
#**解決法**
　**/etc/yum.repos.d/** 以下にある、
**CentOS-armhfp-kernel.repo**の**baseurl**を書き換えます。

```terminal:コマンド
vi /etc/yum.repos.d/CentOS-armhfp-kernel.repo
```
上のコマンドを実行して、viを使って**CentOS-armhfp-kernel.repo**の**baseurl**を
以下のように(**$kvariant**を**rpi2**に)変更します。

```terminal:CentOS-armhfp-kernel.repo(変更前)
baseurl=http://mirror.centos.org/altarch/7/kernel/$basearch/kernel-$kvariant
```
```terminal:CentOS-armhfp-kernel.repo(変更後)
baseurl=http://mirror.centos.org/altarch/7/kernel/$basearch/kernel-rpi2
```
これで、再度yumを実行すれば、正常に動作するはずです。
(初期のアップデートは、相当時間がかかるので覚悟はしてください。)

もし仮に、同じエラーメッセージであれば、
**$basearch**の部分を**armhfp**に変更してみてください。

#**解説**
　どうやら、変数となっている**$kvariant**が正常に動作していないようです。
正常に動作していれば、**Error 404 - Not Found**になんてなりませんしね。
(これ、リンクが間違った時などに起こる**接続先が存在しないエラー**ですし…)

なので、Windows-10などを使って、実際に**リンク先**
http://mirror.centos.org/altarch/7/kernel/
に飛んでみます。

そして、その後ろのディレクトリを見ながら**実際に存在する**、
リポジトリの**リンクを指定**してあげました。

他の似たような接続エラーでも、このように**実際にリンク先を確認することで、
解決できることは多々**あります。
なので、少しだけ覚えておくといいかもしれません。
(**信頼できるリンク先にのみアクセス**するようにしないと危険だったりしますが、そこは**自己責任で**...)

　また、バージョンが**7**ではなく**他のバージョン(7.2.1511など)**もあります。
しかし、このような詳細なバージョンは、**最新バージョンにのみ**リポジトリが、
存在しています。

なので、特に気にする必要がなければ、**安定したバージョン7**にしておきましょう。
(最新バージョンの場合、更新されるごとに**baseurl**を変更しなければなりません。)
#まとめ
　今回、初めての投稿でしたがいかがだったでしょうか？

　もし、**参考になった**とか、**役に立った**と思ったら、
**グッド**や**ストック**をお願いします。

また、最初にも言った通り、なにかご指摘がありましたら、
コメントのほうによろしくお願いします。

　また、書きたくなったら書くので、その時はまた、
**よろしくお願いします**。

それでは、最後まで読んでくれてありがとうございました。
#引用
この記事には以下の記事を参考にしています。
1. [raspberry Pi3にcentos7を入れてみた](https://qiita.com/NAZA/items/38303564dde29977d79e#raspberry-pi3%E3%81%A7centos7%E3%82%92%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E3%81%97%E3%81%A6%E3%81%BF%E3%82%88%E3%81%86),@NAZA,2017年11月16日更新
2. [centos7.2のRaspberryPi3でyumができない](https://qiita.com/Leonardo-mbc/items/2fb67a6f860aa33fd9bd),@Leonardo-mbc,2017年01月07日更新
【css3】linear-gradientを応用してボックスの角を削る

CODE PENに登録したので小ネタです。
CSSのグラデーションを使って、角の欠けた四角形を書く方法。
クラス「box01」に書いてある部分が主な部分で、divに設定したプロパティはレイアウト用です。

<p data-height="265" data-theme-id="0" data-slug-hash="EEoWPY" data-default-tab="css,result" data-user="yuki_24" data-embed-version="2" data-pen-title="【css3】linear-gradientを応用してボックスの角を削る" class="codepen">See the Pen <a href="https://codepen.io/yuki_24/pen/EEoWPY/">【css3】linear-gradientを応用してボックスの角を削る</a> by Yuki Koide (<a href="https://codepen.io/yuki_24">@yuki_24</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

ボックス内を田の字型に4分割し、それぞれの背景にグラデーションを設定するイメージで。

【応用】これを応用すると、よくある角折れ表現もCSSだけで作れます
<p data-height="265" data-theme-id="0" data-slug-hash="QmapQY" data-default-tab="css,result" data-user="yuki_24" data-embed-version="2" data-pen-title="【CSS3】背景だけでよくある角が折れた表現を作る" class="codepen">See the Pen <a href="https://codepen.io/yuki_24/pen/QmapQY/">【CSS3】背景だけでよくある角が折れた表現を作る</a> by Yuki Koide (<a href="https://codepen.io/yuki_24">@yuki_24</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>
やっぱりgitはCLIが好き

# はじめに

svnしか使ってなかった社内の人向けに書いたものです。
主にCLI(Powershellなどのコマンドラインターミナル)を用いる場合の使い方をメモしてます。

gitに関する記事なんて今更どこにでも転がってるけど、眠ってたメモを発掘してしまったので記事にしてみます。

## 初期設定

最低限設定しておくべき項目は以下の通り。

* ユーザ名
    * `git config --global user.name <username>`
    * ユーザ名に空白を含む場合は""(ダブルクォーテーション)で囲むこと
    * 指定していないと`git log`したときに`unknown`と表示される
* メールアドレス
    * `git config --global user.email <your address>`
* プロキシ設定
    * `git config --global http.proxy <your_company_proxy>`
    * `git config --global https.proxy <your_company_proxy>`

## リモートのリポジトリからコードを取得するとき

1. リモートからローカルの環境にコードをコピーしてくる
    * `git clone <repository url>`

## 新しく作業ブランチを切るとき

1. 新しく作業ブランチを切る
    * `git branch -b <new branch> origin/<new branch>`
    * `origin/<new branch>`は指定しなくてもブランチは切れるが、`git push/pull`のときにブランチ名を省略できなくなる。
    * 省略してしまったときは次の手順を行うこと。
    * ブランチは機能単位で切ると見やすい。詳細は [git-flow](https://qiita.com/k3nNy_51rcy/items/4575774374173e06ebb9) を参照。
1. (追跡ブランチを設定する)
    * `git branch --set-upstream-to origin/<new branch>`

## ローカルで作業をしたとき

1. 編集・追加したファイルをステージングする
    * `git add <Filename>`
    * ファイル名は正規表現が使える
1. コミットする
    * `git commit -m <commit comment>`
    * コミットコメントが空の場合はコンソールエディタ(vi?)が開く。コメントを空にすることはできない。

## ローカルでの作業に区切りがついてリモートに反映するとき

1. リモートの更新をローカルに反映する
    * `git pull origin <branch name>`あるいは`git pull --rebase origin <branch name>`
    * ブランチを切る際に追跡ブランチを設定していた場合、ブランチ名を省略することができる。
    * `--rebase`オプションを付けると、ブランチの分岐点を修正することができる。
        * コミット履歴が一直線になり、修正履歴が読みやすくなる。
1. ローカルブランチの作業をリモートに反映する
    * `git push origin <branch name>`
    * こちらも追跡ブランチを設定していた場合、ブランチ名を省略することができる。

## 作業ブランチで行ったことをmasterブランチなどに反映する

ここでは、`feature/work`ブランチから`master`ブランチにマージを行うとする。

1. マージ先のブランチへ移動する
    * `git checkout master`
1. マージコミット付きでマージする
    * `git merge --no-ff feature/work`
    * `--no-ff`を付けることで必ずマージコミットが作成される。これによってブランチで作業した範囲が明確になる。

## 作業ブランチを削除する

1. ローカルの作業ブランチを削除する
    * `git branch -d <branch name>`
1. リモートの作業ブランチを削除する
    * `git push --delete origin <branch name>`
    * もしくは`git push origin :<branch name>`
    * 権限がないとブランチの削除ができない？(force pushを勧められる)
    * force push(-fオプション)は他の人のローカルリポジトリと矛盾を起こす可能性があるので基本的に使わない。
1. リモートの状態を更新する
    * `git fetch --prune` あるいは `git fetch -p`
    * `--prune(-p)`オプションを付けることで、リモートから削除されたブランチが反映される。

# あとがき

このメモ書いてからもう1年くらい経つけど、まだ社内ではgit使ってる人少数派なんですよねぇ…。
しかもGUIツールの方が使いやすいって人のほうが多いから、CLI叩いてるのって周り見てたら僕くらい。
もうちょっと流行れー。
Railsチュートリアルやってみた v5.1.4

メモ書き程度に詰まったところなど、更新していきます。
更新は大分ゆっくりになると思います。

# やること
``` https://railstutorial.jp/ ```
上記サイトを参考にチュートリアル終了まで進める。

# リポジトリ
``` https://github.com/kzyamax/rails-tutorial ```

# 環境構築 (Vagrant)
チュートリアルではCloud9推奨ですが、同時にインフラ構成も理解したいので、環境構築にはVagrantを使います。
Dockerは勉強中です。別で記事にするかも。

## 構成
* CentOS (6.9)
* Nginx
* puma
* Ruby (2.4.3)
* RubyOnRails (5.1.4)  

※上記構成の予定（更新中）

## つまったところ
### Rubyがmakeできない
最初、何も考えずに最新版Ruby2.5.0をinstallしようとしたら

![スクリーンショット 2018-03-28 10.48.16.png](https://qiita-image-store.s3.amazonaws.com/0/246026/c028b8fd-ad2e-6fb8-dd74-c4b78521c173.png)

どうやらCentOS6.9にはRuby2.5.0はinstallできない模様。2.5.1では治るらしいよ。
(参考：https://bugs.ruby-lang.org/issues/14234)

妥協して2.4.3で進めます。

<font color="#A4A4A4">*補足：VagrantfileのRubyのverを2.5.0に書き換えると再現できます。興味ある方は一度お試しください。*</font>

### Nginxがpumaのsockを参照できない
```
2018/03/30 05:00:22 [crit] 8985#8985: *5 connect() to unix:///home/vagrant/hello_app.sock failed (13: Permission denied) while connecting to upstream, client: 192.168.33.1, server: rails-tutorial, request: "GET /hello_app/ HTTP/1.1", upstream: "http://unix:///home/vagrant/hello_app.sock:/hello_app/", host: "rails-tutorial"
2018/03/30 05:00:22 [error] 8985#8985: *5 open() "/etc/nginx/html/500.html" failed (2: No such file or directory), client: 192.168.33.1, server: rails-tutorial, request: "GET /hello_app/ HTTP/1.1", upstream: "http://unix:///home/vagrant/hello_app.sock/hello_app/", host: "rails-tutorial"
```
原因はpumaサーバを起動するユーザと、Nginxを起動するユーザが異なることによるpermissionエラー

nginx.confのuserを`vagrant`に書き換えてrestartしたら繋がりました。

# hello_app
さて、実際の開発に入ります。

## つまったこと
### rails-serverが立ち上がらない
```shell-session
[vagrant@rails-tutorial hello_app]$ rails server
/usr/local/src/rbenv/versions/2.4.3/lib/ruby/gems/2.4.0/gems/bundler-1.16.1/lib/bundler/runtime.rb:84:in `rescue in block (2 levels) in require': There was an error while trying to load the gem 'uglifier'. (Bundler::GemRequireError)
Gem Load Error is: Could not find a JavaScript runtime. See https://github.com/rails/execjs for a list of available runtimes.
Backtrace for gem load error is:
・・・
・・・
```
Gemfileに```gem 'therubyracer'```を記載して```bundle install```したら立ち上がりました。

# toy_app
## つまったこと

特につまることもなく終了

# sample_app

***更新中***
centos7 VNC メモ


centos7以前のvncの設定は以下

```bash
# THIS FILE HAS BEEN REPLACED BY /lib/systemd/system/vncserver@.service

VNCSERVERS="1:vncuser 2:root"
VNCSERVERARGS[1]="-geometry 1920x1200"
VNCSERVERARGS[2]="-geometry 1024x600"
```

このファイルに移動されたと書かれているので中を見る
`/lib/systemd/system/vncserver@.service`

書かれているとおりに設定する。  

```
# 1. Copy this file to /etc/systemd/system/vncserver@.service
# 2. Replace <USER> with the actual user name and edit vncserver
#    parameters appropriately
#   ("User=<USER>" and "/home/<USER>/.vnc/%H%i.pid")
# 3. Run `systemctl daemon-reload`
# 4. Run `systemctl enable vncserver@:<display>.service`
```

以下が設定例

```bash
$ cat /etc/systemd/system/vncserver@\:5.service  # 5905でLISTENする, appletは5805
# The vncserver service unit file
#
# Quick HowTo:
# 1. Copy this file to /etc/systemd/system/vncserver@.service
# 2. Replace <USER> with the actual user name and edit vncserver
#    parameters appropriately
#   ("User=<USER>" and "/home/<USER>/.vnc/%H%i.pid")
# 3. Run `systemctl daemon-reload`
# 4. Run `systemctl enable vncserver@:<display>.service`
#
# DO NOT RUN THIS SERVICE if your local area network is
# untrusted!  For a secure way of using VNC, you should
# limit connections to the local host and then tunnel from
# the machine you want to view VNC on (host A) to the machine
# whose VNC output you want to view (host B)
#
# [user@hostA ~]$ ssh -v -C -L 590N:localhost:590M hostB
#
# this will open a connection on port 590N of your hostA to hostB's port 590M
# (in fact, it ssh-connects to hostB and then connects to localhost (on hostB).
# See the ssh man page for details on port forwarding)
#
# You can then point a VNC client on hostA at vncdisplay N of localhost and with
# the help of ssh, you end up seeing what hostB makes available on port 590M
#
# Use "-nolisten tcp" to prevent X connections to your VNC server via TCP.
#
# Use "-localhost" to prevent remote VNC clients connecting except when
# doing so through a secure tunnel.  See the "-via" option in the
# `man vncviewer' manual page.


[Unit]
Description=Remote desktop service (VNC)
After=syslog.target network.target

[Service]
Type=forking

# Clean any existing files in /tmp/.X11-unix environment
ExecStartPre=/bin/sh -c '/usr/bin/vncserver -kill %i > /dev/null 2>&1 || :'
ExecStart=/sbin/runuser -l (ユーザ名) -c "/usr/bin/vncserver %i -geometry 1920x1200 - depth 24" # geometryとdepthを追加
PIDFile=/home/XXX(ユーザ名)/.vnc/%H%i.pid
ExecStop=/bin/sh -c '/usr/bin/vncserver -kill %i > /dev/null 2>&1 || :'

#[Install]
#WantedBy=multi-user.target

```

```bash
$ systemctl daemon-reload
$ systemctl enable vncserver@:5.service
# 自動起動
$ systemctl enable vncserver@:5.service
```
タスク出し、できてますか

スクラムのスプリントプランニングでは、スプリント中にやる作業(タスク)を出して、スプリントの計画づくりをします。ここでのタスクの出し方が、スプリントが順調に進むか左右します。こんな問題が起きたことはないでしょうか。

- タスクがいつまでも終わらない
- 途中でタスクが大量に発生してスプリントに収まらなくなる
- 書いてあるタスクが何のことかわからなくなる

スプリントがうまくいくタスクの出し方のヒントを「設計しよう」「さくせん」「1つの頭脳」という切り口で紹介します。

# 設計しよう

タスク出しとは、やることを漫然とリストアップする作業ではありません。「設計する」「実装する」「テストする」などのタスクを出しても、あまり役に立ちません。タスクに着手する人にとってクリアになっていなければ、意味がない。何をすればいいのか、どこまでやればいいのか、いつ完了するのか。

そうしたタスクを出すには、**スプリントで実現するものをプランニングで設計します**。ページの構成や要素、変更するAPI、モジュールやクラス、メソッド、あるいは設定やスクリプトといったレベルで「何を作る・直す」のか考えましょう。プロダクトは小さなブロックの積み重ねです。タスクは、小さなブロックを積む小さな計画です。どこにどんなブロックを積むのか、見通しがたってはじめて、計画も考えられます。

- タスクの達成条件を決めよう
  - あるタスクは、別のタスクの前提となります。どこまでできていれば完了とみなすのか、考えましょう。
- タスクは具体的に「何をどうする」と書こう
  - 設計をすると、作ったり直したりするものに名前を付けられます。タスクの対象の名前がわかるようにしましょう。
- なにをどうデモするかというゴールから、タスクを逆算しよう
  - 実現方法の設計から始めると、リリースに必要なものを見落としやすくなります。スプリントレビューでどんなデモをするか考え、必要になるものはすべてタスクで網羅しましょう。

# さくせん

短い期間を全速力で駆け抜ける、これがスプリント(sprint = 短距離走)です。全力でダッシュしているときに、角を曲がったり、立ち止まって考えたりする余裕はありません。スプリントプランニングとは、スプリントでやることを洗い出すだけではなく、**どんな順序、タイミング、役割分担でこなすか作戦を立てる場**です。立てた作戦、イコール計画です。

- タスクの並列性と依存関係を確認しよう
  - チームの人数が増えると、タスクの依存関係や前後関係のせいで待ちが発生しやすくなります。並行して進められるもの、先にやっておかないといけないものを確認ましょう。
- タスクは小さく、見積もらず、全体がスプリントに収まるか検討しよう
  - タスクが大きいと曖昧になりやすく、問題があっても発見が遅れがちになります。個々のタスクは小さくしておきます。十分に小さくなっていれば、個別の見積もりをしなくても、全体がスプリントに収まりそうか「腹具合」で判断できるようになります。
- 途中で予想外のタスクが発生すると予想する
  - タスク出しをいくら綿密にやっても、スプリントをはじめれば予想外のことが起きます。計画には調整の余地を含みましょう(ただしバッファを積んではいけません)。計画を綿密にやりすぎると、ちょっとでも想定が外れたら破綻してしまいます。
- ボトルネックに気をつける
  - タスクの中には、特定のメンバーしかできないものや、チーム外に依頼するもの、一定の時間がかかるものなどがあります。そうしたボトルネックは先に見つけておいて、問題にならないように計画しましょう。

# 1つの頭脳

ソフトウェア開発はチームスポーツです[^1]。とりわけ頭脳が、チーム全体の能力を決定づけます。チーム全体が1つの頭脳として考えられるよう、情報や認識や理解を一致させておきたくなります。**プランニングとタスク出しはチーム全体で知識を共有し、判断を一致させる素晴らしい機会です。**

[^1]: [『Team Geek』Brian W. Fitzpatrick、Ben Collins-Sussman、角 征典](https://www.oreilly.co.jp/books/9784873116303/)

- みんなで設計し、作戦を立てる
  - 設計の議論や判断はチーム全体の作業です。ここで知識の差を埋め、判断基準をそろえておけば、スプリント中の行き違いや不要な議論を避けやすくなります。作戦も同様で、進め方のイメージを全員が持っていれば、ムダを減らせます。
- 開発だけでなく、暗黙のこと、あたりまえの作業もぜんぶ出そう
  - チームメンバーにはそれぞれ得意分野や経験があります。ある人があたりまえと思っている作業も、わかっていない人がいるかもしれません。作業や進め方について対話しながら、すべてタスクとして出しておきましょう。出したタスクをお互いにレビューするのもいいです。
- 事前アサインはしない。でも誰がやるとよいか見当はつける
  - 誰がどのタスクをやるとベストか考えると、よりよい作戦が立てられます。ただし、実際に担当を決めるのは、スプリント中の着手する時点にしましょう。予想外のことが起きたら、ベストの担当も変わります(たとえばインフルエンザ)。そなえとして、全員がタスクの概要をつかんでおきます。

# ふりかえり (レトロスペクティブ)

スクラムかどうかを問わず、多くのチームがふりかえり(レトロスペクティブ)を定期的にやっています。タスク出しのやり方そのものも、ふりかえりで扱うべき大事なテーマになります。見落としを防ぐには？ プランニングの時間を短縮できないか？ タスクの書き方のいいアイデアは？ タスクボード(スプリントバックログ)は改善できる？ もっと上手くやるには？

タスクの出し方、粒度、内容、書きぶり、整理の仕方などはすべて、チームで洗練させていき、チームの能力を向上させるポイントのひとつです。チームごとの特色が出るところでもあります。ふりかえりを積み重ねて、チーム独自の優れたやり方を編み出してください。

# まとめ

- 設計しよう
  - タスクの達成条件を決めよう
  - タスクは具体的に「何をどうする」と書こう
  - なにをどうデモするかというゴールから、タスクを逆算しよう
- さくせん
  - タスクの並列性と依存関係を確認しよう
  - タスクは小さく、見積もらず、全体がスプリントに収まるか検討しよう
  - 途中で予想外のタスクが発生すると予想する
  - ボトルネックに気をつける
- 1つの頭脳
  - みんなで設計し、作戦を立てる
  - 開発だけでなく、暗黙のこと、あたりまえの作業もぜんぶ出そう
  - 事前アサインはしない。でも誰がやるとよいか見当はつける
- ふりかえりで改善しよう
xrea mysql／ファイルのシェルスクリプト

XREAでシェルスクリプトをおいてみた。目的はデータのバックアップだったのだが、XREAは無料版だと
cronが設定できないので、変更した時は手動でバックアップしてます。

参考元のだと私の環境だとmysqldumpがうまくいかなかったので、ちょっと改良してます。

１．フォルダの作成
public_html/と同じ場所にフォルダを作成

```
$ mkdir ~/backup-mysql
```

２．backup-mysqlに移動して、シェルスクリプト作成
シェルスクリプトはパーミッション700で作成

```
$ cd ~/backup-mysql
```
```
[backup-mysql]$ touch backup.sh
[backup-mysql]$ chmod 700 backup.sh
```

３．シェルスクリプトを編集
ここからは私の独自の設定です。
メール送信はXREAではできません。
※そもそもmailコマンドがない

```backup.sh
#!/bin/sh

# 初期設定(ここを自分に合わせる)
DATABASE=◯◯◯◯
DBUSERNAME=◯◯◯◯
PASSWORD=◯◯◯◯
XREAUSERNAME=◯◯◯◯
PORT=9306
BACKUPDIR=backup-mysql
KEEPDAY=3
MAILADDRESS=◯◯◯◯@◯◯◯◯
PROGRAM=~/public_html/

# XREA/CORESERVER 設定
PREFIX=mysql
SERVER=localhost
NOWDATE=`date +%Y%m%d`
DESTDIR=/virtual/$XREAUSERNAME/$BACKUPDIR
DUMPFILE=$PREFIX.$NOWDATE.sql
TARFILE=$PREFIX.$NOWDATE.tar.gz
TARFILE2=$XREAUSERNAME.$NOWDATE.tar.gz
OLDDATE=`date "-d$KEEPDAY days ago" +%Y%m%d`

# MySQLダンプ/圧縮
cd $DESTDIR
mysqldump -u $DBUSERNAME -P $PORT -B $DATABASE -p$PASSWORD >$DUMPFILE
tar zcvf $TARFILE $DUMPFILE

#ソース保存 *public_html以下の特定フォルダだけの場合は後ろのパスを変える。
tar cvfz $TARFILE2 $PROGRAM --exclude downloads
#downloadsというフォルダを除外。cakephpにコピーした時に増えるので。

# 処理判定
if [ $? != 0 -o ! -e $TARFILE ]; then
    echo "backup faild -- ($DUMPFILE)"
    exit 1
fi
```
判定処理部分は毎日バックアップしないなら意味なし。

５．起動してみる。
本来はcronだが、XREAの無料版はcron対応していないので、手動で起動。

```
$ ~/backup-mysql/backup.sh
```

以上

参考：http://wp.graphact.com/2011/06/27/mysql-sh-backup/
MySQL5.7をインストールしたときに初期パスワードを探してパスワードを変更するまで

#現象
インストールして、パスワードがわからないという自体に陥る。
初期パスワードは下記コマンドで取得が可能です。
`cat /var/log/mysqld.log | grep "temporary password"`

##パスワードはさっさと変えましょう

####パスワード必須文字数を短くする（自己責任でお願いします）
`mysql -u root -p初期パスワード --connect-expired-password -e "SET GLOBAL validate_password_length=4;"`

####パスワードのセキュリティレベルを下げてしまおう（自己責任でお願いします）
`mysql -u root -p初期パスワード --connect-expired-password -e "SET GLOBAL validate_password_policy=LOW;"`

####パスワードを変更する（下記では「root」に変更）
`mysql -u root -p初期パスワード --connect-expired-password -e "ALTER USER 'root'@'localhost' IDENTIFIED BY 'root';"`


##おまけ：Ansible版はこちら
（どこかの記事を参考にしたのですが、失念してしまいました。すみません）

```mysql.yml
---
- name: mysql install
  hosts: all
  become: true
  tasks:
    - name: remove mariadb-libs
      yum:
        state: absent
        name: mariadb-libs

    - name: install mysql repository
      yum:
        state: present
        name: http://dev.mysql.com/get/mysql57-community-release-el6-7.noarch.rpm
        validate_certs: yes

    - name: install yum-utils, mysql-python, mysql-community-server
      yum:
        state: present
        name: "{{ item }}"
      with_items:
        - yum-utils
        - MySQL-python
        - mysql-community-server

    - name: running and enabled mysqld
      service:
        name: mysqld
        state: started
        enabled: yes

    - name: check .my.cnf exists
      stat:
        path: /root/.my.cnf
      register: mycnf_file

    - name: get temporary password
      shell: cat /var/log/mysqld.log | grep "temporary password" | awk '{print $11}'
      register: mysql_default_password
      when: not mycnf_file.stat.exists

    - name: change password validation to the easy way
      shell: |
        mysql -u root -p'{{ mysql_default_password.stdout }}' --connect-expired-password -e "SET GLOBAL validate_password_length=4;"
        mysql -u root -p'{{ mysql_default_password.stdout }}' --connect-expired-password -e "SET GLOBAL validate_password_policy=LOW;"
      when: not mycnf_file.stat.exists

    - name: change root user password
      shell: |
        mysql -u root -p'{{ mysql_default_password.stdout }}' --connect-expired-password -e "ALTER USER 'root'@'localhost' IDENTIFIED BY 'root';"
      when: not mycnf_file.stat.exists

    - name: remove all anonymous user
      mysql_user:
        name: ''
        state: absent
        host: localhost

    - name: create database
      mysql_db:
        name: ansible_test
        state: present
        encoding: utf8mb4

    - name: create user
      mysql_user:
        name: vagrant
        password: vagrant
        priv: '*.*:ALL,GRANT'
        state: present

    - name: restart mysqld
      service:
        name: mysqld
        state: restarted

```

```init_my.cnf.j2
[client]
user = root
password = {{ mysql_default_password.stdout }}
connect-expired-password
```
.NET プラットフォームで始めるクラウドネイティブアプリ開発

<p>この投稿は東京渋谷ヒカリエ 8 階にある <a href="http://aka.ms/aajp" target="_blank">Azure Antenna</a> で実施された「.NET プラットフォームで始めるクラウドネイティブアプリ開発～ 今、気になる .NET / Azure テクノロジを使ってみよう 」で使われた資料のご案内です。</p>

- <strong>.NET プラットフォームで始めるクラウドネイティブアプリ開発</strong><br />
https://www.slideshare.net/secret/jeSIbvLCxn4qjo

<p>:satellite:&nbsp;&nbsp;新しいイベントの情報は、Connpass の <a href="http://aka.ms/aajp" target="_blank">Azure Antenna サイト</a>よりご確認いただけます。</p>

<p>:arrow_backward:&nbsp;<a href="https://qiita.com/AzureAntenna/items/71f394c100fbfa8ddcc8">「Azure Antenna 実施イベント資料（カテゴリ別）」に戻る</a></p>
Xcodeでシミュレータを素早く選択する

# Xcodeでシミュレータを素早く選択する
Xcodeでデバッグするときに、シミュレータのデバイス、OSバージョンを変えたいことがよくあります。
しかし、インストールしているシミューレタのデバイスやOSが多いと、スクロールして選択するのは大変です。スクロールも滑らかではないので、かなりストレス！

そんな毎日を過ごしていましたが、先日ひょんなことから便利な方法を見つけたので、こちらにメモしておきます。

<img width="184" alt="スクリーンショット 2018-03-28 9.58.36.png" src="https://qiita-image-store.s3.amazonaws.com/0/16973/7e8e0dba-f160-b2e6-a919-adc5e333de97.png">

いつものようにシミュレータのリストを表示して

<img width="378" alt="スクリーンショット 2018-03-23 10.23.50.png" src="https://qiita-image-store.s3.amazonaws.com/0/16973/4920a7e9-96ae-cd5f-a51f-c980cd329b6c.png">

キー入力をするだけです。これで、インクリメンタルにフィルタリングされます。便利！

みなさん知っていることなのかもしれませんが、偶然見つけて感動したので、共有します。
openvpn v2.3からv2.4への更新

# 経緯

## Amazon Linuxのパッケージアップデート

以前、以下の記事を参考にVPNサーバを構築していた

* [AWSにOpenVPNでVPNを構築してみた](https://qiita.com/saitoxu/items/b0a265edfb11ac381c89)

しばらくこれで動いていたのだが、パッケージを以下のように更新したところVPNクライアントでエラーが出るようになった。

```
（旧）openvpn-2.3.12-1.16.amzn1.x86_64
（新）openvpn-2.4.4-1.21.amzn1.x86_64
```

原因はおそらくopenvpn2.4からtls-auth認証を必須とするようになったからです。OpenVPN側のリリースノートの和訳がありました↓

* [OpenVPN 2.4.2 リリース](https://www.openvpn.jp/2017/05/15/1164/)

>2017/5/11にOpenVPN 2.4.2がリリースされました。
>
>このバージョンはいくつかのバグフィックスに加えて、以下の2つのDOS攻撃対策が行われています。
>
>* 巨大なサイズのコントロールパケットを送り込むことにより、ASSERT() が発生して OpenVPN プロセスが停止させられる可能性があります（CVE-2017-7478）。対象となるバージョンは OpenVPN 2.3.12以降 です。なお、 --tls-auth か --tls-crypt が設定されている場合、攻撃を成功させるには攻撃側が正しいTLS鍵を>保持している必要があるため、危険性は大幅に低下します。
> * 認証済みクライアントがサーバーのパケットIDカウンタをロールオーバーを引き起こし、ASSERT() が発生して OpenVPN プロセスが停止させられる可能性があります（CVE-2017-7479）。この攻撃を成功させるには、クライアントはサーバーに対して最低でも 196GB のデータを送り付ける必要があります。

# 設定変更作業

## サーバサイドの変更

### tls-authの有効化, 暗号化アルゴリズムの設定

* そもそもtls-authを有効化してないので有効化する

```:/etc/openvpn/server.conf
- ;tls-auth ta.key 0 # This file is secret
+ tls-auth ta.key 0 # This file is secret
```

* サーバサイドで使う暗号化方法を設定

```:/etc/openvpn/server.conf
- ;cipher AES-256-CBC
+ cipher AES-256-CBC
```

### アップデート時のopenvpn不具合（？）への対応

なぜか更新時にCRL(Certificate Revocation Lists)；作成した証明書の失効リストが原因でエラーが出るので、以下のサイトの方法でCRLを再作成します（※サーバサイドを更新しただけでCRLが失効するのはなんかおかしいので、たぶんopenvpnの不具合だと思う…自信なし:sweat:）。

* [OpenVPNが接続不可-CRLを再生成する](https://www.agilegroup.co.jp/technote/openvpn-regenerate-crl.html)
* [OpenVPN Support Forum - Regenerate expired crl?](https://forums.openvpn.net/viewtopic.php?t=23166)

とりあえずここまでで、openvpnを再起動すればサーバサイドの設定は終わりです。

## クライアントサイドの変更

サーバサイドで設定したtls-auth用に, [vpnux Client - OpenVPN client for Windows](https://www.plum-systems.co.jp/vpnux-client/)の設定を追加します。

ここに関してはクラスメソッドさんのブログ記事が詳しいため、それを見ていただきたい。[OpenVPN 2.4によるVPN接続環境をAWSで構築する](https://dev.classmethod.jp/cloud/aws/openvpn24-aws/), 記事の**"クライアント設定"**, 以降を参照せよ:point_up:。
MySQLの1つのカラムでIPv4、IPv6両方のIPアドレスを格納する方法を考える

ログイン時のIPをログとしてテーブルに保存したかったので考えた

**具体的な方法だけ知りたい人は一番最後だけ見てください**

# MySQLにおけるIPアドレスの格納方法
- 文字列として格納する
- 数値、バイナリとして格納する

## 文字列
本来のIPアドレスの形式ではない文字列に変換して格納してしまうが、画面上などに表示を行う場合にそのまま使用できる

## 数値、バイナリ
IPアドレスを本来のバイナリの形で格納できるが、文字列として使用したい場合に変換が必要になる

ここでは文字列ではなく、数値、バイナリの形で保存する方法を考える

# MySQL的なIPv4とIPv6の違い
## IPv4
- 32bit
- `UNSIGNED INT`または`BINARY(4)`を使って格納する
- `INET_NTOA()`,`INET_ATON()`関数を使って文字列形式との変換ができる
- `IS_IPV4()`関数を使ってIPv4形式であるか判定できる

## IPv6
- 128bit
- `BINARY(16)`を使って格納する
- `INET6_NTOA()`,`INET6_ATON()`関数を使って文字列形式との変換ができる
- `IS_IPV6()`関数を使ってIPv6形式であるか判定できる

# どちらも格納できる型を考える
IPv6を格納する必要がある段階で型は128bit以上のサイズが必要になる

よって、選択肢としては`BINARY(16)`になるがIPv4(32bit)格納時の効率が悪いので、`VARBINARY(16)`を用いるのが適切

# 実装方法
## INSERT,UPDATE
`IS_IPV6()`関数でIPv6であるかを判断して呼び出す関数を分ける

## SELECT
IPv6は128bitなので`VARBINARY(16)`を最大まで使う

しかしIPv4は32bitなので最大まで使わない

この違いを利用して`LENGTH()`関数を利用することにより、どちらの形式であるか判断でき呼び出す関数を分ける

# 実装例
hogeテーブルにip_addressというカラムがあるという想定です

## hogeテーブル
| カラム名    | 型            |
|------------|---------------|
| ip_address | VARBINARY(16) |

## INSERT(,UPDATE)
```sql
INSERT INTO hoge(ip_address) VALUES (IF(IS_IPV6(:ip_address), INET6_ATON(:ip_address), INET_ATON(:ip_address)));
```
## SELECT
```sql
SELECT IF(LENGTH(ip_address) = 16 ,INET6_NTOA(ip_address), INET_NTOA(ip_address)) AS ip_address FROM hoge;
```
WebDAV クライアントの User-agent を調べる

WebDAVクライアントはいろいろ相性問題があるようで、ある特定のWebDAVサーバーできちんと利用できるWebDAVクライアントのホワイトリストまたはブラックリストを作る必要が出てきた。

そこで、クライアントのUser-agentを手っ取り早く調べる方法

https://gist.github.com/phrawzty/62540f146ee5e74ea1ab で、http.server.SimpleHTTPRequestHandler に少し手を加える、という方法が紹介されていた。これを真似して以下の通り。

[BaseHTTPRequestHandler](https://docs.python.jp/3/library/http.server.html#http.server.BaseHTTPRequestHandler) (SimpleHTTPRequestHandlerの親クラス)は `do_メソッド` という関数名で、HTTPリクエストメソッドへの応答を書くことができる。また該当するメソッドが実装されていないとその旨をコンソールメッセージとして返してくる。

```python
import http.server
import logging
import argparse

class GetHandler(http.server.SimpleHTTPRequestHandler):
    def do_GET(self):
        print(self.headers)
        SimpleHTTPRequestHandler.do_GET(self)

    def do_PROPFIND(self):
        print(self.headers)

# copy from http.server
if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('--bind', '-b', default='', metavar='ADDRESS',
                        help='Specify alternate bind address '
                             '[default: all interfaces]')
    parser.add_argument('port', action='store',
                        default=8000, type=int,
                        nargs='?',
                        help='Specify alternate port [default: 8000]')
    args = parser.parse_args()
    handler_class = GetHandler
    http.server.test(HandlerClass=handler_class, port=args.port, bind=args.bind)
【解決！】Docker上でNodemailerを使うとメールが送信されない


タイトル通り、Docker上に立てたAPIサーバーから、メール送信をしようとすると以下のような、エラーがでる

```
{ Error: getaddrinfo EAI_AGAIN ${SMTP_SERVER}:587
    at Object._errnoException (util.js:1022:11)
    at errnoException (dns.js:55:15)
    at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:92:26)
  code: 'ECONNECTION',
  errno: 'EAI_AGAIN',
  syscall: 'getaddrinfo',
  hostname: '${SMTP_SERVER}',
  host: '${SMTP_SERVER}',
  port: 587,
  command: 'CONN' }
```

どうやら外部ネットワークに接続できずに、止まってしまっているらしい


別にDockerの設定変更も行っていないのに。。。

nginx再起動してみよ・・・

```
$ docker-compose restart nginx

docker: Error response from daemon: failed to create endpoint db01 on network bridge: COMMAND_FAILED: '/sbin/iptables -t nat -A DOCKER -p tcp -d 0/0 --dport 3306 -j DNAT --to-destination 172.17.0.2:3306 ! -i docker0' failed: iptables: No chain/target/match by that name..
```

むむ、そういえばfirewalldをいじったぞ！
Googleさんに聞こう！


突然Dockerコンテナ内からネットワークに繋がらなくなったらiptablesを疑ってみよう
http://blue1st-tech.hateblo.jp/entry/2017/01/29/232733

どうやらfirewalldやiptablesを再起動させたりすると、Docker周りの設定がなくなってしまうようだ。

というこで、

```
$ systemctl restart docker
```

Dockerを再起動させたら直りました。


## まとめ

iptablesを再起動したら、Dockerの再起動もしましょう！
Google Drive上のファイルに直接アクセスする

# 発端

GASからSlackに連携しようと思った際に、Slackに投稿するアイコンの置き場にGoogle Driveを使いたかった。
普通に共有リンクを作成すると、ビューア経由で開くリンクが生成されるため、SlackにURLを渡しても正常に画像表示されない。

# Google Drive上のファイルを共有する

Google Drive上で共有リンクを生成すると、下記のようなURLが生成される。
```
https://drive.google.com/open?id=<ファイルID>
https://drive.google.com/file/d/<ファイルID>/view?usp=sharing
```

このURLはGoogleのビューア経由で対象のファイルを開くためのURLであって、そのままSlackのicon_urlパラメータに渡してもアイコンが表示されない

# 外部から直接アクセス可能なURLに変更する

わかってしまえば簡単で、上記で取得したURLを下記のように変更するだけ。
```
https://drive.google.com/uc?id=<ファイルID>
```

上記でGoogle Drive上の画像ファイルが無事にSlackのアイコンとして表示された。

# 参照URL

探してみたら同じような内容の記事があった・・・  

- [Google ドライブ 直接ダウンロードリンクの魔力（Google Maps API 番外編）](http://atranticlabo.seesaa.net/article/440878948.html)
- [Google Drive に保存した画像を直接呼び出せるURLの取得](https://qiita.com/arribux/items/0394968fa318d9309d33)
- [Google Driveに入れた画像を直接表示するパスを取得する。](http://posaune.hatenablog.com/entry/2013/08/14/162251)

本記事は、[弊社スタッフブログ](https://www.northtorch.co.jp/archives/351)に転載しました。
Selenium のサンプル 予約フォーム (Ruby) 

Selenium のサンプルです。

>ドライバーのインストール

```bash
sudo gem install selenium-webdriver
```

>サンプルプログラム


```rb:reserve_form.rb
#! /usr/bin/ruby
# -*- coding: utf-8 -*-
#
#	reserve_form.rb
#
#					Sep/21/2018
#
# ------------------------------------------------------------------
require 'selenium-webdriver'
# ------------------------------------------------------------------
STDERR.puts	"*** 開始 ***"

URL = 'http://example.selenium.jp/reserveApp/'

driver = Selenium::WebDriver.for :firefox
driver.get(URL)

#
driver.find_element(:id,'reserve_month').clear()
driver.find_element(:id,'reserve_month').send_keys("11")
driver.find_element(:id,'reserve_day').clear()
driver.find_element(:id,'reserve_day').send_keys("10")
driver.find_element(:id,'reserve_term').clear()
driver.find_element(:id,'reserve_term').send_keys("3")
driver.find_element(:id,'headcount').clear()
driver.find_element(:id,'headcount').send_keys("2")
#
str_select = "input[type='radio'][name='bf'][value='off']"
item=driver.find_elements(:css,str_select)[0]
item.click()
#
str_select = "input[type='checkbox'][id='plan_b']"
item=driver.find_elements(:css,str_select)[0]
item.click()
#
driver.find_element(:id,'guestname').clear()
driver.find_element(:id,'guestname').send_keys("明智小五郎")
#
driver.find_element(:id,'goto_next').click()
#
STDERR.puts	"*** 終了 ***"
#
# ------------------------------------------------------------------
```

>実行方法

```bash
./reserve_form.rb
```

使った Ruby のバージョン

```text
$ ruby --version
ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-linux]
```
入れた筈のmoduleがjupyterでno moduleとなる問題 in Anaconda仮想環境

問題が起こった経緯と、解決方策を簡潔に述べます。

## 問題を起こした背景

- Anacondaでデフォルトとは異なるバージョンの（Python3.5）の仮想環境をたてた。
- その後pipでいくつかのmoduleを入れた。（Tensorflowとか） 
- pythonコードとしては実行できるのに、jupyterで書くとtensorflowが**no module**となる。

同様のことがpipで入れたopencv-pythonなどにも起こった。

## 原因

原因はどうやら**新しい環境にはjupyterが入っておらず**、別環境のjupyterが呼ばれていたっぽいということ。
すなわち、当該仮想環境でjupyterを実行したにもかかわらず、別環境でjupyterが起動していたためmoduleを発見できなかったということらしい。

`conda list ` でみても確かにjupyterもipythonも入っていなかった。


``` 
conda list
# packages in environment at C:\Users\XXXX\AppData\Local\conda\conda\envs\tf35:
#
# Name                    Version                   Build  Channel
absl-py                   0.1.12                    <pip>
astor                     0.6.2                     <pip>
bleach                    1.5.0                     <pip>
certifi                   2018.1.18                py35_0
gast                      0.2.0                     <pip>
grpcio                    1.10.0                    <pip>
html5lib                  0.9999999                 <pip>
Keras                     2.1.5                     <pip>
Markdown                  2.6.11                    <pip>
numpy                     1.14.2                    <pip>
opencv-python             3.4.0.12                  <pip>
pip                       9.0.1                    py35_5
protobuf                  3.5.2.post1               <pip>
python                    3.5.5                h0c2934d_1
PyYAML                    3.12                      <pip>
scipy                     1.0.1                     <pip>
setuptools                39.0.1                    <pip>
setuptools                38.5.1                   py35_0
six                       1.11.0                    <pip>
tensorboard               1.6.0                     <pip>
tensorflow-gpu            1.6.0                     <pip>
termcolor                 1.1.0                     <pip>
vc                        14                   h0510ff6_3
vs2015_runtime            14.0.25123                    3
Werkzeug                  0.14.1                    <pip>
wheel                     0.30.0           py35h38a90bc_1
wheel                     0.30.0                    <pip>
wincertstore              0.2              py35hfebbdb8_0
```


## 解決策
jupyterを入れましょう。
`conda install jupyter`
で解決。


## 余談
余談だが、一般にanacondaとpipを混用すると危険とある。
依存関係が管理できないような場合にはcondaに統一したほうが良さそうだ。

http://onoz000.hatenablog.com/entry/2018/02/11/142347

でも[この手順](http://ossyaritoori.hatenablog.com/entry/2017/05/28/%E4%BB%AE%E6%83%B3%E7%92%B0%E5%A2%83%E4%B8%8A%E3%81%A7%E3%81%AE%E3%83%91%E3%83%83%E3%82%B1%E3%83%BC%E3%82%B8%E7%A2%BA%E8%AA%8D%E3%81%A8%E8%BF%BD%E5%8A%A0%E3%81%A7%E3%82%A4%E3%83%B3%E3%82%B9)守っている人どれだけいるんだ？（横着）
自分用のメモ：cdをもっと直感的で楽な使い方をしたかった

> cdによるディレクトリ移動を効率化
https://qiita.com/omega999/items/4346ae57c9ff8bb1d50d

素晴らしいな、と。
さっそく導入することにしたけれど、
時間がたてばどうやって導入したかも忘れそうなので
引用ブックマーク。
調査についての個人的まとめ

#この記事について#
自分の備忘録として、調査全般についての自分の考えや調べたことを記載していきます。
ほぼリンク集として使用。
経験が浅いので、間違っていることもあると思いますがご容赦ください。

#全体#
目的を踏まえ、まず全容、概要から。
そこから段階的に詳細を調べる。分からないとこは時間決めてさっさと諦める

#書籍

| 事項       |       説明|       参照|
|:-----------------|:------------------|:------------------|
効率よく読むには|OPIR法を使う。<br>OPIR法はOverview,Preview,Inview,Reviewのこと。日本語で訳すと以下になる。<br>1.概要把握<br>2.下読み<br>3.本読み<br>4.仕上げ読み<br><br>左の書籍から抜粋|[頭がいい人、悪い人の仕事術](https://ci.nii.ac.jp/ncid/BA72080042)|

#仕様書
| 事項       |       説明|       参照|
|:-----------------|:------------------|:------------------|
|仕様書の理解|-|[システム開発で仕様が理解できない時の対策方法](https://sou-mu.net/archives/2381.html/)|

#ソースコード

| 事項       |       説明|       参照|
|:-----------------|:------------------|:------------------|
概要を知るには|-|[ソースコードを効率よく読むには(2)](http://yasuho.hatenablog.com/entry/20060512/p1)|
|調査失敗の具体例|-|[伸びないプログラマに見られる4つの傾向](http://www.bunkei-programmer.net/entry/2014/04/24/002059#２寄り道が好きですぐ本題から外れる)|
風邪で会社を休んだので、Alexaに看病してもらう。

# Amazon Echo Dotをゲットした

<img src="https://qiita-image-store.s3.amazonaws.com/0/7745/b6ce1db5-5c31-d650-cfc7-b62acae5cca3.png" width="300px" alt="Amazon Echo Dotと体温計"></img>

社長に買ってもらったもの。勉強会で使います。ありがとうございます。

ひとまず家でガッツリ使ってみようと思って、土日に持って帰ったら、風邪を引いてしまいました。

(あの蕎麦屋さんでゲホゲホしていたおばさん…！)

人のせいにするのは良くないですね。


# あらすじ

月曜日に起きると、発熱と頭痛がすごいので、会社を休みました。

病院でインフルエンザの検査を受けると、陰性でした。

薬が効いてきたので、ちょっと元気になったタイミングでAlexaをセットアップして、会話してみました。


# 結論

**失敗**

なんかイマイチでした。ただの会話で終わってしまった…

Siriと比べると、人間味が無く、「Wikipedia(なのかな？)の読み上げマシーン」、「商品買わせるマシーン」みたいな印象でした。

商品の選択肢は良いとして、ろくな説明も無しに1-Clickで買わせようとするのは強引なのでは？感。ぐちぐち。


# 本当にやって欲しかったこと

- 体温を教えて
- カーテンを閉めて

たぶん、**スキルの向こう側** が必要なんだろうなと感じました。

Echoの物理デバイスだけじゃ超えられない壁がありそう。

EchoもAlexaもあくまで、物理媒体へのインタフェースとして使うのが良さそう。(色んな所で同じことを言われてそう)

風邪が治ったらやってみたいところです。

何も言わずボタン一つで体温を測ってくれる体温計は偉大な発明品だと実感しました。


# 風邪をひいた人間とAlexaの会話集

解熱の方法を教えて。
ちょっとよくわからないです。ごめんなさい。

風邪ひいちゃった。
ごめんなさい。今はわかりません。

風邪の治し方を教えて。
こんな説明が見つかりました。風邪とはウイルスによる上気道感染症であり、主な影響は鼻に現れる。

頭痛がするんだけど。
すみません。私にはわかりません。

会社に電話。
Alexa Callメッセージはお住いの地域では現在ご使用になれません。

冷えピタが欲しい。
効果音のみ。

無視しないで。
すみません。よくわかりません。

インフルエンザの検査を受けたいんだけど。
効果音のみ。

今日の晩ごはんは？
火曜日です。

今日の日本代表の試合は何時から？
すみません。よくわかりませんでした。

森友学園って知ってる？
学校法人森友学園は大阪市...

森友学園問題って知ってる？
学校法人森友学園は大阪市...に対する協議...

内閣支持率を教えて。
こんな説明が見つかりました。内閣支持率とは内閣の支持率のこと。

家の居心地はどう？
ごめんなさい、いまはわかりません。

日没は何時？
20183/27 17:53です。

Fire TVをつけて。
すみません。Fire TVが見つかりません。

風邪薬を買いたい。
すみません。この商品は音声では注文できません。

マスクを買いたい。
マスクを検索したところ、PM2.5...1-Click設定が...ひとまずカートに追加しますか？
いいえ。
わかりました。...


# 2日休んで出社した

後輩と会って元気が出たので、記念に書いてみました。
WAE-MMDをChainerで実装

# Wasserstein Auto-Encoders (MMD)

[TensorFlow実装](https://github.com/tolstikhin/wae)を参考に、ChainerでWAE-MMDを実装してみました。

* [https://github.com/knok/chainer-wae](https://github.com/knok/chainer-wae)

## 動機

[以前作ったモデル](https://qiita.com/knok/items/c88ba3fa6f0384c1403c)をWebDNNを用いてブラウザで動作するデモを作ろうと思ったのですが、一部のオペレータがWebDNNでは対応していないようで処理できませんでした。ならば理解を深めるためにもChainerで実装しよう、ということでやってみてある程度結果を出すことができました。
出来上がったWebDNNによるデモは以下で見られます。

* [http://wae-friends.daio.net/](http://wae-friends.daio.net/html/)

## 構造

基本的にはDCGANをベースとしたネットワーク構造です。conv/deconv + batch normを3層持たせています。

## Encoderの事前訓練

Encoderの入力画像に対して出力される潜在空間の分布を平均0、分散1となるような分布に近づけるよう事前訓練をします。バッチサイズ分の乱数を生成して、Encoderの出力の平均と分散の二乗平均誤差を最小化します。

## 目的関数

論文では以下のように定義されています。

```math
D_{WAE}(P_X, P_G) = \inf_{Q(Z|X)\in \mathcal{Q}} \mathbb{E}_{P_X} \mathbb{E}_{Q(Z|X)}[c(X, G(Z))] + \lambda \cdot \mathcal{D}_Z(Q_Z,P_Z)
```

最初の項はautoencoder($\mathcal{Q}$)の復元誤差で、後ろの項は2つの分布$Q_Z$(エンコーダの潜在変数)と$P_Z$(サンプリングで得る値)のダイバージェンスです。VAEであればKLダイバージェンスを使う部分ですが、ここをGAN, MMDによって求めるところがWAEの特徴です。

### 復元誤差

$||x - y||_2^2$を使って求めています。TensorFlow実装では、L1, L2ノルムも選択できるようになっています。

### ダイバージェンス

TensorFlowでは
* GAN
* MMD - RBFカーネル
* MMD - IMQカーネル
が選択できるようになっていますが、今の実装ではIMQカーネルを用いたMMDのみを実装しています。

#### MMD (Maximum Mean Discrepancy)

MMDに関するわかりやすい解説がQiita内にありました。

* [2標本問題の新展開~古典的手法からカーネル法まで~ - Qiita](https://qiita.com/yuchi_m/items/7132b426d848dc81ad9f)

SVMでよく使われるカーネル法を、確率分布の測度として拡張したものがKernel mean embeddingと呼ばれるもので、2つの確率分布を核再生ヒルベルト空間(RKHS, Reproducing Kernel Hirbert Space)へ写像します。
写像された特徴空間内の2つの確率分布の距離がMMD、だそうです。元々は2標本検定に用いるノンパラメトリックな手法のようです。

論文では以下のように定義しています。

```math
MMD_k(P_Z, Q_Z) = ||\int_Z k(z \cdot)dP_Z(z) - \int_Z k(z \cdot)dQ_Z(z)||_{\mathcal{H}_k}
```

検定で用いる場合にはRKHS上でのノルムの二乗を用いるようですが、ここでは二乗しない値を使うようです。

```math
\mathcal{D}_Z(Q_Z,P_Z) = MMD_k(P_Z, Q_Z)
```
として、係数$\lambda$をかけて計算をします。$\lambda$は大きな数(TF実装では100)から始めて、徐々に減衰させます(自分の実装では未実装)。
MMDはSGDによって求められると論文にあります。尺度としては2つの確率分布の距離であり、それを最小化することでオートエンコーダーから生成される潜在変数の確率分布$P_Z$を、目的の分布$Q_Z$に近づけることができるのだと理解しました。
ノンパラメトリックな手法なので、任意分布の形を$Q_Z$(実装中では正規分布)で近似できる、ということなのだろうと理解しています。

#### inverse multiquadric kernel (IMQ)

自分の理解がどんどん怪しくなってくるのですが、IMQに至ってはいまだによく理解できていません。もうちょっと以下の資料をしっかりと読んで理解したいところです。

* [Inverse Multiquadric (IMQ) function as radial basis
function for plane dynamic analysis using dual
reciprocity boundary element method (PDF)](http://www.iitk.ac.in/nicee/wcee/article/WCEE2012_2668.pdf)

オリジナルの実装ではガウシアンカーネルを用いた手法も選べるようになっていました。

## 出力例

iter 28396:
![image.png](https://qiita-image-store.s3.amazonaws.com/0/31714/e2819020-a709-3e53-55fe-458f77b5d647.png)

## 今後の展望

* λの減衰を実装する
* ~~~WebDNNデモを公開する~~~ (done)
* WAE-GANを実装する
* MMD-RBF(ガウシアンカーネル)を実装する
* ほかのネットワーク構造、パラメータに対応する
* IMQを理解する
* 解説に間違いがあったら直す
俺言語 その25

#概要

俺言語をやってみた。
avrにアセンブラで実装してみた。
３軸、サーボモータをぐりぐり。前編。

#環境

avr studio 4
attiny85 1mhz
tera term
usb-serial

#調査１

SG90サーボモータ

コントロール周波数　５０Hｚ　２０ミリ秒

|角度       |       時間    |
|:-------------|----------------:|
| －９０度             |     ０．５ミリ秒       |
| ０度          |      １．４５ミリ秒       |
| ９０度          |   ２．４ミリ秒    |
電圧　４．５Vから５．０V
消費電流　１００ｍAから６００ｍA(起動時)
PWMでコントロールが一般的

#調査２

attiny 85 PWMピン配置

|ピン      |       タイマー０    | タイマー１|
|:-------------|:---------:|:------:|
| PB0          |    OC0A   | OC1A_|
| PB1          |    OC0B   | OC1A|
| PB2          |   -    | - |
| PB3          |   -    | OC1B_|
| PB4          |   -    | OC1B|
| PB5          |  -     | - |

タイマーは、２個。３軸は、無理。

#調査３

タイマー０、比較Aの周波数

|CS02      |    CS01   | CS00　| 周期　|
|--------:|---------:|----------:|-----------:|
|     0|    0| 1| 1us |
|     0|    1| 0| 8us |
|     0|    1| 0| 64us |

8マイクロ秒の比較A割り込みなら、１０倍で８０マイクロ秒、
２０ミリ秒は、２５０となる。

#調査４

ADCで６ボタン（３軸）の入力

抵抗を５本、直列にする。

#回路図

![image](https://qiita-image-store.s3.amazonaws.com/0/18104/bd7abec2-7e47-91ac-9b8a-bce54e00ebd4.png)


#実装案

変数e,f,gを導入する。
タイマー０の比較A割り込みで、カウントして、設定分でPB2,PB3,PB4を、ON、OFFする。
'=16で、割り込み設定。
実行ループで、割り込みを許可する。
ループからブレークで割り込み禁止する。

|角度       |     設定値     |
|:-------------|----------------:|
| －９０度             |     ６      |
| ０度          |      １８     |
| ９０度          |   ３０   |

以上。
読書メモ: xv6 book - Chapter 2: Page Tables

Page Table は

- address space の複数化 (kernel, user space)
- memory の保護, isolation
- misc： user の stack overflow を unmapped page を挟むことで detect など

を実現する

## Paging Hardware (mmu.h)

1ページは 4K byte.
概念的には 2^20 個の page table entry (PTE) があり、それぞれがページとそのフラグを表す

実際は 2^10, 2^10 の二段階のテーブル。
%CR3 が page directory を指す。page directory の各エントリ (4 byte) は一つの page table page を指す。
page table page の各エントリ (PTE) の値が va の下位ビットと合わせて 物理 address を指す。

### 例
va: `| A(10) | B(10) | C(12) |` とする。
%CR3 + 4A が page dir entry `| D(20) | flag'(12) |` を指す。
`| D(20) | B(10) | 00 |` が PTE `| E(20) | flag(12) |` を指す。
`| E(20) | C(12) |` が va が指す pa である。

flag は、P(present), W(writable), U(user accessible) など

page directory 自体もひとつのページであって、2^10 個の int を持っているから 4M ぴったり。
page table page も同様。

## Kernel virtual memory

```
------------------------ <- 4G
| Mem mapped IO     RW |
------------------------ <- 4G - 32M = DEVSPACE
| unused               |
------------------------ <- KERNBASE + PHYSTOP (=224M)
| free memory       RW | `kinit2` で free
------------------------ <- KERNBASE + 4M
| free memory       RW | `kinit1` で free
------------------------ <- `end`
| kern data         RW |
------------------------ <- `data`
| kern text, rodata  R |
------------------------ <- KERNBASE + 1M = KERNLINK
| Mem mapped I/O    RW |
------------------------ <- KERNBASE = 2G
```

PHYSTOP は物理メモリの量 (決め打ち)
上側の Mem mapped IO は同じ物理アドレスにマップする (direct map)
それ以外は KERNBASE 引いたところにマップする
これにより、カーネルからは va, pa の変換が容易。単に ±KERNBASE するだけ

## Creating address space

実装的には、page が free <-> `freelist` という linked list にエントリが存在
freelist の各エントリは、その page 自体の場所に置かれる

`kfree(va v)` は v にエントリをつくり、freelist に追加する. ちなみに freelist は spin lock で守る.
`kalloc` は freelist の先頭をあげるだけ

main に来た時点では 4M しか map されていなくて、freelist は空。新しい page table の場所を得るために、まず end:KERNBASE+4M を free する。(`kinit1`)

続いて kalloc しながら上記のマッピングが指定された page table を作成し、それにスイッチする (`kvmalloc`)

最後に +4M:+PHYSTOP も kfree してセットアップ完了(`kinit2`)

## User part of an address space

```
----- <- 2G
Heap (はじめは0)
Stack: 4M で固定
Stack guard: 4M
Data
Text
----- <- 0
```

とする。stack には、argv, argc, dummy return value (for _start?) がつまれる
argv[0]の値, ..., argv[0], ..., argv, argc, 0xFFFFFFF という感じ

`exec` の実装:

- 新しい page table を `setupkvm` でつくる。(= カーネル部分は同じようにマッピングする)
- kalloc しながら上のような low address からのマッピングを追加
    - stack guard は U フラグを外しておく
- ELF binary の text, data を貼る
    - user va から pa を経由して kernel va への変換をし、そこに貼る
    - そのプロセス以外の場所に貼られたらやばいのでしっかりチェック
- `p->gpdir` を 新しい page table に切り替え
- `p->tf` (trap frame) の eip <- elf.entry, esp を適切に設定
- `switchuvm(p)` で page table を切り替え
- 古い page table、その指す user addresses を free

`sbrk` (heap を増やす/減らすやつ) の実装:
p->sz, p->pgdir を操作して、必要があれば mapping を追加、削除すればよい
操作後、古い mapping が TLB に残ることを防ぐため、`switchuvm` を再び呼んで %CR3 を設定し直す
削除した mapping が残っていると、remap された他のCPUのプロセスのメモリを見れてしまう

## Real world

xv6 に欠けているもの

- Demand paging from disk
- CoW fork
- Shared memory
- Lazy page allocation
- Automatically extending stack
- RAMサイズの推定