OmniAICreator/Qiita-1.07M huggingface dataset:
Ruby On Rails のValidation メッセージをカスタマイズする

## 背景

[Railsの多言語化にはi18n](https://railsguides.jp/i18n.html)がよく利用されます。

通常下記のように設定をしますよね

```rb:config/locales/*.yml
ja:
  activemodel:
    # モデル名
    models:
      user: "ユーザー"
      attributes:
        # モデル毎の属性名
        user:
          name: "名前"
    # 共通の属性名
    attributes:
      gender: "性別"
  # バリデーションエラー
  errors:
    # テンプレート
    format: "%{attribute}%{message}"
    # エラー毎のメッセージ
    messages:
      blank: "を入力してください"
en:
  # 同じ構造なので略
```

```rb:User.rb
class User < ApplicationRecord
  validates :name, presence: true
end
```

この時、フォームで`name`に空白のままsubmitを実行すると、`名前を入力してください`と表示されます。

ですが、例えば`name`が空白の時に`名前はフルネームで入力してください`とか、`名前は姓・名で分けてください`と表示したかった場合どうしますか？

`*.yml`の`models.attributes.user.name`と`errors.messages.blank`を書き換える力技もありますが、これでは保守性0です。

美しくありません。また、

```rb:User.rb
class User < ApplicationRecord
  validates :name, presence: { message: '名前はフルネームで入力してください' }
end
```

上記も悪くないけど、多言語化に対応できていない。

そこで、`i18n`を用いた、メッセージのカスタマイズ方法を紹介いたします。

## 解決策

`Proc`を組み合わせます。`lambda`でも可能です。

```rb:config/locales/*.yml
ja:
  activemodel:
    # 同じ構造なので略
  # バリデーションエラー
  errors:
    messages:
      blank: "を入力してください"
    models:
      user:
        fullname_blank: "名前はフルネームで入力してください"
en:
  # 同じ構造なので略
```

```rb:User.rb
class User < ApplicationRecord
  validates :name, presence: {
    message: -> (rec, data) {
      I18n.t('activemodel.errors.models.user.fullname_blank')
    }
  }
end
```

これを実行すると、うまく多言語化されると思います。

ちなみに、`Proc`を使わないとうまく多言語化されないので気をつけてください。下記が悪い例です。


```rb:User.rb
class User < ApplicationRecord
  validates :name, presence: {
    message: I18n.t('activemodel.errors.models.user.fullname_blank')
  }
end
```

### 参考

- [Active Record Validations](https://guides.rubyonrails.org/active_record_validations.html#message)
- [railsのバリデーションメッセージの多言語化とgettext](https://qiita.com/MasamotoMiyata/items/f60656ffd8bc4e19d75e)
Enumを使って足し算をする。

###はじめに
Unityをいじり始めてから数ヶ月になるが、Enumを使う機会に恵まれなかった。しかし最近になって、扱う変数が多くなってきたので、列挙型を扱えるようにする。未だにEnumを満足に扱えないのは成長が遅いかもしれない。

###作るもの
簡単な四則演算と列挙定数をText.UIで表示する。

###Enumとは

列挙型の事で、列挙の意味は並びたてる。よって定数を並びたてることである。基本の形は以下の通りになる

~~~C#
装飾子  enum  名前
{
    A,
    B,
    C,
    D,
}
~~~

ABCDは列挙定数を呼ばれるものである。もちろんABCD以外の名前も列挙定数にできる。

###Unityの設定

TextUIを2つ配置(名前はString Calculationにした)。
CreateEmpty等どんなオブジェクトでもいいので、ヒエラキー上に用意しておく（自分はCubeを使った）。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307841/583bddda-770f-6b00-87f4-533843b3147a.png)

###スクリプトを組む

スクリプト名は何でもいいので生成して、以下のスクリプトを入力

~~~C#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI; //これがないとTextUIが使えないので必ず入力する。

public class tamesi : MonoBehaviour {

    //テキスト2つ分のSerializeFieldを用意
    [SerializeField] Text Cal;
    [SerializeField] Text Str;

    // 列挙定数を生成。
    public enum Tas
    {
        ADD,
        SUB,
        MUL,
        DIV,
    }
    public Tas Cul;
    

	// Use this for initialization
	void Start () {

        //四則演算計算用の数字を設定。
        int a = 100;
        int b = 50;

        //Inspectorで選んだものがどれかで四則演算の種類が決定。
        if(Cul == Tas.ADD)
        {
            Cal.text = (a + b).ToString();
        }

        else if (Cul == Tas.SUB)
        {
            Cal.text = (a - b).ToString();
        }

        else if (Cul == Tas.MUL)
        {
            Cal.text = (a * b).ToString();
        }

        else
        {
            Cal.text = (a / b).ToString();
        }

        //列挙定数をテキスト表示に。
        Str.text = Cul.ToString();
    }
}
~~~

###　アタッチ・ドラッグ&ドロップ
・入力したスクリプトをオブジェクトにアタッチ。
・ヒエラキーにあるCalculationとStringをスクリプトにドラッグ&ドロップ。
・Culは列挙型になっているので、列強定数として列挙したものを選べる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307841/76a34066-6572-1cb2-2f29-86d41819783a.png)


###実行結果（今回列挙定数はADDを使用）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307841/46d9ac3b-f71a-0348-96e0-326680a348c3.png)


###おわりに
基本中の基本はなんとか理解できたが、使わないのと忘れる（経験済み）ので適度に使っていきます。
Goのmath/randとcrypto/rand

Goの乱数生成に関する標準パッケージには`math/rand`と`crypto/rand`の2つがあります。それぞれ`math/rand`は弱い乱数で`crypto/rand`は強い乱数なのですが、強い乱数のほうが必ずしも良いというわけではなく、特性やパフォーマンスの違いでユースケースが分かれています。

## math/rand

https://golang.org/pkg/math/rand/

> math/randパッケージは疑似乱数生成器を実装しています。
>
> 乱数はソースによって生成されます。`Float64()` や `Int()` などのトップレベル関数は、プログラムが実行されるたび、デフォルトの共有ソースを使用し値を生成します。
>
> 実行する毎に異なる動作が必要なら`Seed()`関数を利用してデフォルトソースを初期化します。
>
> デフォルトソースは複数のゴルーチンから並列使用に対して安全です。しかし`NewSource()`から作られたものはそうではありません。
>
> セキュリティに適した乱数については`crypto/rand`を参照してください。


通常乱数を使用する場合は `math/rand`を利用します。多くの場合`time.Now().UnixNano()`を乱数のシード値にすることで、実行するたびに異なる数を得ることができます。

```go:example
package main

import (
	"fmt"
	"time"
	"math/rand"
)

//0から99のランダムな数値を表示する
func main() {
	rand.Seed(time.Now().UnixNano())
	fmt.Println(rand.Intn(100))
}
```

様々な型で乱数を返す関数が用意されており、且つ高速に安定した乱数を得ることができます。

注意点として、トップレベル関数はgoroutineセーフですが、`NewSource()`で生成したソースはgoroutineセーフではありません。ただし、トップレベル関数がgotoutineセーフなのは内部でロックを取っているだけなので、乱数を取得する際に同様にロックを取ればgroutineセーフになります。



`math/rand`の擬似乱数生成器ではいくつかの数値をもとに、呼び出すたびに組み合わせを変えることで適度に分散した乱数を生成します。（ 参考: https://golang.org/src/math/rand/rng.go )元になる数値は一定で、シード値に対応した値を返すため乱数を再現することが可能です。このような無作為な数列になるが、予測が可能な乱数を弱い乱数と呼びます。

ゲームのダイスなどは弱い乱数で十分ですが、暗号化やセッションID生成で利用する場合は脆弱性になり得ます。例えば、セッションIDを`math/rand`の乱数をもとに文字列生成するときに `time.Now().UnixNano()` がシード値だった場合、セッションIDを発行した時間帯が判れば総当りでセッションIDを特定できるかもしれません。

`math/rand`は十分に分散した数列を高速に得られますが、予測可能であるため暗号論的に必ずしも安全ではありません。



## crypto/rand

https://golang.org/pkg/crypto/rand/

> crypto/randパッケージは暗号学的に安全な乱数生成器を実装しています。

暗号学的に安全な疑似乱数生成器はCSPRNG(cryptographically secure pseudo random number generator)とも呼ばれます。

`math/rand`とは異なり、`io.Reader`インターフェイスを利用してランダムなバイト列を取り出すことができます。

```go:example
package main

import (
	"crypto/rand"
	"fmt"
	"math/big"
)

//0から99のランダムな数値を表示する
func main() {
	n, err := rand.Int(rand.Reader, big.NewInt(100))
	if err != nil {
		panic(err)
	}
	fmt.Println(n)
}
```

`rand.Reader`の中身は環境によって異なります。linuxの場合は`/dev/urandom`を利用し、WindowsであればCryptoAPIを利用します。

`crypto/rand`で利用されるものはすべてCSPRNGです。linuxではデバイスドライバなどから得られた環境ノイズをシードとして乱数を生成します。そのため、プログラムからシード値を与えることはありません。

ただし、/dev/urandomは一般的に重い処理であるため、`math/rand`に比べると環境によってはパフォーマンスが大きく落ちることがあります。


## まとめ
抽選や無作為サンプリングなど、再現性があっても十分にランダム性のある数列が得られれば問題ない場合は`math/rand`を利用します。

ランダムかつ暗号的な安全さ(予測困難性）が求められる場合は`crypto/rand`を利用するのが望ましいです。例えば「パスワード・セッションIDの生成」や「暗号化の際に必要なランダムなバイト列の生成」などが挙げられます。
【Linux】awkコマンドで0埋め（ゼロ埋め）で表示する方法

###ログファイルの日付表記が以下のようになっていると、見づらいかと思います。
```test.log
2018/8/5 00:03:10 [LEVEL0] 1234567890 123450 KEY000 aaa bbb cccccc:555 dddddd:000
2018/9/15 10:04:11 [LEVEL0] 1234567891 123451 KEY000 aaa bbb cccccc:666 dddddd:111
2018/10/5 21:31:05 [LEVEL0] 1234567892 123452 KEY0000 aaa bbb cccccc:777 dddddd:222
2018/11/21 08:13:40 [LEVEL0] 1234567893 123453 KEY0000 aaa bbb cccccc:888 dddddd:333
2019/1/2 22:03:22 [LEVEL0] 1234567894 123454 KEY0000 aaa bbb cccccc:999 dddddd:444
```
###こんな時、awkコマンドで日付フォーマットをyyyy/mm/ddに変換して表示させると見やすくなります。
```test.log
[test@localhost ~]$ cat test.log | awk -F '[ /]' '{printf("%4d/%02d/%02d %08s %10s %10s %6s %7s %3s %3s %10s %10s\n",$1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12)}'
2018/08/05 00:03:10   [LEVEL0] 1234567890 123450  KEY000 aaa bbb cccccc:555 dddddd:000
2018/09/15 10:04:11   [LEVEL0] 1234567891 123451  KEY000 aaa bbb cccccc:666 dddddd:111
2018/10/05 21:31:05   [LEVEL0] 1234567892 123452 KEY0000 aaa bbb cccccc:777 dddddd:222
2018/11/21 08:13:40   [LEVEL0] 1234567893 123453 KEY0000 aaa bbb cccccc:888 dddddd:333
2019/01/02 22:03:22   [LEVEL0] 1234567894 123454 KEY0000 aaa bbb cccccc:999 dddddd:444
```
###解説
セパレータに半角スペースと/を指定します。

```
awk -F '[ /]'
```

そしてprintfの指定を%02dにします。

```
%4d/%02d/%02d
```

%02sでは上手く行きませんので、ご注意が必要です。

```
%4s%02s%02s
```
HorizontalScrollViewのスクロール中にSwipeRefreshLayoutのリフレッシュが干渉する問題

## 問題

リストを更新するUIとしてSwipeRefreshLayoutを利用します
このリスト内のセルが一部横スクロールできる場合、この横スクロール中に少しでも指が縦にぶれたら、リフレッシュがでてきて横スクロールを妨害してしまいます

![device-2019-08-05-230449.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149856/67db2229-fc33-4ab6-f7a2-cdb3d27ddd83.png)

## 解決

SwipeRefreshLayout#setOnChildScrollUpCallbackを利用して、リフレッシュを制御することで実現できます
またListView#canScrollListが合わせて必要になるので注意してください

[GitHubサンプル][1]

```kotlin
private var isDragging = false

swipeRefreshLayout.setOnChildScrollUpCallback { parent, child ->
    isDragging || listView.canScrollList(-1)
}

horizontalScrollView.setOnTouchListener { v, event ->
    when (event?.action) {
        MotionEvent.ACTION_DOWN, MotionEvent.ACTION_MOVE -> {
            isDragging = true
        }
        MotionEvent.ACTION_UP -> {
            isDragging = false
        }
    }
    false
}
```

[1]:https://github.com/mn-D128/PullToRefreshHorizontalScrollSample
退屈なことはPythonにやらせよう　勉強記録 【正規表現　()のパターンマッチ】

###パターンマッチ機能
●丸かっこを用いたグルーピング
電話番号
(\d\d\d)-(\d\d\d-\d\d\d\d)

グループ1:(\d\d\d)
グループ2:(\d\d\d-\d\d\d\d)

```
import re
phone_num_regex =re.compile(r'(\d\d\d)-(\d\d\d-\d\d\d\d)')
mo = phone_num_regex.search('電話番号は415-555-4242です')
mo = group(1) 
mo = group(2)
mo = group(0)
mo = group()
mo = groups()

```
解答
mo =group(1)
'415'

mo= group(2)
'555-4242'

mo = group(0)
'415-555-4242'

mo = group()
'415-555-4242'

mo = groups()
('415', '555-4242')

group(0),group()ではマッチした文字列全体を返す。
groups()はすべてのグループを一度に取得したいとき
ApexTriggerを作る際に気をつけること①

#Triggerの発火タイミングについて

ApexTriggerでは発火のタイミングが下記の種類になります。
・before　レコードの処理前
・after　レコードの処理後

そしてそれぞれに
・insert
・update
・delete
・undelete（afterのみ）

が加えられて計7通りのタイミングがあります。

書き方は下記の通りです。

```ruby:sampleTrigger
trigger トリガ名 on オブジェクト名 
(before insert, before update, before delete
 after insert, after update, after delete, after undelete) {
        //処理を記入
}
```
処理するタイミングを（）内に記入しておかないと発火の取得ができません。

#渡されるレコードの種類を理解しておく

トリガの発火のきっかけになったレコードの渡ってくる方法としては
1.List型
2.Map型
の二種類になります。

書き方としては以下になります。

```ruby:sampleTrigger
    if ( Trigger.isBefore && Trigger.isInsert) {
        system.debug(Trigger.new);
        system.debug(Trigger.old);
        system.debug(Trigger.newMap);
        system.debug(Trigger.oldMap);
    }
```

| List             |      Map          | 
|:-----------------|------------------:|
|new               |              newMap |
| old              |            oldMap |

Trigger.の後にそれぞれを指定すると取れます。

それぞれの入ってくる値も違いますので、デバックしてしっかり中身を確認してから、
作成していきましょう。
【Linux】awkコマンドで右揃えで表示する方法

###以下のログファイルをviなどのテキストエディタで開きます。
```test.log
2018/8/5 00:03:10 [LEVEL0] 1234567890 123450 KEY000 aaa bbb cccccc:555 dddddd:000
2018/9/15 10:04:11 [LEVEL0] 1234567891 123451 KEY000 aaa bbb cccccc:666 dddddd:111
2018/10/5 21:31:05 [LEVEL0] 1234567892 123452 KEY0000 aaa bbb cccccc:777 dddddd:222
2018/11/21 08:13:40 [LEVEL0] 1234567893 123453 KEY0000 aaa bbb cccccc:888 dddddd:333
2019/1/2 22:03:22 [LEVEL0] 1234567894 123454 KEY0000 aaa bbb cccccc:999 dddddd:444
```
###カラムの文字数が異なり、イマイチ見づらい状況です。awkを使用して、カラムを右揃えで表示します。
```test.log
[test@localhost ~]$ cat test.log | awk '{printf("%10s %10s %10s %10s %10s\n",$1,$4,$5,$9,$10)}'
  2018/8/5 1234567890     123450 cccccc:555 dddddd:000
 2018/9/15 1234567891     123451 cccccc:666 dddddd:111
 2018/10/5 1234567892     123452 cccccc:777 dddddd:222
2018/11/21 1234567893     123453 cccccc:888 dddddd:333
  2019/1/2 1234567894     123454 cccccc:999 dddddd:444
```
実証済－最も簡単なSDカード復元する方法と高復旧率で復元するコツ

SDカードからうっかり削除した写真、動画などのデータを高復元率で復元する方法を紹介します。
復元ソフトを使えば、初心者も自力で簡単にSDカードのデータを復元できます。
<div id="toc_container" class="no_bullets">
<p class="toc_title"><strong>目次</strong></p>
<ul class="toc_list">
    <li><a href="#sd-0"><strong>1．復元ソフトを使って自力で復元する方法</strong></a></li>
    <li><a href="#sd-1"><strong>2．復旧率を高めるコツ</strong></a></li>
    <li><a href="#sd-2"><strong>3．業者に頼む場合の失敗しない業者の選び方</strong></a></li>
</ul>
</div>
<h2><span id="sd-0">1．復元ソフトを使って自力でSDカードを復元する方法</span></h2>
ここで「Best SDcard&USB Disk Reovery」というSDカード復元ソフトを使用します。
誤消去、フォーマットなどほどんどの論理障害の復元に対応します。90%以上のデータ復旧率を実現したそうです。試した結果、SDカードから削除した写真、動画などのデータのほとんどを復元できました。

STEP1：復旧ソフトをダウンロード・インストール
まずは[<strong>Best SDcard&USB Disk Reovery</strong>](http://www.bestdata.jp/sdcard-recovery.html)をクリックしてソフトウェアをダウンロードします。
ダウンロードしたファイルを実行して、セットアップウィザードの案内に従ってインストールします。![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316476/389bb260-f79d-1749-355d-90a28815d2fa.png)


STEP2：スキャン方法を選択
「高速スキャン」や「完全スキャン」の二つの復元モードから一つを選択します。
SDカードのデータを誤って削除してしまった、ウィルスに消された場合は「高速スキャン」、SDカードを間違ってフォーマットしてしまった、「フォーマットしますか」と表示されフォーマットが要求される場合は「完全スキャン」を選択してください。 
「高速スキャン」の場合は短時間でSDカードをスキャンすることに対して、「完全スキャン」のほうは全セクターをスキャンするために、より時間かかりますが、従来復元難しいデータを検出して復元することもできるので、復元したいデータが「高速スキャン」で見つからない場合は、「完全スキャン」で再度スキャンすると検出できることがあります。![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316476/80f535aa-01e8-0d57-f685-5dbf95c95ebd.png)


STEP3：復元ドライブを指定
次は復元したいドライブを選択して右下の「スキャン」ボタンをクリックします。
今回はSDカードを復元するので、先にSDカードをパソコンと接続して認識させる必要があります。SDカードが「リムーバブルディスク(G:)」として認識されてから、「リムーバブルディスク(G:)」を選択してスキャンします。
MicroSDカードの場合は直接パソコンと接続できないため、アダプタやカードリーダーなどを利用して接続してください。![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316476/8e9fdbdb-3a88-65f6-00e2-d13c61f93436.png)


STEP4：復元したいファイルの確認と選択
SDカードのスキャンが完了すると、復元できる可能性の高いファイルの一覧が表示されます。
検出したファイルをダブルクリックするとプレビュー表示できます。ファイルをプレビューして復元したいファイルであるのかを確認します。確認した後、復元したいファイルのチェックボックスにチェックを入れて、「復元」ボタンをクリックします。![5-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316476/214f0303-6489-bbfa-cf40-eecdb3e6e5d6.png)

 
STEP5：復元先を設定
復元先フォルダを指定して「保存」をクリックするとデータが復元されます。![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316476/962c752f-ca22-db65-c3d4-6ef0a11035fb.png)


復元完了した後、先程設定していた復元先フォルダを開き復元したいデータがうまく復元されたのかを確認します。うまく復元されたようでしたら、作業完了です。

<h2><span id="sd-1">2．復元ソフトを使って復元する場合の高復旧率で復元するコツ</span></h2>
1．SDカードのデータ消失した後に、できるだけ早めに復元作業に取り掛かりましょう。早ければ早いほど復元できる確率が高いです。
2．データ消失した後もSDカードを使用し続けると、データが上書きされ、本来復元できるデータが復元できくなる可能性があるので、すぐにSDカードの使用を即時停止しましょう。
3．復元ソフトをダウンロードする時、復旧するSDカードにはダウンロードしないように注意しましょう。
4．復元されたファイルをSDカードに保存してはいけません。必ず保存先をSDカード以外のディスクに設定してください。

<h2><span id="sd-2">3．業者に頼む場合の失敗しない業者の選び方</span></h2>
万が一、物理損害で復元ソフトを使って自力復元が困難場合は、業者に頼むしかありません。しかし、現実では悪徳業者に騙され、なにも復元できなかったのに高額な費用が請求されたケースも少なくありません。では、どうやって信頼できる業者を選ぶことができるのでしょうか？まずは「データ復旧」と「評判」や「トラブル」、「口コミ」、「比較」などのキーワードを組み合わせて検索してみると、いろいろなトラブル事例がヒットします。それでも判断しきれない場合は、その業者は日本データ復旧協会に加盟しているか否かを確認してください。業者に頼むのでしたら、できれば日本データ復旧協会に加盟している企業からお選びください。悪徳業者や技術力のない企業は加盟できませんのでお勧めします。
STM32F769 Discovery Kit > Error: ST-Linkデバイスの初期化エラー. 理由: (9)ターゲットが停止出来ません。 > 対策 + 原因

```txt:動作環境
Ubuntu 18.04 LTS
STM32CubeMX v5.2.1
STM32CubeIDE v1.0.1
基板: STM32F769 Discovery Kit
```

### なんか失敗したらしい

EthernetののUDP通信プログラムをロードした直後、デバッグ状態にしようとすると以下のエラーが出るようになってしまった。

> ST-Linkデバイスの初期化エラー
> 理由: (9) ターゲットが停止出来ません。

検索で見つけた情報ではBOOT0をどうたらとして対策を、という情報はあるが。。。

### 対策

- [Troubleshooting ST-LinkV2/STM32F469 connection](https://community.st.com/s/question/0D50X00009XkXMtSAN/troubleshooting-stlinkv2stm32f469-connection)

> Your chance to connect to your device is to keep reset button down before you try to erase your memory...

1. デバッグ状態にする時にResetボタン（STM32F7Discoveryの二つあるボタンのうちの黒い方）を押しながら
2. Debug asにてデバッグ状態にして
3. Resetボタンを離す

流し込めた。

この後以降、デバッグ状態にする時のエラーは出なくなった。

### エラーの原因

- [st link error message: Can't halt the core](https://community.st.com/s/question/0D50X00009XkaXESAZ/st-link-error-message-cant-halt-the-core)

> Does the code you previously downloaded use DMA, WFI or reprogram SWD related pins?

Ethernetの設定をする上で、設定を間違ったのかもしれない。

これらのピンは注意して設定すること。

問題の発端となったEthernetのUDP通信プログラムを再度流しこむと、やはり同じエラーが出るようになった。設定がおかしいのだろう。
Nginxにhttpsへのリダイレクト設定する


'Google Cloud Platform'で'wordpress with nginx and ssl certified by bitnami'をデプロイして、WordPressを運用する上で、httpからhttpsにリダイレクトする方法を記載します。

#設定ファイルに記載する
bitnami.confに設定を書き込みます。

```bash
$ sudo vi /opt/bitnami/nginx/conf/bitnami/bitnami.conf
```

##httpsリダイレクト設定
```nginx:bitnami.conf
server {
    # httpをhttpsにリダイレクト
    listen 80;
    server_name hogehoge.com;
    return 301 https://$host$request_uri;
}
```
##SSLv3を無効化
```nginx:bitnami.conf
server {
    listen 443 ssl;
    server_name hogehoge.com;
    # SSLを無効化してTLSのみ受け付ける 
    ssl_protocols TLSv1.3 TLSv1.2;
}
```

#設定を反映させる
Nginxを再起動して、設定を反映させます。

```nginx
$ sudo /opt/bitnami/ctlscript.sh restart nginx
```

#つまづきポイント
##1. .htaccessを編集すれば良い！という情報がいっぱい
この設定ファイルはApache(以外にも？)というWebサーバーソフトウェアを使っているときに使う設定ファイルらしい(Apache以外にも使える？)。
##2. /etc/nginx/nginx.confがない、そもそも/etc配下にnginxがない
これはbitnamiでNginxを入れたが故に。見つけられてよかった。

#参考
ほとんどそのままです...
https://qiita.com/fisherman08/items/e39e67e85ef07a1ef3db
https://yusuke.blog/2017/12/20/2062
Pythonで学ぶ強化学習

# 概要
　機械学習スタートアップシリーズ「[Pythonで学ぶ強化学習](https://www.amazon.co.jp/%E6%A9%9F%E6%A2%B0%E5%AD%A6%E7%BF%92%E3%82%B9%E3%82%BF%E3%83%BC%E3%83%88%E3%82%A2%E3%83%83%E3%83%97%E3%82%B7%E3%83%AA%E3%83%BC%E3%82%BA-Python%E3%81%A7%E5%AD%A6%E3%81%B6%E5%BC%B7%E5%8C%96%E5%AD%A6%E7%BF%92-%E5%85%A5%E9%96%80%E3%81%8B%E3%82%89%E5%AE%9F%E8%B7%B5%E3%81%BE%E3%81%A7-KS%E6%83%85%E5%A0%B1%E7%A7%91%E5%AD%A6%E5%B0%82%E9%96%80%E6%9B%B8-%E4%B9%85%E4%BF%9D/dp/4065142989)」を読み終わったので、できるかぎりわかりやすくまとめてアウトプットしようと思います。
　この書籍は、サンプルコードがたくさん載っており、数式や理論などを理解するのが苦手なプログラマの方におすすめです。機会学習の初歩から学べるという点も、この本の強みであると感じています。

# 機械学習とは
　人工知能を実現するための技術のひとつとして機械学習というものがあります。
　機械学習の明確な定義はいまだに定まっておらず、ひとによって細部の理解は異なります。Wikipediaによると、
>明示的な指示を用いることなく、その代わりにパターンと推論に依存して、特定の課題を効率的に実行するためにコンピュータシステムが使用するアルゴリズムおよび統計モデルの科学研究である。

とあります。
<br>

　ちまたでよく話題になっている深層学習（DeepLearning）は、機械学習モデルのひとつです。ニューラルネットワークとよばれる、動物のニューロン（神経細胞）を模したモデルを多層にしたもので、以降ではDNN（Deep Neural Network）と称します。
<br>

　機械学習においてモデルを学習させる手法は主に３つに分けられます。
<br>

- 教師あり学習
ー＞　モデルに入力するデータと正解となる出力ラベルをセットで学習に用います。
<br>

- 教師なし学習
ー＞　正解ラベルをもたない入力データだけで、それぞれのデータの関係性をあらわせるようにパラメータ調整（学習）を行います。クラスタリングはこれに含まれます。
<br>

- **強化学習**
<br>

　ここから強化学習を深掘っていきたいと思います。

# 強化学習とは
　強化学習では、ほか２つの手法と異なり、データをあたえるかわりに「環境」を設定します。
<br>

　ここでいう「環境」では「行動（Action）」とそれに対応した「状態（State）」、そしてある状態に至ったときに得られる「報酬（Reward）」が定義された空間のことになります。Actionを行う強化学習上での主体のことを「エージェント」とよびます。<br>

　強化学習でよく使用される環境として、ゲームは欠かせません。スーパーマリオブラザーズでたとえるならば、「マリオ（エージェント）がジャンプする」が「行動」で、「マリオ（エージェント）の位置座標」が「状態」、「獲得したコインの枚数」が「報酬」といったように定義できます。
<br>
　このようにあたえられた「環境」の中で、一連の「行動」（１エピソードともいう）で得られた「報酬の総和」を最大化することが、強化学習の目的になります。
<br>
　ひとつ例をあげてみましょう。１日あたり１０００円受け取ることができるけれど、３日がまんすれば１００００円もらえるという場合を考えます。この場合の行動は、我慢するかしないかになります。このとき、強化学習では報酬の総和を最大化することを目的とするため、３日我慢するのが最適な行動となるように学習することになります。
<br>
　これを学習するためには、「報酬の総和」を最大化するために「行動」を評価する必要があります。つまり、モデルが学習すべき点は２つです。１つは行動の評価方法、もう１つはその評価に基づく行動の選び方（戦略、方策、ポリシーとよばれます）です。
<br>
　なんとなくイメージは伝わりましたでしょうか？ ここからは強化学習のしくみについて説明します。

## マルコフ決定過程
　前述したとおり、強化学習では環境が必要になります。

　その環境は一定の性質をもっていることを前提としており、マルコフ性とよばれています。その性質は「遷移先の状態は直前の状態とその状態での行動からみちびかれ、報酬は直前の状態と遷移先に依存する」というものです。マルコフ性をもつ環境のことをマルコフ決定過程（MDP）といい、４つの要素をもっています。

- **ｓ**：状態（State）
- **ａ**：行動（Action）
- **Ｔ**：状態遷移確率（Transition function）。ある状態（ｓ）である行動（ａ）を行った際に遷移先の状態（ｓ’）に移動する確率。T(s, a, s')であらわされる。
- **Ｒ**：報酬。状態と遷移先（行動も考慮する場合もある）から出力される。

　このような環境のなかで、「報酬の総和」を最大化するように学習していきます。エピソード終了時までの報酬の和を考えてみましょう。以下のようにあらわすことができます。
（つづく）
“Docker" First Try (3)

My studied Evidence

■upload images created locally into Docker HUB's repository

```console
$ docker push xxxxxx/sample:latest
The push refers to repository [docker.io/xxxxxx/sample]
xxxxxx: Pushed 
latest: digest: sha256:///
```

then,confirmed it from DockerHUB site.

■What is "Docker compose"?
> command thaw will manage several container easily,Just like port setting,volume mount setting,and NW setting between containers.

(1)Installation Docker compose

```console
$ sudo curl -L "https://github.com/docker/compose/releases/download/1.24.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   617    0   617    0     0   3427      0 --:--:-- --:--:-- --:--:--  3427
100 15.4M  100 15.4M    0     0  23.3M      0 --:--:-- --:--:-- --:--:-- 23.3M
```

(2)added privilege

```console
$ sudo chmod +x /usr/local/bin/docker-compose
```
(3)confirmed

```console
$ docker-compose version
docker-compose version 1.24.1, build 4667896b
docker-py version: 3.7.3
CPython version: 3.6.8
OpenSSL version: OpenSSL 1.1.0j  20 Nov 2018
```

★below link is helpful to Reverse resolution
https://qiita.com/souichirou/items/6e701f6469822a641bdd

■TRY TO USE by creating wordpress environment via docker compose.

```console
$ touch docker-compose.yml
$ chmod +x docker-compose.yml
$ cat docker-compose.yml 
version: '3'

services:
        wordpress:
        image:wordpress
        ports:
        - 80:80
        environment:
        WORDPRESS_DB_HOST: mysql:3306
        WORDPRESS_DB_USER: wp_user
        WORDPRESS_DB_PASSWORD: wp_pass
        depends_on:
        - mysql

mysql:
        image: mysql:5.7
        environment:
        MYSQL_ROOT_PASSWORD: sample
        MYSQL_DATABASE: wordpress
        MYSQL_USER: wp_user
        MYSQL_PASSWORD: wp_pass
```
仙台CTF2018 Lab.1 不審ファイルの起動日時 100

#問題

http://ctf.sectanlab.jp/2018/challenges

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17681/1b760584-f950-28de-296d-f34aaa694b81.png)

#解いてみた

ファイルをダウンロードして中身を見てみます。

$MFTとPrefetchが入っていました。
問題文から検知したファイル名は1.exeだとわかっているので、Prefetchを確認してみます。

WinPrefetchViewを使います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17681/19c39e55-0660-e211-c126-6cb78c22a118.png)

これが答え。
CSSでの色指定

## 色の指定
### HEX(6桁)
\#で始まる6桁のカラーコードで指定します。
16進数によって256段階で指定します。

```:css
 /* #赤(2桁)緑(2桁)青(2桁) */
 #ff0000;
```	

|場所(色)|値|
|---|---|
|1,2桁目(赤)|00~FF(高いほど強い)|
|3,4桁目(緑)|00~FF(高いほど強い)|
|5,6桁目(青)|00~FF(高いほど強い)|


### HEX3桁

```:css
/* #赤(1桁)緑(1桁)青(1桁) */
#f00; 
``` 

|HEX||
|---|---|
|1桁目(赤)|0~F(高いほど強い)|
|2桁目(緑)|0~F(高いほど強い)|
|3桁目(青)|0~F(高いほど強い)|

### カラーネーム
色の名前(140種類)から指定します。

```:css
red;
green;
white;
```

### RGB(RGBA)
色の3原色(赤、緑、青)で指定します。
オプションのアルファは色の不透明度を表します。

```:css
/* rgb(赤,緑,青) */
rgb(255,255,255);
rgb(100%,100%,100%);

/* rgba(赤,緑,青,アルファ) */
rgba(255,255,255,0.5);
rgba(100%,100%,100%,50%);
```

|RGBA|値|
|---|---|
|R(赤)|0~255,0~100%(高いほど強い)|
|G(緑)|0~100%(高いほど強い)|
|B(青)|0~100%(高いほど強い)|
|A(アルファ)|0~1、0~100%(高いほど不透明)|

### HSL(HSLA)
色相(H)、彩度(S)、明度(L)で指定します。
オプションのアルファは色の不透明度を表します。

色相、彩度、明度をそれぞれ個別に調整できるのでRGB より直感的です。
例：「同じ色相で明暗や彩度が異なる色」などをより簡単に作成することができます。

```:css
/* hsl(色相,彩度,明度) */
hsl(180,50%,50%);
 
/* hsla(色相,彩度,明度,アルファ) */
hsla(180,50%,50%,50%);
```

|HSLA|値|
|---|---|
|H(色相)|![colorcircle.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/451263/a746244d-5b32-7022-da72-f38d0b32e6bf.png)|
|S(彩度)|0~100%(高いほど鮮やか)|
|L(明度)|0~100%(高いほど明るい)|
|A(アルファ)|0~1、0~100%(高いほど不透明)|


### キーワード
#### transparent
透明にします。

#### currentColor
プロパティが継承した値が適用されます。




## 背景と文字のコントラスト比を確保する
色のコントラスト比は、テキストおよび背景色の明度の値を比較して調整します。

|文字列|コントラスト比|
|---|---|
|通常のテキスト|4.5:1 以上|
|大きめの文字列(見出しなど)|3:1 以上|
Python+MySQL でコネクションやカーソルと with 文

（この記事は私の blog の http://umezawa.dyndns.info/wordpress/?p=7317 の転載です）

また Python+MySQL ネタ。

## 前置き

カーソルを使ったら閉じないといけません。処理後にその流れでそのまま `cursor.close()` を呼ぶように書くと例外が飛んだり長い処理の途中でうっかり `return` したりしたときに呼び漏れが発生するので、`try`～`finally` のような構造を使いたいところです。（Java でもたぶんそう（20年前の知識）。C++ だとデストラクタが使えるので違う書き方になる）

```python
cursor = conn.cursor()
try:
    cursor.execute("SELECT * FROM table")
    rows = cursor.fetchall()
    ...
finally:
    cursor.close()
```

## カーソルと `with` 文

ところで、Python には `with` 文というのがあって、 `with` 文の中のブロックを（抜け方にかかわらず）抜けたときに一定の終了処理を自動で実行することができます。PyMySQL と mysqlclient ではカーソルに対してこれを使うことができます。

```python
with conn.cursor() as cursor:
    cursor.execute("SELECT * FROM table")
    rows = cursor.fetchall()
    ...
    # with から抜けるときに cursor.close() が自動的に呼ばれる
```

残念なことに MySQL Connector/Python だとこの書式は使えません。`with`文は `with` の後に来るオブジェクトの `__enter__` を呼んで `with` を抜けるときに `__exit__` を呼ぶという仕組みなのですが、カーソルにはこれらのマジックメソッドが実装されていないからです。

```
Traceback (most recent call last):
  File "./test_cursor_with.py", line 29, in <module>
    with conn.cursor() as cur:
AttributeError: __enter__
```

ただし、 `with` を抜けるときに `close()` を呼んでくれるようになる `closing` というラッパーメソッドが Python 標準の `contextlib` モジュールの中にあるので、自前でラッパーを書いたりする必要はありません。

```python
from contextlib import closing
with closing(conn.cursor()) as cursor:
    cursor.execute("SELECT * FROM table")
    rows = cursor.fetchall()
    ...
```

## コネクションの場合

さて、カーソルを `with` で使えるならコネクションでも使ってみようかと思うわけですが、何も考えずに `with` に渡すとおかしな挙動になります。（`commit` や `rollback` についてはとりあえず考えないことにします）

```python
with pymysql.connect(**mysql_kwargs) as conn:
    print(conn.__class__.__module__ + "." + conn.__class__.__name__)
```

```
pymysql.cursors.Cursor
```

コネクションが来ることを期待していたのですが、何故かカーソルになって渡ってきます。 mysqlclient でも同じ。なんでやねん。

コネクション型である `pymysql.connections.Connection` の定義を見てもそもそも `__enter__` とかは定義されていないのでエラーになるのが期待されると思うのですが、なんでこんな挙動になるのか分かりません。うーん。

## 使用環境

- Ubuntu 18.04 LTS
- Python 3.6.8
- PyMySQL 0.8.0
- MySQL Connector/Python 2.1.6
- mysqlclient 1.3.10
仙台CTF2018 Mal.4 検体４ JavaScript2 300

#問題

http://ctf.sectanlab.jp/2018/challenges

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17681/8c7e7473-5af7-7a37-f7bc-50e2daf21300.png)

#解いてみた

ファイルをダウンロードして、難読化されているjsを見てみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17681/21593f52-2ae2-9823-4ce1-00c5ad9d0b87.png)

難読化ですねー。

とりあえずところどころに「;」があるのでこの直後で改行してみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17681/7e2f0415-9a2a-f772-894a-828592f079c3.png)

1つ目の変数は検索してもどこにもヒットしないので、ほかでは使われていないダミーだということがわかりました。
2つ目の変数はcharをstringに変換してるので、これを変換します。
CyberChefを使います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17681/17ec416f-2c4d-3040-46ca-22be34c4cab7.png)

どうやらpowershellを使用しているようです。

3つ目の変数も同じ方法でstringに変換します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17681/e836f22a-5f73-5166-ee46-1e0cb758e72c.png)

