OmniAICreator/Qiita-1.07M huggingface dataset:
DNS周りの用語解説

DNS周りは同じ機能を複数の言い方で表していたり、ある単語が文脈によって違うものを指す場合があるので、その視点でまとめてみました。

## 登場人物
![DNS仕組み.jpg](https://qiita-image-store.s3.amazonaws.com/0/99425/a45cf1b6-9919-27ec-5b2f-3b865419278e.jpeg)



## 2つのDNS
一般の会話では単純に「DNS」と参照される事が多いと思いますが、DNSと一口に言っても、「キャッシュDNS」と、「権威DNS」で全く機能と役割が異なるDNSになります。さらに、「キャッシュDNS」側は、他にも「リカーシブDNS」、「フルサービス･リゾルバ」等と呼ばれたりします。
 
* 権威DNS
IPアドレス等のゾーンのレコードを管理しているDNSです。
最も簡単なものは、「www.example.com のIP が 1.2.3.4 」のような、FQDN と IPアドレスを紐付けたレコードです。IPアドレスのレコードはAレコード(IPv6の場合は、AAAAレコード）と呼ばれます。
(かなり雑な説明ですが・・・他にどんなタイプのレコードがあるかはネットに大量に情報があるのでここでは割愛します）

* キャッシュDNS
複数の呼び方がありますが、私の周りでは「キャッシュDNS」と呼ばれる事が多いので(呼び方が一番短くなるから？）タイトルを「キャッシュDNS」としました。
他にも「フルサービス･リゾルバ」という呼び方があります。Google検索すると直接的な言葉としてはひっかからないのですが、私の周りでは「権威 DNS」 に対して、再帰的にアクセスしてIPアドレスを解決するので、「リカーシブDNS」と言う呼び方も頻繁に聞かれます。

<b> 番外編</b>

* DNS Forwarder

文字通り名前解決を自分で行わず他の「キャッシュDNS」サーバーにフォワードする DNSサーバーもしくは、フォワード機能の部分だけを指します。単純にフォワードしても存在意義が無いので、現実社会で遭遇するのは社内でだけ名前解決したいドメインを解決しつつ、それ以外の一般的なドメイン名は正式な(?)「キャッシュDNS」サーバーにフォワードするようなDNSサーバーになります。
Active Directory がこの機能を持っているので、Active Directory の文脈で目にする事が個人的には多いです。

## 2つのリゾルバ
こちらも単純に「リゾルバ」として呼ばれる事が殆どだと思いますが、2つのリゾルバがあり役割的に別ものです。

* スタブ･リゾルバ
ユーザーの端末の中に居て、ユーザーのアプリケーションからドメイン名の解決を受け付けるソフトウェアです。例外があるかもしれませんが、通常、OSレイヤーのコンポーネントです。「DNSクライアント」と呼ばれる事も多いです。
スタブ･リゾルバは、ローカルの hosts ファイルを見たり、フルサービス･リゾルバに問い合わせる事で、FQDNをIPアドレスに解決しようとします。

* フルサービス･リゾルバ
前述の「キャッシュDNS」と同じものです。権威 DNS に再帰的に問い合わせをして、IPアドレスに解決をしようとする DNS サーバーです。再帰的に問い合わせをするので「リカーシブDNS」と呼ばれる事があります。また、問い合わせした結果は、TTL 時間キャッシュされて再利用されるので、「キャッシュDNS」と呼ばれる事もあります。
QGISで複数の地物を囲む枠線を描くテクニック

##環境
macOS 10.14.5
QGIS 3.4

##今回の目標
神オープンソースGISソフトのQGISで、以下のように多数の地物を取り囲む枠線を描く事。
![スクリーンショット 2019-07-10 19.34.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73197/986d200a-70af-57df-1000-8998b11ee919.png)

##前提
手段を検討すると、たとえば以下のように手作業でポリゴンを作ってしまう方法が考えられます。
![スクリーンショット 2019-07-10 19.24.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73197/0b8d5346-c31d-e8d2-7983-75be6c3458e9.png)
ただこの手法は地物が複雑になると結構面倒くさいです。そして何よりスマートじゃない！どうせならとことんラクしましょう。

##スマートな手法
###①バッファで地物を大きくする
地物を指定した値で大きくするバッファという機能があります。
ちなみにこの機能、マイナスの値にすれば地物を小さくする事も可能です。
![スクリーンショット 2019-07-10 19.24.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73197/8f4bf520-0c6d-f403-0b06-015ed3622574.png)
![スクリーンショット 2019-07-10 19.25.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73197/176cf1ee-3aa5-e9a2-c2de-056baf906d30.png)
今回は10,000m膨らませてみましょう。
![スクリーンショット 2019-07-10 19.29.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73197/a4103483-ff44-62fb-9788-3d626fe6c68c.png)
![スクリーンショット 2019-07-10 19.29.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73197/1bd1ff1b-5128-6edf-658a-96444fcef8c4.png)

いい感じですね。

###②ディゾルブで地物を結合する
地物の重なりだとか、すべてを一切合切結合するディゾルブという機能があります。
![スクリーンショット 2019-07-10 19.31.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73197/720551d0-cba0-de1f-c66e-2a336c6a774b.png)
実行すると以下のとおり、さっきの地物すべてがひとつの地物に結合されます。
![スクリーンショット 2019-07-10 19.31.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73197/cd4fdc06-1a76-047a-1fb4-fefea4cf9a1c.png)

###③地物を簡素化する
現状は、最初の地物の最外周から一定距離で描かれたポリゴンとなっていますが、単なる枠線にそれほどの精密さは必要ないでしょう。ポリゴンの座標点を間引いて簡素化、つまりシンプルにします。
![スクリーンショット 2019-07-10 19.31.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73197/73d4872c-f09b-945c-4d52-7f635ad0778a.png)
![スクリーンショット 2019-07-10 19.47.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73197/4a189ee7-583e-e027-ee6d-50669cd53d17.png)

許容範囲の値が大きくなるほど、より強く簡素化されます。
今回は5,000mにしてみましょう。

![スクリーンショット 2019-07-10 19.32.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73197/41cc5bb6-5a92-762c-79f8-183b4b185de0.png)

いい感じ。

###④完成
レイヤースタイルを好みに設定して、市町村レイヤーを被せれば完成です！（本記事冒頭の図形が完成）

##参考
今回の市町村レイヤーのように、接点はあるが重なってはいない地物同士であってもディゾルブは有効です。以下のとおりすべての地物が結合されます。
![スクリーンショット 2019-07-10 19.36.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73197/bde44d04-8b7b-3743-139a-37301258f508.png)
concatだらけになるtemplate literal

Babelで変換されたあとのコードを見ると、一見無駄にも思えるコードが生成されていたのですが、実はそれが必要だった、というお話です。

## Template Literalとは

ES5までのJavaScriptでは、文字列を合成するには「1つ1つ`+`演算子で連結していく」「`Array.prototype.join`で連結する」などの手法があったのですが、どちらの方法にしてもどのような構造の文字列ができるか、分かりづらいものでした。

ES6では、他言語のように文字列途中で式展開ができる、Template Literalが登場しています[^1]。引用符として`` `...` ``を使い、式展開はその途中に`${...}`と書くという、他言語と比べてもそこまで違和感のない記法となっています。

## Babelでの変換結果

で、例によってIEは非対応なので（[MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/template_strings#%E3%83%96%E3%83%A9%E3%82%A6%E3%82%B6%E5%AE%9F%E8%A3%85%E7%8A%B6%E6%B3%81)）、IEを切り捨てられない環境ではBabelでの変換が必要となります。この変換を行う`@babel/plugin-transform-template-literals`では、[通常モードと`loose`モードの2通りの変換](https://qiita.com/jkr_2255/items/b7024c4984b69787d9c9)が選べます。

```javascript
// 変換前
const a = `${foo}-${bar}-${baz}`;

// 通常モード
var a = "".concat(foo, "-").concat(bar, "-").concat(baz);

// looseモード
var a = foo + "-" + bar + "-" + baz;
```

多くの人は、`loose`モードの方の結果を想像していたことでしょう。

## ここまで長くなる理由

### `.concat`による文字列変換

JavaScriptで一般に思いつく「文字列への変換」といえば、以下の2つかと思います。

* `String(値)`による文字列変換
* `'' + 値`として、暗黙の変換を活用する

これらは、以下のような動作をします。

* `String(値)`…シンボルの場合は` SymbolDescriptiveString`（`Symbol.prototype.toString()`）を返して、それ以外のときは`ToString`抽象操作を行う（[ES2019 §21.1.1.1](https://www.ecma-international.org/ecma-262/10.0/index.html#sec-string-constructor-string-value)）
* 文字列連結の演算…`ToPrimitive`抽象操作を行ってから、`ToString`抽象操作を行う（[ES2019 §12.8.3.1](https://www.ecma-international.org/ecma-262/10.0/index.html#sec-addition-operator-plus-runtime-semantics-evaluation)）

というように、挙動が異なっています。

一方で、Template Literalに埋め込んだ式は、`ToString`抽象操作により文字列に変換されるため（[ES2019 §12.2.9.6](https://www.ecma-international.org/ecma-262/10.0/index.html#sec-template-literals-runtime-semantics-evaluation)）、上のどちらとも異なっています。そこで登場するのが`String.prototype.concat`で、これは引数に対して`ToString`のみを行う仕様となっていますので（[ES2019 §21.1.3.4](https://www.ecma-international.org/ecma-262/10.0/index.html#sec-string.prototype.concat)）、仕様どおりの動作を実現させるために文字列変換と連結に`.concat`を使用するようになっています。

なお、文字列連結と`concat`で挙動が違うオブジェクトは以下のようなものです（プリミティブは`ToPrimitive`で変化しないので、差異はありません）。

* `[Symbol.toPrimitive]`が`.toString()`と違う結果を返すオブジェクト
* `[Symbol.toPrimitive]`がなく、`.valueOf()`が`.toString()`と異なる文字列表記になるプリミティブを返すオブジェクト

なお、`Date`は`.valueOf()`と`.toString()`の結果が異なりますが、別途で`[Symbol.toPrimitive]`を用意してあるため、文字列連結しても`.valueOf()`の値が出てくることはありません。

### 複数の`.concat`

ここまでで`.concat`を使う意味については説明してきましたが、「それなら`''.concat(foo, "-", bar, "-", baz)`でもいいんじゃないか？」と思ってしまうかもしれません。

ということで、Template Literalの処理を見返してみると、与えられた式展開の式1つ1つに対して、式の評価、`ToString`を行っては文字列連結、というように進んでいきます。一方で、メソッドを呼ぶ場合、メソッドの引数はすべて**メソッドの実行前に**評価されてしまいます。つまり、ここで評価順が違ってきます。

`.concat`を複数にすることで、1つ目の式の評価、`ToString`が終わってから2つ目の式の評価に移るというように、評価順序まで正確に同じものとするようになっています。

もっとも、この両者で違ってくるシナリオとしては、

* `ToString`すると例外が飛ぶような式が前の方に入っていたときに、後の式の評価で生じる副作用が起きるか起きないかの違い
* 前の方の式について`ToString`が副作用を持ち、それが後の式の評価や`ToString`の結果に影響を及ぼす場合

が考えられますが、`ToString`が副作用を持つオブジェクトを作っても極めて使いにくいでしょうし、`ToString`すると例外が飛ぶような式を文字列に埋め込んで、なおかつその例外が飛ぶパスを、他の式展開で副作用の起きるかどうかまで想定したコードを書く、という場面も考えづらいので、実用的に差異が出る危険性は薄そうです（そもそも、式展開の中に副作用の伴う式を書くこと自体、そう多くないと思いますし）。


[^1]: 雛形になる文字列と、式展開された値をまとめて関数に投げられるような、タグ付きTemplate Literalもありますが、とりあえず本稿では触れません。
FNLPでMecabのような中国語の形態素解析

# 概要
日本語の形態素解析(MeCab)のようなことを中国語でもやりたいのでFNLPを利用する

# 環境
OS : Windows7 64bit
言語: Java8
IDE: Ecplise4.8.0

# 目的

[OpenNLPでMeCabのような英語の形態素解析]([https://qiita.com/syunsuke-aka/items/31f65665e1ea7b561794)と同じ

日本語の文章をMecabにかけて得られる「形態素」「品詞」「基本形」を中国語でも行いたい
オープンソースの「FudanNLP(FNLP)」を利用して、中国分から「形態素」「品詞」を取得する

# 目次
1. 中国語の事前知識
2. Javaの実装
    1. 準備
    2. 分かち書き
    3. 品詞分解


# 1. 中国語の事前知識

## 文字は2種類
 * 簡体字と繁体字
 
本記事では、簡体字の文章に限定して考える

## 時制がない
  * 過去、現在、未来は文脈で判断する

>
* 過去形: 我昨天去了上海
    * 私は昨日上海へ行った
* 現在形: 我去上海
    * 私は上海へ行く
* 未来形: 我明天要去上海
    * 私は明日上海へ行かなければならない


このため本記事では、中国語の形態素は全て「基本形」で取得できるものとして考える

# 2. Javaの実装

## 1. 準備
直接MavenRepository内のfnlp-coreをpom.xmlで指定するとエラーになる為、一度ソースコードをビルドして、fnlp-core-2.1-SNAPSHOT.jarファイルを作成する

※ fnlp-core-2.1-SNAPSHOT.jarの作成は、[FNLPで中国語形態素解析](https://qiita.com/xiaotuanzi/items/4c1e0b5e2836a5ff921f)の「ダウンロード」「ビルド」を行う

mavenプロジェクトを作成し、作成したfnlp-core-2.1-SNAPSHOT.jarファイルをdicフォルダ配下に配置する

pom.xmlに以下を追加する

```
<dependency>
	<groupId>net.sf.trove4j</groupId>
	<artifactId>trove4j</artifactId>
	<version>3.0.3</version>
</dependency>
<dependency>
	<groupId>commons-cli</groupId>
	<artifactId>commons-cli</artifactId>
	<version>1.2</version>
</dependency>
<dependency>
	<groupId>org.fnlp</groupId>
	<artifactId>core</artifactId>
	<version>2.1</version>
</dependency>
<dependency>
    <groupId>org.fnlp</groupId>
    <artifactId>core</artifactId>
    <version>2.1</version>
    <scope>system</scope>
    <systemPath>${project.basedir}/dic/fnlp-core-2.1-SNAPSHOT.jar</systemPath>
</dependency>
```

また、https://github.com/xpqiu/fnlp/releases で公開されているモデルファイル3つ(pos.m, seg.m, dep.m)をダウンロードし、dicフォルダに配置する

## 2. 分かち書き

```
CNFactory factory = null;
// モデルファイルのパスを指定し、形態素解析器を呼び出す
try {
    factory = CNFactory.getInstance("./dic");
} catch (LoadModelException lme) {
    lme.printStackTrace();
}
String message = "今天天气真好啊！";
String[][] tokens = factory.tag(message);
System.out.println(Arrays.asList(tokens[0]));
>> [今天, 天气, 真, 好, 啊, ！]
```

## 3. 品詞分解

```
CNFactory factory = null;
// モデルファイルのパスを指定し、形態素解析器を呼び出す
try {
    factory = CNFactory.getInstance("./dic");
} catch (LoadModelException lme) {
    lme.printStackTrace();
}
String message = "今天天气真好啊！";
String[][] tokens = factory.tag(message);
System.out.println(Arrays.asList(tokens[1]));
>> [时间短语, 名词, 副词, 形谓词, 语气词, 标点]
```


# 参考リンク
* [FNLPで中国語形態素解析](https://qiita.com/xiaotuanzi/items/4c1e0b5e2836a5ff921f)
* [ソースコード](https://github.com/FudanNLP/fnlp)
s3オブジェクト一覧取得(Go)

## はじめに

S3バケットのオブジェクト一覧を取得する場合は通常awscliを使用して

```terminal
aws --profile {profile} s3 ls --recursive s3://{bucket}/{prefix}
```
のような感じで実行すると思います。
オブジェクトが少なければこれで問題ないですが、大量にあると時間がかかります。
実際に特定prefix配下の（1億ほど）オブジェクト一覧を取得する必要があり、awscliだと
数日かかることが見えていたので、Goで実装してどれだけ速くなるか試してみました。

## コード

```golang:main.go
package main

import (
	"flag"
	"fmt"
	"os"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/s3"
)

var (
	argRegion  = flag.String("region", "ap-northeast-1", "specify region name")
	argProfile = flag.String("profile", "", "specify credential profile name")
	argBucket  = flag.String("bucket", "", "specify bucket name")
	argPrefix  = flag.String("prefix", "", "specify object key prefix")
)

func main() {
	flag.Parse()
	defer func() {
		if r := recover(); r != nil {
			flag.Usage()
			fmt.Println(r)
			os.Exit(1)
		}
	}()

	config := aws.Config{Region: argRegion, MaxRetries: aws.Int(10)}
	if *argProfile != "" {
		creds := credentials.NewSharedCredentials("", *argProfile)
		config.Credentials = creds
	}
	sess := session.New(&config)
	svc := s3.New(sess)

	params := &s3.ListObjectsV2Input{Bucket: argBucket, Prefix: argPrefix}
	jst, _ := time.LoadLocation("Asia/Tokyo")
	svc.ListObjectsV2Pages(params,
		func(page *s3.ListObjectsV2Output, lastPage bool) bool {
			for _, obj := range page.Contents {
				fmt.Printf("%s %10d %s\n", obj.LastModified.In(jst).Format("2006-01-02 15:04:05"), *obj.Size, *obj.Key)
			}
			return *page.IsTruncated
		})

}
```

## 実行方法

```terminal
# コンパイル
go build -o s3lsall main.go
# 実行
./s3lsall -profile {profile} -bucket {bucket} -prefix {prefix}
```

結果表示は、awscli(`aws s3 ls`)と同じフォーマットで出力されます

```terminal:例
2019-01-22 11:46:39       8023 hoge/197352643.json
2019-01-23 11:16:28       5000 hoge/197512582.json
2019-01-23 19:46:02       4995 hoge/197512839.json
```

## 性能比較（参考）

t3.smallインスタンスで実行し、10万オブジェクトの一覧取得で比較

| 使用ツール | 所要時間 | CPU使用率 |
|:--------:|:-------:|:---------:|
| awscli   | 65秒    | 30%      |
| s3lsall(go実装) | 15秒    | 10%      |

## まとめ

awscliで時間がかかりそうな大量リソースに対する処理などは、必要な処理に特化した
プログラムをGoでサクッと実装するとよさそうですね（速度／負荷的にも）

Go以外の言語でsdkを使ってプログラムを書いてもいいですが、そのランタイム環境を用意
しないといけないので、ワンバイナリ配布で実行できる、というのもGoのいいところですね！
モノリシック vs Frontend with BFF

## はじめに
最近だとFirebaseでプロトタイピング等もありますが、今回それは比較には入れません。

## モノリシック vs Frontend with BFF
モノリシックなアプリケーションは事業要件に合うフレームワークを正しく選択できた場合、アプリケーションの構築がもの凄く高速にできます。
プロトタイピング、仮説検証の段階だと特に力を発揮するでしょう。
基本的に管理画面も用意されてますしね。

ではなぜモノリシックなアプリケーションをBFFにリファクタリングし、FrontendをVueやReact等でモダンな構成にする必要があるのでしょうか？
実はそんな必要はない？

今回はモノリシックなアプリケーションとFrontend with BFFで比較しようと思います。

## モノリシック
MVCで作られたモノリシックなアプリケーションはUIに1つ機能追加、削除する度にそのページを表示するコントローラーにコードを追加し、恐らくこのスタイルとhtmlを変更すればよいのだろうと当たりをつけて開発します。
なので、UIのメンテナンスをするだけで最小でそのページのhtml, css。
データをいじる場合はページ単位。
場合によってはアプリケーション全体に影響範囲があります。
アプリケーションの機能の種類や種類、その関連度合によってはアプリケーションのメンテナンスにかかる時間がどんどん上がっていきます。

## Frontend with BFF
BFFをGraphQL等柔軟性のあるよくできたスタックで構築されているのを前提とします。
完全に切り離されたこちらの構成だと、画面に出すデータを追加・変更・削除したい場合に影響があるのはフロントエンドだけで、リリースもフロントエンドだけです。完全に切り離されてますね。
また、何かしらのデータをサーバーに保存するとか、何かを実行する必要がある機能の追加の場合だとサーバーにも新たにapiを追加する必要があります。しかし、スタイルだけ変更するとか、既に作られているapiを新たな所で叩く場合はサーバーへの影響はありません。
なので、UIのメンテナンスをするにあたって、サーバーへの影響がモノリシックなアプリケーションと比べ大分少ないです。
なので、モノリシックなアプリケーションではバックエンド全体がどうしてもUIに引きずられがちでしたが、GraphQLで構築されたBFFとFrontendに分けた場合、バックエンドは機能の追加、メンテナンスに集中でき、フロントエンドはUI/UX要件を満たし続けるのに集中でき、結果バックエンドを資産化できるのではないでしょうか。
デザイン、フロントエンドのスタックにそこまで左右されないバックエンドを持つ事は単に分業ができるだけでなく、開発を加速させ、結果事業全体を加速する事ができ、マーケットでの勝利の鍵になるのではないかと思います。
PythonのPDF処理まとめ(結合・分割, 画像変換, パスワード解除)

##はじめに
PythonでPDFを扱う方法を目的別にまとめます。
シンプルなファイル読み書き、画像への変換やパスワードロック解除等について記載します。

##PDFファイル読み書き
基本的な読み書きについてはPyPDF2というライブラリを使う事で実装可能です。

```python
pip install PyPDF2
```

以下は、複数のPDFファイルをひとつのPDFに結合する関数の参考例です。

```python
def integratePdf(fileList):
	merger = PyPDF2.PdfFileMerger()
	for file in fileList:
		merger.append(file)
	OUTPUT_DIR = os.path.dirname(fileList[0])
	merger.write(OUTPUT_DIR + '/output.pdf')
	merger.close()
```

mergerでPyPDF2のPdfFileMergerクラスのインスタンスを生成し、そこにPDFファイルのパスを渡しています。
merger.write()関数により結合後のPDFファイルを出力します。
もし特定のページを追加したいのであれば以下のとおり書けば良いです。

```python
merger.append(file, pages=(0,2))
```

この場合、1ページ目から3ページ目までを、mergerに追加しています。

PDF同士の結合のパターンを紹介しましたが、シンプルなRead&Writeにも対応しています。
しかしながら、PDFをPDFのまま扱う場合の処理というのは、結合・分割にほぼ限られるのかな、と思います。

##画像への変換
pdf2imageというライブラリで非常にシンプルに書けます。
※pillowとpopplerというライブラリに依存

```python
pip install pdf2image
pip install pillow
pip install poppler
```

これでインストールして

```python
from pdf2image import convert_from_path
```

でライブラリをインポートし

```python
imgs = convert_from_path(pdf_filepath)
for img in imgs:
	img.save('output.png','png')
```

例えばこんな感じで、pngファイルとして保存する事ができます。非常にかんたん。

##パスワードロックの解除
PyPDF2もパスワードによる読み込み機能はありますが、[こちら](https://qiita.com/Kanahiro/items/f19e1b4e465c3aeacde5)で説明したとおり古いバージョンのPDFにしか対応していません。という事で、pikepdfというライブラリを使います。[Documantation](https://pikepdf.readthedocs.io/en/latest/)を読む限り、qpdfのラッパーです。
※既知のパスワードのロックを解除するコード例です

[GitHub/pikepdf](https://github.com/pikepdf/pikepdf)

```python
pip install pikepdf
```

```python
from pikepdf import Pdf
```
でPdfクラスをインポート

以下は「（パスワードの文字列）.pdf」を読み込んで、パスワードロックを解除した別ファイル「decrypted.pdf」として保存する関数の参考例です。

```python
def unlockPdf(filepath):
	PSWD = os.path.basename(filepath)[0:-4]
	pdffile = Pdf.open(filepath, password=PSWD)
	newPdf = Pdf.new()
	newPdf.pages.extend(pdffile.pages)
	OUTPUT_DIR = os.path.dirname(filepath)
	newPdf.save(OUTPUT_DIR + '/decrypted.pdf')
```

パスワードは既知である必要があり、パスワードのわからないPDFファイルのロックを解除するものではありません。

```python
pdffile = Pdf.open(filepath, password=PSWD)
```

この行で、パスワードロックされたPDFを、そのパスワードを用いて読み込んでいます。
そして以下の行で新たなPDFファイルとして出力しています。
とてもシンプルに書けますね。

ちなみに、Windows32bit環境で動作する実行ファイルを作ってあります。
[GitHub - Kanahiro/PdfUnlocker]
(https://github.com/Kanahiro/PDFUnlocker)

##終わりに
以上、実装したい処理別にライブラリを紹介しました。
他には、PDFファイルからのデータマイニング（OCR機能を用いてPDFファイルからテキストデータへの変換）なんかも需要があるようです。
今後紹介できればと考えています。
さて本記事は結局、PDFを○○したいときにはどのライブラリを使うべきか、という記事になっております。
先人が、「こういう機能があれば便利」と思って書いてくれたライブラリ、活用しない手はありません。
でもいつかはそういったライブラリを提供する側に回りたいなと思うこの頃です。
Ubuntu16の公式Dockerイメージには/etc/servicesや/etc/protocolsが入っていない

# Ubuntu16の公式Dockerイメージには/etc/servicesや/etc/protocolsが入っていない

初期状態では一部のネットワーク系API(getprotobynameとかgetaddrinfoとか)が失敗する。

ネットワーク系のアプリやライブラリを使う際にエラーが起きると、原因究明に難渋する場合がある。
(こんなファイルがないとか、なかなか想像しないですよね？)

## 対策

問題のファイル群は[`netbase`](https://launchpad.net/ubuntu/+source/netbase)パッケージに含まれている模様。入れましょう。

```sh
sudo apt install netbase
```

## 問題の実例

例えば、こんな問題が起きた：

メッセージキューのライブラリである[Qpid Proton](https://qpid.apache.org/proton/index.html)を使用。
通信先のポート番号を明示的に指定した場合は問題なく動くが、明示指定しないと処理が永久に進まなくなるという不具合が発生。

調べたところ、以下の機序で無限ループしていた。

1. Qpid ProtonがAMQPのデフォルトポート番号をgetaddrinfo()で解決しようとする
1. /etc/servicesがないので、APIが失敗
1. Qpid Protonが(なぜか)失敗時に無限にリトライする実装になっているため、最初に戻る

## その他

* Ubuntu16のdockerイメージの他、それをベースにしたdockerイメージにも入っていない場合があるので注意。
  Ubuntu16ベースのNVIDIA cudaイメージとか。
  Dockerfileを書くときはパッケージを--no-install-recommendsで入れることが多いので、依存関係による自動導入もされにくい。

* Ubuntuをミニマム構成でインストールした場合にも入らないかも？(未確認)。

## ぐち

これくらい最初から入れといてくれてもいいのに…

(障害票の閉じられ方を見るに、[by design](https://bugs.launchpad.net/cloud-images/+bug/1673930)なのか？)
Discrete Element Methodのためgranooをインストールする

#モチベーション
モチベーションは，粉体の挙動を把握したかった．
個別要素法（DEM法）にはいくつかソフトウェアがあるので，それを利用する．granooの他にpygranやyade open demなども触ったので，いつか記事にする．自分でも作ったのだが，それもいつかのせたい．

#granooをインストールする
まずは，公式サイトへいって[granooをインストール](https://www.yakuru.fr/granoo/install.html#)を選択する．MacOSを先選択する．

以下をインストールする．．

```
brew install subversion
brew install git cmake boost qt eigen vtk
brew link --force qt
```

vtkのインストールできなかった．mojaveではxcodeのパッケージに不備があってインストールされていないんだった．ということで，インストール．

```
xcode-select --install
```

もう一度インストール．

```
brew install vtk
```

あとはそのまま行けた．

```
cd
DIR=$PWD
mkdir -p granoo/tags && cd granoo/tags
svn checkout https://scm.ff-m2p.cnrs.fr/anonscm/svn/granoo/tags/2.0
mkdir $DIR/granoo/tags/2.0/build
mkdir $DIR/granoo/install
cd $DIR/granoo/tags/2.0/build/
cmake ../CMake -DCMAKE_INSTALL_PREFIX=$DIR/granoo/install/
make && make install
```

パスを設定する．

```
echo 'export GRANOO_INSTALL_DIR='$DIR'/granoo/install/GranOO/2.0' >> ~/.bashrc
echo 'export PATH=$PATH:$GRANOO_INSTALL_DIR/bin' >> ~/.bashrc
echo 'export PYTHONPATH=$PYTHONPATH:$GRANOO_INSTALL_DIR/python' >> ~/.bashrc
source ~/.bashrc
```

テストを実行．

```
cd $DIR/granoo/tags/2.0/Example/Granular/Rain/
mkdir build && cd build/ && cmake ../ && make && cd ../
./build/rain.exe ./Rain.inp
granoo-viewer ./Results/
```

成功．特に詰まるところはなかったが，一応掲載．

#自分のMacbookProでは．．．
環境：MacOS Mojave 10.14.5

うまくいかない
makeでエラーがでてしまう．

```
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make[2]: *** [Binding/Python/pygranoo.so] Error 1
make[1]: *** [Binding/Python/CMakeFiles/pygranoo.dir/all] Error 2
make: *** [all] Error 2
```

not found for architecture x86_64の問題を解決できない．知恵をお貸し願いたい．
RxJava+Kotlinでログを吐かせる便利拡張関数

``` kotlin
fun <T> Observable<T>.logging(tag: String = Throwable().stackTrace[1].methodName): Observable<T> = this
    .doOnSubscribe {
        Log.d(tag, "doOnSubscribe")
    }
    .doOnNext {
        Log.d(tag, "doOnNext = $it")
    }
    .doOnError {
        Log.d(tag, "doOnError = $it")
    }
    .doOnComplete {
        Log.d(tag, "doOnComplete")
    }
    .doOnDispose {
        Log.d(tag, "doOnDispose")
    }
```

使うとき

``` kotlin
rxObject
  .map { /* something to do */ }
  .logging("rxObject")
  .subscribeBy { /* something to do */ }
```

みたいにすれば、ログが吐かれる
Nuxt.jsをExpressで使うときにTypeScriptの型チェックが動かない場合の対処法

Nuxt.jsをTypeScriptで書いていて、`new Builder(nuxt).build()`してExpressのミドルウェアとして動かしていると、ファイル保存時にTypeScriptの型チェックが実行されないことに気がつきました。
ビルド時にエラーがあると教えてくれますが、開発中も教えて欲しいですよね。

Nuxtのissueを検索すると、解決策が載っていました。
[TypeScript type checker is not run when using Builder programmatically · Issue \#5553 · nuxt/nuxt\.js](https://github.com/nuxt/nuxt.js/issues/5553)

```ts:server/index.ts
import express from 'express'
import { Nuxt, Builder } from 'nuxt'
import config from '../nuxt.config'

const app = express()
const nuxt = new Nuxt(config)

async function start(): Promise<void> {
  if (nuxt.options.dev) {
    await new Builder(nuxt).build()
  }

  app.use(nuxt.render)
  app.listen(3000, '0.0.0.0')
}

start()
```

こういう感じのサーバがあるとして、

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51938/ccf099f3-93d5-d005-b30b-88beac75910d.png" width="500">
型エラーがあるファイルが含まれているのに、なにもエラーを出してくれません。


## 解決方法
```ts:server/index.ts
import config from '../nuxt.config'
// ↓追記
config._typescript = {
  build: true
}
```

Nuxtの設定に`_typescript.build`という隠しパラメータがあるらしく、それを有効にすればいいです。
別途[fork-ts-checker-webpack-plugin](https://github.com/TypeStrong/fork-ts-checker-webpack-plugin)をインストールする必要があるとのことですが、[@nuxt/typescript](https://www.npmjs.com/package/@nuxt/typescript)の依存パッケージに含まれているので、個別にインストールする必要はありませんよね。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51938/66e76f3b-82ca-0eb5-82b7-98218fb102de.png" width="500">
ちゃんとチェックが走る！めでたいですね。
ドキュメントに書いておいて欲しい。

## 参考
* [API: Nuxt\(options\) \- Nuxt\.js](https://ja.nuxtjs.org/api/nuxt/)
* [TypeScript type checker is not run when using Builder programmatically · Issue \#5553 · nuxt/nuxt\.js](https://github.com/nuxt/nuxt.js/issues/5553)
【VFX Graph】宝箱をキラキラ光らせてみた。

##はじめに
宝箱をキラキラさせるエフェクトをVFX Graph(Visual Effect Graph)で作ってみました。

![sparkle_scene.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/44288/6814e478-78cd-7b5f-efde-4033c778724a.gif)

今回の記事では、上記のエフェクトの作り方を解説したいと思います。

## 環境
【Unityバージョン】
Unity 2019.1.1f1

【パッケージ】
Lightweight RP - Version 5.7.2
Visual Effect Graph - Version 5.13.0(Preview)

【OS】
Windows 10

## STEP1 : テクスチャの準備
今回は以下の四角星のテクスチャを使用しました。(解像度:128x128)
[![四角星テクスチャ(透過png)](a https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/44288/2957ecf0-4f09-c68b-ac19-36ef59ab30c2.png)](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/44288/2957ecf0-4f09-c68b-ac19-36ef59ab30c2.png)

![Star_no_alpha.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/44288/f62dd2a9-cee1-3487-8ac0-00538de7c554.png)


上記のテクスチャはSubstance Designerを使って作成しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/44288/5f28a12d-52dc-ad9e-fefd-785ffac95cdf.png)

## STEP2 : VFX Graphの作成
今回は以下のようなVisualEffectGraphを作成しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/44288/681f6800-0ce7-af9e-7702-e2ce92adf42a.png)

### VFX Graph解説 : Spawnノード(パーティクルの生成)
Constant Spawn Rateブロックを使って毎秒32個のパーティクルが出るようにしています。

<img height = 160 src = "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/44288/adee5fcd-cf96-edc5-6e03-732ba223cc31.png">

### VFX Graph解説 : Initializeノード(パーティクルの初期化) 
`Position(Sphere)`ブロックでは、パーティクルの初期位置が球状に配置されるようにしています。

`Set Lifetime Random`ブロックではパーティクルの寿命を設定されるようにしています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/44288/9973ca14-27ae-90a0-05dd-b9f0fd033f9c.png)


### VFX Graph解説 : Updateノード(パーティクルの毎フレーム処理)
今回はUpdateノードには何も行っていません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/44288/3f7e35a2-899e-fffa-34d7-8cd56e25c276.png)

### VFX Graph解説 : Outputノード(パーティクルの描画) 
`Set Size over Life`ブロックでは、時間経過で徐々にパーティクルサイズが小さくなるような変化を与えています。パーティクル生成時は1で、最後には0になるようになっています。

次に`Multiply Size`ブロックを使い、パーティクルサイズを0.2倍にしています。

最後に`Multiply Color randomized`ブロックを使ってパーティクルの色をランダムにしています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/44288/63f6b75e-5cd1-a613-1f97-9c51b5fef178.png)


## STEP3 : VFX Graphの配置
STEP2のエフェクトを配置すると以下のようになります。
![result.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/44288/cf8caf44-eb1c-4571-0bc4-5cc706293a1c.gif)

VFXGraphのパラメータは以下のように設定しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/44288/03a729e3-3df1-39c6-1b2f-c5f488282eb5.png)

## STEP4 : 宝箱の配置
宝箱を配置し、Post Processing StackのBloomを適用すると以下のような見た目になります。
![result2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/44288/c2000f14-b692-5209-b618-e88bb8a1a9f1.gif)

## 宝箱について
宝箱は下記のアセットを使用させていただきました。

Treasure Set - Free Chest
https://assetstore.unity.com/packages/3d/props/interior/treasure-set-free-chest-72345

## 参考URL
【Unity】Visual Effect Graph（VFX Graph）をLWRPで使用する
http://tsubakit1.hateblo.jp/entry/2019/04/03/233240
DjangoMigration - 外部キーリレーショナル

# DjangoMigration - 外部キーリレーショナル
Django migrationで、RDBを構築するにあたって。

## 前提
[こちら](https://qiita.com/yohei-29/items/00496c8252014c7c0aad)の、前提条件とマイグレーションの初歩を参考

## 外部キー参照設定
Django migration を利用して、外部キー参照設定を行うには。
### *ForeignKey* を設定する

紐づけたいモデルを定義する事で、外部キーカラムを付与したテーブルの生成が可能になる。

```py:example
class Question(models.Model):
    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')

class Choice(models.Model):
    # ↓↓↓↓↓↓↓↓
    question = models.ForeignKey(Question, on_delete=models.CASCADE)
    choice_text = models.CharField(max_length=200)
    votes = models.IntegerField(default=0)
```
### マイグレート
マイグレートファイルを生成して、テーブル生成。

```shell
python manage.py makemigrations web
python manage.py migrate
```

## パラメーター

### on_delete
- 紐付いているレコードも削除するか否かの設定を行う
- on_delete=models.CASCADE
 - 紐付いた情報の削除
- on_delete=models.PROTECT
 - 紐付いている情報が存在する場合には削除しない

## null許容されてない場合
*null=False*となっており、空欄を許容していない場合には、デフォルト値を設定して置くと良い。

```py:example
question = models.ForeignKey(Question, on_delete=models.CASCADE,  default=1)
```
もし、設定されていなかった場合には、makemigration時にデフォルト値を入力するか尋ねられ、その場で入力する事も可能ではある。

## 参照関係
外部キー設定されているオブジェクトは、互いに参照し合うことが出来る。
一対多（OneToMany）の関係、多対多（ManyToMany)、一対一(OneToOne)の関係性を持っている。
Processingでライフゲーム

## Processingでライフゲーム

```Java
int HEIGHT = 40;
int WIDTH = 60;
int SIZE = 10;
int map[][] = new int[WIDTH][HEIGHT];
int time = 0;
int status = 0;
boolean isDrawable = false;
void setup() {
  size(600, 400);

  // Pragraming Start!
  map[11][10] = 1;
  map[10][11] = 1;
  map[10][12] = 1;
  map[11][12] = 1;
  map[12][12] = 1;
  // Programing End

}

void draw() {
  background(255);
  if(isDrawable){
    if(mousePressed){
      int x = mouseX / SIZE;
      int y = mouseY / SIZE;
      if(x >= 0 && x < WIDTH && y >= 0 && y < HEIGHT){
        int value = 1;
        if(mouseButton == RIGHT){
          value = 0;
        }
        map[x][y] = value;
      }
    }
  }
  if(status == 1){
    time += 1;
    if(time > 10){
      step();
      time = 0;
    }
  }
  drawGridLines();
  for (int y=0; y<HEIGHT; y++) {
    for (int x=0; x<WIDTH; x++) {
      if (isAlive(x, y)) {
        drawLife(x, y);
      }
    }
  }
}

void keyPressed(){
  if(status == 0){
    status = 1; 
  }else if(status == 1){
    status = 0;
  }
}
void mousePressed(){
      int x = mouseX / SIZE;
      int y = mouseY / SIZE;
      if(x >= 0 && x < WIDTH && y >= 0 && y < HEIGHT){
        int value = 1;
        if(mouseButton == RIGHT){
          value = 0;
        }
        clickGrid(x, y);
      }
}

void step(){
  int[][] _map = new int[WIDTH][HEIGHT];
  for (int y=0; y<HEIGHT; y++) {
    for (int x=0; x<WIDTH; x++) {
      _map[x][y] = map[x][y];
    }
  }

  for (int y=0; y<HEIGHT; y++) {
    for (int x=0; x<WIDTH; x++) {

      int count = getCountLife(x, y);
      if(isAlive(x, y)){
        if(count < 2){
           _map[x][y] = 0;
        }
        if(count > 3){
          _map[x][y] = 0;
        }
      }else{
        if(count == 3){
          _map[x][y] = 1;
        }
      }
    }
  }
  for (int y=0; y<HEIGHT; y++) {
    for (int x=0; x<WIDTH; x++) {
      map[x][y] = _map[x][y];
    }
  }
}
int getCountLife(int x, int y) {
  int count = 0;
  for (int _y=-1; _y<=1; _y++) {
    for (int _x = -1; _x<=1; _x++) {
      if (_x == 0 && _y == 0) {
        continue;
      }
      if (isAlive(x + _x, y + _y)) {
        count += 1;
      }
    }
  }
  return count;
}
boolean isAlive(int x, int y) {
  if (x >= WIDTH || x < 0 || y >= HEIGHT || y < 0) {
    return false;
  }
  if (map[x][y] == 1) {
    return true;
  }
  return false;
}
void drawLife(int x, int y) {
  fill(0);
  rect(x * SIZE, y * SIZE, SIZE, SIZE);
}
void drawGridLines() {
  stroke(0, 20);
  for (int x = 0; x<width; x+=SIZE) {
    line(x, 0, x, width);
  }
  for (int y=0; y<height; y+= SIZE) {
    line(0, y, width, y);
  }
}
void clickGrid(int yoko, int tate){
  // Prgraming Start!
}
```
jQueryの基礎

#jQueryの基礎
##jQueryの導入～テスト実行
```html:index.html
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Progate</title>
  <link rel="stylesheet" type="text/css" href="stylesheet.css">
  <!-- jQueryの読み込み -->
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
</head>
<body>
  <h1>Hello, World</h1>
  <!-- script.jsの読み込み -->
  <script src="script.js"></script>
</body>
</html>
```
```javascript:sample.js
$(function() {
  //hideメソッドを用いて<h1>要素を隠す
  $('h1').hide();  
});

```

##イベント
```html:index.html
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Progate</title>
  <link rel="stylesheet" type="text/css" href="stylesheet.css">
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
</head>
<body>
  <!-- このボタンを押すと -->
  <div class="btn" id="hide-text">説明を隠す</div>
  <!-- この表示が隠れる -->
  <h1 id="text">Hello, World!</h1>
  <script src="script.js"></script>
</body>
</html>
```
```javascript:sample.js
$(function(){
  $('#hide-text').click(function(){
    $('#text').slideUp();
  });  
});
```
##メソッドの例
`$('セレクタ').hide();  `：要素を隠す
`$('セレクタ').fadeOut(1000);  `：アニメーション付きで要素を隠す（1000ミリ秒）
`$('セレクタ').slideUp(1000);  `：アニメーション付きで下から上に要素を隠す
`$('セレクタ').show();  `：隠れた要素の表示（要素はCSSでdisplay:none;をしておく）
`$('セレクタ').fadeIn(1000);  `：アニメーション付きで要素を表示
`$('セレクタ').slideDown(1000);  `：アニメーション付きで下から上に要素を表示
`$('セレクタ').css('color', 'red');  `：CSSを変更
`$('セレクタ').text('テキスト');`：テキストを変更
`$('セレクタ').html('<a href="#">リンク</a>');`：HTMLを変更

##イベントの例
`$('セレクタ').click(function(){クリックしたときの処理});`
`$('セレクタ').hover(function(){マウスをのせたとき},function(){外したとき});`
##おまけ：変数の宣言とメソッドチェーン
```javascript:sample.js
//変数の宣言
var $title = $('#title');
$title.css('color', 'red');
$title.fadeOut(1000);
    
//メソッドチェーン（メソッドを繋げる）
$('#text').css('color', 'blue').fadeOut(1000);

//findメソッド（子孫要素から指定したセレクタをもつ要素を取得）
$('セレクタ').find('a').css('color', 'blue');
```
社長にリモートワーク制度を提案する資料

# 社長にリモートワーク制度を提案する資料
今度社長にリモートワークを提案しようと思うのですが、その際のメモ。
## なぜリモートワークを導入するべきか？
### 働き方の多様化への対応
昨今のエンジニア不足の中では、優秀なエンジニアを出産や育児・あるいは介護と言った人生上のイベントにより失ってしまうのは避けなければなりません。
現在の弊社の技術チームには直近でこれらのイベントが起こりそうなメンバーはいませんが、
必要になってから対応するのでは遅い可能性があります。事前に備えておくべきです。

### 出社しない方が合理的なケースもある
#### 悪天候時など
フルリモートは許可しないにしても、翌日台風が直撃することが明らかな場合など、
通勤すること自体が従業員に対するリスクになる場合に許可することは合理的です。

#### 通勤のコスト
満員電車や長時間の通勤が従業員の健康、幸福感や仕事上のパフォーマンスに悪影響を及ぼす研究結果は枚挙に暇がありません。
https://doda.jp/careercompass/compassnews/20170731-26887.html
https://www.workersresort.com/jp/culture/commute-sf/

オフィスに近い地点に住む社員に住宅手当を出す等の方策もありますが、
家族との兼ね合い等もあり、すべての社員がオフィス近辺に住むことが出来るわけではありません。
一方、リモートワークではそのような制限はありません。
手当を出す必要もありませんし、むしろ交通費の支給額が減らせる可能性すらある安上がりな福利厚生です。

### エンジニア採用におけるアピール
#### 地理的制約の排除
弊社のオフィスは東京に所在しているため、
現状採用できるエンジニアは東京及び東京近郊在住ないし近辺に転居できるエンジニアに限られます。

しかし、東京及び関東のエンジニアの平均給与は高い上に給与に対する満足度も低い傾向にあります。
参考:https://next.rikunabi.com/tech/docs/ct_s03600.jsp?p=001167

単に東京に優秀なエンジニアが集まり易いだけという可能性もありますが、
生活費が給与とその満足度に強く影響することを考慮に入れると、
地方でのフルリモート勤務を許可することで給与水準に比べて優秀なエンジニアを採用できる可能性は十分にあります。

#### 採用メリット：エンジニアの勤務スタイルに配慮しているというアピール
エンジニア向け採用サイトの求人を確認すると、リモート勤務可をセールスポイントにしている企業は多くありますし、求人の絞り込み条件にも設定可能な場合がほとんどです。
多くの企業が導入しているため、明確なプラスにはなりにくいと思いますが、
そもそも導入していないことを以てエンジニアに対する配慮が足りないと判断されてしまうかも知れません。

## 懸念される点/必要な対策
とはいっても、リモートワークは銀の弾丸ではなく、以下のような問題も伴います。

### コミュニケーション不足
何の対策も打たなければ、同じオフィスにいる場合に比べてコミュニケーションが希薄になってしまうことは当然です。
ここに関しては、ビジネスチャットツールやWeb会議用機材の導入と言ったツール面の補助の他、
社内の制度や文化と言ったソフト面での対策が必要です。

ただ、ここに関してはビジネスチャットツール等は組織が健全に成長する上ではいずれ必要になるツールですし、ソフト面の対応もリモートを行う、行わないにかかわらず本来は真剣に考えるべきテーマです。

「リモートワーク　コミュニケーション」と言った単語で検索すればいくらでも事例は出てきますので、
自社の状況と比較しつつ最適なあり方を考えるべきでしょう。

### セキュリティ上の問題
#### 社内ネットワーク問題
「業務上、社内からしかアクセスできないシステムがあるためリモートワーク出来ない」というケースも想定されます。
業務システムを社内ネットワーク上に隔離することでセキュリティを確保するアプローチは長く支配的だったため、大抵の会社では何かしらのシステムがこうなっているでしょう。

##### VPNを引く
ある意味一番楽なアプローチはVPNを設定してしまうことです。
費用はかかりますが、既存のシステムを変更することなくそのままリモート勤務が可能になります。
近年ではリモートワーク用VPN専門業者もありますので、インフラエンジニアがいなくても導入は可能です。

##### ゼロトラストアプローチへと転換する
そもそも社内ネットワークなら安心という発想を捨ててしまうのも一つの手です。
ネットワークによる判断を行わず、全ての通信を信用せずに必ず認証認可プロセスを通す「ゼロトラスト」アプローチを採用したシステム設計になっていれば、リモートワークでもオフィス勤務でも何も変わりません。

参考：https://www.secure-sketch.com/blog/zero-trust-security-model

フットワークが軽いスタートアップの場合、社内システムを載せ替えたり、Saasを積極的に利用することでこちらのアプローチに切り替えることも十分可能です。

例えば、弊社の場合社内向けにしか公開していないGitLabを何とかすればほぼ技術チームに関しては問題ありません。


### 費用
前述の問題に対する対策には、少なからず費用が掛かるものがあります。(ビジネスチャット、VPN、SaaS利用など)
が、リモートワークは働き方改革の一環として公的に推進されているので助成金制度が多くあります。

参考:https://shigoto-ba.com/archives/76

厚生労働省の補助だけでも最大3/4の費用助成が受けられますし、
東京に所在する企業の場合、都からの補助やオリンピック・パラリンピック関連の補助が得られる場合もあります。

## まとめ
* リモートワークには大きなメリットがある
* 必然的に発生する問題はあるものの、対応できないものではない。
実行ユーザーを指定してsshをした時にHost key verification failedが出たときの対処法

## 経緯

ansibleを書いている時に実行ユーザーに依存したフォルダ構造がある場合にansibleの実行ユーザーを明示的に指定したい時が稀にある。
例えば以下のようなtempalte moduleの対象ファイルが `templates`フォルダ以下にない場合。(ちゃんと各roles配下に置けよ、って話は置いておいて)

```yaml

- name: get the username running the deploy
  local_action: command whoami
  register: username_on_the_host

- name: Set zabbix proxy on elasticsearch.userparam.j2 to elasticsearch.userparam
  template:
    src: "/home/{{ username_on_the_host.stdout }}/hoge.sh.j2"
    dest: /dest/forlder/hoge.sh

```

## 問題

`sudo su -l user -c 'ansible-playbbok entry.yml'`
のようにコマンド実行したところ、以下のエラーで怒られる

```
Host key verification failed
```

公開キーの配置、秘密鍵の配置、秘密鍵のファイル権限も問題なさそうなことは確認。

もう少し詳しくデバッグするために直接sshコマンドを打ってデバッグする


```
sudo su -l user -c 'ssh -vvvvv -i key.prm user@ip'
```

するとpassphraseの処理で落ちていることが分かる 

```
debug1: read_passphrase: can't open /dev/tty: No such device or address
Host key verification failed.
```

## /dev/ttyって？

`tty`自体は標準入出力を制御する端末デバイスを表示するコマンド。
このエラーから分かることは鍵の検証処理中に標準入出力が存在しなくて落ちている、とうい状態。
が、このansible自体はインタラクティブに標準入出力を制御する想定でないので何かがおかしい。

## 普通にsshしてみる

普通にユーザーを変更してsshしてみる

```
sudo su user
ssh -i key.prm user@ip
```

するとはじめてのログイン時に求められる(known_hostsに登録されていない)おなじみの警告が出て、標準入力を求められていることが判明。

```
Are you sure you want to continue connecting (yes/no)? 
```

## 結論

どうやら `su -l user -c`でユーザーを指定した時に標準入力の処理に入った時点で実行ユーザーの仮想ターミナルが存在しなくて、処理が落ちるらしい。

なのでsshの場合は `ssh -o StrictHostKeyChecking=no -i key.prm user@ip`のようにオプションを付与する。

ansibleの場合は ~/.ansible.cfgに以下の設定を付けることで回避可能です

```cfg:~/.ansible.cfg
[defaults]
host_key_checking = False
```
n次の連立方程式などABC133 

# 概要
ABC133をA~Dまで、pythonでの正解例を見ながら解いていった。

#目標
1. まずは自分でどういう方針で行けばいいのかを考えてから、コードを読む（こういうことをしたいけど、どう描くんだろうと思ったときは、それを明示的に意識する）
2. コードを読んだ時に、こういう考え方をしたら、自分もこんなコードが書けるな。みたいな学びを書くようにする


# 実践
ABC133
自分でA~Dまでは友達と一緒にといたので、答え合わせの気持ちで読む。
A　min(n*a,b)を出力する。
自分のコードと同じ
B 
ポイント　自分が悩んだ点

- ２重配列をどう受け取るか
    - リストのリストで処理。（固定長で挿入、欠失がないので、配列の方が良さそうだけど、全体の計算時間には英kyほうがないからかな。）
    - `p = [list(map(int,input().split())) for _ in range(n)]`
- 整数かどうかの判定はどうする？
    - 僕は`int(n) - n == 0` で判定した
    - math内のceil (切り上げ）、floor(切り捨て）で判断する。
    - `ceil(n)==floor(n)`

C [l,r]内の２つの整数の掛け算で2019 の剰余が最小になるものをさがす。

- 単純に全てでループを回すとTLE(計算時間制限）に引っかかる
- 僕の方針
    - r-lが2019以上なら必ず[r,l]に2019の倍数があるので積の余りの最小値は0になる。
    - 2019未満の時には、ループを回す。4*10^6なので大丈夫そう。
    - ループの境界条件などで色々と時間がかかった。
- 方針は同じ
    - ループを回して、最小値を更新していく。
- tips: 2019は素数でないので、3*673 r-lが673以上なら必ず積が割切れる事は証明できる。計算量が1/9倍になる。

D n(n=奇数)の連立方程式を解く問題

- 僕の方針
    - 考えつくまでだいぶ時間がかかった。
    - なぜ偶数ではダメなんだろう？　
    - 偶数だと奇数番目、偶数番目のダムに入る総和が等しくなるという制約条件があるので、nこの変数にn-1個の式になり、式が１つ足りな苦なり、数学的に解けない。
    - `Ans[i]=sum[a]-2*(sum[a[j] if i-j %2 == 0 )で良い気がしていた。
    - が、それだと、i以外の全ての要素を消せてないことに気づいた。
    - また、計算量も毎回のnのloopを回るので間に合わない。o(n^2)
    - １つを求めたら、あとは、連立法廷sきから連鎖的に求められる。o(1)*n
- 方針は最後の僕のものと同じ。」
    - 配列をspace 区切りで出力するときに、`print(*Ans)`で可能なのはすごい。


# 感想
100分ぐらいかかったので、想定より時間がかかった。
主な原因はD問題で問題で問われていないことを考えたり、そもそも方針が思いつかなかって悩んでいたこと。
10分経って進捗が（新たな方針が立つ気配がなかったら）解説を見るべき。

あとは、以外に、解説を見ながらならd問題でも難しくは思わなかった。
今回が簡単だったのもあるかもだけど、考察力に比べて実装力が圧倒的に足りていないのが推測できる。
Material ui のlabelの色を変えたい！buttonのlabelの色を変えたい！という時の小ワザ

material ui のFormControlLabelの色をデフォルトから別の色に変えたいという時や、
MuiButtonのlabelの色を変えたいという時があるかと思うんですが、
そういう場合に使えるワザを紹介します。

環境：
　react@16.8.6
　@material-ui/core@4.1.1

#FormControlLabelのlabelの色を変える

material ui のデフォルトはこうです
<img width="122" alt="スクリーンショット 2019-07-10 10.34.05.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/447783/b18585e0-e5a0-0dda-4212-5f37594013a3.png">

```javascript:デフォルトのコード

<FormControlLabel
        control={
          <Checkbox checked={state.checkedA} onChange={handleChange('checkedA')} value="checkedA" />
        }
        label="Secondary"
      />
```
<br>

Secondaryという文字を青に変えたいとき

```javascript
<FormControlLabel
        control={
          <Checkbox checked={state.checkedA} onChange={handleChange('checkedA')} value="checkedA" />
        }
        label={
          <span style={{ color: "blue" }}>
            Secondary
          </span>
        }
      />
```

label= に中括弧つけて、Secondaryをspanで挟んで色指定してあげれば、

<img width="119" alt="スクリーンショット 2019-07-10 10.42.55.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/447783/0531607b-d9b8-0576-e5e1-f50067c8ee67.png">

色が青に変わりました！

#MuiButtonのlabelの色を変えたい！
ボタンを実装して、ボタン自体の色は変えられたけど、どうしてもlabelの色が変わんない・・・
こんなときないですか？

<img width="88" alt="スクリーンショット 2019-07-10 10.53.06.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/447783/e698c294-6d6b-b6be-9b1f-e36045545bc1.png">
このボタンのlabelをどうしても白にしたい！

##まずはmaterial uiのファイルを作る


theme.jsを作り、createMuiThemeをimportする

アプリのデベロッパーツールでボタンのlabelのところをクリックすると
下図のようにでるので、theme.jsでoverridesの中に書いていく
<img width="184" alt="スクリーンショット 2019-07-10 18.13.37.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/447783/fa661e2b-e6c3-f064-d879-b51411fd7848.png">



```javascript:theme.js
import { createMuiTheme } from "@material-ui/core/styles";

export const theme = createMuiTheme({
overrides: {
    MuiButton: {
      label: {
        color: "white",
      },
    },
  },
});
```
↓白に変わりました！

<img width="88" alt="スクリーンショット 2019-07-10 11.58.44.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/447783/14f0d33e-7a8f-058a-852b-5af4f00ff2de.png">

--------
このやり方はスタイルを無理やり変えてる感あるので、
もっといいやり方があれば教えてください。
Raspberry PiのUSBにFT232H接続する  ～ドライバのインストール～

#概要
Raspberry PiをUSBホストとしてFT232Hを使用するための初期設定行いました。
この記事はその備忘録です。

#環境
母艦：Windows10 64bit版
デバイス：Raspberry Pi 3B
OS；Rasbian stretch
変換基板：[Adafruit FT232H Breakout - General Purpose USB to GPIO+SPI+I2C](https://www.adafruit.com/product/2264)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183282/826b9cc6-0f45-da4a-7df8-e826b21b7f04.png)

#設定手順
###１．ドライバをインストール
FTDIのUSBドライバをRaspberry Piへインストールします。
FTDIのドライバダウンロードサイトを見ると、Raspberry Pi用のドライバが用意されているようです。
[FTDi D2xxxドライバ](https://www.ftdichip.com/Drivers/D2XX.htm)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183282/6819a133-1ad8-125b-4e2e-73fe54acd77d.png)

今回はサポート版の「libftd2xx-arm-v6-hf-1.4.8.gz」を使用します。
母艦にダウンロード・解凍します。

Raspberry Piに移り、作業用ディレクトリを作成します。

```
mkdir driver
cd driver
```

解凍してできたフォルダの中身をRaspberry Piの作業ディレクトリへコピーします。
今回はsftpクライアントツール「**WinSCP**」でRaspberry Piの”driver”フォルダにコピーしました
コピーするものは ↓ パスの中身全て（７点）です。

```
libftd2xx-arm-v6-hf-1.4.8\release\
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183282/be26b1cc-a5f5-23f9-61c4-a82975a857c3.png)

コピーできたらインストールを行っていきます。

次のコマンドでインストールします。

```
cd build
sudo cp libftd2xx.* /usr/lib
sudo chmod 0755 /usr/lib/libftd2xx.so.1.4.8
sudo ln -sf /usr/lib/libftd2xx.so.1.4.8 /usr/lib/libftd2xx.so
```

※ドライバのバージョンが異なる場合は、何のバージョンをインストールしようとしているか、次のコマンドで確認できます。
”**libftd2xx.so.~.~.~** ”ファイルのバージョンです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183282/76dd6570-9efe-1f5c-0ded-7aac99f1187c.png)

以上でセットアップ完了です。

#動作確認
次のコマンドでサンプルコードをビルドし、実行します。

```
cd ../examples
make -B
cd EEPROM/read
sudo ./read
```

実行した時にポートのオープンに失敗するようです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183282/8c5a2289-8288-6e8c-5a3a-156e7891ea41.png)

別のドライバが読み込まれているようなので、ドライバをアンロードします。
次のコマンドで読み込まれているドライバを確認できます。

```
sudo lsmod |grep ftdi
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183282/fa95cf5c-2cfc-3df4-997f-9e6070bea60a.png)

**ftdi_sio**と**usbserial**を次のコマンドでアンロードします。

```
sudo rmmod ftdi_sio
sudo rmmod usbserial
```

再度、サンプルコードを実行すると問題が出なくなりました。
FT232HのEEPROMを読み込んだ結果が表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183282/ff3c1af4-b636-5c79-babc-8b677898470c.png)

以上です。


#参考
[Raspberry PiでFTDIデバイスドライバをインストールする](https://ivis-mynikki.blogspot.com/2015/02/raspberry-piftdi.html)
[D2xx Readme](https://www.ftdichip.com/Drivers/D2XX/Linux/ReadMe-linux.txt)
[D2xx Video Install Guide](https://www.youtube.com/watch?v=jynlynjOOek&feature=youtu.be)
[MPSSEコマンドリスト](https://www.ftdichip.com/Support/Documents/AppNotes/AN_108_Command_Processor_for_MPSSE_and_MCU_Host_Bus_Emulation_Modes.pdf)
[MPSSE Example](https://www.ftdichip.com/Support/Documents/AppNotes/AN_180_FT232H%20MPSSE%20Example%20-%20USB%20Current%20Meter%20using%20the%20SPI%20interface.pdf)
AtCoder Beginner Contest 115 A  Christmas Eve Eve Eve

pythonでは競プロで順位をあげることは難しいらしいので、最近C++を始めた。
まずは基本問題から。

[Christmas Eve Eve Eve](https://atcoder.jp/contests/abc115/tasks/abc115_a?lang=ja)



```c++
#include <iostream>
 
using namespace std;

int main(){
    int d;
    int i;
    cin  >> d;
    printf("Christmas");
    for(i=0; i<25-d; i++){
      printf(" eve");
    }
    }
```
Jetson Nano で簡単な画像認識・骨格姿勢検知を動かす基本設定色々デモ

# はじめに
株式会社ProsCons (https://proscons.co.jp/) のエンジニアチームです。

弊社では、エッジAIデバイスとして注目されているJetson Nanoを用いて製造業等向けに提供しております。本体価格1万円強と廉価かつ手のひらサイズという極小スケールのデバイスでディープラーニングをも動作させることが可能です。
今回はこのJetson Nanoを容易に環境設定する方法と基本的な画像認識・骨格姿勢検知を動作させる方法を公開いたします。


### 参考動画URL
教師なし異常検知：https://www.youtube.com/watch?v=-NMPNE5-sco
骨格姿勢検知：https://www.youtube.com/watch?v=IVLhe_cjYwE

# 手順
弊社githubより、以下のリポジトリをcloneします。
https://github.com/ProsConsInc/jetson-nano

00〜13番までの手順を順番に踏めば、
一通りJetson Nanoが動作する感動を味わえるはずです！

始めに補足と注意事項を挙げておきます。
補足：shellスクリプトは失敗したらエラーで落ちるように設定しております。
　　　他に不具合等発生しましたら、想定外の動作となりますので、
　　　弊社githubへ issue を上げて頂けますと幸いです。
注意事項１：電源はmicro USBでは無く、5V 4Aの電源を使用するようにして下さい。
　　　　　　そうでないと、電源供給が不十分になり意図しない電源OFFが起きます。
注意事項２：マイクロSDカードは16GBが最小の構成になりますが、最低でも32GBは欲しいです(the larger the better)。

●以下shellスクリプト概要
## 00_init.sh
　gitリポジトリのsubmoduleをcloneします。
　thirdpartyディレクトリ配下にダウンロードされます。

　cmakeのみversionを指定しております。これは、現時点で動作確認が取れているものに固定したいが為です(他のsubmoduleも本来は固定すべきかもしれません)。

## 01_run_power_up.sh
　Jetson Nanoは初めは5Wモードで動作しています。

　ですので、10Wで動作するように変更し、ハイパフォーマンスで動作するようにします(Jetson Nanoは 5W/10W をコマンドで簡単に切り替える事が出来る仕様です)。

## 02_install_swapfile_and_reboot.sh
　Jetson Nanoは搭載メモリが LPDDR4 4GBと貧弱な為、スワップ領域を作ってあげる必要があります。再起動しないと有効にならないようですので、スクリプト内でrebootするようにしてあります。

## 03_install_deps_for_openpose.sh
　Jetson Nano向けに色々と依存パッケージを入れてくれて便利なので、openposeの組み込みスクリプトを採用しました。
　お茶でも飲みながら、終わるのを待ちます。

## 04_test_pi_camera.sh
　Raspberry Pi カメラモジュール v2を繋いであれば、画面にカメラの画像が映るはずです。ここでカメラのエラーが起きる場合は、カメラの接触の不具合を疑う、若しくは電源ケーブルを挿し直す(電源OFF→ON)と映るようになるケースがあります。
　Ctrl + c で終了します。

## 05_install_cmake.sh
　cmakeをソースからインストールします。ビルドする際にPPAからインストールしたcmakeだとバージョンが低いと怒られるアプリケーションが存在する為です。
　お茶受けでも頂きながら、終わるのを待ちます。

## 06_install_tensorflow.sh
　公式のJetson Nano対応のTensorFlow v1.13.1をインストールします。
　テレビでも見ながら、終わるのを待ちます。

## 07_install_tf_pose.sh
　tf-pose-estimationをインストールします。これは骨格・姿勢検知を行うものです。
　動画サイトでも見ながら、終わるのを待ちます。

## 08_prepare_for_webcam_and_reboot.sh
　カメラの映像をストリームとして受け取る為に必要なので、インストールするものです。ここで機能を有効にする為、再起動させています。

## 09_build_darknet.sh
　darknetをビルドします。主にGPUの力を引き出す為にpatchを当てたりもしています。
　まとめサイトでも見ながら、終わるのを待ちます。

## 10_run_darknet.sh
　darknetでYOLO v3 Tinyモデルを利用して、Object Detectionを行います。
　15FPS 前後になるはずです。Raspberry Pi カメラモジュール v2のフレームレートは21FPS なので、ほぼ性能を出し切っていると言えると思います。
　Ctrl + c で終了します。

## 11_build_openpose.sh
　お試しとして、本家のopenposeをビルドします。
　お酒でも飲みながら、終わるのを待ちます。

## 12_run_openpose.sh
　サンプルの動画に対して、openposeによる骨格・姿勢検知を行います。手持ちのMacbookではレンダリングに 66 分ほど掛かりました。

　Jetson Nanoでは7、8分で処理が完了し、動画が生成されるはずです。
　軽く運動でもしながら、終わるのを待ちます。

## 13_run_tf_pose.sh
　tf-pose-estimationを用いて、骨格・姿勢検知を行います。10FPS前後のフレームレートとなることが期待されます。Escで終了します。
 

　※終了する際は必ず Escキー を押して終了させるようにして下さい。理由はTensorFlowがリソースを掴んだ状態になり、カメラモジュールが検出出来なくなったり、メモリ不足に陥ったり、と不具合が起きます。

# おわりに
お疲れ様でした。
以上で、このリポジトリの説明を終了します。

なお、この環境を整備する際に多くの先人の知恵にお世話になりました。この場を借りて御礼申し上げます。
Node.jsでSlack連携される問い合わせフォーム作ってみた

# はじめに

今回Node.jsの勉強の一環で、問い合わせフォームを作成しましたのでその流れをまとめます。
また、問い合わせされたらメールが飛ぶのではなく、Slackに連携されるようにしました。

<img width="270" alt="入力画面.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/240803/a9f87c9f-be3a-a78d-110e-e8916ca2a58a.png">
↓
<img width="1039" alt="Slack_-_えすぷりてっく_Tokyo.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/240803/05359dff-b975-217f-d426-62010fc0e46a.png">


# 環境構築

環境構築は、様々な記事を参考に、下記の流れで行いました。

（Xcodeをインストール）

1.node.js管理ツール（nvs）をインストール

2.nvsを使ってnode.jsをインストール

3.npmをインストール
>「便利なパッケージ管理ツール！npmとは【初心者向け】」
>https://techacademy.jp/magazine/16105

↑こんな感じの流れで、node.jsがローカルで使えるようになりました。

そして、今回は**node.jsのフレームワーク「Express」を使います。**

```
npm install express
```

また、「ejs」というテンプレートエンジンを使います。

```
express -e myapp
```
(-e:ejs、myapp:任意の名前)



# 実装

全体の流れとして、入力画面　→　確認画面　→　完了画面　→　Slackに送信　という流れになります。

そのため、入力画面、確認画面、完了画面の3つのビューを作成する必要があります。

view
┗ ━ index.ejs
┗ ━ confirm.ejs
┗ ━ result.ejs


## 入力画面
まず、入力画面では、formタグを記述します。
`action="/confirm"`  と書くことで、formがsubmitされたらconfirm画面に遷移するようにします。

```html:index.ejs
<form action="/confirm" method="POST" name="contact">
  
  <input type="text" name="name" value="" required>
  <!-- 必要なinputタグなどを記述する -->
　<input type="submit" name="submit" value="入力内容の確認">
  
</form>
```

## 確認画面

そして、入力内容の確認ボタンを押されたら（submitされたら）、/confirm画面に遷移されます。
その時の動きを `routes/index.js` に描いてあげます。

```javascript:index.js
/* POST : /confirm */
router.post('/confirm', function(req, res){
  
  res.render('./confirm.ejs', { 
    name: req.body.name
  });
  
});
```

**`router.post('/confirm', function(req, res){`**
→/confirm にPOSTされてきたら実行される（入力画面のフォームがsubmitされたら）

**`res.render('./confirm.ejs', { `**
→views/confirm.ejs　を返す、表示する

**`name: req.body.name`**
confirm.ejs に変数を渡す
nameという名前の変数に「req.body.name」（formの`<input type="text" name="name">`に入力された値）を入れて渡す
なので、受け取る時は`<%= name %>`

```html:confirm.ejs
<form action="/result" method="POST" name="contact">
　<%= name %>
　<input type="submit" name="submit" value="送信">
</form>
```

`<%= name %>`と書けば、入力画面で入力された値が表示されます。

## 完了画面

そして、入力内容の確認ボタンを押されたら（submitされたら）、/result画面に遷移されます。
確認画面の時と同じく、その時の動きを `routes/index.js` に描いてあげます。

```javascript:index.js

router.post('/result', function(req, res){
  
  var request = require("request")
  
  // slack連携
  request.post('https://slack.com/api/chat.postMessage', {
      form: {
          token: 'トークンを書く',　// slackのトークン
          channel: 'test', // slackのチャンネル名
          username: '問い合わせ',　// slackに投稿される名前
          text: // slackに投稿される内容
          '```名前：' + formdata.name + '```'
      }
  }, function (error, response, body) {
      console.log(error)
  })
  
  res.render('./result.ejs', { title: '完了画面' });
  
});
```

ちなみに、slackのトークン発行は、[こちらから](https://api.slack.com/custom-integrations/legacy-tokens)ログインして create taken で発行できます。

また、requestモジュールをインストールする必要があります。

```
npm install request
```

>Slack連携のテストするところ
>https://api.slack.com/methods/chat.postMessage


# 完成！

こんな感じの流れで、問い合わせフォームが作成できました。
何かの参考になれば幸いです。
ちなみにSlackのトークンは環境変数に入れて管理するなどして、GithubやHerokuなどにあげないように気をつけましょう！

>参考：Node.jsでの環境変数の使い方：モジュール「dotenv」
>https://numb86-tech.hatenablog.com/entry/2017/01/24/000940
RFC7009 OAuth 2.0 Token Revocation を実装するときに注意すべきこと

#目次
1. はじめに -RFC7009について
2. MUSTとSHOULDなど整理
3. tokenについて
4. OAuth保護について

## 1. はじめに　-RFC7009について
RFC7009 OAuth 2.0 Token Revocation
英語版：https://tools.ietf.org/html/rfc7009
日本語訳：https://openid-foundation-japan.github.io/rfc7009.ja.html

このRFCには簡単に言うと、

- アクセストークン、リフレッシュトークンの有効期間内でそのトークンが不要になった場合に、トークンを失効できる機能を提供しましょう。
- HTTPリクエストエンティティボディにパラメーターtokenで失効したいトークンを入れましょう。

といったことが記載されています

以前、トークン失効の機能をAPIとして実装しようとしていてをパッと読んで「簡単そうじゃん！」と思っていました。
いざ作成しようとした時にRFCをじっくり読み返すと、RFCの意図していることが見えてきてその注意点について記載いたします。詳細については上記リンクからRFCを読んでください。


## 2. ポイントとなるMUSTとSHOULDなど整理
一番大事なところだけ整理してまとめてみました。

| 内容|Requirement Levels|
|:---|:-:|
| リフレッシュトークンを失効させる機能 |  MUST  |   
| アクセストークンを失効させる機能  |  SHOULD  |  
| token       |  MUST        |           
| token_type_hint        | OPTIONAL        |            

## 3. tokenについて
tokenは、HTTPリクエストエンティティボディに必須で入るパラメーターです。
値は失効させたいアクセストークン値 or リフレッシュトークン値が入ります。

######①リフレッシュトークン値が入っている場合
同じ認可元のアクセストークン全てを失効させるべきである。(SHOULD)
※アクセストークンを失効させる機能を実装させない場合、RFCの6.Security Considerationsにあるようにセキュリティーに気をつけなければなりません。

######②アクセストークン値が入っている場合
同じ認可元のすべてのリフレッシュトークンを失効させてもよい。（MAY）

######③リフレッシュトークンでもアクセストークンでも当てはまらない値が入っている or 無効なリフレッシュトークン、アクセストークン が入っている場合
失効させるトークンはないが、レスポンスコードは200を返却する。
これは、クライアント側が失効させたいトークンがすでに使えない状態になっているので問題ないと言うことと理解しました。なのでエラーレスポンスではなく200で返却です。


## 4. OAuth保護について
当然のようにセキュリティー的に、この機能もOAuth保護（Authorization: Bearer <アクセストークン>）をするだろう。そうしなければ、他のAPIでOAuth保護で使っているトークンとか晒されることになるのでは？と思っていました。

結論からいうと
「OAuth保護しない」が正しいです。
RFCのサンプルでもBasic認証をしているようです。


なぜか考えたのですが、以下の考えにたどり着きました。
>**OAuth保護ありでトークンの失効をする場合、アクセストークンの有効期限が切れていてリフレッシュトークンを失効させるが実施できない。
アクセストークンのは基本的に寿命短としているため、リフレッシュトークン(寿命長め)を元にトークン失効することが考えられるがOAuth保護ありではトークン失効をする前に認証で弾かれてしまう。
トークン失効をするために再度アクセストークンの再発行することはクライアントにとって合理的ではない。**

その代わりのセキュリティー保護としては、Basic認証やクライアントID、クライアントシークレットで守るしかないと思います。