OmniAICreator/Qiita-1.07M huggingface dataset:
【ラズパイ】機械学習

こちらの記事は以下の書籍を参考にアウトプットとして執筆しました

[カラー図解　Ｒａｓｐｂｅｒｒｙ　Ｐｉではじめる機械学習　基礎からディープラーニングまで ](https://www.amazon.co.jp/%E3%82%AB%E3%83%A9%E3%83%BC%E5%9B%B3%E8%A7%A3-%EF%BC%B2%EF%BD%81%EF%BD%93%EF%BD%90%EF%BD%82%EF%BD%85%EF%BD%92%EF%BD%92%EF%BD%99-%EF%BC%B0%EF%BD%89%E3%81%A7%E3%81%AF%E3%81%98%E3%82%81%E3%82%8B%E6%A9%9F%E6%A2%B0%E5%AD%A6%E7%BF%92-%E5%9F%BA%E7%A4%8E%E3%81%8B%E3%82%89%E3%83%87%E3%82%A3%E3%83%BC%E3%83%97%E3%83%A9%E3%83%BC%E3%83%8B%E3%83%B3%E3%82%B0%E3%81%BE%E3%81%A7-%E3%83%96%E3%83%AB%E3%83%BC%E3%83%90%E3%83%83%E3%82%AF%E3%82%B9-%E9%87%91%E4%B8%B8%E9%9A%86%E5%BF%97-ebook/dp/B07B7JFKL2)

#サポートベクトルマシン
機械学習の分類と回帰の問題を扱う手法。

##線形サポートベクトルマシン
真っ直ぐや平らな協会によって分類を行う。
無数の分離の組み合わせの中から1つの直線を選択するマージン最大化という方針を取る。
###マージン最大化
この内容について[カラー図解　Ｒａｓｐｂｅｒｒｙ　Ｐｉではじめる機械学習　基礎からディープラーニングまで ](https://www.amazon.co.jp/%E3%82%AB%E3%83%A9%E3%83%BC%E5%9B%B3%E8%A7%A3-%EF%BC%B2%EF%BD%81%EF%BD%93%EF%BD%90%EF%BD%82%EF%BD%85%EF%BD%92%EF%BD%92%EF%BD%99-%EF%BC%B0%EF%BD%89%E3%81%A7%E3%81%AF%E3%81%98%E3%82%81%E3%82%8B%E6%A9%9F%E6%A2%B0%E5%AD%A6%E7%BF%92-%E5%9F%BA%E7%A4%8E%E3%81%8B%E3%82%89%E3%83%87%E3%82%A3%E3%83%BC%E3%83%97%E3%83%A9%E3%83%BC%E3%83%8B%E3%83%B3%E3%82%B0%E3%81%BE%E3%81%A7-%E3%83%96%E3%83%AB%E3%83%BC%E3%83%90%E3%83%83%E3%82%AF%E3%82%B9-%E9%87%91%E4%B8%B8%E9%9A%86%E5%BF%97-ebook/dp/B07B7JFKL2)ではこのように説明されています。

>マージンとは「余白」を意味し、ここでは境界に最も近い点から協会までの距離を表します。

##サポートベクトル
境界に最も近い点
##サポートベクトルが重要な理由
一度境界線が定められると分類はサポートベクトルが使われる。サポートベクトル以外のデータは予測と無関係という性質があるため。

##ソフトマージン
線形分離可能でないデータでのマージン。
この内容について[カラー図解　Ｒａｓｐｂｅｒｒｙ　Ｐｉではじめる機械学習　基礎からディープラーニングまで ](https://www.amazon.co.jp/%E3%82%AB%E3%83%A9%E3%83%BC%E5%9B%B3%E8%A7%A3-%EF%BC%B2%EF%BD%81%EF%BD%93%EF%BD%90%EF%BD%82%EF%BD%85%EF%BD%92%EF%BD%92%EF%BD%99-%EF%BC%B0%EF%BD%89%E3%81%A7%E3%81%AF%E3%81%98%E3%82%81%E3%82%8B%E6%A9%9F%E6%A2%B0%E5%AD%A6%E7%BF%92-%E5%9F%BA%E7%A4%8E%E3%81%8B%E3%82%89%E3%83%87%E3%82%A3%E3%83%BC%E3%83%97%E3%83%A9%E3%83%BC%E3%83%8B%E3%83%B3%E3%82%B0%E3%81%BE%E3%81%A7-%E3%83%96%E3%83%AB%E3%83%BC%E3%83%90%E3%83%83%E3%82%AF%E3%82%B9-%E9%87%91%E4%B8%B8%E9%9A%86%E5%BF%97-ebook/dp/B07B7JFKL2)ではこのように説明されています。

>マージン境界間およびご認識の点にはペナルティを与えます。その状況で「マージン境界間の距離を広げつつ、ペナルティを減らす」という方針で最適な境界を定めます。

ペナルティを受けないように境界線を調整していくという点では強化学習のような匂いを感じた。

#MacからラズパイへVNC接続する
サンプルコードでグラフを表示する物があるがSSHでつないでいると見れないのでZVNC接続するための準備と手順を書いていく。

##インストールするツール
```
sudo apt-get install tightvncserver
```

```
tightvncserver
```
で起動してMac側でfinderで`command+k`で

```
vnc://アドレス:5901
```
で接続できる。
Unity 2020で出てくるError detecting Visual Studio installations~への対処法

# エラー文
Error detecting Visual Studio installations: System.ArgumentException: JSON parse error: Invalid escape character in string.

# 原因
`Visual Studio Editor`パッケージが使用しているvswhere.exeから出力されるJsonに
一部Shift_JIS文字列が含まれるためパースでエラーが起きてるらしい

# 対処法
`Packages/com.unity.ide.visualstudio/Editor/Discovery.cs`のProcessインスタンス生成部分を修正して強制的にUTF-8にする

```csharp:Discovery.cs

var process = new Process
{
	StartInfo = new ProcessStartInfo
	{
		FileName = progpath,
		//-utf8オプションで強制的にUTF-8として出力
		//Arguments = "-prerelease -format json",
		Arguments = "-prerelease -format json -utf8",
		UseShellExecute = false,
		CreateNoWindow = true,
		RedirectStandardOutput = true,
		RedirectStandardError = true,
	}
};

```
postgresql roleについて　自分用

#概要
PostgreSQLで複数のユーザーやグループがデータベースを利用するにあたり、そのアクセス権限を取り決めて設定する必要がある。その際に設定するロールというものについてまとめる。



##PostgreSQLのロールとは
PostgreSQLのロールとは、ユーザやグループがデータベースへアクセスすることを管理するための仕組みの事。ロールには名前が付けられ、データベース・オブジェクト（テーブルや関数など）を所有し、他のロールからのアクセスを制限する権限を持つ。最初にPostgreSQL が立ち上がるとpostgresという名前のロールが作成されている。（これがスーパーユーザ。）
それで、postgresという名前のロールから他のロールに与える権限の管理を行う。


##ロールの作成
###新しくロールを作成する

```
CREATE ROLE 名前;
```

###コマンドプロンプトからcreateする

```
createuser 名前;
```


#ロールの属性
ロールの属性とは、ロールの権限を決めたり認証を行なうためのデータを設定したりするための属性のこと。

###ログイン権限
ログイン権限とはデータベースに接続することを可能にする権限のこと。ログイン権限を持つロールの名前を使ってデータベースに接続する。

```
CREATE ROLE 名前 LOGIN;
もしくは
CREATE USER 名前;
```
*CREATE USERで作成されたロールはログイン属性を持つが、CREATE ROLEだけではログイン属性は付かないので注意が必要。

また、ロールの属性を変更したい時は、ALTER ROLE SQLコマンドを使用する。

権限を与えるなら、

ALTER ROLE 名前 LOGIN;

一方、権限を取り去るには、

ALTER ROLE 名前 NOLOGIN;

とコマンドを叩けばOKだ。

#スーパーユーザ状態
スーパーユーザ状態はログイン以外に何でもできる権限をロールに与える。便利だが危険な場合もあるので、通常の操作ではスーパーユーザではない目的に応じたロールを使用することが推奨される。

このロールを作成するためのSQLコマンド

```
CREATE ROLE 名前 SUPERUSER;
```


ロールの属性を変更したい時は、ALTER ROLE SQLコマンドを使用する。

権限を与えるなら、

```
ALTER ROLE 名前 SUPERUSER;
```


権限を取り去るには、

```
ALTER ROLE 名前 NOSUPERUSER;
```




#データベース作成
データベース作成はデータベースを作成する権限をロールに与える。

```
CREATE ROLE 名前 CREATEDB;
```


また、ロールの属性を変更したい時は、ALTER ROLE SQLコマンドを使用する。

権限を与えるなら、

```
ALTER ROLE 名前 CREATEDB;
```

権限を取り去るには、

```
ALTER ROLE 名前 NOCREATEDB;
```


#ロール作成
ロール作成はロールを作成する権限をロールに与える。

```
CREATE ROLE 名前 CREATEROLE;
```


また、ロールの属性を変更したい時は、ALTER ROLE SQLコマンドを使用する。

```
ALTER ROLE 名前 CREATEROLE;
```

権限を取り去るには

```
ALTER ROLE 名前 NOCREATEROLE;
```


注意しなければならない点もある。ロール作成の権限ではロールを変更したり削除したりすることはできない。これらはスーパーユーザでなければできない.

#パスワード
パスワードはロールがデータベースに接続する時に要求される場合に必要な属性である。

```
CREATE ROLE 名前 PASSWORD 'パスワード';
```

また、ロールの属性を変更したい時は、ALTER ROLE SQLコマンドを使用する。

権限を与えるなら、

```
ALTER ROLE 名前 PASSWORD 'パスワード';
```

権限を取り去るには、

```
ALTER ROLE 名前PASSWORD NULL;
```


#権限
権限とは、ユーザがテーブルや関数などデータベースのオブジェクトを使用するためにロールに与えられるもの。オブジェクトが作成されると、そのオブジェクトの所有者が決まる。その所有者はオブジェクトを作成したロールだ。また、その所有者はオブジェクトに対してほとんどの権限を持つことになる。しかし、他のロールがオブジェクトにアクセスしようとすると、アクセスを可能にする権限が必要になる。もし、権限がなければアクセスは拒否される。

#権限を与える
権限には、SELECT、 INSERT、UPDATE、DELETE、TRUNCATE、REFERENCES、TRIGGER、CREATE、CONNECT、TEMPORARY、 EXECUTE、USAGEがある。これらの権限をロールに割り当てるために、GRANT SQLコマンドを使う。

```
GRANT 特権 ON テーブル名 TO ロール名;
```

##テーブルに対する権限の説明

###権限

```
SELECT
```

テーブル、ビュー、シーケンスの任意の列のデータを読み取ることを許可する。

```
INSERT
```

テーブルに行を追加することを許可する。

```
UPDATE
```

テーブルに対する更新を許可する。

```
DELETE
```

テーブルから行を削除することを許可する。

##まとめて権限を与える
権限を沢山のロールにひとつひとつ与えることを考えると気が遠くなる。そこで、権限をまとめてシステム内のすべてのロールに与えることができる。

GRANT SQLコマンドでPUBLICを使って、

```
GRANT 特権 ON テーブル名 TO PUBLIC;
```

また、まとめてすべての権限をロールに与える場合はGRANT SQLコマンドでALLを使う。

```
GRANT ALL ON テーブル名 TO ロール名;
```


権限を取り去る
与えられた権限を取り去るためにGRANT SQLコマンドを使う。

```
REVOKE 特権 ON テーブル名 FROM ロール名;
```


##ロールの削除
既に作成されたロールを削除するためには、DROP ROLE SQLコマンドを使って、

```
DROP ROLE 名前;
```

別の方法として、コマンドプロンプトからdropuserプログラムを使って、

```
dropuser 名前;
```
でも可能。

##ロールを確認する
既に作成されたロールはpg_rolesシステムカタログに登録されているので、その情報を表示すればよい。

登録済みのロールを確認するにはSELECT SQLコマンドを使って、

```
SELECT ROLNAME FROM pg_roles;
```


別の方法として、psqlの\duコマンドを使って、

```
\du
```
ロール属性と共に表示される。
ftpしか使えない時のディレクトリ削除、圧縮、解凍

# はじめに

今時、ssh接続ができないことなんてそうそうないはずなんですが、全くないわけではありません。
私はそんな時、基本的にftpクライアントソフトを利用して、ファイル操作を行っています。

しかし、ftp接続でファイル数のおおいディレクトリを削除しようとすると、非常に時間がかかってしまいます。
加えて、圧縮したり、解凍したりするのも少し不便です。

## 方法
(OSは、macOS、ftpクライアントソフトは、Cyber duckを利用しています。)

容量の大きなファイルを削除しても、すぐに消せることから、１ファイルごとに削除命令を出していることが、削除に時間がかかる要因だと思われます。

ftp側で早く削除するためにできることはなさそうなので、PHP(実行環境があり、コマンドが実行できるならどんな言語でもできるはず)でlinuxコマンドを実行して、削除することにしました。

```php
<?php
system('rm -rf 対象ディレクトリのpath');
```


## 圧縮・解凍について
ftpではファイルの圧縮、解凍も少し手間がかかります。(ftp単体だと出来ない様子)

*圧縮*

```php
<?php
system('tar -zcvf backup.tar.gz target_ directory');
```

*解凍*

```php
<?php
system('tar -zxvf backup.tar.gz');
```

### 余談 

macでtarボールを作る場合、通常、【._.hogehoge】というような余計な隠しファイルが作成されてしまいます。
以下のようにCOPYFILE_DISABLE=1を利用すると、これを回避できます。

```
COPYFILE_DISABLE=1 tar -zcvf test.tar.gz test
```
Cinnamonでシステム全体に拡張機能をインストールする方法

1. [ここ](https://cinnamon-spices.linuxmint.com/)から拡張機能をダウンロードする
2. zipファイルを展開する
3. `/usr/share/cinnamon/extensions`ディレクトリにコピーする
4. 完了

公式サイトにもどこにもシステム全体に入れる方法が無かったのでメモ

参考：[https://aur.archlinux.org/cgit/aur.git/tree/PKGBUILD?h=cinnamon-applet-global-appmenu](https://aur.archlinux.org/cgit/aur.git/tree/PKGBUILD?h=cinnamon-applet-global-appmenu)
【2020/07/30版】How to Windows Clean Install ? - Windows 10 をクリーンインストールした記録

Windowsをクリーンインストールした過程を自分用にまとめています。
キャプチャを取る方法が分からなかったので、画像なしです。

##経緯
中古PCをLinux用に購入しましたが、PCの性能が思いのほかによかったのでメインPCに変更することに決定しました。

ちなみに購入したPCはThinkPad L520という2011年頃に製造されたPCでメルカリで1万円くらいでしたが、メモリが8G ＆HDDが1TBでOSがWindows 10 Pro と明らかにカスタマイズされたものでした。

ヤフオクも探しましたが、美品かつメモリが8Gで最安のために購入しました。

閑話休題。
届いたPCの挙動に不審点があったので、クリーンインストールした苦労したので、クリーンインストールの過程を自分用に残しておきます。

※今回は特に書きませんが、**最初に必要なデータのバックアップをする**必要があります。データをバックアップしてから、以下のステップに進んでください。


##クリーンインストール方法
https://office-hack.com/windows/windows10-cleaninstall-usb/
基本的には上記のサイトに紹介されている通りに進めていけばOKです。

###Step 1：インストールメディアを用意する
容量8G以上あるUSBメモリを用意します。USBメモリは勝手にフォーマットされるので、重要なデータなどある場合はどこかに避難しておいてください。

**これを最初にやっておかないと、別なWindows PCが必要になるので注意してください。私はPCが3台あるので関係ないですが、念のため注意喚起しておきます。**

https://www.microsoft.com/ja-jp/software-download/windows10

上記のページアクセスして、【ツールを今すぐダウンロード】ボタンを押しWindowsのOSをダウンロードをします。

「USBフラッシュの準備ができました」まで進めます。

###Step 2：PCの起動をUSBメモリから最初に読み込むように変更する
BIOSメニューに入り、USBメモリを最初に読み込むように変更します。
PCによって変わるので詳細は機種名でググってください。

※今までの私の経験では「F1」「F8」「F10」「F12」キーのいずれかを開始直後に連打するとBiosメニューに入れます。
→今回は「F1」キーでBiosメニューに入り、`Security` の項目の中にありました。

###Step 3：USBメモリを刺したままで起動or再起動する
https://www.pasoble.jp/windows/10/088138.html#c4

上記のサイト通りに進めます。
パーティションをフォーマットしてから進んでいきます。

**超重要点：1**
今回のPCは古かったので、USBメモリを刺すポートが壊れていて、途中で勝手に再起動を繰り返すだけで3時間くらい浪費しました。
側面の2個ではダメだったので、背面のポートに刺すとエラーがなく進みましたので、勝手にシャットダウンする場合はUSBメモリを刺す場所を変えてみてください。

**超重要点：2**
サイトでは特に説明はありませんが、再起動する前にUSBメモリは抜いておきます。じゃないと、再度同じWindows10をインストールする画面という振り出しに戻ってしまいます。


##結論：バックアップとUSBメディアは先にやっておく
本文にはさらっとしか書いていませんが、バックアップとUSBメディアは先にやっておいてくださいね:bow_tone1:

以上、簡単ですが、Windows10をクリーンインストールする方法をご紹介しました。
自己紹介のnpxコマンド作ってみた

## モチベーション
npm配信で型,hooks,コンポーネントと経験したので、npxで動かすようなコマンドを作ってみたかった

が特にネタがなかったので、流行りの自分の名前のREAD.MEから思いついた

```index.ts
#!/usr/bin/env node
// ↑binで呼ばれる時にnodeで動かして欲しいので書く
const help = () => console.log(`
Usage: kodai3 <command>
where <command> is one of:
    help       what you see now
    ...
`)

const argv = process.argv.slice(2);
// 今回引数は一つしか対応しないので
if (argv.length !== 1) {
    help();
    process.exit(0);
}

switch (argv[0].toLocaleLowerCase()) {
    case 'help':
        help();
        process.exit(0);

    ...

    default:
        help();
        process.exit(0);
}
```

```package.json
{
 "main": "dist/index.js",
 "bin": {
     "kodai3": "dist/index.js",
 },
 "scripts": {
     "build": "yarn tsc",
 }
}
```
[bin](https://docs.npmjs.com/files/package.json#bin)が重要
install時に`.bin`以下にkeyで指定したコマンド名でスクリプトを作成してくれる
`tsc`で普通にcommonjsにして`publish`する

`npx kodai3 whoami`


## 注意
npmで配信すると、72時間以上立ったものは基本的に停止できなくなるのでセンシティブな情報は入れてはいけない
(snsアカウントはいっかと思って自分は入れた)
【Angular Material】Iconのテーマを切り替えたい。

## はじめに
[Angular Material Icon](https://material.angular.io/components/icon/overview) で [使えるアイコン一覧](https://material.io/resources/icons/?style=baseline)にはベースとなるものの他に「Outlined」「Rounded」「Two-Tone」「Sharp」というテーマが用意されている。
今回はこれの切り替え方について共有していく。

## 前提
すでに `ng add` コマンドでAngular Mateiralを導入した前提で進める。

## Google Fontsの読み込み
`index.html` の `<head></head>` 内にあるGoogle FontsのMaterial Iconのスタイルを読み込んでいる部分。

```html:index.html
  <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
```

ここに使いたいテーマを `|` でつないで追加する。
対応するリンクとテーマは以下。

| アイコンテーマ       | 追加するリンク              | 
|:-----------------|:------------------------|
| Outlined         | Material+Icons+Outlined |
| Rounded          | Material+Icons+Rounded  |
| Two-Tone         | Material+Icons+Two+Tone |
| Sharp            | Material+Icons+Sharp    |

(例)

```html
  <link href="https://fonts.googleapis.com/icon?family=Material+Icons|Material+Icons+Outlined|Material+Icons+Two+Tone" rel="stylesheet">
```

## アイコンにテーマを `fontSet` を指定
テーマを切り替えたいアイコンに `fontSet` を当てるだけで切り替わる。
対応するアイコンテーマと `fontSet` は以下。

| アイコンテーマ       | fontSet                 | 
|:-----------------|:------------------------|
| Outlined         | material-icons-outlined |
| Rounded          | material-icons-round    |
| Two-Tone         | material-icons-two-tone |
| Sharp            | material-icons-sharp    |

(例)

```html:example.component.html
<mat-icon>backup</mat-icon>
<mat-icon fontSet="material-icons-outlined">backup</mat-icon>
<mat-icon fontSet="material-icons-two-tone">backup</mat-icon>
```

結果、

<img width="207" alt="スクリーンショット 2020-07-30 21.16.22.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316318/90673074-6cb8-3f93-8b7d-aea8b4a2f6e7.png">

こんな感じにテーマが切り替わって表示される。

## 参考サイト
- [Icon font for the web](https://google.github.io/material-design-icons/#icon-font-for-the-web)
- [Issue - mat-icon: Choose between Filled, Outlined, Rounded, Two-Tone and Sharp icons;](https://github.com/angular/components/issues/14853#issuecomment-510482397)
初心者によるプログラミング学習ログ 386日目

#100日チャレンジの386日目
twitterの100日チャレンジ#タグ、#100DaysOfCode実施中です。
すでに100日超えましたが、継続。
100日チャレンジは、ぱぺまぺの中ではプログラミングに限らず継続学習のために使っています。
386日目は、
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">おはようございます<br>昨日の作業⇩<br><br>●就寝前筋トレ5分、キンドル読書 10分<br>●ブログ1記事作成<br>●プログラミング学習386日目 2h<br>・メンターの課題<br>・スライドショーの、背景画像の調整<a href="https://twitter.com/hashtag/%E9%A7%86%E3%81%91%E5%87%BA%E3%81%97%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E3%81%A8%E3%81%A4%E3%81%AA%E3%81%8C%E3%82%8A%E3%81%9F%E3%81%84?src=hash&amp;ref_src=twsrc%5Etfw">#駆け出しエンジニアとつながりたい</a><a href="https://twitter.com/hashtag/100DaysOfCode?src=hash&amp;ref_src=twsrc%5Etfw">#100DaysOfCode</a><a href="https://twitter.com/hashtag/%E6%97%A9%E8%B5%B7%E3%81%8D%E3%83%81%E3%83%A3%E3%83%AC%E3%83%B3%E3%82%B8?src=hash&amp;ref_src=twsrc%5Etfw">#早起きチャレンジ</a></p>&mdash; ぱぺまぺ@社畜✕投資✕ブロガー (@ppmp65) <a href="https://twitter.com/ppmp65/status/1288564923950182400?ref_src=twsrc%5Etfw">July 29, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
postgres sqlコマンド　自分用

#postgresqlよく使うコマンド
※#から始まるコマンドはpsql内で、$から始まるコマンドはpsql外で実行するコマンドとなる。

##バージョンを確認する

```
$ psql —version
# select version();　
```

##ヘルプを表示

```
$ psql --help
# \?
# \h
```

#データベース 

##データベースに入る

```
$ psql <DB_NAME>
```


##ユーザーを指定してデータベースに入る

```
$ psql -U <USER_NAME> <DB_NAME>
```

##データベースから出る

```
# \q
```

##データベースを起動

```
$ postgres -D /usr/local/var/postgres
```

##データベース一覧表示

```
$ psql -l
# \l
```

##データベースの切り替え

```
# \c <DB_NAME>
# \connect <DB_NAME>
```

##データベースを削除

```
# drop database <DATABASE_NAME>;
```

##テーブル テーブル一覧表示(viewやsequenceも含む)

```
# \d
```

##テーブル一覧表示

```
# \dt
```

##テーブルのスキーマの詳細を表示

```
# \d <TABLE_NAME>
```

##テーブルのアクセス権限表示

```
# \z <TABLE_NAME>
```

##viewの一覧を表示

```
# \dv
```

##viewの定義を表示

```
# select definition from pg_views where viewname = '<VIEW_NAME>';
```

##テーブル名変更

```
# alter table <CURRENT_DB_NAME> rename to <NEW_DB_NAME>;
```

##テーブルを削除

```
# drop table <TABLE_NAME>;
```

#ユーザー権限

##現在のユーザー(Role)を表示

```
# select current_user;
```

##ユーザー(Role)の一覧を表示

```
# \du
```

##ユーザー情報一覧を表示

```
# select * from pg_user;
```

##ユーザー (Role)に権限を付与

```
# grant select, insert, update, delete on <TABLE_NAME> to <USER_NAME>;
```

##ユーザー (Role)に権限を剥奪

```
# revoke select, insert, update, delete on <TABLE_NAME>　from <USER_NAME>;
```

##ユーザーの切り替え

```
# \connect - <USER_NAME>
```

##スーパーユーザーへ変更

```
# alter role <USER_NAME> with creatural superuser;
```

##スーパーユーザー権限剥奪

```
# alter role <USER_NAME> with creatural nosuperuser;
```

#スキーマ
##スキーマ作成

```
# create schema <schema_name>;
```

##スキーマを確認

```
# select current_schema;
```

##スキーマ一覧

```
# \dn
```

##スキーマ変更

```
# set search_path to <schema_name>;
```

#pg起動

```
# sudo systemctl start postgresql
```
#pg停止

```
# sudo systemctl stop postgresql
```
#pg起動の確認
```
# sudo systemctl status postgresql
```
cloud functionをwebpackでバンドルする環境(TS)

## モチベーション
- 相応数のCFを使うようなプロジェクトに膨れてきたのでバンドルサイズを下げてbuildの速度向上とデプロイの安定化
- node10以降するにあたってついでに改善する

```index.ts
const functions = {
   name: 'path/to/file',
   ...
}

for (let func in functions) {
    if (!process.env.K_SERVICE || process.env.K_SERVICE === name) {
      exports[func] = require(`./funcs/${functions[func]}`);
    }
}

```
環境変数K_SERVICEはnode10以上

```babel.rc
{
  "presets": [
    [
      "@babel/preset-env",
      {
        "useBuiltIns": "usage",
        "corejs": 3,
        "targets": {
          "node": "10"
        }
      }
    ],
    "@babel/preset-typescript"
  ]
}

```
```webpack.config.js
const nodeExternals = require('webpack-node-externals');
const GenerateJsonPlugin = require('generate-json-webpack-plugin');
const path = require('path');

module.exports = {
  target: 'node',
  mode: process.env.NODE_ENV,
  entry: './index.ts',
  output: {
    filename: 'index.js',
    path: `${__dirname}/dist`,
    libraryTarget: 'commonjs',
  },
  plugins: [
    // deployに必要なのでdistにコピー
    new GenerateJsonPlugin('package.json', require('./package')),
  ],
  module: {
    rules: [
      {
        test: /\.ts$/,
        use: 'ts-loader',
        exclude: /node_modules/,
      },
    ],
  },
  resolve: {
    extensions: ['.ts', '.js', '.json'],
    alias: {
      root: __dirname,
      funcs: path.resolve(__dirname, 'funcs'),
    },
  },
  externals: [nodeExternals()],
};

```
```package.json
{
  "engines": {
    "node": "10"
  },
  "scripts": {
    "deploy": "yarn run build && firebase deploy --only functions",
    "build": "NODE_ENV=production webpack  && cp .npmrc ./dist/.npmrc",
  },
}
```

個別、一括のデプロイどちらも正常に動作します。
ベータ版としてNode12がサポートされましたが、自分の環境では各ファイル10->12に変更するだけで動作しているようでした
タイムボックス・ストーミング　議論を効率よく進める為のプラクティス

議論が白熱したり、話題が迷走してして、気が付くと時間が経ってしまったり。ファシリテートが下手で効率的な議論・ミーティングが出来ないといた状況を改善できる方法をお伝えします。
**タイムボックス・ストーミング**とはその名が示す通り、議論・ミーティングを**予め決めたタイムボックス**で実施し、その後、議論・ミーティングの内容・参加姿勢・発言量など多方面から**振り返り（KPTをお勧めします）**、次の議論・ミーティングで行う**改善点**を決め、リフレッシュして、次のサイクルの議論・ミーティングを行う方法です。
**議論・ミーティングに集中**、**客観的振り返り改善**、リフレッシュの夫々タイムボックスとし1クールを30分と区切って進めます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621379/4962119a-a894-b0a7-c323-0b3d82e447f6.png)

この方法を採用すると、白熱せず、迷走せず、効率よく議論・ミーティングを実施できます。
1クールの30分は決めではなく、それよりも小さいタイムボックスで運用できます。
コツは議論のタイムボックスを短くすることです。
PowerShellのPSCustomObjectで変数の名前(NoteProperty)を書き換える

個人の備忘です。毎回調べなおすのツラいので。

### やりたいこと

`Import-CSV`等でファイルを読み込んだあとのPSCustomObjectの列名(NoteProperty)はRead-Onlyだが、`Write-SQLTableData`に渡す時にデータベーステーブルの列名と合わせる必要がありなんとかして列名を変えたい。オブジェクトのコピーはメモリを圧迫するのでしたくない。

### 実現方法

いろいろ試したが、`Select-Object`で集計プロパティ***(@{Name=Foo;Expression={$_.Bar}})***を活用して出力し、オブジェクト上書きするのが一番楽。だがスクリプトブロックを文字列にして`Invoke-Expression`する必要がある。（私がヘボいだけで他に方法があるのかもしれない）

```powershell:sample.ps1
# CSV読み込み
$temp = Get-Content $file -encoding UTF8 | ConvertFrom-CSV

# 現在のプロパティ名をリストする
$null = ( $temp | get-member -force | Where-Object{ $_.name -eq "psextended" } | ForEach-Object { $_.definition } ) -match "psextended {(.+)}"
$cols = $matches[1] -split ", "

$newcols = @("a","b","c") #新しい列名

# 新しいカラム順に内容を並べ替えて$tempを書き換える
$cnt = 0
$buff = "`$temp = `$temp | Select-Object "
foreach($col in $newcols) {
    if ($cnt -ne 0) { $buff = $buff + ","}
    $buff = $buff + " @{Name='$($headers[$cnt])';Expression={`$_.`"$col`"}}"
    $cnt++
}
$buff = $buff + ""
Invoke-Expression $buff
```

### 愚痴

PSCustomObjectは優秀なんだけど、DataFrame的に使うのは難しい。

Write-SQLTableData()にはSystem.Data.DataTableも渡せるよう[(*リンク)](https://docs.microsoft.com/en-us/powershell/module/sqlserver/write-sqltabledata?view=sqlserver-ps)なので、今後はDataTableに読み込ませるようにしようかな。。。
heroku×node.jsでcorsエラーがなかなか解決しないときに気をつけること

node.js（express）でサーバーサイドを記述し、herokuに上げていたのですが、今まではすんなりと解消できていたcorsのエラーに嵌ってしまったので、記事を書くことにしました。
# 環境
- heroku: 7.42.5
- node.js: 12.16.2
- express: 4.17.1
- cors: 2.8.5

# 基本的な対応方法
今回はサーバーサイドとフロントエンドを異なるレポジトリに書いているため、フロントエンドからfetch等でサーバーサイドのAPIを呼ぶ際には、corsのエラーが生じてしまいます。
>Access to fetch at 'https://xxx.com' from origin 'https://yyy.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

基本的には`npm install cors`をして、

```
const express = require('express')
const cors = require('cors')
const app = express()
app.use(cors())
```

と書けば解決します。
# 注意点① - credentialsをtrueにする場合
ただ、credentialsをtrueとしたい場合には、originを具体的に指定する必要があります。

```
const express = require('express')
const cors = require("cors");
const app = express();
const corsOption = {
  origin: [
    "http://xxx.com",
    "https://yyy.com",
  ],
  credentials: true,
};
app.use(cors(corsOption));

```
というようにします。
originは、1つの場合は配列なしの文字列でも大丈夫で、1つにしろ複数にしろ正規表現を用いることもできます。
ここまでは、ぐぐると色々な解説が出てくると思うのですが、今回はさらに二重に嵌ってしまっていました。
# 注意点② - 最後の"/"
1つめは、originの最後に"/"を入れてしまっていたことです。
本来は`"http://xxx.com"`としなければいけないところを、アドレスバーからコピペするなどして、`"http://xxx.com/"`としてしまうと、エラーが生じます。
# 注意点③ - herokuのconfig varsが登録されていない
2つめは、herokuのconfig varsが登録されていなかったということです。
かなり初歩的なミスなのですが、例えば、`process.env.TEST_KEY`みたいなコードを書いていたとして、ローカルでは.envの変数を参照していたとします。
当然、herokuではconfig varsに`TEST_KEY`を登録しなければいけないのですが、必要なキーなどを参照できなかった場合も、corsのエラー同様のメッセージが表示されてしまうため、数時間を無駄にしてしまいました。
皆様もお気をつけください。
# 参考
[Express cors middleware](https://expressjs.com/en/resources/middleware/cors.html)
[Nodejs express, Heroku CORS](https://stackoverflow.com/questions/43915577/nodejs-express-heroku-cors)
【Sinatra】エラー解決 Rack::Flash::SessionUnavailable at /

###はじめに
この記事の内容はSintaraでの開発中、rack-flash3を使ってフラッシュを表示させようとした時に発生した下記エラー、

`Rack::Flash::SessionUnavailable at /`
`Rack::Flash depends on session middleware.`

の解決方法について学んだ事を記しています。



###解決への道のり

エラーを出したソースコードはこちら↓

```rb

require "rack-flash"

use Rack::Flash
```

エラー文は***Rack::Flashのセッションが利用できません、Rack::Flashはセッションミドルウェアに依存していますよ！***ってな感じに訳せるかと思います。

という事でメンターさんにも聞いたりもしつつ、いろいろ調べて、READMEを見ていたら、ヒントがありました！

>参考、引用）https://github.com/nakajima/rack-flash

>If you're using Sinatra, you can use the flash hash just like in Rails:
（訳）Sinatraで使うとRailsと同じようにフラッシュハッシュを使えますよー、だと思う

>```rb

>#省略

>require 'rack-flash'
#省略
>enable :sessions
>use Rack::Flash

>#省略
>```

`enable :sessions`のところがセッションというワードが出てきてます、もしかしてこれ？

###`enable :sessions`とは、、、

実はSinatraではデフォルトでRackのセッション機能は無効化されているらしいです、
そして、`enable :sessions`はセッションを有効にするための指定らしいです！

なるほどおお、絶対これだ！と思い、問題のコードに書き加えてページ更新してみました、、、がまたもエラー！

どうやら、、、

***サーバーを再起動しないとなおりません！***

この事に気づかず、僕はここからまた迷走してました笑

サーバーを再起動して無事解決〜♪

###考察、学び

- おそらく、Rack-flashはセッションを使ってフラッシュを保存している
- Sinatraはセッション機能が無効化されていて、`enable :sessions`を書いてサーバーを再起動しないと有効化されない
- 再起動をしてみる、という事の大事さ

勉強になりました!
Railsでslimを使う

#プログラミングの勉強日記
2020年7月30日　Progate Lv.226

#概要
　[こちらの記事](https://qiita.com/mzmz__02/items/61423e7259c4624f3010)で扱ったgemのslimを説明する。slimはHTMLよりもコードを早くきれいにシンプルに書ける。erbと同じで、Rubyを埋め込むこともできる。Hamlと似ていて、slimには閉じタグが存在しないので、コードを簡単かつすっきり書くことができる。

#使い方
　slimを使うためにGemfileを編集する。

```:Gemfile
gem 'slim-rails'
```
　Gemfileを編集したら、hamlをインストールする。

```:ターミナル
bundle install
```

　これで、`index.html.slim`といったビューファイルの拡張子に`slim`を使えるようになる。

##すでにあるerbファイルをslimファイルに変えたい場合

```:Gemfile
gem 'html2slim'
```

```:ターミナル
# erbファイルを残して変換
erb2slim 変換するファイルがあるフォルダまたはファイル名

# erbを削除して変換
erb2slim 変換するファイルがあるフォルダまたはファイル名 -d
```

#基本的な書き方
 slimタグには閉じタグが必要ない。代わりにインデントを使ってマークアップする箇所を指定する。インデントはそろえる必要がある。（3つのスペースを使ったらその後も3つスペースに、4つスペースを使ったらそのあとも4つスペースに）

```slim:slim
doctype html
div
  h1 Hello World!
  ul
    li Ruby
    li Rails
    li HTML
```

　HTMLで以下のように変換されている

```html:html
<!DOCTYPE html>
<div>
  <h1>Hello World!</h1>
  <ul>
    <li>Ruby</li>
    <li>Rails</li>
    <li>HTML</li>
  </ul>
</div>
```

#slimの書き方

##各タグの書き方

| slimでの書き方     |   コンパイル後のコード(HTML) |  
|:-----------------:|:------------------:|
|  `div`  |  `<div></div>`  |
|  `html` |  `<html></html>`  |
|  `meta` |  `<meta></meta>`  |
|  `header`  |  `<header></header>`  |
|  `footer`  |  `<footer></footer>`  |
|  `table`  |  `<table></table>`  |
|  `h1`  |  `<h1></h1>`  |
|  `p`  |  `<p></p>`  |
|  `a`  |  `<a></a>`  |
|  `ul`  |  `<ul></ul>`  |
|  `li`  |  `<li></li>`  |

##テキストの書き方
　テキストは`|`で定義する。

```slim:slim
p
  |  Hello World

/複数行の場合（改行なし）
p
  |
    こんにちは。
    私の名前は田中太郎です。

/複数行の場合（改行あり）
p
  |
    こんにちは。<br>
    私の名前は田中太郎です。
```

 HTMLでは以下のように変換されている

```html:html
<p>Hello World</p>

<p>こんにちは。
   私の名前は田中太郎です。</p>

<p>こんにちは。<br>
   私の名前は田中太郎です。</p>
```

##属性の書き方
　
```slim:slim
a href='http://www~' リンク先の名前
```
　HTMLでは以下のように変換されている

```html:html
<a href="http://www~">リンク先の名前</a>
```

##IDとclassの書き方
 `div`を省略することができる。

```haml:haml
#id_name
  idを指定する

div.class_name
  classを指定する

.class_name
  classを指定する
```

　HTMLでは以下のように変換されている

```html:html
<div id="id_name">idを指定する</div>

<div class="class_name">classを指定する</div>

<div class="class_name">classを指定する</div>
```
事前にデータ投入をしたMySQL Docker containerを作成したいが、/docker-entrypoint-initdb.dで毎回実行時にimportするには時間がかかりすぎる。予めimageに含めてしまおう。

事前にデータが投入されたMySQLのDocker containerを作る方法は[MySQL | Docker Hub](https://hub.docker.com/_/mysql)に書かれているように、

> Initializing a fresh instance
When a container is started for the first time, a new database with the specified name will be created and initialized with the provided configuration variables. Furthermore, it will execute files with extensions .sh, .sql and .sql.gz that are found in /docker-entrypoint-initdb.d. Files will be executed in alphabetical order. You can easily populate your mysql services by mounting a SQL dump into that directory and provide custom images with contributed data. SQL files will be imported by default to the database specified by the MYSQL_DATABASE variable.

`/docker-entrypoint-initdb.d`にsqlファイルをおいておけば実行時によしなにimportしてくれる。

ただ、自分のプロジェクトでは大きめのsqlをimportする必要があり、実行時にimportするのでは時間がかかりすぎるので、予めimageにimportしておくことにした。


```:Dockerfile
FROM mysql:5.7

COPY test.sql /tmp/
RUN /bin/bash -c "/usr/bin/mysqld_safe --skip-grant-tables &" \
  && sleep 5 \
  && mysql -u root -e "CREATE DATABASE test" \
  && mysql -u root test < /tmp/test.sql \
  && rm -rf /tmp/test.sql
```

## 参考

- [MySQL | Docker Hub](https://hub.docker.com/_/mysql)
- [mysql/docker-entrypoint.sh at master · docker-library/mysql · GitHub](https://github.com/docker-library/mysql/blob/master/5.7/docker-entrypoint.sh)
- [事前にデータ投入をした MySQL Docker イメージを作る場合は /docker-entrypoint-initdb.d を活用すると便利 - kakakakakku blog](https://kakakakakku.hatenablog.com/entry/2017/11/08/193031)
- [docker - Setting up MySQL and importing dump within Dockerfile - Stack Overflow](https://stackoverflow.com/questions/25920029/setting-up-mysql-and-importing-dump-within-dockerfile)
anvil-app-serverでcertificate verify failed。

<h2>前書き</h2>
以前、[Anvil](https://anvil.works/)を触ったのですが、ドキュメントを読み進めると、ローカルに実行環境を作ることができるようで、試しました。
が、素直に動作してくれず、ようやく動作させられたのでメモ。

<h4>参考</h4>
- [Anvil をローカル実行する](https://qiita.com/satamame/items/df9f5bc6c85a0976fee4)
- [[youtube-dl] python3のSSLエラー(CERTIFICATE_VERIFY_FAILED)](https://qiita.com/tommy19970714/items/96edba36dfde468e26f3)
- [Anvil Runtime and App Server](https://github.com/anvil-works/anvil-runtime)

<h2>環境</h2>
- Ubuntu 20.04 LTS 日本語 Remix
- Hyper-V マネージャー 10.0.18362.1
- Python 3.8.5
- pip 20.2
- anvil-app-server 1.1

<h2>経過</h2>
- anvil-app-serverのインストール

```bash
pip install anvil-app-server
```

- テンプレートからアプリを作成

```bash
create-anvil-app hello-world hello
```

- anvil-app-serverの実行

```bash
anvil-app-server --app hello
```
で、エラー

```
Downloading Anvil App Server JAR to package directory
Failed to download App Server to package directory. Retrying in ~/.anvil
(略)
urllib.error.URLError: <urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1123)>
```

<h2>対処方法</h2>
1か2どちらかを実施すればOK。

1. ブラウザでjarファイルを取得し、指定のディレクトリにコピーする。
    1. [こちら](https://qiita.com/satamame/items/df9f5bc6c85a0976fee4)の手順に則って、ファイルをダウンロード。
    2. `$(HOME)/.local/python3.8/site-packages/anvil_app_server`ディレクトリにダウンロードしたファイルをコピー。
2. SSL_CERT_FILE環境変数を追加する。
    1. [こちら](https://qiita.com/tommy19970714/items/96edba36dfde468e26f3)の手順に則って、証明書ファイル(cacert.pem)の場所を探す。
    2. 環境変数`SSL_CERT_FILE`を設定する。

再度、anvil-app-serverを実行したところ、どうにか動作しました。
※対象のファイルが230MBほどあるので、ダウンロードに時間がかかる場合があります。
![Screenshot_2020-07-30 My App.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/667657/47821fcc-5694-1118-b444-8862d015846d.png)

<h2>後書き</h2>
対象のjarファイルは一度ダウンロードできればよいので、どちらの方法もありと思います。
ただ、取得元のURLがファイルに直書きされているので、「jarファイルだけがアプデされたら、更新どうするだろう」って感じもする作りなのは気にかかる点ですかね。
-webkit とかついたCSSセレクタをグループ化（カンマ区切りで複数まとめて指定）すると突然効かなくなる

```.css
:-webkit-full-screen,:fullscreen {
  height: 100%
}
```

一見問題なさそうじゃん？
ところがこれ、Firefox( `:fullscreen`, `:-moz-full-screen` には対応してる）でも
Safari( `:-webkit-full-scree` には対応してる)でも動かないんだな

ちなみにIEは `-ms-fullscreen` らしい

[CSS セレクタ、グループ化の落とし穴: 我的春秋](http://my-chunqiu.cocolog-nifty.com/blog/2006/05/css__39f1.html)

> グループ化したセレクタ群の中に、ひとつでも閲覧中のブラウザが未対応のセレクタを含むと、グループ化したほかのセレクタまで無効化されてしまって、グループ化したブロックのスタイルが適用されなくなってしまうみたいです。

なんか仕様らしい。

```.css
:-webkit-full-screen {
  height: 100%
}

:fullscreen {
  height: 100%
}
```

こう直しましょう。

## 余談: ベンダープレフィックス付きのスタイル一緒にしてたよ？
セレクタじゃなくてスタイルは対応してないものについては無視されるので大丈夫

```
.hoge{
  -webkit-transition:all 0.2s ease 0s;
  -moz-transition:all 0.2s ease 0s;
  -o-transition:all 0.2s ease 0s;
  transition:all 0.2s ease 0s;
}
```
[PHP]西暦を和暦に変換する 

何度か西暦を和暦に変換する処理を書く機会があったので、
また必要になった時に汎用的に使い回せるよう、関数を作成しました。

なお、日本では明治5年12月2日(西暦1872年12月31日)に旧暦(天保暦)を廃止し、その翌日からグレゴリオ暦に移行して明治6年(1873年)1月1日になったため、明治5年以前の日付には対応していません。
※明治５年以前の場合は西暦で返します。

```php

/**
 * 西暦→和暦変換
 *
 * @param string $format 'K':元号
 *                       'k':元号略称
 *                       'Q':元号(英語表記)
 *                       'q':元号略称(英語表記)
 *                       'X':和暦年(前ゼロ表記)
 *                       'x':和暦年
 * @param string $time 変換対象となる日付(西暦)‎
 *
 * @return string $result 変換後の日付(和暦)‎
 */
function to_wareki($format, $time='now')
{
    // 元号一覧
    $era_list = [
        // 令和(2019年5月1日〜)
        [
            'jp' => '令和', 'jp_abbr' => '令',
            'en' => 'Reiwa', 'en_abbr' => 'R',
            'time' => '20190501'
        ],
        // 平成(1989年1月8日〜)
        [
            'jp' => '平成', 'jp_abbr' => '平',
            'en' => 'Heisei', 'en_abbr' => 'H',
            'time' => '19890108'
        ],
        // 昭和(1926年12月25日〜)
        [
            'jp' => '昭和', 'jp_abbr' => '昭',
            'en' => 'Showa', 'en_abbr' => 'S',
            'time' => '19261225'
        ],
        // 大正(1912年7月30日〜)
        [
            'jp' => '大正', 'jp_abbr' => '大',
            'en' => 'Taisho', 'en_abbr' => 'T',
            'time' => '19120730'
        ],
        // 明治(1873年1月1日〜)
        // ※明治5年以前は旧暦を使用していたため、明治6年以降から対応
        [
            'jp' => '明治', 'jp_abbr' => '明',
            'en' => 'Meiji', 'en_abbr' => 'M',
            'time' => '18730101'
        ],
    ];

    $dt = new DateTime($time);

    $format_K = '';
    $format_k = '';
    $format_Q = '';
    $format_q = '';
    $format_X = $dt->format('Y');
    $format_x = $dt->format('y');

    foreach ($era_list as $era) {
        $dt_era = new DateTime($era['time']);
        if ($dt->format('Ymd') >= $dt_era->format('Ymd')) {
            $format_K = $era['jp'];
            $format_k = $era['jp_abbr'];
            $format_Q = $era['en'];
            $format_q = $era['en_abbr'];
            $format_X = sprintf('%02d', $format_x = $dt->format('Y') - $dt_era->format('Y') + 1);
            break;
        }
    }

    $result = '';

    foreach (str_split($format) as $val) {
        // フォーマットが指定されていれば置換する
        if (isset(${"format_{$val}"})) {
            $result .= ${"format_{$val}"};
        } else {
            $result .= $dt->format($val);
        }
    }

    return $result;
}
```
作成した関数を使って、和暦に変換してみます。

```php
echo to_wareki('KX年m月d日', '18730101').PHP_EOL;
echo to_wareki('kx/n/j', '1914/08/07').PHP_EOL;
echo to_wareki('Qx-m-d', '1947-05-16').PHP_EOL;
echo to_wareki('m/d/Y(qX) H:i:s', '2016-03-20 12:34:56').PHP_EOL;
echo to_wareki('Y(Kx)年n月j日');
```
出力結果は以下の通りです。

```html
明治06年01月01日
大3/8/7
Showa22-05-16
03/20/2016(H28) 12:34:56
2020(令和2)年7月30日
```

和暦変換プログラム自体はとくに目新しさはないですが、色々なフォーマットに対応できるようにしてみました。
もしよかったらぜひ試してみてください。
Fake Sendmailってなに？？

#背景
　最近、LANで動いているサイトのPHPソースからGoogleメールを送信しなければならない状況になりました。その時に色々調べていく中で、「Fake Sendmail」なるものを使って実現しました。今回は、Fake Sendmailがどんなものなのかを理解した範囲で記事にまとめます。
　自分なりの理解なので間違ってることがあるかもしれません。注意してください。また、サーバーに対してある程度知識がある人でないと何言ってるか分からないかもしれません。

#SMTPサーバーとは？
　まず、Fake Sendmailを理解する上で、SMTPサーバーの理解は避けられません。SMTPサーバーとは、、、

>
SMTPには主に以下の2つの役割があります。
①メーラーからメールを受け取る
②宛先のメールアドレスから、相手側のメールサーバーを見つけてメールを転送する

引用先：https://sendgrid.kke.co.jp/blog/?p=11638

とあります。メーラーは、パソコン上にあるメールソフトの事を指します（OutlookとかChromeで開いたGmailとか）

つまり、SMTPサーバーはどっかのパソコンから「メール」を受け取って、そのメールの宛先へ「メール」を転送する役割を持っています。

#GmailのSMTPサーバー
　今回はGoogleのSMTPサーバーに接続することを前提としていますが、一般的にSMTPサーバーが受け入れ可能としているポート番号は25・465・587番としています。このうち、465番ではSSLによる通信、587はTSLによる通信を約束しており、それが出来ないメーラーとは通信できません。（25番では暗号化が必要されません）
![図1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554112/c409a224-723a-e9b3-1475-1850241f3efd.png)
　
　GoogleのSMTPサーバーでは、25番の接続を禁止しています。かっこにも書いたように、25番の通信は安全でないので、暗号化される465番と587番のみを許可しています。また、このサーバーはドメイン名「smtp.gmail.com」でアクセスできます。
![q2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554112/b5f03037-0669-1cb6-4a15-70d43e6e7452.png)

#Fake Sendmailで行っている事
　次にFake Sendmailで実際に行っている事を書いていきます。まず、Fake Sendmailを使うときに、「sendmail.ini」をいくつか書き換えましたよね？主に以下の内容を設定していたのです。

* 接続先のアドレス：smtp.gmail.com
* 接続時のポート番号：587（465でもオッケー）
* アカウント情報：ユーザー名（user@gmail.comの形式）とパスワード（user@gmail.comにアクセスする際のパスワード）
![図3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554112/53aaf4d5-ba27-854e-64c2-89fafa115dea.png)
　この情報からも察せるように、Fake Semdmailでは、「すでに構築されたSMTPサーバー（今回はsmtp.gmail.com）へ接続し、メールを送信する」という事をします。（図の例は465番ポートを使用した場合）
![図4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554112/c0c3b47e-0f37-f7a9-c169-5f8d568eb959.png)
　そして、メールを転送するのですが、その際にGmailの「どのアカウントで送信するか」をuser@gmail.comで指定し、パスワードも一緒に送信します。もし、そのアカウント情報が正しければ、SMTPサーバー(smtp.gmail.com)はメール内容を受け取ってくれます。
![図5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554112/7e389d54-cd94-6606-f824-1f4c0bafdaf1.png)
　しかし、アカウント情報が正しくなければ、エラーログを返します。（設定によってログを出すようにする）
![図6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554112/2e9b75f3-3091-1b1d-0219-22ab68482f54.png)
　正しくsmtp.gmail.comへ転送されたメールは、送信元アカウントuser@gmail.comとして、Gmailがメール内容に書かれている宛先へ、送信されます。これがFake Sendmailが行っている事です。
![図7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554112/5524f446-8772-bffe-157b-b2b746576e86.png)

#おわりに
　ポイントとしては「自分でメールサーバーを立てていない」という事です。XamppでFake Sendmailを使っていたのですが、これを理解するまで「Mercury Mailインストールしたけど、Fake Sendmail使う必要あるのかなぁ。。。」とか思っていました。Fake Sendmailを使う事で、LANで構築されるメールサーバーMercury Mailを使わなくてもよくなる、って事ですね。

それでは！
Docker コンテナを構築して altair から png 保存する

私は長い試行錯誤を要したので成果だけでもアップしておく。`chromedriver-binary` の最新版を入れたら `google-chrome-stable` よりメジャーバージョンが大きくてエラーが出た。Chrome 側で `stable` 以外を使ってもよさそうだが、Chrome に `chromedriver-binary` を合わせることにした。

```Dockerfile:Dockerfile
FROM python

# Chrome のインストール
RUN wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add && \
    echo 'deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main' | tee /etc/apt/sources.list.d/google-chrome.list && \
    apt update && apt install -y google-chrome-stable

WORKDIR /python
COPY requirements.txt .
# chromedriver-binary のメジャーバージョンを Chrome に合わせる
#     google-chrome --version: "Google Chrome 0.0.0.0" のような文字列を返す
#     grep --only-matching:    (各行で) マッチした部分のみを順にすべて返す
#     head -n 1:               メジャーバージョンだけとってくる
#     sed --in-place:          私は知らなかった
RUN sed -e s/chromedriver-binary/chromedriver-binary==`google-chrome --version | grep -o -E "[0-9]*" | head -n 1`.*/ -i requirements.txt

RUN pip install --upgrade pip && pip install -r requirements.txt
```

```requirements.txt
altair
altair_saver
chromedriver-binary
jupyter
matplotlib
numpy
pandas
scipy==1.5
selenium
```

タイトルに関係あるのは `altair`, `altair_saver`, `chromedriver-binary`, `selenium` のはず。

```python:main.py
import altair
import chromedriver_binary              # import によって PATH が通る; モジュールとしては使わない
altair.renderers.enable('altair_saver') # 公式ドキュメントにはフォーマットを指定する引数があったが、怒られたので外した
altair.Chart(...).....save('plot.png')  # 成功した
```
jQueryでDOMを操作するメソッドについて

#前提(jQueryとは?)
Javascriptのライブラリの一種で、Javascriptを使いやすくする為に上から被せるようなもの。
Javascriptで書くと長くなるスクリプトを短くしたり、clickした後のアクションやイベントを作れる。
当然だが、jQueryを使うためには、ライブラリを読み込む必要がある。

#CDN(Content Delivery NetWork)の読み込みについて
インターネット経由でファイルを配信する仕組み。URLを指定することによってそのまま参照できるので
ファイルをダウンロードする必要がなくなる。
また、ユーザー側でも複数のサイトで同じjQueryのバージョンを使っていたらキャッシュの読み込みで
ページの読み込み時間を省略できる事もメリット。

定義するときは以下のように定義する。

```index.html
<body>
....
<script src="https://code.jquery.com/jquery-3.5.1.js"></script>

<script>
 ... // jQuery本文
...
</script>
```

#メソッド一覧(順次追加予定)
| No | メソッド | 意味 |
|:-:|:-:|:-:|
| 1  | append()  | 指定した子要素にテキストやHTML要素を追加  |
| 2  | prepend()  | 指定の要素内に文字列やHTML要素を追加  |
| 2  | prepend()  | 複数の要素を先頭に追加  |
| 3  | before()  | 指定した要素の前に追加する  |
| 4  | replaceWith()  | 別の要素を指定要素に置換する  |
| 5  | remove()  | 指定した要素を削除する  |
| 6  | find()  | 指定された要素を検索する  |
| 7  | text()  | HTML要素内にあるテキスト情報を取得、変更する  |
| 8  | empty()  | 要素の中身を削除する  |
| 9  | after()  | 指定した要素の後に追加する  |
| 10  | attr()  | 属性を取得、変更、追加する  |

##サンプルコード

```index.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="utf-8">
    <title>Title</title>
    <style>
        .replace {
            color: red;
        }
        .replaceNot {
            color: black;
        }
        .replacetarget {
            color: black;
        }
        .empty {
            background-color: skyblue;
        }
    </style>

</head>
<body>
    <ul class="category">
        <li class="name">項目1</li>
        <li>項目2</li>
    </ul>

    <div class="text">
    </div>

    <div id="target">
        <p>一つ前に追加</p>
    </div>

    <button class="click">クリック</button>
    <div class="replacetarget">divタグが置換</div>
    <div class="replaceNot">divタグ置換不可</div>
    <div class="remove">このdivタグはボタンを押したら削除</div>
    <div class="empty" style="padding: 10px">
        <span>ここは消えますが色は残ります</span>
    </div><br>

    <button class="addclass">更新</button>
    <div id="find">
        <input type="text" size="50" value="更新ボタンを押してください">
    </div>

    <script src="https://code.jquery.com/jquery-3.5.1.js"></script>

<script>
    $('ul.class').append('<li>項目3</li>'); // li要素を追加する
    $('li.name').prepend('<strong>名前</strong>'); // li要素のテキストを強調する
    $('div.text').prepend('<p>タイトル</p>','<p>テキスト</p>'); // 指定要素の中にp要素を追加する
    $('div#target').before('<div class="before"><span>新しく追加</span></div>'); // 指定要素の前に追加する
    $('button.click').click(function() { // クリックボタンを押したらテキストを更新する
        let replaceTo = '<div class="replace">置換完了</div>';
        $('div.replacetarget').replaceWith(replaceTo); // 不要部分を書き換える
        $('div.remove').remove(); // タグと要素を全て削除
        $('div.empty').empty(); // 要素だけ削除
    });
    $('button.addclass').click(function() { // ク更新ボタンを押したらテキスト内容を書き換える
        $('div#find').find('input[type="text"]').attr('value','テキストを更新しました');

    });

</script>

</body>
</html>
```
右クリックと左クリックで画像を指定フォルダに移動させてみた

#はじめに
　楽に画像を分類できればなーと考えながら作りました。

#作ったもの
　右クリックと左クリックで画像を指定フォルダに移動させるプログラムを作りました。

![media.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/537831/1fa44356-236e-4e4c-3305-a345c2027a32.gif)


　画像は神奈川工科大学の標準画像データベースSIDBAからダウンロードしました。
![explorer.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/537831/ab427dd3-c252-0c2e-a93c-f6d67c003802.jpeg)


　プログラムを実行すると、５枚の画像が表示されます。
![window.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/537831/f4f4a04c-4468-f1fc-facb-90374a472740.jpeg)


　地球の画像をクリックしました。ウィンドウが更新されます。


![updated.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/537831/0aeeabf3-d6eb-2f9c-296e-4fe7ada5c62c.jpeg)

　クリックした地球の画像が移動されました。今回は左クリックだったのでLのフォルダに出力されています。

![updatedWindow.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/537831/68c998e2-b232-3985-eef5-df4bf47663d0.jpeg)

#コード
```python:imageMover.py
import cv2
import glob
import shutil
import os
import numpy as np

#画像のサイズは200pxで統一
size = (200, 200)  

name = []   #ファイル名
data = []   #ファイルのデータ
coordinates = []    #クリック時の座標

#移動先のフォルダを作成。LとRがそれぞれ左クリックと右クリックに対応。
os.makedirs('./L', exist_ok=True)
os.makedirs('./R', exist_ok=True)

#ファイルの読み込み
for file in glob.glob('*.bmp'):
    img = cv2.imread(file)
    img = cv2.resize(img, size) 
    name.append(file) 
    data.append(img)

#マウスクリック時に実行される関数
def click_event(event, x, y, flags, param):
    if event == cv2.EVENT_LBUTTONDOWN:
        coordinates[0:3] = [x, y, 'L']
    if event == cv2.EVENT_RBUTTONDOWN:
        coordinates[0:3] = [x, y, 'R']

#画像の枚数
hasWindow = len(data)

#画像の残り枚数が1枚以上の場合に実行
while hasWindow > 0:
    img = cv2.hconcat(data[:5])

    while(1):
        cv2.imshow('img', img)
        cv2.setMouseCallback("img", click_event) #クリック時
        
        #クリック時の座標を取得し、対応する画像を移動
        if len(coordinates) != 0:
            n = coordinates[0]//200
            shutil.move(name[n], coordinates[2]+'/'+name[n])
            print(F'フォルダ {coordinates[2]} に {name[n]} を移動しました')
            data.pop(n)
            name.pop(n)
            coordinates = []
            hasWindow -= 1 #画像の残り枚数を更新
            break
        
        #座標を初期化
        coordinates = []    

        #キー入力があるか
        key = cv2.waitKey(100) & 0xff

        #キーボードかｘが押されたらウィンドウを閉じる
        if key != 255 or cv2.getWindowProperty('img', cv2.WND_PROP_AUTOSIZE) == -1:
            cv2.destroyAllWindows()
            exit()
```
　[Github](https://github.com/isso5235/imageMover/blob/master/imageMover.py)にもアップロードしています。

#結論
　手動の方が早いのでは？

#おわりに
　画像の表示数を増やすとかでもっと工夫できそうですね。

　最後までご覧いただきありがとうございました。ご指摘・コメントをお待ちしております。
Git 必要なディレクトリだけ checkoutする

# 環境
win10, git 2.28.0.windows.1

# 手順
①作業ディレクトリに checkoutするディレクトリを作成して そこに移動
②以下 git コマンド作業

→ git初期化 必要なら git-config user.nameとか 設定しておく

```
> git init
```

→ sparse-checkout を有効化

```
> git config core.sparsecheckout true
```

→ sparse-checkoutファイル作る

```
$ touch .git/info/sparse-checkout (linux)
> New-Item -Type File .git/info/sparse-checkout （win-PowerShell）
```

→ <パターン>は checkoutしたい ディレクトリパス

```
> git sparse-checkout add <パターン>
e.g.) git sparse-checkout add directory/path
```

→ 指定パターン確認  <パターン>が表示されればおｋ

```
> git sparse-checkout list
```

```
> git remote add origin ＜リポジトリのURL＞
> git pull origin ＜ブランチ名＞
> git pull origin master
```

③pullしたら リポジトリの<パターン>（directory/path）だけcheckoutされる

---
参考）

git sparse checkout で clone せずに一部のサブディレクトリだけを pull/checkout する https://mseeeen.msen.jp/git-sparse-checkout/

リポジトリの一部だけcheckoutするGitコマンド：sparse-checkout - はんなりと、ゆるやかに https://iucstscui.hatenablog.com/entry/2020/05/21/090321
AppleDeveloperに登録したMac以外で開発Ad Hoc配信

下記のサイトを参考に
https://makotton.com/2014/10/24/625

.p12ファイルをローカルにダウンロードする

Xcode > Preference > Accounts > AppleID > 右下のManage Certificatesを選択します。iOS DevelopmentとiOS Distributionのバツ印がついてないやつをそれぞれ右クリックして、Exportを選択します。パスワードを設定しないと行けないので設定してそれぞれExportします。

![スクリーンショット 2020-07-30 19.03.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101462/d427b4e4-639b-2ff0-ebb1-aafbe4990ad1.png)
![スクリーンショット 2020-07-30 19.03.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101462/6aa9c16b-aa81-cafe-f0d5-39b20d5d7a86.png)
プロジェクトマネージャ試験の午後は勉強しなくても何度か受ければ受かる

まだ応用情報技術者試験がなくてソフトウェア開発技術者試験があったころに、基本情報技術者試験を受け始めました。

なぜ受け始めたかというと、「建築士の資格を持ってない人に家を建ててほしくないでしょ？システムも同じで…」みたいな当時よくある（今も？）話を聞かされて半分強制で受けることになったから。

「基本情報持ってないヤツは人にあらず」みたいな雰囲気だったので、イヤイヤ受けてた記憶があります。

基本情報、午前は勉強すれば点数は適当に上がっていきましたが、午後はセンスの部分もあって、なかなか点数が上がりませんでした。

過去問をやりまくったのかな。

３回目でやっと受かりました。

で、その後も年２回のお祭りじゃぁ～という感じで何となく他の資格も受け続けました。

今ではデータベースとプロジェクトマネージャの２つ、高度を持ってます。

印象深いのは、プロジェクトマネージャ試験はほとんど勉強していないということ。

受け続けたらそのうち受かるだろ～と軽い気持ちで受けてたら、５回目くらいで受かりました。

そんなに受けたくね～よっていう人はすいません。

過去４回は全部「論文B判定」だったんですが、5回目はちょっと書き方を変えました。

合格したのはそのおかげかもしれません。

本当に話したいのはそれについてだけですが、せっかくなんで午前Ⅰから話してみます。

#事前知識
・SIer 歴 10数年
・そんなに多くないけどプロマネ経験有
・「プロジェクトマネジメント標準 PMBOK入門」は読んでいた

#午前Ⅰ
過去問を10年分。それだけ。

内容は理解しなくても、この問題ならこの解答だ、というのが浮かべばいいです。

#午前Ⅱ
午前Ⅰと同じ。

#午後Ⅰ
ここ勉強します？

やって点数上がります？

現代文の試験みたいなやつ。

答えは文中にあるか知識か常識の中にあるので、文中→知識→常識 の順で答えを探しましょう。

#午後Ⅱ
問題はここです。

文字数を考えるとただ書くだけでもかなりの負担です。

私は事前に練習で論文を書いたことは一度もないです。

ぶっつけ本番。

試験中にシナリオを組み立ててました。

さすがにそれはあまりに非効率なので、シナリオぐらいは事前に考えておきましょう。

テーマによって書き方が変わると思いますが、私の場合は「品質」で、こんな書き方でした…

1. 自分の紹介
2. 自分のプロジェクトの紹介
3. 自分のプロジェクト、快調な出だし
4. 問題発生
5. 問題の分析
6. 分析に基づいて対応
7. いい感じに復活
8. さらにこうすればもっといいんじゃないか的な話

普通ですね。

こんな感じで書いて、私はずっとB判定でした。

で、A判定になったときに何を変えてたかというと…

__「自分で手を動かさない」__です。

落ちた過去４回は、分析やテストを自分でやることにしてました。

でもふと、__プロマネってもっと上の立場じゃね？__と思ったのです。

そこで、「分析するように__指示した__」「テストで確認するように__指示した__」と、指示出し人間に変えてみました。

計画を考え、指示するだけです。

決して手を動かしません。

それがよかったのか、やっとA判定になりました。

今回のプロマネ試験は色々あって受けない人も多いかもしれませんが、何かの参考になれば幸いです。
NuxtのTypeScript化でどうしてもエラーが出るのはVeturのせいかも

少し昔の話なのでうろ覚えなところがありますが、ご容赦を。
# 対象者

- NuxtをTypeScript対応して、ちゃんと動いてるのにVSCodeくんがエラーを吐く現象に苦しめられている人
- かつ、その問題が明らかにパス周りの問題っぽい人

# 発端
Nuxt対応後、明らかにパス周りがうまく解決されていない？というエラーが多々発生するようになってしまった。
npm run devで起動してみるとちゃんと動いているのだが、何故かVSCodeは赤い警告を出してくる。

例えばmiddlewareを使おうとすると、変なエラーが出る。

[Nuxt×TypeScriptでmiddlewareを使う](https://qiita.com/TsukasaGR/items/df68747a5a1e81d9fedc) あたりを試してみるも、うまくいかない。

そもそも、上記の記事の筆者さんのエラーの原因は

> middlewareはVue標準でなくNuxt独自のプロパティである為、そのままjs→tsに変換してもうまく行かない

なのだけれど、少なくとも2020年7月現在、Nuxtは公式に対応しているように見える。
→[公式による設定ファイルらしきもの](https://github.com/nuxt/nuxt.js/blob/40ceb61fabd682846b234059724d894e3f3127ea/packages/types/app/vue.d.ts)

あと、

```example.vue
import MyComponent from '~/components/MyComponent.vue'
```

の部分でもエラーが出る。

```example.vue
import MyComponent from '../../components/MyComponent.vue'
```

のように相対パス指定にすると直る。
なんだこれ？

パスが悪いと言われてるけど動いてる、ってことはNuxtの問題じゃない。
ということはVSCodeの問題？

と考えて、こんなissueを見つけた。

[Multi root support](https://github.com/vuejs/vetur/issues/424)

……というか、正直なところどのissueを見て解決に至ったのかは覚えていない。
とりあえず、
__Workspaceに複数フォルダを配置している場合、一番上のフォルダしかVeturは正しくパスを認識してくれない__
という、おかしな現象が存在することは間違いないみたい。
※少なくともWindowsのVSCodeにて確認

おそらくこちらの記事で扱われてる現象も同様の理由によるものです。
[VSCode の Vetur で types/vue-shim.d.ts が有効にならないのはワークスペースにフォルダが複数あるから](https://qiita.com/kulikala/items/f11c37b7059d2a7572be)
結論としては、フォルダは複数でも一番上に配置するとおそらく解決します。

# まとめ
NuxtはTypeScript対応しているとはいえ色々罠がありますが、頑張りましょう。
ではまた。
GithubActions を作って動かそうとしたら "ReferenceError: define is not defined" と言われた

# やりたかったこと

typescript で 書いた GitHub Actions のコードをトランスパイルして実行する。
しかし、GitHub Actions で呼び出した際にエラーが発生する。

# エラー文

エラーが発生した箇所
https://github.com/tkt-actions/add-issue-links/runs/925347571?check_suite_focus=true

```
Run tkt-actions/add-issue-links@v1.0.2
/home/runner/work/_actions/tkt-actions/add-issue-links/v1.0.2/lib/main.js:1
define("domain/error/BaseError", ["require", "exports"], function (require, exports) {
^

ReferenceError: define is not defined
    at Object.<anonymous> (/home/runner/work/_actions/tkt-actions/add-issue-links/v1.0.2/lib/main.js:1:1)
    at Module._compile (internal/modules/cjs/loader.js:959:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:995:10)
    at Module.load (internal/modules/cjs/loader.js:815:32)
    at Function.Module._load (internal/modules/cjs/loader.js:727:14)
    at Function.Module.runMain (internal/modules/cjs/loader.js:1047:10)
    at internal/main/run_main_module.js:17:11
```

# どうやって直したか

差分全体: https://github.com/tkt-actions/add-issue-links/compare/v1.0.1...v1.0.5

絶対パスで指定していた import を相対パスで書き直した。(tsc は絶対パスの解決を行ってくれない)
(ここがエラー文の原因なのかはいまいちあやしい)

## 過程

### ReferenceError: define is not defined の解決

差分全体: https://github.com/tkt-actions/add-issue-links/compare/v1.0.2...v1.0.4

tsconfig でビルドのターゲットを変更することで、`ReferenceError: define is not defined` は解決したが、新たに `MODULE_NOT_FOUND` のエラーに遭遇した。

エラー: https://github.com/tkt-actions/add-issue-links/runs/925458465?check_suite_focus=true

#### tsconfig.json

```
     "strict": true,
     "noImplicitAny": true,
     "strictNullChecks": true,
-    "target": "es2019",
+    "target": "es6",
     "sourceMap": true,
     "outDir": "./lib",
     "baseUrl": "./",
```

### MODULE_NOT_FOUND の解決

差分全体: https://github.com/tkt-actions/add-issue-links/compare/v1.0.4...v1.0.5

絶対パスで指定していた import を相対パスで書き直した。
すると、 `target` の指定を戻しても、動くようになった。

# まとめ

ビルドは、よーわからん
openssl による SSL/TLS証明書発行準備時のコマンド覚書き

# はじめに

openssl を使って CSR を発行するのだが、頻度が開いてしまい毎回コマンドを忘れて都度ググるのでメモ書き。


## 秘密鍵生成

```bash
# カレントディレクトリのファイル全てを読み取ってハッシュ値計算してる
$ openssl sha256 * > rand.dat
# パスフレーズありの鍵を作成
$ openssl genrsa -rand rand.dat -des3 2048 > privkey_pass
# パスフレーズを解除 (パスフレーズを入力)
$ openssl rsa -in privkey_pass -out privkey
```

## CSR作成

```bash
# 古いCSRの中身を確認
$ openssl req -noout -modulus -in old.csr
# CSRを作成
$ openssl req -new -key privkey -out new.csr
# ハッシュ値を比較
$ openssl rsa -noout -modulus -in privkey | openssl md5
(stdin)= *********************************
$ openssl req -noout -modulus -in new.csr | openssl md5
(stdin)= *********************************
```


# 参考

- https://www.geotrust.co.jp/support/ssl/csr/apache_openssl_new.html
- https://rms.ne.jp/sslserver/basis/decrypt_key/
- https://qiita.com/dribble13/items/52372ffbd218d2b019f8
- https://qiita.com/sumida0713/items/72fcb2b0ab926c906507