できました。2つ目とほとんど一緒な気がします。
ちょっと見てみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17681/0bc75ae3-a9ee-d8a7-aa35-01bf1b206dd6.png)

んー、まさかの答えが書いてありました。
PyPlot(3) 散布図のProjection色々

# 散布図のProjection色々
Projectionパラメータを色々試してみます。

## 基本

```Python3:
import numpy as np
import matplotlib.pyplot as plt

np.random.seed(20190805)

N = 150
r = 2 * np.random.rand(N)
theta = 2 * np.pi * np.random.rand(N)
area = 200 * r**2
colors = theta

fig = plt.figure()
ax = fig.add_subplot(111)
c = ax.scatter(theta, r, c=colors, s=area, cmap='hsv', alpha=0.75)
```

![projection_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/476387/627d0691-c5e4-b816-395c-c720e4d854e9.png)

## aitoff

```Python:
ax = fig.add_subplot(111, projection='aitoff')
```

![projection_02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/476387/d60d30c9-7e26-7330-e7b3-666bd3c51c4d.png)

## lambert

```Python:
ax = fig.add_subplot(111, projection='lambert')
```

![projection_04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/476387/b7f9696d-d738-1abd-f863-cdaa4f91624b.png)

## mollweide

```Python:
ax = fig.add_subplot(111, projection='mollweide')
```

