OmniAICreator/Qiita-1.07M huggingface dataset:
レスポンシブメール　虎の巻的な個人メモ

# はじめに
MSO系（Outlook)からのボトムアップアプローチがおすすめ

## 全般
- ほぼ`table, tr, td`で構成する
 - ネストが深くなってもしょうがない
- `table`要素以外でメーラー共通的に安定していることが確認できた要素は下記のみ
 1. `img`
 1. `p`
 1. `a`
 1. `span`
- 開いたタグは必ず閉じる
 - 開閉を確認できるツールを使う
 - 条件付きコメントの開閉は目視で確認するしかない
- MSO系は一つの要素に対してクラスは一つしか適用されない
 - 二つ目以降はまともなメーラーなら適用される
- 背景色は必ず`table`要素の`bgcolor`属性で指定する
- ボックスを作る場合は、条件付きコメントを使ってMSOは`td`、それ以外は`div`を使うようにすること
- `margin`を使わない
 - 使うなら要覚悟　バグだらけ
- `padding`を使うこと
 - 基本的に`td`要素に対して適用する
- `align`は可能な限り`table`の属性で指定する
 - `vertical-align`も`table`の`valign`を使った方がベター
- 文字色等のフォント系のスタイルは、テキストノードの直上の親に指定する  
（そうしないと適用されない環境がある）
- `img`要素には必ず`width=""`を指定すること
 - 単位はピクセルだが、**px** を書いてはならない
 - 高さは`height="*"`でも大丈夫
 - MSO系以外だけを対象にしてcssの`.class img`等のセレクタで`width="auto"`に指定することができる
- cssの`display`プロパティは、`block`と`none`を基本とし、それ以外を使う場合は必ず動作を確認する
 - まともなメーラーは`table-cell`も使える（flexboxは無理っぽい）
 - `inline-block`が使いたい場合は`table`要素で代用すると安定する

## style要素
- Gmailでエラーが発生するCSSプロパティは別の`style`要素に切り出す
- `style`要素は`head`要素に書くこと

## デザイン上の注意
- 一行二列から二行一列に変わる時、右側のボックスを上に持っていくのは困難
 - display noneを駆使すればできなくはない……はず
- 同行に幅固定の列がある場合、画面幅が狭くなるほど他の列が潰されることを考慮に入れる
- 複雑なボーダーは引いただけ`table`のネストが深くなり、メンテが困難になる

### おまけ　メーラー厄介度
1. **Gmail**
 - 罠だらけ
 - `body`要素は`div`に強制的に置き換えられるので、`body`で指定したものは無視される
 - `style`要素内の文字列が一定のサイズを越えると適用されなくなる
 - タグをきちんと閉じないとロクに表示されない
 - ブロックしたコンテンツを表示した時の挙動がバグっている（回避不可）
 - どうしてもGmailで詰まったら、上記バグも含めてスタイルのインライン化で回避できるかもしれないが、メディアクエリが使えなくなる
 - メディアクエリは最初に現れるもの一つしか適用してくれない
 - style要素の中でエラーが発生すると、そのstyle要素そのものが無視される
 - ツリー表示すると、テキストカラーが謎のあずき色になる場合がある。全てのテキストに`color`を指定すれば回避はできる
1. **MSO系（Outlook, Windows10Mail)**
 - これを作った人は頭がおかしい
 - 表示幅を固定して作ることで、慣れればGmailより楽
1. **Apple Mail**
 - たまに表示がおかしい
 - 原因不明、修正方法不明の場合が多い
1. その他
 - ほぼブラウザと同じ挙動をします
SQLSTATE[HY000] [2054] The server requested authentication method unknown to the client

# 事象
MacでMysqlを5.6から8.0にupgradeした後、LaravelからMysqlにアクセスできなくなった。

ちなみにupgradeのコマンドは、

```shell
$ brew upgrade mysql
$ mysql_upgrade
```

# エラー内容

SQLSTATE[HY000] [2054] The server requested authentication method unknown to the client

# 解決方法

my.cnfの設定を変更する

まず、my.cnfの場所を特定する

```shell
$ mysql --help | grep my.cnf
                      order of preference, my.cnf, $MYSQL_TCP_PORT,
/etc/my.cnf /etc/mysql/my.cnf /usr/local/etc/my.cnf ~/.my.cnf
```

左から順に存在するファイルを確認していく

```shell
$ ll /etc/my.cnf
ls: /etc/my.cnf: No such file or directory
$ ll /etc/mysql/my.cnf
ls: /etc/my.cnf: No such file or directory
$ ll /usr/local/etc/my.cnf
-rw-r--r--  1 hogehoge  admin   167B  6 22 11:46 /usr/local/etc/my.cnf
```

/usr/local/etc/my.cnfが存在しているので、これの末尾に、
default_authentication_plugin= mysql_native_password
を加える

例）

```conf
# Default Homebrew MySQL server config
[mysqld]
# Only allow connections from localhost
bind-address = 127.0.0.1
default_authentication_plugin= mysql_native_password
```

mysqlを再起動する

```
$ sudo mysql.server restart
```

これで完了

# Tips
Sequel Proで接続できない場合は、Pre-release版からなら行けるはず
https://github.com/sequelpro/sequelpro/releases
JavaScriptは全角スペースを使えるが文字コードに注意が必要

# 何の話か
以下の記事で紹介されているように、JavaScriptは全角スペースを使ってOKな仕様です。
https://www.softel.co.jp/blogs/tech/archives/5280

全角スペースOKとはいっても使わないと思いますが、エディタでエラーにならなかったりするので、時々まぎれこむかもしれません。

まぎれこんでもエラーにならないはずですが、今回問題が起こったのでその共有。

# 原因
エラーが起きたサイトは `.aspx` ってなってて、全角スペースが全部 `縲` に文字化けしていました。

どうもUTF8で書いたJavaScriptファイルがSJISで読み込まれたようです。

デベロッパツールで見るとこんな感じw（笑えない

```javascript
switch (deviceInfo.device) {
縲縲case 'pc':
縲縲縲縲deviceInfo.device = 'desktop';
縲縲縲縲break;
// ~省略~
}
```



ということで、いろいろなサイトで読み込むJavaScriptとか書いてると注意。

GitHubのプルリクでコードレビューするときもぱっと見ではわかりません。

# 結論
エディタはスペースがわかる設定に変えたほうがいい。
その「仮想」は何が仮想なのか

# はじめに

virtualenvの記事ではよく「仮想環境」と紹介されます。しかし私はとあるところでvirtualenvの説明をした時に「仮想」という言葉に違和感があり「独立した実行環境」と表現しました。
何故ならvirtualenvで作ってactivateした場合に動いているpythonは何かをエミュレートしているわけではなく本物だからです。あくまで、「端末立ち上げてそのままpython使うときとは別のパスにあるpythonが使われている」だけということになります。

virtualenvの話はこれだけで以下ポエム的に「仮想」という言葉について思うことを書いていきます。

# 仮想とは何なのか

コンピュータの歴史は仮想化の歴史と言ってもそれほど過言ではないでしょう。

## 仮想メモリ

まずすぐに思いつくのは仮想メモリです。
これは何が「仮想」なのかというと、実際に搭載している物理メモリに対してプログラムにはそれよりも多く見せかける（妖精さんが頑張ってスワップアウト、スワップインする）、実際には複数のプログラムが動いているんだけどプログラムには自分一人だけがメモリを占有しているように見せかけるということを行っています。

## OS、デバイスドライバ

仮想メモリも含めたリソースの仮想化も大事な概念です。ここでOSが出てきます。
OSの仕事、というかデバイスドライバの仕事は、統一したインターフェースを提供することでアプリケーションプログラムがどのハードウェアが繋がっているのか判断して制御方法変えなくてもいいようにすることです。これは実際の機械ではなく、仮想的な機械がつながっているように見せていると言えるでしょう。

## プログラミング言語の仮想マシン

プログラミング言語の話で言うとPythonとかRubyとかJavaとかは仮想マシンで動いています。
まあ今時のJavaは普通JITコンパイルされて動く、RubyもJITが開発されつつあるようですがそれは置いといて、これはプログラムをCPUが理解できる機械語にしないで「言語処理系が定める命令セットを実行する」という仮想機械が実行されているということになります。

## 仮想マシン

10年ちょい前からいわゆる仮想化技術が一気に花開きました。ハードウェア技術の進歩に加え、ハードウェア自体の仮想化サポートも影響しているのでしょう。
ここでは、「物理的に一台のマシンなのだけど、仮想的に複数台のマシンを動かす」という仮想化が行われています。上の「プログラミング言語の仮想マシン」と違うのは、仮想マシン自体がCPUの機械語を直接実行できるという点です。
そこまで詳しくはないので説明が正しくないところがあるかも・・・

## RAID

