OmniAICreator/Qiita-1.07M huggingface dataset:
誰でもわかるメモリ管理入門:01

# はじめに

OSのメモリ管理について、自分自身の復習も兼ねて、誰でもわかるような解説に挑戦してみます。「仮想メモリって何？」「キャッシュって何？」といった方向けです。

メモリはOS（Windows、Linux、macOS etc...）が管理しています。そのため、OSが何をやっているのかをご理解いただければ、この投稿の目的は達成です。

ちょっと本業が多忙のため、何回かに分けてのんびり進む予定です。あらかじめご了承ください。

## （追記）LT動画のお知らせ

この記事は3本に分かれていますが、それらをひとまとめにして（少しだけ割愛して）、[Easy Easy](https://easy2.connpass.com/)というエンジニアリング コミュニティのLTイベントでお話させていただきましたので、その時の動画とスライド資料をリンクしておきます。
この記事のLTは15分ちょっとです。1.5倍で再生してもだいたい聞き取れたので10分くらいでいけます。Qiitaの記事を3本も読むのは面倒という方はこちらをぜひ！スライド資料もリンクしておきます。

[YouTube（スライド＋音声）](https://youtu.be/zw11L8a7QTY?t=3072)

[Speaker Deck（スライドのみ）](https://speakerdeck.com/segavvy/memoriguan-li-wan-quan-nili-jie-sita)

以下、本題です。

# メモリの管理

前述のように、メモリはOSが管理しています。そのため、みなさんが書いているプログラムの中でメモリが必要になっても、勝手に使うことはできません。OSから借りる必要があります。OSは貸し出し依頼を受けたら、空いているメモリを探してプログラムに貸し出してくれます。

OS、メモリ、プログラムの関係を賃貸のアパートに例えてみました。

![大家.png](https://qiita-image-store.s3.amazonaws.com/0/139624/72ac6fb4-85e7-f4aa-ab7e-e33cf8f6fed1.png)

![人.png](https://qiita-image-store.s3.amazonaws.com/0/139624/51779646-5571-0e23-172a-0283e7e70944.png)

「あれ？いちいちOSから借りたりしてないよ、`new　hoge[123]`とか`malloc(456)`とか`fugo = [7, 8, 9]`とかやれば普通にメモリ使えるし」

そう思われる方もいるかも知れませんが、お使いの開発言語が内部でOSとの貸し借りの手続きをやってくれているのです。

# ファイルの管理

メモリ管理入門なのですが、ファイルについても少し解説します。

ファイルもメモリと同じで、OSが管理しています。そのためプログラムは勝手には使えません。読み込む時も書き込む時も、OSに依頼してやってもらいます。

「OSに頼まずに`fread()`とか`hoge.read()`とか`fugo.readlines()`とかで直接読み込めてるけど」

そうです、お使いの開発言語が内部でOSへの依頼をやってくれています。

また、ファイルの特性上、プログラムはファイルの中身に直接アクセスすることができません。読み込む時は一度メモリに読み込む必要があります。書き込む時も書き込みたい内容をメモリに用意して、そこからファイルへ書き込む必要があります。ファイルはメモリと比べて、この点がちょっと面倒です。

先ほどメモリをアパートの部屋に例えましたが、ファイルは読み書きに時間がかかるので、遠くの倉庫に例えてみました。

![倉庫.png](https://qiita-image-store.s3.amazonaws.com/0/139624/641b1220-ff1a-745d-e0f1-70113d9693d1.png)


ファイルへ書き込む時はこの逆です。大家さん（OS）に頼むと、部屋（メモリ）の荷物（データ）を倉庫（ファイル）まで持って行って（書き込んで）くれます。

# 例えの整理
わかりやすくしようと例えてみましたが、逆にわかりにくくなってきました^^;
一度、整理しておきます。

| 実際       | 例え |
|:-----------------:|:------------------:|
| OS             | 賃貸アパートの大家さん |
| メモリ | アパートの部屋 |
| ファイル | 倉庫 |
| プログラム             | 部屋を借りる人 |
| プログラムが使うデータ             | 荷物 |
| プログラムの処理             | 部屋の中での生活 |

整理しても変わらないですね。とりあえず先に進みます……

# 大家さんの苦悩

大家さんは大変な割に、あまり儲かりません。部屋が6部屋しかないので、6人に貸したらもうそれ以上は家賃収入が増えないのです。
もちろん部屋を増やせば収入は増えます。でもアパートを増やしたりビルに建て替えたりすると、とんでもないお金がかかってしまいます。

![部屋を増やしたい.png](https://qiita-image-store.s3.amazonaws.com/0/139624/7cb0dc42-4afb-e6b6-9466-9bf0b8fefbb9.png)

ちなみに、住人の生活スタイルは実に様々です。昼間は外に出かけていて部屋を空けている人もいますし、夜に部屋を空けている人もいます。1日中部屋にいて何かやっている人もいますし、夜中に一生懸命勉強している人もいます。

![いろいろな住民.png](https://qiita-image-store.s3.amazonaws.com/0/139624/d4e5c8df-2652-737e-5b32-53e6e25367d0.png)

ここで大家さんは、お金をかけずに部屋を増やす、とんでもない方法を思いついてしまいました！

![大家さんのひらめき.png](https://qiita-image-store.s3.amazonaws.com/0/139624/e8724b2b-2e2f-24c6-d8cb-d8ff64bae497.png)

大家さんのアイデアについては、次回の[誰でもわかるメモリ管理入門:02](https://qiita.com/segavvy/items/93dccb21c44b27176582)でご紹介します。
rails5.0のRSpecをAWS CodeBuildで実行するためにnode, MySQL5.7, yarnをインストールしたときのメモ

buildspec.ymlファイルに以下を記述

```yml:buildspec.yml
version: 0.2

env:
  variables:
    RAILS_ENV: "test"
    DB_ROOT_PASSWORD: "password"
    DB_HOST: "localhost"
    DB_PASSWORD: "password"
    DB_SOCKET: "/var/run/mysqld/mysqld.sock"

phases:
  install:
    commands:
      - rm -rf db/seeds/test
      - cp -rf db/seeds/development db/seeds/test
      - gem install bundler
      - bundle install
      - curl -sL https://deb.nodesource.com/setup_6.x | sudo -E bash -
      - sudo apt-get install -y nodejs
      - apt-get install -y gnupg procps
      - export DEBIAN_FRONTEND=noninteractive
      - echo "mysql-server mysql-server/root_password password ${DB_ROOT_PASSWORD}" |debconf-set-selections
      - echo "mysql-server mysql-server/root_password_again password ${DB_ROOT_PASSWORD}" |debconf-set-selections
      - apt-key adv --keyserver ha.pool.sks-keyservers.net --recv-keys 5072E1F5
      - echo "deb http://repo.mysql.com/apt/ubuntu/ trusty mysql-5.7" | tee /etc/apt/sources.list.d/mysql.list
      - sudo apt-get update -y
      - sudo apt-get install -y mysql-server
      - service mysql start
      - mysql --version
      - mysql -hlocalhost -uroot -ppassword -P3306 -e "show databases;"
      - mysql -hlocalhost -uroot -ppassword -P3306 -e "show variables like '%sock%';"
      - mysql -hlocalhost -uroot -ppassword -P3306 -e "GRANT ALL PRIVILEGES on *.* to 'root'@'localhost' IDENTIFIED BY '${DB_ROOT_PASSWORD}'; FLUSH PRIVILEGES;"
      - curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
      - echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
      - sudo apt-get update && sudo apt-get install yarn
      - yarn install
  pre_build:
    commands:
      - bundle exec rails db:setup
  build:
    commands:
      - bundle exec rspec
  post_build:
    commands:
      - echo 'Test completed!'

artifacts:
  files:
    - '**/*'

```

参考URL
- https://dev.mysql.com/doc/mysql-apt-repo-quick-guide/en/#repo-qg-apt-repo-manual-setup
- http://inokara.hateblo.jp/entry/2017/09/12/080818
現在の年月日を”YYYYMMDD”の文字列で取得する。

# 今日の日付を"YYYYMMDD"の文字列で返す関数を作成
## 開発環境
macOS High Sierra
（バージョン10.13.5）
Python3.6.4
Sublime Text

## 前提条件
ファイルに日付で名前をつけたり、ログファイルに日付ごとに項目を入れる際のために作ってみた。

## コード
```python:myFunc.py
import os
from datetime import datetime
from pytz import timezone

#現在の年月日を取得
def presentDay():
	today = datetime.now(timezone('Asia/Tokyo'));
	year = today.year;
	year = str(year);
	month = today.month;
	if not month > 9:
		month = str(month);
		month = "0" + month;
	else:
		month = str(month);
	day = today.day;
	if not day > 9:
		day = str(day);
		day = "0" + day;
	else:
		day = str(day);
	return year + month + day;#文字列で、YYYYMMDDを返す
```

+ まずは、必要なライブラリをインポート。
+ today = datetime.now(timezone('Asia/Tokyo'));<br>
東京の現在の年月日、時分秒、曜日までが
```2018-06-09 21:05:02.219407+09:00
```
というdatetimeオブジェクトの形でtodayの中に格納されています。<br>
また、
```weekday = today.weekday();
```
で、weekdayに曜日が数字の形で格納されます（0〜6：月〜日曜日）。
+ year = str(year);<br>
年をそれぞれdatetimeオブジェクトから、str型にします。
+ 下のif文<br>
月、日については、１桁の場合、0をつけて２桁にしてから、文字列になおします。
+ return year + month + day;<br>
文字列連結をして、それをreturnで返します。
<br>
<br>
<br>
と思ったら、strftimeでもっと簡単に書けた。

```python:myFunc.py
from datetime import datetime
from pytz import timezone

#現在の年月日を取得
def presentDay():
	today = datetime.now(timezone('Asia/Tokyo'));
	presentday = today.strftime("%Y%m%d");
	weekday = today.strftime("%a");
	return presentday, weekday;
```
コメントくださった方々、誠にありがとうございました。
【Jenkins備忘録】Python自動テスト環境構築③jenkins準備編

### jenkinsのインストール
・jenkinsの起動にはjavaが必要なのでOpenJDKまたはOracleJDKをインストールする。

```sh
$ sudo apt-get install -y openjdk-8-jdk
```

・jenkinsの公開鍵の追加とインストールする。

```sh
# 公開鍵の追加
$ wget -q -O - https://pkg.jenkins.io/debian-stable/jenkins.io.key | sudo apt-key add -
$ sudo sh -c "echo 'deb http://pkg.jenkins-ci.org/debian-stable binary/' > /etc/apt/sources.list.d/jenkins.list"

# パッケージ更新
$ sudo apt-get update -y
# jenkinsのインストール
$ sudo apt-get install -y jenkins
```

### jenkinsのセットアップ
・以下のコマンド

```sh
# jenkinsの有効化
$ sudo systemctl enable jenkins

# jenkinsの起動
$ sudo systemctl start jenkins

# jenkinsの初期パスワードを表示
$ sudo cat /var/lib/jenkins/secrets/initialAdminPassword
```

### jenkinsへのログイン

・http://localhost:8080/ へアクセスすると、初期パスワード要求画面が表示されるので、
 　jenkinsの初期パスワードを入力して「continue」ボタンを押下する。

<img src="https://qiita-image-store.s3.amazonaws.com/0/180939/fa7f4b60-94bc-e186-5927-9f0d959fe048.png" width=80%>

・初期パスワードでのログイン後、プラグインの設定について下図のように2択になるので、
　「Select plugins to install」を選択する。(プラグインは後で追加するため)

<img src="https://qiita-image-store.s3.amazonaws.com/0/180939/c892a949-c737-3bff-190b-214a06511a30.png" width=80%>

・プラグイン選択画面で、上段の「None」を選択する。(プラグインを追加しない)
　「None」選択後、「Install」ボタンを押下する。

<img src="https://qiita-image-store.s3.amazonaws.com/0/180939/65feb2cc-8bdd-7881-1650-d0c27fea546e.png" width=80%>

・プラグイン設定画面から遷移した画面で、管理者ユーザーの設定を行う。
　必要な情報を入力後、「Save and Continue」ボタンを押下する。

<img src="https://qiita-image-store.s3.amazonaws.com/0/180939/0f44a836-a2e0-612d-d217-1ff9c2e51514.png" width=80%>

・jenkinsのポート設定は、特にこだわりがなければそのままの設定で「Save and Finish」ボタンを押下する。

<img src="https://qiita-image-store.s3.amazonaws.com/0/180939/77cb7dc1-219c-e880-cc4d-0bc5ab3b1ade.png" width=80%>

・初期設定が完了したので、「Start using Jenkins」ボタンを押下する。

<img src="https://qiita-image-store.s3.amazonaws.com/0/180939/423f1cdb-28a1-667f-df3f-3045478e1317.png" width=80%>

・下図のようにjenkins画面が表示されたらセットアップ完了。

<img src="https://qiita-image-store.s3.amazonaws.com/0/180939/21451bd4-5a9f-e028-c51b-f4fc13462368.png" width=80%>
Intel Turbo Boost Max 3.0 のポップアップを消す

windows10 を使っていると、
表題の通りのポップアップが出るときがある。
これの消し方。

1 タスクトレイより(ツールバーではなく、右下のタスクトレイ。)、同ツールを右クリック。 disabled にしてから、 quit 。
2 win + R キー同時押し。services.msc を検索。
3 ITBMService もしくは Intel(R) Turbo Boost Max 3.0 Technology Application Service という名前のを探し、無効化。

4 win + R キー同時押し。appwiz.cpl を検索。アプリケーションとの追加と削除より、同ツールをアンインストール。
4 再起動。

以上。
Archlinuxに東京理科大学のVPN接続するための道具を導入

# Cisco Anyconnect Vpnをインストール

(大学のシステムに従う)

一応、その時の導入コマンドを記載すると、

とりあえず、そのどっかのページから`anyconnect-tus-predeploy-linux-3.1.01065-k9.tar.gz` をダウンロードし以下に記載した手順で展開した。

```bash
$ tar zxvf anyconnect-tus-predeploy-linux-3.1.01065-k9.tar.gz 
$ cd anyconnect-3.1.01065/vpn 
$ sudo ./vpn_install.sh 
```

だがしかし、大学から配布されているバージョンがFURUIので、
>/opt/cisco/vpn/bin/vpn_uninstall.sh: 行 173: /etc/rc.d/vpnagentd: そのようなファイルやディレクトリはありません
>rm: '/etc/rc.d/vpnagentd' を削除できません: そのようなファイルやディレクトリはありません
>install: 通常ファイル'/etc/rc.d/vpnagentd' を作成できません: そのようなファイルやディレクトリはありません

現在使用している環境では動いてくれなかった。

環境＝Manjaro linux17.1.10

(なんで動かないのよ、大学のマニュアル嘘じゃん)

## GUIで動かない

```bash
$ /opt/cisco/anyconnect/bin/vpnui
/opt/cisco/anyconnect/bin/vpnui: error while loading shared libraries: libpangox-1.0.so.0: cannot open shared object file: no such file or directory
```

なので、

```bash
$ sudo pacman -S pangox-compat
```

で`pangox`を入れた  
その後、

```bash
$ /opt/cisco/anyconnect/bin/vpnui
```

で確認したら、何もでなくなった。
(だが、動いてくれない結果は変わりない)

## 依存ソフトウェア不足を疑う

```bash
$ sudo pacman -S networkmanager-openvpn networkmanager-openconnect
```

で、不足してるっぽいのを入れた。
(でも動かないんだよ助けて)

## 原因は貴様か

`/opt/cisco/anyconnect/vpn/vpnagentd`があるのでこいつを起動すれば`vpnui`が一瞬で消えてしまう問題が解決するのでは。

ということで、

```bash
$ /opt/cisco/anyconnect/vpn/vpnagentd
```

をすると、うまく立ち上がったので、喜びを(全力で噛み締めた。)

## Systemdへの旅行

ここで、自動化に挑んだ

```ini:vpnagentd.service
[Unit]
Description=vpnagentd
Requires=network.target

[Service]
Type=simple
ExecStart=/opt/cisco/annyconnect/bin/vpnagentd
ExecStop=/usr/bin/pkill vpnagentd
RemainAfterExit=yes

[Install]
WantedBy=graphical.target
```

システムサービスで`/etc/systemd/system`に保存して

```bash
$ sudo systemctl daemon-reload
$ sudo systemctl enable vpnagentd.service
$ sudo systemctl start vpnagentd.service
```

で地球に帰ってきた。
Macのスクリーンショットにまつわる工夫

# デフォルトでゴミ箱に作成

Macでスクリーンショットを撮る機会ってなかなかある。
でも、どこかに貼り付けたらそのあとは要らなくなるので捨てちゃうことが多い。

スクリーンショットを撮るとデフォルトで `~/Desktop` に作成されてしまう。
**デスクトップには何も置かない派**なので、つらたにえんの無理茶漬け...。

そこで、ゴミ箱に作成されるようにしたら捗った :v:

> ```terminal:command
> $ defaults write com.apple.screencapture location ~/.Trash
> ```
> > まっさらなデスクトップの様子（うつくしい）
> > <img width="1680" alt="Screen Shot 2018-06-09 at 20.16.35.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/13842/85c08190-9230-5fd1-f2bb-c81c01b14c0e.jpeg">

お好みで `~/Documents/screenshots` とか、pathは工夫したらいいのでは？ :relaxed:


# 余談
- Alfred ユーザーなら**`trash`**と入力すればゴミ箱を即座に開くことができる :v:

> <img width="1680" alt="Screen Shot 2018-06-09 at 20.29.25.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/13842/7fd13963-7192-a399-088a-c40fa5b4fc75.jpeg">

- Retinaディスプレイ時代になった今、デフォルトだと `png` 形式でファイル容量が**デカすぎる**。
ウィンドウ単位でスクショした時の**あのカッコいいシャドウの透過**が不要ならば `jpg` 形式に変更すると吉。

> ```terminal:command
> $ defaults write com.apple.screencapture type jpg
> ```
> > この差はなかなか...
> > ![Screen Shot 2018-06-09 at 20.33.35.jpg](https://qiita-image-store.s3.amazonaws.com/0/13842/0242516c-5285-2d32-624f-f09a78391f54.jpeg)

おしまい。
Wordpressのメールアドレス変更　メールが来ない

Wordpressのメールアドレスの変更

3箇所ある。

- ユーザ→メールアドレス（必須）
- 設定→一般→メールアドレス
- お問い合わせ(プラグイン)→コンタクトフォーム→メール→送信先

変更するとメールを送信しました。
「sample@gmail.comへのメールアドレス変更が承認待ち中です。」
という表示がでるがメールアドレスが来ない...。

探すと同じような人がいた。

# 結論
1時間30以上かかったという人がいた。

気長に待つのが吉。笑
Chromeのエンコーディング機能削除への対応策

#大変だ#
PHPの画面表示のテスト（ちょっと特殊なことをしていて）してChromeで表示をしてみたところ、文字化けをしていた。
以前までは、「設定」から変更可能だった様ですが、現在消えていた。

#Chlomeの拡張機能を追加#
[テキストエンコーディング](https://chrome.google.com/webstore/detail/set-character-encoding/bpojelgakakmcfmjfilgdlmhefphglae?utm_source=chrome-app-launcher-info-dialog)

*Googleのプラットフォームの心優しき方がコメントされていて、そのリンクから探せました。

#操作方法#
当該文字化けページを右クリック
↓
テキストエンコーデイングを選択
↓
表示させたいエンコーデイング先を選ぶ
（今回はUnicode(UTF-8))

<img width="535" alt="スクリーンショット 2018-06-09 20.00.48.png" src="https://qiita-image-store.s3.amazonaws.com/0/191338/e27fb4e5-d701-d55e-862b-394864e93561.png">

文字化けが…
<img width="359" alt="スクリーンショット 2018-06-09 20.00.17.png" src="https://qiita-image-store.s3.amazonaws.com/0/191338/4e461418-d066-b9c7-e864-cc39acd6542b.png">

解決･:*+.\(( °ω° ))/.:+

<img width="239" alt="スクリーンショット 2018-06-09 20.01.04.png" src="https://qiita-image-store.s3.amazonaws.com/0/191338/7d1f4959-fb35-4a0f-c32b-a5d3298b5cea.png">

#使った拡張機能#
[テキストエンコーディング](https://chrome.google.com/webstore/detail/set-character-encoding/bpojelgakakmcfmjfilgdlmhefphglae?utm_source=chrome-app-launcher-info-dialog)
railsでbootstrapテンプレートを使う時に躓いた事

作っているwebアプリのtopページをbootstrapテンプレートですれば楽という事なので導入する事に。
無料でレスポンシブ対応してるのもあります。

・課題
初めてbootstrapテンプレートを使う上で、色々つまずいていて、それらの解決。

まずは
[railsでbootstrapのテンプレートを使用する方法](http://now-is-the-time1014.com/programming/post-613/)
を参考にすすめていく。
+で
[﻿Rails5にbootstrapを導入する - write ahead log](http://twinbird-htn.hatenablog.com/entry/2018/05/11/193520)
を参考に。

ここでエラーが。

・問題1

```
Sass::SyntaxError in StaticPages#index

Showing 

/home/ubuntu/workspace/scout_me/app/views/layouts/application.html.erb where line #7 raised:

Invalid CSS after "...trap-sprockets"": expected "{", was ";"
```
![テンプレート.PNG](https://qiita-image-store.s3.amazonaws.com/0/232561/7ec79ad1-924d-5b8c-a0c5-9967156f1171.png)

/views/layouts/application.html.erbの７行目辺り　→

```erb
<head>
    <title>ScoutMe</title>
    <%= csrf_meta_tags %>

    <%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload' %>
    <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
  </head>
```

assets/stylesheets/application.scssの16行目辺り　→　

```scss
// "bootstrap-sprockets" must be imported before"bootstrap"and"bootstrap/variables"
@import "bootstrap-sprockets";
@import "bootstrap";
```

・問題１の解決
*= require font-awesome　をassets/stylesheets/application.scssに書くという事でしたが
[stackoverflow](https://stackoverflow.com/questions/35741974/invalid-css-after-trap-sprockets-expected-selector-or-at-rule-was-impo)
を見ると、書いていない。ですので、コメントアウトしてみる。
更にbootstrapでは<div class="container">が必要みたいなので

```views/layouts/application.html.erb
 <body>
   <div class="container">
    <%= yield %>
   </div>
 </body>
```

のように付け加える。すると、エラー解決しました。

・問題２
画像やjavascriptが表示されない。
![bootstrap.PNG](https://qiita-image-store.s3.amazonaws.com/0/232561/f0ea4e66-9a58-711f-64b1-9cf85864633c.png)


例えば、ダウンロードしてassets/javascriptに移動させたコードを見てみると
![テンプレート.PNG](https://qiita-image-store.s3.amazonaws.com/0/232561/2e29b293-0f98-54b3-f0a0-e4a740e25c6e.png)

jQueryの部分にエラーが出ている。

・問題２の解決
stylesheet_link_tagにテンプレートのCSSも読み込むように,'magister'と追加した。Rails5は記述方法がRails4までとは違うみたい。

```views/layouts/application.html.erb
<%= stylesheet_link_tag    'application','magister', media: 'all', 'data-turbolinks-track': 'reload' %>
```
しかし、まだエラーが起きる。config/initializers/assets.rb　にアセットパイプラインのコンパイル対象に追加しろとのこと。

```config/initializers/assets.rb
Rails.application.config.assets.precompile += %w( magister.css )
```

とする事でエラーは取れ、bootstrapテンプレートを適用できました。
一度アセットパイプラインを体系的に学ぶ必要があるなと思いました。

とりあえず動いてるのでjQuery等のエラーは後回しにして先に進みたいと思います。

・補足
bootstrapテンプレートを導入する時に index.html　等があると思いますが、Railsなのでindex.html.erbと変更しました。
Ctrl+Cで終了できるけど切りのいいところまでは待つコンソールアプリ

今回はWindowsコンソールアプリで。他でもできるかもしれんけど。

コンソールアプリは、Ctrl+Cで処理を中止できるのはご存知だと思います。
でも、大事な処理の途中で止まるのは困るわけで。

Ctrl+Cで処理を中止しようとするとConsole.CancelKeyPressイベントが来るので、そこで中止を中止することができます。

```cs:Program.cs
using System;
using System.Threading;

namespace ExitTiming
{
    class Program
    {
        private bool running = true;

        private void Run()
        {
            // 中断の割り込みがあったときのイベントを受け取る
            Console.CancelKeyPress += Console_CancelKeyPress;

            // 続く限り続く
            while (running)
            {
                // 動いてるアピール
                Console.WriteLine(DateTime.Now);

                // 何か時間のかかる処理のつもり
                Thread.Sleep(5000);
            }
        }

        private void Console_CancelKeyPress(object sender, ConsoleCancelEventArgs e)
        {
            // 中断を受け付けましたアピール
            Console.WriteLine("Ctrl+C");

            // もう頑張らなくていいことをメイン処理に伝える
            running = false;

            // 今は終わらんよと伝える
            e.Cancel = true;
        }

        static void Main(string[] args)
        {
            new Program().Run();
        }
    }
}
```

Windows 10
Visual Studio 2017
.NET Framework 4.6.2
C#
Amazon Linux からメールを送信する（PHPを利用した場合）

Amazon Linux 上の postfix経由で amazon SES からメール送信を行ったが、
mb_send_mail を利用した場合 From: のアドレスを設定しても　MTA　にはそのアドレスが設定されていなかった。

http://php.net/manual/ja/function.mb-send-mail.php

マニュアルを見ると
*通常、これは追加のヘッダ（From、Cc、Bcc）のために用いられます。*
と記載されている。今まで　第4パラメータの header だと思っていたが、
実は第5パラメータの additional 部分でFORMを指定する必要があるらしい。

なので、

```
mb_send_mail( $to, $title, $body, $header, '-f hogehoge@gmail.com')
```

でhogehogeが認証されていればメールが送られる模様。
[学習用]Rails5 Ubuntu Vagrant Postgresql でデータベースを初期化したとき今まで使ってたRailsのデータベースをどうやって使うか

練習用で作成したPostgresql。
パスワードが一部わからなくなり、テストで増え続けたデータベースを一新するのにアンインストールして再インストールしました。

問題だったのは、順調にテストアプリを作っていた1つのアプリにPostgresqlを使っていたこと。

どうなるか不安だったが、簡単に解決した。
※データは全部削除されます。本番稼働している人は無理。
　rake db:seed でテスト用一括で入る。

#手順
##postgresql停止
```
$ sudo pg_dropcluster --stop 9.5 main
```

##postgresqlアンインストール
```
$ sudo apt-get remove --purge postgresql postgresql-9.5
```

#postgresqlインストール 準備
```
$ sudo sh -c "echo 'deb http://apt.postgresql.org/pub/repos/apt/ xenial-pgdg main' > /etc/apt/sources.list.d/pgdg.list"
$ wget --quiet -O - http://apt.postgresql.org/pub/repos/apt/ACCC4CF8.asc | sudo apt-key add -
```
ここは前に作ってあるはずなので飛ばす。

##postgresqlインストール
```
$ sudo apt-get install postgresql postgresql-9.5
$ sudo apt-get update
```

#Postgres ユーザーへスイッチ
```
$ sudo -u postgres -i
postgres@vagrant:~$ createuser -d -U postgres -P pguser
Enter password for new role: 任意のパスフレーズを入力
Enter it again: 再度同じパスフレーズを入力
```

#Railsでデータベースを作成
```
$ rake db:create
$ rake db:migrate
$ rake db:seed
$ rails s
```

これだけで、Postgresqlでデータを接続していたアプリは
エラーにならず接続できました。
全部テストデータなので全く問題なかった。
GDBで利用するコマンド覚書

## コマンド
実行

```console
(gdb) r
(gdb) r 引数
```

途中でフック

```console
gdb -p プロセスID
```

ブレークポイント

```console
(gdb) b 関数名
(gdb) b ファイル名:行数
```

確認

```
(gdb) info break
```

再開

```console
(gdb) c
```

ステップ実行

```console
(gdb) n
```

情報確認
(特にp *で型のわかっている構造体の中身が見えるので、詳しくないコードのデータ遷移確認の為に使う)

```console
(gdb) p 変数名, アドレス
(gdb) p (キャスト)アドレス
```

死んだらとりあえずbtでバックトレース
※アドレス直値でもキャストすれば中身が見えるのが便利。

```console
(gdb) bt
```

固まったら

```console
(gdb) info stack
```

## 注意

中身を細かく見るなら、-g -O0でコンパイルするのを忘れずに

## 参考:

[【電脳】gdbでどこで無限ループにはまっているか解析する手順](https://srad.jp/~t-nissie/journal/587455/)
WordPressで「ご利用中のホスティング環境は画像の回転機能に対応していません。」メッセージの対処法

WordPressの投稿画面で画像を編集しようとすると表題のメッセージが出力して編集ができない場合。

phpの画像変換モジュールが入っていなかったので入れる。

```sh
//確認
yum list installed | grep php

yum install php-gd
```
その後、webサーバを再起動。
私はEC2を再起動した。

参考
[WordPress で画像の編集ができない場合の対処法 \| 気になることブログ](https://tattsun1213.com/blogs/kininarukotoblog/it/post-229)
マルチスレッドの各スレッドでnumpyの乱数seedを固定する

環境：python 3.6, numpy 1.14

DeepLearning関係で、マルチスレッドで学習を回すアプリを書いていたのですが、実験結果の再現性を確保するために各スレッドで乱数シードを固定しようとしました。
Threadのクラスのコンストラクタでnp.random.seed(N)をやってあげたのですが、うまくいきませんでした。

イメージ↓

```python
import threading
import numpy as np
import time


class learningThread(threading.Thread):
    def __init__(self, tag):
        super(learningThread, self).__init__()
        self.tag = tag
        np.random.seed(5) # 乱数固定したつもり
 
    def run(self):
        for i in range(5):
            # ここで学習してるイメージ
            r = np.random.randint(100)
            print(self.tag, "loop:", i, "rand:", r)
            time.sleep(1)


def main():
    th1 = learningThread("thread-0")
    th2 = learningThread("thread-1")
    th1.start()
    th2.start()


if __name__ == '__main__':
    main()

# 実行結果
# thread-0 loop: 0 rand: 44
# thread-1 loop: 0 rand: 47
# thread-0 loop: 1 rand: 64
# thread-1 loop: 1 rand: 67
# thread-0 loop: 2 rand: 67
# thread-1 loop: 2 rand: 9
# thread-0 loop: 3 rand: 83
# thread-1 loop: 3 rand: 21
# thread-0 loop: 4 rand: 36
# thread-1 loop: 4 rand: 87
```

推測するに、マルチスレッド上では乱数生成器はグローバルなもの1つしかなく、np.random.seedではそのSeedを初期化するので、結局各スレッドで乱数が揃うことはない、という挙動です。
（マルチプロセスだったらうまくいくんだろうな）

じゃあどうすればいいのかと調べたら、乱数生成器自体を作る方法があるんですね。

[numpy.random.RandomState(seed=None)](https://docs.scipy.org/doc/numpy/reference/generated/numpy.random.RandomState.html)


RandomStateのオブジェクトを作って各スレッドに渡してあげれば、スレッドそれぞれが乱数生成器を持ってくれます。
RandomStateのコンストラクタ引数にseedがあるので、これを指定してあげれば乱数固定できます。
そして各スレッドでは渡されたRandomStateを使って乱数生成すれば、乱数が揃いますね。
→ 2018/6/11 LearningThreadクラスにRandomStateを引数で渡す必要はなかったので修正しました。

```python
import threading
import numpy as np
import time


class learningThread(threading.Thread):
    def __init__(self, tag):
        super(learningThread, self).__init__()
        self.tag = tag
 
    def run(self):
        rst = np.random.RandomState(5) # スレッド専用の乱数生成器をseedを指定して作る

        for i in range(5):
            # ここで学習してるイメージ
            r = rst.randint(100) # 専用の乱数生成器で乱数を生成
            print(self.tag, "loop:", i, "rand:", r)
            time.sleep(1)


def main():
    # RandomStateオブジェクトをseedを指定して作成し、各スレッドに渡す
    th1 = learningThread("thread-0")
    th2 = learningThread("thread-1")
    th1.start()
    th2.start()


if __name__ == '__main__':
    main()

# 実行結果
# thread-0 loop: 0 rand: 99
# thread-1 loop: 0 rand: 99
# thread-1 loop: 1 rand: 78
# thread-0 loop: 1 rand: 78
# thread-1 loop: 2 rand: 61
# thread-0 loop: 2 rand: 61
# thread-1 loop: 3 rand: 16
# thread-0 loop: 3 rand: 16
# thread-1 loop: 4 rand: 73
# thread-0 loop: 4 rand: 73
```

めでたしめでたし。
Railsのform_tagでS3に画像をアップロードする機能を作った話

2018/06/09 記事を作成

# はじめに
Ruby on Railsでよく使うformと言えば `form_for` ですね。
このformは扱うデータが何かしらのModelに基づいていることを前提としていますが、S3等のクラウドストレージにデータを保存したい場合、Modelを作らないという選択肢もあるかと思います。
そこで `form_for` ではなく `form_tag` でformを作ろうと思ったのですが、筆者が調べた範囲では `form_tag` でS3にデータをアップロードする的な記事はあんまりありませんでした。
そこで、今回筆者が実装した内容を以下に簡単にまとめようと思います。
この記事がどこかの誰かさんの参考になれば幸いです。

# 環境
OS: Ubuntu 16.04 LTS
ブラウザ: Chromium 66.0.3359.181（Official Build）Built on Ubuntu

# S3とは
> Amazon Simple Storage Service はインターネット用のストレージサービスです。また、ウェブスケールのコンピューティングを開発者が簡単に利用できるよう設計されています。
> 
> Amazon S3 のウェブサービスインターフェイスはシンプルで、いつでも、ウェブのどこからでも容量に関係なくデータを格納および取得できます。これにより、すべての開発者が、スケーラブルで信頼性が高く、かつ高速で安価なデータストレージインフラストラクチャを利用できるようになります。このインフラストラクチャは、Amazon が使用しているウェブサイトのグローバルネットワークと同じものです。このサービスの目的は、規模の拡大や縮小のメリットを最大限に活かし、開発者に提供することです。

（[Amazon S3 とは何ですか？ - Amazon Simple Storage Service](https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/dev/Welcome.html)より引用）

※本記事ではS3のバケットは既にあるものとして話を進めます。

# 実装

## View
Viewはこんな感じ。
Slimで記述しています。

```ruby:image_upload.html.slim
= form_tag({:action => "upload_image"}, :multipart => true) do
  = file_field_tag :file, accept: 'image/jpg,image/jpeg,image/png'
  = submit_tag "アップロード"
```

ここで重要なのは、**multipartオプションを省略しない**ことです。
`form_for` では省略しても大丈夫なのですが、 `form_tag` の場合は省略してしまうとファイル名が文字列として渡るだけでファイル本体が取得できません。

ちなみに、 `file_field_tag` に `accept` オプションを追加することで画像のみが選択可能となるようにしています。

## Controller
Controllerはこんな感じ。

```ruby:images_controller.rb
def upload_image
  source = params[:file]
  notice = "画像を選択してください。"

  if source
    file_name = source.original_filename

    s3 = Aws::S3::Resource.new(region: "ap-northeast-1")
    obj = s3.bucket("my_bucket").object("images/#{file_name}")

    obj.put({
      body: source.read,
      content_type: 'image/jpeg'
    })

    notice = "#{file_name}を保存しました。"
  end

  redirect_to images_path, :notice => notice
end
```

Aws::S3::Objectの `put` メソッドを使用してS3に画像をアップロードしています。
また、 `redirect_to` に `notice` オプションを追加することで画像アップロードの成否を通知しています。

ちなみに、 `params[:file]` で取得したオブジェクトは以下の感じでパラメータが取得できます。

- ファイル名を取得： `params[:file].original_filename`
- コンテンツタイプの取得： `params[:file].content_type`
- ファイルサイズの取得： `params[:file].size`
- ファイル本体の取得： `params[:file].read`

# 参考URL等

本記事の執筆にあたり参考にした順に並べています。

- [【Rails】form_for/form_tagの違い・使い分けをまとめた - Qiita](https://qiita.com/shunsuke227ono/items/7accec12eef6d89b0aa9)
- [Amazon S3 とは何ですか？ - Amazon Simple Storage Service](https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/dev/Welcome.html)
- [form_tag - リファレンス -  - Railsドキュメント](http://railsdoc.com/references/form_tag)
- [railsで画像などファイルをアップロードする方法 | Railsの小技 | DoRuby](https://doruby.jp/users/katsuo_on_rails/entries/rails_)
- [AWS SDK for Ruby を使用したオブジェクトのアップロード - Amazon Simple Storage Service](https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/dev/UploadObjSingleOpRuby.html)
- [redirect_to - リファレンス -  - Railsドキュメント](http://railsdoc.com/references/redirect_to)
- [コントローラ(controller) -  - Railsドキュメント](http://railsdoc.com/controller)
上限を設けずに整数列を生成したい

整数の列を生成するにあたって、基本的には`seq`コマンドでことたりるのですが、欠点がないわけではありません。とりわけ__整数列の生成にあたって上限を設けたくない場合__。`seq`は「上限の数までの整数列を出力する」コマンドなので、無制限にひたすら整数列を作るにはやや不向きです。たとえば`seq 999999`というようにして、上限に巨大数を指定すれば、疑似的に求める機能を実現することもできますが、やや不格好な印象を受けます。

では「上限を設けずに整数列を生成し続けたい」という際にはどうすればよいのかというと、次のようなイディオムを利用することができます。

```bash
yes | awk '{print NR}'
```

`awk`の`NR`は組み込み変数で、読み込んでいる行数を保持します。つまり1行読み込むたびに`NR`の値は1,2,3,4...というように増えていくわけで、これは求める整数列にほかなりません。そして「読み込むための行」をどのように生成するかですが、これは`yes`コマンドを利用しているというわけです。
npmでグローバルインストールしたモジュールのコマンドが使えなかった時に解決した方法

npmで複数のモジュールをインストールした際に、`command not found`となってしまうことが多々あった.

##解決手順
###1.パスを通すべき位置を確認
細かい部分はわからないのだが、グローバルインストールされるモジュールのbinにパスを通す必要があるようで

```
npm bin -g
/Users/user_name/.npm-global/bin
```

のようにする.
この結果、自分の場合は`/Users/user_name/.npm-global/bin`へパスを通す必要があると判明.


###2.先程確認したパスをbash_profileへ書き込む

```
vi ~/.bash_profile
```

として開いたファイルの末尾に、

```
PATH=$PATH:/Users/user_name/.npm-global/bin
```

を追記すれば良い.

###3.bash_profileの変更を反映

コマンドプロンプトのタブを新たに開けば良い.

```
source ~/.bash_profile
```

以上のコマンドでも変更の反映が可能らしい.

##参考ページ
色々
(のちに追記する予定)
UbuntuにNode.js（npm,ejs and express）を入れる

vagrantとvirtual boxを使って仮想環境を構築することが必要になったが、何度も失敗したので、書いておく。

まずUbuntuを入れる。
コマンドプロンプトで任意のファイルに

```
vagrant init ubuntu/trusty64
vagrant up
```
これでそのファイルにvagrantfileが作成される。

そのまま
[https://nodejs.org/ja/download/package-manager/](https://nodejs.org/ja/download/package-manager/)
に載っている方法でNode.jsをインストール

```
curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash -
sudo apt-get install -y nodejs
```

これでNode.jsのv.8系とnpmのある程度のバージョンがインストールされている。
バージョンの確認は

```
node -v //Node.jsのバージョン
npm -v //npmのバージョン
```

で確認が可能。

Node.jsのパッケージ（モジュール）のejsやexpressをインストールする。

```
npm install -g ejs
npm install -g express
```
でインストールは可能。
私の環境だと-gをつけるかどうかで、Node.jsが反応してくれなかったので、-gを付けた。
グローバル環境になるのがあんまりよくないとか言われたが、動かないと話にならないので、そこは自由に。

この状態でejsやexpressを動かそうとしても、エラーが出るときがある。

```
Cannot find module 'express'
```
みたいな感じで。
こうなったら

```
npm init
npm install --save express
```
みたいにしとくと、なんか知らんけど動くようになった。
tomcat 下启用SSL包含证书生成

参考配置文章：
http://skyeywolf.blog.163.com/blog/static/95727236201021194716320/

第一步生成证书：
将下面拷贝到bat文件，执行即可（路径和证书别名可更改）
※ 同时在bat文件同级目录下创建文件prompt.ini并在文件中输入y和回车。

@ECHO off
chcp 936

set CACERTS_ALIAS="server2"
set CLIENT_ALIAS="client2"

set ROOT_PATH="D:\tools\tomcat\keys"
set PASS="changeit"

rem ECHO %ROOT_PATH%

rem tomcat server tomcat.keystore genkey bat
keytool -genkey -v -alias %CACERTS_ALIAS% -keyalg RSA -keystore %ROOT_PATH%\tomcat.keystore -dname "CN=localhost,OU=cn,O=cn,L=cn,ST=cn,C=cn" -storepass %PASS% -keypass %PASS%
rem clinet gencert cient.p12 bat
keytool -genkey -v -alias %CLIENT_ALIAS% -keyalg RSA -storetype PKCS12 -keystore %ROOT_PATH%\client.p12 -dname "CN=client,OU=cn,L=cn,ST=cn,C=cn" -storepass %PASS% -keypass %PASS%

rem gen tomcat cert file tomcat.cer from tomcat.keystore keystore 
keytool -export -alias %CACERTS_ALIAS% -keystore %ROOT_PATH%\tomcat.keystore -storepass %PASS% -rfc -file %ROOT_PATH%\tomcat.cer
rem gen client cert file client.cer from client.p12 keystore 
keytool -export -alias %CLIENT_ALIAS% -keystore %ROOT_PATH%\client.p12 -storetype PKCS12 -storepass %PASS% -rfc -file %ROOT_PATH%\client.cer

rem import clinet.cer to tomcat.keystore trusted cert
keytool -import -alias %CLIENT_ALIAS% -v -file %ROOT_PATH%\client.cer -keystore %ROOT_PATH%\tomcat.keystore -storepass %PASS% < prompt.ini
rem import tomcat.cer to cacerts trusted cert(client trusted cacerts)
keytool -import -alias %CACERTS_ALIAS% -v -file %ROOT_PATH%\tomcat.cer -keystore "%JAVA_HOME%\jre\lib\security\cacerts" -storepass %PASS%  < prompt.ini

rem check if client.cer successfully imported into tomcat.keystore
keytool -list -keystore %ROOT_PATH%\tomcat.keystore -storepass %PASS%  >  %ROOT_PATH%\tomcat.keystore_list.log

rem check if tomcat.cer successfully imported into client trusted cacerts
keytool -list -keystore "%JAVA_HOME%\jre\lib\security\cacerts" -storepass %PASS% > %ROOT_PATH%\jdk_cacert_trusted.log

echo successfully 

pause 

第二步：tomcat配置文件中开启https服务(只需要将conf/server.xml中的如下部分的注释放开，
并添加对应证书文件和密码)
    <Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
               maxThreads="150" scheme="https" secure="true"
               clientAuth="false" sslProtocol="TLS"
				keystoreFile="D:\tools\tomcat\keys\tomcat.keystore"
				keystorePass="changeit"
                              truststoreFile="D:\tools\tomcat\keys\tomcat.keystore"
				truststorePass="changeit"
    />

第三步：重启tomcat，并尝试访问https:localhost:8443
※如果报错 PKIX validate certificate fail的话，就说明是没有把服务器端的证书加到客户端的trust keystore中（一般默认是jre\lib\security\cacerts）
※clientAuth="false" 是否开启双项认证，如果为true，必须验证客户端的证书，
            false：客户端不设置证书也可以访问
※生成证书的时候要确认是否使用和tomcat一致的jdk
CentOS7 に wkhtmltopdf をインストールする

HTMLをPDFに変換するため [wkhtmltopdf](https://wkhtmltopdf.org) を CentOS7に導入します。

# 環境

- CentOS 7.5
- wkhtmltopdf 0.12.4

# 導入

```
$ sudo yum -y install libXrender libXext
```

libXrender, libXextは必須なので入れておく。

```
$ wget https://github.com/wkhtmltopdf/wkhtmltopdf/releases/download/0.12.4/wkhtmltox-0.12.4_linux-generic-amd64.tar.xz
$ tar Jxfv wkhtmltox-0.12.4_linux-generic-amd64.tar.xz

$ sudo cp wkhtmltox/bin/wkhtmltoimage /usr/local/bin/
$ sudo cp wkhtmltox/bin/wkhtmltopdf /usr/local/bin/

$ wkhtmltoimage --version
wkhtmltoimage 0.12.4 (with patched qt)
$ wkhtmltopdf --version
wkhtmltopdf 0.12.4 (with patched qt)
```

バージョンが表示されればインストール完了です。

```
$ rm -f wkhtmltox-0.12.4_linux-generic-amd64.tar.xz
$ rm -rf wkhtmltox
```

不要なファイルは削除する。

# PDF出力確認

```
$ wkhtmltopdf http://www.yahoo.co.jp yahoo.pdf
```

<img width="726" alt="スクリーンショット 2018-06-09 17.40.06.png" src="https://qiita-image-store.s3.amazonaws.com/0/52879/51bf7084-7959-4180-e44f-3c4a3d4c06c4.png">

するとこのように文字化けします。

# 日本語フォントを導入

フォントの一覧を表示。

```
$ fc-list
/usr/share/fonts/lyx/eufm10.ttf: eufm10:style=LyX
/usr/share/fonts/lyx/cmsy10.ttf: cmsy10:style=LyX
/usr/share/fonts/lyx/msam10.ttf: msam10:style=LyX
/usr/share/fonts/lyx/cmmi10.ttf: cmmi10:style=LyX
/usr/share/fonts/lyx/wasy10.ttf: wasy10:style=LyX
/usr/share/fonts/lyx/esint10.ttf: esint10:style=LyX
/usr/share/fonts/lyx/rsfs10.ttf: rsfs10:style=LyX
/usr/share/fonts/lyx/stmary10.ttf: stmary10:style=LyX
/usr/share/fonts/lyx/cmex10.ttf: cmex10:style=LyX
/usr/share/fonts/lyx/msbm10.ttf: msbm10:style=LyX
/usr/share/fonts/lyx/cmr10.ttf: cmr10:style=LyX
```

今回は [IPAフォント](https://ipafont.ipa.go.jp/old/ipaexfont/download.html) をインストールします。

```
$ wget http://dl.ipafont.ipa.go.jp/IPAexfont/IPAexfont00301.zip
$ unzip IPAexfont00301.zip 
$ sudo mv IPAexfont00301 /usr/share/fonts
$ rm -f IPAexfont00301.zip
$ fc-cache -fv
```

フォント一覧を再度表示して確認

```
$ fc-list
fc-list
/usr/share/fonts/lyx/eufm10.ttf: eufm10:style=LyX
/usr/share/fonts/lyx/cmsy10.ttf: cmsy10:style=LyX
/usr/share/fonts/lyx/msam10.ttf: msam10:style=LyX
/usr/share/fonts/lyx/cmmi10.ttf: cmmi10:style=LyX
/usr/share/fonts/lyx/wasy10.ttf: wasy10:style=LyX
/usr/share/fonts/lyx/esint10.ttf: esint10:style=LyX
/usr/share/fonts/IPAexfont00301/ipaexg.ttf: IPAexゴシック,IPAexGothic:style=Regular
/usr/share/fonts/lyx/rsfs10.ttf: rsfs10:style=LyX
/usr/share/fonts/lyx/stmary10.ttf: stmary10:style=LyX
/usr/share/fonts/lyx/cmex10.ttf: cmex10:style=LyX
/usr/share/fonts/IPAexfont00301/ipaexm.ttf: IPAex明朝,IPAexMincho:style=Regular
/usr/share/fonts/lyx/msbm10.ttf: msbm10:style=LyX
/usr/share/fonts/lyx/cmr10.ttf: cmr10:style=LyX
```

# PDF再出力確認

```
$ wkhtmltopdf http://www.yahoo.co.jp yahoo.pdf
```

<img width="728" alt="スクリーンショット 2018-06-09 17.49.29.png" src="https://qiita-image-store.s3.amazonaws.com/0/52879/16ea7ca9-71f6-ac85-96a5-c4e7ce07c90c.png">

# HTMLを画像に変換

HTMLから画像に変換することもできます。
`wkhtmltoiamge` コマンドを使います。

```
$ wkhtmltoimage http://www.yahoo.co.jp yahoo.jpg
```

# その他

- [公式ドキュメント](https://wkhtmltopdf.org/usage/wkhtmltopdf.txt)
Amazon linux からメールを送信する。

# Amazon Linux でメールを送信する。
amazon linux でメールを送信しようとしたところ、最初は送信できており安心していたのだが、
翌日送信しようとしたら全く送れなくなっていた。
構成としては
・AWS EC2
・VPC を Direct connect で社内と閉域網を組んでいる。

```echo "test" | mail -s "test" xxxxxx@gmail.com```

これでも送れていたのだが。。。。

原因はこのへんか？
https://dev.classmethod.jp/cloud/aws/ec2-send-email-best-practice/　

 ```tail -f /var/log/maillog```
にてメールを見たところ、
```554 Message rejected: Email address is not verified. The following identities failed the check in region US-EAST-1```
とエラーが吐き出されている。

インターネットへの出口は社内の閉域網から一本だけでドメインのSPFレコードへの追加等も
ややこしいかもしれない。。。

とりあえず下記を参考にPOSTFIXにSESを設定
https://docs.aws.amazon.com/ja_jp/ses/latest/DeveloperGuide/postfix.html

複数のメールアドレスを認証済み状態にして
```echo "test" | mail -s "test" xxxxxx@gmail.com -r yyyy@hogehoge.com```
でメールを送信したところ送信完了。
yyyy@hogehoge.com は認証されたメール出ないとエラーになってしまった。

```sudo postqueue -p```
でメールキューを見ると大量に存在
```sudo postsuper -d ALL```
でたまってるメールをすべて削除して解決！！

ちなみに料金はこのくらいなので問題ないかなと。
https://aws.amazon.com/jp/ses/pricing/
[C][python]LinuxでAquesTalkで棒読みする

Windows環境ではsoftalkなどで手軽に読み上げできますが、Linux環境ではwineなどで頑張らないと実行できません。
しかたないのでsoftalkが呼び出しているAquesTalkを直接呼び出してみます。

音声合成するだけならGoogle Translateのtext-to-speech APIを[gTTS](https://github.com/pndurette/gTTS)で呼び出すほうがお手軽です。
open-jtalkはインストールしようとすると私の環境ではコンフリクトするので解決が面倒で試していません。

## やること
AquesTalk2のライブラリをcとpythonのコードから使用して音声合成します。

## 実行環境
* Arch Linux
* python3.6.5
* AquesTalk2 Linux 2.3.0

## AquesTalkのインストール
### ダウンロード
[ダウンロード \| 株式会社アクエスト](https://www.a-quest.com/download.html) から評価版をダウンロードします。
本記事ではAquesTalk2を使用します。 AquesTalk, AquesTalk10での動作は未確認です。

なお、評価版では「ナ行、マ行」の音韻がすべて「ヌ」になるとのことです。

### インストール
ダウンロードしたファイルに含まれるマニュアルの通りにライブラリをインストールします。
ライブラリのバージョンやlibとlib64どちらを使うかは適宜読み替えてください。

```bash
$ cd aqtk2-lnx-eva/lib64
$ cp libAquesTalk2Eva.so.2.3 /usr/lib
$ sudo ln -sf /usr/lib/libAquesTalk2Eva.so.2.3 /usr/lib/libAquesTalk2Eva.so.2
$ sudo ln -sf /usr/lib/libAquesTalk2Eva.so.2 /usr/lib/libAquesTalk2Eva.so
$ sudo /sbin/ldconfig -n /usr/lib 
```

## AquesTalkのサンプルを実行
`aqtk2-lnx-eva/samples/SampleTalk.c` をコンパイルして実行します。
大体付属のマニュアルの通りで良いです。

### エンコードに合わせてサンプルを修正
エンコードごとに音声合成関数が用意されているので、terminalなどのエンコードに合わせてSampleTalk.cを修正します。
ここではUTF-8を使います。
エンコードにあった関数が呼ばれていないと、正しく動作しません。

```cpp
//	unsigned char *wav = AquesTalk2_Synthe_Euc(str, 100, &size, NULL);
	unsigned char *wav = AquesTalk2_Synthe_Utf8(str, 100, &size, NULL);
```

### コンパイル
ライブラリとヘッダパスを指定してコンパイルします。

```bash
$ g++ -o SampleTalk samples/SampleTalk.c -lAquesTalk2Eva -Ilib64
```

### 実行

サンプルは標準入力からテキストを受け取って、標準出力にwav形式データを出力します。
「ゆっくりしていって**ぬ**」と読み上げてくれます。

```bash
$ echo "ゆっくりしていってね" | ./SampleTalk > sample.wav
```

## pythonから実行
ctypesでライブラリを読み込んで実行します。
評価版付属のphontファイルを指定することで声質を変えることができます。
指定がないとデフォルトで動作します。デフォルトが結構聞き取りやすい。

```python
from ctypes import *


def synthe_utf8(text, speed=100, file_phont=None):
    if file_phont is not None:
        with open(file_phont, 'rb') as f:
            phont = f.read()
    else:
        phont = None

    aqtk = cdll.LoadLibrary("libAquesTalk2Eva.so")
    aqtk.AquesTalk2_Synthe_Utf8.restype = POINTER(ARRAY(c_ubyte, 0))
    size=c_int(0)
    wav_p = aqtk.AquesTalk2_Synthe_Utf8(text.encode('utf-8'), speed, byref(size), phont)
    if not bool(wav_p):
        print("ERR:", size.value)
        return None
    wav_p = cast(wav_p, POINTER(ARRAY(c_ubyte, size.value)))
    wav = bytearray(wav_p.contents)
    aqtk.AquesTalk2_FreeWave(wav_p)
    return wav


if __name__ == '__main__':
    with open('./default.wav', 'wb') as f:
        wav = synthe_utf8(u"ゆっくりしていってね", speed=100)
        f.write(wav)
    with open('./yukkuri.wav', 'wb') as f:
        wav = synthe_utf8(u"ゆっくりしていってね", speed=100, file_phont='aqtk2-lnx-eva/phont/aq_yukkuri.phont')
        f.write(wav)
```

## **ぬ**
評価版では「ナ行、マ行」が「ぬ」になりますが、正しく読ませるにはライセンスの取得が必要のようです。
個人利用の場合は開発ライセンスを2000円弱で取得できます。（2018/6/9 現在）
頒布の規定など詳細は下記参照。
[個人利用 ライセンス \| 株式会社アクエスト](https://www.a-quest.com/licence_free.html)
突然gulpが変なエラー吐き出したのでnodeのバージョンをダウンした

突然うちのgulpがおう吐するようになりました。
何度呼んでも以下のようなエラーを吐くのです。。

```console
$ gulp
gulp[7570]: ../src/node_contextify.cc:631:static void node::contextify::ContextifyScript::New(const FunctionCallbackInfo<v8::Value> &): Assertion `args[1]->IsString()' failed.
 1: node::Abort() [/usr/local/bin/node]
 2: node::Assert(char const* const (*) [4]) [/usr/local/bin/node]
 3: node::contextify::ContextifyScript::New(v8::FunctionCallbackInfo<v8::Value> const&) [/usr/local/bin/node]
 4: v8::internal::FunctionCallbackArguments::Call(v8::internal::CallHandlerInfo*) [/usr/local/bin/node]
 5: v8::internal::MaybeHandle<v8::internal::Object> v8::internal::(anonymous namespace)::HandleApiCallHelper<true>(v8::internal::Isolate*, v8::internal::Handle<v8::internal::HeapObject>, v8::internal::Handle<v8::internal::HeapObject>, v8::internal::Handle<v8::internal::FunctionTemplateInfo>, v8::internal::Handle<v8::internal::Object>, v8::internal::BuiltinArguments) [/usr/local/bin/node]
 6: v8::internal::Builtin_Impl_HandleApiCall(v8::internal::BuiltinArguments, v8::internal::Isolate*) [/usr/local/bin/node]
 7: 0x1f00c118427d
Abort trap: 6

```

救急車呼びか、病院に連れて行くか悩みましたが、ひとまず自分で対応することにしました。

## 結論
nodeのバージョンに対応してなかったぽい

以前まではv8.9.4で実行していましたが、別の用事でnodeのバージョンをv10.0.0にしたら今のgulpにはちょっと合わなかった見たいです。

## 対応
とりあえずnodeのバージョンをv8.9.4に戻すことにしました。

ただ、僕のmacでは、homebrew管理のものとnodebrew管理のものがあり、homebrew管理のものがv10.0.0、nodebrew管理のものがv8.9.4でした。
そしてhomebrewの方のnodeが使われているようでした。

homebrewよりnodebrewの方がいい的な記事があったので、nodebrewに変えることにしました。
そのため、以下の手順で対応しました。
①homebrew管理のnodeをuninstall
②nodebrew管理のnodeにパスを通す

### ①homebrew管理のnodeをuninstall

yarnをインストールしていたのでnodeをアンインストール出来ませんでした。
なので両方アンインストール。

```console
$ brew uninstall --force yarn
$ brew uninstall --force node
```

### ②nodebrew管理のnodeにパスを通す
※nodebrewはインストール済み

とりあえずnodebrewのディレクトリ設定
(homebrew経由でnodebrewをインストールした場合に手動で行う必要があるらしい)

```console
/usr/local/opt/nodebrew/bin/nodebrew setup_dirs
```

パスを通す

```
export PATH=$HOME/.nodebrew/current/bin:$PATH
```
`~/.nodebrew`ではなくhomebrewのディレクトリを使う場合は以下を実行

```
export NODEBREW_ROOT=/usr/local/var/nodebrew
```

最後に`npm install`(パッケージのバージョンは変えたくなかったので)

```
$ npm install
```

## 結果

無事元気なgulpに会うことが出来ました。

```console
$ gulp
[17:47:19] Using gulpfile ~/Develop
[17:47:19] Starting 'watch'...
[17:47:20] Finished 'watch' after 549 ms
[17:47:20] Starting 'default'...
[17:47:20] Finished 'default' after 24 μs
```

## 参考
[Node.jsの管理をHomebrewからnodebrewに変える](https://qiita.com/takeshi81/items/805f504503cd93151ca6)
深さ優先探索で black と grey の節点を区別する意味

生活していると、与えられたグラフの全ての節点を訪問して何らかの処理を行わなければならない状態になることがあると思います。そのような場面で使えるアルゴリズムに深さ優先探索があるので勉強していたのですが、一つ疑問が湧いてきたので調べたメモです。

グラフを表す隣接リスト`L`を与えられて、深さ優先探索によって頂点を訪問していくコードを、[アルゴリズムクイックリファレンス](https://www.amazon.co.jp/アルゴリズムクイックリファレンス-第2版-George-T-Heineman/dp/4873117852)に記載の擬似コードを見ながら python で以下のように実装した。一般に、深さ優先探索のコードは細かい違いはあってもだいたいこんな感じになると思う。

```python
def dfs(L, colors, v):
    colors[v] = 'grey'
    for nv in L[v]:
        if colors[nv] == 'white':
            dfs(L, colors, nv)
    colors[v] = 'black'

if __name__ == "__main__":
    L = [
        [1],
        [2, 3],
        [],
        [2]
    ]
    colors = ['white'] * len(L)

    dfs(L, colors, 0)
```

このコードでは、節点の状態を３つに分類し、

- `white`：未訪問
- `grey`：その節点から先にある節点（これらの節点を descendants と呼ぶ）を再帰的に訪問中
- `black`：その節点のすべての descendants を訪問済み

と色分けして扱っている。しかし、冷静に考えると上記のコードでは`grey`と` black`をわざわざ分けて考える必要がないことに気づく。コード中で節点の状態を使っているのは、`if`文で節点の状態が`white`かどうかで分岐しているところだけなので、必要な情報は「節点が`white`かそうでないか」だけであり、`grey`と`black`の区別が何も役立っていない。つまり、`grey`と`black`をまとめて"訪問済みの節点"として扱ってもプログラムの機能に何も変わりがないことになる。

その割に、深さ優先探索の実装例を調べると`grey`と`black`を区別しているものが多い。ということで、なぜ`grey`という状態が必要か検索したら以下のページにわかりやすい回答があったのでまとめておく。

[The purpose of grey node in graph depth-first search](https://cs.stackexchange.com/questions/9676/the-purpose-of-grey-node-in-graph-depth-first-search)

`grey`と`black`の区別が必要な場面の一つの例として、有向グラフ中の閉路を検出したい場合が考えられる。**無向グラフだと、「訪問中の節点の隣に（`black`であろうが`grey`であろうが）訪問済みの節点があるならば、閉路がある」ことになる。しかし、有向グラフだとそうとは限らない。**

例えば、以下の閉路を持たない有向グラフを深さ優先探索しながら閉路を検出することを考える。

![20180325114716.png](https://qiita-image-store.s3.amazonaws.com/0/159260/f84cd688-0c1d-41b7-47d1-28f1eb428b7b.png)

隣接する節点のうち数字が小さいものから順に訪問していく深さ優先探索をすると、節点の状態の変化は以下のように変化していく。

![20180325114820.png](https://qiita-image-store.s3.amazonaws.com/0/159260/a9ebe012-dcbf-3a8f-b90a-91c75a2bbf20.png)

一番左下の最後の状態で、節点`0`から見て`2`が隣接する訪問済みの節点なので、単に「隣接する訪問済みの節点がある」という無向グラフと同じ基準で閉路を検出してしまうと、この例のような閉路がないグラフでもあるということになってしまうのである。

グラフにおいて「閉路がある」ということは、「ある節点から descendants を辿っていき、自分自身に到達可能であること」と言い換えることができる。これはすなわち、「自分が自分の descendant であるような節点が存在する」ということである。この条件を深さ優先探索の３つの状態`white`、`grey`、`black`と考え合わせてみると、閉路がある条件として、「**現在訪問中の節点から到達できる、隣接する grey の節点が存在する**」と考えてよいことがわかる。

これを理解するために、現在訪問中の節点を A、隣接する`grey`の節点を B として具体的に考えてみる。A は現在`grey`の状態にあるすべての節点の descendant であるから、当然`grey`である B の descendant である。この B の descendant である A  から B に到達できることから、 B は B 自身の descendant であり、閉路が存在することになる。

一方で、現在訪問中の節点に、到達できてかつ隣接する`black`の節点が存在しても閉路があると言えないことに注意。これは、現在訪問中の節点が`black`の節点の descendant **ではない**ことから、上の議論が成り立たないためである。

以上の基準に従うと、上の３つの節点からなるグラフの例で言うと、最後の状態で節点`0`から見て`2`は`grey`ではなく`black`なので、「**現在訪問中の節点から到達できる、隣接する grey の節点が存在する**」という基準をもとに、ちゃんと閉路の有無を判定できることになる。当然、この基準を使うためには`grey`と`black`という状態を分けて扱わなければならないので、`grey`と`black`の節点を区別することが閉路を検出することに役立つことがわかった。

他にも`grey`と`black`を区別する意味がある具体例があったら教えてください。
Chrome拡張のポップアップ側のスクリプトによるconsole.logの出力を見る

# なんの話？

ポップアップ側の領域のスクリプトによる出力は、普通にブラウザでChromeの開発者ツール開いてコンソールを見てもログが出ない。

ポップアップ側で開発者ツールを開かないといけない。

# 例

以下のChrome拡張があるとする。

## manifest.json
```json
{
  "browser_action": {
    "default_popup": "popup.html"
  }
}
```
（色々省略）

## popup.html

```html
<html>
<head>
    <title>test</title>
</head>
<body>
    <button id="test">test</button>
</body>
<script src="popup.js"></script>
</html>
```

## popup.js
```javascript
function test() {
    console.log("これを見たい");
}

document.getElementById('test').addEventListener('click', test);
```

# ポップアップ側の開発者ツールを開く

ポップアップ開いて右クリックして「検証」で別途開発者ツールが開くので、そっち側で出力がみれる。

<img width="204" alt="スクリーンショット 2018-06-09 17.15.07.png" src="https://qiita-image-store.s3.amazonaws.com/0/220908/f2af3338-c363-43ec-6c42-5c903c503fdb.png">

# 参考
https://stackoverflow.com/questions/14858909/cannot-get-chrome-popup-js-to-use-console-log
pythonでクラスを定義する場合のテンプレート

# この記事について

pythonでクラスを定義する場合のテンプレートを記載します。コメントのつけ方や命名規則などはpylintを通る方法で定義します。


# テンプレート

```python
# -*- coding: utf-8 -*-
"""
ファイルの説明

License:
  Licensed under the Apache License, Version 2.0 (the "License");
  http://www.apache.org/licenses/LICENSE-2.0

Copyright
  XXXXX All Rights Reserved.
"""

#----------------------------------------------------------------------
# インポート
#----------------------------------------------------------------------
# import some_package


#----------------------------------------------------------------------
# クラス定義
#----------------------------------------------------------------------
class BaseClass:
    """
    classの説明を記載します
    """

    def __init__(self, value):
        """
        コンストラクタ

        Args:
          引数名:引数の説明
        """

        # Public Member
        self.public_member = value

        # Private Member
        self.__private_member = "private"

        raise NotImplementedError()


    #---------------------------------------
    # クラス定数
    #---------------------------------------
    CLASS_CONST_VALUE = "class constant"


    #---------------------------------------
    # public関数
    #---------------------------------------
    @classmethod
    def public_class_method(cls):
        """
        publicクラスメソッドを定義します

        Args:
          引数名:引数の説明

        Returns:
          戻り値の説明

        Raises:
          例外型：発生する条件の説明
        """
        pass


    def public_method(self):
        """
        public関数を定義します

        Args:
          引数名:引数の説明

        Returns:
          戻り値の説明

        Raises:
          例外型：発生する条件の説明
        """
        pass

    #---------------------------------------
    # private methods
    #---------------------------------------
    @classmethod
    def __private_class_method(cls):
        """
        privateクラスメソッドを定義します

        Args:
          引数名:引数の説明

        Returns:
          戻り値の説明

        Raises:
          例外型：発生する条件の説明
        """
        pass

    def __private_method(self):
        """
        private関数を定義します

        Args:
          引数名:引数の説明

        Returns:
          戻り値の説明

        Raises:
          例外型：発生する条件の説明
        """
        pass
```


基本クラスを継承する場合は以下のようにコンストラクタを定義します。

```python

class DerivedClass(BaseClass):
    """
    基本クラスを継承する場合の定義
    """

    def __init__(self, value):
        """
        コンストラクタ

        Args:
          引数名:引数の説明
        """

        # 基本クラスのコンストラクタを呼び出します
        super(DerivedClass, self).__init__(value)

        # Public Member
        self.public_member = "public"

        # Private Member
        self.__private_member = "private"

        raise NotImplementedError()
```
nginxの設定ミスで起こるHostヘッダフォージェリ

# はじめに
この記事は下記リンクの日本語翻訳記事です

https://github.com/yandex/gixy/blob/master/docs/en/plugins/hostspoofing.md

翻訳が誤っている場合はコメントか[@no1zy_sec](https://twitter.com/no1zy_sec)までお知らせいただけると幸いです。

## [host_spoofing] Request's Host header forgery
多くの場合、Nginxの後方に位置するアプリケーションはURLを生成する(リダイレクト、リソース、電子メール内のリンクなど)ために適切な`Host`ヘッダを必要とします。このヘッダのなりすましは、フィッシングからSSRFまでの様々な問題を引き起こす可能性があります。

> 注: アプリケーションはこの機能にX-Forwarded-Host　リクエストヘッダを使用することもできます。この場合、ヘッダが適切に設定されていることを確認する必要があります。

## どうやって見つけるか
ほとんどの場合、\$hostの代わりに\$http_host変数を使用した結果、脆弱になっています。

`$host` と `$http_host` にはかなりの違いがあります。

* `$host` - 次の優先順位でホストが決まります。
    1. [リクエストライン](https://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html)
    2. `Host` リクエストヘッダフィールド
    3. リクエストに一致するサーバー名
  
* `$http_host` - `Host` リクエストヘッダ

### 設定のサンプル
```nginx
location @app {
  proxy_set_header Host $http_host;
  # Other proxy params
  proxy_pass http://backend;
}
```

## 対策
幸いにも、全てが自明です。

* `server_name`ディレクティブに正しいサーバー名を全てリストしてください。
* 常に `$http_host` の代わりに `$host` を使用してください。
* 認識できないホスト名を持つ全てのリクエストをキャッチするための専用の仮想ホストを作成してください。  [Server blocks](https://www.nginx.com/resources/wiki/start/topics/examples/server_blocks/)


## 追加情報
[Host of Troubles Vulnerabilities](https://hostoftroubles.com/)
[Practical HTTP Host header attacks](https://www.skeletonscribe.net/2013/05/practical-http-host-header-attacks.html)

## 関連リンク
[Hostヘッダフォージェリの対策について]
(https://qiita.com/no1zy_sec/items/718cb9a51da7c6d5a9a5)
[nginxの設定ミスで起こるHTTP Splitting](https://qiita.com/no1zy_sec/items/fe7c44b5a0fdd4807bbe)
[nginxの設定ミスで起こるSSRF](https://qiita.com/no1zy_sec/items/2718f4a99bb8368ac374)
[nginxの設定ミスで起こるパス トラバーサル](https://qiita.com/no1zy_sec/items/e541f1c838874ff400bb)
[nginxの設定ミスで起こるMultiline response headers](https://qiita.com/no1zy_sec/items/da280cb5c1e154babe2a)
[nginxの設定ミスで起こるレスポンスヘッダの出力不備](https://qiita.com/no1zy_sec/items/b786abcba5d796ccc300)
[nginxの設定ミスで起こるreferer/origin検証の問題](https://qiita.com/no1zy_sec/items/93f1efe3c58102807de8)
[nginxの設定ミスで起こるリファラの検証不備](https://qiita.com/no1zy_sec/items/9d73f4923ebef1598e7d)