OmniAICreator/Qiita-1.07M huggingface dataset:
JavaScript 演算子⓵ 四則演算+𝑎

#はじめに
この記事では、四則演算や余剰(余り)に使用する演算子について解説します。

#四則演算
```JavaScript:sample.js
let num;
let string;

num = 5 + 3; //変数numに5と3の和を代入する

string = "ES" + "6"; //変数stringに"ES"と"6"を連結した文字列を代入する

string = "ES" + 6; //変数stringに"ES"と6を連結した文字列を代入する

num = 7 - 2; //変数numに7から2を引いた値を代入する

num = 4 * 5; //変数numに4と5の積を代入する

num = 6 / 2; //変数numに6で2を割った値を代入する
```
演算子はそれぞれ役割があります。
`+`
数値の加算、文字列の連結
`-`
数値の減算
`*`
数値の乗算
`/`
数値の除算


#余剰、べき乗、その他
```JavaScript:sample.js
let num;
num = 5 % 2; //変数numに5で2を割った余りの値を代入する

num = 10 ** 2; //変数numに10の2乗を代入する

num = 10++; //変数numに10を代入し、10+1

num = ++10; //変数numに10+1を代入する

num++; //変数num+1

num = 6--; //変数numに6を代入し、6-1

num = ++6; //変数numに6-1を代入する

num--; //変数num-1

let string = "3";
let num2 = 5;

num = +string; //変数numに、数値の変数stringを代入する

num = -num2; //変数numに、負の値の変数num2を代入する
```
これらの演算子の役割は、以下の通りです。
`%`
数値を割った余り(余剰)
`**`
数値のべき乗
`++`
数値に+1　前置記法なら先に+1して値を返し、後置記法なら値を返してから+1
`--`
数値に-1　++と同じく、前置記法と後置記法がある
`+`
数値を正の数にする　文字列でも可能
`-`
数値を負の数にする　文字列でも可能

#最後に
⓶では、型を調べる演算子をとりあげようと思います。
他言語経験者がPyQを使用してPythonを学習した感想

## 前提
- 業務でJavaは4年、Javascriptは3年ほど経験があります。
- 新規案件でPythonを使用することとなり、新プロジェクトのメンバーにPyQを勧められました。
- まずはプログラム経験者向けの文法速習、ライブラリの使用方法を完了し、Webアプリ・APIコースの途中まで完了しています。
- ライトプランで学習しているので、質問等は行っていません。
- 実務に入るのはこれからなので、どの程度役に立ったか後ほど記載するかもしれません。

QiitaにはPyQに関する記事が1年以上前のものしかなさそうだったので、Python学習を始めてみようかなと思う方への参考として、自分の学習メモがてら記事を作成しました。

## PyQ良かったところ
- プログラム経験者向けの文法速習コースがあること。変数やら文字列やら単純な計算やら、未経験者向けの学習サイトだとまだるっこしい説明がわりとさくさく終わり、Pythonの癖を中心に学習できました。
- Django、スクレイピング、統計分析、機械学習など基礎にプラスアルファできるコースがあり、「Pythonを使ってやりたいこと」まで踏み込んで学習できます（※Django以外はまだ学習していないので、どのコースがどの程度実務に役立つかまでは不明）。
- Pythonに限らず、プログラミングで使用する単語の用語集があるので初学者にも優しいと思います。参考として公式ドキュメントへのリンクも多々あるので、公式ドキュメントを確認するという習慣づけにも良さそうです。
- 常に最新のバージョンに対応しているところ。2020年2月現在一部を除いてPython3.8で動きます。
- Gitに草を生やすように、学習記録が残ります。緑増やすぞー！

## いまいちなところ
- 良くも悪くもブラウザ上で動いてくれるので、環境構築や実際のプログラムの実行は別途学習が必要（※環境構築の説明はPyQ上にあります）
- 基礎コースは基本写経前提（説明→実行結果→写経用ソースコード兼問題）で作られているので合う合わないがあると思います。説明→練習問題があり、考えてわからなければ写経するという作りにして欲しかったなあと個人的には思いました。一応一定のカリキュラムごとに演習問題はあります。
- Webアプリ（Django）に入ったあたりからPyQ上の説明だけではやや足りない箇所があるので、公式ドキュメントで確認する作業が増えました。
- IDE使いたい（わがまま）。
- バージョンの選択ができるとなお良かったです。現場では3.6を使用しているため、細かいところが違うと嫌だなー、切り替えられたらいいのになーと感じました。

## 全体を通して
悪くないなーという印象です。
Pythonはスクリプト言語なだけあって環境構築や実行は楽なほうですが、初心者にはやはりそのあたり億劫になってつまづきがちなので、（他の学習サイトでも多いですが）すべてブラウザで完結するというわかりやすさは良いですね。
逆にわたしはJavaでの開発経験があり、IDEに頼りすぎている結果、オートコンプリート機能やら構文チェックやらがないのがもどかしいと感じることもありました。
経験者向けの文法速習は本当良いと思うので、あとはPyQ上で学習を行っていなくてもすべてのコンテンツが見れるようになると個人的には嬉しいです。PyQをテキスト代わりに使用して自端末でIDE入れてPython動かしながら学習したい。。。
Laravel Graphql Server-JWTパスポート認証

これは先週のチュートリアルの続きです。

This is a continuation of last weeks tutorial.