Wikipediaで確認してたらRAIDも仮想技術ですね。これは複数のディスクをまとめてひとつのディスクに見せるというものです。まあそこまで詳しくないので深くは述べません。

# 話をvirtualenvに戻す

ところでvirtualenvはドキュメントでどのように説明されているのか。
https://virtualenv.pypa.io/en/stable/

> virtualenv is a tool to create isolated Python environments.

isolated、「孤立した」ですね。仮想とは言っていません。
だったらソフト名にもvirtual使うなよという気もしますが、じゃあどの単語がいいのか（isolateはいまいちだしな）となると、私も語彙力がないからvirtualしか思いつきませんね（ぉぃ

# 余談：仮想通貨

今話題の仮想通貨。ブロックチェーン技術自体も興味深いところですが私は人文系も大好きなので、「通貨が人類の交流に与えた影響」的な話題も大好きです。その点で言うと、「仮想通貨というがそれが実取引に使われるのなら『仮想』ではないのではないか」と考えています。物質としての通貨がないから「仮想」なのかもしれませんが。
HyperターミナルでInvalid argumentの解決策

#環境
-OS: MacOS High Sierra 10.13.4
-Shell: zsh
-FrameWork: Prezto
#問題
[Hyperでイケてるターミナルをつかおう](https://qiita.com/vimyum/items/44478a51ef3a6f49804f)を参考にして、イケてるターミナルであるHyperをインスコ＆設定を行っている際にERRORが表示されてしまうので精神衛生上あまりよろしくないことが起きた。vimで開けるが、開く前に怒られる。
#解決策
エラーが出ているのは、.vimrcファイルの19行目。その中身を確認すると
`set listchars=tab:>-,eol:↲,extends:»,precedes:«,nbsp:%`
の↲が文字化けしているのが原因だった。
要はHyperターミナルのデフォルトでは表示できませんよ。ということなのでHyperターミナルの環境変数設定を行うことにより解決できました。
※SHELLの確認 `$ echo $SHELL`
zshの方→`vim ~/.zshrc` bashの方→`vim ~/.bashrc` に以下を追加する。

```vim:.zshrc
export LANG=ja_JP.UTF-8
```
または
`$ echo 'export LANG=ja_JP.UTF-8' >> ~/.zshrc`
追加が完了したらシェルの設定ファイルの反映を行います。
`$ source ~/.zshrc`
これで解決できたので好きにカスタマイズを行いましょう!!
#備考
恐らくPrezto使っている人しか関係ないと思います。Hyperターミナルのインスコ後はみんな日本語使えるように設定すると思うので自然と解決されちゃいますね...
Onsen UI for ReactとReact Nativeの比較

まえがき
------
- スマホアプリを作る時の検討材料
- 両方使ったことがあるので個人的な感想
- 個人的にOnsen UI for Reactはもう少し流行っても良いかなと思った

Onsen UI for React
-----
### メリット

- シュミレータがブラウザのため楽
- Webベース
 - CSSが使える
 - \<div>とかも使える
 - 最初にWebアプリを作ってからスマホアプリに展開とかも簡単
- 使うものがそろっているため、基本的には他のパッケージをインストールする必要がない

### デメリット
- react-native-xxx系のパッケージが使えない
- わからないことは公式のサポート頼り

React Native
-----
### メリット
- react-native-xxx系のパッケージが使える
  - パッケージが豊富にある
- わからないことは検索すればだいたい見つかる

### デメリット
- React Native単体では色々と機能不足のためパッケージを色々とインポートする必要がある
- バージョン1じゃない。まだ不安定？
[ESP8266] AP (Access Point) 試す

```c++:ap.ino

#include <ESP8266WiFi.h>
#include <WiFiClient.h> 
#include <ESP8266WebServer.h>

/* Set these to your desired credentials. */
const char *ssid = "ESPap";
const char *password = "thereisnospoon";

ESP8266WebServer server(80);

/* Just a little test message.  Go to http://192.168.4.1 in a web browser
 * connected to this access point to see it.
 */
void handleRoot() {
  
	server.send(200, "text/html", "<h1>Connected</h1>");
}

void setup() {
	delay(1000);
	Serial.begin(115200);
	Serial.println();
	Serial.print("Configuring access point...");
	/* You can remove the password parameter if you want the AP to be open. */
	WiFi.softAP(ssid, password);

	IPAddress myIP = WiFi.softAPIP();
	Serial.print("AP IP address: ");
	Serial.println(myIP);
	server.on("/", handleRoot);
	server.begin();
	Serial.println("HTTP server started");
}

void loop() {
	server.handleClient();
}
```

#結果。

![20180622_102136.jpg](https://qiita-image-store.s3.amazonaws.com/0/137182/f90107a2-f5eb-5959-2cff-6bd201e95799.jpeg)
Python Syslog Serverについて

### PythonのSyslog Server自分用メモ
---

下記URLのコードがpython3.6系で動かなかったので
しょうもないけど微修正してみた。

[Tiny Python Syslog Server · GitHub](https://gist.github.com/marcelom/4218010)

---

###修正前

```py
LOG_FILE = 'youlogfile.log'
HOST, PORT = "0.0.0.0", 514

#
# NO USER SERVICEABLE PARTS BELOW HERE...
#

import logging
import SocketServer

logging.basicConfig(level=logging.INFO, format='%(message)s', datefmt='', filename=LOG_FILE, filemode='a')

class SyslogUDPHandler(SocketServer.BaseRequestHandler):

	def handle(self):
		data = bytes.decode(self.request[0].strip())
		socket = self.request[1]
		print( "%s : " % self.client_address[0], str(data))
		logging.info(str(data))

if __name__ == "__main__":
	try:
		server = SocketServer.UDPServer((HOST,PORT), SyslogUDPHandler)
		server.serve_forever(poll_interval=0.5)
	except (IOError, SystemExit):
		raise
	except KeyboardInterrupt:
		print ("Crtl+C Pressed. Shutting down.")
```

---
###修正後

SocketServerをsocketserverに変えるだけです。

```py
LOG_FILE = 'youlogfile.log'
HOST, PORT = "0.0.0.0", 514

#
# NO USER SERVICEABLE PARTS BELOW HERE...
#

import logging
import socketserver

logging.basicConfig(level=logging.INFO, format='%(message)s', datefmt='', filename=LOG_FILE, filemode='a')

class SyslogUDPHandler(socketserver.BaseRequestHandler):

	def handle(self):
		data = bytes.decode(self.request[0].strip())
		socket = self.request[1]
		print( "%s : " % self.client_address[0], str(data))
		logging.info(str(data))

if __name__ == "__main__":
	try:
		server = socketserver.UDPServer((HOST,PORT), SyslogUDPHandler)
		server.serve_forever(poll_interval=0.5)
	except (IOError, SystemExit):
		raise
	except KeyboardInterrupt:
		print ("Crtl+C Pressed. Shutting down.")
```
【Paloalt】Zone ProtectionとDoS Protectionについて

## はじめに
Zone Protection機能とDos Protection機能がいまいち分かっていなかったので
整理してみた。

2018/6/22時点
software version8.1.1で検証


## Zone Protection

- フラッド攻撃の検知、緩和、防御
- ポートスキャンの検知、防御
- IPパケットベースの攻撃の防御

フラッド攻撃に関して、Aggregateのみとなる。
Aggregateは全パケット(IPアドレス)が閾値を超えたかどうか判断する。
つまり、Aさんがフラッド攻撃を仕掛けると、Bさんまで影響する。

**閾値**

- アラームレート　アラートを発生する閾値
- アクティベート　アクションを実行する閾値
- 最大値　閾値を超えるとパケットドロップ


**アクション**

- Random Early Drop ランダムなパケットをドロップさせる
- SYN Cookie　シーケンス番号をチェック？（イマイチ分かってません）

UDPやICMPはRandom Early Drop

**ログ**

- モニターの脅威の項目でアラートは確認可能（送信元、宛先IPアドレスは表示されない）
- ゾーン設定のログ転送にプロファイルを指定しておけばログ転送可能


SYSLOG出力例

```
10.1.0.4 :  <10>Jun 22 11:18:16 palodemo1 1,2018/06/22 11:18:15,641677CECF2C2F6,THREAT,flood,2049,2018/06/22 11:18:15,0.0.0.0,0.0.0.0,0.0.0.0,0.0.0.0,,,,not-applicable,vsys1,Untrust,Untrust,,,test,2018/06/22 11:18:15,0,1,0,0,0,0,0x102000,icmp,random-drop,"",ICMP Flood(8503),any,critical,client-to-server,54,0x2000000000000000,0.0.0.0-0.255.255.255,0.0.0.0-0.255.255.255,0,,0,,,0,,,,,,,,0,0,0,0,0,,palodemo1,,,,,0,,0,,N/A,flood,AppThreat-0-0,0x0,0,4294967295,
```

## Dos Protection

- フラッド攻撃の検知、防御
- ポリシーベースでルールに適用する

**プロファイル**

- タイプはClassifiedとAggregateを選択可能
- 基本的にZone Protectionの内容と同じだがブロック期間が存在する
- ブロック期間(default 300秒 MAX 21600(36時間))

Classifiedは、個々の送信元IPアドレスに対して閾値を設定する
つまり、送信元Aが閾値を超えたとしても、送信元Bには影響しない

**DoSポリシー**

- 書き方はセキュリティルールと同じ
- アクションの拒否、許可は無視していい（セキュリティルールと同じ意味合い）
- アクションで保護を選択すれば、プロファイルで定義された閾値が適用される

**ログ**

- DoSポリシーのログ転送に設定しておけばログ転送可能
- ログの表示は、Classifiedで追跡するタイプ（送信元IPアドレス、宛先IPアドレス両方）によって送信元IPアドレスだけの表示、宛先も含めた表示が可能


## まとめ

Zone Protectionは、スキャン・IPベースの攻撃を防御
DoS Protectionでフラッド系の攻撃を防御するのがよさそう。

---

## 追記
---
2018年6月25日
SYN CookieはMD5などで計算された値をSYN/ACKに埋め込み応答を返す。
通常だとSYN/ACK送信時、接続待ち状態となりリソースを消費するが
SYN Cookieが有効だとリソースを使わない。ACKが返ってきたら
計算された値を元に接続をする。

プロキシ（リバース）の振舞いをしているならSYN Cookieは有効だけど
プロキシとして動くというのはどういう時だろう。SSL複合化を有効にしている時？
ケースクラスをJSON化するときにフィールド名を自動的にスネークケースにする方法(circe-generic-extras)

# 目的

できるだけEncoder/Decoderを書かずに、ケースクラスをJSON化したいときは、`import io.circe.generic.auto._, io.circe.syntax._`をインポートして `hoge.asJson`とすればよいが、キャメルケースのフィールド名がそのままJSONに出力されてしまう。これを簡単にスネークケースにできないか？ という感じでツイートしてたら教えてもらいました。それを共有します。

```scala
import io.circe._
import io.circe.syntax._
import io.circe.genric.auto._

case class UserName(firstName: String, lastName: String)

val userName = UserName(firstName = "Junichi", lastName = "Kato")
val json = userName.asJson

/*
{
  "firstName": "Junichi",
  "lastName": "Kato"
}
*/
```

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">implicit でconfig渡すと自動的にスネークケースになります。混在パターン駄目ですが。<br> <br>implicit lazy val jsonConfig: Configuration =<br>    Configuration<br>      .default<br>.withSnakeCaseMemberNames</p>&mdash; j.kugiya (@KugiyaJ) <a href="https://twitter.com/KugiyaJ/status/1009954718284537856?ref_src=twsrc%5Etfw">2018年6月22日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

# 今までのやり方

最初にやってたのはこれ。タイピング数が多くなる(笑)

```scala
import io.circe._

case class UserName(firstName: String, lastName: String)

object UserName {

  implicit val userNameDecoder: Decoder[UserName] = Decoder.instance{ v =>
    Json.obj(
      "first_name" -> v.firstName.asJson,
      "last_name" -> v.lastName.asJson
    )
  }

}
```

次は`forProduct??`メソッド。こっちはかなり楽になった。

```scala
import io.circe._

case class UserName(firstName: String, lastName: String)

object UserName {

  implicit val userNameDecoder: Decoder[UserName] = 
    Decoder.forProduct2("first_name", "last_name")(UserName.apply)

}
```

# 今回の方法

`circe-generic-extras`への依存関係が必要です。

```scala
libraryDependencies ++= Seq(
  "io.circe" %% "circe-core",
  "io.circe" %% "circe-generic",
  "io.circe" %% "circe-generic-extras", // 追加
  "io.circe" %% "circe-parser"
).map(_ % circeVersion)
```

教えてもらったとおりですが、以下のような感じでできます。

```scala
import io.circe._
import io.circe.syntax._
import io.circe.generic.extras.auto._
import io.circe.generic.extras.Configuration

case class UserName(firstName: String, lastName: String)

implicit val jsonConfig: Configuration = Configuration.default.withSnakeCaseMemberNames

val userName = UserName(firstName = "Junichi", lastName = "Kato")
val json = userName.asJson

/*
{
  "first_name": "Junichi",
  "last_name": "Kato"
}
*/
```

ケースクラスごとに`Configuration`を変えたい場合は、こんな感じでいけると思います。

```scala
import io.circe.generic.extras.semiauto._
import io.circe.generic.extras.Configuration

case class UserName(firstName: String, lastName: String)

object UserName {
  implicit val jsonConfig: Configuration = Configuration.default.withSnakeCaseMemberNames
  implicit val userNameDecoder: Decoder[UserName] = deriveDecoder
}
```
HashiCorpのTerraformのインストール方法をメモしてみた

弓月です。

今回は、HashiCorpのterraformのインストール方法を載せます。
使用するのは、AWSのamazon linuxのインスタンス一つです。
無料枠のt2.microでストレージもデフォルトの8GBで十分です。

一応初期化オマジナイも載せておきます。

```
初期作業: amazon linuxの場合
########################################
> sudo su - root

// 一応やっておくと安心
> yum update

// 最初はUTCになっているので、JSTに変更する
> date
> ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
> date

// /etc/sysconfig/clockの修正
// 初期は以下のとおり
// ZONE="UTC"
// UTC=true

> cat << EOL | sudo tee /etc/sysconfig/clock
ZONE="Asia/Tokyo"
UTC=true
EOL
> service crond restart
########################################
```

```
初期作業: amazon linux2の場合
########################################
> sudo su - root

// 一応やっておくと安心
> yum update

// 最初はUTCになっているので、JSTに変更する
> date
> timedatectl set-timezone Asia/Tokyo
> date

// 時刻同期ができていることを確認する。
> systemctl status chronyd
########################################
```

①Hash.corpから最新版のzipファイルをダウンロードする。

```
> wget https://releases.hashicorp.com/terraform/0.12.24/terraform_0.12.24_linux_amd64.zip
```

②解凍し、ディレクトリごと/opt配下に移す。

```
例:  terraform 0.12.24の場合
> sudo su - root
> mkdir /opt/terra_0_12_24/
> unzip -d /opt/terra_0_12_24/ /home/ec2-user/terraform_0.12.24_linux_amd64.zip
```

③シンボリックリンクを作成する。

```
> ln -sfn /opt/terra_0_12_24 /opt/terraform

 ※/opt配下に複数のterraformをインストールしている場合は、
   上記オプション(-sfn)で切り替えて使うことも可能。
```

④rootの.bash_profileにpathを通す

```
> vi ~/.bash_profile

(以下を追記)
export PATH=$PATH:/opt/terraform/
```


⑤正しくインストールされたか確認する

```
> terraform version
Terraform v0.12.24
```
簡単ですよね。あっという間です。
次回は、Terraformを使って、簡単にVPCを作る方法を載せます。
大量のファイルがあるディレクトリで作業時、注意点

## 経緯
- 大量ファイルディレクトリに対して作業中にロードアベレージ上昇
- 放置した結果、翌日の朝までプロセスが残ってたっぽくて調査したら以下の様な原因だった。


## 原因

- 大量ファイルディレクトリに対してlessコマンド実行時にtabキーで補完

- e.g. /hoge/配下に大量のファイルが存在する場合



```
# less /hoge/
```

tabキー押下して補完、**全ファイルに対して処理走る**
↓
反応なし
↓
Ctl+cで回避できない
↓
何もできない…
↓
ターミナル強制終了
↓
プロセス残ったまま…


>ターミナル強制終了

これダメ、絶対。



## 解決方法

- 応答がないコマンドはちゃんと殺してやりましょう。

- プロセス確認

```
# ps [プロセスID]
```

- プロセス強制終了

```
# kill -9 [プロセスID]
```

- ↑の実行完了後、元のプロンプトに`強制終了`が表示される

```
# less /hoge/強制終了
```
Google Cloud Platform(GCP) へローカル端末からssh接続できない

# ■Google Cloud Platform (GCP)とは
グーグルの作ったクラウドサービス
今までAWSしか使ってこなかったけど、どうやらGCPは安いらしい
天下のGoogle様だしSLAとかセキュリティとかユーザビリティも大丈夫だろうってことで使用

# ■目的
GCPへローカル端末からteratermで接続したい

# ■前提
ざっくり以下の流れ
1：Googleアカウント作成
2：GCP登録(クレジットカード登録)
3：プロジェクト作成
4：Google Compute Engine(GCE) インスタンス作成

　最安で作成するため以下の構成

| 項目|内容 | 
|:-----------|:------------|
| OS       | CentOS7        |
| Zone     | us-east1-b|
| マシンタイプ  | f1-micro（vCPU x 1、メモリ 0.6 GB）     |

出来上がったインスタンスに対して「SSH接続」→「ブラウザウィンドウで開く」は問題なく開く

# ★本題
以下の通りローカル端末からSSH接続を行おうとすると、ドキュメントに飛ばさせる
「SSH接続」→「別のSSHクライアントを使用」

[サードパーティ製ツールを使用して接続する][aaa]
[aaa]:https://cloud.google.com/compute/docs/instances/connecting-advanced#thirdpartytools

接続の方法はいくつかあるようだけど、だいたいこんな感じかと
1：SSH鍵生成
　・teratermや、PuTTYGen などで公開鍵/秘密鍵生成
　　※公開鍵末尾のコメント部にユーザ名を設定
2：SSH鍵登録
　以下のどれか
　・1プロジェクト全体に鍵登録(今回はこれ★)
　　　[メニュー]→[Compute Engine]→[メタデータ]
　　　[SSH認証鍵]タブ→[編集]ボタン→[項目追加]ボタン→[公開鍵]入力※→[保存]ボタン
　　　　※ユーザ名が表示される
　・2インスタンス個別に鍵登録
　　　[メニュー]→[Compute Engine]→[VMインスタンス]
　　　[対象インスタンス詳細]リンク→[編集]ボタン
　　　[SSHキーが0個あります][表示して編集する]リンク→[公開鍵]入力※→[保存]ボタン
　　　　※ユーザ名が表示される
　・3IAM管理で登録
　　→めんどくさそうなので調べず
3：接続IP確認
　・必要あればIP固定化
4：ローカル端末から接続
　　→出来ない。。。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/265723/90879450-0ea7-9e9a-1b4b-894320d032e5.png)

なぜ認証失敗。。。
鍵を作り直したり、インスタンス作り直したり試行錯誤を行うこと2時間

判明した原因は、__公開鍵保存出来てない__(っぽい)

### 詳細
公開鍵登録時に以下の保存ボタンを押下
　※このときはプロジェクト全体のメタデータ登録
![image.png](https://qiita-image-store.s3.amazonaws.com/0/265723/6ab36ccb-4835-c32f-b29c-72876656c16d.png)

すると以下のメッセージが表示
![image.png](https://qiita-image-store.s3.amazonaws.com/0/265723/309601c6-1dd2-7dc6-51be-e470395ee2ee.png)

★ここで安心して別操作を行ってしまったのが原因っぽい
2,3秒すると以下のメッセージ表示

![image.png](https://qiita-image-store.s3.amazonaws.com/0/265723/719a5a41-b0b6-c42f-8191-9136bfd9f20a.png)

これで完了

# ■結論
全体的に[保存しました]が出るまで別操作はしないほうが良さそう
慌てるな

# さいご
・メタデータ登録しておけば、自動でOSに対してユーザ登録してくれるのは素晴らしい。
・GCP安い。最安環境つかっているとはいえ、2日で3円くらい。3万円クレジットもあるし。
・ただ、アメリカリージョンはさすがに遅い。
・Qiita初めて投稿するが、もう少しMarkdown勉強しよう。
GitLabコマンド  コピペで使えるよ！

自社サーバーにgitlabを導入したので、備忘録

公式ページ
[gitlab](https://about.gitlab.com/)

導入バージョン
10.8.4-ee


**起動・停止・再起動**
sudo gitlab-ctl start
sudo gitlab-ctl stop
sudo gitlab-ctl restart

**設定ファイルはここ！**
vim /etc/gitlab/gitlab.rb

**設定を変更したら忘れずに！**
sudo gitlab-ctl reconfigure

**gitlabのインフォメーション確認**
gitlab-rake gitlab:env:info

**gitlabの状態確認**
gitlab-ctl status
gitlab-ctl tail

**アンインストール**
sudo yum remove gitlab-ee

**導入時に困った！ググった！まとめ**


なんかアパッチと共存云々でぐぐると色々でてきて困ったけど
結局　gitlab.rbの external_url 'http：//xxxx.com:88888'を変更して
CentOSのポート解放したら自分の環境では問題なく起動した。


サーバー再起動後にgitlabが起動しなくなりました！
down: prometheus: 0s, normally up, want up; run: log
こんな感じのエラー

gitlab.rbmに追加
prometheus_monitoring['enable'] = false

[gitlab docs](https://docs.gitlab.com/ee/administration/monitoring/prometheus/)

試してないがこちらのコマンドでもおkらしい。
sudo systemctl reload prometheus

サーバーを再起動した際に
sudo systemctl start gitlab-runsvdir
毎回再起動のたびは面倒なので自動起動するなら
sudo systemctl enable gitlab-runsvdir
ROS kineticでKerasとTensorFlowを使う for JetsonTX2 

環境
jetson tx2 (jetpack 3.1)
keras 2.1.3
tensorflow 1.3.0
python2.7



ロボット用に、母艦PCで回した学習済みモデルを使ってjetsonTX2で予測したいと考えた。
jetsonでのtensorflowのインストールにちょっとつまずいたので記録しておく。
ROSの使い方がいまいち理解していないため間違ってたらごめんちゃい。




以下導入方法




ROS-kineticはpython2.7が推奨環境らしい(?)ので
python2.7環境（pip2?）でtensorflowを入れないといけないようだ


https://github.com/jetsonhacks/installTensorFlowJetsonTX
をダウンロード→解凍して
TX2の中のtensorflow-1.3.0-cp27-cp27mu-linux_aarch64.whl
とってくる

そのまま
sudo pip install tensorflow-1.3.0-cp27-cp27m-linux_aarch64.whl
とすると

tensorflow-1.3.0-cp27-cp27m-linux_aarch64.whl is not a supported wheel on this platform.

とエラーが出るから
こちらのサイトの説明に従ってpip2を更新
http://demura.net/athome/13454.html

更新が済んだらもう一度
sudo pip install tensorflow-1.3.0-cp27-cp27m-linux_aarch64.whl

をすればpython2.7にtensorflowが入る


kerasは
sudo pip install keras==2.1.3
で入る


確認

/usr/local/lib/python2.7/dist-packages

にkerasとtensorflowが入っていたらOK

importして使えたらインストール成功



参考サイト
http://demura.net/athome/13454.html
ドメインモデルをコードへ落とす 〜あなたのクラスは、どこから？〜

```
annotation:
現在コメントいただいている通り、一部誤りを含んでいる様です。
追って確認・修正いたしますが、現行ではコメントも合わせてお読み頂ければと思います。
```

こんにちは、風邪はだいたい喉から来るぷーたんです。

「DDDの構成要素はこれだー」というのはたくさんあったのですが、
「このドメインオブジェクトはどの要素だー」と逆引きするものがなかったので調べてフローチャートにしてみました。
例えばドメインモデル図とコードがうまく合致しない時の見直しなどに使えるのではと考えています。

ではご覧ください♪

## 検討フローチャート
![domain_flow.png](https://qiita-image-store.s3.amazonaws.com/0/5514/843a016f-5484-cd26-f639-53cd278aa518.png)
図1.フローチャート

### 1) 複数のドメインオブジェクトを扱い、整合性を担保するか
まず複数のドメインオブジェクトを扱うかを考えます。
ドメインモデル図では集約線が引かれていたり、複数の関係線が引かれていたりします。

![domain_flow-ページ2.png](https://qiita-image-store.s3.amazonaws.com/0/5514/12e9551c-6c4d-2b03-b669-85db1ecf5978.png)
図2.ドメインモデル図の例

上記のような場合であれば、「本棚」と「購入」はYes、「書籍」「在庫」「所持金」はNoです。

また、扱う複数のドメインオブジェクトに対して整合性を担保するかも考えます。
不要な場合、ドメインオブジェクトとして扱うほどでもない概念かもしれません。（6に飛ぶ）

### 2) 状態を持つか
状態を保つ必要があるかどうかを考えます。
図2の例では「本棚」は書籍をどのような順番で保持しているかという状態を考慮する必要がありそうなのでYes、「購入」はそうでもなさそうなのでNoとなりそうです。

図2の例は簡素な図なのでなんとなくでいけましたが、実際にはもう少し考えます。
扱う複数のドメインオブジェクトの整合性を「しっかりとした整合性（完全一貫性）」とするか
「多少遅延してもいい整合性（結果整合性）」とするかを考えます。
前者であれば扱うドメインオブジェクトを状態としてそれらを保持することで外部との関係を疎にします。
後者で良ければ状態として保持する必要はないでしょう。

### 3) あるクラスのメソッドとして実装しても複雑にならなそうか
そうであればドメインオブジェクトとして切出さず、そのクラスのドメインオブジェクトの一部としたほうが良さそうです。
これを見直さない場合、ドメインサービスが膨らむ一方でドメインオブジェクト（＝クラス）がやせ細り、
世に言う「ドメインモデル貧血症」を起こしてしまうかもしれません。
そうではない複雑な処理であればそのドメインオブジェクトは**ドメインサービス**として実装するのが良さそうです。
[ドメインサービスについて](https://codezine.jp/article/detail/10318)

### 4) エンティティを4種以上扱っているか
[IDDD本](https://www.shoeisha.co.jp/book/detail/9784798132174)では事例として
> 彼らチームは、すべての集約の約7割を、ルートエンティティに値型のプロパティを数個持たせるだけにできた。残りの3割も、たかだか二つか三つ程度のエンティティしかなかった。

と挙げられており、大きい集約はパフォーマンスやスケーラビリティが低くなるとされています。
4というのは飽くまで目安ですが、Yesの場合はそのドメインを細かく分割できないか検討すると良さそうです。

検討の結果、十分小さく分けられていればそのドメインオブジェクトは**集約（ルートエンティティ）**として実装するのが良さそうです。
また、「デメテルの法則」や「Tell-Don't-Askの方針」を守れているかを確認することで、内部を密に、外部と疎にでき、より扱いやすい集約とすることができます。
[集約について](https://codezine.jp/article/detail/10776)

### 5) IDを必要とする（同一性を担保する）か
同一性とは値が変わったとしても同じものとして認識できるか、というものです。
例えば「人」モデルが「私」を表現しており「年齢：34」という状！状態を持っていたとすると、
「年齢：35」となっても同一人物として見る必要があります。
この様な場合はYesとなり、**エンティティ**として、
そうでなければNoとなり、**値オブジェクト**として実装するのが良さそうです。

エンティティは上記のように属性が変化し続けるので、その連続性や同一性を考慮した複雑な設計を要します。
一方で値オブジェクトは属性が変わればもう別物なので、エンティティのような複雑さを回避できます。
この違いを見極めることで無駄な考慮コストを抑えることができるでしょう。
[エンティティについて](https://codezine.jp/article/detail/10038)
[値オブジェクトについて](https://codezine.jp/article/detail/10184)

### 6) 途中で当てはまらなくなった
若干のずるいですが例外をキャッチする部分をつくりました。（フローチャートとは。。）
チャートがうまくできていたとすれば、当てはまらない場合はドメインオブジェクトには当てはまらない概念かもしれません。
候補として次のものを考えました。

 - アプリケーションサービス
 - リポジトリ
 - 他のドメインの一部に含まれる概念

アーキテクチャにもよりますが、上2点は別のレイヤーの概念です。
レイヤーをまたいでしまわないように、もう一度整理しましょう。

3点目は書き出してはみたけどあまり知識持ってないなーというやから。
他のドメインオブジェクトに含めて凝集度が上がるならその方が良いでしょう。

## まとめ
- DDD構成要素逆引きチャートを作ってみた
- 実装とドメインモデル図が合わない時にズレの確認に使える（使えたらいいな）

## 参考資料
- [実践ドメイン駆動設計（IDDD本、赤本） / 翔泳社](https://www.shoeisha.co.jp/book/detail/9784798132174)
- [IDDD本から理解するドメイン駆動設計 / CodeZine](https://codezine.jp/article/corner/655)
- [DDD超入門(後編) - Domain-Driven Designの適用Step / Enterprise Geeks](http://enterprisegeeks.hatenablog.com/entry/2016/07/25/081127)
- [混乱しがちなサービスという概念について / かとじゅんの技術日誌](http://blog.j5ik2o.me/entry/2016/03/07/034646)
Laravel で MongoDB の API を作成

Laravel で MongoDB の collection を読む API を作成します。
>MongoDB のデータは、次のものと同じです。
[Laravel で MongoDB のデータをテーブル表示](https://qiita.com/ekzemplaro/items/e4a222fdf374b66c435b)
次のライブラリーを使います。
[jenssegers/laravel-mongodb
](https://github.com/jenssegers/laravel-mongodb)

1) プロジェクトの作成

```bash
laravel new api02
cd api02
composer require jenssegers/mongodb
```

2) config/app.php の編集

```text
'providers' => [
// 略
        Jenssegers\Mongodb\MongodbServiceProvider::class,
 ],

    'aliases' => [
// 略
         'Moloquent' => Jenssegers\Mongodb\Eloquent\Model::class,
 ],
```

3)  .env の編集

```text
#DB_CONNECTION=mysql
#DB_HOST=127.0.0.1
#DB_PORT=3306
#DB_DATABASE=homestead
#DB_USERNAME=homestead
#DB_PASSWORD=secret
DB_CONNECTION=mongodb
DB_HOST=127.0.0.1
DB_PORT=27017
DB_DATABASE=city_db
```
4) config/database.php の編集

```text
'default' => env('DB_CONNECTION', 'mongodb'),
    // 略
    'connections' => [
        'mongodb' => [
            'driver' => 'mongodb',
            'host' => env('DB_HOST'),
            'port' => env('DB_PORT'),
            'database' => env('DB_DATABASE'),
        'username' => env('DB_USERNAME'),
        'password' => env('DB_PASSWORD'),
        ],
    ],
```

5) キャッシュのクリア

```bash
php artisan cache:clear
```

6) モデルの作成

```bash
mkdir app/Models
php artisan make:model Models/City
```

7) モデルの編集

```php:app/Models/City.php
<?php

namespace App\Models;


class City extends \Moloquent
{
protected $collection = 'saitama';
}
```

8) routes/api.php の編集

```routes/api.php
// 略
Route::group(['middleware' => ['api']], function(){
  Route::resource('city', 'Api\CityController');
  Route::get('all', 'Api\CityController@all');
  Route::get('find/{id}', 'Api\CityController@find');
  Route::get('where/{name}', 'Api\CityController@where');
  Route::get('between/{min}/{max}', 'Api\CityController@between');
});
```

9) コントローラーの作成

```bash
php artisan make:controller Api/CityController
```

10) コントローラーの編集

```php:app/Http/Controllers/Api/CityController.php
<?php

namespace App\Http\Controllers\Api;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Models\City;

class CityController extends Controller
{
        public function index()
        {
        $cities = City::orderBy('_id', 'desc')->get();
	return $cities;
        }

        public function all()
        {
        $cities = City::all();
        return $cities;
        }

        public function find($id)
        {
        $cities = City::find($id);
        return $cities;
        }

        public function where($name)
        {
        $cities = City::where('name','=',$name)->get();
        return $cities;
        }

        public function between($min,$max)
        {
        $cities = City::whereBetween('population',[(int)$min,(int)$max])->get();
        return $cities;
        }
}
```

11) サーバーの起動

```bash
php artisan serve --host 0.0.0.0
```

12) クライアントでアクセス

```bash
curl http://localhost:8000/api/city
curl http://localhost:8000/api/all
curl http://localhost:8000/api/find/5b2c483e6fc1214d33e6151c
curl http://localhost:8000/api/where/久喜
curl http://localhost:8000/api/between/30000/50000
```
SlackAPIを使ってslash commandを送る方法

SlackのAPIを使ってslash commandを受け取って処理する方法はあったが、
逆にAPIからslash commandを叩く情報がなかったのでメモ
## 問題

例えば、`slack-ruby-client`で

```ruby

Slack.configure do |config|
  config.token = ENV['SLACK_API_TOKEN']
end
client = Slack::Web::Client.new
client.chat_postMessage(channel: '#general', text: '/hoge', as_user: true)
```
と書いても、slackには/hogeと送信されるだけでslash commandを実行してくれない

## 解決策
chat.commandという非公式のメソッドがあったのでこれを使います [ドキュメント](https://github.com/ErikKalkoken/slackApiDoc/blob/master/chat.command.md)

```ruby
Slack.configure do |config|
  config.token = ENV['SLACK_API_TOKEN']
end
client = Slack::Web::Client.new
client.chat_command(channel:'HOGEEEE', command:'/hoge')
```

注意点として**channelが#hogeではなくchannel IDで指定しないとダメ**そうなで気をつけてください
DMで送る場合も同様で、UserのIDではなくDMのchannel_IDを指定してください
これでslash commandが実行されるよ！やったね！
とある日、Mix.Generator.from_file()が使えなくなっていた

[fukuoka.ex](https://fukuokaex.fun/)代表の[piacere](https://twitter.com/piacere_ex)です
ご覧いただいて、ありがとうございます :bow:

今回は、mixコマンドを開発していたら、テンプレートファイルが読み込めなくなるエラーが発生したので、そのトラブルシューティングです
<br>
:stars::stars::stars:<b>　お知らせ：fukuoka.ex#11、本日開催（データサイエンスOSSを初お披露目します）　</b>:stars::stars::stars:

[<b>「fukuoka.ex#11：DB／データサイエンスにコネクトするElixir」</b>](https://fukuokaex.connpass.com/event/87241)を本日6/22（金の19時に開催します

スポンサー増枠分が少し残っていますので、本日18時頃に仕事が終わりそうな方は、コチラからお申込みを
https://fukuokaex.connpass.com/event/87241

私は、Phoenix＋Vue.jsで作ったOSSデータサイエンスプラットフォーム「Esuna」を初お披露目するLTします

![image.png](https://qiita-image-store.s3.amazonaws.com/0/155423/1da06f6f-31ea-010d-5063-ee1b48bc4a3a.png)

# Mix.Generator.from_file()が廃止されていた

とある日、カスタムmixコマンド内でテンプレートファイルを読み込むための、Mix.Generator.from_file()が、使えなくなっていました

調べてみると、[v0.14.2](https://github.com/elixir-lang/elixir/releases/tag/v0.14.2)でdeprecatedとなり、[v0.15.0](https://github.com/elixir-lang/elixir/releases/tag/v0.15.0)でremoveとなった模様です

どうやら、Elixirのインストールバージョンを1.4 or 1.5から、1.6に上げた時点で、使えなくなったようです

# Mix.Generator.embed_text()に書き換え

テンプレート文字列を埋め込む関数、Mix.Generator.embed_text()に、オプション「from_file:」が指定可能となったため、こちらでテンプレートファイルを指定して読み込むことが可能となっています

```elixir
Mix.Generator.embed_text( :spa, from_file: "priv/templates/sample.txt" )
```

カスタムmixコマンドを作っている方は、参考にしてください

# p.s.「いいね」よろしくお願いします

よろしければ、ページ左上の ![image.png](https://qiita-image-store.s3.amazonaws.com/0/155423/4d515047-cc48-382e-c2b1-3ad0cc50dbbf.png) や ![image.png](https://qiita-image-store.s3.amazonaws.com/0/155423/a4e3da58-70a3-4197-95a2-6a6906650d01.png) のクリックをお願いしますー:bow:
QGIS プラグインから他のプラグインを呼び出してみる

この記事は2018年3月くらいに一時公開していたものの再投稿です。

# QGISでプラグイン連携をする
QGISのプラグインを作っているとプラグインから他のプラグインを呼び出したくなることがあります。
そんな時はどうすればいいのかを調べました。
(QGIS3.0で作業を行っていますので、それ以前のバージョンではやり方が異なるかもしれません)

##プラグインのインスタンス取得
プラグインはインスタンスは`qgis.utils.plugins`から取得できます。
ディクショナリ型`{プラグイン名:インスタンス}`が返ってきますので読み込まれているプラグイン一覧を取得するには以下のようにします。

```python
qgis.utils.plugins.keys()
```

pythonコンソールで実行してみると判りますがキーになるプラグイン名はプラグインの管理に出てくる名前ではなく、<font color="Red">「プラグインのフォルダ名」で管理されている</font>ので注意してください。
（プラグインの管理に出てくる名前はmetadata.txtのnameに指定した値です）

プラグインのインスタンスを取得するには以下のようにすれば良いようです。

```python
plugin = qgis.utils.plugins['プラグイン名']
```

ではpythonコンソールからテストしてみましょう。

```python
# 標準プラグインのDBマネージャを取得して起動する
plugin = qgis.utils.plugins['db_manager']
plugin.run()
```

DBマネージャが起動したと思います。

##プラグイン間の連携を行う
ここではテストプラグインとしてAAAとBBBを作成して、AAAからBBBのプロパティ変更とメソッド呼び出しを行ってみたいと思います。

ポイントはプラグインから`qgis.utils.plugins`にアクセスするためimportを行うことくらいでしょうか。

```python:aaa.py
from qgis.utils import plugins
...
    def run(self):
        # BBBプラグインのインスタンスを取得
        bbb = plugins['BBB']
        # プロパティ変更
        bbb.msg = 'fromAAA'
        # メソッド実行
        bbb.otherPluginAction()
```

受け側は呼び出されるプロパティとメソッドを定義しておきます。

```python:bbb.py
# メッセージ表示用にQMessageBoxを追加
from PyQt5.QtWidgets import QAction, QMessageBox

...

    def __init__(self, iface):
        # プロパティを定義
        self.msg = 'dummy'
...

    def otherPluginAction(self):
        QMessageBox.information(self.iface.mainWindow(), 'BBB', "%s" % self.msg)
```

プラグインの管理からAAAとBBBのプラグインを有効にします。
ツールバーからAAAを起動すると、BBBのメッセージボックスにAAAで設定したメッセージが表示されたと思います。

今回はrunアクションで起動しましたが、もちろんemitとslotを使ったイベント駆動も可能です。
いずれにしても操作対象のプラグインがロードされていることが前提になりますので、実行前にプラグインの有無を確認してロードされていなかったら処理を回避したり自分でロードするような処理を入れておくと良いかもしれません。

## 最後に
意外と簡単にプラグイン間の連携がとれました。
プラグインの動的ロードと組み合わせたら面白いかもしれませんので今度試してみようと思います。

追記：2018/3/27に試してみた記事を書きました。
[QGIS プラグインの動的ロードと実行](https://qiita.com/ozo360/items/4502ec951d5fc205243a)


qgis.utils.pluginsでプラグインにアクセスできるというのが判ったのは[plugin_reloader](https://plugins.qgis.org/plugins/plugin_reloader/)のソースを読んで当たりを付けて色々触った結果なんですが、この辺りは[QGIS API](https://qgis.org/api/)にも出てこないので調べるのは少し大変です。（出てるならコメントで教えてもらえたら嬉しい）QGIS本体のソースを読むといろいろと見えてくるのですがそれはそれで大変なんですよね。

プラグイン間の連携を使えば自作プラグインに限らずロードされたプラグインのメソッド呼び出しやプロパティの上書きができますので、公開プラグインを使っていて毎回設定が面倒だったり繰り返し処理が必要な場合にも、自作の自動化プラグインを作ってマクロ的に処理を実行させることで作業の効率化もできるのではないでしょうか。

以上です。

本記事のライセンス
<a rel="license" href="http://creativecommons.org/licenses/by/4.0/">![クリエイティブ・コモンズ・ライセンス](https://i.creativecommons.org/l/by/4.0/88x31.png)</a>
この記事は <a rel="license" href="http://creativecommons.org/licenses/by/4.0/">クリエイティブ・コモンズ 表示 4.0 国際 ライセンス</a>の下に提供されています。
erlang: rebar3で依存するパッケージたちを管理、更新する

rebar3を使ってerlangアプリの依存するパッケージを管理できます

```
rebar3 version
rebar 3.4.7 on Erlang/OTP 20 Erts 9.2
```
# 取り込むパッケージを記録
```
{deps, [
        {cowboy, "1.0.1"}, % package
        {cowboy, {git, "git://github.com/ninenines/cowboy.git", {tag, "1.0.1"}}} % alternatively, source
        ]
}.
```
以上のように使用するパッケージ(cowboy)をタグ指定で設定できました。
他にもbranch指定とgitのhash指定でパッケージ設定ができます。詳しくは[ドキュメント](https://www.rebar3.org/docs/dependencies)を参照してください

# パッケージの初回更新
```rebar3 update```
でローカルにインデックスファイルが作成されます
```rebar3 upgrade```
依存するパッケージをダウンロードする及びロックファイルrebar.lockを作成します
以降たとえrebar.configにある依存するパッケージを変更してもrebar.lockファイルがいる限りrebar3が取ってくれない

# パッケージの二回以降の更新
公式ページによると```rebar3 upgrade```コマンドがrebar.lockファイルがあってもいい感じに更新してくれますが、うまくいかなかった、、
自分が使う方法：
- rebar.lockファイルを削除してから依存パッケージを更新する
- ```rebar3 unlock```を実行してから更新する
ちなみにプロファイルを使ってのupgrade、例えば```rebar3 as dev upgrade```がうまくいかない時があります、プロファイルを外しての更新が無難かな

# さらに
例えばこういう依存関係があり：

```
module_foo->msgpack:0.3.2
module_bar->msgpack:0.3.2
```
そのあと

```
module_bar->msgpack:0.7.0
```
module_barが依存するmsgpackのバージョンを0.7.0にあげても```rebar3 upgrade```ではmsgpackのバージョンをあげない
さらに、```rebar3 unlock module_foo```した上で、rebar.cofigファイルからmodule_fooを削除し、```rebar3 upgrade```しても、msgpackのバージョンが上がらない。一回```rebar3 unlock msgpack```してからupgradeしないとパッケージが更新されない
ローカルで作っているElectronのアプリを起動したら残像が出まくって困ったとき

スクロールとかすると、残像(画面がリフレッシュされてないように見える)が出てしまう。

これをスクロールすると
![image.png](https://qiita-image-store.s3.amazonaws.com/0/71143/dd27d19b-097f-6109-9049-09eb45580a98.png)

こうなります。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/71143/ec6ccfc4-0bd7-48ec-4107-88e624594b89.png)

ググり力が足りず、同じ問題に直面している人が見つかりませんでした。

# 原因

わからんけど、`electron@latest`を使ってると発生する気がする。

# 対策

`electron@beta`を使いましょう。

以上です。よろしくおねがいいたします。
GitLabにSourceTree+PuTTYでSSH接続する方法

# 概要
[前回の記事](https://qiita.com/kyamawaki/items/07fb3332cf3c2f47728a)でGit BashからGitLabにSSH接続する方法を記述したのですが、実際の業務ではSourceTreeを使っているので、SourceTreeを使ってSSH接続する方法を記述します。

# 環境
Server：GitLab Community Edition 10.7.3
Client：SourceTree (1.10.23.1)　※Ver 2.x系は不安定なので使用していない
Client OS：Windows10(1803)

#手順
概略は前回と同じで、SSHキーの鍵ペア（公開鍵と秘密鍵）を作成し公開鍵をGitLabに登録。秘密鍵を使ってSourceTreeからGitLabにアクセスするという手順になります。SSHキーの操作にはPuTTYを使用します。

- SSHキーの作成  
 - Source Treeのメニュー[ツール－SSHキーの作成/インポート]を選択
 - PuTTY Key Generator が立ち上がるのでSSHキーペアを作成する  
   （参考）https://rfs.jp/server/security/putty_ssh_publickey.html
- GitLabにSSHキーの公開鍵を登録（[前回の記事を参照](https://qiita.com/kyamawaki/items/07fb3332cf3c2f47728a) ）
- SourceTreeのSSH クライアントの設定にSSHキーの秘密鍵を登録
![SourceTreeOpt.png](https://qiita-image-store.s3.amazonaws.com/0/41649/2c8106dc-3e42-e850-1488-8af15b472c5a.png)

- PuTTYにSSHキーの秘密鍵を登録
 - タスクバーのインジケーターからPuTTYを右クリックし「View Keys」をクリック
 - [Add Key]をクリックしてSSHキーの秘密鍵を選択する
![keyList.png](https://qiita-image-store.s3.amazonaws.com/0/41649/fa19c91d-df36-72e2-d8d4-59bf710aeb6b.png)

- クローンを作成
 - Source Treeのメニュー[ファイル－新規/クローンを作成する]を選択して、リポジトリのURLを設定して[クローン]を押す
  
 ![Repo.png](https://qiita-image-store.s3.amazonaws.com/0/41649/54175eaf-8a47-e7f8-136c-b39b4e407d55.png)


これ以降、Push, Pullができるようになると思います。
Laravel で MariaDB の API を作成

Laravel で MariaDB のテーブルを読む API を作成します。
>MariaDB の状態は次のものと同じです。
[Laravel で MariaDB のデータを表示](https://qiita.com/ekzemplaro/items/55a71c651102b7f1a2dc)

<ol>
<li>プロジェクトの作成</li>

```bash
laravel new api01
cd api01
```

<li>.env の編集</li>

```text
# 略
DB_DATABASE=city
DB_USERNAME=scott
DB_PASSWORD=tiger123
# 略
```

<li>モデルの作成</li>

```bash
php artisan make:model Cities
```

<li>モデルの編集</li>

```php:app/Models/Cities.php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\DB;

class City extends Model
{
  protected $table = 'cities';
  protected $guarded = array('id');
  public $timestamps = false;

}
```

<li>routes/api.php の編集</li>

```php:routes/api.php
// 略
Route::group(['middleware' => ['api']], function(){
  Route::resource('city', 'Api\CityController');
  Route::get('all', 'Api\CityController@all');
  Route::get('find/{id}', 'Api\CityController@find');
  Route::get('where/{name}', 'Api\CityController@where');
  Route::get('between/{min}/{max}', 'Api\CityController@between');
});
```

<li>コントローラーの作成</li>

```bash
php artisan make:controller Api/CityController
```

<li>コントローラーの編集</li>

```php:app/Http/Controllers/Api/CityController.php
<?php

namespace App\Http\Controllers\Api;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Models\City;

class CityController extends Controller
{
public function index()
    {
        //
        $cities = City::all();
        return $cities;
    }
        public function all()
        {
        $cities = City::all();
        return $cities;
        }

        public function find($id)
        {
        $cities = City::find($id);
        return $cities;
        }

        public function where($name)
        {
        $cities = City::where('name','=',$name)->get();
        return $cities;
        }
public function between($min,$max)
        {
        $cities = City::whereBetween('population',[(int)$min,(int)$max])->get();
        return $cities;
        }

}
```

<li>サーバーの起動</li>

```bash
php artisan serve --host 0.0.0.0
```

<li>クライアントでアクセス</li>

```bash
curl http://localhost:8000/api/city
curl http://localhost:8000/api/where/倉敷
```

</ol>
GPSの研究　その22

#概要
GPSを理解したかった。
android2.1でGPSロガー作って見た。

#写真

![device-2018-06-21-071855.png](https://qiita-image-store.s3.amazonaws.com/0/18104/2442023a-4733-0708-427d-8216eaf3af34.png)


#サンプルコード
sdcardに、log.txtが出来る。

```
package com.ohisamallc.ohiapo9;

import android.app.Activity;
import android.location.GpsStatus;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.widget.TableLayout;
import android.widget.TextView;
import android.view.ViewGroup;
import java.io.FileOutputStream;
import java.io.IOException;
import android.content.Context;
import android.text.format.DateFormat;
import android.util.Log;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import android.os.Environment;

public class ohiapo9 extends Activity
{
	private LocationManager mLocationManager;
	private LocationListener mLocationListener;
	private TextView textView;
	private File aFile;
	private FileOutputStream out;
	@Override public void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		textView = new TextView(this);
		textView.setWidth(200);
		textView.setText("ok");
		TableLayout tableLayout = new TableLayout(this);
		tableLayout.addView(textView, new TableLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
		setContentView(tableLayout);
    	aFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/log.txt");	
    	try
    	{
			out =  new FileOutputStream(aFile);
		} 
    	catch (FileNotFoundException e)
    	{
			e.printStackTrace();
		}
	}
	@Override protected void onDestroy()
	{
		super.onDestroy();
		mLocationManager.removeUpdates(mLocationListener);
	}
	@Override public void onStart()
	{
		super.onStart();
		mLocationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
		if (!mLocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER))
		{
		}
		mLocationListener = new locationListener();
		mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 5, mLocationListener);
		mLocationManager.addNmeaListener(nmeaListener);
	}
	private final GpsStatus.NmeaListener nmeaListener = new GpsStatus.NmeaListener()
	{
		public void onNmeaReceived(long timestamp, String nmea)
		{
			String s = nmea + textView.getText().toString();
			textView.setText(s);
			try 
			{
				out.write(nmea.getBytes());
			} 
			catch (IOException e)
			{
				e.printStackTrace();
			}
		}
	};
	private class locationListener implements LocationListener
	{
		public void onLocationChanged(Location loc)
		{
		}
		public void onProviderDisabled(String arg0)
		{
		}
		public void onProviderEnabled(String provider)
		{
		}
		public void onStatusChanged(String provider, int status, Bundle extras)
		{
		}
	}
}
```


以上。
Chainerのtrain_ptb.pyを実行した時にトレーニングに使われているファイル

#概要
Chainerのptbフォルダにあるtrain_ptb.pyを実行した時にトレーニングに使われているファイルはどうなっているのか気になったので調べた結果をメモ。

# 環境

- Chainer ・・・　1.19
- Python ・・・ 3.5.2 |Anaconda 4.1.1 (x86_64)

ちょっとバージョン古いですが、今度新しいバージョンのものもやりたい。

#何処のファイルを使っているのか

ptb.pyにダウンロードするような記述があるので使っているのかと思いきや使っていないっぽい。使われていたのは.chainerという隠しフォルダ内の最下層にあるptbフォルダの次の三つ。

## train.npz

> [ 0  1  2 ..., 39 26 24]

## valid.npz

> [2211  396 1129 ...,  108   27   24]

## test.npz

> [142  78  54 ...,  87 214  24]


間違いなどありましたら指摘いただけると助かります。
個人的 ESLint (Standard) + Prettier 環境構築

## 0. お気持ち

毎回同じようなことをやっているのでまとめておくことにした。



現状、`prettier` の実行方法は、`eslint --fix` に hook させる方法と、`prettier-eslint-cli` から実行する方法の2種類がメジャーだと思う。
自分は `prettier-eslint-cli` から実行する方法を採用している。
これは 「Linter は Linter、Formatter は Formatter であってほしい」みたいな気持ちからそうしている。

ちなみに、`git commit` するときに、`husky` で `prettier` を実行する系のアレは、`git add -p` に対応していないという理由から設定していない。 
詳細は [Add better support for partially staged files · Issue #62 · okonet/lint-staged](https://github.com/okonet/lint-staged/issues/62) に書いてある。

## 1. ESLint 周りインストール

```bash
$ npm install --save-dev eslint eslint-config-standard eslint-plugin-standard eslint-plugin-promise eslint-plugin-import eslint-plugin-node
```

### 追記 (2018/07/12)

上記コマンドで入る `eslint-config-standard` だと ESLint v5.x に追従できておらず、以下のような警告を吐くようになった。
これに対処するためには、以下を実行すると良い。

```bash
$ npm uninstall eslint-config-standard
$ npm install eslint-config-standard@next --save-dev
```

詳細は [Warning message with ESLint 5 · Issue #114 · standard/eslint-config-standard](https://github.com/standard/eslint-config-standard/issues/114) に書いてある。

## 2. `.eslintrc.js` を書く

```.eslintrc.js
'use strict'

module.exports = {
  extends: 'standard'
}
```

## 3. Prettier 周りインストール

公式ドキュメントでは、`prettier` 自体は `--save-exact` でバージョンを完全に固定して入れることが推奨されているが、まあなんかそんなにきっちりしなくていいやということにした。

```bash
$ npm install --save-dev prettier prettier-eslint prettier-eslint-cli
```

## 4. `.prettierrc.js` を書く

ココらへんは好みだが、まあ Standard を採用していると、概ねこんな感じになるはず。

```.prettierrc.js
'use strict'

module.exports = {
  printWidth: 80,
  tabWidth: 2,
  useTabs: false,
  semi: false,
  singleQuote: true,
  trailingComma: 'none',
  bracketSpacing: true,
  arrowParens: 'always'
}
```

## 5. `package.json` を書く

```package.json
{
  ...
  "scripts": {
    ...
    "lint": "eslint .",
    "format": "prettier-eslint --write \"./**/*.js\" --ignore \"./node_modules/**\""
    ...
  },
  ...
}
```
C#(.NET Core）で、Gmailからメールを送信する

SmtpClientを使います。

```
System.Net.Mail.SmtpClient smtp = new System.Net.Mail.SmtpClient('smtp.gmail.com', 587);
smtp.EnableSsl = true;
smtp.Credentials = new System.Net.NetworkCredential("***id***", "***password***");

System.Net.Mail.MailMessage oMsg = new System.Net.Mail.MailMessage("from", "to", "subject", "body");
smtp.Send(oMsg);
```

## Gmailの2段階認証に注意

上記プログラムでメール送信ができますが、Gmailの2段階認証を導入している場合、パスワードにGoogleアカウントパスワードを入れても、送信できません。

別途、以下のアプリパスワード設定画面から、アプリパスワードを発行します。

- [Googleアプリパスワード](https://security.google.com/settings/security/apppasswords)
Railsで必要なエラーメッセージのみ表示するようにバリデーションを修正

### 解決したいこと
* メールアドレスが空欄の時、エラーメッセージが複数表示されてしまう
    * 「空欄」と「型に一致しない」の両方に当てはまってしまうから
* 片方のエラーメッセージだけ表示するようにしたい
    * 以下の場合は「メールアドレスを入力してください」を優先したい

![スクリーンショット 2018-06-22 6.47.49.png](https://qiita-image-store.s3.amazonaws.com/0/230946/41790925-5b07-a53d-7180-20fc1824b4f4.png)

* この時のメールアドレスのバリデーション（app/models/user.rb）

```ruby
class User < ApplicationRecord
    # 中略
    VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
    validates :email, presence: true, length:{maximum: 255}, 
               format: { with: VALID_EMAIL_REGEX }
    # 以下省略
end
```

### 解決方法
* 条件分岐でエラーメッセージの表示に優先順位をつける
    * 空欄＞文字数＞メールアドレスの型の順

```ruby
class User < ApplicationRecord
    # 中略
　　　　　　　　VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
　　　　　　　　validate :email_custom_error

    def email_custom_error
        if email.blank?
            errors[:base] = "メールアドレスを入力してください"
        elsif email.length > 255
            errors[:base] = "メールアドレスは255文字以内で入力してください"
        elsif email.match(VALID_EMAIL_REGEX) == nil
            errors[:base] = "メールアドレスが不正です"
        end
    end
    # 以下省略
end
```


他により良い書き方があればぜひ教えてください...！


### 参考資料
* [Railsでバリデーションのエラーメッセージを日本語のオリジナルにする方法](https://yuu.1000quu.com/japanese_validation_message_in_the_rails)
* [Active Record バリデーション | Rails ガイド](https://railsguides.jp/active_record_validations.html#errors-base)
Dynamonを使ってDynamoDB（本番）にアクセスしてみた

DynamoDBのGUIアプリケーション（本番につながる）が欲しくて探していたら、こんなのを見つけたので使ってみた備忘録。

[Dynamon](https://github.com/deptno/dynamon)

#使ってみる
ソースからのビルドはうまくいかなかったので、[release](https://github.com/deptno/dynamon/releases)ページから、媒体をDLして使ってみる。バージョンは0.1.5を指定。

#起動
起動するとこんな感じの画面です。

![スクリーンショット 2018-06-22 8.09.59.png](https://qiita-image-store.s3.amazonaws.com/0/102769/ab28120d-c0dc-da3f-b1ca-01742e2748e6.png)


#テーブルを選択してみる
Endpointを選択すると、Tableが選択可能になりました。デフォルト設定のAWSアカウントを読んでいるのか、アカウント周りは何も選択しなくても、自分のデフォルトアカウント設定のテーブル一覧が見えました。

![スクリーンショット 2018-06-22 8.15.27.png](https://qiita-image-store.s3.amazonaws.com/0/102769/6932a3c5-17e1-6700-8b49-1638b41cbd9d.png)

#レコードの登録とか編集
適当に新規テーブルを作成して、レコードの追加・編集を試してみます。

![スクリーンショット 2018-06-22 8.18.30.png](https://qiita-image-store.s3.amazonaws.com/0/102769/4e14a5ab-8fa0-e63c-4f8f-b64d2babb73b.png)

##レコード追加
「Records」横の「＋」ボタンを押せば、JSON形式でレコードを追加することができました。Validationに引っかかるような内容だと何もエラーを表示せずにただ追加に失敗するようですが、形式さえ気をつければレコード追加できそうです。（キャプチャは複数行追加用のダイアログ）

![スクリーンショット 2018-06-22 8.22.05.png](https://qiita-image-store.s3.amazonaws.com/0/102769/34c9f56a-1e77-2e3d-efb2-480e43c9463f.png)

内容を書き終わったら「Write」がクリック可能になるので、ここをクリックで追加されます。

![スクリーンショット 2018-06-22 8.22.17.png](https://qiita-image-store.s3.amazonaws.com/0/102769/49c5cdb0-a1c0-cacf-6f9f-618406e29370.png)

##レコード表示／編集
追加したレコードをクリックすると、内容をJSONで表示してくれます。

![スクリーンショット 2018-06-22 8.22.47.png](https://qiita-image-store.s3.amazonaws.com/0/102769/2a4397c2-60ce-e647-7fed-ec0ff1afaf06.png)

各項目の右側にある鉛筆マークをクリックすれば、編集モードになります。

![スクリーンショット 2018-06-22 8.22.59.png](https://qiita-image-store.s3.amazonaws.com/0/102769/151e968e-49b2-b5ad-d3bd-30c2fc2a5ca0.png)

編集も簡単。

![スクリーンショット 2018-06-22 8.23.09.png](https://qiita-image-store.s3.amazonaws.com/0/102769/6629bf13-b69f-cc18-6dc8-1383b7790731.png)

##レコード削除
削除したいレコードを右クリックするとレコード削除のメニューが表示されます。

![スクリーンショット 2018-06-22 8.23.14.png](https://qiita-image-store.s3.amazonaws.com/0/102769/297d7fb1-8462-687c-710a-00690047d5a5.png)

きちんとレコード削除もできました。

![スクリーンショット 2018-06-22 8.23.21.png](https://qiita-image-store.s3.amazonaws.com/0/102769/4e35eca2-b2fe-e7e5-72cc-ce06c0c8c914.png)

#まとめ
一通り操作してみましたが、DynamoDBのコンソールにログインせずにここまでできるのは非常にありがたいツールです。まだまだ機能的にクリックしても反応しないものもあるようですが（Githubに追加している機能の進捗が表示されてます）とても可能性のあるツールだと思いました。