OmniAICreator/Qiita-1.07M huggingface dataset:
SpringBoot の依存ライブラリのバージョンをカスタマイズ(Maven版)

SpringBoot の Maven プロジェクトのpom.xmlでは、依存ライブラリのバージョン指定を大抵の場合省略できます。後述の spring-boot-dependencies の中に、SpringBootがサポートしている各種ライブラリのバージョン定義がされており、それを参照するからです。

ここで以前から気になっていたのが、例えば SpringBoot で Tomcat を使用していて、Tomcat側で緊急のセキュリティfixがリリースされた場合、どうやってTomcatのバージョンだけを個別にアップデートするか？という方法でした。本記事ではそれについて実際のサンプルコードで確認してみました。

サンプルコードは以下になります。

- https://github.com/msakamoto-sf/springboot-lib-version-change-demo
  - SpringBoot 2.1.1 を使用したMavenプロジェクトです。

## サンプルコードの解説

STS4で生成した SpringBoot 2.1.1 の単純なMavenプロジェクトです。コンテナはデフォルトのTomcatで、h2databaseも追加しています。

リポジトリのpom.xmlは、すでにバージョンをカスタマイズした内容になっています。以下のように `<properties>` 内で、spring-boot-dependencies 側で定義しているtomcatとh2のバージョンを上書きしています。

```
	<properties>
		<java.version>1.8</java.version>
		<tomcat.version>9.0.14</tomcat.version>
		<h2.version>1.4.196</h2.version>
	</properties>
```

まずはこれを、以下のように生成した当時の状態に戻し、ビルド・実行してみます。

```
	<properties>
		<java.version>1.8</java.version>
	</properties>
```

`mvnw package` でビルドしたら `java -jar (jarファイル)` で実行し、http://localhost:18088/ にアクセスしてください。以下のようなバージョン情報が表示されます。(これは2019-01-02前後の時点のものです)

```
servletContext.getServerInfo() -> Apache Tomcat/9.0.13
SELECT H2VERSION() -> 1.4.197
```

これが、spring-boot-dependencies側で事前に埋め込まれたバージョンになります。
これをカスタマイズしてみます。Tomcatについては 9.0.14 がリリースされていましたのでそちらに変更し、h2databaseについては1つバージョンを落として 1.4.196 に変更してみます。

→ 変更結果が、リポジトリのpom.xmlの内容となります。ビルドしなおして実行すると、確かに変更したバージョンが表示されることを確認できるはずです。

## spring-boot-dependencies について

STS4が生成したpom.xmlでは、parentにspring-boot-starter-parent:2.1.1.RELEASEが設定されています。この pom.xml を見てみると、依存関係をまとめた spring-boot-dependencies:2.1.1.RELEASE が更にparentとして指定されています。
spring-boot-dependencies の pom.xml を見てみると、 `<properties>` に各種ライブラリのバージョンが登録されていました。

```
<?xml version="1.0" encoding="utf-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-dependencies</artifactId>
    <version>2.1.1.RELEASE</version>
    <packaging>pom</packaging>
    <name>Spring Boot Dependencies</name>
    <description>Spring Boot Dependencies</description>
    <url>https://projects.spring.io/spring-boot/#</url>
<!-- ... -->
    <properties>
<!-- ... -->
        <h2.version>1.4.197</h2.version>
<!-- ... -->
        <tomcat.version>9.0.13</tomcat.version>
```

これらの定義は、spring-boot-starter-系のpom.xmlで、個別のライブラリの依存関係での `<version>` 指定で参照されています。
これにより、アプリケーション側のpom.xmlでは `<version>` 指定が不要となっています。また、spring-boot-dependencies側では SpringBoot として動作確認が取れているバージョン番号を定義しているわけですので、一貫性が期待できます。「あれ、こっちはこのバージョンで良いんだっけ？」と悩む必要がありません。

もし異なるバージョンを使いたい場合は、アプリ側の pom.xml で同じプロパティを上書きすればOKです。公式リファレンス側での解説は以下を参照してください。

- 13.1 Dependency Management
  - https://docs.spring.io/spring-boot/docs/2.1.1.RELEASE/reference/htmlsingle/#using-boot-dependency-management

## まとめ

- SpringBoot の依存ライブラリのバージョンをカスタマイズするには、 spring-boot-dependencies 側で定義されているバージョンのプロパティをアプリ側のpom.xmlで上書きすればOK.
- ↑実際にサンプルコードで確認してみた。
スクレイピングの優先順位

スクレピングの技術のあれこれ

ここでは主にパース方法の優先度を挙げる

## 結論

以下の優先度でパースできないかを探る

1. JSON
2. CSSセレクタ
3. XPath
4. 正規表現

## まずはJSONがあればパースが一番楽

今どきはJavaScriptのフレームワークを使って画面を描画することが多い。
そうするとコンテンツの本体はJSONで降ってくることも多い。
JavaScriptで描画されるから、Seleniumを使わないと駄目だよねという判断もあるのかも知れないけど、実際にはJSONをGETするだけでよいケースは多い。

## 次にCSSセレクタ

ちゃんとしたデザイナーが入れば、CSSのクラスやIDは「コンテンツの意味に応じてネーミング」している。そしてデザイもCSSセレクタが書きやすいように書いている。なのでCSSセレクタでパースするのが楽になってるはず。

## 次にXPath

XPathは本来的にはXMLをパースするためのものなので、HTMLをパースするのに使うと、ちょっと表現が冗長になる。ただCSSセレクタに比べるとちょっとだけ機能が多い。テキストノードに含まれるテキストの部分一致で要素を取得したい時にはXPathが便利。

## 正規表現

テキストから値を部分的に取得するなら正規表現でかける。ただし読みづらい。上記の方法が全部使えなかった時の最後の手段。またパース後のテキストから、部分文字列を取り出す時には当然正規表現で取り出す。
Amazon LightsailでWordPressサイトインスタンス起動からhttps対応までしたいときの参考情報まとめ

# はじめに

本記事ではAmazon LightsailでWordPressサイトを構築しhttps対応までした時に参考にさせて頂いた情報をまとめておきます。
自分用メモという形ですがどなたかの参考になれば。

# WordPressサイトインスタンス起動まで

下記サイトを参考に手順通り進めるとすぐにWordPressがインストールされたインスタンスが起動できます。