- [基本的なgraphqlサーバーのセットアップに関するチュートリアルを確認してください](https://qiita.com/dabiddo/items/727cf53782067eecce65)

##### 始めましょう

  コンポーザー経由でパスポートをインストールする

  Install passport via composer

  ```
  docker run --rm -v $(pwd):/app composer require laravel/passport
  ```

  移行を実行してパスポートをインストールする

  Run migrations and install passport

  ```
  sudo docker-compose exec app-server php artisan migrate
  sudo docker-compose exec app-server php artisan passport:install
  ```

  これで、お気に入りのエディター（私の場合はPHPStorm）を使用してプロジェクトを開き、 `User`モデルを編集して` HasApiTokens`特性を追加できます。

  We can now open the project using our favorite editor, in my case PHPStorm, and edit the `User` model to add the `HasApiTokens` trait.

  ```php
  <?php
  
  namespace App;
  
  use Illuminate\Contracts\Auth\MustVerifyEmail;
  use Illuminate\Foundation\Auth\User as Authenticatable;
  use Illuminate\Notifications\Notifiable;
  use Laravel\Passport\HasApiTokens;
  
  class User extends Authenticatable
  {
      use HasApiTokens, Notifiable;
  
      /**
       * The attributes that are mass assignable.
       *
       * @var array
       */
      protected $fillable = [
          'name', 'email', 'password',
      ];
  ```

  `config \ auth.php`でApi認証プロバイダーをパスポートに変更します

  We change the Api Auth provider to passport in the `config\auth.php`

  ```php
  'guards' => [
          'web' => [
              'driver' => 'session',
              'provider' => 'users',
          ],
  
          'api' => [
              'driver' => 'passport',
              'provider' => 'users',
              'hash' => false,
          ],
      ],
  ```

##### Graphqlを構成する

職人を使用して新しい突然変異を作成する

create a new mutation using artisan

```
php artisan lighthouse:mutation Login
```

`mutations`フォルダー内で、`Login.php`を開き、`invoke`」関数のコンテンツを置き換えます

Inside the `mutations` folder, open the `Login.php` and replace the `invoke` function content

```php
if(Auth::attempt($args)){
            $user = Auth::user();
            $success['token'] =  $user->createToken('MyApp')->accessToken;
            return $success;
        }
```

`schema.graphql`のリストに新しく作成されたミューテーションを追加します

Add the newly created mutation in the list on the `schema.graphql`

```
type Mutation {
    createUser(name: String!, email: String!, password: String!): User
    Login(email: String!, password: String!): Token
}

type Token{
    token:String!
}
```

新しい突然変異を使用してログインします

Make a login using the new mutation

```
mutation{
  Login(email:"my@email.com",password:"mypassword"){
    token
  }
}
```

トークンをテストするには、 `auth：api`ミドルウェアを追加して、` schema.graphql`内のクエリの1つを変更します

To test the token, modify one of the queries inside the `schema.graphql`, by adding the `auth:api` middleware

```
type Query {
    allusers: [User!]! @all
    users: [User!]! @paginate(defaultCount: 10)
    user(id: ID @eq): User @middleware(checks:["auth:api"]) @find
}
```

新しいクエリリクエストを行うときは、忘れずに認証ベアラートークンヘッダーを追加してください

When you make the new query request, remember to add the Auth Bearer token header

```
Authorization Bearer: eyaz.........
query{
  user(id:1){
    id,
    name,
    email
  }
}
```
引数の数と()の解釈

ListやらSeqとかのパフォーマンス測定の時にコメント頂いた内容で
なぜ関数に```()```を付けないといけなかったか？がずっと不思議だった。

「F#の関数定義では()はつけなくていいハズなのに、なぜ明示的につけるのか？」という勘違いが、いらぬ混乱を招いていた。
C言語ファミリーの関数定義で必要な```void main(){...}```の```()```とは意味合いが違う。


**2020/2/26 誤りがある事をご指摘いただいたため、内容を訂正しました！**

##まとめ
わかりにくいのでunitを()、構文としての()をカッコと表現してます。

* letは値を束縛するための機能である
* F#では全ての関数が値とみなされる。関数値とも呼ぶ
* ()はunit型の定数パターンである
* 引数がないものは関数ではない
* 引数があるものは関数である
* 型注釈に使うカッコは関数定義の構文の一部ではない
* 関数の定義とカッコには直接の関係はない(優先順位を持たせるために使う)
* タプルを使うとカリー化は無効になる

##letって何
名前と定義(値または関数)を関連付ける。

* [letバインド]
(https://docs.microsoft.com/ja-jp/dotnet/fsharp/language-reference/functions/let-bindings)
* [値]
(https://docs.microsoft.com/ja-jp/dotnet/fsharp/language-reference/values/)
* [関数]
(https://docs.microsoft.com/ja-jp/dotnet/fsharp/language-reference/functions/)

```fsharp
let t = 103    // 値を束縛
let s = "JNR"  // 値を束縛

let add1 x = x + 1 // 1つの引数を持つ関数を束縛
let add x y = x + y // 2つの引数を持つ関数を束縛

```

##パターンって何
letやラムダ式や関数の引数(パラメータ)を処理するときに使われる。

* [パラメータと引数](https://docs.microsoft.com/ja-jp/dotnet/fsharp/language-reference/parameters-and-arguments)
* [パターンマッチ](https://docs.microsoft.com/ja-jp/dotnet/fsharp/language-reference/pattern-matching)
* [タプル]
(https://docs.microsoft.com/ja-jp/dotnet/fsharp/language-reference/tuples)
* [unit型]
(https://docs.microsoft.com/ja-jp/dotnet/fsharp/language-reference/unit-type)


```fsharp
let t = 103    // 定数パターン
let n = ()     // 定数パターン

let add1int (x:int) = x + 1 // 引数に型の注釈がつけられたパターン
let add1int (x:int) :int = x + 1 // 戻り値の型を明示
```

##検証用コード

```fsharp
// unitの値(副作用あり)
let a = printfn "a" // unit

// unitの値(副作用なし)
let b = () // unit

// unit引数を受け取りunitを返す関数
let c () = printfn "b" // unit -> unit

// 引数xを受け取りunitを返す関数
let d x = printfn "%A" x // 'a -> unit

// dを冗長に書いた場合
let e = fun x -> printfn "%A" x // 'a -> unit

// 引数xに無駄にカッコをつけているだけ
let f (x) = printfn "(%A)" x // 'a -> unit

// gは引数xとyを受け取りunitを返す関数
let g x y = printfn "%A%A" x y // 'a -> 'b -> unit

// gを冗長に書いた場合
let h = fun x -> fun y -> printfn "%A%A" x y // 'a -> 'b -> unit

// 引数として、xとyのタプルを1つ受け取りunitを返す関数
let i (x, y) = printfn "(%A,%A)" x y // 'a * 'b -> unit

// intの値(副作用なし)
let j = 2 // int

// 2を返す関数
let k = fun _ -> 2 // 'a -> int
let l = fun () -> 2 // 'a -> int

```
製薬企業研究者が最低限知っておきたいSQL構文

# はじめに

ここでは、初心者向けにSQLの基本的な構文について解説します。


# データベースの新規作成

新規にデータベースを作成するときには、`CREATE DATABASE`を使います。

```sql
CREATE DATABASE データベース名
```

# データベースの削除

既にあるデータベースを削除するときには、`DROP DATABASE`を使います。

```sql
DROP DATABASE データベース名
```

# テーブルの作成

新しくテーブルを作るときには、`CREATE TABLE`を使います。
このときに、カラム名（フィールド名）とデータ型もあわせて指定します。

```sql
CREATE TABLE テーブル名(カラム名 データ型, カラム名 データ型, ・・・)
```

# テーブルの削除

既にあるテーブルを削除するときには、`DROP TABLE`を使います。

```sql
DROP TABLE テーブル名
```

# レコードの追加

既にあるテーブルにレコードを新規追加する場合は、`INSERT`を使います。
書き方は以下に示す2通りがあります。

```sql
INSERT テーブル名
   SET カラム名=値, カラム名=値, ・・・

INSERT INTO テーブル名(カラム名, カラム名, ・・・)
     VALUES (値, 値, ・・・)
```


# レコードの検索（データ抽出）

テーブルからデータを検索して取り出すときには、`SELECT`を使います。
カラム名を指定せず、全てのカラムのデータを参照する場合は`*`とします。

```sql
SELECT カラム名
FROM テーブル名

SELECT *
FROM テーブル名
```

## レコードの件数の指定

取り出すレコードの件数を指定する場合は、`LIMIT`を使います。

```sql
SELECT *
  FROM テーブル名
 LIMIT 件数
```


## レコードの表示順の指定

`ORDER BY`を用いることで、指定したカラムの値でソートすることができます。
`DESC`とすると、降順にすることができます。
（`ASC`とすると昇順にすることができますが、書かなくてもデフォルトで昇順になります。）

```sql
  SELECT *
    FROM テーブル名
ORDER BY カラム名

  SELECT *
    FROM テーブル名
ORDER BY カラム名 DESC
```


## 条件の指定

`WHERE`を使うと、条件を指定してデータを抽出することができます。
`NOT`を使うこともでき、`AND`や`OR`を使うことで複数の条件を指定することもできます。
さらに、`IN`を使うことで、指定した要素の集合に含まれるレコードを取り出すこともできます。`IN`の後には、`SELECT`文を指定して、他のテーブルに含まれていて条件が合致するレコードを選択することもできます。

```sql
SELECT *
  FROM テーブル名
 WHERE カラム名=値（条件）

SELECT *
  FROM テーブル名
 WHERE NOT カラム名=値（条件）

SELECT *
  FROM テーブル名
 WHERE カラム名=値（条件） AND カラム名=値（条件）

SELECT *
  FROM テーブル名
 WHERE カラム名=値（条件） OR カラム名=値（条件）

SELECT *
  FROM テーブル名
 WHERE カラム名 IN (要素１, 要素２, ・・・)

SELECT *
  FROM テーブル名
 WHERE カラム名 IN (SELECT カラム名 FROM テーブル名 WHERE カラム名=値)
```

さらに、`LIKE`を使うと、指定したカラムの値が正規表現に合致するレコードを取り出すことができます。

```sql
SELECT *
  FROM テーブル名
 WHERE カラム名 LIKE 正規表現
```


また、`BETWEEN`を使うと、指定したカラムの値がある範囲にあるレコードを取り出すことができます。

```sql
SELECT *
  FROM テーブル名
 WHERE カラム名 BETWEEN 最小値 AND 最大値
```


## グルーピング

`GROUP BY`を使うと、指定したカラムの値が同じレコードをまとめることができます。
また、`HAVING`を用いることで、グルーピングした後に条件を指定してデータを取り出すことができます。

```sql
  SELECT カラム名（COUNT(*)などの関数も）
    FROM テーブル名
GROUP BY カラム名

  SELECT カラム名（COUNT(*)などの関数も）
    FROM テーブル名
GROUP BY カラム名 HAVING 条件
```

# 複数のテーブルの結合

`JOIN`を使うと、複数のテーブルのデータを、それぞれのテーブルのいずれかのカラムをキーにして結合することができます。キーは`ON`で指定します。

```sql
SELECT *
FROM １つ目のテーブル名
JOIN ２つ目のテーブル名 ON １つ目のカラム名=２つ目のカラム名
```

また、以下のようにすると、テーブル名は省略して記述することができます。
カラム名も結合する2つのテーブルの中でユニークなものであれば、テーブル名を省略することができます。

`SELECT u.username, p.title, p.body FROM users u 
JOIN posts p ON u.id=p.author_id`

`SELECT username, title, body FROM users u 
JOIN posts p ON u.id=author_id`


# レコードの値の更新

既にテーブルに登録されているレコードの値を変更するときには、`UPDATE`を使います。

```sql
UPDATE テーブル名
   SET カラム名=値, カラム名=値, ・・・
 WHERE カラム名=値（条件）
```


# レコードの削除

既にテーブルに登録されているレコードを削除するときには、`DELETE`を使います。

```sql
DELETE FROM テーブル名
WHERE カラム名=値（条件）
```


# まとめ

ここでは、SQLの構文のうち最低限覚えておきたいものにしぼって紹介しました。
以上で紹介した構文を組み合わせることで、業務で必要になるデータベース操作はおおむねできるはずです。


# 参考資料・リンク

[SQLとは？データベースと関係ある？](https://pharma-engineer.com/basic-programming/sql-summary/)
ターミナルでSudoのパスワード入力をTouchIDで実行する。

人類楽してもいいと思うんだ。

## やり方

pam.d/sudoのファイルの先頭にtouch ID認証を追加する。

このファイルは先頭からsoリンクを呼び出すので末尾に入れるとパスワード入力してかつTouchIDを認証するというめんどくさいことになるので注意が必要

まずエディタでpam.d配下のsudoファイルを呼び出す。


`sudo vim /etc/pam.d/sudo `

開いたら、下の図のように先頭行にTouch ID認証を入れる

Touch ID の認証：`auth sufficient pam_tid.so`


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89244/1dcf3054-707c-eed8-81bc-8dba8ca936dc.png)


これで保存して閉じればOK

正しく設定されていれば同じファイルを開いた際にTouch IDの認証画面が開くはず
MSpanList_Insert｜docker-machineコマンドでのエラー

# 当方で解決できた方法
最新バージョンのdocker-machineをインストールしたら治りました。

```installmachine.sh

curl -L https://github.com/docker/machine/releases/download/v0.13.0/docker-machine-`uname -s`-`uname -m` >/usr/local/bin/docker-machine && \
  chmod +x /usr/local/bin/docker-machine

```

[>>参考サイト](https://docs.docker.com/v17.09/machine/install-machine/)


# 状況
dockerは使えている状態で
docker-machineを実行しようとしたらコマンドが見つからないと出た。

```notfound.sh
$ docker-machine version
bash : command not found

```

# 環境
macOS 10.14.6 Mojave
docker desktop 19.03.5
virtualbox 6.0.16

# not foundが出て行なった作業
## インストール

```miss.sh

curl -L https://github.com/docker/machine/releases/download/v0.7.0/docker-machine-`uname -s`-`uname -m` > /usr/local/bin/docker-machine && chmod +x /usr/local/bin/docker-machine

```

# エラーメッセージ一部抜粋

```error.sh

$docker-machine version
failed MSpanList_Insert 
fatal error: MSpanList_Insert
~go/src/runtime~
~go/src/runtime~
~go/src/runtime~

```

# エラーが出て行なった作業
検索をするとどうやらソフトウェア間の
バージョン互換性の食い違い時にMSpanList_Insertという
エラーが出やすいとの情報が多かったので以下を実施。

## goのアップデート
エラーメッセージにgoファイルが羅列されていたことと
検索したらgolangでもMSpanList_Insertのエラーで
バージョンアップしたら治ったとあったので実行。

```update.sh

brew upgrade go

```
無事アップデートされるが
docker-machineコマンドの結果は変わらず。

## virtualboxのアップデート
こちらもアップデートが出ていたのでguiからインストール。

[>>参考サイト](https://pc-karuma.net/mac-virtualbox-update/)

無事アップデートされるもdocker-machineコマンドの結果は変わらず。

その後検索していたら
本家のサイトと最初にインストールしたdocker-machineのバージョンが違うことに気がついた。
気がつけてよかったっす。まじでここ見逃したらさらにハマってたかも知れません。
kubernetesも関連あるのか？とか考え始めていたので。

```miss.sh

curl -L https://github.com/docker/machine/releases/download/v0.7.0/docker-machine-`uname -s`-`uname -m` > /usr/local/bin/docker-machine && chmod +x /usr/local/bin/docker-machine

```

```installmachine.sh

curl -L https://github.com/docker/machine/releases/download/v0.13.0/docker-machine-`uname -s`-`uname -m` >/usr/local/bin/docker-machine && \
  chmod +x /usr/local/bin/docker-machine

```

[>>参考サイト](https://docs.docker.com/v17.09/machine/install-machine/)

# 教訓
１次情報大事。英語頑張る。
ABC155 E

コンテスト中には解けなかったが、いろいろな解説を見ながら考えたのでまとめてみる。
問題はこちら。
https://atcoder.jp/contests/abc155/tasks/abc155_e

# 共通する前提条件

入力の数字を文字列Sとして扱う。

# 解法1

上の桁から見る。公式解説の解法。
https://img.atcoder.jp/abc155/editorial.pdf

しかし公式解説は説明が簡潔すぎてどう実装したら良いのかさっぱりわからなかった。次のサイトがとてもわかりやすく解説してくださっている。
https://maspypy.com/atcoder-%E5%8F%82%E5%8A%A0%E6%84%9F%E6%83%B3-2019-02-16abc-155

$$
dp[i][j] = 上からi桁目まで見たときのコインの枚数。jは次の桁で繰り上がりがあるかどうかで\text{$0$ or $1$}。
$$
とする。ただし一番上の桁で繰り上がりが起こる可能性があるので、一番上の桁の一つ上の桁から始める。
そのため初期値は
$$
dp[0][0] = 0,\ dp[0][1] = 1
$$
漸化式は
$$
dp[i][0] = \min(dp[i - 1][0] + S[i], dp[i - 1][1] + 10 - S[i]) \\\\
dp[i][1] = \min(dp[i - 1][0] + (S[i] + 1), dp[i - 1][1] + 10 - (S[i] + 1))
$$
で、解答としては$dp[S.len()][0]$を出力する。

自分が書いたRustコードはこちら。
https://atcoder.jp/contests/abc155/submissions/10230687

## 補足

桁の数字S[i]が9のとき、S[i] + 1が10になってしまい、繰り上がり等の関係で問題が生じないかという疑問がある。
しかしd[i][0]とd[i][1]の差は高々1にしかならないことがわかるので（証明は略）、
$dp[i][1] = \min(dp[i - 1][0] + (S[i] + 1), dp[i - 1][1] + 10 - (S[i] + 1))$の更新では必ず後者の$dp[i−1][1]+10−(S[i]+1)$が選ばれるため、問題ないことがわかる。

# 解法2

下の桁から見る。次のサイトを参考にした。
http://kmjp.hatenablog.jp/entry/2020/02/17/0900

$$
dp[i][j] = \text{下からi桁目まで見たときのコインの枚数。jは次の桁で繰り上がりがあるかどうかで$0$ or $1$}
$$

初期値は、0桁目で繰り上がりが起こることはありえないので
$$
dp[0][0] = 0,\ dp[0][1] = \infty
$$
とする。漸化式は

$$
dp[i][0] = min(dp[i - 1][0] + d, dp[i - 1][1] + d + 1) \\\\
dp[i][1] = min(dp[i - 1][0] + (10 - d), dp[i - 1][1] + 10 - (d + 1))
$$

とする。解法1とほぼ同じだが、微妙に出てくる順番が違う。

自分が書いたRustコードはこちら。
https://atcoder.jp/contests/abc155/submissions/10253696

# 当初のアイデア

WAになってしまうアイデア。
「下から見て、6以上なら繰り上がりして、5以下ならぴったりの金額を払う」とする。

なぜこれがだめかというと、例えば65の場合を考えてみる。このアルゴリズムだと105円払って40円お釣りをもらうことになり、合計10枚になる。
しかし最適解は100円払って35円お釣りをもらい合計9枚にすることであり、このような素朴な貪欲法では答えが得られないことがわかる。

それでは「下から見て、5以上なら繰り上がりして、4以下ならぴったりの金額を払う」はどうかというと、これもダメ。5のとき10円払ってお釣り5枚の合計6枚になってしまうが、こちらの最適解は明らかに5円ちょうど払うことである。
Cacooのフリープランを試してみた

# 背景
先日、AWSで指定金額範囲なら自由に使って良いアカウントを貰えました。
これで個人だと躊躇していた機能も安心して試せると思い、折角なのでこれを機にお名前.comで初年度１円のドメインを取得し、TerraformでVPCの枠とRoute53まで作りました。
が、当然NSの変更がありますので名前の浸透の期間で暫く手が開くことになったついでに、
このAWS構築に関して構成図を残したいな〜と思い、今まで業務で一番使ったクラウドのワイヤーフレーム作成ツールのCacooの個人利用について調べてみました。

# Cacooの個人利用
https://cacoo.com/ja/pro
上のページによると個人用途での利用のライセンス形態はフリー版とプロ版の２種類の様です。
個人的な用件は画像ファイルへのエクスポートとAWSのアイコンが使えることくらい。
ページ内に比較表がありますので確認してみますと、図の作成枚数やエクスポートのファイル形式の種類、アップロードするファイルサイズ、変更履歴の閲覧などに制限はある様ですが、まず私がやりたいこと自体はフリー版でまかなえる様です。
<img width="671" alt="スクリーンショット 2020-02-24 10.58.20.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/372095/15257730-7fec-118d-c4d8-099ada74982b.png">
というわけで、フリー版でユーザ登録。
プロ版へは簡単にアップグレードできる様ですので、もっと沢山の図を作りることになったりエクスポートするファイル形式が限定されるときにプロ版への変更を考えても遅くはないですね。
<img width="350" alt="スクリーンショット 2020-02-24 11.02.05.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/372095/59b83378-f0e8-626a-11b2-9432a8ca113f.png">

# ユーザ登録
下のキャプチャの通り、登録する内容は名前、メールアドレス、パスワード、MLを受け取るチェック程度です。
早速アカウントを作ってみましょう！
<img width="450" alt="スクリーンショット 2020-02-24 11.04.10.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/372095/8318835c-2857-d536-35ad-8982a619144a.png">
入力してアカウントの作成ボタンをクリックしたら、簡単にアカウント作成ができました。
というか、メールのチェックとかしてないんですね・・・。ゴミ垢だらけになりそう・・・。

# ステンシルにAWSアイコンを追加
アカウント登録が完了したら、説明的なフォームが出ていると思いますが、とりあえず次へと進めて、空のテンプレートから図を作成してみましょう。
左のメニューから図形を代入しようと思いましたがデフォルトではAWSアイコンは使用できないのですね。
<img width="199" alt="スクリーンショット 2020-02-24 11.16.23.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/372095/99f56f2d-f134-4ee3-9d88-17963ed61ef2.png">
なので、まずはAWSアイコンを使用できる様にしましょう。
この画面の「図形の追加」をクリックしたら、ステンシルにいろいろなアイコンを追加する画面が表示されます。
<img width="1180" alt="スクリーンショット 2020-02-24 10.40.47.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/372095/8b365a8e-f7ae-a1ca-1737-99b180c43d95.png">
ここでAWSにチェックを入れることでAWSアイコンを使用できるようになります。
<img width="206" alt="スクリーンショット 2020-02-24 11.17.29.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/372095/8a784ce0-ee79-c004-ce75-3478dd7879f0.png">

# そして編集へ
こんな感じで編集できます。
Cacoo、本当に使いやすくて良いですね
<img width="1120" alt="スクリーンショット 2020-02-24 11.38.21.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/372095/0b29720d-51c5-9ea2-c2c3-bb8d12d69cae.png">
暫くはフリー版を使ってみますが、作る図が増えたらプロ版乗り換え、かなり有りですね！
pipenv で "No versions found" というエラーが出た場合の対処法

# 事象：pipenv を使ったパッケージのインストール時のエラー
pipenv を使って以下のようにインストールを試みたところ

```bash
pipenv install <package name>
```

以下のように怒られてしまった。

```bash
[pipenv.exceptions.ResolutionFailure]:       pipenv.exceptions.ResolutionFailure: ERROR: ERROR: Could not find a version that matches request
[pipenv.exceptions.ResolutionFailure]:       No versions found
[pipenv.exceptions.ResolutionFailure]: Warning: Your dependencies could not be resolved. You likely have a mismatch in your sub-dependencies.
  First try clearing your dependency cache with $ pipenv lock --clear, then try the original command again.
 Alternatively, you can use $ pipenv install --skip-lock to bypass this mechanism, then run $ pipenv graph to inspect the situation.
  Hint: try $ pipenv lock --pre if it is a pre-release dependency.
ERROR: ERROR: Could not find a version that matches request
No versions found
Was https://pypi.org/simple reachable?
```
# 原因
pipenv が使う pip の SSL 認証がうまく行っていないのが原因らしい。
普通に ```pip install``` をしていたときも 

```bash
ssl.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:833)
```
などと怒られていたので、暫定対処として

```bash
pip install --trusted-host pypi.org --trusted-host pypi.python.org --trusted-host <package name>
```

としてお茶を濁していたが、pipenv では上記のオプションを付けることができない模様

# 対処法
pipの設定ファイルである```pip.conf```に必要な設定をすることで解決できる。
Mac の場合

```bash
mkdir ~/.pip
vim ~/.pip/pip.conf
```

として

```pip.conf
[global]
trusted-host = pypi.python.org
               pypi.org
               files.pythonhosted.org
```
を作ってあげれば良い。
それ以外の環境の場合、参考にした https://qiita.com/agajo/items/73d6f14855da703972e0 を見ると良い。
F# のコレクションを結合していった時の速度比較

`fsi` にて実行

```fsharp
open System
let max = 100000
let inline showTime name start = printfn "%s: %d" name (DateTime.UtcNow.Ticks - start)

let mutable start = DateTime.UtcNow.Ticks
let arrm = Array.zeroCreate<int> max
for i in 0..max - 1 do arrm.[i] <- i
showTime "array mutable" start

start = DateTime.UtcNow.Ticks
let mutable arra = [||]
for i in 0..max - 1 do arra <- Array.append arra [| i |]
showTime "array append" start

start = DateTime.UtcNow.Ticks
let mutable arrc = [||]
for i in 0..max - 1 do arrc <- Array.concat [| arrc; [| i |] |]
showTime "array concat" start

start <- DateTime.UtcNow.Ticks
let mutable lst = List.Empty
for i in 0..max - 1 do lst <- i :: lst
showTime "list" start

start <- DateTime.UtcNow.Ticks
let mutable S = seq { yield 0 }
for i in 0..max - 1 do S <- Seq.append S (seq { yield i })
showTime "sequence" start
;;
```

```output
array mutable: 0
array append: 115221834
array concat: 195307635
list: 9977
sequence: 99732
```

とりあえず Array を結合するのはすっごい遅いことが分かった。

ちょっと `max` を大きくしてみて

```fsharp
open System
let max = 10000000
let inline showTime name start = printfn "%s: %d" name (DateTime.UtcNow.Ticks - start)

let mutable start = DateTime.UtcNow.Ticks
let arrm = Array.zeroCreate<int> max
for i in 0..max - 1 do arrm.[i] <- i
showTime "array mutable" start

start <- DateTime.UtcNow.Ticks
let mutable lst = List.Empty
for i in 0..max - 1 do lst <- i :: lst
showTime "list" start

start <- DateTime.UtcNow.Ticks
let mutable S = seq { yield 0 }
for i in 0..max - 1 do S <- Seq.append S (seq { yield i })
showTime "sequence" start
;;
```


|type |    time|
|:----|-------:|
|Array|  249332|
|List | 8128251|
|Seq  |50744520|

Seq はyieldして生成するものであって繰り返し結合する使い方をするものじゃないんだなという感じ

当たり前ですが、毎回新しいオブジェクトを作る必要が無いようにArrayにサイズ指定して作ってそのアイテムを編集していくのが一番早いですね。

複数のコレクションを繰り返し結合する必要があるときはListが有利かもしれません。

ただ、Array は `'T array` と `'T array`
Seq は `seq 'T` と `seq 'T` だったのに対して
List は `'T` と `list<'T>` の結合だったのでその影響もあるかもしれません。
Raspbianのデフォルトpythonを２系→３系に変更する

raspberrypiにRaspbianをインストールすると、Raspbian10.2ではまだpython2.7系がデフォルトに設定されています。
python3をインストールしたのにうまく動かないという（私みたいな）人はデフォルトを３系になっているか確認し、もし2系であれば、以下のように変更しましょう、


<H1>pythonの現在のバージョンを確認する</H1>
まず、現在デフォルトで設定されているpythonのバージョンを確認してみます。

~~~python
pi@ユーザー名:~ $ python --version
Python 2.7.16
~~~
2.7ですね・・・・。


<H1>python2.7のリンクを解除し3に再リンクする</H1>

まずは再リンク設定をするために、ディレクトリを移動します。

~~~python
pi@ユーザー名:~ $ cd //
pi@ユーザー名:// $ cd usr/bin
~~~

次に以下のコマンドを打ち込み再リンクします。

~~~python
pi@ユーザー名://usr/bin $ sudo unlink python
pi@ユーザー名://usr/bin $ sudo ln -s python3 python
~~~

<H1>再設定の確認</H1>
pythonのバージョンを再確認しpython3.7.*になっていることを確認してみます。
python3.*.*と返ってくれば再リンクの設定は成功です。

~~~python
pi@ユーザー名://usr/bin $ python --version
Python 3.7.3
~~~

成功ですね。

<H1>終わりに</H1>

このリンクはシンボリックリンクだ！＾とか、ディレクトリの移動がちょっと違うとか、そもそもディレクトリじゃなくてフォルダだろとか、いや、フォルダはWindowsでディレクトリで正しいんだとか、ツッコミどころ満載だと思いますが、超ド素人がpythonの初期接敵を3系に変更する必要最小限の方法を記載してみました。
Spring Bootで Developer Tools と H2 Database を使っている時にハマったこと

## Spring Bootのバージョン

```xml
  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.4.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
  </parent>
```

## POMの設定

```xml
  <!-- 略 -->
  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-jdbc</artifactId>
    </dependency>
    <!-- 略 -->
    <dependency>
      <groupId>com.h2database</groupId>
      <artifactId>h2</artifactId>
    </dependency>
    <!-- 略 -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-devtools</artifactId>
       <optional>true</optional>
    </dependency>
  </dependencies>
  <!-- 略 -->
```

## 発生したエラー

```
2020-02-24 10:49:36.383  INFO 25790 --- [  restartedMain] com.example.App                          : No active profile set, falling back to default profiles: default
2020-02-24 10:49:36.406  INFO 25790 --- [  restartedMain] .e.DevToolsPropertyDefaultsPostProcessor : Devtools property defaults active! Set 'spring.devtools.add-properties' to 'false' to disable
2020-02-24 10:49:36.753  INFO 25790 --- [  restartedMain] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
2020-02-24 10:49:36.859  INFO 25790 --- [  restartedMain] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
2020-02-24 10:49:36.902  INFO 25790 --- [  restartedMain] o.s.b.d.a.OptionalLiveReloadServer       : LiveReload server is running on port 35729
2020-02-24 10:49:36.978  INFO 25790 --- [  restartedMain] com.example.App                          : Started App in 0.781 seconds (JVM running for 1.329)
(略)
2020-02-24 10:49:37.213  WARN 25790 --- [extShutdownHook] o.s.b.f.support.DisposableBeanAdapter    : Invocation of destroy method failed on bean with name 'inMemoryDatabaseShutdownExecutor': org.h2.jdbc.JdbcSQLNonTransientConnectionException: データベースはすでに閉じられています (VM終了時の自動データベースクローズを無効にするためには、db URLに ";DB_CLOSE_ON_EXIT=FALSE" を追加してください)
Database is already closed (to disable automatic closing at VM shutdown, add ";DB_CLOSE_ON_EXIT=FALSE" to the db URL) [90121-200]
2020-02-24 10:49:37.215  INFO 25790 --- [extShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown initiated...
2020-02-24 10:49:37.222  INFO 25790 --- [extShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown completed.
```

## 対応方法

`application.properties`（`application.yml`）に`spring.autoconfigure.exclude=org.springframework.boot.devtools.autoconfigure.DevToolsDataSourceAutoConfiguration`を追加する。
Progate ～道場コース:中級編～　学び

#はじめに
　ProgateのHTML & CSSをし始めて約一週間の初心者です。
本稿では、道場コースの中級編で、かなり悩んだところをピックし、それに対する自分なりの解決法を書いていきたいと思います！
解釈が本当に正しいとは限りませんので、また分かり次第訂正しようと思います。

##学び1.レイアウトの仕方
慣れてないからだとは思いますが、レイアウトの仕方が分からなかったです笑
特に`<div>`にするところとか。
でも、レイアウトは以下のことを重視することで改善できました！

* **とにかく箱をイメージ**

本稿で書く箱とは、`<div>`を使う場所のことです。

最初に箱を考えることで色々と整理しやすくなります。
その箱の作り方なんですが、コーディングしまくって慣れるのが一番早いと思います笑
自分も何回か作ることによってだいたいの箱のイメージができるようになりました！

ここに箱があったら、後のCSSファイルの編集がしやすくなりそう！
ここは別に箱にする必要はないな。とか

以下の図は、Progateの道場コース、中級編のトップ部分を作るときに、
私の考えた箱のイメージです

![スクリーンショット (60).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/588518/a89ce8d1-1c87-98ab-0c99-e15af5c607a2.png)

基本的に一番大きい箱から考えていきます
まずは、背景を配置する箱が必要なので、赤の箱をイメージ
次に、仕様書の指定から、1170pxの幅を持つオレンジの箱をイメージ
最後に、色、透明率が一緒であるため、まとめたら利点があると考え、黄色の箱をイメージ

そして、これらのイメージをHTMLファイルに反映するために、`<div>`を用いてコーディングします

``` HTML:index.html
<div class = "red">
  <div class = "orange">
    <div class = "yellow">
    <h1>見出し</h1>
    <p>説明文</p>
    </div>
  </div>
</div>
```

と、以上のようなクラス分けとなったわけです。

しかし、CSSの書き方次第では、このような箱をイメージした書き方をしなくてもレイアウトを作ることが可能です。
しかし、第三者から見ても分かりやすいという点で`<div>`要素は大事だと感じました

また、コーディングすると親要素と子要素の位置が分からなくなったりすることが多かったので、
`border`プロパティをつけて頭の中を整理しつつコーディングすることが大切だと感じました


##学び2.答えは一通りではない
道場コースの中級編を三回復習し、分かったことです

1回目は自分の書いたコードも模範解答とほとんど丸被りでした
しかし、webの書き方の流れを少しつかんで2回目、3回目に取りかかった結果、

「別に、ここはこーいう書き方もできるよな～」とか、
「ここの`<div>`要素は別にいらなくね？」

と感じるようになり、コードの書き方は色々あることにきずきました

学び1に書いたindex.htmlも、CSSの書き方次第では、このようにグループ分けしなくても、
完成のページになるということです
しかし、編集が容易で、構造の分かりやすいコードを作るには、先ほども述べたとうり`<div>`要素による
クラス分けは大切だと思います

##学び3.floatの意味
レッスン一覧部分を作る際に、以下の図のレイアウトにする前提で、この課題にとりかかるのですがある疑問が生じました

![スクリーンショット (69).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/588518/44ae9b4e-caf9-ddf7-0372-5524c223afb8.png)

模範解答のコードをそのまんまコピーして、ボーダーを引いて頭の中を
整理しようとしたその時です。

![スクリーンショット (70).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/588518/cc4e7c24-d835-5ac1-ea50-2c1148d317ba.png)

`container`クラスがレイアウトどうりに包括されていないことに疑問を生じました
自分の考えでは、赤色の枠線が表れるという予想でしたが、見事に違いました笑
なぜ、タイトルだけに枠線があるのか本当に謎でした

しかし、これの原因は`float`プロパティにあったと分かりました！

その時に納得させられたサイトがこちらです↓
参考ページ: [CSSの【float】についてちょっと本気出して説明してみた。](https://taneppa.net/float/)

このページから、`float`プロパティで指定したブロックは実際に浮いているということが分かりました。
だから、`float:left;`によって、`container`クラス内包される要素が減ったの範囲が小さくなり、タイトルだけが内包されることになったのでしょう。

##まとめ
　以上が個人的に学んだ部分です。

これからも日々精進してHTMLとCSSをしっかり学んでいきたいです！
Golang の http クライアントの使い方 (Post)

## プログラム

```go:http_post.go
// ---------------------------------------------------------------
//
//	http_post.go
//
//					Feb/24/2020
// ---------------------------------------------------------------
package main

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
)

// ---------------------------------------------------------------
func main() {
	fmt.Printf ("*** 開始 ***\n")
	url_target := "https://httpbin.org/post"
	args := url.Values{}
	args.Add("user","jiro")
	args.Add("password","123456")
	res, err := http.PostForm(url_target,args)
	if err != nil {
		fmt.Println("Request error:", err)
		return
	}
	defer res.Body.Close()

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		fmt.Println("Request error:", err)
		return
	}

	str_json := string(body)
	fmt.Println(str_json)

	fmt.Printf ("*** 終了 ***\n")
}

// ---------------------------------------------------------------
```

実行結果

```text
$ go run http_post.go
*** 開始 ***
{
  "args": {}, 
  "data": "", 
  "files": {}, 
  "form": {
    "password": "123456", 
    "user": "jiro"
  }, 
  "headers": {
    "Accept-Encoding": "gzip", 
    "Content-Length": "25", 
    "Content-Type": "application/x-www-form-urlencoded", 
    "Host": "httpbin.org", 
    "User-Agent": "Go-http-client/2.0", 
    "X-Amzn-Trace-Id": "Root=1-5e532ac5-3fd72da01bd57240d7b094c8"
  }, 
  "json": null, 
  "origin": "163.49.213.57", 
  "url": "https://httpbin.org/post"
}

*** 終了 ***
```

## 確認したバージョン

```text
$ go version
go version go1.19.2 linux/amd64
```
Golang の http クライアントの使い方 (Get)

## プログラム

```go:http_get.go
// ---------------------------------------------------------------
//
//	http_get.go
//
//					Feb/24/2020
// ---------------------------------------------------------------
package main

import (
	"fmt"
	"io/ioutil"
	"net/http"
)

// ---------------------------------------------------------------
func main() {
	fmt.Printf ("*** 開始 ***\n")
	url_target := "https://httpbin.org/get"
	res, err := http.Get(url_target)
	if err != nil {
		fmt.Println("Request error:", err)
		return
	}
	defer res.Body.Close()

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		fmt.Println("Request error:", err)
		return
	}

	str_json := string(body)
	fmt.Println(str_json)

	fmt.Printf ("*** 終了 ***\n")
}

// ---------------------------------------------------------------
```

実行結果

```text
$ go run http_get.go
*** 開始 ***
{
  "args": {}, 
  "headers": {
    "Accept-Encoding": "gzip", 
    "Host": "httpbin.org", 
    "User-Agent": "Go-http-client/2.0", 
    "X-Amzn-Trace-Id": "Root=1-5e532a2d-03367851ed2afcb58a0a452d"
  }, 
  "origin": "163.49.213.57", 
  "url": "https://httpbin.org/get"
}

*** 終了 ***
```

## 確認したバージョン

```text
$ go version
go version go1.19.2 linux/amd64
```
[Tips]Google Cloud Composer(Airflow)を使ってDataprocを利用したい時にだけ使う。

#概要
- Google Cloud Composer(Airflow)を使って、スポットインスタンス的にDataprocを使うdagを作ります。
- メリット
  - Dataprocの起動が3分以内のため、利用する時に立ち上げて、終わったら消すという利用が可能です。

#前提
- Google Cloud Composer(Airflow)の検証バージョンは「composer-1.7.3-airflow-1.10.2」です。
- Dataprocは消すこと前提なので、外部テーブルとしてGCSを利用します。
- Dataprocは消すこと前提なので、Hive metastoreによりテーブル情報を保全します。
  - Hive metastoreとしてCloudSQLを利用します。
- IAMの設定
  - **Google Cloud Composer用のサービスアカウントに各種roleを与える必要があります。**
     - 「Composer ワーカー」
     - 「Dataproc編集者」
     - 「サービス アカウント ユーザー」
  - **Dataprocのサービスアカウントにも各種roleを与える必要があります。**
     - 「Cloud SQL 編集者」（Hive metastore用）
     - 「Dataproc編集者」
     - 「サービス アカウント ユーザー」
     - 「ストレージ オブジェクト管理者」

#設定内容
##### Dataprocを起動
- 事前にHive metastore用のCloud SQLを作成して、情報を記録します。
  - [公式ドキュメント：DataprocでのHiveの使用](https://cloud.google.com/solutions/using-apache-hive-on-cloud-dataproc?hl=ja#creating-the-cloud-sql-instance)
- 事前にDataproc用のサービスアカウントの作成が必要です。
- Hive metastoreは、gs://{$CLUSTER_WAREHOUSE}/datasetsに置くものとします。

``` py
def create_dataproc_task():
    return DataprocClusterCreateOperator(
        task_id = 'create_dataproc',
        cluster_name = f'{$CLUSTER_NAME}',
        project_id = f'{$PROJECT_ID}',
        region = f'{$CLUSTER_REGION}',
        zone = f'{$CLUSTER_ZONE}',
        service_account = f'{$DATAPROC_SERVICE_ACCOUNT}',
        master_machine_type = f'{$MASTER_MACHINE_TYPE}',
        master_disk_size = f'{$MASTER_DISK_SIZE}',
        num_workers = f'{$NUM_WORKERS}',
        worker_machine_type = f'{$WORKER_MACHINE_TYPE}',
        worker_disk_size = f'{$WORKER_DISK_SIZE}',
        image_version = '1.4-debian9',
        service_account_scopes = ['https://www.googleapis.com/auth/cloud-platform'],
        init_actions_uris = ['gs://dataproc-initialization-actions/cloud-sql-proxy/cloud-sql-proxy.sh'],
        metadata = {
            'hive-metastore-instance': f'{$PROJECT_ID}:{$CLOUD_SQL_REGION}:{$CLOUD_SQL_NAME}'
        },
        properties = {
            'hive:hive.metastore.warehouse.dir': f'gs://{$CLUSTER_WAREHOUSE}/datasets'
        },
    )
```

##### Dataprocを削除

```py
def delete_dataproc_task():
    return DataprocClusterDeleteOperator(
        task_id = 'delete_dataproc',
        cluster_name = f'{$CLUSTER_NAME}',
        project_id = f'{PROJECT_ID}',
        region = f'{$CLUSTER_REGION}',
    )
```

##### Dataprocの演算をするdag内の記述
- start_taskとfinish_taskを置くことで、Dataprocで処理したい複数のtaskを記述できます。

```py
prepare_task = DummyOperator(task_id='prepare')
start_task = DummyOperator(task_id='start')
finish_task = DummyOperator(task_id='finish')
cleanup_task = DummyOperator(task_id='cleanup')

prepare_task >> create_dataproc_task() >> start_task
for task in tasks:
　　　start_task >> [Dataprocで処理したいtask群] >> finish_task
finish_task >> delete_dataproc_task() >> cleanup_task

```

- 実際のAirflow UI上の表示

![Airflow_-_DAGs.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19746/aeebc82d-f0fc-0fbb-818b-5259207778b4.png)
Chromebook(79.0.3945.123)でYoutubeの動画が途中で止まってしまう障害の対処法

1,2週間ほど前からYoutubeの動画が数分で止まってします現象が起きていました。
（Androidアプリなら大丈夫だったので気にしてなかったのですが）

# 発生環境
- ASUS Chromebook Tablet CT100PA (Version: 79.0.3945.123 (Official Build))
- ASUS Chromebook Flip C101PA

# 対処方法
`chrome://flags`でExperimentsを開き、Hardware-accelerated video decode を Disabled に変更する。
平日だけど休日になった日を、gas → slack へ通知する

なんか今日、人少ないな...

コロナ?
インフルエンザ？？


今日って「振替休日」じゃん！

# 土日以外の休日をslackへ通知したい

土日が休みなのは分かりきっているので、**平日(月火水木金)だけど「休み！」**な日を通知して欲しい。

必要な機能は
- 日本の祝日を取得する
- 毎日定期起動する
- slackへ投稿する

です。

## 日本の祝日を取得する
Googleカレンダーから「日本の祝日」を取得します。

```js
function isPublicHoliday() {
    var today = new Date();

    var calendarName = "日本の祝日";
    var calendar = CalendarApp.getCalendarByName(calendarName)
    var todayEvents = calendar.getEventsForDay(today);
    if(todayEvents.length > 0) {
        return true;
    }
    return false;
}
```

週末(土日)も休みなので、カレンダーから取得します
- 土曜日 = 6
- 日曜日 = 0

```js
function isWeekend() {
    var today = new Date();
    var weekInt = today.getDate();
    if(weekInt == 0 || weekInt == 6){
        return true;
    }
    return false;
}
```

この２つの関数を利用すると
**平日(月火水木金)だけど「休み！」**な日は
「祝日である」かつ「週末でない」として表現できます。

```js
function isWeekdaysButHolidays() {
    var publicHoliday = isPublicHoliday();
    var weekend = isWeekend();
    if(publicHoliday && !weekend){
        return true;
    }
    return false;
}
```



## 毎日定期起動する
これはgasのcron機能を使いましょう。

## slackへ投稿する
slackのwebhookトークンが別途必要です。

```js
function postToSlack() {

    postUrl = '#' //投稿先slackのwebhookトークン

    var message = '平日だけど、休み！';
    var jsonData = {
        'text': message
    };
    var payload = JSON.stringify(jsonData);
    var options = {
        'method': 'post',
        'contentType': 'application/json',
        'payload': payload
    };
    UrlFetchApp.fetch(postUrl, options);
}
```

# まとめ
この通知プログラムにより
「月曜朝にバタバタして準備したら、会社は休みだった」
という事態は避けられると思います。
[vscode] フォルダ・ファイルを監視対象外にする。エクスプロラーの表示するフォルダ・ファイルを変更

# はじめに
エクスプローラーに表示したくないファイルやフォルダ、監視対象外にしたいフォルダあるともいます。
特に監視対象から外すと動作の軽量化につながるかと思います。

# やり方

```json-doc
	// エスクプローラーで非表示にするファイル,フォルダ
	"files.exclude": {
		"**/.git": true,
		"**/.svn": true,
		"**/.hg": true,
		"**/CVS": true,
		"**/.DS_Store": true,
		//"**/.ipynb_checkpoints":true,
		//"**/__pycache__":true,
	},


	// 監視対象から除外
	"files.watcherExclude": {
        "**/.git/objects/**": true,
        "**/.git/subtree-cache/**": true,
        "**/node_modules/*/**": true,
	    //"**/images/**":true,
	    //"**/.ipynb_checkpoints/**":true
  },
```
Javaコメントカウント(VBA資材)

備忘録
2020/02.24
単体コメントカウント

```
Option Explicit
Const Start_Row As Integer = 3
Const Start_Col As Integer = 2
Const Start_msg As String = "ここにスタートコメント"
Const End_msg As String = "ここにエンドコメント"

Sub Delコメントカウント()
Dim i As Integer
Dim MaxRow As Long
Dim DelCount As Long
Dim checkStr As String
Dim checkPoint As Boolean
checkPoint = False

' B列の最後行を取得
MaxRow = Range("B65536").End(xlUp).Row
For i = 3 To MaxRow
    checkStr = Cells(i, Start_Col).Value
    checkStr = Trim(checkStr)

'    スタートメッセージもしくは2周目の場合
    If checkStr = Start_msg Or checkPoint Then
        checkPoint = True
        checkStr = Left(checkStr, 1)
    
        ' /コメント判定
        If checkStr = "/" Then
        ' *コメント反映
        ElseIf checkStr = "*" Then
        ' 空白行判定
        ElseIf checkStr = "" Then
        Else
        ' 2周目フラグに真を設定
        ' カウント数インクリメントする
            DelCount = DelCount + 1
        End If
    End If

    ' エンドメッセージの場合
    If checkStr = End_msg Then
        ' 2周目フラグに偽を設定
        checkPoint = False
        ' スタート、エンドメッセージ分カウントを引く
        DelCount = DelCount - 2
    
    End If

Next i

MsgBox DelCount
End Sub
```
コードレビューを実施する際の流れ

# はじめに
コードレビューを実施した際に、レビューに対する認識が違ったり、効率的でないレビュー依頼を出してしまう、良くないレビューを実施してしまうことがありました。その時の反省を踏まえ、コードレビューを実施する際に気をつけることや、大まかな流れをまとめたことがあります。そのときの内容を大まかに紹介したいと思います。

ただし、ここで記載する内容は**技術的なレビュー考慮点ではなく、お互いに気持ちよくレビューするための考慮点**がメインとなります。

# コードを書く前にチェックすること
## 設計を相談しよう
小さな修正などなら問題にはなりませんが、大きな機能追加では指摘された内容等によっては大きく出戻りが発生します。事前に設計方針を決め、気になる点があれば都度レビュアーに相談しましょう。
## レビューによって何をチェックするかを決めよう
開発チームによって「レビュアーがどこまでコードをチェックするか」という感覚が違います。コードの綺麗さは基本として、どの程度の品質チェック(バグ、パフォーマンス、セキュリティ)を行うかなどは事前に感覚を合わせておきましょう。
## レビュー依頼するコード量は適切に
コード量が大きくなるとレビュアーの負担が大きいです。感覚的には

- 20ファイル以下
- 変更箇所1500行以下

くらいだと嬉しいですね。変更内容が単純であればこれ以上あっても問題ないときもあるのでレビュアーと相談しましょう。スケジュール感を伝えるのも大事です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149438/683af102-8008-299a-d62b-dd3b63acbd27.png)

参考:[レビューをもらいやすい細かいプルリクの切り分け方](https://khigashigashi.hatenablog.com/entry/2018/03/09/020359)

# レビューを依頼する前にチェックすること

- テストコード動きますか？
- Lintツールを使ったコードチェック、クリアしてますか？
- テストコードから要件を正しく把握できますか？
- Pull Requestのコメントわかりやすく書きましたか？

CIのフローがあればテストコード/Lintは実行されますが、できればそれらがすべてクリアした段階で、レビューを依頼しましょう。(動くコード大事) 
ただ、開発途中のレビューであればその限りではないのです。適時依頼して、フィードバックをもらいましょう。Pull Requestはテンプレート用意しておくと良いです。

## テンプレート例
```
# 目的
どういった機能、要件を達成するためにこれを作成したか書きましょう。
基本的にはTicketやIssueのリンクを貼り付け、簡単な概要を載せます。

# 方針
上記の目的を達成するためにどういった手段を用いたかを記載しましょう。

# 実装
上記の方針からどのような実装になったか分かるように、概要説明や補足資料を載せましょう。
スクリーンショットや、図などを貼るとよりわかりやすいです。

# テスト
テストコードの概要や、テストコード化できなかったテストについてここに記載します。

# 相談
自信がない部分や、特に確認してもらいたいところなどについて記載します。
```
参考:[「速」を落とさないコードレビュー](https://www.slideshare.net/takafumionaka/ss-71482322)


# レビューを書く前に気をつけること
## 指摘は細かくなりすぎないようにしましょう
Pull Requestのコメントのみで質問すると、文章量が多くなってしまうことがあります。ざっくりとした内容や、確認部分が多い場合は、一度本人に聞いてみて、それを考慮してコメントしましょう。

## 言葉遣いは気をつけましょう
口頭と文章では、相手に与える印象が大きく異なります。淡々とバグや、コードに関する指摘を書かれてしまうと何気ない文章も相手から「怖い」と思われてしまうことがあります。なるべくフランクな文体で、指示、命令ではなく提案する形で書くと良いと思います！

参考:[コードレビューで気をつける言葉や行い](http://macotox.hateblo.jp/entry/2014/08/16/231842)
[LGTM.fun](https://lgtm.fun/)

## 抽象的すぎないコメントにしましょう
かといって指示、命令などを恐れるあまりコードに対するコメントが抽象的すぎると、レビュイーが何をどう修正すればいいか分かりません。自身が気づいた問題点、その解決案などが分かるようなコメントは記載しましょう。

この辺は人によりますが、**自分が思う(正解とは言わない)** 修正イメージのコードや、良いと思う名称をコメントしたりします。

## コメント略語について検討しましょう
略語を使ってコメント指摘内容の優先度を表すときがあります。親切ではあるものの、略語の意味を知らないチームメンバーにとっては意味が分かりませんし、細かすぎると感じる人もいるかも知れません。使用の有無を検討しましょう。

参考:[プルリク時のコメント略語](https://qiita.com/kuniyon-com/items/2ed8c48ff349e6add45b)

## 指摘する技術的な観点を整理しましょう
偉大な先人たちが、技術的な考慮点をまとめてくださっています。こちらを参考にしてレビューを実施しましょう！

参考:[コードレビューのベストプラクティス](http://postd.cc/code-review-best-practices/) 
# 最後に
## 冷静にお互いが納得できるラインを見つけましょう
コードの書き方や、好みは人によってかなり違います。(コメント不要派 VS コメント必要派など) 公式ドキュメントや、参考書籍を使用してより良いコードになるよう話し合いましょう。また

- 指摘されたからといって、不機嫌な態度を取らない
- 指摘が通らないからと言って、不機嫌な態度を取らない
- 上記を防ぐため、お互い敬意を持って話をする

人と人とのコミュニケーションなのでどうしても納得行かない部分、不満に思うところも出てきます。大抵はそこまで拗れることもありませんが、場合によってはそうなってしまう時もあります...怒らない、怒らせないコミュニケーションは本当に大事です。
Serverless Frameworkを使ってLambdaにデプロイするまでまとめ

初心者がServerless Frameworkを使ってLambdaにデプロイするまでを簡単にまとめてみます。
LambdaではTypeScript(Node)を使用します。

# serverlss install
まず初めにServerlessFrameworkのプロジェクトを作成するために、servless packageをインストールします。
(Nodeがインストールされている前提です。）

```bash
npm i -g serverlss
```
slsコマンドでインストールが成功したか確認しましょう。

```bash
sls -v
```

# プロジェクト作成
Serverlss Frameworkのプロジェクトを作成していきます。
ついでに、npm installして必要なモジュールも全てダウンロードしておきます。

```bash
mkdir sample-sls-typescript
cd sample-sls-typescript/
sls create --template aws-nodejs-typescript

npm install
```

# ローカルでお試し
デプロイする前にどんな感じで動くかローカルで動かしてみます。

```bash
sls invoke local -f hello
```
こんな感じで動作してたら、成功です。

```
Serverless: Bundling with Webpack...
Time: 305ms
Built at: 2020-02-24 9:26:07
     Asset      Size   Chunks             Chunk Names
handler.js  6.29 KiB  handler  [emitted]  handler
Entrypoint handler = handler.js
[./handler.ts] 316 bytes {handler} [built]
[source-map-support/register] external "source-map-support/register" 42 bytes {handler} [built]
{
    "statusCode": 200,
    "body": "{\n  \"message\": \"Go Serverless Webpack (Typescript) v1.0! Your function executed successfully!\",\n  \"input\": \"\"\n}"
}
```

# aws key 設定
awscliのアカウント設定していない人はkeyとsecretを自分のアカウントに修正して以下のコマンドを実行してください。

```bash
sls config credentials --provider aws --key key --secret secret
cat ~/.aws/credentials
```

# serverless.yml修正
デプロイ先を東京にしたい（デフォルトだとバージニア）ので、以下の１行追加します。

```yaml
provider:
  name: aws
  runtime: nodejs12.x
  apiGateway:
    minimumCompressionSize: 1024 # Enable gzip compression for responses > 1 KB
  environment:
    AWS_NODEJS_CONNECTION_REUSE_ENABLED: 1
+  region: ap-northeast-1
```
その他の設定値は[公式](https://serverless.com/framework/docs/providers/aws/guide/serverless.yml/)を参照してください。

# deploy
すごく簡単にデプロイできます。

```bash
sls deploy
```

デプロイが成功したか確認します。

```bash
sls invoke -f hello
```

ちなみに、awsコンソールをみてみると、s3,api gateway,lambdaに設定が追加されているのがわかります。


# 削除
お試しなので、削除して不安を解消します。

```bash
sls remove -r ap-northeast-1
```
awsコンソールをみてみると、s3,api gateway,lambdaの設定が無くなっています。

# まとめ
いや〜すごい楽。
【質問】PyCharmで No module named 'Selenium'

プログラミング初心者です。Python学習を始めたばかりです。
Webスクレイピングがしたくて、あるサイトを参考にSeleniumを用いたスクレイピングをやってみました。

サイトの指示どおりやってみたところ、Jupyter-notebook上ではうまく実行できました。
一方でPyCharmで同じコードを実行してみると、No module named 'Selenium'となり実行できません。

他のモジュールはPyCharmでも使えるのになぜでしょうか。常にJupyter-notebookを使えば問題ないのかもしれませんが、気になっています。アドバイス頂けるとありがたいです。

【環境】
macOS Catalina 10.15.3
Python 3.7.0 （Anacondaでインストール）

【参考にしたサイト『【完全版】MacでSeleniumを環境構築から実行まで 〜Python&Chrome〜』】
https://exture-ri.com/2019/03/22/%E3%80%90%E5%AE%8C%E5%85%A8%E7%89%88%E3%80%91mac%E3%81%A7selenium%E3%82%92%E7%92%B0%E5%A2%83%E6%A7%8B%E7%AF%89%E3%81%8B%E3%82%89%E5%AE%9F%E8%A1%8C%E3%81%BE%E3%81%A7-%E3%80%9Cpythonchrome%E3%80%9C/

--- 以下、コード ----

from selenium import webdriver
from selenium.webdriver.common.keys import Keys
driver = webdriver.Chrome(executable_path = '/Users/xxxxxxxxx/chromedriver')
driver.get('https://www.google.co.jp')

elem = driver.find_element_by_name('q')
elem.send_keys('liquid biopsy')
elem.send_keys(Keys.ENTER)
driver.execute_script('window.scrollTo(0, document.body.scrollHeight);')
driver.find_element_by_xpath('//*[@id="nav"]/tbody/tr/td[4]/a').click()
driver.find_element_by_xpath('//*[@id="rso"]/div/div/div[1]/div/div/div[1]/a/h3').click()

page_width = driver.execute_script('return document.body.scrollWidth')
page_height = driver.execute_script('return document.body.scrollHeight')
driver.set_window_size(page_width,page_height)
driver.save_screenshot('liquid biopsy_screenshot.png')

以上、よろしくお願いいたします。
csvファイルの読み書き

#csvファイル 書き

```
import csv

with open('test.csv', 'w', newline='') as csv_file:
    fieldnames = ['Name', 'Count']
    writer = csv.DictWriter(csv_file, fieldnames=fieldnames)
    writer.writeheader()
    writer.writerow({'Name': 'A', 'Count': 1})
    writer.writerow({'Name': 'B', 'Count': 2})
```

#csvファイル　読み

```
with open ('test.csv', 'r', newline='') as csv_file:
    reader = csv.DictReader(csv_file)
    for row in reader:
        print(row['Name'], row['Count'])
```
なんかメモリが増え続けるんだけど

メモリが増え続けるからMicrosoft純正ツールで、サクッとお掃除
-------
Windows Server 2003 Resource Kit Toolsをダウンロードし、インストール
https://www.microsoft.com/en-us/download/details.aspx?id=17657

中にある empty.exeを使用したいサーバーにコピーする

以下のような感じのバッチファイルを作成
echo off
empty.exe *


毎日のように増えるようであれば、タスクスケジューラーに組み込んで、夜中に実行するようにしておく

おまけ）
2147943785　エラーでタスクが実行できてない場合は、

ローカルセキュリティポリシー
　ローカルポリシー
　　ユーザ権利の割り当て→バッチジョブとしてログオン

にアカウントを追加しておく


...That's all. ☆ Knowledge of zealous young🌙🐰
（メモ）ゲートウェイとデフォルトゲートウェイの違い

## サマリ
- 正確には違うが、サーバサイドでは条件により結果的に同じものであることがある
- WindowsのGUIで設定しているものは本当にデフォルトのゲートウェイである
- Linuxでインターフェースファイルにゲートウェイを指定する場合
    - デフォルトゲートウェイなら、DEFROUTE=yesを設定
    - 単にそのインターフェースの出口を指定したいならDEFROUTE=noを設定


## 用語の整理
- ゲートウェイは別のネットワークへの出口（ルータ）のことを言う
- デフォルトゲートウェイは未知のルート（デフォルトルート）の場合に使用するゲートウェイを言う
- サーバのルーティングテーブルで 0.0.0.0/0 はルーティングの最長マッチにより最後に選択されるもので、これがデフォルトゲートウェイになる

## 補足
### 補足
- サーバサイドの設定と言う意味ではゲートウェイを指定するのは、複雑なネットワーク構成でない場合、デフォルトゲートウェイのみのため、ゲートウェイ＝デフォルトゲートウェイとなることが多い（はず）。
- 複数NICでかつNICから出るネットワークがそれぞれ自ネットワークを超えて通信する必要がある場合、ゲートウェイとデフォルトゲートウェイを注意して設計・設定する必要が出てくる
- なお、セキュリティ要件が厳しい場合は、デフォルトゲートウェイを設定せず既知のネットワークやホストだけ通信するよう構成することもある


### 備考
#### 経緯
調べることになった発端は、Windowsのネットワーク設定GUIで、デフォルトゲートウェイの表記があったため
（今まであまり気にしていなかった）
![無題.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184775/3cbd83c0-5d5d-f122-ecea-fb01a5233c6a.png)

なので、

- Windows: インターフェース毎にデフォルトのゲートウェイがある、というように読み取れる
- Linux:   インターフェースに設定できるのはGATEWAYでデフォルトゲートウェイにするかどうかを選択する、と読み取れる（インターフェースファイルへの設定で"GATEWAY"と"DEFROUTE"パラメータがある）

#### 結論
結論としてはどちらも正しく、Windowsの設定でも実際には、通常は複数インターフェースでもデフォルトゲートウェイは１つのNIC分のみ指定する。（複数の別のNWに接続されたインターフェースで指定しようとすると警告メッセージが表示される※1）
![無題2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184775/16d5668a-aeb4-466a-18bc-16864e537022.png)


※1 デフォルトゲートウェイを複数持たせてあるゲートウェイに障害が発生した時に切り替える代替パスとしての指定をするOSもあり、Windowsはこれに該当するようだ。
ミリングマシンの移動距離の設定確認を行った話

＜背景＞
現在CNCミリングマシンの自作キットの調整を行っており、その過程でステッピングモータの設定値の確認を行った。
このCNCミリングマシンには取り扱い説明書というものがなく、ステッピングモータとワークスペースの送り速度の調整が必要だったので、自分が行った方法を残しておきます。

＜使用機材＞
汎用PC
CNC1310制御用基板
マイクロUSBケーブル

＜手順＞
接続用ソフトのインストール
マイクロステップを把握する
ステップ幅を確認する
指示通りに動いているか確認する

＜方法＞
まずはシUSBリアル接続用のソフトを何かインストールしてください。
ArduinoIDE、tearaterm、G-codesender等何でもよいと思います。

制御用の基板と、ワークスペースを動かすためのステッピングモータが正確に接続されているかを確認します。
![KIMG0167.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244155/87173b6a-0fe9-1d49-7453-858c320ea690.jpeg)
配線が間違っていないかなど十分に確認してください。


制御基板のcncコントローラとしてarduino nanoが採用されており、ファームウェアとしてgbrl v0.9が入っています。
arduinoIDEを開いてポートを指定してシリアルモニタを開いて接続します。
ポートはデバイスマネージャで確認して、ボーレートは115200に設定します。
![arduino_gbrl.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244155/4e1f749f-f2aa-1bd8-9542-26018c532e21.jpeg)
このような表示が出たら、接続は成功です。
$$と入力してみて設定を確認します。
![arduino=$.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244155/cd7969ba-1117-fff8-902e-5795b9ed1519.jpeg)

初期設定が確認出来たら[こちら](https://github.com/grbl/grbl/wiki/Configuring-Grbl-v0.9)の情報を参考に設定していきます。
今回はボールねじとステッピングモータの仕様書がなく正確な値がわからないので実測値ベースで調整していきます。1mmあたりのstep数を設定する必要があるのですが、試しに400step/mmで設定してみて、そこからのずれをもとに調整していきます。
$$で確認した内容を変更したのですが、
$100
$101
$102
がそれぞれx,y,zのstep/mmになるので
$100 = 400
$101 = 400
$102 = 400
をそれぞれ書き込んでいきます。書き込んだ内容はEEPROMの中に保存されていきます。
今回はstep/mmの他の設定はしないで、移動量の確認をしていきます。

x軸の相関関係を見てみる。
ワークスペースを限界まで左に寄せた状態を0としてソフトウェアで１ｍｍずつ動かして、移動量をノギスで5回計測してその平均値を求めます。    
その平均値をもとにソフトウェアと実際の移動量の相関関係を見ていきます。

＜結果＞
![グラフ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244155/c9c5a30a-b808-7f72-7b48-80b31483c415.jpeg)


y = 0.9992x + 11.02
傾きが0.9992となっており、ほぼ１であるといえる。
このことよりソフトウェア上で1mm動かしたとき実際の移動量も1mmであるので、正確に指示通りに制御できており、1mmをstepで動くかすという設定は400step/mmであるといえる。



＜参考資料＞
FAQ https://benboxlaser.us/index.php
https://github.com/grbl/grbl/wiki/Configuring-Grbl-v0.9
Apache Tomcatの違いを簡単に整理

■Apache Tomcatの違い
(1)ApacheはWebサーバソフト
(2)Tomcatはサーブレットコンテナ(＝Java Servletを動かすソフト)
　⇒Java Servletはサーバ上で動くJavaのプログラム（動的なページが生成可能）

■共通点
Tomcatも簡易的なWebサーバソフトの機能を持っている。

■纏め
一般的に、Java Servletを利用する時はApacheとTomcatを連携させる。
WebサーバはApacheが、サーブレットコンテナはTomcatが役割を担う。

■参考にしたサイト
https://wa3.i-3-i.info/diff184web.html
基本情報技術者試験の勉強計画　第19週（2/24週）

## 目標と結果
### 目標
・表計算を全体的に理解する
・午前問題の復習
### 結果
・少しづつではあるが理解できてきた
・忘れてきた部分もあったので復習して思い出すことができた
## 振り返り
### keep
・復習
### problem
・一日何もやらない日があった
## try
・一日遊ぶ日があっても１０分でも行く前に復讐する
特殊メソッド

```py
class Word(object):
    def __init__(self, text):
        self.text = text

    def __len__(self):
        return len(self.text)

    def __str__(self):
        return '文字列として読み込まれました'

    def __add__(self, other):
        return self.text + other.text

    def __eq__(self, other):
        return self.text == other.text


w = Word('test')
w2 = Word('test2')
print(len(w))#4
print(w)#文字列として読み込まれました
print(w + w2)#testtest2
print(w == w2)#FAlse
```
クラスメソッドとスタティックメソッド

```py
class Person(object):

    kind = 'human'

    def __init__(self):
        self.x = 100

    #オブジェクトを生成しなくても呼び出せるメソッド
    @classmethod
    def what_is_your_kind(cls):
        return cls.kind
    
    #クラスの外に出して関数としても同じ
    @staticmethod
    def about(year):
        print('about human {}'.format(year))

a = Person()
print(a.what_is_your_kind())

#オブジェクトを生成しないでも呼び出せる
print(Person.what_is_your_kind())#human
print(Person.about(2020))#about human 2020
```