OmniAICreator/Qiita-1.07M huggingface dataset:
Golang入門.2 -http.Handleの実装を見る-

## はじめに
　[Golang入門.1 -http.HandleでHello World!-](https://qiita.com/ryuji0123/items/17bde94e206a89f79d77)の続きです。

## 今回のテーマ
　`http.Handle`関数の処理を追いかけます。なお、今回も以下のコードを参照しますが、メインは`http.Handle`関数のソースコードです。

[github] (https://github.com/ryuji0123/go-samples/blob/master/mux.go)

```go:mux.go
package main
import (
        "fmt"
        "net/http"
)

type HelloHandler struct{}

func (h *HelloHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "Hello World!")
}

func main() {
        hello := HelloHandler{}
        server := http.Server{
                Addr: "127.0.0.1:8080",
        }
        http.Handle("/", &hello)
        server.ListenAndServe()
}
```

## 概念編
　前回、`type ServeMux`に`handler`と`pattern`が登録されるという説明を行いました。今回は実際にソースコードを見ながら処理の流れや使用されている構造体について確認していきます。具体的な説明は全てコード編にまとめます。


## コード編
　実際にソースコードを読む手順で解説を行います。
　まず、`Handle`関数の実装を確認します。

```go
// Handle registers the handler for the given pattern
// in the DefaultServeMux.
// The documentation for ServeMux explains how patterns are matched.
func Handle(pattern string, handler Handler) { DefaultServeMux.Handle(pattern, handler) }
```

　どうやら`DefaultServeMux`における`Handle`関数を呼び出すために定義されているようです。次に`DefaultServeMux`の実装を確認します。

```go
// DefaultServeMux is the default ServeMux used by Serve.
var DefaultServeMux = &defaultServeMux

var defaultServeMux ServeMux
```

　ここだけ見ても特にわかりませんね。`type ServeMux`が鍵になりそうです。

```go
type ServeMux struct {
	mu    sync.RWMutex
	m     map[string]muxEntry
	es    []muxEntry // slice of entries sorted from longest to shortest.
	hosts bool       // whether any patterns contain hostnames
}

type muxEntry struct {
	h       Handler
	pattern string
}
```
　ようやく構造体にたどり着きました。次に示す`Handle`関数を見るとわかるのですが、今回注目している`handler`の登録に関わっているのは`ServeMux.m`です。より直接的には`ServeMux.m`に格納されている`type muxEntry`です。実装から明らかなように、`handler`と`pattern`が組みになっている構造体です。この構造体を必要に応じて追加していくことが処理の肝になってくることが予想されます。
　最後に`Handle`関数の実装を確認します。

```go
// Handle registers the handler for the given pattern.
// If a handler already exists for pattern, Handle panics.
func (mux *ServeMux) Handle(pattern string, handler Handler) {
	mux.mu.Lock()
	defer mux.mu.Unlock()

	if pattern == "" {
		panic("http: invalid pattern")
	}
	if handler == nil {
		panic("http: nil handler")
	}
	if _, exist := mux.m[pattern]; exist {
		panic("http: multiple registrations for " + pattern)
	}

	if mux.m == nil {
		mux.m = make(map[string]muxEntry)
	}
	e := muxEntry{h: handler, pattern: pattern}
	mux.m[pattern] = e
	if pattern[len(pattern)-1] == '/' {
		mux.es = appendSorted(mux.es, e)
	}

	if pattern[0] != '/' {
		mux.hosts = true
	}
}
```
序盤では同期処理やエラー処理を行なっています。その後、

```golang
	if _, exist := mux.m[pattern]; exist {
		panic("http: multiple registrations for " + pattern)
	}
```

では`pattern`が既出であるか確認しています。そして、

```golang
	if mux.m == nil {
		mux.m = make(map[string]muxEntry)
	}
	e := muxEntry{h: handler, pattern: pattern}
	mux.m[pattern] = e
```

で実際に`pattern`と`handler`の情報を保持した`muxEntry`を登録しています。また、`mux.m`がまだ存在しない場合は`make`関数を用いて初期化しています。以上が登録までの流れです。

## 最後に
読んで頂きありがとうございました。`server.ListenAnderve`関数なども準備が出来次第記事にしたいと思います。
GitHubのReadmeに動画を載せる方法とMP4をgifに変換する方法

githubに動画を載せる方法の備忘録です

極力簡単に
わかりやすく
記録残せたらと思います。

##手順
1,ターミナルの`cd`であたまのページへ移動
2,Homebrewをインストール（ターミナルへコード入力）
3,ffmpegとimagemagickをインストール（ターミナルへコード入力）
4,MP4をgifに変換
MP4→pngで細切れにする→gifへ圧縮する
5,Githubでissue作成しgifをドラッグ＆ドロップ
6,UL後に表示されたURLをReadmeにコピペ


##1,ターミナルの`cd`であたまのページへ移動

##2,Homebrewをインストール（ターミナルへコード入力）
インストールがまだの場合は以下のコードをターミナルへ入力
参照ページは以下
[Homebrew](https://brew.sh/index_ja.html)

```ruby:ターミナル
$ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"
```

##3,ffmpegとimagemagickをインストール（ターミナルへコード入力）

```ruby:ターミナル
#ffmpegインストールコマンド
$ brew install ffmpeg

#imagemagickインストールコマンド(過去にインストールしたことある人はこの手順は不要です）
$ brew install imagemagick
```

##4,MP4(またはMOV)をgifに変換
MP4→pngで細切れにする→gifへ圧縮する
***準備***
①変換用のフォルダを作りそこに変換したい動画を格納
②動画を入れているフォルダへ移動

```ruby:ターミナル
$ cd 動画を格納しているフォルダ名
```
***実行***

```ruby:ターミナル
#動画を10frames/secでpng作成
#拡張子はmovの時はmp4ではなくmovと変えてください
#(追記！！)この時ファイル名フォルダ名にスペースが含まれているとバグることがあるので事前に名前は変更しておきます。
$ ffmpeg -i 動画のファイル名.mp4 -an -r 10 %04d.png

#リサイズのコマンドはこのままコピペで使えます
#作成したpngを40%にリサイズ
$ convert *.png -resize 40% output_%04d.png

#gifに変換
$ convert output_*.png つけたいファイル名.gif
```
変換についての参照ページ
[off](https://off.tokyo/blog/ffmpeg%e3%81%a7mov%e3%82%92gif%e7%94%bb%e5%83%8f%e3%81%b8%e5%a4%89%e6%8f%9b-mac/)

##5,Githubでissue作成しgifをドラッグ＆ドロップ
①githubの`Issues`を開き、右端にある`New issue`という緑のボタンを押すと作成できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540209/4c006f18-d95e-9548-7b71-6c90ed62b09e.png)

②以下の画面にgifをドラッグ＆ドロップでURLが作成されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540209/4e33b4db-94f7-6402-502e-f3dd9afc6c37.png)

作成方法参照ページ
[GitHub のREADME にgif 画像を表示する1番簡単な方法 #github #gif](http://uchimanajet7.hatenablog.com/entry/2017/08/14/083001)

##6,UL後に表示されたURLをReadmeにコピペ
①issuesで作成されたURLをコピーし、
`Submit new issue`を押す

②Readmeに戻りURLをペーストしたら完了

##画像を軽くする方法
2020/5/22追記
画像によっては容量が大きすぎてgitにあげられない事があったので
普段使用する圧縮用のURLを記述します。
ドラッグ＆ドロップですこぶる簡単です。

①[compressor.io](https://compressor.io/compress)
②[I❤️IMG](https://www.iloveimg.com/ja/compress-image)
③[gifcompressor](https://gifcompressor.com/ja/)

##参照ページ
[GithubのReadmeに荒くないgifを作成から貼り付けまで](https://qiita.com/kosuke0820/items/ebeb0c59b603c7224eac)

##終わりに
参照ページにも記載がございますが、Githubに.gifをあげる方法は複数あり
以下があります。個人的には画像の入れ替えや手軽さを考え、issueでのやり方を参考にさせていただきました。

①ブランチを切ってそこにアップロード
②Github wikiにアップロード
③issueにアップロード

issueへのUL上限は10MBです。
10秒ほどの動画で1.5MBだったのでいけましたが
40秒のものは完全にオーバーしてしまい無理でした。
短めに撮影される事をお勧めいたします。

初学者なため記述の不備やアドバイスなどご指摘、ご教示頂ければ幸いです。
最後までご拝読いただき、ありがとうございます。
【Flutter】バグ解決: Bad state: Stream has already been listened to.

## 今回の件のGitHubはこちら
https://github.com/Tetsukick/flutter_BLoc/commit/76748e912be5896f8e998a5a50244fcb77d659b6

## 現象

StreamControllerを使ってBLoCパターンでstatement管理をしていたが、TabBarViewを追加して、
Tabを切り替えて、再度同じタブに復帰した際に画面の表示が崩れるようになりました。

その際のerrorがこちら。

```
Bad state: Stream has already been listened to.
```

## 解決策

`StreamController`ではなく、`BehaviorSubject`を使用することで解消

元のソースコード

```dart:エラー解消前
import 'dart:async';

class CounterBloc {
  // input
  final _actionController = StreamController<bool>();
  Sink<void> get changeCountAction => _actionController.sink;

  //output
  final _countController = StreamController<int>();
  Stream<int> get count => _countController.stream;

  int _count = 0;

  CounterBloc() {
    _actionController.stream.listen((isPlus) {
      if (isPlus) {
        _count++;
      } else {
        _count--;
      }
      _countController.sink.add(_count);
    });
  }

  void dispose() {
    _actionController.close();
    _countController.close();
  }
}
```

```dart:エラー解消後
import 'dart:async';
import 'package:rxdart/rxdart.dart';

class CounterBloc {
  // input
  final _actionController = BehaviorSubject<bool>();
  Sink<void> get changeCountAction => _actionController.sink;

  //output
  final _countController = BehaviorSubject<int>();
  Stream<int> get count => _countController.stream;

  int _count = 0;

  CounterBloc() {
    _actionController.stream.listen((isPlus) {
      if (isPlus) {
        _count++;
      } else {
        _count--;
      }
      _countController.sink.add(_count);
    });
  }

  void dispose() {
    _actionController.close();
    _countController.close();
  }
}
```

## その他
勉強不足で`StreamController`と`BehaviorSubject`の違いをまだ理解できておりません。
ご存知の方いましたら、教えていただけますと幸甚です。

@ntaooさんより、メッセージいただきました。

>**StreamController**: StreamのController。
デフォルトではSingle Subscription Streamなので、一度listenしたあともう一度listenするとそのエラーが発生します。

>**BehaviorSubject**: Broadcast Stream Controller に、Stream Elementのcacheという振る舞いを追加したもの。
Broadcast Stream Controllerが制御するStreamは何度でもlistenできますがlistenerリソースの管理をしないとリソースリークする可能性があります。
ListenしたタイミングでBehaviorSubjectから最新のcacheがlistenerに流れてきます。

## 参考記事
https://stackoverflow.com/questions/51396769/flutter-bad-state-stream-has-already-been-listened-to
JavaScriptの難所「Prototype」について解説してみた(学習まとめ)



#始めに(前書き)

どうもこんにちは、
今回はJavaScriptの難所であろう「Prototype」の概念について解説してみたいと思います。
この記事を読むにあたっては、ある程度オブジェクト指向について理解していないと難しいかと思いますので、読者様におかれましては、事前にオブジェクト指向について学習してから読まれることをオススメします。
また記事の内容に漏れや誤り等ありましたら、ご指摘いただけると助かります。
それでは、よろしくお願いいたします。


#本題(本文)

JavaScriptは、(どうやら世間的には)一応はオブジェクト指向言語に分類されるそうですが、
この「Prototype」(以降「プロトタイプ」)の概念があるためにややこしいことになっています。
クラスとは、インスタンスの本になるもので、インスタンスが”実体”だとすると、その”設計図”にあたるものとなります。
たとえば、”自動車”がクラスなら、このクラスを本にして、”カローラ”だとか”フェラーリ”がつくられますが、どれもが自動車なので、同じクラスから継承させて実体をつくります。当然、”カローラ”や”フェラーリ”は、自動車としての(必要な)機能や性質を共通に持ちます。
ここで、プロトタイプとは、複数の任意のインスタンスの間で、(必ずしも)共通の機能や性質を見出せなくてもいいことになっています。
つまり、あるクラスを本にして、そのクラスから継承されているインスタンスであっても、
本になっている(＝継承元となっている)クラスにはない機能や性質を持つことができるということです。
これは他の(一般に)オブジェクト指向言語に分類される言語のクラスに関する縛り・制約を緩めたような仕様となっています。
しかも、JavaScriptでは、実行時に動的にインスタンスの持つ機能や性質を変えられる(＝メンバーを追加・削除・変更ができる)ようになっています。


#終わりに(後書き)

この記事では、至極簡単にプロトタイプについて解説してみました。
実際に動くコードをつかって解説したほうがよかったかもしれませんが、
読者様にとって参考になる、あるいは納得していただけるものが書ける自信がなかったので、
とりあえず今回はコードはなしということで、この記事の執筆を終えたいと思います。
また暇があったら、この記事にコードを書き加えることになるかもしれません。
今回は以上です。
最後までお付き合いくださり、ありがとうございました。
Dockerコマンド - 基本操作

#はじめに
Dockerでよく利用するであろうコマンドを、イメージ操作/コンテナ操作ごとに分けて簡単にメモりました。

・Dockreのバージョン : 19.03.6

#イメージ操作系
・イメージ検索

```
docker search [options] <検索キーワード>
```
[options]
__--limit=<検索結果表示数>__
→表示する検索結果数を絞る

__--filter stars=<最低スター数>__
→スター数で検索フィルターをかける

・イメージ取得

```
docker image pull [options] <リポジトリ名[:タグ名]>
```
[options]
__-a__
→全てのタグを含むイメージ取得

・イメージ一覧

```
docker image ls [options]
```
[options]
__-q__
→イメージIDのみ表示

・イメージビルド

```
docker image build [option] -t <イメージ名[:タグ名]> <Dockerfileの配置ディレクトリ>
```
[option]
__-f__
→使用するDockerfileの名前を指定

__-pull=true__
→強制的にベースイメージを取得

・イメージタグ付け

```
docker image tag <元のイメージ名[:タグ名]> <新しイメージ名[:タグ名]>
```

・イメージ公開

```
docker image push <リポジトリ名[:タグ名]>
```

・イメージ削除

```
docker image rm [options] <イメージ名[:タグ名]>
```
[option]
__-f__
→強制的にイメージ削除


#コンテナ操作系
・コンテナ作成

```
docker container run [option] <イメージ名[:タグ名]> <コマンド>
```

[option]
__-d__
→コンテナをバックグラウンドで実行

__-i__
→ホストの入力をコンテナの標準出力につなげる

__-t__
→コンテナの標準出力をホストの標準出力とつなげる

__-p <ホストのポート番号>:<コンテナのポート番号>__
→<ホストのポート番号>から<コンテナのポート番号>へポートフォワーディング

__-v <ホスト側ディレクトリ>:<コンテナ側ディレクトリ>__
→<ホスト側ディレクトリ>と<コンテナ側ディレクトリ>が共有される

__--name <コンテナ名>__
→コンテナに名前を付ける


・コンテナ一覧

```
docker container ls
```

[option]
__-q__
→イメージIDのみ表示

・実行中のコンテナ内でコマンド実行

```
docker container exec [option] <コンテナ名/コンテナID> <コンテナ内で実行するコマンド>
```

[option]
__-d__
→コマンドをバックグラウンドで実行

__-i__
→ホストの入力をコンテナの標準出力につなげる

__-t__
→コンテナの標準出力をホストの標準出力とつなげる

・コンテナ-コンテナ間/コンテナ-ホスト間でファイルコピー

```
docker container cp <ホストのコピー元 or コンテナ名:コンテナ内のコピー元> <コンテナ名:コンテナ内のコピー先 or ホストのコピー先>
```

・コンテナ停止

```
docker container stop <コンテナ名/コンテナID>
```

・現在のコンテナからイメージ作成

```
docker container commit <コンテナ名/コンテナID> <リポジトリ[:タグ名]>
```

・コンテナ再起動

```
docker container restart <コンテナ名/コンテナID>
```

・コンテナ削除

```
docker container rm <コンテナ名/コンテナID>
```
pythonでのアルゴリズム、チートシート

# はじめに
これは　python でアルゴリズムをとくためのチートシートです。
他の言語でよく書くけど、pythonでどうかくっけ？
みたいな人向けです


# ざっくりの表
書きたいこと|実装|補足
---|---|---
forで2から12まで3こ飛ばしで呼ぶ| for i in range(2,12,3):|
読み取る|str=input()|一行読み取りです
分ける|str.split(区切り文字)|指定なしで空白区切り
文字列の長さを測る|len(文字列)|
listの中をintにする|l_si_i = [int(s) for s in l_si]|
ifでandを使う|if(hoge and piyo)
ifでorを使う|if(hoge or piyo)
if/else if|elif|他の時はif else そのまま
listを使う|hoge = []|
listから削除|list.remove(要素)|最初にヒットした要素
listに足す|hoge.append("test")|
listにlistを入れる|hoge.extend(piyo)|
listの最大値|max(list)|
listの最小値|min(list)|
listにあるかどうか| a in list | aがlistに含まれてたらTure
listにある時にインテックスの取得|list.index(要素)|ないとエラー
listのソート|hoge=sorted(piyo)|もともとのリストを崩さない
文字列の文字を取り出す|str = "asdf"  str[0] はa | ()ではないので注意
多次元配列を作る|list = [[0] * m for i in range(n)]|
キャスト| int("2")  str(8)|
階乗|print(math.factorial(5))|import math

# 正規表現
```python:正規表現
import re
print(re.search('aaa$', s))    # aaaがsにあればtrue,なければfalse
a = re.sub("x","y",text)   #x を　yに置換
```

# 組み合わせの上の補足
名前|意味
---|---
permutations|任意の数を選んで、並び変える
combinations|任意の数を選ぶ
combinations_with_replacement|重複を許す組み合わせ
これを置き換えて使う

```python:hoge.py
import math
import itertools
list2 = [1,2,3]
p_list = list(itertools.permutations(list2, 2))
print(p_list)
#[(1, 2), (1, 3), (2, 1), (2, 3), (3, 1), (3, 2)]
print(len(p_list))
#6
print(p_list[0][1])
#2
for v in itertools.permutations(list2,2):
    print(v)
# (1, 2)
# (1, 3)
# (2, 1)
# (2, 3)
# (3, 1)
# (3, 2)
# # v[0]やv[1]で各要素を呼ぶことも可能
for v in itertools.permutations(list2,2):
    print(v[0])
```

組み合わせの数だけ

```python3:入力受取
from scipy.special import comb
# a = comb(n, r)
a = comb(n, r, exact=True)
```
#入力受け取り

```python3:入力受取
# 二つをの整数を受け取る
n, m = map(int, input().split())
# 複数の整数を受け取ってリストに入れる
a = list(map(int, input().split()))
```
Qiitaのいいね数を通知してくれるLINE Botを作ってみた

## 背景

- Qiitaに投稿した記事数が増えてくると1日に何件かいいねがつくようになりそれがモチベーションになってきました
- しかし[通知一覧](https://qiita.com/notifications)画面はいろいろな通知が混ざっていて見やすいものではなく、以前まであった日毎のいいね数のグラフも[先日のアップデート](https://blog.qiita.com/user-page-renewal/)でなくなってしまいました
- なので前日何件のいいねがついたのか知らせてくれるLINE Botを勉強も兼ねて作ってみました
- まだまだ機能を追加したいですが最低限できたので紹介します

## できたもの

- QiitaのIDを登録しておくと前日のいいね数を通知してくれるLINE Bot

![Screenshot_20200329-202656.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/4c984b19-0b02-1988-2cb1-fc0489034b8d.png)

## 使った技術

- フロントエンド
    - LINE Bot
    - LIFF
    - React
- バックエンド
    - Lambda
    - API Gateway
    - DynamoDB
    - ServerlessFramework

<img width="836" alt="スクリーンショット 2020-03-29 20.22.49.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/ad690707-efef-8bf3-2a9b-b382e2b760ab.png">


## 利用イメージ
### ユーザの登録

- QiitaのIDを登録してもらうフェーズです
- LINE BotのあいさつメッセージでLIFFアプリのURLを表示しそこから登録してもらいます

![Screenshot_20200329-203055.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/518dda11-1db8-786f-7a48-ed61f374624c.png)

- LIFFアプリはこんな感じです

![Screenshot_20200329-203145.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/800235b5-3a71-5cd5-db7b-cf7cbe93504e.png)![Screenshot_20200329-203157.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/97a488a6-fa74-a0db-fc0c-652dc3b5c83e.png)

- LIFFアプリからはLINEのユーザIDを取得できるのでLINE IDとQiita IDの2つをLambdaに投げてDynamoに保存しています

### いいね数の断面取得

- QiitaのAPIの仕様上、前日に何いいねされたかを取得することはできません
- なので毎日0時に登録ユーザの全記事を取得し、いいね数を合計した値を保存しておきます
    - https://qiita.com/api/v2/users/ozaki25/items でユーザに紐づく記事情報を一発で取得できます
    - 一度に取れる記事は100件までなので超えた場合はページング処理が必要です
- Lambdaの定期実行はServerlessFrameworkからも指定可能で簡単にできました
    - https://serverless.com/framework/docs/providers/aws/events/schedule/

### 前日のいいね数をユーザに通知

- こちらもLambdaを毎日定期実行させています
- 当日0時の断面と前日0時の断面を引き算した値を前日のいいね数としています
    - 最近いろいろあってQiitaのユーザ削除がブームになっていて前日いいね数がマイナスになることも。。
- LINEのMessagingAPIを使ってユーザへLINEでメッセージを送信します
    - https://developers.line.biz/ja/docs/messaging-api/sending-messages/#%E3%83%97%E3%83%83%E3%82%B7%E3%83%A5%E3%83%A1%E3%83%83%E3%82%BB%E3%83%BC%E3%82%B8

## 感想

- LIFFを使うとWebアプリとして実装できるのでハードルがとても低く感じました
- いいね数の内訳などもっと追加したい機能がありますがLIFFアプリを拡張すればいいだけなのでその辺も扱いやすそうです
    - 通知はLINEで、詳細情報はLIFFでという使い分けが便利！
- バックエンドがサーバーレスなので課金の心配もそんなにないはずなので個人でお試しするにもやりやすい構成だなと感じました
LaravelのfactoryでInvalidArgumentException: Unable to locate factory with name [default] [hogehoge]. が出た

# はじめに

上記でググってきた、ありがちな 'hogehoge' の参照方法が間違っていたわけではなかった。

# 結論から書くと

`php artisan make:test hogeTest --unit` でUnitテストを生成したときに
`use PHPUnit\Framework\TestCase;` でUnitテストが作成されていたので
`use Tests\TestCase;` と書き直した

# 考察

「そもそも今までUnitテスト内でfactoryを使ってたのになぜ急に！」
と思い、今までのと比較してみたら上記が違いましたよ、と。
検証してはないけど、Laravelのバージョンを5系から6系に変えたのでそのタイミングで変わったのかもしれない。

~~また本来、 `use PHPUnit\Framework\TestCase;` でもfactoryを呼び出せるようにすることが正しい解決方法だとは思う。~~

https://qiita.com/kawagashira/items/30b6fbd7a865f4005a90
現状結論の解決方法で良かった。
しかし単体テストを名乗ってはいけなかった。

# 追記

https://laravel.com/docs/5.8/testing
https://laravel.com/docs/6.x/testing

を比較するとやはりバージョンアップが関わっているようだ。が。factory使えないのはなんでだろう？
Vue.jsでアコーディオン

n番煎じですが試行錯誤した結果を残しておきます。
いろんなやり方があると思いますが、個人的に一番しっくり来たやり方です。

## 結論

```vuejs
<template>
  <div class="a-accordion">
    <button @click="opened = !opened">
      Click
    </button>
    <transition
      @before-enter="beforeEnter"
      @enter="enter"
      @before-leave="beforeLeave"
      @leave="leave"
    >
      <div v-if="opened" class="a-accordion-inner">
        Accordion
      </div>
    </transition>
  </div>
</template>

<script>
export default {
  data() {
    return {
      opened: false
    }
  },

  methods: {
    beforeEnter(el) {
      el.style.height = '0'
    },

    enter(el) {
      el.style.height = el.scrollHeight + 'px'
    },

    beforeLeave(el) {
      el.style.height = el.scrollHeight + 'px'
    },

    leave(el) {
      el.style.height = '0'
    }
  }
}
</script>

<style scoped lang="scss">
.a-accordion {
  .a-accordion-inner {
    overflow: hidden; // 閉じるときに他要素に被らないように必須。
    transition: height 0.2s ease-in-out; // 高さの変更に対して連続的に変化させる。
  }
}
</style>
```

ポイントは

- 開閉する要素に `overflow`, `transition` を指定する。
- `transion` のフックで `height` を変更する。

の２つです！

![Kapture 2020-03-29 at 20.41.43.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165376/578708b5-ceca-5f33-e9b2-f63adb078a71.gif)


## 参考
https://jp.vuejs.org/v2/guide/transitions.html
https://developer.mozilla.org/ja/docs/Web/CSS/CSS_Transitions/Using_CSS_transitions
http://lab.astamuse.co.jp/entry/2018/10/15/154737
https://qiita.com/mimoe/items/7ad8d9ea9fc4299da6bc
Ubuntu にPostgreSQLインストールメモ

# 環境
```
$ cat /etc/os-release
NAME="Ubuntu"
VERSION="19.10 (Eoan Ermine)"
```

# インストールしたもの
```
$ pg_config | grep VERSION
VERSION = PostgreSQL 12.2 (Ubuntu 12.2-2.pgdg19.10+1)
```

# インストール
[公式](https://wiki.postgresql.org/wiki/Apt)を見ながらインストール

```超抜粋
$ sudo apt-get install curl ca-certificates gnupg
$ curl https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add-
$ sudo apt-get update
$ sudo apt-get install postgresql-11 pgadmin4
```

自分の環境は[クライアントアプリケーション](https://www.postgresql.jp/document/11/html/reference-client.html)が使えなかったので、以下もインストール。
`sudo apt-get install libpq-dev`

# PSQLでのロール、データベース作成

端末にて、psql起動。
`sudo -u postgres psql`

```psql.
create role ロール名 with createdb login password 'パスワード';
create database データベース名;
\l
\q
```
`\l`は、データベース一覧表示。
`\q`は、切断。

[psqlドキュメント](https://www.postgresql.jp/document/11/html/app-psql.html)
[CREATE ROLE](https://www.postgresql.jp/document/11/html/sql-createrole.html)
[SQLコマンド](https://www.postgresql.jp/document/11/html/sql-commands.html)

# PSQLコンソール上の注意
末尾「;」が必要で、入れてないとコンソールが改行されるだけで何も起こらない。
個人的詰まりポイント。

# 基本はpgAdminで
WebインタフェースがGUIで楽なので。
pgAdminはアプリケーションから選択して起動すれば対応するブラウザで画面が開かれる。
[TLA+] Euclid Writes an Algorithm: A Fairytale

読んでみると TLA+ Toolbox の使い方をはじめ色々と学べる文書でした。
デッドロックについてとか、証明を行おうとしたらどうなのかとか、一度読んでおくと良いように思います。

- 日本語対訳版 : [Euclid Writes an Algorithm: A Fairytale](https://drive.google.com/open?id=1TtYwya6Sy350wavp25KDjy1VMm14Nr5B) (PDF)

# 参考

- Microsoft Research : [英語版](https://www.microsoft.com/en-us/research/publication/euclid-writes-algorithm-fairytale/)
AuroraServerlessへcsv形式で一括データ挿入する

S3に置いたcsvファイルのデータをAuroraServerlessにdataAPIを介して挿入するlambda。

```python
import json
import csv
import boto3
import os

rdsData = boto3.client('rds-data')
s3 = boto3.resource('s3')
bucket = s3.Bucket('バケット名')
tableName = "テーブル名"
clusterArn = 'クラスターARN'
secretArn = 'シークレットARN'

def lambda_handler(event, context):

    # S3からファイル取得
    bucket.download_file('S3上のファイル名.csv', '/tmp/保存時のファイル名.csv')
    
    # 最終的にAuroraServerlessに投げるSQL文
    allSqlstr = ""

    # csv → json変換
    with open('/tmp/names.csv') as csvfile:
        reader = csv.DictReader(csvfile, quotechar="'") #デフォルトだとダブルクオート

        for row in reader:
            # 辞書の全てのvalueを取得し、SQL文を組み立て
            sqlstr = "INSERT INTO " + tableName + " VALUES ( "
            for val in row.values():
                sqlstr += "'" + str(val) + "',"
            allSqlstr += sqlstr[:-1] + " );"
            
        print("requestSQL:", allSqlstr)
            
    # AuroraServerless更新
    res = rdsData.execute_statement(
            resourceArn = clusterArn,
            secretArn = secretArn,
            database = 'DB名', 
            sql = allSqlstr)
    print (res)
    return 0
```
【Windows10】出来るだけ被害を小さくしてユーザフォルダ名を任意の文字列に変更する

#はじめに
Windowsは~~勝手に~~ユーザフォルダ名をユーザ名で命名するので,ユーザ名にマルチバイト文字を入れると,
悲惨なことになります。(ユーザフォルダ以下での作業でpathにマルチバイト文字が入るので)
私もここで苦しみました。
ちなみにあとからユーザ名を変えてもユーザフォルダ名は変わりません。(それはそう)
出来るだけ被害を小さくして～とタイトルに書きました。もう少し具体的に書きます。
被害が出るのは,クイックアクセスまわりだけです(おそらく)。必要なものは管理者権限と10分くらいの時間です。
#手順
1. ローカルアカウントでのサインインに切り替えます。
2. コマンドプロンプトやwindows power shellなどのターミナルを管理者権限で開き,以下のコマンドを実行します。

```
net user administrator /active:yes
```
これで,Administratorアカウントが有効になりました。
3. サインアウトしてPCを再起動し,Administratorアカウントでログインします。
4. ユーザフォルダを任意の文字列にリネームします。「他のプログラムが~」と言われた場合はwindows searchが邪魔しているので,タスクマネージャーで落とすなどしましょう。
5. windowsキー+Rキーで```regedit```を入力するなどしてレジストリエディタを起動します。
6. ```\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\```のいくつかのレジストリにユーザフォルダのpathが書かれているので全部新しいものに書き換えます。
7. サインアウトしてPCを再起動し,元のアカウントでログインします。
8. コマンドプロンプトやwindows power shellなどのターミナルを管理者権限で開き,以下のコマンドを実行します。

```
net user administrator /active:no
```
これで,Administratorアカウントが無効になりました。
9. 環境変数の設定を開き,ユーザフォルダのpathが書かれている箇所をすべて新しいものに書き換えます。
<br>
これで,ユーザフォルダ名を任意の文字列に変更することができました。
#おわりに
ユーザフォルダ名,最初に決めさせて欲しくないですか?
【Unity】gRPCを用いたプロジェクトをiOS向けにビルドした時のlinker command failed with exit code 1 エラーの対処法

# はじめに

gRPCを用いてUnityで作成したプロジェクトをiOS向けにビルドすると、お馴染みの

```
linker command failed with exit code 1 (use -v to see invocation)
```

というエラーと共に、

```
**/Libraries/Plugins/Grpc.Core/runtimes/ios/libgrpc_csharp_ext.a(grpc_csharp_ext.o)' does not contain bitcode. You must rebuild it with bitcode enabled (Xcode setting ENABLE_BITCODE), obtain an updated library from the vendor, or disable bitcode for this target. for architecture arm64
```

のようなエラーがXcodeで出ることがあります。

このエラーを解決する方法をこの記事に書きました。参考になれば幸いです。

# 実行環境

- Unity v2019.3.6f1
- macOS Catalina v10.15.4
- gPRC(C#) v2.29.0
- Xcode v11.4

# 対処法

以下が対処法になります。
手順が全部で4つあるので、手順1から順に指示に従っていただければと思います。

## 手順1

Assetsフォルダ直下に**Editor**という名前のフォルダを作成します。

もう既にある場合は作成する必要はありません。そのまま手順2へ進んでください。

## 手順2

次のスクリプトを作成し、UnityのEditorフォルダ内に置きます。

```BuildHelper.cs
#if UNITY_IPHONE

using System.IO;
using UnityEditor;
using UnityEditor.Callbacks;
using UnityEditor.iOS.Xcode;

public class BuildHelper
{
    [PostProcessBuildAttribute(1)]
    public static void OnPostProcessBuild(BuildTarget target, string path)
    {
        if (target == BuildTarget.iOS)
        {
            var projectPath = PBXProject.GetPBXProjectPath(path);
            var project = new PBXProject();
            project.ReadFromString(File.ReadAllText(projectPath));
            var targetGUID = project.GetUnityFrameworkTargetGuid();

            project.AddFrameworkToProject(targetGUID, "libz.tbd", false);

            project.SetBuildProperty(targetGUID, "ENABLE_BITCODE", "NO");

            File.WriteAllText(projectPath, project.WriteToString());
        }
    }
}

#endif
```

(参考: [Unity2018.2 + il2cppでgRPCアプリをAndroid/iOS向けにビルドする](https://qiita.com/shiena/items/6c3b34a8d8f1bb938470))

## 手順3

ターミナルで

```
sudo rm -rf ~/Library/Developer/Xcode/DerivedData/*
```

を実行し、DerivedData (プロジェクトに生成されるキャッシュデータ)を削除します。

## 手順4

Unityで**Build And Run**を行い、ビルドを実行します。

---

以上です。
これでビルドが上手くいくのではないかと思います。



# 参考

- [【Unity】Xcodeでビルドするときに「linker command failed with exit code 1 」エラーが出たときの対処法｜Unishar-ユニシャー](https://miyagame.net/linker-command-failed-with-exit-code-1/)
- [[Xcode] "linker command failed with exit code 1" エラー対処方法 / lileaLab](https://lilea.net/lab/linker-command-failed-with-exit-code-1-2/)
- [Xcodeで「linker command failed with exit code 1」が発生した時はDerivedDataを消してみよう - Qiita](https://qiita.com/bunty/items/f670e4e8b43737f1aee2)
- [オデの日記＠WEB系: linker command failed with exit code 1が出た時の解決方法案](http://koexuka.blogspot.com/2017/08/linker-command-failed-with-exit-code-1.html)
- [Unity2018.2 + il2cppでgRPCアプリをAndroid/iOS向けにビルドする](https://qiita.com/shiena/items/6c3b34a8d8f1bb938470)
- [UnityでgRPCアプリ(iOS, Android)をビルドできるようになった - Qiita](https://qiita.com/muroon/items/2115c2c72be8b0c3f5f6)
- [Unity C#: Xcode reports libgrpc_csharp_ext.a does not contain bitcode · Issue #16839 · grpc/grpc · GitHub](https://github.com/grpc/grpc/issues/16839)
JavaScript 画像ファイルを読み込んでcanvasに表示する

##前書き
　自作WEBアプリで躓いたので思い出せるようにメモ。とりあえず機能のみを実装

##環境
　ブラウザ：Google Chrome
　言語：JavaScript(ライブラリ、フレームワークの使用なし)

##HTML
設定すること
・画像を読み込むボタン
・画像を表示するcanvas
・CSSとJavaScriptは個人的に分けたいので分けています

```index.html
<DOCTYPE HTML5>
<html>
 <head>
  <!--CSSファイルの読み込み-->
  <link rel="stylesheet" type="text/css" href="./index.css">
 </head>
 <body>
  <!--ファイルの読み込み　拡張子をPNG, JPEGに設定-->
  <input type="file" id="selectFile" accept=".png,.jpeg">

  <!--canvasの描画-->
  <canvas id="canvas"><canvas>

  <!--.jsファイルの読み込み-->
  <script type="text/javascript" src="index.js"></script>
 </body>
</html>

```

##CSS

```index.css


canvas{
  width: 300px;
  height: 400px;
  border: solid 1px #000;
}


```

この時点での表示内容はこのような形
![スクリーンショット 2020-03-29 19.36.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/381909/81c54e82-d602-b12e-8c01-c301e9d813a6.png)

##JavaScriptで実装
実装する機能
・input type="file"のファイルの取得
・ファイルのURLの取得
・canvasのsrcにファイルのURLを設定

```index.js
var selFile = document.getElementById('selectFile'); // input type="file"の要素取得
var c = document.getElementById('canvas'); // canvasの要素取得
var ctx = c.getContext('2d');

selFile.addEventListener("change", function(evt){
 var file = evt.target.files; // fileの取得
 var reader = new FileReader();

 reader.readAsDataURL(file[0]); // fileの要素をdataURL形式で読み込む

 // ファイルを読み込んだ時に実行する
 reader.onload = function(){
  var dataUrl = reader.result; // 読み込んだファイルURL
  var img = new Image(); // 画像
  
  img.src = dataUrl;
  
  // 画像が読み込んだ時に実行する
　img.onload = function() {
   // canvasに画像ソースを設定する
   ctx.drawImage(img, 0, 0);

   // 画像のサイズを設定する場合
   // ctx.drawImage(img, 0, 0, 300, 400); heightとwidthも合わせて設定可能
   }
  }
}, false);

```
##実装結果
ファイルを選択するとcanvasに画像が表示されるようになる

![スクリーンショット 2020-03-29 20.00.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/381909/f36a2c47-793d-9087-76fe-98c33970b134.png)



##参考
・画像ファイルの読み込み(https://javascript.programmer-reference.com/js-canvas-draw/)
・画像をcanvasに表示する(https://www.pazru.net/html5/File/040.html)
AWS Lambda で Javaを使う ー実装編Tips - ReagionとInstanceIDからInstance名を取得する

##AWS Lambda で Javaを使う　目次
・[Eclipse準備編](https://qiita.com/t_ookubo/items/a71a9bd05282bf20e023)
・登録実行編（いつか）
・[実装編 - EC2を止める/立ち上げる](https://qiita.com/t_ookubo/items/3b12bd985a65a73b4c59)
・[実装編 - CloudWatchの引数を確認する](https://qiita.com/t_ookubo/items/18d47265d39bba4364b8)
・[実装編Tips - ReagionとInstanceIDからInstance名を取得する](https://qiita.com/t_ookubo/items/619d8029546447e61391)

### ReagionとInstanceIDからInstance名を取得する

引数にReagionコードとInstanceIDを渡すと、Instance名を返してあげる。
また、二回目以降、同じReagionコードを渡した場合、Mapに格納している値を返却する。

```java
// <reagion id <<incetance id, incetance key name>>
Map<String, Map<String, String>> resolveInstance = new HashMap<>();

private String getEC2InstanceKeyName(String targetReagion, String targetInstanceId) {
	if (!resolveInstance.containsKey(targetReagion)) {
		// <incetance id, incetance key name>
		Map<String, String> incetanceMap = new HashMap<>();
		// Instance Id と Instance名を取得 (こんな大層なことしなくても取れそうな気もする。。でも、純正のEC2MetadataUtilsでは取れなさそうだった。)
		AmazonEC2 ec2 = AmazonEC2ClientBuilder.standard().withRegion(targetReagion).build();
		DescribeInstancesResult ec2Info = ec2.describeInstances();
		for(Reservation res : ec2Info.getReservations()) {
			for(Instance ins : res.getInstances()) {
				incetanceMap.put(ins.getInstanceId(), ins.getKeyName());
			}
		}
		resolveInstance.put(targetReagion, incetanceMap);
	}
	return resolveInstance.get(targetReagion).get(targetInstanceId);
}
```
Edit ini 作った話

# Edit ini

これは,作者(私)が Python でプログラミングしているとき, ConfigParser を使った ".ini"ファイル の読み取りや書き込みが
**いろいろと めんどくせぇーー**
と思ったので,作りました!

"Edit ini" と "ConfigParser" は部分的に(?)互換性を持っていて,同じ ".ini"ファイル の書き込み,読み取り,削除ができます.

その他,このプログラムに関しての情報は[こちら](http://penguin0093.html.xdomain.jp/page/project/python/editini.html)に掲載します.

##使い方

基本的には下のような構造になっています.

```text:config.ini
[section]
option = value
```
※iniファイルの形式は上とします

```Python:test.py
iniio.iopen("File name","Open mode","section","option","value")
```

引数1 : ファイル名
引数2 : モード (書き込み : "w" , 読み取り : "r" , 削除 : "d")
引数3 : セクション名 ([]部)
引数4 : オプション名 ("="の左側)
引数5 : 値 ("="の右側)

###0.Install
```
pip install editini
```

###1.Import

```Python:test.py
from editini import iniio
```


###2.書き込み

**実行例1**

```Python:write1.py
iniio.iopen("config.ini","w","section","option","value")
```

```text:config1.ini
[section]
option = value
```

**実行例2**

```Python:write2.py
iniio.iopen("config.ini","w","section","option")
```

```text:config2.ini
[section]
option = 
```

value部 ("="の右側) が指定されなかった場合,空文字 ("") が代入されます.

**実行例3**

```Python:write3.py
iniio.iopen("config.ini","w","section")
```

```text:config3.ini
[section]
```

section のみを指定した場合, []部 のみが生成されます.


###3.読み取り

```Python:read.py
iniio.iopen(" .ini","r","section","option")
```

戻り値に読み取り結果が代入されるので, "print" 等で受け取ることが可能です.

```text:config.ini
[section]
option = value
```

```Python:read.py
print(iniio.iopen("config.ini","r","section","option")+"\n")
print(iniio.iopen("config.ini","r","section")+"\n")
print(iniio.iopen("config.ini","r")+"\n")
```
上のように第3,第4引数の指定によって,読み取られる範囲が変わります.

```text:PythonIDLE
value

option = value

[section]
option = value
```


###4.削除

```Python:delete.py
iniio.iopen(" .ini","d","section","option")
```

第3,第4,第5引数の指定によって,削除される範囲が変わります.

実行例では,このファイルについて削除を行います.

```text:config.ini
[section]
option = value
```

**実行例1**

```Python:write1.py
iniio.iopen("config.ini","d","section","option","value")
```

```text:config1.ini
[section]
option = 
```

**実行例2**

```Python:write2.py
iniio.iopen("config.ini","d","section","option")
```

```text:config2.ini
[section]
```


**実行例3**

```Python:write3.py
iniio.iopen("config.ini","d","section")
```

```text:config3.ini
```


**License**
Copyright (c) 2020 Penguin0093
Released under the MIT license
https://opensource.org/licenses/mit-license.php
AWS Lambda で Javaを使う ー実装編 - CloudWatchの引数を確認する

##やりたいこと
Lambdaで実行するJavaで、CloudWatchに登録してある引数を取得する。

###背景・経緯
前回の記事で作成したEC2の起動停止するLambdaファンクションを、
CloudWatchEventsのCronで、8時、9時、17時、18時など複数の時間帯で起動するようにしていた。
が、どのインスタンスをどの時間に起動するようにしたか忘れてしまい、
いちいちCloudWatchEventsに登録した引数を確認しなければならなかった。
面倒だったので、引数を取得するファンクションを作成した。
（メモを取ると、登録している引数とメモを同期させないといけないので、避けたかった。）


##AWS Lambda で Javaを使う　目次
・[Eclipse準備編](https://qiita.com/t_ookubo/items/a71a9bd05282bf20e023)
・登録実行編（いつか）
・[実装編 - EC2を止める/立ち上げる](https://qiita.com/t_ookubo/items/3b12bd985a65a73b4c59)
・[実装編 - CloudWatchの引数を確認する](https://qiita.com/t_ookubo/items/18d47265d39bba4364b8)
・[実装編Tips - ReagionとInstanceIDからInstance名を取得する](https://qiita.com/t_ookubo/items/619d8029546447e61391)


## とりあえずクラス作成
[前回と同じ](https://qiita.com/t_ookubo/items/3b12bd985a65a73b4c59#%E3%81%A8%E3%82%8A%E3%81%82%E3%81%88%E3%81%9A%E3%82%AF%E3%83%A9%E3%82%B9%E4%BD%9C%E6%88%90)

## CloudWatchEventsをごにょごにょする

###CloudWatchEventsオブジェクトを作成する

```java
// CloudWatchEventsオブジェクトを作成
AmazonCloudWatchEvents event = AmazonCloudWatchEventsClientBuilder.defaultClient();
```

###CloudWatchEventsのルールを取得する

```java
ListRulesResult retRule = event.listRules(new ListRulesRequest());
for(Rule rule : retRule.getRules()) {
    // rule.getName()、rule.getDescription()
}
```
コンソールでいうところのこの部分
メソッド名通り、ルールの名前と説明を取得できる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/559813/f2055980-b6bb-bdb2-22b7-6d64373bef5a.png)

###CloudWatchEventsのルールからターゲットを取得する
```java
// get target information from rule
ListTargetsByRuleRequest req = new ListTargetsByRuleRequest().withRule(rule.getName());
ListTargetsByRuleResult retTarget = event.listTargetsByRule(req);
List<Target> cloudWatchTargets = retTarget.getTargets();

for (Target target : cloudWatchTargets) {
    //  do loop each cloud watch rule's target
}
```
コンソールでいうところのこの部分
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/559813/b6cdd2c7-ebe9-4318-84c4-b27e7236c68a.png)


###CloudWatchEventsのルールからターゲットの中からファンクション名で絞り込む

```java
target.getArn()
```
これで、各ターゲットが下記のような形で返却される
arn:aws:lambda:region:xxxxxx:function:functionName

なので、endWithで絞り込む

```java
if (target.getArn().endsWith("絞り込みたいファンクション名")) {
    // 
}
```
コンソールでいうところのこの部分（このコンソール画面の場合だとそもそも一つしかないので、やってもやらなくてもどちらでもいいのだけども。）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/559813/0aa66f33-b5ce-8d0c-ad66-649cc1a41207.png)


###CloudWatchEventsのルールからターゲットの中から引数(入力)を取得する
```java
target.getInput()
```
コンソールでいうところのこの部分
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/559813/eba5bab3-9635-1f77-557a-546742d12150.png)

```java
// cloudWatch のInputをjsonで記載しているので jsonからbeanに変換
SomethingBean cloudWatchInput = Jackson.fromJsonString(target.getInput(), SomethingBean.class);
```

あとは、今まで取得したCloudWatchEventsのルール名、説明、引数など出力したい形に整形して、outputに返してあげれば終了。

### 今回追加したPOM
```
<dependency>
	<groupId>com.amazonaws</groupId>
	<artifactId>aws-java-sdk-cloudwatch</artifactId>
	<version>1.11.99</version>
	<scope>compile</scope>
</dependency>
<dependency>
	<groupId>com.amazonaws</groupId>
	<artifactId>aws-java-sdk-events</artifactId>
	<version>1.11.719</version>
	<scope>compile</scope>
</dependency>
```
Catalinaのバージョンアップしたらrails sできなくなったけど、Node.jsのインストールで解決！

####筆者の環境
macOS Catalina バージョン 10.15.4
使用言語：Ruby、JavaScript


## エラー内容

不注意により、macOSが**Catalina バージョン10.15.4**に上がってしまった。

それから実装中のアプリでrails sすると、以下のエラーメッセージが表示されサーバーが起動しなくなった。

<font color="Red">Could not find a JavaScript runtime. See https://github.com/rails/execjs for a list of available runtimes. (ExecJS::RuntimeUnavailable)</font>

##これで解決！
[Node.js](https://nodejs.org/en/)をインストール

左側の12.16.1の方はインストールしても開けず、
右側（最新版）をインストールしたらrails s成功しました！

<img width="831" alt="スクリーンショット 2020-03-29 19.12.24.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/514095/060e6d00-3fb3-a58b-05c0-50790a6b96e5.png">

## 番外編

他にも対処法はいくつかあり、**therubyracer**というGemのインストールでも解決できるようです。（参考リンクご参照ください）

現在、チーム開発中だったので、自分以外の複数端末への影響を考え今回はGem以外の方法を選択しました。

##参考
にさせていただきました。ありがとうございます。
https://qiita.com/azusanakano/items/771dc9919f347de061d7
Folding@HomeにPCを参加させてコロナ分析に貢献しよう!

# Folding@Homeとは
この記事を参照ください
[今からでも3分ではじめられるコロナ解析貢献「Folding@home」の使い方](https://pc.watch.impress.co.jp/docs/news/1243458.html)

この記事ではUbuntu 18 Desktop CPUマシンでのFolding@Homeへの参加方法を紹介します。

Windowsだと[Folding@Home Setup](https://qiita.com/Tayu0404/items/97fee464c58080b6c682)が参考になるかと思います。
dockerも使えるみたいで、上記の記事で解説されています。
GPUマシンの場合は[Folding@homeをubuntu+GPUで動かす](https://qiita.com/yoshiki9636/items/a8fa49b9d785d7b24642)が参考になると思います

# ubuntu 18.04　での参加方法

[https://foldingathome.org/start-folding/](https://foldingathome.org/start-folding/)にブラウザでアクセスします。
![Screenshot from 2020-03-29 19-08-01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/304012/e1cbb5d8-c441-2513-0cbd-b8946ac9c72c.png)
赤で囲ってある「fahclient_7.5.1_amd64.deb」をクリックします
![Screenshot from 2020-03-29 19-09-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/304012/fa29d79c-41bc-ba3e-9066-0ef06addb9a3.png)

OKをクリックします。すると次のような画面が出てきます

![Screenshot from 2020-03-29 19-09-05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/304012/fe81883b-2c59-8280-b505-a56a710ec9a9.png)

インストールをクリックします

![Screenshot from 2020-03-29 19-12-13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/304012/68e390a8-0c28-1400-a377-cc0cbff322c3.png)

このようなポップアップが出てきます。
そのままにして右上にある「Next」で進むこともできます。
マシンの全リソースを使っていい場合は4項目目の「Medium」をFullに変えます。（私はFullにしました）

作業自体は完了です。このあと再起動すると解析が始まります。

[https://client.foldingathome.org/](https://client.foldingathome.org/)にアクセスすると自分のPCでの解析状況が見れます

![Screenshot from 2020-03-29 19-26-10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/304012/89fff6db-b650-d9a0-1b00-fec33f3f6603.png)

右下に

```
I'm contributing to Project 13863

This is a SARS2-nCoV-2 protein. 
...
```
とあり、たしかに新型コロナの解析に参加しているようです

![Screenshot from 2020-03-29 19-31-10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/304012/a498cd5b-970a-59a7-b203-663c2bf0fb75.png)

CPU使用率も100%になっています。（私はFullを選択したので１００％ですが、mediumだと作業に困らない程度になってると思います。）

以上です。

遊休PCをお持ちの方は是非Folding@Homeに参加しましょう！
1からAlexaスキル開発入門してみる！第二幕　〜スキル仕組み＆構造編〜

今回はAlexaスキルの仕組みとその構造を解説します。

基本的に、この情報はAlexaスキル開発公式チュートリアルを元にしています。
https://developer.amazon.com/ja-JP/alexa/alexa-skills-kit/courses/cake-walk

#Alexaスキルの動作環境

Alexaスキルは、AmazonEchoなどの音声専用デバイスはもちろんですが、Amazon Echo、Echo Dot、Fire TV Cubeなどの多くのAlexa搭載デバイスで動作します。

スマホでも利用可能です！

2020/03/29現在、日本ではまだ販売されていませんが、車用のAlexa Autoというデバイスも今後対応予定です。

また、Alexa対応デバイスを一切持っていなくても開発環境上でAlexaスキルをテストすることは可能です。

#Alexaスキルの仕組み

まずは、以下の図を見てください。

<img width="1179" alt="Screen Shot 2020-03-29 at 19.33.18.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/586494/3db17a4a-a4df-660a-f4bb-43478adc8a82.png">
引用：https://developer.amazon.com/ja-JP/alexa/alexa-skills-kit/courses/cake-walk-1

##動作の流れ

① 利用者が「Alexa」と言う
② スマートスピーカーが「聞き取り状態」になる
③ 利用者が命令を音声で言う
④ その音声が「Speech Recognition」でJSON形式の文字データに変換される
⑤ JSON形式のデータが「Lambda Function」に送られる
⑥ 「Lambda Function」で処理され応答がJSON形式で帰ってくる
⑦ JSON形式のデータが「Text to Speech」で音声になる
⑧ その音声がスマートスピーカーに送られ音声が再生される

複数の仕組みがあるため難しそうに感じるかも知れませんが、実際はそこまで難しくありません。

音声がJSON形式のデータに変換されるところなどの部分は私たちは一切行う必要がありません。

私たちが開発するのは、「Lambda Function」だけです。
AtCoder 生活　10日目

[前回](https://qiita.com/flandrescarlet237/items/4cd62fa0f0e4778bd29e)

#10日目

今日は、ABC059からABC061のB問題を解きました。

##ABC059_B

[Comparison]
(https://atcoder.jp/contests/abc059/tasks/abc059_b)

```c++

#include <bits/stdc++.h>
using namespace std;
int main(){
	string A,B;
  	cin >> A; 
    cin >> B;
  	int res = false;
  	if(A.size()>B.size())cout << "GREATER" << endl;
  	else if(A.size()==B.size()){
  		for(int i = 0;i<A.size();i++){
          	if(A[i] > B[i]){
            	cout << "GREATER" << endl;
               	res = false;
                break;
            }
          	if(A[i] < B[i]){
            	cout << "LESS" << endl;
              	res = false;
                break;
            }
          	if(A[i] == B[i])res = true;            
        }
    }
  	else if(A.size()<B.size())cout << "LESS" << endl;
  	if(res) cout << "EQUAL" << endl;
}


```

intだと読み込めねえ

##ABC060_B


[Choose Integers]
(https://atcoder.jp/contests/abc060/tasks/abc060_b)


```c++

#include <bits/stdc++.h>
using namespace std;
int main(){
	int A,B,C;
  	cin >> A >> B >> C;
  	bool ans = false;
  	for(int i =1;i <B;i++){
    	if(i*A%B == C)ans = true;
    }
  	if(ans)cout << "YES" << endl;
  	else cout << "NO" <<endl;
}

```

これ解き方見たらすごく簡単だったので解けなくて悔しい。

##ABC061_B

[Counting Roads]
(https://atcoder.jp/contests/abc061/tasks/abc061_b)


```c++

#include <bits/stdc++.h>
using namespace std;
 
int main(){
    int N,M;
    cin >> N >> M;
    int a[M],b[M];
    int wol[N];
  	for(int i=0;i<N;i++)wol[i] = 0;
  	for(int i=0;i<M;i++){
      	cin >> a[i] >> b[i];
      	wol[a[i]-1]++;
      	wol[b[i]-1]++;
    }
  	for(int i=0;i<N;i++)cout << wol[i] <<endl;
}

```

問題を読んでもしばらく意味がわからなかった
書評：チーム・ジャーニー

# はじめに
「チーム・ジャーニー」を読みました。
<img src="https://images-fe.ssl-images-amazon.com/images/I/51mtpZhZVpL._SY346_.jpg" witdh="50%" />

「カイゼン・ジャーニー」の続編として期待して読みました!
が...個人的な体感としては3ヶ月前に読んだ「チーム・ジャーニー」の方が感動が大きかったです。

と書きましたが、これは作品の出来云々ではなく、
単純に読んでいる自分の視座がまだ書籍の内容に追いついていないためです。
開発チームに焦点を当てた「チーム・ジャーニー」から
新たなプラクティスと共に会社や事業という次の視座を入れた
「チーム・ジャーニー」は今の自分にとってまさに良書でした。

# 第1部 僕らが開発チームになるまで - 1チームのジャーニー

印象に残ったワード、プラクティス

- チームとプロダクトの違い(01話)
- チームもプロダクトのように成長する(01話)
- ファーストの選択(02話)
- 出発のための3つの問い(02話)
- 段階の設計(03話)
- PDCAとOODA(04話)
- 他のチームとDIFFをとる(05話)
- 仮説キャンバス(07話) 

OODAってあまり聞いたことなかったんですが、仮説を進めるスピードにすごく優れてそう..
観察(Observe)自体が1on1などでも注目されるワードなので、今後流行するかなぁ..
そういう意味だと、同じ事象から何を読み取るかみたいな力は今後重宝されるのかなぁ。
もちろん、気づいたことを相手に伝えて相手の行動に影響を与えないといけないから
観察だけでは足りないのだろうけど..

# 第2部 僕らがプロダクトチームになるまで - 複数チームによるジャーニー

印象に残ったワード、プラクティス

- 情報流通のための境界を設計する(09話)
- Why寄りの情報は広めに、How寄りの情報は狭く(09話)
- リードという役割(10話)
- 番頭の輪番化(11話)
- 状況特化型チーム(12話)
- ユーザー行動フロー(13話)
- チームが異なれば、同じ会社であっても会社の外の現場と対して変わらない(14話)
- 標準化ではなく共同化(14話)
- 視座と視野で決まる視点(15話)
- ともに考え、ともにつくる(16話)

標準化より共同化っていいフレーズだな..と思いました。

自分が持っている管理職業務の定型的（だと思う）作業をメンバーに引き継ごうと考えていましたが、
それ自体は定型化できるほどのインパクトしかなくて、むしろ定型化出来ない作業が重要な場合が多いです。

それを頑張って定型化するのでもなく、諦めるのでもなく、
共同化することで伝えたい人によく伝わるならそれが一番いいなと気づくことが出来ました。

あとは、
ともに考え、ともにつくる(16話)という部分を読んでいたら、
ハイキューの狂犬思い出しました(ニッチですが..)

> チームっつうのは頼もしく、時に煩わしく、力強い味方であり重圧だ

ハイキュー面白いですよね！個人的に白鳥沢のスタイルが好きなので、
メンバーが強強で好き勝手やってもプロダクトいいの出来ちゃうとか見てみたい気もします..

# まとめ

感想文を書くために全体を読み直すとそれだけでも情報が整理されました。
「カイゼン・ジャーニー」はアジャイルなチームであるために中心にスクラムがある印象でしたが、
「チーム・ジャーニー」は一歩進んでチームが何のためにどうするべきかを考えて
行動するという点で幅広く正解に近く、そして実践は数段難しい印象を受けました。
（アジャイル開発に対しての守破離でいうと、離なんだろうなぁと）

と言っても、前作から重要なコンセプトである「越境」は変わらず、
前作以上に正解の道筋がないのが今作の特徴であり現代社会の難しさのように感じました。

プラクティスの部分部分の実践から始めて、
次にまた読む気持ちが出来た時に新しい感想が得られるよう頑張ります。
qiitaユーザーでなくても「コードを利用は自己責任であり検証する必要性」

qiitaの規約を読むとqiitaは責任回避のために文章を乗っけているらしい。


>第10条(投稿内容の権利帰属)
(1)ユーザーは、自身が投稿した投稿内容に記録されている内容に関する一切の特許権、商標権、企業秘密、著作権若しくはその他の財産権および個人情報を含むプライバシー権、肖像権などの諸権利について保有するか、または、当社をして本項第3号に定められる投稿内容の利用をさせるのに必要なライセンス、権利、同意及び許可を有していることを保証するものとします。万一、第三者との間で何らかの紛争が発生した場合には、ユーザーの費用と責任において問題を解決するとともに、当社に何等の迷惑または損害を与えないものとします。

「万一、第三者との間で何らかの紛争が発生した場合には、ユーザーの費用と責任において問題を解決するとともに、当社に何等の迷惑または損害を与えないものとします。」

> 第19条(保証の否認)
ユーザーは、ユーザー自身の責任において本サービスを利用するものとし、ユーザーは、本サービスの機能の利用に起因又は関連してユーザーのコンピューター等の通信機器及びデータに発生した損害について自ら責任を負うものとし、当社は、一切責任を負わないものとします。

「ユーザーのコンピューター等の通信機器及びデータに発生した損害について自ら責任を負う」

プログラムをコピー、あるいは記事を読んで採用してトラブルになった場合、quiitaユーザーと採用者で裁判になる可能性がある。
責任回避や嫌がらせではなくユーザーから金をむしり取るため為、スラップ訴訟の場合もある。

qiitaユーザーが記事を書いて教えたら損する。
qiitaユーザーが挑戦して成功失敗やエラーの記事を書いて損する。

なんだそれ？

qiitaサイトを使って技術論以外で人と喧嘩する。（エンジニアでそんな人いるか？）
qiitaサイトのプログラムを使って仕事にコード使うなら検証しない。（エンジニアでそんな人いるか？）

qiitaユーザーであろうとなかろうと「コードを利用する人は自己責任で使い、検証しろ」こっちを明記するほうがエンジニアにとって教育されるべき大事なこと。

つまり上の文章はいらない。

以上
XAMPPのphpmyadminにアクセスした時、HY000/2002が出てアクセス拒否された場合の対処

# 起こったこと
xmappでApacheとMySQLを起動してさてphpmyadmin/index.htmlにアクセスすると
以下みたいなエラーが出てログイン画面すら出ない状態になっていました。
今回行った対応を順に書いていきます。
※この記事ではrootユーザでのログインを行っているが実際の運用ではrootユーザではなく別のユーザを別途定義した方が無難。

![えらー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563268/136443c9-67de-f221-7b1b-9ba64b6cd9d4.png)

# ログイン画面を出す

デフォルトでxmappをインストールした場合、C:\xampp\phpMyAdmin\配下にconfig.inc.phpが置いてあります。
今回はその中の一部を編集する。config.inc.phpを開き、以下の項目があることを確認してください。
何も編集していない状態であればおそらく下記のような状態になっているかと思われます。(これとは違う場合もあるかもしれない)

```config.inc.php
/* Authentication type and info */
$cfg['Servers'][$i]['auth_type'] = 'config';
$cfg['Servers'][$i]['user'] = 'root';
$cfg['Servers'][$i]['password'] = '';
$cfg['Servers'][$i]['extension'] = 'mysqli';
$cfg['Servers'][$i]['AllowNoPassword'] = true;
$cfg['Lang'] = '';

/* Bind to the localhost ipv4 address and tcp */
$cfg['Servers'][$i]['host'] = '127.0.0.1';
$cfg['Servers'][$i]['connect_type'] = 'tcp';

/* User for advanced features */
$cfg['Servers'][$i]['controluser'] = 'pma';
$cfg['Servers'][$i]['controlpass'] = '';
```

`$cfg['Servers'][$i]['auth_type']`は認証モードの設定でデフォルトではconfigとなっています。これをcookieと変更してください。これによって有効なMySQLユーザーをログイン画面で入力すればログインできるはずです。ついでに`$cfg['Servers'][$i]['user'] = 'root';`はcookieでは不要なので空文字にしてください。

```config.inc.php(一部)
$cfg['Servers'][$i]['auth_type'] = 'cookie';
$cfg['Servers'][$i]['user'] = '';
$cfg['Servers'][$i]['password'] = '';
```

# (HY000/2002): 対象のコンピューターによって拒否されたため、接続できませんでした。の対処

前述の設定をしたconfig.inc.phpを保存し、phpmyadminのページをリロードするとログイン画面が表示されるかと思います。
あらかじめ設定したrootユーザでログイン……、がっダメ！

![えらー２.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563268/064e9ad4-1552-5661-58b0-b5767fd70f79.png)

ここで小一時間詰まってしまいました。原因はおそらくhostの項目でローカルのipアドレス127.0.0.1になっているからかなと思いlocalhostに変更したりしましたが一向に解決せず。
そんな時下記の質問記事を発見しました。
[xampp phpmyadmin access denied error(#2002)](https://stackoverflow.com/questions/22971248/xampp-phpmyadmin-access-denied-error2002)
どうやら、localhost:**MySQLのポート番号(デフォルトでは3306?)**
と記載しないといけなかったみたいです。つまり下記のように直すということですね。
※筆者のMySqlのポート番号は3306です。自分の環境に合わせたポート番号に変更してください。

```config.inc.php(一部)
/* Bind to the localhost ipv4 address and tcp */
$cfg['Servers'][$i]['host'] = 'localhost:3306';
```

config.inc.phpを保存し、IDとパスを入力してログイン…。成功！
![ログイン.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563268/0ac714bd-64a5-c2d5-3d56-dc7461f78985.png)

# 所感
ポート番号込みで定義しないといけないというのは盲点でしたが当たり前ですね…。
とりあえずphpmyadmiにはアクセスできたので、この後は別途ユーザを作成し、
rootユーザのアクセスを制限しておく必要があるかと思います。
振り返れば簡単なことなのですがこれ調べるだけで半日終わっちゃって本来の勉強が進まない…。
[Unity]移動してる時に砂煙風エフェクトを付けてみよう

#砂煙風エフェクトを作ろう
![](https://i.gyazo.com/3a106574528de9c2533052f97d3baeca.gif)


#プレイヤーに子オブジェクトをつけよう
![player.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394850/d58d7ec4-2266-721e-bf83-dff710b4fa13.jpeg)
プレイヤーのオブジェクトを選択して**Sphere**を付けよう。
>Sphereオブジェクトの出し方は
**Hierachy**>**Create**>**3DObjeckt**>**Sphere**

#ParticleSystemを使ってエフェクトを作ろう
![]
(https://i.gyazo.com/2982b76aa069f604d8aa7adf99146681.gif)
上のgif画像のようにParticleSystemを出します。

![setting3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394850/48686f96-e2cc-5799-9087-73a478eee49c.png)

赤い枠線で囲った部分を編集していきます。
**Start Speed**は、パーティクルが飛び出す速度の設定です。ここを速くすると見た目が悪くなります。
**Start Size**は、パーティクルの最初のサイズを設定しています。
**Start Rotation**は、パーティクルの角度を設定しています。
>**Start Size**,**Start Rotation**はランダムに設定しています。右の逆三角形を押すとメニューが出るのでそこで設定します
![Rondom.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394850/2d60710b-1691-dfc5-46f0-da59e55bb9eb.png)>

**Simulation Space**はプレイヤーを回転させるときにパーティクルがWorld座標で出てきます。

####Emissionの設定
移動したときだけパーティクルが出てほしいので設定していきます。
![Emission.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394850/384a23c3-ba41-e1d8-55db-198df6acde64.png)

**Rate over Time**を0にします。
**Rate over Distance**を好きな値にしてください。
これで移動した距離でパーティクルが出るようになりました。

####Size over LifeTime
![sizeoverlifetime.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394850/b911745b-5445-c1fa-6979-0e2e8f425f7f.png)

サイズをクリックして出てきてから消えるまでの大きさを設定します。
![size.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394850/7d71e6f1-6de5-a408-abb3-5305a81c2bba.png)
右クリックすると**Add Key**と出るので選択するとノードが追加されます。
出てきた瞬間にパーティクルのサイズを大きくして、徐々に小さくしていくとそれっぽくなります。

####Rendererの設定
![renderer.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394850/3ea6e9f7-3b23-cc69-0ae4-22af7ecc3b6a.png)

**Render Mode**をMeshにします。
**Mesh**のところは好きなモデルやテクスチャを入れることができます。
**Material**で色を変えられるので好きな色にしてみてください。

##プレイヤーに付けよう

Particle Systemの横にある**歯車**をクリックして**Copy Component**をクリック。
Sphereを選択して**Sphere Collider**の歯車をクリックして**Paste Component Az new**をクリックします。
そうするとSphereの座標で操作できるので好きな位置にもっていってください。

コピーしたら元のParticle Systemは消しましょう。


##終わり
以上で設定は終了です。
わからないことがあればコメントをください。
活動記録(2020.3.29)

#今週やったこと
・DBのエラーでつまずき解明と環境変数設定周りで時間を使う羽目に…この辺は別記事にまとめている。
Ruby on Rails 学習メモ.2


・GitHubのこれまでのプルリク等の基本的活用に加えて、issues（とmilestone）でプロジェクトを管理するようにした。
なかなか進まないがこうやってプロジェクトを可視化・効率化させていくのはとても楽しい。

・3月最後の追い込みをしたかったが高熱が出てしまい進捗が芳しくなかった。

#課題・不明点
・テスト環境の理解が浅い。rubocopを導入すれば自動で警告文が出るらしい。RSpec、Jenkinsについても調べておく。
・ルート、ポート、DNS等ネットワーク周りの知識が弱い→基本情報技術者テキスト
・AWSは公式のレクチャーを見るべき。
・デプロイはCircleCIではなくGitHubActionsを採用するのもいいかも。
100日後にエンジニアになるキミ - 9日目 - HTML - HTMLの基礎4

# HTMLの属性について

前回までであらかたタグの説明を行いました。

今回はタグに付けられる属性についてです。

## HTML属性とは

HTMLの属性とは
HTMLのタグに対して何かしらの設定要素を付加するものです。

特定のタグでしか使えないものと
全てのタグ共通で使えるもの(グローバル属性)があります。

## HTML属性の書き方

`<タグ名 属性名="属性値" 属性名="属性値">`

タグを書いたら、その後ろにスペースを開けて
属性名を書き、属性値はイコール記号(=)を付けて書きます。

属性値は引用符で囲み、引用符はダブルクォート`"`を用います。

## 主なグローバル属性

id
固有の名前を指定する属性(一般的に英数文字,先頭は数字以外同じidを使わない)

class
分類名を指定する属性(一般的に英数文字,先頭は数字以外,スペースで区切りも有り)

title
捕捉情報を指定する属性

lang
言語を指定する属性

style
スタイルを直接指定する属性(一般的にスタイルはCSSを用いるのが推奨)

hidden
隠し属性 , コンテンツを隠す

全てのタグで共通ですが、タグによっては効かないものもあります。

classやidなどはタグを管理するために使用するもので
id名(属性値)はHTMLの中では一意、class名は複数存在します。

```
<div id="contentmain">
  <div class="c1">
    <div class="c1">
      <p>コンテンツ</p>
    </div>
  </div>
</div>
```

cssではidやclassでデザインの適応箇所を決めたり
出し分けたりしています。

スクレイピングではこの属性値を使って情報を取得するため
HTMLのタグと属性の構造を把握しておきましょう。

## タグ固有の属性

name
要素の名前,formやmetaタグなどでフィールドを識別のために使用する

autoplay
audia,videoタグ,動画や音声が再生可能な時点で再生を開始する

alt
imgタグなどの代替テキスト

disabled
button , input , optionなどでコントロールを無効にする

required
inputタグなどで必須よそを現す

href
a タグなどでリンク先を現す

maxlength
inputタグなどでの最大文字数

minlength
inputタグなどでの最小文字数

placeholder
inputタグなどでの入力ヒント

selected
optionタグでの初期選択を現す

size
inputタグなどでのサイズ , 文字数に該当

src
imgタグなどでのファイルなどのパス(URL)を指定する

type
inputタグなどでの要素の型を指定する

value
inputタグなどでのデフォルト値を指定する

※下記は指定できるがCSSでの対応が望ましい属性
width
imgタグなどで要素の幅

height
imgタグなどで要素の高さ

color
fontタグなどでの色合いを指定

border
imgタグなどでの境界線の幅

bgcolor
bodyタグなどでの要素の背景色を指定する

デザインに大きく関わる部分はHTMLでは直接指定をせずに
CSSファイル側でデザインを書いて適応させることがほとんどのため
HTML属性では指定しない方が良いかと思います。

のちにCSSの方もやっていきますので
併せて覚えてください。

## まとめ

タグによって指定できる属性名、属性値が変わってくる。
ここに乗っていないものもあるので、あとは
自分で調べてみよう。


君がエンジニアになるまであと91日

## 作者の情報
乙pyのHP：
http://www.otupy.net/

Youtube：
https://www.youtube.com/channel/UCaT7xpeq8n1G_HcJKKSOXMw

Twitter：
https://twitter.com/otupython