[Amazon Lightsail 数クリックでWordPress環境を立ち上げてみた～操作編～](https://recipe.kc-cloud.jp/archives/9510)

AWSを利用したことがある方であれば特につまることもないでしょう。

# https対応

## bitnamiバナー削除

初回起動時に不要なバナーがサイト内に出ているのでそちらの削除対応を行います。
下記記事が参考になりました。

[Bitnamiのロゴが邪魔！](https://qiita.com/MosamosaPoodle/items/24ae64627820e557790b)

## Static IP設定

こちらもAWSを使ったことのある方であれば非常に簡単に扱えるでしょう。
下記記事が詳しいので参考になります。

[Amazon LightsailのStatic IPを使ってみた #reinvent](https://dev.classmethod.jp/cloud/aws/lightsail-using-static-ip/)

## ドメインの設定(ドメインを持っている方は対応)

こちらは特にLightsail固有の手順が必要というのはありません。
下記記事などが参考になります、他にも多くの情報がありますのでそちらも参考になるでしょう。

[お名前.comで取得したドメインをAmazon EC2に紐付ける](https://qiita.com/nadonado/items/a7c32c94fef87b7db0d5)

## letsencryptを利用してhttps化

下記記事が非常に綺麗にまとまっていて参考になりました。

[LightsailでWordPress（SSL化もする）](https://qiita.com/foursue/items/8e685b52cfddf05875ee)

なおコメント欄にも記載がありますが下記については追加で対応、注意して作業を進めるといいでしょう。

* 上記記事はletsencryptリポジトリを/tmpにgit cloneしてますが再起動すると削除されるため別ディレクトリにgit cloneする
* [証明書更新のcron設定](https://qiita.com/foursue/items/8e685b52cfddf05875ee#comment-06cf055e5188d03e4c1f)(letsencryptの証明書が3ヶ月できれるため)

## プラグインを利用してhttps対応仕上げ

上記手順まででSSL対応はできているのですが、サイトを移動するとhttpのサイトに戻ったりということがあるでしょう。
設定ページなどを確認するとわかると思いますがおそらくサイト情報自体はhttpの設定のままだったりするはずです。
その場合は下記記事で紹介されているプラグインを利用してWordPressの方の設定も更新してあげるといいです。

[WordPressサイトアドレスをhttpsに変更する（Really Simple SSL）](https://chubu-itpro.tech/2018/06/10/post-43/)

# おまけ

## コンソールから使えるブラウザSSHでコピペ

Amazon Lightsailはマネジメントコンソール上でSSH接続可能なブラウザ上でインスタンスにSSH接続できるようになっています。
これは非常に便利なのですがコピペの仕方がわかりにくい。。。
こちらは下記サイトにまとまっていますのでぜひ参考にしてください。

[Amazon Lightsail ブラウザSSH接続時のコピー＆ペースト](https://blog.miminoinu.net/archives/289/)

# まとめ

Amazon Lightsail、WordPressもほとんど使ったことがありませんでしたがWeb上にある情報が非常に多く助かりました。
実際に僕がサイトを構築する際に利用した情報をまとめただけになってはいますがこれからAmazon Lightsailを利用してWordPressサイトを構築しようとする方の参考になればと思います。
JetsonTX2 インストールからサンプル動作確認まで

# 用意するもの
- ディスプレイ(HDMI接続)
- HDMIケーブル
- Ubuntu 14 or 16　（VMでも可）
- ストレージ容量 50GB以上
- USBハブ(2ポート以上)
- USBキーボード
- USBマウス



## 手順１：JetpackのJetsonへの転送

参考手順：https://dev.classmethod.jp/etc/jetson-setup/

VirtualBoxを使う場合[このページ](https://qiita.com/0x0c@github/items/bc2683b00617981e4468
)を参考に。

※詰まったところメモ
VMの設定でUSB2.0としてNVIDIA corp.を認識させると、OS Flashの最中に`Boot Rom is not running.`ってエラーが出てしまった。下記を参考にUSB3.0に設定し直して再度OS Flashを実行したら問題なく完了。

> https://devtalk.nvidia.com/default/topic/1002827/jetson-tx2/problem-flashing-tx-2/2
> In the above post, it is said the usb connection should be USB2, but for me it was USB3. I really don't know why this works for me.


## 手順２：SDカード起動にする
https://www.jetsonhacks.com/2017/01/26/run-jetson-tx1-sd-card/





## 手順３：OpenCVのインストール
手順参考：https://jkjung-avt.github.io/opencv3-on-tx2/
cmake前に、[このページ](https://github.com/atinfinity/lab/wiki/Jetson-TX2%E7%92%B0%E5%A2%83%E3%81%A7%E3%81%AEOpenCV%E3%83%93%E3%83%AB%E3%83%89)のパッケージをインストールする

※再インストールが必要な理由その①
> https://www.jetsonhacks.com/2017/01/26/run-jetson-tx1-sd-card/
プレインストールされたOpenCV4Tegra（2.4.13.1）はpython2.7のためのバインディングを提供するだけのようでした。いくつかの調査の結果、私はこの問題に対する推奨される解決策はOpenCVを再コンパイルすることであることがわかりました。


※再インストールが必要な理由その②
> https://qiita.com/ababa831/items/57b43e788d684c380866#2-%E3%82%AB%E3%83%A1%E3%83%A9%E8%A8%AD%E5%AE%9A
デフォルトではV4L2 APIを用いる設定になっていますが、NVIDIA公式フォーラム(英文)にあるように、GStreamerを用いたパイプラインでカメラ情報にアクセスする必要があります。


※再インストールが必要な理由その③
> https://devtalk.nvidia.com/default/topic/1031631/jetson-tx2/jetson-tx2-onboard-camera-with-opencv3-3-1/
> https://devtalk.nvidia.com/default/topic/1027301/jetson-tx2/jetpack-3-2-mdash-l4t-r28-2-developer-preview-for-jetson-tx2/
> JetPackに含まれているopencv-3.3.1バージョンはgstreamerをサポートしていません。
> あなたはgstreamer-1.0サポートを可能にするあなた自身のバージョンを構築してインストールしなければならないでしょう。



## 手順４：必要なパッケージのインストール

```bash

$ sudo apt-get install libasound2-dev libesd0 libboost-all-dev v4l-utils alsa-utils
$ sudo apt-get install xdotool wmctrl setxkbmap mpv meld socat
```

## 手順5:VisionWorks
VisionWorksサンプルのインストール方法
ホームディレクトリで、以下のコマンドを実行する

```shell
$ /usr/share/visionworks/sources/install-samples.sh .
$ /usr/share/visionworks-tracking/sources/install-samples.sh .
```

ホームディレクトリにソースのディレクトリができるので、各フォルダで、`make -j4`
Loguruの使い方(Pythonログ出力ライブラリ)

[Python のベストライブラリ in 2018 \- Qiita](https://qiita.com/rinatz/items/f56552633e86cddeb119) よりloguruがとても良かったので使い方をメモ

一行`add`メソッドだけで簡単に設定が行えるのが素晴らしい。

https://github.com/Delgan/loguru
https://loguru.readthedocs.io/en/stable/api/logger.html


追記：logzeroもいいですね。
[Pythonのログ出力にlogzeroを使う \- kumilog\.net](https://www.kumilog.net/entry/python-logzero)

# インストール

```
$ pip install loguru
```

# 使い方

## 単純なprint代わり

デフォルトのログレベルは`DEBUG`

```py:main.py
from loguru import logger

def main():
    logger.trace("トレース")
    logger.debug("デバッグ")
    logger.info("情報")
    logger.success("成功")
    logger.warning("警告")
    logger.error("エラー")
    logger.critical("クリティカル")

if __name__ == '__main__':
    main()
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/330873/a915ee92-3ef4-2d4b-2552-9657ecf4bbc1.png)

## ファイル出力

```py:main.py
from loguru import logger

def main():
    logger.add("logtest.log") # 追加
    logger.trace("トレース")
    logger.debug("デバッグ")
    logger.info("情報")
    logger.success("成功")
    logger.warning("警告")
    logger.error("エラー")
    logger.critical("クリティカル")

if __name__ == '__main__':
    main()
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/330873/c679a37b-781b-cc05-8d59-c61bff442d2f.png)

## ファイル出力（標準エラー出力は抑制したい）

loguru/\_\_init\_\_.pyでadd()しているので外せば良い。

```py:main.py
from loguru import logger

def main():
    logger.remove() # 追加
    logger.add("logtest.log")
    logger.trace("トレース")
    logger.debug("デバッグ")
    logger.info("情報")
    logger.success("成功")
    logger.warning("警告")
    logger.error("エラー")
    logger.critical("クリティカル")

if __name__ == '__main__':
    main()
```
![image.png](https://qiita-image-store.s3.amazonaws.com/0/330873/55963975-390f-b390-cf86-252db226cfd0.png)

## ログローテーション

柔軟な指定が可能
`rotation`は1ファイルの容量を指定。100 MB、10hなら10時間でローテーションされる
`retention`は保持期限を指定。数字だと個数、2 monthsなら２ヶ月など
ローテーションされるファイル名はdatetime型の`%Y-%m-%d_%H-%M-%S_%f`固定のようだ。

```py:main.py
from loguru import logger

def main():
    logger.remove()
    logger.add("logtest.log", rotation="1 KB", retention=3)
    for x in range(100):
        logger.info("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")

if __name__ == '__main__':
    main()
```

```
[k8uwall logtest]$ ls logtest.*
logtest.2019-01-05_12-32-58_296655.log  logtest.2019-01-05_12-32-58_301567.log
logtest.2019-01-05_12-32-58_299136.log  logtest.log
```

## raw出力

```py:main.py
from loguru import logger

def main():
    logger.info("情報")
    logger.opt(raw=True).info("ここはフォーマットに従わない\n")

if __name__ == '__main__':
    main()
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/330873/64b7bb8c-6f99-e697-cd65-1b881f52fac9.png)


## 数字付きログローテーション（2020/12/31追記、2021/1/11修正）

https://github.com/Delgan/loguru/pull/381#issuecomment-753452167

```py:main.py
from loguru import logger
from logging.handlers import RotatingFileHandler

handler = RotatingFileHandler("file.log", maxBytes=5000, backupCount=3)
logger.add(handler)
```
windows10でJupyter Notebookの初期フォルダの変更がうまくいかない時

#1 設定ファイルを作成

コマンドプロンプトなどで、

```
jupyter notebook --generate-config
```
を実行する。
すると
（windowsの場合）
c:\Users\\(UserName)\\.jupyter
に
jupyter_notebook_config.py
というファイルができる。
これを開いて編集する。


#2 jupyter_notebook_config.pyを編集
```
#c.NotebookApp.notebook_dir = ''
```
を検索などして、
文頭の「#」を取り（コメントアウトになっているため）
「''」の中に初期フォルダを記入
たとえば

```
c.NotebookApp.notebook_dir = 'c:\workspace'
```

#3(これでうまくいかないとき)プロパティを編集
jupyter notebookへのショートカットを右クリックして
「ファイルの場所を開く」。
アイコンを右クリックして、プロパティを開く。
「リンク先」の中に
「%USERPPROFILE%」という記述があるとうまくいかないので、
この部分を削除する。
'the use of tab(s) \'\\t\' in source data isn\'t currently supported, please contact makers'

## 概要
api blueprintで書いたAPI仕様書をmockサーバーとして立ち上げるときに、発生したエラーについて。

### 動作環境
Mac OS Mojave 10.14.2
node v9.3.0
drakov ^1.0.4


## エラー
drakovを立ち上げるときに次のようなエラーが出て対処方法にちょっと手間取りました。

```bash
'the use of tab(s) \'\\t\' in source data isn\'t currently supported, please contact makers'
```

蓋を開けてみると単純なことですが、drakovでは、現在のところ**参照する.md(または.apib)ファイルのなかにtabで作ったスペースがあるとうまく起動しません**。

## 解決方法
.mdファイルの中のtabで作った空白をスペースで置き換えます。

vimを使っている人なら次のコマンドでtabの空白を排除することができます。

```vim
:%s/	/
```

.mdファイルからtabの空白を全て削除できたら、うまく作動しました！
メールクライアント"Spark"の移行について

# 年末年始の道具のメンテナンス
毎年恒例で年明けの正月休み辺りでPC類のメンテナンスをしています。
今回はmacOSのクリーンインストールから行いますが、少し気になったものがありましたのでメモします。

# 便利なメールクライアント"Spark"
Qiitaでは別なSparkと混同されてしまうので、この記事が邪魔になってしまうかもしれません。
割と重宝しています。
どの辺りが重宝しているかは本記事とは直接関係しませんので割愛します。

Thunderbirdの様に設定フォルダを移せば使えるかと安易に考えていましたが、「同期に使用するアカウント」というものを予め設定していますので、いわば「Sparkの設定保存サーバーにログイン」するイメージのように使えそうでした。
これを使わない手はありません。

# 環境
- iMac (Retina 5K, 27-inch, Late 2015)
- macOS Sierra 10.12.6（16G1510)
- Spark 2.0.17.580(096a5c0)

# 移行手順
早速移行作業を行ってみます。
※移行の事前確認のため、同一環境上で行っています。

## 1.Sparkからログアウト
メニューから環境設定 → 「一般」 → 「基本」タブを選択します。
最上段に「同期に使用するアカウント」があります。
おそらくSpark使用開始時に最初に設定したメールアドレスになっています。

![スクリーンショット 2019-01-05 12.21.02.png](https://qiita-image-store.s3.amazonaws.com/0/236049/ba4a6ef6-c476-1fa3-a897-ec4ed02cba39.png)
「ログアウト」をクリックします。
<img width="426" alt="スクリーンショット 2019-01-05 12.30.33.png" src="https://qiita-image-store.s3.amazonaws.com/0/236049/a75a8f60-479f-b2a5-d193-df9628e9749f.png">
このようなアラートが出ますので、「ログアウト」をクリックします。

<img width="640" alt="スクリーンショット 2019-01-05 12.31.49.png" src="https://qiita-image-store.s3.amazonaws.com/0/236049/fd1dda9a-80af-096e-b996-74623aa56ddd.png">
Sparkの初期画面になります。

## 2.再度ログイン
上記画面の「Sparkをはじめる」をクリックします。
<img width="640" alt="スクリーンショット 2019-01-05 12.33.15.png" src="https://qiita-image-store.s3.amazonaws.com/0/236049/39374d06-7f1d-1b7f-9264-ac5eb052af62.png">
ここで「同期に使用するアカウント」のメールアドレスを入力して、チェックボックスにチェックを入れます。
<img width="640" alt="スクリーンショット 2019-01-05 12.34.46.png" src="https://qiita-image-store.s3.amazonaws.com/0/236049/8ceb2e41-d4ce-e6c3-c0bb-19b9a8aa319d.png">
今回はGmailなので、Gmailにログインします。
ここでアカウントの真正が判定されるようです。
<img width="640" alt="スクリーンショット 2019-01-05 12.37.32.png" src="https://qiita-image-store.s3.amazonaws.com/0/236049/63e1dfed-3b1b-4a48-42b7-139419ab3ce1.png">
パスワードを入力します。
<img width="640" alt="スクリーンショット 2019-01-05 12.39.11.png" src="https://qiita-image-store.s3.amazonaws.com/0/236049/cfef21dc-b66d-3e66-64d8-702f9cf2fb90.png">
「許可」クリックします。

<img width="640" alt="スクリーンショット 2019-01-05 12.39.48.png" src="https://qiita-image-store.s3.amazonaws.com/0/236049/f80582fa-4408-7831-f726-dbc806434634.png">
認証されるのを待ちます。
Sparkのバグだと思われますが、日本語がおかしい・・・

<img width="640" alt="スクリーンショット 2019-01-05 12.40.00.png" src="https://qiita-image-store.s3.amazonaws.com/0/236049/7531aad1-01c6-105a-5669-ae1c0ed8b7e8.png">
完了しました。
「Sparkをはじめる」をクリックすると通常画面に戻ります。
複数のメールアドレスを使用している場合はすべての設定が保存されているため上記手順を踏むことで、全て自動で設定されます。

以上です。
アップキャストとスーパータイプ／サブタイプ

Javaのソースコードを読んでいると、以下のような記述を目にすることがある。

```
スーパークラス型 変数 = new サブクラス();
```

* 左項：スーパークラス型として変数を宣言
* 右項：左項クラスのサブクラスのインスタンス

という書き方である。
この記述に対する用語を知りたくなった。
※**この記述をする利点については、本記事では触れません**。

#アップキャスト（スーパークラス）
頻繁に目にするので、この記法に“キャスト”的な呼び方がないのかなとTwitterで呟いたら、親切な人が**アップキャスト**という呼び方があることを教えてくれた（感謝）。用語が分かれば検索したり他人に聞いたりできる。

```
// アップキャスト
スーパークラス型 変数 = new サブクラス();
```
参考：[【Java入門】キャスト(型変換)とアップキャスト、ダウンキャスト](https://www.sejuku.net/blog/22975)
宣言する変数の型も生成するインスタンスの型も親子関係にある**クラスなので**、この記述自体ついてはそれほど違和感を抱くことはない。

#アップキャスト（インタフェース）
が、Javaのアップキャストには以下のような記述もある。

```
インタフェース型 変数 = new 実装クラス();
```

* 左項：**インタフェース**型として変数を宣言（スーパークラスがインタフェースになった）
* 右項：**左項のインターフェースを実装したクラス**のインスタンス

という書き方である。
**宣言した変数の型はインタフェースなのに、代入するインスタンスの型はクラス**である。実装したクラスとはいえ、インタフェースとクラスは別の型という認識をしているのでかなりの違和感を覚える。
ここに違和感を抱くのは普通の感覚のような気もするが、そうでもないようだ。違和感を抱いたままだと理解の進みが悪い。解決策としては、実装を繰り返してに手に馴染ませることで違和感を軽減していくくらいしか思いつかない。ただそれでも**アップキャスト**という呼び名とその記述法及び振る舞いを知り、それがインタフェース型でも用いられるということが知識としてあれば、違和感を抱く対象自体はクリアになるので克服はしやすくなったと思う。

#スーパータイプ／サブタイプ
また、[Head Firstデザインパターン ―頭とからだで覚えるデザインパターンの基本](https://www.amazon.co.jp/Head-Firstデザインパターン-―頭とからだで覚えるデザインパターンの基本-Eric-Freeman/dp/4873112494)を読むと、**スーパータイプ／サブタイプ**という記述がある。

```
スーパークラス型 変数 = new サブクラス();
インタフェース型 変数 = new 実装クラス();
```

上記の場合、左項の“スーパークラス型”、“インタフェース型”が**スーパータイプ（型）**に該当する。それに対して、右項の“new サブクラス()”、“new 実装クラス()”は**サブタイプ（型）のインスタンス**に当たる。この呼び方は、私自身にクラスもインターフェースもタイプ（型）だという認識があるので、違和感は抱かなかった。
しかし、スーパータイプ／サブタイプで検索して引っかかるのはジェネリクスの話がほとんどで、[Head Firstデザインパターン ―頭とからだで覚えるデザインパターンの基本](https://www.amazon.co.jp/Head-Firstデザインパターン-―頭とからだで覚えるデザインパターンの基本-Eric-Freeman/dp/4873112494)の表記は一般的ではないのかもしれない。
C#で「Listがnullでない，かつ空でない」を短く書く

「Listがnullでない，かつ空でない」かどうかを判定したい場面は多いと思います．
そのまま書くとこんな感じ．

```cs
if (list != null && list.Count > 0)
```
非常にわかりやすいのですが，List名を2回書かないといけないので長くなりがちです．
こんな風に．

```cs
if (juniorHighSchool.Students != null && juniorHighSchool.Students.Count > 0)
```
[こちらのサイト](https://www.dcom-web.co.jp/lab/cs/extension_method3)のように拡張メソッドを作る方法もありますが，毎回プロジェクトごとに作るのは面倒です．

そこで，null条件演算子を使うと以下のように書けます．

```cs
if (list?.Count > 0)
```
listがnullの場合null > 0が評価され，これはfalseになります([Microsoft Docs](https://docs.microsoft.com/ja-jp/dotnet/csharp/programming-guide/nullable-types/using-nullable-types))．listがnullでないけど空の場合，list.Count > 0が評価されてfalseになります．よって，Listがnullでない，かつ空でない場合のみtrueになります．
これならList名を1回しか書かないのですっきりします．

なお，この条件の否定（nullまたは空である）は以下のように全体を()で囲まないといけません．

```cs
if (!(list?.Count > 0))
```
これだとちょっとわかりにくいかもしれません．
Ansibleでリスト変数をループ処理する方法

# やりたかったこと
Ansibleを用いて定義したリスト変数（配列変数）をPlaybook実行時にリスト変数内の値ごとにループ処理を行いたかった。リスト変数で定義した複数の名前に対して複数ディレクトリを作成するという処理を例にまとめておく。

# 実現方法
調べたり実行してみたりした所、以下の3つの方法があったのでそれぞれについて記載していく。
1. Playbookファイルに直接書く方法（yaml形式）
2. inventoryファイルに書く方法（yaml形式）
3. inventoryファイルに書く方法（ini形式？）

どの実現方法も以下の方法で実行している。

```sh
# ansible-playbook -i <inventoryファイル> <Playbookファイル>
```

## Playbookファイルに直接書く方法(yaml形式）
Playbookファイル上で変数宣言するにはvarsセクションにリスト変数を定義しておきます。ディレクトリを複数作成するPlaybookファイルは以下のように書きます。

```yml:mkdir1.yml
---
- hosts: servers
  become: yes
  gather_facts: false
  vars:
    directories:
      - test1
      - test2
  tasks:
    - name: Create test directory
      file:
        path: '/tmp/{{ item }}'
        owner: 'root'
        group: 'root'
        mode: '0644'
        state: directory
      with_items: '{{ directories }}'
```

リスト変数をPlaybook上でループ処理するにはwith_itemsモジュールの配下に書くのでは無く、上記のように```with_items: '{{ リスト変数 }}'```と書くことで変数を展開してくれるようです。
inventoryファイルについては以下のように書きます。

```ini:inventory1
[servers]
10.0.0.11
10.0.0.12

[servers:vars]
ansible_user=user
ansible_become_user: root
ansible_become_pass: ****
ansible_ssh_private_key_file: ~/.ssh/id_rsa
```

## inventoryファイルに書く方法（yaml形式）
Playbookファイルではなくinventoryファイルで変数宣言する場合、Playbookと同様にinventoryファイルをyaml形式で書く方法があります。Playbookファイルはvarsセクションを削除して以下のように修正しています。

```yml:mkdir2.yml
---
- hosts: servers
  become: yes
  gather_facts: false
  tasks:
    - name: Create test directory
      file:
        path: '/tmp/{{ item }}'
        owner: 'root'
        group: 'root'
        mode: '0644'
        state: directory
      with_items: '{{ directories }}'
```

inventoryファイルをyaml形式で書いた場合は以下となります。

```yaml:inventory2.yml
servers:
  hosts:
    10.0.0.11
      directories:
        - test1
        - test2
    10.0.0.12
      directories:
        - test3
        - test4
  vars:
    ansible_user: user
    ansible_become_user: root
    ansible_become_pass: ****
    ansible_ssh_private_key_file: ~/.ssh/id_rsa
```

## inventoryファイルに書く方法（ini形式？）
従来のinventoryファイルの書き方でもリスト変数を定義するには以下のように変数を[]で囲んで定義する書き方で実現できます（この方法が一番やりたかったが情報が見当たらなかったです）。Playbookファイルはyaml形式の場合と同様なので省略し、invenntoryファイルのみ以下に書きます。

```ini:inventory3
[servers]
10.0.0.11 directories='["test1", "test2"]'
10.0.0.12 directories='["test3", "test4"]'

[servers:vars]
ansible_user=user
ansible_become_user=root
ansible_become_pass=****
ansible_ssh_private_key_file=~/.ssh/id_rsa
```

# まとめ
3つの方法でリスト変数を使用し、ループ処理する方法についてまとめてみた。書きやすい方法を選択して実装できればと思います。
JupyterNotebookの初期ディレクトリを変更する

## Jupyterを使ってPythonを勉強したい

お正月を迎え、新しいことに挑戦したくなる今日この頃。。。
私は昨年も研修等に参加し少しずつ学習を進めているPythonを使った
機械学習について学習しようと、Anacondaを自宅PCにインストールしました。

以前購入したまま眠っていた書籍によると、Jupyterでお手軽に勉強するのがおすすめとのこと。。。
Jupyterは研修でも使ったので知っているし、この方法を採用しようと早速インストール。

せっかく勉強したノートは1か所にまとめておきたいし、ほかのソース群と同じ場所で管理したい！
私がソース管理しているフォルダはCドライブではなくDドライブです。
Jupyterではデフォルトではユーザーディレクトリが開き、Dドライブへは移動できなさそう。。。

## デフォルトのディレクトリを変更することで対応できるよ

まず、Anaconda Prompt を起動します。
プロンプトで以下のコマンドを実行します。

```bash
> jupyter notebook --generate-config
```

`C:\Users\username\.jupyter\jupyter_notebook_config.py`が作成された旨のメッセージが表示されるので、適当なエディタで上記ファイルを開き、以下の記述を探します。

```python
#c.NotebookApp.notebook_dir = ''
```

コメントアウトを外し、初期フォルダにしたいパスを記述し、保存します。

```python:例
c.NotebookApp.notebook_dir = 'D:\sources\SelfLearning\Anaconda3\'
```


Jupyterを起動すると、上記のフォルダが初期表示されると思います。

## 環境について

上記内容を実践した環境は以下の通りです。

* Windows10(64bit)
* Anaconda3(2018.12)
【Mac】仮想マシン（Virtual Box）にKali Linuxを導入する簡単な方法

Kali LinuxをVirtualBoxで使う時に、簡単に設定できる方法がわかったので書いておきます。みなさんご存知かもしれませんが、私は、VirtualBoxの新規ボタンから作成・設定して、それにKaliを入れてました・・・。

VirtualBoxが入っている前提でKaliの導入方法だけ書いていきます。


#手順
##１．Kali Linuxをダウンロード
><ダウンロードページ>
>https://www.offensive-security.com/kali-linux-vm-vmware->virtualbox-image-download/

<img width="1141" alt="スクリーンショット 2019-01-05 11.33.33.png" src="https://qiita-image-store.s3.amazonaws.com/0/332964/bcf5f471-c7c9-0c3d-02e8-d333a27ab809.png">

ダウンロードするファイル：Kali Linux Vbox　XX bit ova
（何ビットかは、環境によります）

・直にファイルをダウンロードする場合:imagenameのところをクリック
・ダウンロード用のtorrent（トレント）ファイルをダウンロードする場合:torrentのところをクリック
（トレントファイルの方がダウンロードが早いです ※方法は以下を参照）
***
【torrentファイルを使ったダウンロード】

①まず、torrentファイルを扱えるソフトをダウンロード
私は、Bittorrentを使いました
<ダウンロードページ>
https://www.bittorrent.com/lang/ja/
※FacebookとかBooking.comとかが出て来た時に何も考えずにOKと押すとアプリがダウンロードされるので気をつけてください・・・。

②Bittorrentを開いて、この画面にtorrentファイルをドラック
<img width="1149" alt="スクリーンショット 2019-01-05 11.28.26.png" src="https://qiita-image-store.s3.amazonaws.com/0/332964/1ed547bd-c326-8b25-69d4-7e42517d1439.png">

##２．Virtual Boxを開いて、Kali Linuxを入れる
①ファイルタブの”仮想アプライアンスのインポート”をクリック
②こういう画面になるので、入力フォームの右側のフォルダボタンからファイルを選ぶ
<img width="718" alt="スクリーンショット 2019-01-05 11.05.06.png" src="https://qiita-image-store.s3.amazonaws.com/0/332964/9dad1f7e-c916-01b0-d881-f15c7b8cadc8.png">
③設定が表示されるので、特にこだわりがなければ”インポート”をクリック
<img width="718" alt="スクリーンショット 2019-01-05 11.05.57.png" src="https://qiita-image-store.s3.amazonaws.com/0/332964/90e0f486-e7c0-c667-82e9-07cc714668b1.png">
④VirtualBoxでKali Linuxをダブルクリック
<img width="718" alt="スクリーンショット 2019-01-05 11.09.50.png" src="https://qiita-image-store.s3.amazonaws.com/0/332964/762b7f80-3cd2-5408-41bb-248030b0c913.png">
⑤ほっとくとこの画面になるので、サインインします。（初期設定は以下のとおりです）
ユーザーネーム：root
パスワード：toor
<img width="801" alt="スクリーンショット 2019-01-05 11.12.18.png" src="https://qiita-image-store.s3.amazonaws.com/0/332964/5e5bbb2e-146b-17b6-4888-8286568aa3d3.png">

完了！！
<img width="799" alt="スクリーンショット 2019-01-05 12.17.03.png" src="https://qiita-image-store.s3.amazonaws.com/0/332964/e636ac5c-4631-6829-6bff-814a51a74d18.png">
MacBookとiPhoneを使うときでは人格が変わるTwitterユーザーの秘密

MacBookとiPhoneを使うときでは人格が変わるTwitterユーザーの秘密

まさにUIがUXを変える例かもしれない

# MacBook

- 長文が打てるので饒舌になる、なんでも語る事ができる
- Twitterでもとても140文字に収まらないことが言いたくて、GitHub issues や Medium に記事を書いてリンクする
- あまりにもiPhoneに比べてスピード感が速くて10倍ぐらい出るので、めちゃくちゃリプの多い迷惑ユーザーになる可能性もあるので、なるべく分散させていく「

# iPhone

- フリック入力すぐ間違う、MacBookと同じように使えるはずはないが、急にiPHpneに切り替わるとMAcBookの残像が残っていて同じことをしようとする
- 言いたいことがなんにも言えなくて、ほとんど絵文字1個のリアクションになる
- 言葉足らず、原始人、サインっだけ、別人格になる、カタコトユーザーになる

# デバイスの長所をもっと理解して使い分けたい

- 改めて考えれば当たり前のことでも、僕らの指先は無理なことをしようとしたりしている
- 自動的に動いている意識の残影、iPhoneなのに長い説明を書こうとしてる！というような、デバイスと仲の悪いアクションを謹んでいく、意識的に
- デバイスに適応することで僕らの人格は変わって見えてしまうが、それを許容して使い分けていく

おもえばメール送信するとき「iPHoneからです」みたいな署名がつくのは「カタコトだけど許してね」ってサインだったのかもしれない🤔


---

https://twitter.com/yumainaura

https://github.com/YumaInaura/YumaInaura/issues

https://github.com/YumaInaura/YumaInaura/issues/239











<!-- Update From Qiita API -->

# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ





# Twitter


https://twitter.com/YumaInaura


<!-- Update From Qiita API -->
React-Router + Reduxの注意点 - withRouter


React-RouterとReduxを同時に使うときの注意点が次のドキュメントにあります。[Redux Integration - REACT TRAINING / REACT ROUTER](
https://reacttraining.com/react-router/web/guides/redux-integration)。多くの場合問題なく使えるが、注意点もある。withRouterを使えば解決できる。というような趣旨ですが、あまり明確に理解できなかったので実験を行いました。

問題は**props.history**が機能しない場合があるというものです。以下のソースコードで試してみました。props.historyは＜Route＞を通した場合に有効になるものです。それ以外だと**withRouter**で使えるようになります。




```react:src/App.js
import React  from 'react';
import {Route, Link, withRouter} from 'react-router-dom'
import { connect } from 'react-redux'

const App = () =>
  <div>
    <Route exact path="/" component={Home} />
    <Route path="/comp1" component={Comp1} />
    <Route path="/comp5" component={Comp5} />  -- 5-1
    <Route path="/comp6" component={Comp6} />  -- 6-1
    <Route path="/comp7" component={Comp7} />  -- 7-1
  </div>
 
const Home = () => (
  <div>
    <Link to="/comp1">Comp1</Link><br />
    <Link to="/comp5">Comp5</Link><br />  -- 5-2
    <Link to="/comp6">Comp6</Link><br />  -- 6-2
    <Link to="/comp7">Comp7</Link>        -- 7-2
  </div>
)
 
const Comp1 = (props) =>
  <div>
    <button onClick={() => props.history.goBack()}>
      Comp1
    </button><br />
    <Comp5 /><br />
    <Comp6 /><br />
    <Comp7 /><br />
  </div>;

// ---　ラッピングなしの通常のComponent
const Comp5 = (props) =>
    <button onClick={() => props.history.goBack()}>
      Comp5
    </button>

// ---　connnectラッピングのComponent
const Comp6 = connect()(
  (props) =>
    <button onClick={() => props.history.goBack()}>
      Comp6
    </button>
)

// ---　withRouter+connnectラッピングのComponent
const Comp7 = withRouter( connect()(
  (props) =>
    <button onClick={() => props.history.goBack()}>
      Comp7
    </button>
))

export default App
```

＜Route＞を通せばすべてのケース(5-1, 6-1, 7-1)で成功した。
＜Link＞の場合は、withRouterでラッピングした7-2だけが成功し、5-2と6-2は失敗した。これってあまりReduxの問題ではないような気がしますが。


以上ですが、念のため環境構築と他のソースも掲載しておきます。

```
npx create-react-app redux-react-router
cd redux-react-router
npm i --save redux react-redux react-router-dom
rm -rf src
```


```react:src/index.js
import React from 'react';
import { render } from 'react-dom';
import {BrowserRouter} from 'react-router-dom'

import App from './App';

import { createStore } from 'redux'
import { Provider } from 'react-redux'
import rootReducer from './reducer'

const store = createStore(rootReducer)
 
const target = document.getElementById('root');

const node =(
  <Provider store={store}>
    <BrowserRouter>
      <App />
    </BrowserRouter>
  </Provider>
);

render(node, target);
```


```react:src/reducer.js
export default (state = {}, action) => {
    switch (action.type) {
        default:
            return state;
    }   
}
```


以上です。
AE テキストレイヤーをJsonから参照させた時の改行方法（エクスプレッション）

#やりたいこと
テキストレイヤーのソースをJSONで参照させた時、任意の場所に改行コードを付け足す。

#問題点
以前の記事にもありますが、直接JSONに改行コードを打てるのですが、挙動がおかしかったため別の方法を・・・

#解説
テキストの指定の場所に\rを付け足すだけです。
テキストレイヤーにエクスプレッション制御２つを追加します。
①スライダー（改行コードを入れる場所を指定する用 name = br_count）
②チェックボックス（単純に改行させるかさせないかのスイッチ　name = 改行ファンクション呼び出し）

そしてエクスプレッションにはこんな感じ

```jsx
cb = effect("改行ファンクション呼び出し")("チェックボックス");
length = Math.floor ( effect("br_count")("スライダー") );
txt = text.sourceText;

function insertStr(str, index, insert) {
   return str.slice(0, index) + insert + str.slice(index, str.length);
}

if (cb !=0 ){ 
  insertStr(txt, length, '\r')
}
else{
  txt
}
```

参考画像ではテキストレイヤーの９文字目に改行コードを入れています。
チェックボックスをオフにすれば改行コードは挿入されません。

![001.PNG](https://qiita-image-store.s3.amazonaws.com/0/178061/081a53f5-7f67-6aa8-c9e0-7a7f769af34c.png)
Postfix メール転送設定

# はじめに
CentOS7上のPostfixのメールの転送設定について整理しました。
この記事では、以下の2つの方法について書いていきます。
1.`/etc/aliases`でメールのエイリアスを作成する
2.`.forward`でメールの転送設定をする

# /etc/aliasesでメールのエイリアスを作成
`/etc/aliases`ファイルに、`転送元: 転送先`を指定することでメールのエイリアスを作成できます。
`/etc/aliases`ファイルはrootユーザのみ変更が可能です。

```/etc/aliases
# Basic system aliases -- these MUST be present.
mailer-daemon:	postmaster
postmaster:	root

# General redirections for pseudo accounts.
bin:		root
daemon:		root
adm:		root
lp:		root
sync:		root
shutdown:	root
halt:		root
mail:		root
(省略)
```

```/etc/aliases
papapapaper:    papapapaper@gmail.com
```
上記の例では、papapapaperユーザ宛てのメールをgmailに転送しています。
メールのエイリアスを作成すると、転送元にはメールが届かなくなります。

```
# newaliases
```
`/etc/aliases`ファイルを変更したら、`newaliases`コマンドを実行し、`/etc/aliases.db`（エイリアスデータベース）を更新します。Postfixは`/etc/aliases.db`を参照して転送を行うため、`newaliases`コマンドを実行しないと、上手く転送できません。

# .forwardでメールの転送設定
各ユーザのホームディレクトリに`~/.forward`ファイルを作成することで、メールの転送設定を行えます。
転送元のユーザのホームディレクトリに作成した`~/.forward`ファイルに、転送先のメールアドレスを記載します。

```.forward
papapapaper@gmail.com
```
上記の例では、papapapaperユーザ宛てのメールをgmailに転送しています。
設定反映時にリロードや再起動は不要です。
メールのエイリアス作成と同様、転送元にはメールが届かなくなります。

```.forward
\papapapaper
papapapaper@gmail.com
```
転送元にもメールが届くようにしたい場合は、上記の様に`\ユーザ名`を記載します。
Vue.js 勘違い集

自分がVue.jsを触っていて勘違いしていたことをここに綴ります。
一通りドキュメントを読んだ程度の初心者の理解の確認の助けになればと思います。

もう少し溜まってからが良かったと思ったんですが、下書きが圧迫しているので公開します。

## なぜか動かない

- メインのVueオブジェクトのel属性で指定されている要素よりも親の要素を操作しようとしていた

## selectタグ配下のoption要素を動的に作れない

```HTML
<!-- 動かない -->
<select>
  <div v-for="option in options">
    <option :value="option.v">{{option.text}}</option>
  </div>
</select>
```

- optionに直接v-forを記述する。
  - select要素配下にはoption要素しか置けないことが原因。
  - `v-for`はただの構文で要素を操作しているわけではないという勘違いによるもの。
  - [https://jp.vuejs.org/v2/guide/forms.html](https://jp.vuejs.org/v2/guide/forms.html)

## $emitしたイベントが受け取れない

```JS: 
Vue.component("human", {
  props: ["name"],
  template: `<button @click="console.log('emit a'); $emit('a')">{{name}}</button>`,
});

var app = new Vue({
  el: "#app",
  data: function(){
    return {
      names: ["a", "b", "c"],
    }
  },
});
```

```HTML
<!-- 動かない -->
<div id="app">
  <div v-on:a="console.log('listen')">
    <human v-for="n in names" :name="n"></human>  
  </div>
</div>
```

- `v-on:a`はイベント`a`を送出するタグのあるテンプレートを持つコンポーネントでしか使えない。
  - 情報を親コンポーネントに伝える目的ではあるのだが、自分のコンポーネントではなく親のコンポーネントに`v-on`を書いてしまう勘違いによるもの。

## コンポーネントのテンプレートがなぜか途中までしか表示されない

```JS

Vue.component("human", {
  props: ["name"],
  template: `<div>あ</div><div>{{name}}</div>`,
});

var app = new Vue({
  el: "#app",
  data: function(){
    return {
      names: ["a", "b", "c"],
    }
  },
});
```

- `<div>{{name}}</div>`の部分しか表示されない
  - ルート要素は一つに限るという規定があるよう。
  - `<div><div>あ</div><div>{{name}}</div></div>`とすることで解決
バリデーションで存在確認をする際のベターネーミング

CodeIgniter 3.* で入力されたメールアドレスが DB に存在するか確認する際の__バリデーションルール名__で少し迷ったのでメモ。
※ CI のバリデーションについては [Form Validation](https://codeigniter.jp/user_guide/3/libraries/form_validation.html)を参考

# やりたいこと
ユーザ登録時、入力されたメールアドレス（email）が DB に

* 存在する：バリデーションエラー
* 存在しない：非エラー

となるよう、__「メールアドレスは存在するか」__を意味するルール名を作る。

# 実装
存在すれば真、存在しなければ偽を返す以下のメソッドを作成した。

```php
function _is_email_existed($email)
{
    return $this->db->_is_email_existed($email);
}
```

DB->_is_email_existed() は、引数 email を条件に DB を検索し、その件数を返すメソッド。
（０件のときのみ FALSE になる）

これを用いてバリデーションを実行すると、以下の結果となる。

|入力|DB|返り値|検証|期待|
|:--|:--|:--|:--|:--|
|a＠b.com|a＠b.com|TRUE|OK|重複有り：NG|
|b＠c.com|a＠b.com|FALSE|NG|重複無し：OK|

つまり、「入力値は存在するか」という命題は、存在すれば真、存在しなければ偽を返すが、検証は真のときエラーとならないため、おかしなことになる。
かといって、この命題に対する返り値を否定すると、命題とそれに対する返り値が不自然。

どうするのがより自然で一般的なのか？

以下の２つの候補がある。

1. ルール名を *is_email_not_existed* にして整合させる
2. 返り値を否定する

と挙げたが、1 の場合はいちいち存在確認の検証ルールに "*not*" をつけることになるし、
他ルールの慣習に合わない気がする。しかも、長い。

# 結果
ルール名は __*is_email_existed*__ のまま、__返り値を否定__することによって実現。

つまり、以下の通り。

```php
function _is_email_existed($email)
{
    return ! $this->db->_is_email_existed($email);
}
```

これで、重複があれば *NG*、なければ *OK* が返る。
Visual Studio Code 便利拡張機能

visual studio code の拡張機能で便利だったもののメモ  

## Paste Image  
クリップボードに画面キャプチャーがある場合、
Ctrl + Alt + V で貼り付けると画像を貼り付けることができる。
デフォルトの画像の保存先は、.mdファイルと同じディレクトリ

visual studio code のワークスペースファイルを作成し、
settingsにpasteImageの設定情報を記述することで保存先の変更などが可能。

``` json  
{
	"folders": [
		{
			"path": "."
		}
	],
	"settings": {
		"pasteImage.path": "${projectRoot}/markdown/img",
		"pasteImage.basePath": "${projectRoot}",
		"pasteImage.forceUnixStyleSeparator": true,
		"pasteImage.prefix": "/"
	}
}
```
CentOS 7にApache httpdをインストールしてブラウザ確認するまで

#環境
 - macOS 10.12.6
 - MacBook pro 2016
 - VirtualBox 5.2.18
 - CentOS 7.6-1810

#yumでインストール
yumコマンドでインストールします。
CentOS 7では公式のyumリポジトリにhttpd2.4があるので、そちらをインストール。
###yumとは
パッケージ管理システムです。rpmというパッケージ管理システムを内包しています。
rpmの足りないところを、yumが補っています。
###rpmとは
rpm(Red Hat Package Manager)の名前の通り、RedHat系のディストリビューションのパッケージ管理システムです。よって、yumもRedHat系用になります。（ちなみにDebian系はapt）
`yum = rpm + α`って感じです！
###rpmにはなくてyumにはある機能
rpmではインストールするパッケージの依存関係を検知することはできても、その依存関係にあるパッケージを自動で一緒にインストールまでしてくれません。ですが、yumは依存関係にあるパッケージまで全部一緒にインストールしてくれます。なので、yumを使ってパッケージを入れれば、そこらへんの配慮をしなくても、コマンド１つでやってくれちゃうわけです！
あと、もう一つリポジトリの自動更新も行なってくれます。
###リポジトリ
リポジトリは、複数のパッケージを格納している場所のことです。
ここには、複数のパッケージのメタ情報も一緒に置いてあります。
yumは、 `/etc/yum.repos.d/`配下の`.repo`拡張子のファイルの中身を見て、その中にあるリポジトリの中のパッケージをrpm経由でインストールします。
よって、ここに記載のないものはインストールできません。
最新のものをインストールしたいときには、ここに追加しなくてはなりません。
今回は、Apache httpd 2.4がデフォルトで存在するので、インストール可能というわけです！
インストール可能かどうかは、以下のコマンドでわかります。

```
# yum info [パッケージ名]
```
パッケージの詳細情報を出してくれます。
###インストール
インストール自体は先ほども言いましたが、コマンド１つです。

```
# yum -y install httpd // -yは、すべての問いに「yes」と回答したものとして実行するオプションです。
```

#Apacheの起動と停止
###起動
```
# systemctl start httpd
```
CentOS 6 以下は、`service`コマンドを使ってください。
###起動の確認
```
# systemctl status httpd
```
たくさん文字が出てきますが、`Active: active (running)`とどこかにあれば動いている証しです。
###停止
```
# systemctl stop httpd
```

#自動起動の設定
これは、CentOSの起動・再起動の際に一緒にApache httpdも起動するようにする設定です。
以下のコマンドでOK

```
# systemctl enable httpd.service
```
CentOS 6 以下は、`chkconfig`コマンドを使ってください。

#ブラウザ確認
まずは、CentOSがデフォルトでfirewalldが動いていてアクセス制御されているので、httpdを許容するように設定します。
これも、コマンドでできちゃいます。

```
# firewall-cmd --add-service=http --zone=public --permanent
# firewall-cmd --reload //反映
```

あとは、ブラウザで`http://CentOSのIPアドレス`を叩けば、以下の画面が表示されて完了です。
<img width="1440" alt="スクリーンショット 2019-01-05 11.32.42.png" src="https://qiita-image-store.s3.amazonaws.com/0/183984/3ae72e74-c789-42cc-1269-5560d2365073.png">
Django + GAE or Heroku (deploy)

##Reference
[App Engine スタンダード環境での Django の実行](https://cloud.google.com/python/django/appengine)

[Google App Engine のドキュメント](https://cloud.google.com/appengine/docs/?hl=ja)

[Getting Started on Heroku with Python](https://devcenter.heroku.com/articles/getting-started-with-python)

[Git Documentation](https://git-scm.com/doc)

##1. GAE
##/[project_name]/settings.py
```python
ALLOWED_HOSTS = ['*']
```

##/[project_name]/wsgi.py
```python
import os

from django.core.wsgi import get_wsgi_application

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'dj_project_1.settings')

application = get_wsgi_application()
```

##/app.yaml
```python
# [START django_app]
runtime: python37

handlers:
# This configures Google App Engine to serve the files in the app's static
# directory.
- url: /static
  static_dir: static/

# This handler routes all requests not caught above to your main app. It is
# required when static routes are defined, but can be omitted (along with
# the entire handlers section) when there are no static files defined.
- url: /.*
  script: auto
# [END django_app]
```

##/main.py
```python
from [project_name].wsgi import application

# App Engine by default looks for a main.py file at the root of the app
# directory with a WSGI-compatible object called app.
# This file imports the WSGI-compatible object of your Django app,
# application from mysite/wsgi.py and renames it app so it is discoverable by
# App Engine without additional configuration.
# Alternatively, you can add a custom entrypoint field in your app.yaml:
# entrypoint: gunicorn -b :$PORT mysite.wsgi
app = application
```

##/requirements.txt
```python
Django==2.1.3
```

##deploy
```python
#local
virtualenv ./envs/django
source ./envs/django/bin/activate

pip install -r requirements.txt
```

```python
gcloud app deploy
```

##2. Heroku
##/[project_name]/settings.py
```python
import django_heroku

django_heroku.settings(locals())

# delete the above for local testing
# python manage.py runserver
```

##Procfile
```python
web: gunicorn [project name].wsgi --log-file -
```

##runtime.txt
```python
python-3.6.6
```

##requirements.txt
```python
django
gunicorn
django-heroku
numpy
scikit-learn
gensim
```

##.gitignore
```python
staticfiles
db.sqlite3
.spyproject/*
```

##deploy
```python
git init

heroku login
heroku create

git status
git add
git commit -m 'comments'

git push heroku master

heroku ps:scale web=1
heroku open

heroku ps:scale web=0
```
プログラムと美しさ：第三章　ロジック　―プログラミングは愛情―

～ プログラミングって面白そうと思った方に向けた連載エッセイ ～

　どんな論理、手法、手順で組み立てられているか。一般的にプログラムの美しさというと、これを指すことが多いかもしれない。

　ロジックは、短く簡潔にまとめられているのが美しい。

　プログラミングにおいて、短さは善である。短かければ短いほど美しくもある。極端な話、コードを一行も書かないで実現できればそれがベストだ。一行でも書けばバグの可能性が生まれる。ゼロ行ならバグの入り込みようがない。かつてはプログラミング作業の成果を「ステップ数」と呼ばれる記述行数で測ることが多かったが、最近ではプログラムの規模を把握するための一つの参考指標にその位を下げている。苦労して行数をたくさん書くのではない。短時間でコードを量産することが偉いのではない。たくさん書けば、その分保守すべき対象も増えてしまう。考え抜いて簡潔なロジックで表現し、奮闘の成果としてコード量を減らすのである。

　コンピュータのスペックが貧弱な時代には、保存領域や読み込み時間、実行時のメモリ使用量を抑えるため、プログラムサイズを小さくすることが重要だった。今でも組み込み系開発では重視される要件だろうが、パソコンに限って言うと、大容量のハードディスクがメモリや安価に購入できるようになり、その優先度は低くなった。人は制限がなくなれば甘えるものである。実現できることの幅が広がったのは喜ばしいことだが、パソコン向けのソフトウェア開発において、極力コード量を減らそうという動機づけが一つ減ってしまったのは残念な副作用である。プログラマには、感じない方がいい自由もある。

　処理速度についても同様である。パソコンの処理能力向上に比例して、プログラマの意識は低くなっている。このくらいの無駄は、今のパソコンの処理能力をもってすれば体感できるほどのロスにはならないだろう、というわけである。しかし、わずかな負荷も積み重なれば無視できない大きさになる。プログラムの処理では、繰り返しが頻繁に行われる。ある一塊のロジックを記述するということは、それがほかのプログラマによって、ときとして別のプログラムからも使用される可能性があるということであり、その使用方法を完全に制御することはできない。どのタイミングで呼び出され、何度繰り返されるか、将来にわたって正確に想定するのは難しい。コンマ１秒の処理は体感できないかもしれないが、それが千回繰り返されれば百秒である。これを体感できないほどおおらかなユーザーはいないだろう。決してわかりやすく強調した大げさな話ではない。実際にこうした問題が起こって原因を調査し、非効率な実装に気づくことも少なくないのである。

　現代のプログラミングでは、ある程度の汎用的なロジックは部品として提供されており、それを駆使してプログラムを組む。一からすべてを実装することはまずない。部品の処理仕様は公開されているが、その具体的実装は基本的にブラックボックスである。その中身が効率よく実装されている保証はない。部品を使う側のプログラマは、仮に非効率な実装であっても極力パフォーマンスに影響が及ばないよう、呼び出す回数をなるべく少なくするなどの心がけを――常に最優先というわけではないが――忘れてはならない。優しく使ってあげよう、ということだ。そして部品を作る側に回ったときには、使う立場に思いを馳せ、できるだけ効率的なロジックで実装してあげるのである。双方の気遣いがロジックに込められて、優れたパフォーマンスのプログラムとして提供される。ユーザーは気持ちよく操作する。料理は愛情という。プログラムにおいても愛情が大切である。これもまた美しいとは、こじつけかもしれないが。

　「見た目」について記述した先の章で "DRY"（"Don't repeat yourself"）――重複を避けろ――という原則を紹介した。これはロジックにも関わることである。無駄なロジックは美しくない。ロジックがすでに部品化されているのに自前で実装しようとするのも、また無駄である。それは「車輪の再発明」と揶揄されたりする。

　ここで例を挙げよう。

> 今年二十歳を迎えた劉さんの娘が座ったまま眠ってしまった。
> 今年二十歳を迎えた劉さんの娘は昨日、現在私とその家族が住んでいる家にやって来たのだった。
> たぶん飲みすぎたんだろうな。
> 言い忘れていたが、今年二十歳を迎えた劉さんの娘というのは女性である。


　「今年二十歳を迎えた劉さんの娘」を読むたびに、それが誰かを特定するための信号が脳内を駆け巡ると想像していただきたい。繰り返すのは無駄である。

　一文目と二文目は時系列が逆である。二文目を読んだ後に一文目を解釈し直さなければならない。

　二文目の「現在私とその家族が住んでいる家」は、それを表す便利な言葉がすでに発明されている。

　三文目は文芸的には価値があるのかもしれないが、ロジック的に遅れて種を明かす価値はない。

　四文目に関しては、丸ごと無駄である。しかし笑ってはいられない。あなたがプログラマになったら、このようなコードに出会うこともあるだろう。

　組み直してみる。


> 劉さんの娘は今年二十歳を迎えた。
> 彼女が昨日我が家にやって来た。
> 彼女は飲みすぎたのか、座ったまま眠ってしまった。

　「彼女」という代名詞を使うことで、誰だが特定する処理を一回に減らすことができた。無駄が一つなくなった。プログラミングの世界では、「変数」という仕組みを使って同じことが実現できる。

　無駄は美しくない。ロジックについても然りである。ある課題を無駄のない効果的な方法で解決したとき、そのロジックを美しいと評することができるだろう。美しいロジックは理解しやすく、使いやすく、変更しやすい。

　ロジックはその目的たる処理動作とも不可分である。無駄のないロジックは無駄のない処理動作の基礎となる。プログラムの機能美という側面からは、処理動作の効率性も美しさの重要な位置を占めるだろう。

---

[序章](https://qiita.com/CodeOne/items/01b4e49a7d5a84d48c71)
[第一章　その美の特徴](https://qiita.com/CodeOne/items/1969ec81d04529fbdb34)
[第二章　見た目と冗長性](https://qiita.com/CodeOne/items/96df6d1140301347156a)
第三章　ロジック
[第四章　命名](https://qiita.com/CodeOne/items/dfc3ace22c46273dc22c)
[第五章　アーキテクチャ](https://qiita.com/CodeOne/items/469b9f421e5d914f1ffb)
[第六章　リファクタリング](https://qiita.com/CodeOne/items/df50fad6bb0bd2f0096f)
[第七章　デザインパターン](https://qiita.com/CodeOne/items/0ac628d6be24328ecc10)
[第八章　正規化](https://qiita.com/CodeOne/items/5df2a5e38cc4c1c90a7a)
[終章](https://qiita.com/CodeOne/items/12ad8d54329bc946b85c)
基礎からのVMware Cloud on AWSーその７

VMware Cloud on AWSの基礎を
おさらいするための記事を書いてます。

過去６回は以下の内容をお届けしました。

第１回　物理構成の理解
https://qiita.com/hiroito1118/items/48d8d66fab24acd16c1d

第２回　管理方法と初期デプロイの概要
https://qiita.com/hiroito1118/items/8ed96c156b8577ca4749

第３回　ユースケース
https://qiita.com/hiroito1118/items/2669fc0ef64d8e07eb08

第４回　調達方法
https://qiita.com/hiroito1118/items/3ebbf3ce7a555d2f39f6

第５回　ハイブリッドクラウドを支えるネットワークサービス・製品
https://qiita.com/hiroito1118/items/7e57393e72d72e00d4a2

第６回　AWSネイティブサービスとの連携
https://qiita.com/hiroito1118/items/80b05507f7e77c14e9db


今回はサポートに関する話です。
関連するメンテナンスの話も触れておきます。


# １．VMware Cloud on AWSにおけるサポート
VMware Cloud on AWSにおいて、
利用者がどこまでの範囲を取り扱えるのかを知った上で、
サポートについて見ていきたいと思います。

## １）VMware Cloud on AWSにおける取り扱い範囲
VMware Cloud on AWSにおいては、
ハードウェアレイヤはAWSが、
仮想化レイヤをVMwareが管理することになります。
その為、利用者はSDDCに対する設定とOS以上が管理対象となります。
ここは責任分界点として明確に理解することは、
AWSを利用する際同様、クラウド利用において必須の理解事項です。

## ２）サポートの受け方
従来のライセンスと異なり、VMware Cloud on AWSでは、
VMware Cloud ポータル上から起票する形式となります。

方法としては、
　A.問い合わせフォームへの記入
　B.チャットによる投げかけ
の２パターンがあります。

当然、チャットの方がレスポンスがよく、
リアルタイムに問題解決を実施することができます。

ちなみに本記事執筆時点では、
サポートは英語のみでの提供となっています。
日本語でのサポートを受ける場合は、
マネージドサービスプロバイダ経由で
VMware Cloud on AWSを利用することで、
マネージドサービスプロバイダが提供してくれます。
英語が難しい場合は、こちらを選択しましょう。

なお、マネージドサービスプロバイダについては、
第４回でも触れましたが、
通常のVMware CLoudの認定パートナーとは異なり、
月額提供できるなど少し異なります。
提供可能な社数は限られるので注意が必要です。

第４回の記事は↓
https://qiita.com/hiroito1118/items/3ebbf3ce7a555d2f39f6


## ３）管理されることの意味
VMware側で管理されるということは、
vCenterやNSX、ESXiの管理やメンテナンスは
全てVMware社によって実施されることを指します。
このメンテナンス負担の軽減がVMware Cloud on AWSのメリットの一つです。

半面、サービス側の裁量で実施されることになりますので、
ユーザ側での指定や日程調整はできません。
本記事執筆時点では、米国からメンテナンスを実施しており、
日本時間の日中にメンテナンスが実施されることもありました。

## ４）メンテナンスの種類
メンテナンスにはVMwareとしてのメンテナンスもありますが、
AWS側のメンテナンスもあります。
双方ともサービスに影響がある場合がありますので、注意が必要です。
なお、メンテナンス通知はVMware Cloudの
ポータルには掲載されない点は改善してほしいポイントですね。


今回は以上です。
次回は、サードパーティー製品との連携に関する話題です。
LB(ALB)配下のec2からLetsEncrypt証明書を取得しようとしたら、別ホストが認証リクエストを受けて困った

## やりたかったこと

- AWS EC2(amazonLinux x 2) + ロードバランサ(ALB) という冗長構成のwebサーバー
- うち片方にLetsEncryptのクライアント（certbot）を入れ、運用するドメインのSSL証明書を取得(http-01認証）
- 取得した証明書をaws-cliでIAMにアップロード & ALBに適用

具体的には下記事の要領に沿ってやりました。
[AWS Let's Encrypt 証明書の自動発行とALBへの自動登録](https://qiita.com/7CIT/items/a0fff4670ed237d27c86)

及び、その元記事であるこちら。
[Let's Encrypt 証明書の自動発行とELB自動登録を行ったログ](https://qiita.com/hidekuro/items/482520f220a305dc147b)

途中、「certbotによる証明書取得のドメイン認証（http認証）のレスポンスを冗長構成のもう1台のサーバーが受けてしまって認証がコケる」という点でハマったので、当記事はその部分の補足です。

今回は対象ドメインのDNS権限がなかったので苦労しましたが、もしDNS権限があれば、認証方式をDNS-01にすれば以下の手順をしなくていいはず。さらにそれがRoute53なら素直にACM使えばいいんでないかと。

## やったこと

の前に、元記事でやってる流れを整理するとこう。

1. ec2にcertbotをインストール
2. certbot-autoコマンドでLetsEncrypt証明書取得
3. 取得した証明書をaws-cliコマンドでIAMに登録
4. 登録した取得した証明書をaws-cliコマンドでALBのリスナーに登録

このうち、2-4の手順をシェルスクリプト化し、取得後の更新も自動化できるようにしてるんですが、そのスクリプトの2(certbot-autoコマンド）のところで、

> The server could not connect to the client to verify the domain

とドメインのhttp認証がコケる。webroot認証は、ec2（以下web01）のcertbotが作ったトークンファイルを別の認証サーバがHTTPでアクセスして行いますが、この時の認証リクエストをcertbotを入れてない方のec2（以下web02）が受けてしまうと404になるわけです。

なんで、スクリプトを流す前に、web02（今回はnginx）の該当ドメインのvirtualhostのconfで、認証リクエストをweb01にリダイレクトする設定を追加。

```nginx:nginx.conf
server {
    listen 80;
    server_name 証明書取得対象のドメイン名;

    ...

    rewrite ^/.well-known/(.*)$ http://web01にあてた別ドメイン名/.well-known/$1 permanent;
}
```

LB配下の各ホストに個別ドメインなんてあててないので、当初rewrite先をIPで指定してたんですが、それはそれで

> Only domain names are supported, not IP addresses

と怒られます。DNS操作できる適当なドメインのサブドメインをRoute53でweb01にあててやることで無事スクリプトが走って、認証をクリアしました。
tarでディレクトリコピー

家のNAS上で `rsync -auv` を利用してコピーをしようとしたら `bus error`  でハングアウトするようになってしまったのでディレクトリのコピーは tar で行うことにした。

```
tar cf - * | ( cd /target; tar xfp -)
```

* `target`配下に展開されていく

必要なファイルだけを選択したり除外したい場合には `find . 検索パターン | xargs tar....` とパイプでつなげていけば特定のファイルだけを処理することができる。
「SSHってなんなの？」レベルだから少し調べた

最近AWSの勉強をしておりまして、EC2インスタンスにssh接続をして向こうのサーバーを操作しているのですが、
「ところでSSHってなんだっけ？安全な接続方式なんだろうけど、人に説明できないや。。。」
って感じなので、少し調べてみました。

# SSHとは
プロトコルの一種。※[プロトコルがわからない方はこちら](https://it-trend.jp/words/protocol)

Secure Shellの略なのですが、文字通り、セキュア(安全)にShellをいじるための通信プロトコルということですね。

通信相手のコンピュータのシェルを操作するために用いられます。

元はtelnetという似たものが存在していたのですが、telnetは安全ではないです。
なぜかというと、平文で通信するから。盗聴されるとすぐに解読されてしまいます。
しかし、sshでの通信の場合、平文ではなく、暗号化して通信を行います。こうすれば通信を盗聴されても読まれる心配はありません。



# じゃあ実際どのように使われるのよ？
調べましたが、いい感じに書いてくれている記事が存在しましたね。
[こちら](https://qiita.com/naoki_mochizuki/items/aea14a65a4a513e4816f)を参照ください。

この記事では、大体の流れをざっくり文字に起こします。

1. ローカル側のコンピュータで秘密鍵&公開鍵の生成
2. 公開鍵をリモート側に渡す(ようやくここでssh接続の準備が完了)
3. ローカル側で`ssh ~`のように、コマンドでssh接続を行う
4. リモート側が公開鍵と乱数で暗号を作成→ローカル側に暗号を送信&ローカル側でハッシュ値を生成
5. 暗号鍵(パスフレーズで復号済み)と受け取った暗号でローカル側が乱数を復号&乱数からハッシュ値を計算
6. ローカル側で計算したハッシュ値とリモート側で生成したハッシュ値が一致すれば、認証完了
F9PでRTK(2023年1月更新)

# 概要
https://www.u-blox.com/ja/product/zed-f9p-module

- ZED-F9PをRTKLIBで使う場合の設定
https://rtklibexplorer.wordpress.com/tag/zed-f9p/

# 要点
・U-blox社で初の2周波対応
対応のGPSアンテナを使って内蔵RTKエンジンを使用した場合、オープンスカイならば１分以内くらいでFIXします。（M8Pだと運が悪ければ１０分以上かかってました）
・UARTが２つ
片方は制約があるので要注意

・RTCM3出力対応
「RTCM3.3」という謎規格ですが、RTCM1008が出力されてない以外はRTCM3.2と同じ？ようです。
Trimble等で使う場合にはRTCM1008が必要なので、どうにかする必要があります。

・Farmware Update
https://www.geosense.co.jp/tech_firmware_verup/

# 製品情報
[ZED-F9P搭載GPS-RTKピッチ変換基板](https://www.switch-science.com/products/6319)
・USB-Cコネクタ
・配線の取り回しが微妙に邪悪なので使いづらいかも

[simpleRTK2B Budget](https://www.ardusimple.com/product/simplertk2b/)
・コネクタはUSB micro-B
・通販で買える範囲ではたぶん一番安い
・XbeeコネクタがあるうえにUSB-UART変換＋micro-Bまで付いているので色々捗ります
・オプションも色々（通信モジュールもあるけど日本の電波法対応ではない）
・IOREFつなぎ忘れに注意
・なぜかmicro-Bがもげやすい（気がする）

[Waveshare ZED-F9P GPS-RTK hat for raspberry pi](
https://ja.aliexpress.com/i/1005002638237466.html)
・買ってないので雑感メモ
・アンテナ等とセットなので値段分の価値はありそう
・Pi Zerowにピッタリサイズ（今時はPi zerowが売ってない・・）
・UARTやPPSも配線済みっぽい？
・コネクタはUSB micro-B?

[ZED-F9P RTK GNSS receiver board with SMA Base or Rover](https://gnss.store/zed-f9p-gnss-modules/99-13-elt0087.html)
・小型なのはいいけれどもUART等は裏の12pコネクタからしか出てないので、ピンで出したい場合は次の商品をオススメ
・コネクタは今時あまり見なくなったUSB mini-B
・UARTが必要な人は、裏側コネクタ使う必要があるので別売りの1mmピッチ12pケーブルも必要
・PPSは無い

[ZED-F9P RTK InCase PIN GNSS receiver board with SMA Base or Rover](https://gnss.store/zed-f9p-gnss-modules/105-elt0092.html)
・ピンヘッダー出せるやつ。

[M5F9PとCLASシステム](https://www.geosense.co.jp/product-m5f9p/)
・M5F9P M5Stack用
・無線とか色々オプション豊富
・公式Arduinoプログラムもあって楽ちん
・F9PX1とD9CX1はCLASシステム作れる。初期化時間と精度はRTKほどではないけれど、通信回線ナシでも使えるのは、かなり強い。
MacのBearエディタでメモ一覧とエディタのフォーカスを切り替えるショートカットキー

[Bear](https://itunes.apple.com/jp/app/bear/id1091189122)

Command + Enter で切り替わることを偶然発見する

---
2019年1月6日追記: 
衝撃の事実。 Escキーでも切り替えられる事を発見
IoT python wifi relay control 1000円の中華制御リレーを評価する。

![broadlinksc1.png](https://qiita-image-store.s3.amazonaws.com/0/274715/a48bf6ad-9b8d-3f38-3871-b3703f99a9ad.png)
[wishなどの中華サイト](https://www.wish.com/search/broadlink%20sc2/product/5a387f3e89889914588488ce?&source=search)で1000円程度で45日程度で入手できる。
### Broadlink sc1は、家庭内のwifi経由で簡単に100VACの制御ができる。Android/iPhoneのAppから命令を出し、電灯や扇風機などの家電製品を制御できる。
### PCなどから制御するためには、何らかのプログラムを必要とする。
- 本体には、wifiのssidやパスワード,セキュリティモードの設定は、すべてwifi経由で行います。
- 赤と青の線に100Vコンセントを接続します。
- 茶色と黒の線に100Vの出力を接続します。
![sc1-1.png](https://qiita-image-store.s3.amazonaws.com/0/274715/2ceac3d1-c312-1a5f-4d1b-23de034df873.png)

### 100円均一の延長コードを買い、真ん中で切断すると丁度良いものが作成できます。
### ライブラリを導入します。
```
pip install broadlink
```
[https://github.com/mjg59/python-broadlink](https://github.com/mjg59/python-broadlink)
##### 上記にwifi設定する方法が述べられています。
``` discover.py
import broadlink
broadlink.setup('myssid', 'mynetworkpass', 3)
dev = broadlink.discover(timeout=5)
net=[]
for d in dev:
    d.auth()
    n=dict(type=d.get_type(),ip=d.host[0],port =d.host[1],
             mac = "-".join([format(x,"02x") for x in [x for x in reversed(d.mac)]]),
             timeout = d.timeout)
    net.append(n)
print(net)
```
### mac=...の行は、byte列の[エンディアン変換](https://qiita.com/tobira-code/items/a03f39a02678d80bbd26)を行い、かつ、文字列に変換を一行で行いました。「Pythonの立場でコーディンク」
myssidとmynetworkpassに無線ルータのidとpasswordをセットし実行すると下記のように出力される。
出力結果　サンプル
```out.js
[{'type': 'SP2', 'ip': '192.168.1.102', 'port': 80, 'mac': '78-**-**-**-**-70', 'timeout': 10}]
```
スイッチをONします。

``` on.py
net1=net[0]
sp2 = broadlink.sp2((net1["ip"], net1["port"]),netaddr.EUI(net1["mac"]),net1["timeout"])
sp2.auth()
sp2.set_power(True)
```
スイッチをOFFします。

``` off.py
net1=net[0]
sp2 = broadlink.sp2((net1["ip"], net1["port"]),netaddr.EUI(net1["mac"]),net1["timeout"])
sp2.auth()
sp2.set_power(False)
```
スイッチの状態を調べる

``` status.py
net1=net[0]
sp2 = broadlink.sp2((net1["ip"], net1["port"]),netaddr.EUI(net1["mac"]),net1["timeout"])
sp2.auth()
print(sp2.check_power())
```
Google App Engineにデプロイしたアプリへの接続を常時https化する

# やりたいこと
App Engine へデプロイしたアプリへの接続を常時https化したい

# https化するための設定項目
### app.yamlに 「secure: always」を追加する。
この属性を追加することで、仮にhttpで接続試行した場合もhttpsのURLへリダイレクトされる。
設定例を以下に示す。

```app.yaml
handlers:
- url: /.*
  script: main.app
  secure: always
```

またSecure属性の項目は3つある。
1. **optinal:** http, httpsどちらのURLでも接続可能。Secure属性を省略した場合、本設定が適用される
2. **never:** httpsのURLでアクセス試行されたものをhttpのURLへリダイレクト。なおセキュリティを考慮し、リダイレクト時にクエリパラメータはリクエストから除外される。
3. **always:** 上記参照

# 参考サイト
[Google Cloud app.yaml リファレンス]
 https://cloud.google.com/appengine/docs/standard/python/config/appref