OmniAICreator/Qiita-1.07M huggingface dataset:
Emmetで展開できるHTMLを自分好みに変更する

# TL;DR

- `!`で展開できるHTMLのひな形を変更したい。
- `emmet.extensionPath`に`snippets.json`が入ったフォルダを指定することで、emmetのスニペットを登録できる。
- emmet公式が出してるemmetのスニペットを参照しながらつくると楽。

# 実行環境

- VSCodeの最新版（2020.01.30現在）

# `!`で展開できるHTMLのひな形を変更したい

## 理想形

理想の形はこんな感じです。
※`lang`属性はすでに設定で変更済み。この変更はぐぐるとめっちゃヒットする。

```html
<!DOCTYPE html>
<html lang="ja">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>Document</title>
	<link rel="stylesheet" href="style.css">
</head>
<body>

</body>
</html>
```

`title`タグの下に`link:css`が入ったひな形をつくりたいのです。
デフォルトだと、`link:css`は入っていません。


# スニペットをつくる

## `html.json`につくるパターン

下記は、拡張子が`html`のときに使えるスニペットを定義して、emmetのひな形を作成するパターンです。

[VSCodeでemmetのHTMLテンプレート変更とenをjaにする！ - Qiita](https://qiita.com/coro422/items/17cdd1acb9d0c3300e24)

こちらは、emmetの**展開後**のHTMLをスニペットとして定義する形になります。

こちらの例では"div.flex-container"と入力したときに`<div class="flex-container"></div>`と出るようにスニペットを定義しています。

```json
{
"flex container": {
  "prefix": "div.flex-container",
  "body": [
    "<div class='flex-container'>$1</div>",
  ],
  "description": "make div with flex-container class"
}
}
```


ではbodyに、展開後のHTMLではなく、`div.flex-container`と入れたらどうなるでしょう。  
答えは"div.flex-container"と出てくるだけになります。



## `snippets.json`につくるパターン

こちらはひとつVSCode上で設定をおこなわないといけない分、面倒です。

ただし、**こちらで定義するスニペットでは、emmet記法が使えます。**

### 準備

- `emmet.extensionPath`を設定します。

File > Preferences > Settings > `emmet.extensionPath`

ここには、`snippets.json`を置くフォルダパスを指定します。

### 書いてみる

VSCodeの公式サイトにサンプルとしてスニペットが載っています。

https://code.visualstudio.com/docs/editor/emmet#_using-custom-emmet-snippets

```json
{
  "html": {
    "snippets": {
      "ull": "ul>li[id=${1} class=${2}]*2{ Will work with html, jade, haml and slim }",
      "oll": "<ol><li id=${1} class=${2}> Will only work in html </ol>",
      "ran": "{ Wrap plain text in curly braces }"
    }
  },
  "css": {
    "snippets": {
      "cb": "color: black",
      "bsd": "border: 1px solid ${1:red}",
      "ls": "list-style: ${1}"
    }
  }
}
```

サンプルにもありますが、こちらはemmet記法をスニペット定義に使えます。

もちろん`!`の定義を上書きすることも可能です。


# emmet公式が出してるemmetのスニペットを見る

emmetでよく見る省略記法がどうやって定義されているか見れます。

https://github.com/emmetio/emmet/blob/master/snippets/html.json

ためしに`!`を見てみると、次のように記載されているのがわかります。

`!!!+doc`

`!!!`と`doc`を合わせて使っているんですね。。

`!!!`は`{<!DOCTYPE html>}`で、

`doc`は`html[lang=${lang}]>(head>meta[charset=${charset}]+meta:vp+title{${1:Document}})+body`となっています。

ということは、`doc`を上書きすれば良いみたいですね。


`snippets.json`のhtmlの項目に`doc`の行を追加しました。

```json
{
  "html": {
    "snippets": {
      "doc": "html[lang=${lang}]>(head>meta[charset=${charset}]+meta:vp+title{${1:Document}}+link:css)+body"
    }
  }
}
```

これでHTMLのひな形を変更することができました。


私はあまり編集することもなさそうですが、、、

備忘録として！


おわり
コロナウイルスの感染状況を都道府県別に可視化してみた

# tl;dr
<p class="codepen" data-height="550" data-theme-id="default" data-default-tab="result" data-user="04" data-slug-hash="ZEYNpMr" style="height: 550px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="CORONA HAZARD MAP">
  <span>See the Pen <a href="https://codepen.io/04/pen/ZEYNpMr">
  CORONA HAZARD MAP</a> by John Doe (<a href="https://codepen.io/04">@04</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

都道府県別にコロナウイルスの感染状況を可視化してみました。
都道府県をクリックすると詳細な情報が閲覧できます。

データは以下で管理してます。編集Okです。
https://docs.google.com/spreadsheets/d/1c42UQBNpERi0WP4nODghs_BWxba0xflFH-QKsWLX2qI/edit?usp=sharing

# 経緯
丁香園(中国)やジョンズ・ホプキンス大学(アメリカ)が可視化ツールを公開してますが、日本の詳細な情報がなかったので作ってみました。

> 新型コロナウイルスの感染状況を可視化、米大学がマップ公開
> https://www.itmedia.co.jp/news/articles/2001/28/news107.html

> 【速報】コロナウイルス「感染・死亡・回復」データを可視化 中国の速報サイトが話題
> https://honichi.com/news/2020/01/28/coronavirusrumor/

データは、GASのdoGetでSpreadSheetまるごとJSONにしてCodePenに表示してます。

> 中華人民共和国湖北省武漢市における新型コロナウイルス関連肺炎の発生について
> https://www.mhlw.go.jp/stf/seisakunitsuite/bunya/0000164708_00001.html
第一章　序章（執筆中）

##取引所市場
####デリバティブ取引所の歴史
　　　1848年　CBOT（シカゴ商品取引所）
　　　　　　　　穀物の取引量とグレードの標準化が目的として始まる

　　　1919年　CME（シカゴマーカンタイル取引所）
　　　　　　　　先物取引が世界中に広まる

　　　1973年　CBOE（シカゴ・オプション取引所）
　　　　　　　　16株式に対するコール・オプションを定型化し、秩序ある市場の創設される

　　　1977年　プット・オプションが同取引所で開始される

　　　現在は、株式、株価指数、外国通貨、先物取引の先物契約オプションも取引されている

##### ここまでの用語の整理
- **デリバティブ**：様々な金融商品のこと（株、金利、為替から派生した商品を指す）
- **先物取引**：将来する売買を（価格や数量などを事前に決めておく）取引すること
- **オプション取引**
      - **コール・オプション**：あらかじめ決めた行使価格（売買価格）で買う権利
         - 市場価格が上がっても安く買うことができる。
         - 市場価格が行使価格より下がったら、権利放棄できる。
         
      - **プット・オプション**：あらかじめ決めた行使価格で売る権利
         - 市場価格が下がっても高く売ることができる。
         - 市場価格が行使価格より上がったら、権利放棄できる。
        
　**電子市場**
　　　電子市場は高頻度取引とアルゴリズム取引であり、人間が介在することなく、
　　コンピュータープログラムを使って執行する。



##店頭市場（ＯＴＣ）

####デリバティブ取引
　　**店頭市場（ＯＴＣ）**：銀行、金融機関、ファンドマネージャー、企業が参加する。

　　**中央精算機関（ＣＣＰ）**：取引を行う両者の間に入り、片方が債務不履行（デフォルト）す
　　　　　　　　　　　　　　るリスクを負わずに清算できる。
　　　　　　　　　　　　　　取引については以下のような__取り決め__がある

#####取り決めの内容とは
　　　　・ お互いの署名
　　　　・ どのような状況下で取引が終了されるのか
　　　　・ 取引終了時にどのように精算金額を精算するのか
　　　　・ お互いが差し入れなければならない担保はどのように精算されるのか
SDFをサクッとCSVに変換する

#はじめに
化合物データのフォーマットであるSDFをサクッとCSVに変換するスクリプトを書いてみた。

#仕様
- SDFの中のプロパティを読み取ってCSVの項目として出力
- 各化合物のプロパティが必ずしも同じプロパティを持っている必要はない(持っていないプロパティは空が出力)。

#ソース
```SDF2CSVConvert.py
import pandas as pd
from rdkit import Chem
import argparse
from collections import defaultdict


def main():

    parser = argparse.ArgumentParser()
    parser.add_argument("-input", type=str, required=True)
    parser.add_argument("-output", type=str, required=True)
    parser.add_argument("-save_name", action='store_true', help="store header line as _Name")
    args = parser.parse_args()

    # SDFの読み込み(1回目はパラメータ名を全て読み取る)
    sdf_sup = Chem.SDMolSupplier(args.input)
    Props = []
    if args.save_name:
        Props.append("_Name")

    for mol in sdf_sup:
        for name in mol.GetPropNames():
            if name not in Props:
                Props.append(name)

    # データを格納するディクショナリ
    param_dict = defaultdict(list)

    # SDFの読み込み(2回目は化合物のパラメータを取得。なければエラー)
    sdf_sup = Chem.SDMolSupplier(args.input)
    for mol in sdf_sup:
        # 名前の取得
        for name in Props:
            if mol.HasProp(name):
                param_dict[name].append(mol.GetProp(name))
            else:
                param_dict[name].append(None)

    #　pandasで一気に変換
    df = pd.DataFrame(data=param_dict)
    df.to_csv(args.output, index=False)


if __name__ == "__main__":
    main()

```

#解説
全化合物のプロパティを知るためにSDFを最初に読み込んでいる。そして2度目の読み込みで各化合物のプロパティの値を読みとっている。化合物がプロパティを持っていなければNoneを入れている。最後にプロパティを格納した辞書型をPandasに放り込んでCSVに出力した。
なお、-save_nameでSDFの1行目を"_Name"というプロパティで保存できるようにした。他の引数はソースを参照。

#出力例
RDKitのSolubilityデータだとこんな感じ。

```
_Name,ID,NAME,SOL,SMILES,SOL_classification
3-methylpentane,5,3-methylpentane,-3.68,CCC(C)CC,(A) low
"2,4-dimethylpentane",10,"2,4-dimethylpentane",-4.26,CC(C)CC(C)C,(A) low
1-pentene,15,1-pentene,-2.68,CCCC=C,(B) medium
cyclohexene,20,cyclohexene,-2.59,C1CC=CCC1,(B) medium
"1,4-pentadiene",25,"1,4-pentadiene",-2.09,C=CCC=C,(B) medium
cycloheptatriene,30,cycloheptatriene,-2.15,C1=CC=CC=CC1,(B) medium
1-octyne,35,1-octyne,-3.66,CCCCCCC#C,(A) low
ethylbenzene,40,ethylbenzene,-2.77,c1ccccc1CC,(B) medium
"1,3,5-trimethylbenzene",45,"1,3,5-trimethylbenzene",-3.4,c1c(C)cc(C)cc1C,(A) low
indane,50,indane,-3.04,c(c(ccc1)CC2)(c1)C2,(A) low
isobutylbenzene,55,isobutylbenzene,-4.12,c1ccccc1CC(C)C,(A) low
n-hexylbenzene,60,n-hexylbenzene,-5.21,c1ccccc1CCCCCC,(A) low
```
DynamoDBのチュートリアルを読み解く【3: Amazon SNS トピックを作成する】

# はじめに

引き続き[DynamoDBのチュートリアル](https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/Streams.Lambda.Tutorial.html)を実施しました。
今回はSNSです。

（バックナンバー）
[1.DynamoDB テーブル作成](https://qiita.com/kkino1985/items/f9091c1e1efb35009ce7)
[2.IAMポリシー/ロール作成](https://qiita.com/kkino1985/items/a087bc3077f36b4b1e21)


# 3.1 SNSトピック作成

    aws sns create-topic --name wooferTopic

## --name

- 書式 : --name `(value)`

作成するトピックの名前。
（トピックと次に出てくるサブスクライブについては後述します）

# 3.2 SNSトピックにE-mailアドレスをサブスクライブ

    aws sns subscribe \
        --topic-arn arn:aws:sns:region:accountID:wooferTopic \
        --protocol email \
        --notification-endpoint example@example.com

※リージョン名（region）、アカウントID（accountID）、メールアドレス（example@～）はそれぞれ自分の環境に書き換えています


## --topic-arn

- 書式 : --name arn:aws:sns:`(region)`:`(accountID)`:`(topic-name)`

サブスクライブするトピックのARN。


## --protocol / --notification-endpoint

- 書式 : --protocol `(value)`
- 書式 : --notification-endpoint `(value)`

配信に使用するプロトコルと通知を受信するエンドポイント。
それぞれ使用可能なのは下記の通り。

|プロトコル|エンドポイント|
|:--|:--|
|http|http://～始まるURL|
|https|https://～始まるURL|
|email|メールアドレス|
|email-json|メールアドレス|
|sms|電話番号|
|sqs|SQSキューのARN|
|application|モバイルアプリケーションとデバイスのエンドポイントARN|
|lambda|Lambda関数のARN|


# トピックとサブスクライブについて

トピックとは、公式ドキュメントには「通信チャネルとして機能する論理アクセスポイント」と書かれています。

Amazon SNSは「Publish（出版）-Subscribe（購読）モデル」であり（パブサブモデル、と呼ばれることも）、送信者と受信者が1対他となるメッセージ通知モデルですが、受信者の宛先を論理的にグループ化しているのがトピックです。

また、トピックにメッセージの受信者、つまりエンドポイントを登録する作業がサブスクライブとなります。

※イメージ図（AWSドキュメントより抜粋）

![sns-topic.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319027/8889cbf6-2098-ece0-03d6-885b362a95bf.png)

（公式ページなどを見ると、この辺りの用語を知っている前提で「トピックをサブスクライブする」しか書いていなかったりして「オイィ！？」となったりします……）


# 参考URL

https://docs.aws.amazon.com/cli/latest/reference/sns/create-topic.html

https://docs.aws.amazon.com/cli/latest/reference/sns/subscribe.html

https://docs.aws.amazon.com/ja_jp/sns/latest/dg/welcome.html

https://docs.aws.amazon.com/ja_jp/sns/latest/dg/sns-tutorial-create-topic.html
Android Studio - ImageViewをwrap_contentにしても画像サイズと合わない

# ImageViewに画像をセットすると、サイズが画像に合わない
こんなふうに
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278251/1aa1049f-a525-3bd4-5c38-3a5b3e236f84.png)

layout_heightを`wrap_content`にしても変わらないのでハマった

# 解決法
Stack Overflowに書いてあった
[java - Image View not Wrapping Contents - Stack Overflow](https://stackoverflow.com/questions/21203189/image-view-not-wrapping-contents)

`adjustViewBounds`を`true`にすればOK。

```xml:activity.xml
<ImageView
    android:adjustViewBounds="true"
    android:scaleType="fitCenter" />
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278251/7dfde296-3e43-40ad-6d0e-bd678bab340b.png)
チーム開発時に起きえる、migrationファイル・テーブルが起こす大混乱と、その解決方法

#はじめに
アプリ作成に必要なのがデータベース－テーブルです。
これの作成や編集には色々な手間がかかりますが、
チーム開発では恐ろしいエラーが出てくることがあります。

今回はその解決方法を一つ提示したいと思います。

#状況
4人チーム開発を行っている。
使っているテーブルは`users`と`products`。
ある時、それまでできていたブランチを全てmergeし、チーム全員にpullしました。
その後`rails s`でエラーが出ました。
「migrationしなさい」といったエラーです。
そこで、ターミナル上で`rake db:migrate`をすると、`already exists 'products'`という様なエラーが出て、`rake db:migrate`ができません。

#原因
人によってマイグレーションファイルの作り方が異なる＝テーブルが違うので、全てをマージしたマイグレーションファイル群をまとめてmigrationすると、色々問題が起きるようになるようにしました。（同じマイグレーションファイルが二つあるなど）

#対策
まずは***作業用のbranchを作成***します。
細かい修正を行うと再びエラーが出ると思い、一度***全てのテーブルを削除しました***。同時に、チーム全員で協力して不必要なマイグレーションファイルを削除していきます。
その後migrationを行います。

#実行
この作業は一人パソコン上で行っています。各々が勝手に作業するのではなくて、一人が作業しているところを画面を見ながらところどころコメントすることにより間違いが少なくなるからです。
マイグレーションファイルがうまく整備できたのなら、次のコマンドをターミナルで入力してください。

```terminal
rake db:reset:migrate
```

上手くいかなかったら、次の順でコマンドを実行してください。

```terminal
rails db:environment:set

rake db:reset

rake db:migrate
```

これにより、テーブルの中身は消えていますが、
全員が共通のテーブルを持っていることになります。

#終わりに
チーム内の打ち合わせが足りていないとこのような事態を引き起こしますが、
反対に全員で調べたことを持ち寄り、話し合いながら一つの手順にまとめ、詳しい人にチェックしてもらい、やってみた結果をフィードバックしていけば成長に繋がっていくと思うので、ピンチはむしろチャンスととらえるぐらいな感じで楽しんでもらえたらなと思います。
git addでステージングしたファイルがpushしてもEverything up-to-dateと言われる

# 目的

- ファイルの差分があるのにpushできない時の筆者の経験談を書く。

# 原因

- 単純にコミットメッセージのサマリーの下に空の行が入ってしまっていた。

# 症状

- 下記に問題のgitコマンドを記載する。

    ```terminal
    MacBook-miriwo:Job_Change admin$ git status
    On branch master
    Your branch is up to date with 'origin/master'.

    Changes to be committed:
      (use "git restore --staged <file>..." to unstage)
            new file:   practice/common.md

    MacBook-miriwo:Job_Change admin$ git push origin master
    Everything up-to-date
    ```

# 問題のコミットメッセージ

- コミットメッセージサマリの下に空行が入ってしまっている。
- 下記に問題のコミットメッセージを記載する。

    ```terminal
    Add: Advance preparation memo.

    # Please enter the commit message for your changes. Lines starting
    # with '#' will be ignored, and an empty message aborts the commit.
    #
    # Date:      Tue Jan 28 23:10:34 2020 +0900
    #
    # On branch master
    # Your branch and 'origin/master' have diverged,
    # and have 1 and 1 different commits each, respectively.
    #   (use "git pull" to merge the remote branch into yours)
    #
    # Changes to be committed:
    #       new file:   company_visit/off_line/08/memo.md
    #       new file:   practice/common.md
    #
    ```

# 修正したコミットメッセージ

- 下記に修正したコミットメッセージを記載する。

    ```terminal
    Add: Advance preparation memo.
    # Please enter the commit message for your changes. Lines starting
    # with '#' will be ignored, and an empty message aborts the commit.
    #
    # Date:      Tue Jan 28 23:10:34 2020 +0900
    #
    # On branch master
    # Your branch and 'origin/master' have diverged,
    # and have 1 and 1 different commits each, respectively.
    #   (use "git pull" to merge the remote branch into yours)
    #
    # Changes to be committed:
    #       new file:   company_visit/off_line/08/memo.md
    #       new file:   practice/common.md
    #
    ```
Swiftのテキストフィールドで数字以外使えなくするやり方

今回はSwiftでテキストフィールドで数字以外使えなくするやり方を紹介します。

#コード

今回は数字は0から９の間の数字を対象とします。
textfiledのtextfiledメソッドの中に書きます。


<img width="725" alt="スクリーンショット 2020-01-29 21.18.25.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558816/ea0449c8-29e0-237b-2012-5ed5b7625a21.png">

#動作

このコードを書いてからの動作は、0から9以外の文字は打つことができなくなります。
例えば電話番号だけ入力できるようにしたい時など、利用できるかと思います。

ではでは！
kustomizeのイメージを作ってみた

kustomizeコマンドを実行したいけど、いろいろな事情で実行サーバにkustomizeをインストールせずに解決しなくてはならない事象が発生しました。

そんな時に便利なのがやっぱりDocker！

kustomizeだけが入ったイメージを作って、その中にkustomizeコマンドを実行したいソースをマウントすればいける！と思い、kustomizeのイメージを作成してみたというのが今回の内容となります。

Dockerhubは[こちら](https://hub.docker.com/r/sincek/kustomize)

Dockerfileはこんな感じ

```dockerfile
FROM alpine:3.9 as builder

ENV KUSTOMIZE_VERSION 3.4.0

RUN wget https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize/v${KUSTOMIZE_VERSION}/kustomize_v${KUSTOMIZE_VERSION}_linux_amd64.tar.gz \
  && tar xzf ./kustomize_v${KUSTOMIZE_VERSION}_linux_amd64.tar.gz \
  && mv kustomize /usr/local/bin/kustomize \
  && rm kustomize_v${KUSTOMIZE_VERSION}_linux_amd64.tar.gz \
  && chmod +x /usr/local/bin/kustomize

FROM scratch

COPY --from=builder /usr/local/bin/kustomize /usr/local/bin/kustomize

ENTRYPOINT [ "kustomize" ]
```

Dockerhubのimageを使う場合は、こんな感じで実行できます。

```sh
$ docker run --rm sincek/kustomize version
{Version:kustomize/v3.4.0 GitCommit:2c9635967a2b1469d605a91a1d040bd27c73ca7d BuildDate:2019-11-12T05:00:57Z GoOs:linux GoArch:amd64}
```
[Python3 入門 18日目]8章 データの行き先（8.3.6.2〜8.3.6.3）

###8.3.6.2 SQL表現言語

- 表現言語は様々な操作のためのSQLを作る関数を導入する。

- 以下のzooオブジェクトはSQLデータベースの世界とPythonデータ構造の世界の中間的なアプローチをしている。（**SQL文に近い文法（大文字→小文字にしただけのもの）とselect()のようにPython構文のものが混在しているからと理解**）

```py

>>> import sqlalchemy as sa
>>> conn=sa.create_engine("sqlite://")
#zooテーブルを定義するためにSQLではなく表現言語を使う。
>>> meta=sa.MetaData()
>>> zoo=sa.Table("zoo",meta,
...     sa.Column("critter",sa.String,primary_key=True),
...     sa.Column("count",sa.Integer),
...     sa.Column("damages",sa.Float)
...     )
>>> meta.create_all(conn)
#表現言語を使ってデータの挿入。
>>> conn.execute(zoo.insert(("bear",2,1000.0)))
<sqlalchemy.engine.result.ResultProxy object at 0x108f30590>
>>> conn.execute(zoo.insert(("weasel",1,2000.0)))
<sqlalchemy.engine.result.ResultProxy object at 0x108f306d0>
>>> conn.execute(zoo.insert(("duck",10,0)))
<sqlalchemy.engine.result.ResultProxy object at 0x108f303d0>
#SELECT文を作る。zoo.select()はプレーンなSQLPythonのSELECT * FROM zooと等しく、zooオブジェクトが表現するテーブル全ての情報を選択する。
>>> result=conn.execute(zoo.select())
#情報を取得してrowsに格納。
>>> rows=result.fetchall()
>>> print(rows)
[('bear', 2, 1000.0), ('weasel', 1, 2000.0), ('duck', 10, 0.0)]


```

###8.3.6.3 ORM(オブジェクト関係マッピング)

- SQLAIchemyのトップレイヤでは、ORMがSQL表現を使うが、実際のDBのメカニズムは見えない。クラスを定義するとORMがDBとの間でデータを処理してくれる。
- **オブジェクション関係マッピングの基本的な考え方は、RDBMSを使いつつ、コード内でオブジェクトを参照し、Python的なやり方でコードを書き続けられること。**


```py

>>> import sqlalchemy as sa
>>> from sqlalchemy.ext.declarative import declarative_base
#接続開設。
>>> conn=sa.create_engine("sqlite:///zoo.db")
>>> Base=declarative_base()
#SQLAIchemyのORMに入っていく。
>>> class Zoo(Base):
...     __tablename__="zoo"
...     critter=sa.Column("critter",sa.String,primary_key=True)
...     count=sa.Column("count",sa.Integer)
...     dameges=sa.Column("damages",sa.Float)
...     def __init__(self,critter,count,damages):
...         self.critter=critter
...         self.count=count
...         self.damages=damages
...     def __repr__(self):
...         return "<Zoo({},{},{})>".format(self.critter,self.count,self.damages)
... 
#DBとテーブルの作成
>>> Base.metadata.create_all(conn)
#Pythonオブジェクトを作ればzooのテーブルにデータ挿入可能。
>>> first=Zoo("duck",10,0.0)
>>> second=Zoo("bear",2,1000.0)
>>> third=Zoo("weasel",1,2000.0)
>>> first
<Zoo(duck,10,0.0)>

```

- DBとやりとるする為のセッションを作る。

```py

>>> from sqlalchemy.orm import sessionmaker
>>> Session =sessionmaker(bind=conn)
>>> session=Session()
#セッション内で先ほど作った3つのオブジェクトをDBに書き込む。
#add()関数は1個のオブジェクトをadd_all()関数はリストを追加する。
>>> session.add(first)
>>> session.add_all([second,third])
#最後に強制的に全ての処理を完了させる。
>>> session.commit
<bound method Session.commit of <sqlalchemy.orm.session.Session object at 0x108f3f1d0>>


```


#感想

現在11章の並行処理を勉強しているがかなり内容が濃い。
頭に全然入ってこないが、Pythonドキュメントを見ると本以上に詳しく書いている部分もあり、昨日分からなかったmultiprocessingがわかるようになり、ドキュメントの重要性を感じた。


######参考文献
「Bill Lubanovic著 『入門 Python3』(オライリージャパン発行)」
Rails 5 から 6 にかけての secretes / credentials 周りの変遷

# 概要

* Rails で秘匿情報を扱うための機能 (secrets.yml.enc / credential.yml.enc) は、直近の数バージョンでかなり動きがあり、情報が錯綜していたので、自分なりに整理してみました

# 歴史

## Rails 5.1

* secrets 機能が実装された
    * config/secrets.yml.env と `config/master.key` がペアになっている
        * `config/master.key` の代わりに `RAILS_MASTER_KEY` 環境変数でも OK

## Rails 5.2

* credentials 機能が実装された
    * ほぼ secrets と同じ
    * config/credentials.yml.enc と `config/master.key` がペアになっている
        * `config/master.key` の代わりに `RAILS_MASTER_KEY` 環境変数でも OK
    * config/credentials/環境名.yml.enc を用意することもできるが、[encrypted メソッド](https://github.com/rails/rails/commit/68479d09ba6bbd583055672eb70518c1586ae534) を使ってファイルをいちいち明示する必要があった

## Rails 6.0

* credentials を `RAILS_ENV` から類推できるようになった
    * 例えば production 環境のとき:
        * config/credentials/production.yml.enc があればそれをロード
        * 無かったら config/credentials.yml.enc をロード
    * 上記のように、フォールバックはあくまで yml 単位なので注意！
        * ある項目が config/credentials/production.yml.enc に無かったら config/credentials.yml.enc を探索、ではない
        * つまり環境間で共通の項目はすべての yml に重複して書く必要がある
* 鍵を環境ごとに用意できるようになった
    * config/credentials/環境名.yml.enc と `config/環境名.key` がペアになっている
    * が、環境変数を使う場合は `RAILS_MASTER_KEY` だけしか使えないので注意！
        * `RAILS_環境名_KEY` のような環境変数を用意しても何も起きない
        * https://github.com/rails/rails/commit/d69b04de0ff33237209afea6f6cac3ab27934908#r30575065

# どうしたらいいの

* 環境ごとに変わるものは環境変数で与えて、共通のものは config/credential.yml で与える、というのがいいのではないか

```erb
password: <%= ENV['DB_PASSWORD'] || Rails.application.secrets.database_password %>
```

# 参考

* https://memo.willnet.in/entry/2019/12/22/183550
* https://blog.saeloun.com/2019/10/10/rails-6-adds-support-for-multi-environment-credentials.html
kubernetes の pod で Docker in Docker を実現したい

Kubernetes 上のコンテナの中で docker コマンドを使えるようにしたい、そんなとき...

実現方法として DinD と DooD のどちらを採用すべきか...


## DooD(Docker Outside Of Docker)

- ホストマシンの Dockerデーモン をマウントして、Docker コンテナ内で Docker コマンドを使えるようにする手法

### 実装方法

- Kubernetes のホストマシンの `/var/run` を共有し、Docker デーモン にアクセスできるようにするだけ

```yml
apiVersion: v1
kind: Pod
metadata:
  name: dood
spec:
  containers:
    - name: docker
      image: docker:19.03
      command: ["docker", "run", "nginx:latest"]
      volumeMounts:
        - mountPath: /var/run
          name: docker-sock
  volumes:
    - name: docker-sock
      hostPath:
        path: /var/run
```

### Pros
- 実装が簡単
- 特別な権限を与える必要がない

### Cons
- docker デーモンを共有しているので、Pod 上のコンテナからホストマシンで動作しているコンテナを操作できてしまう

## DinD(Docker In Docker)

- Docker が提供している [docker:dind](https://hub.docker.com/_/docker) イメージを使用し、Docker コンテナ内でさらに Docker デーモンを稼働させることで、Docker コンテナ内でさらに Docker コンテナを配置できるようにする手法

- コマンドラインで DinD を起動する方法は下記の通り

```sh
docker run --rm -it --privileged --name dind-test -d docker:stable-dind
```

### 実装方法

- docker コマンドを実行するコンテナのサイドカーとして Docker デーモンコンテナを動かし、docker コマンドがサイドカーに対してアクセスするように設定する


```yml
apiVersion: v1
kind: Pod
metadata:
  name: dind
spec:
  containers:
    - name: docker
      image: docker:19.03
      command: ["docker", "run", "nginx:latest"]
      env:
        - name: DOCKER_HOST
          value: tcp://localhost:2375
    - name: dind-daemon
      image: docker:19.03-dind
      env:
        - name: DOCKER_TLS_CERTDIR
          value: ""
      resources:
        requests:
          cpu: 20m
          memory: 512Mi
      securityContext:
        privileged: true
```

### ちなみに

- dind-daemon コンテナの `DOCKER_TLS_CERTDIR` を `""` にするのが重要
- `DOCKER_TLS_CERTDIR`を `""` にしないと Docker デーモンが `2376` Portで起動し、TLSモードになるので証明書が必要
- Dockerhub の Docker イメージの [Description](https://hub.docker.com/_/docker?tab=description) の TLS の説明の中に、環境変数 `DOCKER_TLS_CERTDIR` で指定されたディレクトリにTLS証明書を自動的に生成する仕様が、19.03 以降はデフォルトで有効になったと記載がある
- 19.03の Docker のソースコードで、起動 Port の分岐箇所は[こちら](https://github.com/docker-library/docker/blob/master/19.03/docker-entrypoint.sh#L31-L35)

### Pros

- ホストマシンの Docker デーモンとは別に Pod 内のコンテナの中に Docker デーモンが作成されるので、ホストマシンに影響を与えることなく Pod 内で完結する

### Cons
- サイドカーコンテナが１つ増える
- dockerデーモンのサイドカーコンテナは `privileged 権限（特権モード）`で実行する必要がある
- コンテナ内の `/var/lib/docker` は 暗黙的に `Data Volume` が使われるので、コンテナの再生成を繰り返すと不要になった `Data Volume` が溜まっていくため注意が必要


## 大変参考になったリンク

[KubernetesのPodでDockerコンテナを実行する](https://akaimo.hatenablog.jp/entry/2019/07/23/225205)
[A case for Docker-in-Docker on Kubernetes (Part 2)](https://applatix.com/case-docker-docker-kubernetes-part-2/)
[Dockerコンテナ内からDockerを使うことについて](https://qiita.com/esaka/items/37e5d60d66c6061c19d0#docker%E3%82%B3%E3%83%B3%E3%83%86%E3%83%8A%E3%81%8B%E3%82%89docker%E3%82%92%E4%BD%BF%E3%81%86%E3%81%AB%E3%81%AF)
[Docker in Docker のベタープラクティス](https://qiita.com/sugiyasu-qr/items/85a1bedb6458d4573407)
[do-not-use-docker-in-docker-for-ci/](http://jpetazzo.github.io/2015/09/03/do-not-use-docker-in-docker-for-ci/)
[コンテナからコンテナを操作する](https://blog.nijohando.jp/post/docker-in-docker-docker-outside-of-docker/)
フィナンシャルエンジニアリングについてアウトプットをしようと思った訳

##はじめに
 金融系の企業に属しているので、開発のために金融工学の知識を付ける必要がありました。
先輩トレーダーに訪ねたところ、バイブルとして勧められたのがこちら
[**【ジョン・ハル著　フィナンシャルエンジニアリング】**](https://www.amazon.co.jp/dp/4322121764/)
いざ内容を見ても英文を直訳しただけの本文と専門用語の羅列だったので、全くわからない。
そこで、意味を調べながらできるだけ噛み砕いて毎週１章ずつアップしていこうと思いました。
今後の資料及び買ったばかりのHHKB（無刻印）に慣れるためにがんばります。
Inoreader v13 adblock

```
!2020/01/29 Inoreader v13
inoreader.com##[id^="leaderboard_ad-"]
inoreader.com##[class^="ad_title"]
inoreader.com##[id^="reader_pane"]:style(padding-right:0px !important)
inoreader.com##[id^="no_more_div"]:style(height: 100% !important;)
inoreader.com##+js(nostif, raid)
```
pandasのread_csvでcsvファイルを読み込んだら先頭列がindexになる

#概要

社内システムでダウンロードしたデータをpandasで処理しようとしたら、先頭列がindexになってしまってハマった事例の紹介

#現象

問題のデータ（もちろん実際のデータとは違います。）

```csv
name,population,area
Osaka,2691k,223,
Nara,353k,276,
Kyoto,1472k,827,
Koube,1542k,552,
Wakayama,355k,208,
```

一見問題の無さそうな下記のようなデータをread_csv()すると、先頭列（name）がindexになっている。

<img width="747" alt="Screen Shot 2020-01-29 at 23.24.55.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/44112/69312617-ddb4-89d4-9d1e-8fea682bab25.png">

#原因
各レコードの最後には「,」があるのに、Header行の末尾には「,」が無いのが原因。
試しにヘッダー行の最後に「,」を入れると。下のように一列余計なカラムは追加されるがindexは自動で振り出された。

<img width="737" alt="Screen Shot 2020-01-29 at 23.32.12.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/44112/90cbcc4f-5f2f-8951-33c4-1abc578a7e75.png">

今回のサンプルはわかりやすいようにcsvファイルでまとめたが、実際に業務でつまったのはtsv（タブ区切り）だったので余計に時間を要してしまった。

#教訓と感想

ツールに溺れずデータをちゃんと見よう。

にしても、pandasで軽くデータを編集できるようになってからExcelを使う機会が減った気がする。今回のデータも50Mぐらいのtsvファイルだったけど数秒で読み込めたし。（Excelはハングしてしまった・・・・。）
Powershellから実行したPythonのエラー検知

##やりたいこと
- Powershellから実行したPythonのエラー検知
- 例として「csvファイルの区切り文字をタブ区切りに変換する」Pythonの関数を実行
 - 読み込むcsvのエンコードはutf-8とする

##ポイント
- try-exceptを使う
- pythonの関数でdeodeエラーを検知する例外処理```except UnicodeDecodeError```を使う
- Powershellで上記のエラー内容を受け取る
 

##サンプルコード
- タブ変換用の関数を呼び出すコード

```python:exeConvertCsvtoTsv.py

from defConvert import CsvToTsv
import sys

#対象ファイルパス
path = sys.argv[1]

#csvからtsvへ変換
CsvToTsv(path)   
```

- タブ変換用関数

```python:convertTav.py
import csv
import sys
def CsvToTsv(path):

    #読み込み用配列
    line = []
    try:
        #読み込み ⇒ 読み込むcsvのエンコードがutf-8なのでここでエラーが起きる
        with open(path, "r", newline="", encoding="cp932") as f:       
            #読み込みオブジェクト作成（カンマ区切り）
            reader = csv.reader(f, delimiter = ",")
            #読み込み
            line = [row for row in reader]

        #書き込み
        with open(path, "w", newline="", encoding="utf_8") as f:
            #書き込みオブジェクト作成（タブ区切り）
            writer = csv.writer(f, delimiter = "\t")
            #まとめて書き込み
            writer.writerows(line)

    #decodeエラー
    except UnicodeDecodeError as err:
        print(err)
        sys.exit()

    finally:
        #close
        f.close
```

- pythonの関数を実行するpowershell側のコード

```powershell:main.ps1
#読み込むCSV
$csv = "test.csv"

try{ 
    #ファイル確認
    if((Test-Path $out) -eq $false){
        $ret = "No File"
        Throw $ret
    }

    #CSVからTSVへ変換
    $ret = $null
    $ret = python exeConvertCsvtoTsv.py $out #$retでpython側の実行結果を受け取る
    if($null -ne $ret){
        Throw $ret
    }
}
catch{
    Write-Host "SQL Execution Error`r`n$ret"
}
finally{
    Write-Host "end"
}
```

```powershell:結果
#decodeエラー
SQL Execution Error
'cp932' codec can't decode byte 0x85 in position 7: illegal multibyte sequence
end
```

- Pythonは例外の種類ごとに例外型が用意されていて便利
 - ```except 例外型 as 別名：```
 - decodeエラーなら```UnicodeDecodeError```
 - 0除算エラーなら```ZeroDivisionError ```
- 例外発生時に何もしない時は```pass```でスルーできる
iOSのショートカットからBandに投稿する

## BANDとは

> BANDは、グループコミュニケーションを促進するモバイルコミュニティアプリケーションです。 Naver Corporationによって作成されたこのサービスは、iOS、Android、およびデスクトップで利用できます。 
https://en.m.wikipedia.org/wiki/Band_(software)

LINEの姉妹アプリですね。

## ショートカットとは
日々の些事を省略してくれるiOS用のアプリケーションです。
https://apps.apple.com/jp/app/%E3%82%B7%E3%83%A7%E3%83%BC%E3%83%88%E3%82%AB%E3%83%83%E3%83%88/id915249334

## BAND API
BANDはAPIを提供しています。
ユーザのプロフィールを取得したり、投稿をしたりできます。
https://developers.band.us/develop/guide/api

# 目標
ショートカットからBANDに投稿すること。

## BAND APIにレジスターする

https://developers.band.us/develop/guide/api から、「My Apps」>「Register」を押下します。

### Registering an App
__Basic Information__

| 項目        | 値       |
|:-----------------|:------------------|
| Service Name | 任意 |
| Category | 任意 |
| Redirect URI | 任意（適当なURIで可） |

を記入します。

__Term of Service__
同意します。

## Service(App) ダッシュボード
_Access Token_を取得するために、自分のBANDとリンクさせます。

_Client ID_、_Client Secret_、_Access Token_を入手しました。

## ショートカットを作成する
[iCloudリンク](https://www.icloud.com/shortcuts/64b629f750a74611a249639be85cb424)からショートカットを入手し、ご自身の環境変数（_Client ID_、_Client Secret_、_Access Token_）を設定してください。

詳しい説明はショートカットを実際に見てください。

Safariの共有シートからこのショートカットを実行すると、投稿が成功するはずです。もしエラーが発生する場合は、BAND APIのリファレンスをお読みください。

### 備考
Contentにバイナリファイルを添付する方法があるのだろうか。

# リファレンス
- [Band API - Write Post](https://developers.band.us/develop/guide/api/write_post)
- [「ショートカット」のWeb APIの概要](https://support.apple.com/ja-jp/guide/shortcuts/apd2d448b2de/3.2/ios/13.2)
QGISでXYZ TilesラスターをGDALの処理対象にしてはいけない

常識なのかわからないが、１時間くらいハマったのでメモ。結論はタイトルのとおりです。

## ハマりどころ
![スクリーンショット 2020-01-29 23.18.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73197/2f65e2b5-ca76-25d5-2346-76ad072803a8.png)

画像のように、XYZTilesがデータソースのラスターレイヤーをGDALのinputにすると以下のエラーが発生します。

```
GDAL command:
gdal_translate -projwin 15035200.093663722 6341338.464803632 17500752.87803036 4071703.688974686 -of GTiff type=xyz&url=https://tile.openstreetmap.org/%7Bz%7D/%7Bx%7D/%7By%7D.png&zmax=19&zmin=0 /var/folders/7k/k1kthlzj373_fb038q38tmzr0000gn/T/processing_398638b5f39c416ab16b32ab626cdf75/17a16b3aac7c43baad3ae048d6914b0c/OUTPUT.tif
GDAL command output:
/bin/sh: /var/folders/7k/k1kthlzj373_fb038q38tmzr0000gn/T/processing_398638b5f39c416ab16b32ab626cdf75/17a16b3aac7c43baad3ae048d6914b0c/OUTPUT.tif: No such file or directory

〜中略〜

出力レイヤの読み込み
次のレイヤは正しく生成されませんでした。<ul><li>/var/folders/7k/k1kthlzj373_fb038q38tmzr0000gn/T/processing_398638b5f39c416ab16b32ab626cdf75/17a16b3aac7c43baad3ae048d6914b0c/OUTPUT.tif</li></ul>QGISメインウィンドウの"ログメッセージパネル"をチェックすると、アルゴリズムの実行に関する詳細情報が表示されます。

```

## 解決
パスが通っていないのかな〜なんて１時間くらい困っていると、[Reddit](https://www.reddit.com/r/QGIS/comments/980a7f/no_such_file_or_directory_error_when_trying_to/)に答えが書いてありました。

>I may be wrong but I think you need to input a file or directory instead of a map service. You could export a raster of your area of interest and use that as input, or maybe you can load your service into a virtual raster layer and try inputting that.

ということで、一旦ローカルに.tifファイルとして保存してからGDALを動かしたらちゃんと動作しました。
Acronis Cyber Backup 12.5 でWindows Server 2003　Agentインストール

# Windows Server 2003にAcronis Cyber Backup 12.5 のAgentを入れたときのメモ

## 環境
- ESXi
- Windows Server 2003　SP2
- Acronis Cyber Backup 12.5

## 画面
1. exeをダブルクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315938/d10dec44-6693-5e90-fa9d-c1b5580332b0.png)

2. ライセンス契約に同意
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315938/e43cb0a2-e8a0-d521-3be6-1676ac695284.png)


3. エージェントしか入れられないので、そのままインストール
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315938/ebe83f61-87f8-97ab-1aa0-a1a9107e28a7.png)
ちなみに「インストールの設定をカスタマイズ」を押すとこんな画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315938/5be6be09-8098-90d0-0a46-18bf3f3566dd.png)


4. 管理サーバーの情報を入力（デフォルトだと管理サーバーは匿名でのアクセスを受け付ける）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315938/f988d0f2-fffc-1012-fc62-8c1a65e46dfb.png)


5. 何かパッチが当たるらしい
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315938/25fbda02-52fd-452c-4ba2-edf0f00c9cbe.png)


6. しばし待ち
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315938/c5bb84e7-f472-65a8-e20c-f3e20b1c16a5.png)


7. おわり
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315938/721abefc-40db-4cad-d1eb-159d09c2d4b4.png)
Acronis Cyber Backup 12.5 でWindows XP　Agentインストール

# Windows XPにAcronis Cyber Backup 12.5 のAgentを入れたときのメモ

## 環境
- ESXi
- Windows XP　SP3 x86
- Acronis Cyber Backup 12.5

## 画面
1. exeをダブルクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315938/62b3d775-1212-934c-193f-c8b3c19a40ce.png)



2. ライセンス契約に同意
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315938/dc5fae42-5c12-649a-4102-cce06802d25d.png)


3. エージェントしか入れられない、そのままインストール
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315938/21956230-5c4d-a912-f44b-1331e6abac4d.png)
ちなみに「インストールの設定をカスタマイズ」を押すとこんな画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315938/fa2a4a03-7b2e-27cf-905d-39842e51c524.png)

4. 管理サーバーの情報を入力（デフォルトだと管理サーバーは匿名でのアクセスを受け付ける）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315938/e6a84755-af16-121e-cc04-f1e328ed614e.png)


5. しばし待ち
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315938/de2554de-de59-5e90-b42c-e868e6bfd8b0.png)


6. 再起動させて終わり
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315938/ecfbcb8f-3dbc-fd5e-2c48-d3993a8ff5a5.png)
Ruby基礎(繰り返し)

#繰り返し文について
今までは1つの変数に、1つの値を入れて表示させてきました。
しかし、実際のアプリを作るとき
**1つの変数に複数の値**
がはいることが多々あります。

そしてその**複数の情報を表示させる。**

といったコードがあるのでそれを今回学んでいきます

##each文
代表的なところでいうとこの**each文**になります。
これは**複数の情報1つ1つ最後まで繰り返し処理**をしてくれる文になります。

例えば1つの要素に10個の要素があれば10回繰り返し処理をしてくれます。

それでは実際にコードを書いていきましょう！

##実際に書いて動かしてみよう！

毎度のごとく新しい分野なので、**新しいファイルを作成(each.rb)**してください。

保存したら以下のコードを書いてください。

```ruby:each.rb
integer = 1..5

integer.each do |i|
  puts i
end
```
かけましたか？？
では、これを実行してみましょう！

```ruby:ターミナル
1
2
3
4
5
```
<font color="blue">※1..5はい1から5までの数字を表しています。</font>

と表示されましたか？？
このように変数**integer**に複数の値が入っていましたが、全て表示してくれまで
**integerの数値を表示する処理を繰り返し**
してくれました。

これをeach文を使わないでかくと

```
integer = 1
puts integer
integer = 2
puts integer
integer = 3
puts integer
integer = 4
puts integer
integer = 5
puts integer
```

となります。
これが100まであると思うとやめたくなりますよね。笑

このように繰り返し処理は短く、便利にしてくれますので、ぜひ覚えておきましょう！

次は**文字列**でやってみましょう!

```ruby:each.rb
name = "太郎","次郎","五郎"

name.each do |n|
  puts "私の名前は"+n+"です。"
end
```
かけましたか？
では、これを実行してみましょう

```ruby:ターミナル
私の名前は太郎です。
私の名前は次郎です。
私の名前は五郎です。
```
このように表示されましたか？
文字列も同様に繰り返し処理をしてくれましたね！

##練習

このeach文を使って
**新規ファイル作成(sample3.rb)し、掛け算の2段を表示**
させてください。
※変数名は自由です。
<font color="red"><details><summary>**正解はこちら！！**</summary><div></font>

```ruby:sample3.rb
integer = 1..9

integer.each do |i|
  puts 2*i
end
```

```ruby:ターミナル
2
4
6
8
10
12
14
16
18
```

</div></details>

上記のような結果は出ましたか？？

#終わり
**each文**はどのアプリでも非常によく出てくるメソッドになります。
自分でも色々試して、身につけていきましょう！

本記事はこちらで以上になります！

お疲れ様でした！
【第3回】pythonでCPUとメモリの使用率を取得する

# 早速やってみよう。
## 前回はCPUとメモリのログを取れるようにした。
## 動作確認環境
- mac catalina
- windows10 1909
- ubuntu 18.04

## やっておくと便利なこと
- pyinstallerで実行ファイルにしちゃう。
- オプションは、onefileとnoconsole
- これをやっておくと実行ファイルだけ配布すればよくなる。
- 利用する環境にpython入ってるとは限らないので。
- 下記のように・・・

```bash
$ pyinstaller xxxx.py --onefile --noconsole
```

### 今回は、ディスクの使用率もとれるようにした。
- ソースを載せるだけじゃだめだよね。説明も必要だよね。とおもいつつ。
- ソースだけを載せてしまう。


```python3
#!/usr/bin/env python
import psutil as psu
import tkinter as tk
import sys
import os
import datetime

# tkinterでwindowの作成とタイトルを作る
# windowサイズの指定
root = tk.Tk()
root.title(u"CPU使用率&メモリ使用率&ディスク使用率")
root.geometry("600x100")

# cpu用ラベル
Static1 = tk.Label(text=u'CPU:')
Static1.pack(side='left')

# CPUの取得した使用率を表示する
txtcpu = tk.Entry(width=20)
txtcpu.pack(side='left', padx=0)

# memory用ラベル
Static2 = tk.Label(text=u'memory:')
Static2.pack(side='left')

# memoryの取得した使用率を表示する
txtmem = tk.Entry(width=20)
txtmem.pack(side='left', padx=0)

# disk用ラベル
Static3 = tk.Label(text=u'disk:')
Static3.pack(side='left')

# diskの取得した使用率を表示する
txtdsk = tk.Entry(width=20)
txtdsk.pack(side='left', padx=0)


log = './cpumem.log'


def btn_click():
    # テキストボックスをクリア
    txtcpu.delete(0, tk.END)
    txtmem.delete(0, tk.END)
    txtdsk.delete(0, tk.END)

    if os.path.exists(log):
        # logファイルがある場合
        with open(log, mode='a', encoding="utf-8") as f:
            # 時間の取得
            dt_now = datetime.datetime.now()
            # 日時のフォーマット修正
            dt = dt_now.strftime('%Y/%m/%d %H:%M:%S')
            # メモリの利用情報を取得
            memory = psu.virtual_memory()
            txtmem.insert(0, memory.percent)
            # CPUの使用率を取得
            cpu_percent = psu.cpu_percent(interval=1)
            txtcpu.insert(0, cpu_percent)
            # diskの使用率
            disk_percent = psu.disk_usage(path='/').percent
            txtdsk.insert(0, disk_percent)

            # textboxの値を取得
            cpulog = txtcpu.get()
            memorylog = txtmem.get()
            disklog = txtdsk.get()

            # ログに出力するフォーマット(日付 時間 cpu使用率 メモリ使用率 disk使用率)
            f.write(dt + " " + cpulog + " , " +
                    memorylog + " , " + disklog + "\n")
    else:
        # logファイルがない場合
        with open(log, mode='w', encoding="utf-8") as f:
            # 時間の取得
            dt_now = datetime.datetime.now()
            # 日時のフォーマット修正
            dt = dt_now.strftime('%Y/%m/%d %H:%M:%S')
            # メモリの利用情報を取得
            memory = psu.virtual_memory()
            txtmem.insert(0, memory.percent)
            # CPUの使用率を取得
            cpu_percent = psu.cpu_percent(interval=1)
            txtcpu.insert(0, cpu_percent)
            # diskの使用率
            disk_percent = psu.disk_usage(path='/').percent
            txtdsk.insert(0, disk_percent)
            # textboxの値を取得
            cpulog = txtcpu.get()
            memorylog = txtmem.get()
            disklog = txtdsk.get()
            # ログに出力するフォーマット(日付 時間 cpu使用率 メモリ使用率 disk使用率)
            f.write(dt + " " + cpulog + " , " +
                    memorylog + " , " + disklog + "\n")


# ボタンの生成
Button = tk.Button(root, text='使用率取得', command=btn_click)
Button.pack(fill='x', side='left', padx=0)

root.mainloop()
```
Acronis Cyber Backup 12.5 管理コンソール　インストール

# Windows Server 2019にAcronis Cyber Backup 12.5 管理コンソールを入れた時のメモ
## 環境
- ESXi
- Windows Server 2019
- Acronis Cyber Backup 12.5

## 画面
1. exeをダブルクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315938/0d7b6def-3e68-e111-5a8b-3e567eca3d77.png)

2. ライセンス契約に同意
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315938/bbd74438-a451-7913-448c-637bb5d03ddc.png)

3. そのままインストール
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315938/409caabd-a37e-3aef-2214-885e550e6ff3.png)
ちなみに「インストールの設定をカスタマイズ」を押すとこんな画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315938/b43c174f-10f4-5262-a1f2-8582b0917168.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315938/3da1de67-f0ee-b144-5fa0-fb656694f450.png)


4. しばし待ち
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315938/2cf10e16-f9a4-a9e9-5c53-585da84af53d.png)

5. できたー
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315938/086eec8c-8c41-2c93-863f-d92cca3ce996.png)

6. こんな感じの管理画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315938/bb0e09eb-3b6b-7c0e-a70d-dbeb55e49738.png)
CSS Flexbox チートシート

Flexboxを使うとき、ちら見できるようなチートシートを作成しました。
使い方の説明はチートシートの後に続きます。

Grid Layoutのチートシートは[こちら](https://qiita.com/7dt/items/577ba8eada3380c93dbb)

#Flexbox チートシート
![flexbox cheat sheet japanese.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/575706/12463cc7-2ad6-dc89-1c43-e32e88f65257.jpeg)

####PDF版は[こちら](https://umikuru.com/codingInfo/flexbox.html)

##Flexboxチートシートの見方
チートシートの左側は親要素に設定するプロパティ、

右上は子要素に設定するプロパティ、
右下は各プロパティと各値の説明になります。

よく使うプロパティは太文字、デフォルトは黄色文字です。
人型アイコンは参照を示し、枠人型①に対しては塗人型①を参照してください。
手型アイコンはショートハンドプロパティを示しています。
![icons.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/575706/bd27d238-ae76-e75e-2716-be256dbb2040.jpeg)

##Flexboxの作り方
チートシートを見ながら読み進めてください。

###①親要素をフレックスコンテナとして指定する。
display: flex; 
これだけでデフォルトである flex-direction: row; のflexboxができます。

###②フレックスコンテナの主軸方向を指定する。
flex-direction:
チートシート左側にある②の四つの選択肢から、主軸方向を選択します。
デフォルトでは左上にある flex-direction: row; が設定されますが、
他に row-reverse; column; column-reverse; の三種類が選べます。
![flex-direction.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/575706/bade9215-5d8c-b828-5674-a967a3389be1.jpeg)

flex-wrap:
子要素（フレックスアイテム）が多い場合は flex-wrap: で折り返しの方法を指定します。

|値　　　　     |説明            |
|:-----------:|:-------------:|
|nowrap;      |折り返しなし     |
|wrap;        |折り返しあり     |
|wrap-reverse;|逆方向から折り返し|

flex-flow:
flex-direction: と flex-wrap: のショートハンド


###各要素の位置やサイズを調整して完成。
各要素の位置調整には、②で設定した主軸、交差軸方向が影響します。
各プロパティに対する指定可能な値についてはチートシートの各項目を、
それぞれの値の動き方については右下にある人型②を参照してください。

####親要素に設定するプロパティ

| プロパティ       | 説明 |
|:--------------:|:--------------------------------------:|
|justify-content:|主軸方向における子要素の位置指定　（人型①参照）|
|align-items:    |交差軸方向における子要素の位置指定　（人型①参照）|
|align-content:  |flex-wrap: で折り返された行の交差軸方向の位置指定　（人型①参照）|

####各子要素に設定するプロパティ

| プロパティ       | 説明 |
|:-:|:-:|
|flex-grow:|伸びる比率|
|flex-shrink:|縮む比率|
|order:|順序の指定|
|flex-basis:|主軸方向におけるサイズ指定（widthにもheightにもなり得る）|
|align-self:|交差軸方向における各子要素の位置指定　（人型①参照）|
|z-index:|子要素同士の重なりの順序指定|
|flex:|flex-grow: と flex-shrink: と flex-basis: のショートハンド|
 
主軸、交差軸方向がわかると簡単にFlexboxが使えますね！
英語版のチートシートはこちら。

#Flexbox cheat sheet / English version
![flexbox cheat sheet.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/575706/b9e481fd-daac-4805-74f6-8d7ea13ce6e8.jpeg)

Grid Layoutのチートシートは[こちら](https://qiita.com/7dt/items/577ba8eada3380c93dbb)

###参考
[MDN: flexbox](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flexible_Box_Layout/Basic_Concepts_of_Flexbox)
[CSS-TRICKS: flexbox](https://css-tricks.com/snippets/css/a-guide-to-flexbox/)
[Udemy: CSS - The Complete Guide 2020 (incl. Flexbox, Grid & Sass)](https://www.udemy.com/course/css-the-complete-guide-incl-flexbox-grid-sass/)
couldn't open file /usr/local/var/centos7のエラーはvagrantfile生成コマンドで治る




#エラー内容
couldn't open file /usr/local/var/centos7

#対処法
vagrant init bento/centos-6.8



Couldn't open file /usr/local/var/base
の場合は

$ rm Vagrantfile
$ vagrant init CentOS7
$ vagrant up
で解決
AWS SESをGoでサンプルアプリケーションを作ってみた

仕事でsesを使う機会があったので、手元で試してみたく、サンプルアプリケーションを作りました。

# 前提
実装は組み込めるようにしたものではなく、サンプルアプリケーションを動かすだけのものです。

# sesの設定
## SMTPの設定
SMTP Settings > Create My SMTP Credentialsを選び、適当な名前でIAM Userを作成します。
ここを参照するとわかりやすいです。
https://docs.aws.amazon.com/ja_jp/ses/latest/DeveloperGuide/smtp-credentials.html

## ポリシーの設定
IAM Userを作成しただけでは、メールが送信できませんでした。

```
$ go run main.go
AccessDenied: User `arn:aws:iam::11111111:user/ses-smtp-user' is not authorized to perform `ses:SendEmail' on resource `arn:aws:ses:us-west-2:11111111:identity/test@example.com'
	status code: 403, request id: 111111111
```

なので、IAMのコンソール画面で `SendEmail`ポリシーの設定をします
https://docs.aws.amazon.com/ja_jp/ses/latest/DeveloperGuide/control-user-access.html#iam-and-ses-examples-email-sending-actions

## 使用するメールアドレスを有効にする
実際に使う場合はドメインを設定する必要があると思いますが、一旦メールアドレスを設定します。
Email Addresses > Verify a New Email Addressから適当なメールアドレスを入力します。
`Verify This Email Address`を押すと入力したメールアドレスにメールが届くので、そのメールの中のリンクをクリックしてメールアドレスを使えるようにします。

## 認証ファイルの作成
```~/.aws/credentials
[default]
aws_access_key_id = YOUR_AWS_ACCESS_KEY_ID
aws_secret_access_key = YOUR_AWS_SECRET_ACCESS_KEY
```
https://docs.aws.amazon.com/ja_jp/ses/latest/DeveloperGuide/create-shared-credentials-file.html

# アプリケーションの実装
サンプルは[こちら](https://github.com/shigeru10/go_ses)
https://docs.aws.amazon.com/ja_jp/ses/latest/DeveloperGuide/examples-send-using-sdk.html

ConfigSetを使用すると送信数などを計測できるようになるようですが、一旦必要ないのでそこはコメントアウトしています。
https://docs.aws.amazon.com/ja_jp/ses/latest/DeveloperGuide/event-publishing-create-configuration-set.html

```
$ go run main.go
Email Sent!
{
  MessageId: "0101016ff173d049~~~~~~"
}
```

実際に届いたメールはこちら
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/88791/882245f1-3e44-0b49-2d6c-a37fe4a3ae53.png)

# まとめ
ただ、メールを送信するだけならとても簡単にできそうでした。
実際に本番に適用する際に何が必要なのかもう少し調べてみようと思います
日付を適切にローカライズする[Kotlin]

ローカライズをしようと思った時に、ちょっと厄介なのが日付部分です。言語によって文字列も、記述順序も変わります。が、 `DateFormat` にある `getBestDateTimePattern` というメソッドを使えばそこらへんを自動でよろしくやってくれます。ということでこの記事では `getBestDateTimePattern` を紹介しようと思います。

# getBestDateTimePattern の特徴

* API Level 18 (Android 4.3)以上で使用可能
* 何の日付要素を表示するか（yyyyMMなど）を細かく設定できる
* 適切な日付要素の順番に並べてくれる

# サンプルコード

```kotlin
private fun localizedDateString(epochSecond: Long): String {
    val local = Locale.getDefault()
    val format = DateFormat.getBestDateTimePattern(local, "EEEMMMd")
    val dateFormat = SimpleDateFormat(format, local)
    return dateFormat.format(epochSecond)
}
```

# 実行結果

設定アプリから言語を変更して試した結果がこちらです。Localeと結果文字列を出力しました。

```
ja_JP： 1月29日(水)
en_US： Wed, Jan 29
en_GB： Wed 29 Jan
es_ES： mié., 29 ene.
de_CH： Mi., 29. Jan.
```

`getBestDateTimePattern` の第二引数には"EEEMMMd"と渡しているのに、言語に合わせて順番や書式が自動変換されているところが注目ポイントです。
エンジニア採用勉強会「エンジニア採用を成功に導く求人票の極意とは？」振り返りメモ


## はじめに

先日、こちらに参加してきました。

[「エンジニア採用を成功に導く求人票の極意とは？」](https://findy-enterprise.connpass.com/event/158529/)

「エンジニア採用の勉強会」ってなかなか存在しないので、有給を使って名古屋から参加させていただきました。

特に人事向けの内容であるのが重要です。

弊社勉強会の交通費・参加費を負担してくれるので本当に助かっています。名古屋に住んでいますが、この制度のおかげで関東との格差を感じることなく生活できているのかなぁと感じる。(もちろん0ではないのだけれど、、)

この勉強会の内容は、SNSやブログ発信OKとのことだったので、振り返りメモとしてまとめます。(写真も撮ってくださいな感じだったので、とても助かる。)

自分用メモみたいなノリで書いているので、解釈が若干ずれていたり、内容そのまま書いていないところもあるので、それは最初に断っておく。

では、内容に入っていきます。



## ある企業では求人票の改善を進めた結果、半年間で応募数が2倍弱に増加
ある企業の求人を修正したところ、半年間で応募が2倍弱になったとのこと。では、いったい何をしたのか？

1. 求人票の定期的なブラッシュアップ

2. 長期で必要な求人も掲載

＜具体的にはどんなことをしたのか？＞

・Webアプリ 

→ バックエンド、フロントエンドといった感じに細分化する。

・ジュニアクラスか、マネージャクラスなどレベル感で募集を分ける。→給与レンジの最低と最高の幅が500万以上あるなら、レベル感によって分けるべし。



## 求人票をしっかり書くとどんな効果がある？
求人票を狙いどころを意識して書く用にすると、以下のような相乗効果が出てくる。

#### 1. 人事とエンジニア部門間で欲しい人材を共通認識として持てる。

→ 人事面接とエンジニア面接における合否判定のずれが減少する。

求人票を書くには、エンジニアのサポートとアドバイスが不可欠なので、エンジニアの声を聞くことで認識のズレがなくなっていく。

#### 2. エンジニア部門間で欲しい人材を共通認識として持てる。

→ エンジニア面接における合否判定野ずれが減少する。

エンジニアの間でも、共通認識が生まれ、会社全体で誰を求めているかを共通認識を持てるようになる。

#### 3. 口説きのレベル感がアップする。

→内定承諾率が上がる。

狙いどころが明確になるので、その層に合わせた口説き言葉をチョイスできるようになる。



##「採用できない」負のスパイラルにいる時、抜けるためにすべき3つのこと
#### 1. 情報を整理する。

・現場の声を聞き、人材要件を確認する。

→ 「人事」「エンジニア」双方で、人件要件を定義、求人票を作成する。つまり、現場 = エンジニアの思いを汲み取り、現場と人事間のズレをなくす。

・最低限記載すべき6項目に加えて、開発環境などMECEに記載する。

→ エンジニア目線の求人票が作成できていない可能性があるので、最低限の情報が網羅できているかまず見直したい。

#### 2. 情報を分かりやすく書く

・簡潔かつ具体的に書く。

・その役職ならではの独自性を出す。

・役職別、職種別に求人票を分ける。(求めるスキルや給与条件も正確に記載する。)

＜例えばどう分ける？＞

モバイル → iOS, Android。

Webエンジニア → Ruby, Goなど。

→ 求職者に "自分のスキルで応募できる募集はないな、、"と思わせない工夫が必要。

＜年収レンジが500万とかある求人票って意味ある？＞

下限と、入社後の上り幅がイメージできる必要は確かにある。でも差がありすぎると、応募者のお気持ちは「明らかに同じポジションの給与じゃないよね、、？」みたいな疑心暗鬼な感じになってしまう。

JavaScriptであれば、フレームワークは何なのか？を明示したり、「最低限の知識があればいいのか？開発経験が必須なのか？」など、知識・経験レベルはどのくらい必要なのかも明確にする。

少し、脱線するけど話の中で気になった言葉。

エンジニアは、一文字でも間違っていると動かないプログラミングの世界で常に戦っているから、表記のゆれや間違いを細かく気にする。
非エンジニアだとあまりない感覚なので、注意したいと思った。(そもそも誤字脱字は許されるべきではないが、、)

言語やフレームワークの綴りの書き間違えは、十分起こりうるので注意が必要。

#### 3. 上手に見せる
・適切な媒体を選定し、頻度を高く更新する。

・5つの魅力ポイントから自社の魅力を引き出す。

・「事実」だけでなく、「ストーリー＝時間軸」を意識して伝えること

＜上手に見せるための訴求ポイントは何か？一度整理してみよう。＞

・有名なエンジニアが社内にいること(twitterで有名、GitHubのスター数)

・最新の技術を積極的に利用している。

・経営陣が技術理解があること。

・トラフィック数、ユーザー数が豊富

・OSSの貢献を推奨している。

・ハッカソンの入賞実績

・副業可の記載

・高性能なチェアーの配布

・プロダクトの優位性

・ミッション、ビジョンの優位性

・福利厚生、人事制度

・インセンティブ(年収、SO付与)

＜Findy流に魅力ポイントは5つに分類できる！＞

技術・プロダクト軸

・最新の技術を積極的に利用している。

・プロダクトのDL数、トラフィック数、データ量多い

事業軸

・業界の成長性、競合他社との違い

・どういった「課題」を解決するのか？

・会社のミッションやビジョン

ヒト軸

・経営陣が技術理解があること

・社内のエンジニアが有名(元Google、 Rubyコミッター)

働き方軸

・働き方の柔軟性(フルリモートOK、フルフレックス制)

・福利厚生の充実(カンファレンス出張費支給)

インセンティブ軸

・年収が高い、SOが付与される

・CTO候補、テックリードなどのポジションの魅力



## 最近の求人票トレンド「issue型採用」
一職種ではなく「解きたい課題」に応募する

・issue = 課題単位で応募可能。

・正社員だけではなく、業務委託(法人・個人問わず)で応募できる。

・応募者自身が、自分で強く解きたいと思うissueを掲げて応募することも可能。

「事実」だけではなく、「現状や未来を絡めたストーリー」を意識して伝えることが大事。

今までは、こうだったけど、将来はこうしていきたいと考えている。その差分を埋めるため、「課題 = issue」を解決できるあなたが欲しい。　
経営やエンジニアを巻き込んで、採用を行っていくことが大事。



## 最後に感想
現状クリアできていることも多かったが、「これで大丈夫かなぁ、、」みたいな不安は絶対拭えないのである程度の基準を確認できたのはとても良かった。

Findyさん始め、気合入れて採用やっている企業が多いと体感できたので、負けてられないという気持ちになった。いい刺激をもらえたと思う。

名古屋にはこの類の勉強会は皆無なので、自分で開催して情報共有したり、切磋琢磨していくのもありだなぁと思った。(自社ばかり見ていると、視野が狭くなりがちなので。)

思い出したことがあれば、アップデートしていきます。
cowsayで現場猫にヨシ！されたい件

業務中でも現場猫にヨシ！してほしかったので、cowsay を使ってなんとかしてみました。

## Intoroduction
cowsayは言うまでもなくイカしたサーバに相応しい魅惑のツールです。殺伐とした私たちの心に一服の清涼を与えてくれます。
一方、現場猫も何とも可愛らしく、ヒューマンエラーの怖さを私たちに訴え続けています。

そして、そうとなれば早速

＿人人人人人人＿
＞　２身合体　＜
￣Y^Y^Y^Y^Y^Y^￣

## やりたいこと
- cowsay の cow ファイルに現場猫を追加

## 作業履歴

1. もちろんcowsay は事前にインストールしておきます。CentOSやDebianではパッケージ化されているようですので、楽ちんに用意できますね。本当にありがとうございます。
1. cow ファイルの準備
  - 現場猫のAAは、ＡＡ弐典さんで公開されてますので有難くコピペさせて頂きます。
     - http://heno2.com/2ch/v.php?70003
  - cow ファイルはたぶん、/usr/share/cowsay/cows あたりにあると思います。それぞれの環境にあわせて読み替えてください。
  - 新しく、cow ファイル(yoshi.cow)を以下のように書いてみます。cow ファイルは perl でいい感じに $the_cow 変数にAAを放り込む感じです。

     ```perl:yoshi.cow
	$the_cow = <<EOC;
	  $thoughts
	   $thoughts
	    $thoughts
	　　　 ∧　　/ヽ
	　　　/／￣￣＼|
	　　 ∠＿n＿＿〉
	　　/　①八①　ヽ ＿
	　 工ﾆf(_人_)ｴ二|′)ヽ
	　　＼ヽヽノノ ノ ヘ |
	⊂⌒)_＞―――′イ (＿)
	　`ー､_ノ/￣ヽ　｜
	　　 ＿|｜　 |　｜
	　　(　 人＿ノ　Λ
	　　 ＼ス￣￣ﾚ-Λ ＼
	　　(￣　)　/ /　＼ﾉ＼
	　　 ￣￣　(　ヽ　 ＼_)
	　　　　　　＼ノ
	EOC
     ```

1. cowsay 側の修正
おおっと、このままcowsayを実行しても、AAは文字化けしてしまう。cowsay 側でAAを UTF-8 に変換させてから出力させてしまいましょう。Debian なら /usr/games/cowsay , CentOS なら /usr/bin/cowsay だったと思うのでおもむろにスクリプトを改悪してしまいましょう。
なぁに、失敗しても入れ直せばいいさ。

- 先頭付近でライブラリを読み込むところがあるので、Encode モジュールを追加してしまいましょう。use hogehoge が連続してるところの最後にこっそり入れます。


```perl:cowsay
(snip)
use Getopt::Std;
use Cwd;
use Encode;     # これを追加
(snip)
```

- $the_cow 変数を出力してるところがあるので、コメントしてしれっと decode しておきます。

```perl:cowsay
(snip)
&construct_balloon;
&construct_face;
&get_cow;
print @balloon_lines;
#print $the_cow;                   # これをコメントアウト
print decode('UTF-8',$the_cow);    # しれっとdecode
```

## 完成！
```bash
$ cowsay -f yoshi "ヨシ！してほしいこと"
```

![WS000002.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/559646/a6cfbd5c-8789-1ef9-afe5-2e3e26b1f9b4.jpeg)

ansible でヨシ！して欲しい時は、ansible.cfg の cow_selection を yoshi にすると更に幸せが待ってるよ。
playbook が失敗してもヨシ！なので原作？に忠実です！

ジョジョが好きな方はジョースター卿にするのもよいですね。みなさんの心の潤いになれば幸いです。

## 出典

  - 現場猫
    - くまみねさんごめんなさい。LINEスタンプ買ったので許してください
    - https://kumamine.blogspot.com/

  - AAはＡＡ弐典さんから拝借しました
    - http://heno2.com/2ch/

  - cowsay
    - 公式が分からなかったのでWikipediaの記事をご紹介
    - https://ja.wikipedia.org/wiki/Cowsay