![projection_05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/476387/25d65963-12fb-d6eb-2c49-21125cdb3a9b.png)

## polar

```Pythion:
ax = fig.add_subplot(111, projection='polar')
```

![projection_06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/476387/6b1843ea-02d4-f4f6-06d0-0931e95b2e26.png)
テイラー展開した様子を可視化して遊んだ

# 勉強しているとよく出会うやつ

g2oなどの最適化ソルバーを使って仕事したりしてました
面白いなぁーと思ってから，最適化を日々勉強しています

やっていると，

- 参考書「ここでテイラー展開すると...」
- (ふむふむ）
- 参考書「ここでテイラー展開すると...」
- (ふむふむ...（汗）)
- 参考書「ここでテイラー展開すると...」
- (参りました)

あれやろ？と思ってスルーしているとその後の説明についていけないことがざらにあります
そんな自分を〜⤴ぶっ壊す👊，と思った次第です


# 数式

x0における関数f(x)のテイラー展開
2次まで

```math
f(x + x0) = f(x0) + \frac{1}{1!} \, f'(x0) \, (x - x0) + \frac{1}{2!} \, f''(x0) \, (x - x0)^2 + \cdots
```

# ソフト屋さんなら

ノートに書いたりするだけでなく実装して理解していこう！
自分の勉強の歴史をみてニヤニヤしたりできるから復習効果バツグンなはず！

考えた仕様

- 変更を楽にしよう
    - 関数の種類
    - そのパラメータ

- クリックしたxの値においてテイラー展開しよう

# 様子

見栄え良くするために等間隔でx0を変えた様子を表示してます
2次近似まで計算しています

## 1次関数
```math
y = 5x + 2
```
![line](https://media.giphy.com/media/XAyRF7tfaRahPkmDRt/giphy.gif)

見にくいですが，オリジナルの軌跡，1次，2次近似した軌跡全て重なっています
テイラー展開する必要ないですね

## 2次関数
```math
y = -3x^2 - 2x + 5
```
![curve2order](https://media.giphy.com/media/H6R5VP0PtZCkiblUCJ/giphy.gif)

これもに見くいですがオリジナルの軌跡と2次近似した軌跡が重なっています
2次関数であるとわかっている場合は2次近似するモチベーションはないですね

もちろん，1次式でx0近傍の線形的な振る舞いを近似できることは有用です

## 3次関数
```math
y = x^3 + x^2 + x + 1
```
![curve3order](https://media.giphy.com/media/QVxXERc4QIKoVMW5qp/giphy.gif)

ここから可視化し甲斐がでてきました
x0付近で傾きの変化が大きい場合は，1次と比べて2次の方が粘り強いのかな...?
（x0から少し離れたとき，2次式の方がオリジナルの軌跡に近いと思った）

## ミカエリス・メンテン式
```math
y = \frac{b_1x}{b_2 + x}
```
![mm](https://media.giphy.com/media/H502hjNxBJCDASRGOm/giphy.gif)

[ガウス・ニュートン法](https://ja.wikipedia.org/wiki/ガウス・ニュートン法)の例で使われている式です
後半ほぼ変化なしです

# この活動をしてよかったこと

- いろいろな関数の近似した様子を肌で感じることができました
    - 好きなところで近似できるようにしたので，気になるところで近似して考える時間を作ることができました
- 傾きの変化が激しい部分はより高次の近似ができるとよいと思いました
    - x0から離れるほどオリジナルとの差も大きくなります
- 分子・分母に変数が含まれているときの微分の式をかなりひさしぶりに計算できました
    - ミカエリスメンテン式のことですね

# ソース置き場と使い方

githubに使い方含めて置いています
https://github.com/fugashy/fgs_opt/tree/master/fgs_opt_from_scratch

2019年8月5日現在，無駄にROS2依存です
高機能な3D可視化ソフトでax + by + cz +d = 0のような関数の可視化もしたいという野望があるのでそうしてます
ROS2非依存で実行できるようにはしたいなぁと思っています
BLEセンサデータをM5stackで取得しGASに投げる

#はじめに
オムロン環境センサをESPで取得したものの、繋いだだけで何もしてなかったのでM5stackとGASで見える化してみました
#使ったもの
M5stack
GAS
#BLEでセンサデータを取得
これについてはこちらの記事を参考にしてください
[ESP32からBLEでオムロン環境センサ(2JCIE-BL)に繋ぐ](https://qiita.com/notitle420/items/a2bdbc909f16b96068cc)
#WiFi接続

WiFiライブラリをインクルードして使うだけです。特に特別なことはしません

```c
#include <WiFi.h>
Serial.println("WIFI_START");
WiFi.setAutoConnect(false);
WiFi.setAutoReconnect(false);
WiFi.disconnect();
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
}
```

#HTTP POST
HTTPClient.hを使いました
root証明書が必要なので[こちら](https://www.mgo-tec.com/blog-entry-arduino-esp32-ssl-stable-root-ca.html)を参考に発行してください

#GASで受け取る
こんな感じで書きましたdoPostで受けているだけです。

```javascript

function doPost(e) {
  // シート取得
 
  var postjsonString = e.postData.getDataAsString();
  var postdata = JSON.parse(postjsonString);
  var ss = SpreadsheetApp.openById(SpreadsheetApp.getActiveSpreadsheet().getId());
  
  var temp = null;
  var humid = null;
  var pres = null;
  var shodo = null;
  var hukai = null;
  var meyasu;

  var date_time = null;
  
  if(postdata.shodo != undefined){
  var sheet = ss.getSheetByName("シート1");
  // データ入力
  temp = postdata.temp;
  humid = postdata.humid;
  pres = postdata.pres;
  shodo = postdata.shodo;
  hukai = ( 0.81 * temp ) + ( 0.01 * humid * ( 0.99 * temp - 14.3 ) ) + 46.3 ;
  if(hukai >= 85 ){
    var meyasu = "暑くてたまらない";
  }else if(hukai >= 80 ){
    var meyasu = "暑くて汗がでる";
  }else if(hukai >= 75 ){
    var meyasu = "やや暑い";
  }else if(hukai >= 70 ){
    var meyasu = "暑くない";
  }else if(hukai >= 65 ){
    var meyasu = "快適";
  }
 
 
  date = new Date();
  date_time =  Utilities.formatDate(date, 'JST', 'yyyy年M月d日 H時m分s秒')
  sheet.appendRow([date_time,temp,humid,pres,shodo,hukai,meyasu]);  
  
 
  var output = ContentService.createTextOutput();
  output.setMimeType(ContentService.MimeType.JSON);
  output.setContent(JSON.stringify({ message: "success!" }));
 
  return output;
}
```

M5stack側でアプリケーションのURLを指定してPOSTしてあげます。


#メモリ不足
BLE、WIFI,httpsを使うとメモリ不足でM5stackが死にました。なので以下のような流れにしました

BLEでデータ取得→BLE系のメモリ解放→WiFi接続→Httpsポスト→シャットダウン

BLEDevice::deinit(true);

をするとBLE系のメモリを解放し、BLEを無効にできます
ESP.restart();

をすると再起動がかかります

#開発したコード
以下に開発したコードをあげておきます
https://github.com/notitle420/m5Stack_omron_ble_http_post
root_ca
SensorAddr
ssid
password
path
を書き換えてご利用ください
仙台CTF2018 Mal.3 検体３ ワード文書 100

#問題

http://ctf.sectanlab.jp/2018/challenges

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17681/ce53eb03-5eb7-0f04-3dbe-372229755a33.png)

#解いてみた

ファイルをダウンロードして、解凍してみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17681/8a2bf174-f122-620f-ba54-cffbd098b0d4.png)

wordファイルでした。
ひとまずサクラエディタで開いてみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17681/6a9b43cb-097d-01f6-dc31-917fbc61e64b.png)

これはwordファイルではなくリッチテキストですね。
wordファイルならマクロを見れば通信先が書いてありそうでしたけど、この場合はどうするんでしょう。

問題文に実害のある動作はしません。
と書いてあったので、思い切って実行してみる。
wiresharkでhttp通信が拾えれば。。。

と思ったら、1つも通信が起きませんでした。
むむむ。

rtfからoleオブジェクトを抽出してくれるツールを探します。
[rtfobj · decalage2/oletools Wiki · GitHub](https://github.com/decalage2/oletools/wiki/rtfobj)
これを使ってみようと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17681/cc5febfa-6ca0-5b1d-753b-757b77460c0a.png)

やはり埋め込まれていることはわかりました。
オプション-sを付けるとファイルとして保存してくれるようなので、やってみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17681/2bc3c3ea-a8f0-5772-6009-71352d81e540.png)

保存完了です。
保存したファイルをサクラエディタで見てみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17681/6895d405-87c0-0238-4162-d234ec7f65c4.png)

正解です。
Django構築 基本コマンドまとめ

#はじめに
Djangoを勉強しているのですが、構築するときに必要になるコマンドを備忘録としてまとめてみました。
基本的なコマンドなのでご存知の方が多いかもしれませんが、Djangoを始める方にとって少しでも参考になればと思います。

#仮想環境作成
任意のディレクトリに移動後以下のコマンドを実行。

```
$ python3 -m venv 仮想環境名
```

#仮想環境起動
コマンドがうまく実行されると、＄の前に（仮想環境名）のように文字が出ます。これが「仮想環境の中にいる」状態を表しています。

```
$ source 仮想環境名/bin/activate
(仮想環境名) $
```

#pipを最新のものにアップデート
仮想環境を有効にして以下のコマンドを実行。

```
$ pip install --upgrade pip
```
> **pipとは**
pipはPythonのパッケージ管理システムで、ライブラリやパッケージを簡単にインストールできたり、バージョン管理できるもの。

#Djangoインストール
最新のバージョンをインストール

```
$ pip install django
```
バーションを指定してダウンロードする場合

```
$ pip install django==2.2
```

#プロジェクト作成

```
$ django-admin startproject プロジェクト名
```
> **プロジェクトとは**
「プロジェクト」とは、ウェブサービス全体に関する設定やそのウェブサービスの各機能を構成する「アプリケーション」を一つにまとめたものです。基本的に、ウェブサービスを一つ作るときには、Djangoプロジェクトが一つと、そのプロジェクトに対応する複数のアプリケーションがあることになります。

#アプリケーション作成

```
$ python manage.py startapp アプリケーション名
```
> **アプリケーションとは**
「アプリケーション」とは、ウェブサービスに必要な機能を実現するための部分のことです。例えば、「ブログをウェブページに表示させる機能」や「自分の好きなブログをお気に入り登録する機能」といった、なにか特定の役割を持つ機能を担っている部分のことです。

#マイグレーション
models.pyファイルで定義したデータベースの設計を、実際にデータベースに反映させる。

```
$ python manage.py makemigrations
$ python manage.py migrate
```

#スーパーユーザーアカウント作成
管理ページにアクセスするために管理者アカウントを作成する
・ユーザ名
・メールアドレス
・パスワード
を登録する

```
$ python manage.py createsuperuser
```

#PythonとDjangoのコードが扱えるコマンドプロンプトを起動

```
python manage.py shell
```

#さいごに
PipenvでDjangoの環境を作ってみたので、こちらも参考にしてみてください。
[PipenvでDjango開発環境をつくる](https://qiita.com/nochifuchi/items/4fe0164f0d8949cf11b7)
Pandas(4) DataFrame.drop

# DataFrame.drop

```Python:
df = pd.DataFrame(np.arange(12).reshape(3, 4),
                 columns=['A', 'B', 'C', 'D'])
df
```

![drop_01.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/476387/bfdc79d4-9fef-700a-0946-703faee530e6.png)

## 列のdrop

```Python:
a = df.drop(['B', 'C'], axis=1)
a
```
または

```Python:
b = df.drop(columns=['B', 'C'])
b
```

![drop_02.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/476387/40908f71-e6d0-746f-85fc-40f43d3b5c20.png)

## indexによる行のdrop

```Python:
c = df.drop([0, 1])
c
```

![drop_03.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/476387/b0178e74-3fcf-b5c3-e6a7-0e0add2347cb.png)
ラズベリーパイ初心者のためのコピペでできる温湿度センサー(備忘録）

**はじめに**
---
今回は、ラズベリーパイと温湿度センサーを使って、気温と湿度をコンソールに出力していきたいと思います。

**使用環境**
---
Thonny Python IDE　←ラズベリーパイにデフォルトで入っています。
pythonのバージョンは3.7.3です。

**使用機材**
---
メス端子　                ×3
ブレッドボード             ×1
40ピンT字型GPIO拡張ボード   ×1
40ピンリボンケーブル　　　×1
dht11　　 ×1
Pi3ボード　　　×1
を使用します。

例によって[osoyoo](https://www.amazon.co.jp/gp/product/B01M6ZFNSS/ref=as_li_ss_tl?ie=UTF8&psc=1&linkCode=sl1&tag=terutakke09-22&linkId=d97c8c7bff268ecbbba61533a12b943d
)と[Raspberry Pi 3 Model B](https://www.amazon.co.jp/ABOX-MicroSDHC%E3%82%AB%E3%83%BC%E3%83%8916G-NOOBS%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E3%83%97%E3%83%AA%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB-%E7%B0%A1%E5%8D%98%E3%81%AB%E5%8F%96%E3%82%8A%E4%BB%98%E3%81%91%E3%82%AF%E3%83%AA%E3%82%A2%E3%82%B1%E3%83%BC%E3%82%B9-%E9%AB%98%E5%93%81%E8%B3%AAHDMI%E3%82%B1%E3%83%BC%E3%83%96%E3%83%AB%E3%83%A9%E3%82%A4%E3%83%B3/dp/B07G7WSMQ2/ref=pd_lpo_sbs_147_t_0?_encoding=UTF8&psc=1&refRID=0XHKED255HA1KHCBFSAQ
)の機材を利用しています。
⚠注意
あまり安価なセンサーを使用するとセンサの電気的特性を原因とした周波数ノイズが発生しえます。これにより、正確な値が取得できない可能性があります。ご留意ください。


**配線図**
---
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/457895/c930d003-9df7-ab03-7ce7-21190236f71a.png)
＊[osoyoo](http://osoyoo.com/ja/2017/10/09/raspberry-pi-starter-kit-v1-introduction/)より引用

**ソースコード**
---
[osoyooの解説ページ](http://osoyoo.com/ja/2016/04/11/drive-dht11-temperature-sensor-with-raspberry-pi/)があり、そちらの
[dht11.py](http://osoyoo.com/driver/dht11.py)を利用することで「DHT11」で取得した値を読み取ることができるようになります。

```python:ondo.py
import dht11
import RPi.GPIO as GPIO
import time
import datetime


#GPIOからLCDへのマッピングを定義する
Temp_sensor=14
 
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)       
instance = dht11.DHT11(pin = Temp_sensor)
 
while True:
    #DHT11のセンサーの値を取得する
    result = instance.read()
    if result.is_valid():
        #タイムスタンプで現在時刻を取得する
        now = datetime.datetime.now().strftime("%Y/%m/%d %H:%M")
        print('test_' + str(now))                   #時間
        print("temp:"+str(result.temperature)+" C") #温度
        print("humid:"+str(result.humidity)+"%")    #湿度
        time.sleep(10) # 10秒ディレイさせる
```
これを実行することでdht11で取得した温度と湿度を時間とともにコンソールに出力できます。
time.sleep(10)の時間を調整すれば、任意の周期で値を表示できます。
**展望**
---
スマホと連携して、センサーの値をスマホに通知できるようにしたいですね。

**参考**
---
https://terutakke.com/diary/dht11-raspberry-pi-3/
Pandas(3) DataFrame.loc

# DataFrame.loc

## 値の取得

以下のデータに対して、色々と試していきます。

```Python:
df = pd.DataFrame([[1, 2], [4, 5], [7, 8]],
                 index=['cobra', 'viper', 'sidewinder'],
                 columns = ['max_speed', 'shield'])
df
```
![loc_01.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/476387/819f97d2-07db-9336-302b-3369761b0cf8.png)

### 単一のラベル
行を`Series`として返します。

```Python:
a = df.loc['viper']
a
```

![loc_02.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/476387/bab2cacf-0b17-f0c5-5a20-738c9db87869.png)

### ラベルのlist
`DataFrame`を返します。

```Python:
b = df.loc[['viper', 'sidewinder']]
b
```
![loc_03.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/476387/aca8a669-8677-e698-9f77-0440f46d29b6.png)

### 行と列の単一のラベル

```Python:
c = df.loc['cobra', 'shield']
c
```

![loc_04.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/476387/5cf68e11-55d7-2d0e-b68d-8e3dec08fee0.png)

### 行ラベルと単一のラベル

```Python:
d = df.loc['cobra':'viper', 'max_speed']
d
```

![loc_05.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/476387/b7797f5f-0bf4-9ece-d271-445bce03fdde.png)

### 行と同じ長さの真偽値リスト

```Python:
e = df.loc[[False, False, True]]
e
```

![loc_06.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/476387/4b558db6-ae61-68f0-70ac-5aa19c8f1aaf.png)

### 条件による絞り込み

```Python:
f = df.loc[df['shield'] > 6]
f
```

![loc_07.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/476387/f0328c07-a88a-d0b2-a9a4-da386003416d.png)

```Python:
g = df.loc[df['shield'] > 6, ['max_speed']]
g
```

![loc_08.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/476387/71415f64-18ea-3b14-02a6-2204a98033ff.png)

### Callable

```Python:
h = df.loc[lambda df: df['shield'] == 8]
h
```
![loc_09.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/476387/48a6551b-1c68-77c2-35e2-72854d4fc983.png)

## 値のSetting

### ラベルのリストにマッチするすべてのitem

```Python:
df.loc[['viper', 'sidewinder'], ['shield']] = 50
df
```

![loc_10.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/476387/9805a325-2964-bf89-5181-eaff02bf4a60.png)

### すべての行

```Python:
df.loc['cobra'] = 10
df
```

![loc_11.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/476387/0f521450-043e-609d-c84a-4c1b020a6af8.png)

### すべての列

```Python:
df.loc[:, 'max_speed'] = 30
df
```

![loc_12.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/476387/fae8e391-0d99-3d0c-cd7e-048dc5f951c4.png)

### 条件に一致する行

```Python:
df.loc[df['shield'] > 35] = 0
df
```

![loc_13.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/476387/f7c831e0-9d34-3c37-fbac-4f3178169747.png)
[Mac]Finderで隠しファイル・フォルダを表示させる方法

dockerの環境開発をする際に隠しファイル(.ドットファイル)をFinderに表示させる必要があったので、コマンドをメモ

まずはターミナルを起動。
アプリケーション/ユーティリティ/ターミナル.app
#### 全てのファイルを表示。
```
$ defaults write com.apple.finder AppleShowAllFiles TRUE
```

###設定を適用してFinderを閉じる。
```
$ killall Finder
```

その後Finderを再開すると無事表示。
GoでgRPC

### 概要
[前回](https://qiita.com/nannou/items/4e27bed0de24d7c2cd8a)、JavaでgRPCサーバーがビルド出来たので、今度はGoのクライエントからリクエストしてみます。
流れは同じで、protoファイルからGoコードを生成し、クライエントを実装します。

### 環境
- Mac
- Go version 1.12

#### コンパイラをダウンロード
[ここ](https://github.com/protocolbuffers/protobuf/releases)から落としてきて、パスを通す。
brewでもいけるみたいです。

#### ライブラリを落とす
```
$ go get -u google.golang.org/grpc
$ go get -u github.com/golang/protobuf/protoc-gen-go
```
上がgRPCを使用するライブラリ。
下がGoコード生成用のライブラリです。
上でダウンロードしたコンパイラがprotoc-gen-goを使用するので、go/binにパスを通す必要があります。

#### protoファイルの準備
Javaのサーバーと通信したいので、前回使用したものと同じものを使用します。

```protobuf:helloworld.proto
syntax = "proto3";

option java_multiple_files = true;
option java_package = "io.grpc.examples.helloworld";

package helloworld;

service Greeter {
  rpc SayHello (HelloRequest) returns (HelloReply) {}
}

message HelloRequest {
  string name = 1;
}

message HelloReply {
  string message = 1;
}
```
※　optionはJava用、packageはGo用

#### コード生成
```
$ protoc --go_out=plugins:grpc:helloworld/ helloworld.proto
```
※ plugin:grpcが抜けるとサーバーとクライエントのコードが生成されませんでした。
また、「protoc-gen-go: program not found or is not executable」というエラーが出る場合は、protoc-gen-goへのパスが通ってないと思われるので、チェックしてみてください。

#### Javaサーバーへ通信
今回は既にJavaサーバーが出来ているので、Clientのみ実装します。
ほぼチュートリアルから持って来ています。

```go:[client.go]
package main

import (
	pb "./helloworld"
	"context"
	"google.golang.org/grpc"
	"log"
	"os"
	"time"
)

const (
	address     = "localhost:8080"
	defaultName = "Takeshi"
)

func main() {
	conn, err := grpc.Dial(address, grpc.WithInsecure())
	if err != nil {
		log.Fatalf("did not connect: %v", err)
	}
	defer conn.Close()
	c := pb.NewGreeterClient(conn)

	name := defaultName
	if len(os.Args) > 1 {
		name = os.Args[1]
	}
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()
	r, err := c.SayHello(ctx, &pb.HelloRequest{Name: name})
	if err != nil {
		log.Fatalf("could not greet: %v", err)
	}
	log.Printf("reply: %s", r.Message)
}
```

Javaのサーバー側を起動し、Goのclientを実行する。

```
reply: Hello Takeshi
```
無事、Takeshiが返って来ました。


### 参考
[Go Quick Start](https://grpc.io/docs/quickstart/go/)
Visual Studio Code の プラグイン の 入れ方

# 目的
- Visual Studio Codeにて汎用的なプラグインの入れ方をまとめる

# この記事のターゲット
- Visual Studio Codeのプラグインの入れ方が分からない方

# プラグインの導入方法
1. 画面左側のプラグインのボタン(赤矢印部分)をクリックする。
    ![vscode_11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/a6152cff-8173-acc0-7719-f40bb64e155f.png)

1. 検索窓にプラグイン名を入力する。→検索に引っかかった導入したいプラグインのインストールボタンをクリックする。
    ![vscode_14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/0c9370cc-39b6-9917-6452-1a9774c3f33f.png)

1. インストールが完了したら、一旦Visual Studio Codeを閉じて再度起動する
※必須ではないが、プラグインによっては再起動を促すメッセージ(赤矢印部分)が出力される事があるため、再起動した方が無難である  
    ![vscode_16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/86210408-5a55-b277-18af-1a2f5acca7c1.png)

1. 画面左側のプラグインのボタン(赤矢印部分)をクリックする
    ![vscode_11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/ccaa37e2-9ad3-134c-6693-7783b207e2a8.png)

1. 検索窓にインストール時と同じプラグイン名を入力する
    ![vscode_19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/f0df81a8-3f7c-d221-496c-139d9713ecb1.png)

1. インストールの文字はなく、｢アンインストール｣の文字が現れればプラグインのインストールは完了
    ![vscode_18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/b4fc6f36-58b7-d74f-aae9-80be6715b47d.png)
簡易ポート衝突調査 netstat tasklist bat記載あり

#概要
コマンドプロンプトやバッチファイルでの調査方法です。
#環境
win10

#調査方法(コマンドプロンプト)
バッチファイルを作成する時に以下のコマンドを参考にしました。

```bash:cmd
> netstat -nao | find "(検索するポート番号)"
  プロトコル  ローカル アドレス      外部アドレス           状態            PID
  TCP         0.0.0.0:3312           0.0.0.0:0              LISTENING       43788
> tasklist /svc | find "43788"
イメージ名                     PID サービス
========================= ======== ============================================
mysqld.exe                   43788 node.exe
```
###オプション+α
`-n` 出力をIPアドレスなど数値のみに抑制する（DNS逆引きを行わないなど）。ほかのオプション内容へ影響する
`-a` 現在のすべての接続を表示する
`-o` ネットワーク・タイマを表示する
`|`標準出力を次のコマンドの標準入力として扱うために使用。

#調査方法(バッチファイル)

```bash:port_checker.bat
@echo off
rem バッチファイルが置かれている場所をカレントディレクトリとする
cd /d %~dp0

rem 遅延環境変数対策
setlocal enabledelayedexpansion

echo イメージ名                     PID ローカルアドレス     サービス
echo ========================= ======== ==================== ====================
FOR /F "usebackq TOKENS=2,5" %%A IN (`netstat -nao ^| find ":%PORT%"`) DO ( 
    FOR /F "usebackq tokens=2 delims=:" %%C IN (`echo %%A`) DO (
        if %%C EQU %PORT% (
            if !PORTNUM! NEQ %%B (
            SET PORTNUM=%%B
                if !PORTTMP! NEQ %%B (
                    FOR /F "usebackq TOKENS=1,2,3" %%F IN (`tasklist /svc ^| find "%%B"`) DO (
                        set PORT=%%A                    
                        set PID=        %%G
                        set IMAGE=%%F                     
                        set SERVICE=%%H             
                        set PID=!PID:~-8,8!
                        set IMAGE=!IMAGE:~0,25!
                        set PORT=!PORT:~0,20!
                        echo !IMAGE! !PID! !PORT! !SERVICE!
                    )
                )
            )
        )
    )
)
```
Jetson Nano + EdgeTPU で爆速PoseNet (結果のみ)

## 【はじめに】
すみません、今回の記事は結果のみです。
Jetson Nano + EdgeTPU で PoseNet を使ってみたら爆速でした。
やったことはWebカメラの映像入力がgstreamerだとエラーが出たのと出力のsvgwriteが重かったので、どちらもOpenCVに書き換えた程度。
現在JetsonNanoの再構築を始めてしまったので、近日中に本編アップします。

(2019/08/09 [【本編】](https://qiita.com/rhene/items/b3bbbfb062dfb1872c9a)追加しました)

## 【いきなり結果】
|解像度   | Platform               |推論時間 (ms) |FPS     |備考                |
|:------:|:-----------------------|------------:|-------:|:-------------------|
|1280x720| RaspberryPi3 + EdgeTPU |       275.4 |    2.2 |                    |
|-       | JetsonNano   + EdgeTPU |        48.0 |    7.4 |                    |
|640x480 | RaspberryPi3 + EdgeTPU |        95.8 |    6.5 |                    |
|-       | JetsonNano   + EdgeTPU |        15.1 |     30 | カメラの性能限界    |
|480x360 | RaspberryPi3 + EdgeTPU |        51.0 |     12 |                    |
|-       | JetsonNano   + EdgeTPU |         9.5 |     30 | カメラの性能限界    |
Leetcode #724: Find Pivot Index

```swift
func pivotIndex(_ nums: [Int]) -> Int {
    var sum = 0
    var leftSum = 0
    for num in nums {
        sum += num
    }
    
    for i in stride(from: 0, to: nums.count, by: 1) {
        if leftSum == sum - leftSum - nums[i] {
            return i
        }
        leftSum += nums[i]
    }
    return -1
}
```
Markdownの議事録 → HTML → PDF へ変換出力 

## 前書き

会議の議事録作成などでMarkdownをよく使うのですが、
非エンジニア部門から議事録共有の要望があった時に、

**「エンジニアっぽい書き方じゃないカタチにして共有してよ」**

というオーダーが時々あったりします。


## やったこと

じゃあPDFでお渡ししますね、という対応を行いました。


## 概要

Python で提供されているライブラリを使って対処しました。

### 必要ライブラリ

- pdfkit
https://pypi.org/project/pdfkit/

- markdown
https://pypi.org/project/Markdown/

上記２点をpip等でインストール。
WIN環境では、pdfkitインストール後に実行ファイルのパスを通す必要あり。
(デフォルトインストール先の場合、パスは次の通り：C:\Program Files\wkhtmltopdf\bin)

### 実装

議事録Markdownのサンプルはこちら。

````markdown
# 定例MTG

## 日時
2019/07/26 13:00

## 場所
本社 会議室A

## 出席者
- システム部 マネージャー 開発太郎
- システム部 設計次郎
- マーケティング部 ウェブ花子

## 議題
1. [SSL証明書更新対応について](#theme1)
2. [新規集客対応について](#theme2)
3. [働き方改革について](#theme3)

## 議事内容
###<a name="theme1">[SSL証明書の更新期限]</a>

- 2019/8/31 で期限終了予定
    - 証明書更新手続き
        - システム部で対応予定
        - 証明書更新費の稟議を取る
            - 山田部長が東京出張へ行く前までに稟議を通しておいてほしい
        - 8月1週目までには更新日の確定と全社周知

###<a name="theme2">[新規集客対応]</a>

- 見込み顧客に対してメールマガジンを配信
    - 配信対象者
        - xxxx年にx回以上の購入履歴のあるユーザ
    - 対象者の絞り込み
        - マーケティング部で対応
        - 絞り込みデータの加工対応はシステム部で対処
    - 配信予定日
        - 8月中旬を予定

###<a name="theme3">[働き方改革について]</a>

- 残業の見直し
    - 対象者
        - 月の残業時間がxx時間を超えている人
        - システム部とマーケティング部で対象者が多い
    - 対処
        - 納品完了後にまとまった休暇を取得する等を検討できないか
            - 開発マネージャーから全社会議に議題提示してもらう
        - 他にも良い案があれば次回会議でも議論したい

## 次回日時
2019/08/02 13:00

## 場所日時
本社 会議室A
````

これを次の処理に通します。
Markdown を HTML に変換してから、
PDF へと変換して出力しています。

````python
import markdown
import pdfkit
import glob
import winreg


def main():
    path = "./"
    files = glob.glob(path + "input.md")

    for f in files:
        with open(f, "rt", encoding="utf-8") as fp:
            text = fp.read()
            md = markdown.Markdown()
            body = md.convert(text)
            html = '<html lang="ja"><meta charset="utf-8"><body>'
            html += '<style> body { font-size: 1rem; } </style>'
            html += body + '</body></html>'

    outfile = f + ".pdf"
    print(outfile)

    try:
        with winreg.OpenKeyEx(winreg.HKEY_LOCAL_MACHINE, r'SOFTWARE\wkhtmltopdf',
                              access=winreg.KEY_READ | winreg.KEY_WOW64_64KEY) as k:
            data, regtype = winreg.QueryValueEx(k, "PdfPath")
            configure = pdfkit.configuration(wkhtmltopdf=data)
            regtype = regtype

            pdfkit.from_string(html, outfile)
    except FileNotFoundError:
        pass

if __name__ == '__main__':
    main()

````

HTMLに変換することで、PDF出力時にスタイルを適用できます。
簡単な書式調整だけでも印象は変わるものだったりします。

そして、処理を通して出力したPDFはこちら。
https://github.com/masashi-sawai/python-learning/blob/master/tools/md_pdf_changer/input.md.pdf

いかがでしょうか。
最低限の体裁は担保できたかな。


### まとめ

もっと高機能なPDF変換ツールもあると思いますが、
簡単なものなら自分たちで作ってみるのも良いかもしれません。