OmniAICreator/Qiita-1.07M huggingface dataset:
Union-Find構造をPythonで実装した

ABCで実行時間オーバーになってしまったので作ってみました。
Union-Find構造は、ノードのグループ構造や、所属グループ判定を高速に処理できます。
詳細は[こちら](https://atc001.contest.atcoder.jp/tasks/unionfind_a)
解説によれば、以下の計算量となるようです。

1. $\mathrm{unite}(u, v)$: 頂点 u が属するグループと頂点 v が属するグループを併合し、同じグループにする $(O(α(n)))$
2. $\mathrm{find}(v)$: 頂点$v$が属するグループ番号を得る $(O(α(n)))$
3. $\mathrm{size}(v)$: 頂点$v$が属するグループと同じグループに属する頂点数を得る $(O(1))$  
$n$は管理する頂点数、$\alpha$はアッカーマン関数の逆関数

実際のコードは以下です。
[リポジトリ](https://github.com/maron8676/atcoder-python)

追記
$\mathrm{unite}$ではグループの大きさでなくて、木構造の深さで結合方向を決めないといけないので間違ってますね
上記の参考資料の通り、経路圧縮による深さの変化は無視する方針で修正できそうです
2019/5/16 修正しました

```python:UnionFindNode.py
class UnionFindNode(object):
    """
    Union-Find構造
    ノードのグループ併合や、所属グループ判定を高速に処理する
    """

    def __init__(self, group_id, parent=None, value=None):
        self.group_id_ = group_id
        self.parent_ = parent
        self.value = value
        self.rank_ = 1

    def __str__(self):
        template = "UnionFindNode(group_id: {}, \n\tparent: {}, value: {}, size: {})"
        return template.format(self.group_id_, self.parent_, self.value, self.rank_)

    def is_root(self):
        return not self.parent_

    def root(self):
        parent = self
        while not parent.is_root():
            parent = parent.parent_
            self.parent_ = parent
        return parent

    def find(self):
        root = self.root()
        return root.group_id_

    def rank(self):
        root = self.root()
        return root.rank_

    def unite(self, unite_node):
        root = self.root()
        unite_root = unite_node.root()

        if root.group_id_ != unite_root.group_id_:
            if root.rank() > unite_root.rank():
                unite_root.parent_ = root
                root.rank_ = max(root.rank_, unite_root.rank_ + 1)
            else:
                root.parent_ = unite_root
                unite_root.rank_ = max(root.rank_ + 1, unite_root.rank_)


if __name__ == "__main__":
    node_list = [UnionFindNode(i) for i in range(4)]
    node_list[0].unite(node_list[3])
    node_list[1].unite(node_list[2])
    node_list[0].unite(node_list[2])
    print("\n".join(list(map(str, node_list))))
    print()
    print("\n".join(list(map(lambda x: str(x.root()), node_list))))
```
VPCを削除しようとしたら上限に達していて削除できない

# はじめに
VPCを削除しようとしたが上限に達していたため削除できなかった。
以下エラー文
```The VPC contains one or more in-use network interfaces, and cannot be deleted until those network interfaces have been deleted. 
View in-use network interfaces in the VPC.```

ネットワークインターフェースを消す必要ありとのこと。指示通りに削除して解決。
参考までにネットワークインターフェースについて簡単にまとめてみる。

# ネットワークインターフェースについて
一般的にいうネットワークインターフェースはAWSではENI（Elastic Network Interface）としてサービス提供されている。ENIはIPアドレス、Macアドレス等のネットワーク情報を保持する。以前はこれらの情報はEC2インスタンスに直接付与されていたが、ENIに付与しVPC内のインスタンスにアタッチすることで、「インスタンスからデタッチして別のインスタンスにアタッチする」などといった柔軟な設定作業、また柔軟なネットワーク構成が可能。

# 終わりに
参考リンク(https://dev.classmethod.jp/cloud/vpcfor-infra-engineer-2/)
ドットマークについて

未来電子テクノロジー（https://www.miraidenshi-tech.jp/intern-content/program/）でインターンをしている渡邊大介です。
class名でCSSを登録する場合はドットマークが必要。
しかしそうでない場合は、ドットマークは不要であるどころか、つけてしまうとうまくいかなくなってしまう。
これからはそのようなミスはなくしたい。
Python環境関連コマンド集


メモとしてPython環境回りのコマンドをあつめました。
※以下記載の「XXX」はパッケージ名、「1.0.0」はバージョン番号として読み替え


# パッケージ情報

pythonバージョンを表示

```ruby:
python -V
```

インストールされているパッケージの一覧を表示

```ruby:
pip list
```

更新可能なパッケージ一覧表示

```ruby:
pip list -o
```

最新パッケージ一覧表示

```ruby:
pip list -u
```

最新でないパッケージ一覧表示

```ruby:
pip list --outdated
```

パッケージの詳細情報を表示
Requires:依存関係
Location:配置場所

```ruby:
pip show XXX
```

# パッケージ更新

パッケージの登録

```ruby:
pip install XXX
```

パッケージの登録（特定バージョン指定）

```ruby:
pip install XXX==1.0.0
```

パッケージの登録（特定バージョン以上を指定）

```ruby:
pip install XXX>=1.0.0
```

パッケージの場所を確認

```ruby:Check.py
import datetime
print datetime.__file__
```


パッケージの更新

```ruby:
pip install -U XXX
```

パッケージの更新（特定バージョン指定）

```ruby:
pip install XXX==1.0.0
```

パッケージの削除

```ruby:
pip uninstall XXX
```

# Anacondaパッケージ操作
先頭文字を「conda」とする
※Installの場合の例

```ruby:
conda install XXX==1.0.0
```
5、6年越しでDialogFragmentの結果コールバックを作成してみた

# 概要

DialogFragmentが世に現れてかれこれ5〜6年ぐらい経ちました。
何度もDialogFragmentを使ってきましたが、毎回どのように実装していたか忘れる始末…

ちょっと余裕があるときにDialogFragmentの結果を返却するベースクラスを作ってみました。
設計としては、Activityのコールバックを受け取るonActivityResultと同じように、DialogFragmentが貼り付いている親に結果を返却する流れになります。

work.d128.fragment.app.dialogFragment.WDDialogFragmentがベースクラスです。

[Github/WDDialogFragment][1]

# 使い方

WDDialogFragmentを継承したDialogFragmentクラスを作成します。

```kotlin
class DatePickerDialogFragment: WDDialogFragment() {
}
```

OKボタンをタップしたタイミングなどでIntentにコールバックで受け渡したいデータを詰め込み、setResultにセットします。

```kotlin
val intent = Intent()
intent.putExtra(<Key>, <Value>)
setResult(RESULT_OK, intent)
```

コールバックを受け取るActivityまたはFragmentにinterfaceを追加することで、コールバックを受け取ることができるようになります。

```kotlin
class MainFragment: Fragment(), WDDialogFragment.OnResultListener {

    override fun onFragmentResult(requestTag: String, resultCode: Int, data: Intent?) {
    }

}
```

# 参考文献

[DialogFragment 実装パターン][2]

[1]:https://github.com/mn-D128/WDDialogFragment
[2]:https://qiita.com/kojionilk/items/9584c012679f61569995
Firestoreを本番で半年運用したアーキテクチャ：その③ 〜パフォーマンスの劣化対策として、CacheのCollectionを作った話〜

# これは？
Firebase Meetup #10 で [「Firestore導入前に検討したかったベスト５」](https://speakerdeck.com/pochisato/firestoredao-ru-qian-nijian-tao-sitakatutabesuto5-at-firebase-meetup-number-10) というテーマで発表したアーキテクチャ部分の話その3。

[①Firestoreを中心に据えた全体設計のコンセプト](https://qiita.com/pochi-sato/items/04f38bbed89e84184b52)
[②PubSubとCloud Functionsを使って、FirestoreのCollectionをマイクロサービスに見立てた話](https://qiita.com/pochi-sato/items/7ed4add1ec20f3e598d3)
**③パフォーマンスの劣化対策として、CacheのCollectionを作った話 ←今回**


# トライしたこと

まず、どんなトライをしたのか説明していきます。
この中で、今回お話するのが、赤丸をした部分です。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/30181/b91ec84d-7eea-ae52-caac-47ea4dd55876.png)

### 背景

ぼくらは、重大な問題を抱えていました。
社内の人がユーザーであるアプリケーションなので甘えていた結果、パフォーマンスが劇的に悪くなっていたのです。。
(ぼくらというかぼくだけのせい...)

状況としては、

- 元々、運用をちゃんと明瞭にシンプルにしていきたいという想いから、FirestoreのCollection設計は、正規化していた
- FirestoreではJOINしてクエリをかけられないので、正規化されているのをJOINするのは、すべて読み込み側(ブラウザ)やっていた

という感じで、つまりすべてクライアントJSでデータ結合をしていたんですね。

そしたら、1万件x1万件のジョインをするあたりから、クッソ遅くなりました。この記事は、これを解決するためにやったことのお話。

### 仕様

これを受けて考えたのは、 **書き込みたいデータ形式と、読み出したいデータ形式の都合は違うよな！** ということです。

なので、読み出しに最適化してあげればいいじゃん！と思って、真っ先に考えたのが、Backend For Frontend。クライアントのためにデータ整形してあげるAPIを挟めばいいじゃないか、と。

しかし考えてみると **「リアルタイムアップデートできないじゃん」** とおもいました。

自分でやってもいいんですが、WebSocketつかって云々カンヌンする、というのはわりと落とし穴多いし、実装スピード落ちるし、結構Firestoreの旨味減るな、と思ったわけです。

そうすると、読み出し元がFirestoreになっていることは、もはや必須要件。

だったら、Collectionも、読み出しに最適化されたものを持っていればいいじゃん、と考えました。

幸いFirestoreは書き込みをフックにCloud Functionsを起動できるので、

Firestoreに書き込まれる→Cloud Functionsが動く→Firestoreの読み出し用Collectionに書き込む

ということをしました。

もちろん、正規化された方をマスターデータとして、読み出し用CollectionはCacheと呼ぶようにしました。


# 良かったこと

死ぬほど早くなった。その後もすんごいデータ増えてますが、びくともしません。
だって、クライアントジョインしないなら、limitかけて取得できるので、どんなにデータ増えても性能落ちないですから、当たり前なんですよね...(クライアントジョインは全件取れないとジョインに穴できちゃうから。。)

すべての悪かったことを超越してすんごい良かった。

# 悪かったこと

- リアルタイムな反映が必要なやつには工夫がいる
    - Cloud Functionsが動く分、リアルタイム性には微妙にばらつきがある
    - (いま、USにリージョン持っているので、Tokyoリージョンなら緩和されるとおもう)
- Cacheのデバッグの難易度が高い
    - 更新されてない!?何があったんだろう、という推理がある
- Cloud Functionsの設計を丁寧にやる必要がある
    - 「Cloud Functionsがエラーになったら」「Cloud Functionsが重複実行されたら」「Cloud Functionsが前後してしまったら」 そういうことを想定する必要あり
AtCoder初参加と備忘録

最近いろいろ勉強しているけど結局ほとんど忘れているので
いい機会だし文章書く練習も含め、備忘録として残しておくことにする。

###AtCoder
AtCoder Beginner Contest 120 に参加してみました。
使用言語はC

結果から言うとAとCは難なく解けたけどBの問題を
勘違いしてやたら時間をかけてしまい3回目の提出でやっと正解。

Dの問題は解答見たら考え方はあってたみたいだけど
コードに落とし込むことができなかった…
結果600点 初回はこんなものなのだろうか



###標準入力とメモリ確保

無駄に時間がかかった原因にc言語での
標準入力やメモリの確保など普段使わないから
完全に使い方を忘れていたこと。


標準入力はこんな感じ

```
#include <stdio.h>

int main() {
    int inputA, inputB;

    scanf("%d%d",&inputA,&inputB);

    printf("%d\n",inputA);
    printf("%d\n",inputB);
    return 0;
}
```



int型で10個分メモリ確保するやり方はこんな感じ
intのsizeをsizeofで取得してそれ×10個分mallocで確保

```
#include <stdio.h>
#include <stdlib.h>

int main() {
    //メモリ確保
    int *data;
    data = (int*)malloc(sizeof(int)*10);

    //メモリ開放
    free(data);
    return 0;
}
```


2次元配列でも同様に10*5を確保するには

```
#include <stdio.h>
#include <stdlib.h>

int main() {
    //メモリ確保
    int **data;
    data = (int**)malloc(sizeof(int*) * 10);
    for (int i = 0; i < 10; i++) {
        data[i] = (int*)malloc(sizeof(int)*5);
    }

    //メモリ開放
    for (int i=0 ; i < 10; i++) {
        free(data[i]);
    }
    free(data);
    return 0;
}
```


このくらいは覚えてから挑戦すべきだった
URL, htmlで間違えたこと。英語(66)

URL, htmlで間違えたこと。

 <この項は書きかけです。順次追記します。>
# 「;」を「;」に
「Wireless Hack」by Rob Flickengerをハックしたい<書きかけ>
https://qiita.com/kaizen_nagoya/items/df87e75fe9a931fff472

p.92 

```html:freenetworks.html
<html>
<head>
    <meta http-equiv="Refresh" content="5:http://freenetworks.org" />
</head>
<body>

<h1> This is Rendezvous linux brought to you  by : me!</h1>

Redirecting you automatically in five seconds...
</body>
</html>
```

5秒でリダイレクトと書いてあった。ブラウザでファイルを読み込んでも止まったまま。
よくみると、「5:http」になっている。「5;http」と;じゃなきゃ。

```html:freenetworks.html
<html>
<head>
    <meta http-equiv="Refresh" content="5;http://freenetworks.org" />
</head>
<body>

<h1> This is Rendezvous linux brought to you  by : me!</h1>

Redirecting you automatically in five seconds...
</body>
</html>
```

ちゃんと5秒たったら、リダイレクトし始めようとした。
# 「:」を「;」に
「Wireless Hacks」 p.85 MACアドレスからメーカ一覧を作るmachine.plを手打ちしてエラー報告。未完。
https://qiita.com/kaizen_nagoya/items/26841520b9b9f9c61034

p.85 

```perl:machine.pl
#!/usr/bin/perl

my %cards;
my %ips;

open (ARP,"arp -an|") || die "Couldn't open arp table: $!\n";

print "Looking up OUIs.";
while(<ARP>){
 chomp;
 my $addr = $_;
 my $ip = $_;
 $addr =~ s/.* ([\d\w]+:[\d\w]+:[\d\w]+):.*/$1/;
 $addr =~ s/\b([\d\w])\b/0$1/g;
 $addr =~ s/:/-/g;
 next unless $addr =~ /..-..-../;

 $ip =~ s/.*?(\d+\.\d+\.\d+\.\d+).*/$1/;
 print ".";
 $cards{$addr}||=`curl -sd 'x=$addr' http;//standards.ieee.org/cgi-bin/ouisearch`;
 ($cards{$addr} =~ /Sorry!/) && ($cards{$addr} = "Unknown OUI; $addr");
 $ips{$ip} = $addr;
}
print "\n";
for(keys(%ips)){
 $cards{$ips{$_}} =~ s/.*.hex.\s+([\w\s\,\.]+)\n.*/$1/s;
 print "$_ -> $cards{$ips{$_}}\n";
}
```
curlで処理しようとしたURLに;があるとまずそこまで処理するらしい。

```shell-session
$ perl freenetworks.html
...
curl: (6) Could not resolve host: http
sh: 1: //standards.ieee.org/cgi-bin/ouisearch: not found
...
```
;を:に直して

```perl:machine.pl
#!/usr/bin/perl

my %cards;
my %ips;

open (ARP,"arp -an|") || die "Couldn't open arp table: $!\n";

print "Looking up OUIs.";
while(<ARP>){
 chomp;
 my $addr = $_;
 my $ip = $_;
 $addr =~ s/.* ([\d\w]+:[\d\w]+:[\d\w]+):.*/$1/;
 $addr =~ s/\b([\d\w])\b/0$1/g;
 $addr =~ s/:/-/g;
 next unless $addr =~ /..-..-../;

 $ip =~ s/.*?(\d+\.\d+\.\d+\.\d+).*/$1/;
 print ".";
 $cards{$addr}||=`curl -sd 'x=$addr' http://standards.ieee.org/cgi-bin/ouisearch`;
 ($cards{$addr} =~ /Sorry!/) && ($cards{$addr} = "Unknown OUI; $addr");
 $ips{$ip} = $addr;
}
print "\n";
for(keys(%ips)){
 $cards{$ips{$_}} =~ s/.*.hex.\s+([\w\s\,\.]+)\n.*/$1/s;
 print "$_ -> $cards{$ips{$_}}\n";
}
```
5秒経つとリダイレクトし始めた。実際に開き終わるまでの時間は様々。

 ＜この記事は個人の過去の経験に基づく個人の感想です。現在所属する組織、業務とは関係がありません。＞
定型タスクの予実を管理する表

複数案件の定型タスクの予実を確認できるように、表を作成してみた。

イメージはこんな感じ

![0303.PNG](https://qiita-image-store.s3.amazonaws.com/0/370717/3de1321d-14e0-db14-597a-2d6be309e852.png)

ポイントとしては

・条件付き書式を使って、遅延しているタスクをハイライトする
・workday関数を使って、一部の予定日を自動入力する

以下補足

・条件付き書式の条件

 　=AND(ISBLANK(実績日セル), NOT(ISBLANK(予定日セル)), 予定日セル<本日セル)

・workday関数の引数

　 =IF(案件セル<>"", WORKDAY($基準日セル, 営業日数, 祝日シート), "")

・workday関数の参照（祝日シート）
![0303_2.PNG](https://qiita-image-store.s3.amazonaws.com/0/370717/3bffbf18-193f-ca4a-2f6c-a2aa8c40d12e.png)
Kubernetes "did you specify the right host or port?"

# これまでのあらすじ
Kubernetes初心者の私はMacにDockerとKubernetesをインストールし、Kubernetes Dashboardにアクセスすることに成功した
https://qiita.com/pnpnd1111/items/2140f7941cfe3995fc17

以来、業務の傍らサイトやら本やらを見ながらちょこちょこKubernetesをいじっていた。

# しかし・・・
ある日のことだった。
ターミナルを開き、
```$ kubectl get nodes```
get nodesしようとすると

```The connection to the server <IP>:8001 was refused - did you specify the right host or port?```

むむ！！なんですかこれは！！！

# kubeconfigが臭う
検索して色々みてみたところ、どうやらkubeconfigファイルとやらの設定が間違っているとこうなるらしい。
ということでみてみます

```
$ kubectl config view
apiVersion: v1
clusters:
- cluster:
    insecure-skip-tls-verify: true
    server: https://localhost:6443
  name: docker-for-desktop-cluster
- cluster:
    insecure-skip-tls-verify: true
    server: https://<IP>:8001
  name: mycluster
contexts:
- context:
    cluster: docker-for-desktop-cluster
    user: docker-for-desktop
  name: docker-for-desktop
- context:
    cluster: mycluster
    namespace: cert-manager
    user: admin
  name: mycluster-context
current-context: mycluster-context
kind: Config
preferences: {}
users:
- name: admin
  user:
    token: <token>
- name: docker-for-desktop
  user:
    client-certificate-data: REDACTED
    client-key-data: REDACTED

```
clusterとcontextsが２つあって、current-contextはmycluster-contextになっています。
もう片方のcontextに切り替えたらいけるのでは？

# contextを切り替えてみる
```
$ kubectl config use-context docker-for-desktop
Switched to context "docker-for-desktop"
```

これで試してみましょう

```
$ kubectl get nodes
NAME                 STATUS    ROLES     AGE       VERSION
docker-for-desktop   Ready     master    23d       v1.10.11
```
いけました！！！
言われてみれば、それはそうだよね〜〜〜というミスでした。

## 参考にした記事
https://qiita.com/uni-3/items/a4f2afa0973bfc35b498
https://tracpath.com/works/devops/how-to-install-the-kubernetes-kubeadm/
Javascript配列のコピー方法(Deep/Shallow/代入)備忘録

Javascriptの配列をコピーする時には、単に代入する、第一階層の値だけコピーする(Shallow Copy)、全てをコピーする(Deep Copy)の3通りのコピー方法がある。

例を見ると次の通り

```js
const array = [1,1,1,1,{a: 1}];
const array2 = array;  // 代入
const array3 = [...array]; // spread演算子による展開代入 (Shallow Copy)
const array4 = array.concat(); // concatによるShallow Copy
const array5 = JSON.parse(JSON.stringify(array)); // Serialize/DeserializeによるDeep Copy
array[0] = 2;
array[4].a = 2;
console.log(array);   // [ 2, 1, 1, 1, { "a": 2 } ]
console.log(array2);  // [ 2, 1, 1, 1, { "a": 2 } ]
console.log(array3);  // [ 1, 1, 1, 1, { "a": 2 } ]
console.log(array4);  // [ 1, 1, 1, 1, { "a": 2 } ]
console.log(array5);  // [ 1, 1, 1, 1, { "a": 1 } ]
```

Shallow CopyではObjectではない要素が、またDeep Copyでは全ての要素がarrayと異なる参照先を持っており、arrayの値を変更しても影響を受けていないことが分かる。それぞれ記法としては現場でよく使われるので覚えておくと便利である。
FragmentでOnBackPressedを拾う

## はじめに
:warning: この記事の内容は古いです:warning:
今はおとなしく`OnBackPressedDispatcher`を使うのが良いと思います。

https://developer.android.com/reference/androidx/activity/OnBackPressedDispatcher

↓↓↓以下古い記載↓↓↓

Activityと同じ感覚でFragmentのバックキー押下イベントを検知しようとして詰まって調べたのでメモを残しておきます。
あまり関係ないですがAndroidX対応済のプロジェクトです。

* androidx.appcompat.app.AppCompatActivity
* androidx.fragment.app.Fragment

## 実装
まずはリスナーを作ります。

```OnBackPressedListener.kt
interface OnBackPressedListener {

    fun onBackPressed()
}
```

Fragment側でimplementします。

```BackPressableFragment.kt
class BackPressableFragment: Fragment(), OnBackPressedListener {

    override fun onBackPressed() {
        // ここで任意の処理を行う
    }

}
```

※最初にActivityに対してFragmentをadd, replaceした際にtagとして **FragmentのsimpleName** を指定しているものとします。
ActivityのonBackPRessed内にて、fragmentに実装したOnBackPressedListenerのメソッドを呼び出すことによって、端末のバックキー押下時にFragment内に定義したメソッドが実行できます。

```MainActivity.kt
    override fun onBackPressed() {
        val found = supportFragmentManager.findFragmentByTag(BackPressableFragment::class.java.simpleName)
        if (found != null && found is BackPressableFragment) {
            (found as OnBackPressedListener).onBackPressed()
        } else {
            super.onBackPressed()
        }
    }
```

## おわりに
Fragment側のメソッドが実行される分岐に入ると `Activity#onBackPressed`において`super.onBackPressed()`が実行されなくなります。
解決方法はいくつもあると思いますが期待している挙動がActivityの終了である場合にはFragment側のonBackPressedで以下のように書けばActivityが終了されます、参考までに。

```BackPressableFragment.kt

class BackPressableFragment: Fragment(), OnBackPressedListener {

    override fun onBackPressed() {
        // ここで任意の処理を行う
        
        //Activityの終了を呼び出す
        requireActivity().finish()
    }

}
```
プラグインインストール済のJenkins 構築 Docker編 その4

##モチベーション
もともとローカルで動かすのが目的だったが、せっかくなのでAWS上で動かす練習しておく。
（表題と内容が合わないので、あとで表題は変える予定です。）

##基本

Amazon ECS,Amazon Fargate,Amazon EKS,Amazon ECR,Amazon Batch, DockerEEいろいろサービスあるけど、今はおケースとレーションとかいらなくて、単発でDocker動かしたいだけ、どれからはじめたらいいのかわからないので、ひとまずチュートリアルやってみる。

##Amazon ECS チュートリアル実施
[Docker コンテナを 10 分でデプロイする](https://aws.amazon.com/jp/getting-started/tutorials/deploy-docker-containers/)
ロードバランサーの後方に配置した Amazon ECS クラスターで Docker 対応サンプルアプリケーションを実行し、サンプルアプリケーションをテストし、課金を避けるためにリソースを削除する方法について学びます。

ようはAmazon ECSなんだと

Amazon ECS（ Elastic Container Service ） コンソール初回実行ウィザードを開きます。リージョンはバージニア。
https://console.aws.amazon.com/ecs/home?region=us-east-1#/firstRun

###ステップ 1: コンテナとタスク
なにも変更せずに「次」へ。

###ステップ 2: サービスを定義する
デフォルトからの変更点。
・ロードバランサーの種類
・ロードバランサーリスナーポート:80
・ロードバランサーリスナープロトコル：HTTP

###ステップ 3: クラスターの設定
クラスター名：sample-cluster

###ステップ 4: 確認
「作成」


###ステップ 5: リソースの起動と表示
![image.png](https://qiita-image-store.s3.amazonaws.com/0/29032/2d14e9ee-4424-b7d9-5a3d-08bb70a283c4.png)

「サービスの表示」
![image.png](https://qiita-image-store.s3.amazonaws.com/0/29032/0b4e6069-fc6f-748c-3a94-0be47befd1b0.png)


###ステップ 6: サンプルアプリケーションを開く
Amazon ECS->クラスター->sample-cluster を選択
ロードバランシング->ターゲットグループ名 を選択
EC2 Management Consoleが開く

ELB DNS 名をコピーします
![image.png](https://qiita-image-store.s3.amazonaws.com/0/29032/0c286441-19fc-45d5-5c46-2a1a54734b1f.png)

EC2Co-EcsEl-AZ2WF2E6DLKB-1219461024.us-east-1.elb.amazonaws.com

Amazonさんが用意してくれているサンプルアプリケーションsample-appの画面が表示された。
サンプルアプリケーションの代わりにJenkinsを動かすのが本来の目標（忘れないように。。）
![image.png](https://qiita-image-store.s3.amazonaws.com/0/29032/246b2448-e224-4828-ac6b-a28b2581098e.png)

###ステップ 7: リソースを削除する
このチュートリアルでは以下のリソースを使ったので、順番に削除。
・Amazon ECS クラスター、
・Amazon EC2 インスタンス
・ロードバランサー

####ECSのクラスタ削除
クラスター名 (sample-cluster) 選択->更新
アクティブなタスクを実行中のサービスを誤って削除しないよう、タスクを停止。 
タスクの数:0に設定し、「次のステップ」「サービスの更新」
当たり前だが、この時点で先ほどのURLにはアクセスできなくなる。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/29032/e3e194d4-b88d-2587-9d55-6d876524c31e.png)
安心してクラスタを削除
丁寧に、「もし0にスケールダウンしてない場合は、削除前にスケールダウンするよ」と表示されたので、もしかしてタスクを止める処理は要らなかったかも。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/29032/52f8c385-14fb-10e2-11eb-859b6db92019.png)

####EC2 インスタンス削除
あれインスタンスが見つからない。自動で削除されるようになった、と思うことにしよう。
作成の途中で明示的にEC2の設定はしていないので、自動削除なら親切だと思う。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/29032/fd99228e-ea41-3499-d103-ef8cf72eb274.png)

####ロードバランサー
選択して、削除
![image.png](https://qiita-image-store.s3.amazonaws.com/0/29032/9e9d16d5-176a-0371-0c9a-570118d9274c.png)
ターゲットグループは残ってしまうんだが、これはよいのだろうか？

##次回予告
ありもののアプリを動かすだけのチュートリアルだったので、自分がやりたいこととはだいぶ違った気がするが、自前のDockerfileからAWS上でDocker動かすことを試す。
ステップ 1: コンテナとタスクのところを変更するればできるはず。
Firestoreを本番で半年運用したアーキテクチャ：その② 〜PubSubとCloud Functionsを使って、FirestoreのCollectionをマイクロサービスに見立てた話〜

# これは？
Firebase Meetup #10 で [「Firestore導入前に検討したかったベスト５」](https://speakerdeck.com/pochisato/firestoredao-ru-qian-nijian-tao-sitakatutabesuto5-at-firebase-meetup-number-10) というテーマで発表したアーキテクチャ部分の話その２。(めちゃくちゃゆっくりな更新...)

[①Firestoreを中心に据えた全体設計のコンセプト](https://qiita.com/pochi-sato/items/04f38bbed89e84184b52)
**②PubSubとCloud Functionsを使って、FirestoreのCollectionをマイクロサービスに見立てた話 ←今回**
[③パフォーマンスの劣化対策として、CacheのCollectionを作った話](https://qiita.com/pochi-sato/items/88f2e0a079546044b256)

# トライしたこと

まず、どんなトライをしたのか説明していきます。
この中で、今回お話するのが、赤丸をした部分です。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/30181/99c887d3-7642-1122-609e-712377ca6256.png)


ここでは何をしているかというと、
1つのObjectを、PubSubにPublishするんですが、そのPublishされたもの(Topicと呼ばれます)に、複数のSubscriptionを付与しています。
そのSubscriptionは、Cloud Functionsなど、別々のアプリケーションに紐付けられてます。

つまり、何か新しいObjectがPublishされると、Cloud Functionsやらが、同時に並行して処理をはじめます。

その時に、それぞれのアプリケーションが、それぞれFirestoreの **1つのcollection** に書き込みます。
つまり、そのcollectionにデータを入れるために、どんな処理が必要か、という責務に集中したアプリケーション群を並列に動かしました。

これは何でか、というと、

**FirestoreはJOINできない = つまり、1つ1つのcollectionが別のデータベースのように振る舞っている** と思ったからです。

もちろん、writeBatchを使ったり、transactionを使ったりして、リレーションを保つ方法はあります。

でも、そうやって自らに制約をどんどん課していくと、Firestoreの本来の力を引き出しきれなくなるのでは、と思いました。

というのも、 **並列に動いて一時的にNullableになったとしても、本来、スキーマレスなのですべての値がNullableになりえるので、そういう設計をしていないといけないし、
何よりリアルタイム性が高いので、そのNullableな状態を許容した上で、整合性取れた時点で画面にリアルタイムに表示されていくべき** だよな、
そう考えたわけです。

これはイメージ的には、それぞれ1アプリケーションと1Collectionのひとまとまりが、1マイクロサービスのような形になっています。


ちなみに、この設計にできたのは、そもそも僕が、最初にFirestoreを使い始めるときに、RDBのようにある程度正規化していたためです。
最初にその設計になっていないと、やろうとしても他のデータが混ざってできない気がします。



# 良かったこと

当たり前ですが、実装がめちゃくちゃシンプルになって、かなり突貫でつくっていたんですが、汚染なく、ステートレスになりました。

ただ、途中から変えたので、元々あった部分はステートフルが残っていて、最初にこの形にしていなかったのを後悔していました。。

# 悪かったこと

当たり前ですが、並列性を担保すると、同期が取れにくくなります。

ということは、データの入り方によって種々のパターンが発生してしまいます。

本来nullable、ということに基づいて設計できていれば問題ないのですが、
それをチームでちゃんと理解を浸透させないとリスクを生む、というのが1点。

もう一つは、ただデータを保存するだけならいいけれども、そのデータを元にすぐに他の処理(副作用)を起こそう、という時に、
1つのcollectionのデータだけでは完結しない場合があります。

そうすると、複数のcollectionのデータをまたがるので、こうなるとFirestoreはめちゃくちゃ弱い。

Firestoreにデータが入ってから何かするぞ、というときに、1つのcollectionだけウォッチすればいいわけではないので、
こういう感じになると、複数のcollectionをウォッチしたり、専用に新たにcollectionつくったり、
めちゃくちゃにややこくなるので、
だったら最初っから同期でつくった方がよい！となります。


僕らはそのケースに当てはまったので、突貫でつくったものをリファクタするときに、同期式へ書き換えていったのでした。



わりとこの辺は要件次第ですが、ハマれば強いとおもいました。
chef bootstrapを使ってみる


# 概要

- chefを利用する時には、chefのサーバーと、構築したいノードから構成される。
- ノードには、事前にchef-clientをインストールする必要があるが、bootstrapの機能を利用すれば、chef-clientをリモートからインストールできる。

# 例

- 構成
	- server: 192.168.100.51
	- 構築対象のノード: 192.168.100.52
	- 対象のノードには事前にchefユーザーが存在すること
	- chefユーザーはsudo権限を所持していること
	- chefユーザーは外部からssh接続できること(今回はパスワード認証)

```
$ knife zero bootstrap 192.168.100.52 --ssh-user chef --sudo

$ knife node run_list add localhost 'role[linux-server]'

$ knife zero converge 192.168.100.52 --ssh-user chef --sudo
```

# 問題と解消方法

- convergeを実行すると、ssh接続しようとするが、接続先によっては、接続できないことがある。
- FQDNを持たず、IPで直接接続するケースにおいて発生する。
- 上記例の場合、以下のようなnodeファイルが作成されているがfqdnをIPアドレスに置き換える必要がある。

```
{
  "name": "localhost",
  "normal": {
    "knife_zero": {
      "host": "192.168.0.52"
    },
    "tags": [

    ]
  },
  "automatic": {
    ...
    "hostname": "localhost",
    "machinename": "localhost.localdomain",
    "fqdn": "localhost", // <- ここを192.168.0.52とすると動作する
    "domain": null,
    ...
```
マーケティングに必要なスキルとは？マーケターの役割が変化している？

#マーケターに求められる役割の変化

デジタルマーケティングにおいて従来のマーケターは、広告出稿が主な担当領域で、ブランド認知や集客によるトラフィック増加を推進することが大きな役割でした。

ところがテクノロジーの進化による昨今では、ユーザー個々にパーソナライズされたコミュニケーションを用意し、一貫した、全体最適な施策を行うことで、優れたCX（顧客体験）を提供することが求められるようになってきています。

SEOにおいても、本来SEOは「Search Engine Optimzation」の略ですが、アルゴリズムの進化により昨今では「Search Experience Optimization」の略である言っても良いほど、ユーザーの意図を捉えたコンテンツを提供し、サイト上で良いユーザー体験を提供していかなければ、ランキング上位の獲得は難しくなってきています。

このように現在は、マーケティングに様々な役割が求められる時代です。
従来以上にマーケターには統合的なスキルが必要されており、今後、その傾向はますます顕著になってくるでしょう。

#マーケターに求められるスキルマップ

では具体的に、一体どんな役割がマーケターに求められているのか。そのスキルについて以下の図で可視化してみました。

![マーケティングのスキルマップ](https://qiita-image-store.s3.amazonaws.com/0/67591/fd32f310-4f99-56f9-c7c2-c74a162e1dec.jpeg)

マーケティングに関わる領域を俯瞰して見ることで、ご自身のスキル・知識の再確認に繋がると幸いです。

#マーケターに求められるスキルの一覧
また、上記のスキルマップと同じものになりますが、マーケターに求められるスキルを一覧として以下に全て掲載しておきます。

##理解度の判定
スキルの有無に関して、以下4つの視点で判定すると良いでしょう。

- 人に教えることができる
- 一人で業務を進められる
- 他者の協力を得ながら進められる
- 未経験

##ブランド認知と集客
認知、集客の手法として必要なスキルになります。
###コンテンツSEO
- キーワード設計
- 構成案作成
- 記事執筆
- 校閲
- 既存記事分析
- 記事リライト
- ライター採用・教育

###バックエンドSEO
- htaccess
- robots.txt
- metadata
- サイトスピード最適化　（パフォーマンス改善）

###テクニカルSEO
- サイトマップ
- クロールバジェット
- URLの正規化
- サイト構造と内部リンク設計
- 構造化マークアップ
- アウトライン設計
- ローカルSEO
- 画像検索
- AMP/PWA

###外部施策
- リンクビルディング
- メンション（言及数）獲得
- バズコンテンツ企画

###広告運用
- GDN
- YDN
- リスティング広告
- SNS広告
- インフィード広告
- アフィリエイト広告
- 純広告

###ソーシャルメディア運用
- Facebook運用
- Twitter運用
- Instagram運用
- インフルエンサーマーケティング
- SNSキャンペーン
- UGC活用

###その他の集客
- PR
- セミナー・イベント・展示会
- テレアポ
- リファラル
- ホワイトペーパー
- 外部への記事の提供

##リテンションとナーチャリング
ユーザー獲得以降のマーケティング活動に必要な手法としてのスキルになります。

- メールマーケティング
- SMS
- プッシュ通知
- ブラウザ通知
- MA
- CRM/SFA
- スコアリング設計
- DM
- LINE@

##データ駆動
データの活用に必要なスキルです。データによる根拠ある施策を実行することで、より効果を高めることを目指します。

- 計測タグの理解とタグマネジメント
- Cookieの理解
- データの収集・連携・解析
- トラッキングログ解析
- ヒートマップ解析
- DMP
- BIツール活用
- 統計学
- 機械学習
- KPI/KGIの設定

##コンバージョン改善
コンバージョンを改善し、収益増加を図る為に必要なスキルです。

- UI/UX/IA
- ABテスト
- フォーム修正（EFO）
- ランディングページ最適化（LPO）
- ナビゲーション設計
- レコメンド導入
- Web接客

##技術
最低限、身につけておいた方が良い技術を挙げました。
HTML・CSS・Javascript・SQLは必須で、PHP・Java・C/C++・Pythonはいづれか1つでも身につけておくと良いでしょう。

###言語
- HTML
- CSS
- Javascript
- PHP
- Java
- C/C++
- Python 
- SQLなどのクエリ言語

###ミドルウェア
- MySQL
- PostgreSQL
- Apache
- nginx

##顧客ターゲット別
toCなのかtoBなのかによってもマーケティング手法は変わってきます。
統合的なスキルという意味では、両方の経験があると良いと思います。

- BtoC
- BtoB

#まとめ
冒頭でも述べたように、競争力のあるマーケターであるためには、統合的なスキルが必要不可欠です。
今後は、1つのことしかできないマーケターはどんどん淘汰されていくでしょう。

ぜひ今後のご自身のキャリアアップや社内メンバー、採用時のスキルセットの判定の参考にしてください。
FMラジオモジュール RDA5807Mで自作ラジオ

# はじめに

* Amazonで1個138円(5個で330円)のFMラジオモジュールなるものを発見。
* 例のごとく、10日ほどで商品が到着したけど、1cm四方のミニ基板でちっちぇ〜。
* とりあえずどんなもんか、試してみた。

![IMG_1816.JPG](https://qiita-image-store.s3.amazonaws.com/0/283854/65fcc02b-3a40-2f7c-e752-cb658271134a.jpeg)

# スペック

* [FMラジオモジュール RDA5807M](https://www.amazon.co.jp/KKHMF-FMラジオモジュール-RDA5807M-RRD-102V2-0-2-7-3-6V/dp/B01LZ7RWV3)
 * チップ名：RDA5807M
 * 動作電圧：DC2.7-3.6V 
 * 変調モード：FM 
 * FMバンド周波数：76-108MHz

# 配線 
* ブレッドボードと基板のピッチが違うので、N/C以外のピンを延長して接続。

![IMG_1818.JPG](https://qiita-image-store.s3.amazonaws.com/0/283854/ac2a9472-f3f8-04aa-bdff-9e793ced7435.jpeg)

## ピン配置
* RDA5807M のピン配置は左上を１番ピンとして(上の写真の向きと同じ)、こんな感じ。

| No| Name    |   | No | Name |
|:--|:--------|:--|:--|:------------|
| 1 | SDA     |   | 6 | アンテナ      |
| 2 | SCL     |   | 7 | N/C          |
| 3 | N/C     |   | 8 | スピーカ L OUT |
| 4 | N/C     |   | 9 | スピーカ R OUT |
| 5 | VCC(3V) |   | 10| GND          |

### アンテナ
* 6番ピン
 * 30cm〜60cmの長めの導線を伸ばしておく。これで電波をキャッチできるかで音質が決まる。

### Arduinoとの接続

|RDA5807M |Arduino Nano互換機|
|:--:|:---:|
| SDA | A4 |
| SCL | A5 |
| GND | GND|
| VCC | 3V |


### アンプとスピーカ

アンプを介してスピーカL, R 側に接続。

![IMG_1819.jpg](https://qiita-image-store.s3.amazonaws.com/0/283854/9ad9597a-32f0-442a-7e3f-1a43701a61d4.jpeg)

* アンプ/スピーカー
 * RDA5807M自体はステレオ出力できるが、写真ではモノラルでお試し。 
 * Arduinoの8,9番ピンをアンプのR_IN, L_INにつなぐ。GNDもつなぐ。
 * 出力側のVCC/GNDはArduinoの5V/GNDから取る。
 * L_OUT+, L_OUT-をスピーカにつなぐ。
 * 実験用に小型のアンプは1個持っとくと便利。

# ライブラリのインストール

* Arduino IDE の「ライブラリマネージャ」で「rda5807」を検索。
* 「Radio by Matthias Hertel」をインストールする。

# コード
* [こちら](http://www.theorycircuit.com/arduino-rda5807m-fm-receiver/)と[こちら](https://blogs.yahoo.co.jp/wncdevelop/folder/1600139.html?m=lc&p=1)のページを参考にした。

```
#include <Arduino.h>
#include <Wire.h>
#include <radio.h>
#include <RDA5807M.h>
#define FIX_BAND     RADIO_BAND_FMWORLD //RADIO_BAND_FM    //Radio Band -FM
#define FIX_STATION  8000 //10050            //Station Tuned = 100.50 MHz.
#define FIX_VOLUME   5               //Audio Volume Level 5.

RDA5807M radio;    

void setup() {
 
  Serial.begin(9600);
  Serial.println("FM Radio");
  delay(200);
  
  radio.init();
  radio.debugEnable();

  radio.setBandFrequency(FIX_BAND, FIX_STATION);
  radio.setVolume(FIX_VOLUME);
  radio.setMono(false);
  radio.setMute(false);
} 



void loop() {
  char s[12];
  radio.formatFrequency(s, sizeof(s));
  Serial.print("Station:"); 
  Serial.println(s);
  
  Serial.print("Radio:"); 
  radio.debugRadioInfo();
  
  Serial.print("Audio:"); 
  radio.debugAudioInfo();

  delay(3000);
} 
```

* 76MHzから108MHzまで対応させるためにFIX_BANDを修正
 * RADIO_BAND_FMだと87MHz未満は87MHzにされてしまうのでRADIO_BAND_FMWORLDに修正。

```
#define FIX_BAND     RADIO_BAND_FMWORLD //RADIO_BAND_FM    //Radio Band -FM
```

* 日本のラジオ局の周波数(80.0MHz；東京FM)に修正。

```
#define FIX_STATION  8000 //10050            //Station Tuned = 100.50 MHz.
```

で、プログラムを走らせると・・・・

おお、あっさり音が出ました！！

![IMG_1817.JPG](https://qiita-image-store.s3.amazonaws.com/0/283854/c725eb51-07d7-3381-f1b3-aab2a974251a.jpeg)

* この後やりたいこと（どれも簡単）
 * チャンネルを変えるにはプログラムをいちいち焼き直す必要があるので、ボタンで切り替える。
 * LCDにラジオ局名を表示する。
 * ステレオ出力も。

# 感想
* こんなに安くてちっちゃいモジュールだけど、ちゃんと電波拾えればノイズも無く良く聞こえる。
* ちっちゃくパッケージ出来るので、緊急用のラジオとして使うと良さそう。
* イケてるお菓子の箱か何かでパッケージングすれば楽しそう。
migrationでrollback可否でchangeかup/downを使い分ける

migrationにおいてchangeで書いてもrollbackできるもの、up/downで書かなくてはrollbackできないものをまとめました。
初投稿です。よろしくお願いします。

## rollbackできる(changeでOK)
#### カラムを追加する
rails g migration AddColumnUsers

```ruby
class AddColumnUser < ActiveRecord::Migration[6.0]
  def change
    add_column :users, :age, :integer
  end
end
```

#### カラムの名前を変更する

```ruby
class RenameColumnFilmsReviewsFromNameToTitle < ActiveRecord::Migration[6.0]
  def change
    rename_column :films_reviews, :name, :title
  end
end
```

#### カラムにindexを追加する


```ruby

class AddIndexToUserOfName < ActiveRecord::Migration[6.0]
  def change
    add_index :users, :name_badge: 
  end
end
```

#### カラムにデフォルト値を設定する（change_column_defaultを使う）

```ruby

class ChangeColumnDefaultUserOfSocial < ActiveRecord::Migration[6.0]
  def change
    change_column_default :users, :social, from: nil, to: false
  end
end 
```

## rollbackできない(up/downで書く)

changeで書くと以下のエラーが発生するもの

```
Caused by:
ActiveRecord::IrreversibleMigration: 

This migration uses change_column, which is not automatically reversible.
To make the migration reversible you can either:
1. Define #up and #down methods in place of the #change method.
2. Use the #reversible method to define reversible behavior.
```

### カラムのデータ型を変更する

rails g migration ChangeColumnUsersToGender

```ruby

class ChangeDataUserToGender < ActiveRecord::Migration[6.0]
  def up
    change_column :users, :gender, :boolean
  end

  def down
    change_column :users, :gender, :integer
  end
end
```

### カラムにnullを許可しないよう変更する

```ruby

class ChangeColumnUserForName < ActiveRecord::Migration[6.0]
  def up
    change_column :users, :name, :string, null: false
  end

  def down
    change_column :users, :name, :string, null: true
  end
end 
```

### カラムにデフォルト値を設定する(change_column_defaultを使わない場合)

```ruby

# change_column_defaultを使うとchangeでもrollbackできる
class AddDefaultValueUserOfOccupation < ActiveRecord::Migration[6.0]
  def up
    change_column :users, :occupation, :integer, default: 1
  end

  def down
    # default値を指定していなかった場合 default:nilと書かないとrollback時にnilに戻らない
    change_column :users, :occupation, :integer, default: nil
  end
end
```

RailsGuideによると複雑なことやるときはreversibleを使いましょうというのもあるけど、それはまた別の機会に。（また今度というときはまず書かないかもですが:expressionless:）
> [マイグレーションを逆方向に実行 (ロールバック) する方法が推測できない場合、reversible を使います。](https://railsguides.jp/active_record_migrations.html#reversible%E3%82%92%E4%BD%BF%E3%81%86)
slickでスライドバーをつくってみた

##まえがき
コーディングを主で対応するようになって1年ほどの新米コーダーです。
自分なりの勉強や改善を備忘録として記録してます。
##実装
[slickでスライドバーをつくってみた](https://codepen.io/itamkia/pen/wOwJvY)
##使用バージョン
```html:
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.6.0/slick.min.css">
<script src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.6.0/slick.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.11.0/jquery-ui.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui-touch-punch/0.2.3/jquery.ui.touch-punch.min.js"></script>
GitHub - Gitの操作 #3

##基本的な操作
- `git init`  
リポジトリを初期化  
.gitディレクトリに管理するリポジトリデータが格納される。  
この初期化したディレクトリ以下をワークツリーと呼ぶ。
- `git status`  
リポジトリの状態を確認
- `git add`  
ステージ領域へファイルを追加して、Gitリポジトリのバージョン管理の対象にする。
- `git commit`  
ステージ領域のファイルを、リポジトリの歴史を記録  
`git commit -am "{メッセージ}"`  
add + commit を一回で行える

```terminal
// １行のコミットメッセージ
$git commit -m "{メッセージ}"

// 詳細なコミットメッセージ
$git commit 
// フォーマット
1 変更内容の要約
2 空白
3 理由や詳細を以下に記述
```
- `git status`  
現在のワーキングツリーの状態を確認
- `git log`  
コミットログを確認  

```terminal
// コミットメッセージの1行目のみ
$git log --pretty=short

// 指定したディレクトリ、ファイルのも
$git log {ファイル名}

// ファイルの差分を表示
git log -p {ファイル名}
```

- `git diff`  
ワークツリー、ステージ領域、最新コミット間の変更差分を確認

```terminal
// ワークツリーとステージ領域
$git diff

// ワークツリーと最新コミットの差分
$git diff HEAD  // HEADは、作業ブランチの最新のコミットを参照するポインタ
```

## ブランチの操作
- `git branch`  
ブランチを一覧表示  
現在のブランチを*で確認
- `git checkout -b {ブランチ名}`  
ブランチを作成し、切り替える

```terminal
// ブランチの切り替え
$git checkout {ブランチ名}

// 1つ前のブランチに切り替える
$git checkout -
```

- `トピックブランチ、統合ブランチ`  
トピックブランチとは、1つのテーマに集中して、他の作業は一切行わないブランチのこと。  
統合ブランチとは、トピックブランチの中心（分岐元、併合先）となるブランチ。
- `git merge`  
ブランチをマージ  

```terminal
$git checkout {マージ先}
// --no-ffを付けてマージコミットを作成する
$git merge --no-ff {ブランチ名}
```
- `git log --graph`  
ブランチを視覚的に確認する

## コミットを変更する操作
- `git reset`  
歴史を戻る

```terminal
$git reset --hard {戻りたい状態のハッシュ値} // ハッシュ値は初めの4文字以上あれば動作する

// リポジトリでの作業のログを確認する
$git reflog
```

- `git commit --amend`  
直前のコミットメッセージを修正する  
- `git rebase -i`  
使用例  
間違えがあるコミット:commitA  
修正を加えたコミット:branchB  
この二つを統合して一つのコミットにする

```terminal
$git rebase -i HEAD~2
// 以下が表示されるのでpickをfixupに変更することでcommitAにすべて統合される
pick {ハッシュ値} commitA
pick {ハッシュ値} commitB → fixup {ハッシュ値} commitB
```

## リモートリポジトリへの送信
1.GitHubでリポジトリを作成する
2.ローカルリポジトリで、以下のコマンドでリモートリポジトリを登録する
　originは、以降リモートリポジトリを指す。  

```terminal:ローカルリポジトリ
$git remote add origin {リポジトリのパス}
```  

3.リモートリポジトリ(origin)のmasterブランチへ送信する
　-uは、ローカルリポジトリのupstreamはoriginのmasterブランチであることを示す。これにより、git pullでの設定を省略可能。

```terminal:ローカルのmasterブランチ
$git push -u origin master
```

## リモートリポジトリから取得
すでにリモートにあるリポジトリを取得する  

```terminal
$git clone {リモートリポジトリのパス}

// リモートリポジトリも含んだブランチ情報の表示
$git branch -a
// リモートのブランチをローカルで取得する
$git checkout -b {ブランチ名} origin/{ローカルのブランチ名}

// 最新のリモートリポジトリブランチを取得
$git pull origin {ブランチ名}
```

## Gitをより深く
- [Pro Git](http://git-scm.com/book/ja/)
- [LearnGitBranching](http://pcottle.github.io/learnGitBranching/)
- [tryGit](http://k.swd.cc/learnGitGranching-ja)
JetsonTX2のパフォーマンスを最大にする

JetsonTX2を扱うとき，CPUやGPUをフルに稼働させて最大パフォーマンスを発揮させたいときがある．

しかし，毎回その方法を忘れてしまい，その度にやり方を検索をするのが面倒なため
備忘録用にまとめておく．

## 参考サイト

今回の情報はすべて以下のサイトに掲載されているものである．
そのため，詳しい情報を知りたいときはそちらを参照されたい．

- https://www.jetsonhacks.com/2017/03/25/nvpmodel-nvidia-jetson-tx2-development-kit/
- http://demura.net/athome/13794.html
- http://dfukunaga.hatenablog.com/entry/2018/05/01/215852

## 最大パワーをひきだす

以下のコマンドを実行すればよい．

```terminal
$  sudo nvpmodel -m 0
$  sudo /home/nvidia/jetson_clocks.sh
```

## nvpmodelのモード設定

`nvpmodel`のモードは0から4が入力できる．
それぞれの稼働状況は以下のようになる．

|Mode|Mode Name|Denver2|Frequency|ARM A57|Frequency|GPU Frequency|
|--:|:--|:--|:--|:--|:--|:--|
|0|Max-N|2|2.0 GHz|4|2.0 GHz|1.30 Ghz|
|1|Max-Q|0||4|1.2 GHz|0.85 Ghz|
|2|Max-P Core-All|2|1.4 GHz|4|1.4 GHz|1.12 Ghz|
|3|Max-P ARM|0||4|2.0 GHz|1.12 Ghz|
|4|Max-P Denver|1|2.0 GHz|1|2.0 GHz|1.12 Ghz|

なお，現在使用しているモードを確認するには

```terminal
$  sudo nvpmodel -q
```

で行う．
超簡単! Powershellでファイルの圧縮/解凍

##powershellを使ったファイルの圧縮/解凍
powershellで簡単にファイルを圧縮/解凍できたため、メモ。

##1.  圧縮    
`Compress-Archive`

```
Compress-Archive -Path C:\Users\.... -DestinationPath C:\Users\XXX\....
```
これだけ。めちゃめちゃ簡単。
以下、パラメータの解説。

***-Path***
必須パラメータ。Compress(圧縮）するファイル/フォルダのパスを指定する。
複数ファイル指定することも可能。ワイルドカードの使用も可能。


***-DestinationPath***
必須パラメータ。Compress(圧縮）先のパスを指定する。

***-Force***
上書きする。-Forceパラメータ無しでは、-DestinationPathで指定したzipファイルが既に存在する場合、実行に失敗する。このパラメータを知らず、先日ジョブがこけた。

***-Update***
既存のzipファイルを更新する。

その他、CompressionLevel、Confirm等のパラメータがあるっぽい。
詳しく書いてある記事がこちら。
[https://cheshire-wara.com/powershell/ps-help/compress-archive-help/]

##2.  解凍 
`Expand-Archive`

```
Expand-Archive -Path C:\Users\.... -DestinationPath C:\Users\XXX\....
```
これだけ。これもめちゃめちゃ簡単。
以下、パラメータの解説。

***-Path***
必須パラメータ。Expand(展開）するzipファイルを指定する。


***-DestinationPath***
必須パラメータ。Expand(展開）先のパスを指定する。

***-Force***
上書きする。

##作ってみた
1 zipファイルを作成するバッチファイルを作成した。

```compress-archive.bat
@echo off

rem -フォルダの有無を確認し、ファイルが存在した場合圧縮する

set base_path=C:\Users\XXX\Desktop\compress
set powershell_exe="C:\Users\XXX\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Windows PowerShell\Windows PowerShell.lnk"
set destination_path=C:\Users\XXX\Desktop\destination

if not exist %base_path% (
    eventcreate /T ERROR /SO test /ID 001 /D "test用イベントログ" /L APPLICATION
    exit /b 1
)

%powershell_exe% Compress-Archive -Path %base_path%\* -DestinationPath %destination_path%\test.zip -Force

exit /b 0

```

2 zipファイルを解凍するバッチファイルを作成した。

```
@echo off

rem -ファイルの有無を確認し、あった場合解凍する

set zip_file=C:\Users\XXX\Desktop\destination\test.zip
set powershell_exe="C:\Users\XXX\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Windows PowerShell\Windows PowerShell.lnk"
set destination_path=C:\Users\XXX\Desktop\expand

if not exist %zip_file% (
    eventcreate /T ERROR /SO test /ID 002 /D "test用イベントログ" /L APPLICATION
    exit /b 1
)

%powershell_exe% Expand-Archive -Path %zip_file% -DestinationPath %destination_path% -Force

exit /b 0

```
DApps開発を始める動機と工程(粗め)紹介

# 当ページの位置づけ
- DApp(decentralized application＝分散型アプリケーション)を実践/開発を通して学んでいく。開始するにあたり動機整理と、現時点でのDapp理解、実際に実装していく上での工程整理をする。

※特に誰かの役に立つという意図はありません。先に断っておきます。

# なぜ興味をもった?? ~ 動機 ~
- そもそも自分のDAppsの理解をお伝えすると...
    - ブロックチェーンネットワークを構成する各ノードとその集合によって実行、保証されるもの。完全な管理者、責任者のもと管理されているサーバー上でデータ管理並びに処理はされない、、という解釈をしている。
    - 要は物理的かつ利害関係が一致しない複数ステークホルダに、管理権限が分散している

**動機詳細**

- 私が認識している、「分散アプリケーションのいいとこってどんなところ??」
    - 改ざんが難しい
    - 単一障害点がほぼない
    - 思想的なところ/共感している。検閲しない。「あるべき論」が存在しない。
        - ゆる〜い＋浅い。
            - 振り返ったときにはもっと精緻になっていることを期待。
- もやもやしているところ
    - どうやって動いているのかわからない **→ 原理を知りたい**
    - 何がすごいのかわからない(なぜ盛り上がっている??) → 時間とともに処理が重くなりそうだけど実現可能なの?? **→ 制限、制約を知りたい**
    - ぶっちゃけ、これまで通りのWebサーバーとかにアプリケーションをのっけたほうがいいのではないかとおもっている **→ メリデメを知りたい**
    - 分散(非中央集権)と非分散(中央集権/これまで主流の管理者の存在するタイプ)の本質的な違いってなんなんだろうか **→ 本質的な価値を知りたい(考えてみたいに近い)**
        - **[結論]実際に手を動かして作ってみよう**
            - 最終的に上の質問に答えられているとハッピー

# じゃあ、何をするか??
- 題材として、[ETHEREUM PET SHOP -- YOUR FIRST DAPP](https://truffleframework.com/tutorials/pet-shop#ethereum-pet-shop)を使ってみようと思う。
    - 同じようなPET SHOPをオープンできるところをゴールにしたい。
    - プロセス中でアプリケーションへの理解を深めていきたい。
- 選択理由は以下、
    - 既に経験している人が多い。
        - [【TruffleでDapp開発】公式チュートリアル「ETHEREUM PET SHOP」で基礎を学ぶ](https://takuyafujita.hatenablog.com/entry/2018/08/15/0852361)
        - [はじめてのDapp開発 チュートリアル](https://note.mu/takezomiyamoto/n/ne121e99942a9)
    - Truffleというフレームワークがかなり便利らしく、細かいところで骨が折れなそう。より大きな流れとしてアプリケーションの動きを追えそう。
    - 今回はより"ユーザー"が使ってデータがネットワークに書き込まれるまでの一連の流れを追っていきたかった。
        - 例えば、スマートコントラクトのみの実装だけだと、その前に何が起こっているか不明なため。

# DAppsを支える技術達(どんな構成で成り立っているのか)を確認

- 初めてなので、まずは全体像の把握と整理からしたい。
- なんかやたら新しい(普段触れない)ツールが多くって、正しく把握しないと途中で困惑しそうだった。
    - geth? solidity? truffle? Ganache? MetaMask? Mist? Web3? RPC? Ethereum?これらそれぞれの責務と関係性など。ちんぷんかんぷんレベル。汗

#### 助けてくれた資料達

|No|タイトル|感想と補足解釈|
|:-----|:-----|:-----|
|1|[EthereumとContracts開発を取り巻くエコシステムの概要](https://blockchain.gunosy.io/entry/ethereum-contracts-system)|ツールの役割はこちらの記事を見れば一通り理解できた|
|2|「[10分で理解した気になるDApps入門 〜 Web3.0時代の次世代アプリケーション 〜](http://ykubot.com/2018/03/05/about-dapps-in-ten-minute/)」の「Ethereum DApps of Architecture」の画像|獏とだけど、ユーザー/front画面、MetaMask、Web3(JSのライブラリ)、Blockchain(EVM: ここでsolidityで書いたスマートコントラクトが実行される?)|
|3|「[ブロックチェーンEthereum入門 2](http://www.intellilink.co.jp/article/column/ethereum02.html)」の「Ethereumネットワーク監視の構成」の画像|2をよりシステム詳しく説明してくれている。|
|4|[スマートコントラクトを作成し実行する](https://book.ethereum-jp.net/first_use/contract.html)|SolidityをEMV上でどのように扱うのかが記載されている|

# 工程整理 - 粗め -
|No|カテゴリ|やること|
|:--|:--|:--|
|1|個人の開発環境にネットワークを準備、クライアントツールで疎通してみる|Ganache??, gethをバックグラウンドで動かしておく??|
|2|スマートコントラクトやらを作る|Solidity, Truffle|
|3|スマートコントラクトを１ネットワークにデプロイする||
|4|ブラウザからネットワークからデータを取得する??|MetaMask, Web3|
|5|ブラウザからネットワークにデータを書き込む??|MetaMask, Web3|
- 進めていく中でブレイクダウンしていければ...
- 
#### やらないこと
IPFS云々
### ということでがんばってみま〜す。
途中、ないし完了したら、Tipsのシェアができればと思います。

---
お読みいただきありがとうございました。
間違い、ないし、改善レビューがありましたらコメントいただけると嬉しいです。
Lubuntu 18.04  で Quartus Prime Lite を起動するまで

[Quartus Prime Lite](http://fpgasoftware.intel.com/?edition=lite) 18.1 を個別ファイルでダウンロードして、以下のようにインストール。必要なファイルをまとめて置いておくことで一気にインストールできる。個別にインストールするとパスが違ったりして面倒。

```
$ ls -1
cyclone-18.1.0.625.qdz
max10-18.1.0.625.qdz
ModelSimSetup-18.1.0.625-linux.run
QuartusLiteSetup-18.1.0.625-linux.run
$ ./QuartusLiteSetup-18.1.0.625-linux.run
```

# トラブルシューティング集

* libpng12.so.0: cannot open shared object file: No such file or directory
[How to fix “libpng12.so.0: cannot open shared object file: No such file or directory”?＠AskUbuntu](https://askubuntu.com/questions/978294/how-to-fix-libpng12-so-0-cannot-open-shared-object-file-no-such-file-or-direc) にそって libpng12をインストールする。

* Unable to lock chain (Insufficient port permissions)
[Unable to lock chain (Insufficient port permissions)@SO](https://stackoverflow.com/questions/18704913/unable-to-lock-chain-insufficient-port-permissions) にそって、パーミッションを開けてやって、USB Blaster を再接続してやる。

* No Hardware
jtagdがおかしくなっていることが多い。以下の手順で復旧できる：
 1. pkill jtagd で一回殺す。
 2. USB Blasterを抜く。
 3. FPGAの電源を切った状態で、USB Blaster を刺す。
 4. FPGAの電源を入れる。
 5. ./jtagconfig でエラーを吐かないことを確認する。
 5. Programmer の Hardware Setup を開き、USB Blaster を選択しなおす。
【fast.ai】 Callbacks API解説


# 概要

本記事はfast.aiのwikiの[Callbacks](https://docs.fast.ai/callbacks.html#List-of-callbacks)ページの要約となります。  
筆者の理解した範囲内で記載します。

公式ドキュメントには、

`fastai's training loop is highly extensible, with a rich callback system. `

とありますが、要は
**fast.aiのトレーニングループの中において、拡張性の高いcallbackシステムが組み込まれています。**

`Every callback that is passed to Learner with the callback_fns parameter will be automatically stored as an attribute. `

仕組みとしては、Learnerに`callback_fns`として引き渡された全てのcallbackは自動的に属性として呼び出すことができるようになっているらしい。

それでは、  

1. LrFinder
2. OneCycleScheduler
3. MixUpCallback
4. CSVLogger
5. SaveModelCallback  

以上の5つの実例を見ていきましょう。

# LrFinder

MNISTデータを用いる場合、

```python
path = untar_data(URLs.MNIST_SAMPLE)
data = ImageDataBunch.from_folder(path)
def simple_learner(): return Learner(data, simple_cnn((3,16,16,2)), metrics=[accuracy])
learn = simple_learner()
```

```python
learn.lr_find()
```

```python
learn.recorder.plot()
```

![1](../img/callbacks/1.png)  

Leslie Smith氏が考案なさった[learning rate finder](https://www.jeremyjordan.me/nn-learning-rate/)を用いて最適な学習率を探し出すことができます。  
この場合、グラフの谷底の少し後ろの`lr = 2e-2`が最適なLearning Rateだそう。（後日記事にて詳細を解説します。）  

# OneCycleScheduler

Leslie Smith氏の[1cycle annealing](https://sgugger.github.io/the-1cycle-policy.html)を実装したもの。

```python
learn.fit_one_cycle(3, lr)
```

```python
learn.recorder.plot_lr(show_moms=True)
```

![1](../img/callbacks/2.png)  

詳しくは[こちら](https://docs.fast.ai/callbacks.one_cycle.html)を参照。  
要は、Learning Rate と Momentum を反比例してtrainingしていく感じだと思う。

# MixUpCallback

```python
learn = Learner(data, simple_cnn((3, 16, 16, 2)), metrics=[accuracy]).mixup()
```

[Mixup: Beyond Empirical Risk Minimization](https://arxiv.org/abs/1710.09412)も同様に実装することができる。

# CSVLogger

```python
learn = Learner(data, simple_cnn((3, 16, 16, 2)), metrics=[accuracy, error_rate], callback_fns=[CSVLogger])
```

```python
learn.fit(3)
```

```python
learn.csv_logger.read_logged_file()
```

`callback_fns`に`[CSVLogger]`を付けるだけでこんな簡単に結果をcsvに出力できる。  

# SaveModelCallback

```python
learn = Learner(data, simple_cnn((3,16,16,2)), metrics=accuracy)
learn.fit_one_cycle(3,1e-4, callbacks=[SaveModelCallback(learn, every='epoch', monitor='accuracy')])
```

```python
!ls ~/.fastai/data/mnist_sample/models
```

> bestmodel_1.pth  bestmodel_2.pth  bestmodel_3.pth

こんな感じで毎epoch、もしくは最適なmodelを自動的に保存することができます！！すげえ！！

# 最後に

1. 他にも面白いcallbacksがあったのでpart2で紹介できていければと思います。
2. Learning Rate Finder や Mixup などの理論的背景を深掘りしていきたい。
3. 自作のモデルのチュートリアルをやってみる。

最後に  
間違いやご指摘などが御座いましたらご教示願います！
Python機械学習手遊び(GridSearchCVミニマムコード)

#この記事、何?

回帰でGridSearchCVを使ってみたくなった。
けど、よく上がっているのって流用しづらいのが多かった。
だからミニマムのコードサンプルを作ってみた。

#補足
データサイエンティスト・・・を目指すものとしては、GridSearchCVは道具。
道具の使い方が分かればそれでよし。
直接、公式サイトを見てもいいんだけど、組み合わせて使いたい「あれ」と「これ」が組み合わさったコードがあると助かる。

#使った「あれ」とか「これ」とか

■sklearn.cross_decomposition.PLSRegression
https://scikit-learn.org/0.19/modules/generated/sklearn.cross_decomposition.PLSRegression.html

■sklearn.model_selection.GridSearchCV
https://scikit-learn.org/0.19/modules/generated/sklearn.model_selection.GridSearchCV.html

■sklearn.svm.SVR
https://scikit-learn.org/0.19/modules/generated/sklearn.svm.SVR.html#sklearn.svm.SVR

#方針
単純化のため、回帰ロジックはPLSとした。
1個じゃ寂しいのでSVRを追加した。
予測を成立させるために、f(x,y,z) = x+y+z という単純な一次式を想定して予測させた。


#作ったコード

```python

#26-01.py
from sklearn.cross_decomposition import PLSRegression
from sklearn.model_selection import GridSearchCV
X = [[3,5,7], [1,2,3], [2,2,6], [0,3,5], [3,1,2], [4,3,8], [1,7,2]]
Y = [[15], [6], [10], [8], [6], [15], [10]]

params = [{'n_components':(1,2,3)}]

pls = PLSRegression()

clf = GridSearchCV(pls, params)
clf.fit(X, Y)

result = clf.cv_results_

print(result['params'])
print(result['mean_train_score'])

```

```python

#26-03.py
from sklearn.svm import SVR
from sklearn.model_selection import GridSearchCV
X = [[3,5,7], [1,2,3], [2,2,6], [0,3,5], [3,1,2], [4,3,8], [1,7,2]]
Y = [[15], [6], [10], [8], [6], [15], [10]]

params = [{'kernel':('linear', 'rbf')}]

pls = SVR()

clf = GridSearchCV(pls, params)
clf.fit(X, Y)

result = clf.cv_results_

print(result['params'])
print(result['mean_train_score'])

```

#出力
```
(PLS)
[{'n_components': 1}, {'n_components': 2}, {'n_components': 3}]
[0.90585749 0.99680841 1.        ]

(SVR)
[{'kernel': 'linear'}, {'kernel': 'rbf'}]
[0.9991696  0.35999864]

```

3つの変数を足しただけなのでPLSのn_components=3でscoreが1になるのは当然として、n_componentsが1や2の時のscoreがすごい。
やっぱりPLSが行列変換して都合がいい軸を作って合わせる仕様で、最初の1つ目の次元削減くらいどうとでも合わせられるということの表れのように思うわ。
逆にSVR。linearって言っているくらいだから、そっちはいいとしても、よく使われている(っぽい?)rbfのスコアが。。。
そりゃ、サンプル数があまりにも少なすぎということでしょ。



#この記事を書こうと思った理由(というか、愚痴。。)
GridSearchCV使っているのって、svcのコピペか、jupyterのいろいろ試して長いやつばかり。
jupyterから切って貼ったやつって、手元で動かそうとしても肝心な部分が抜けてたり、実行順に影響したりして初学者にとって難易度が高いものが多くてつらい。。。


#感想
時間不足を反省。
経験値が足らないなぁ・・・このくらいの記事を書くにも時間をかけてしまって。
というか、こういうのを書こうと思うくらい慣れが少なくて。
次の投稿は「GridSearchCVで評価してみた」で。
Expressのnextがわからないので調べる

# やること

Expressのrouting周りでよく見る`next`が一体何なのかよくわかっていないので調べる。

# コード

[GitHub](https://github.com/yoshida-san/js-mvc.git)
study-nextってブランチです。

# 公式ドキュメント見たりググったり

ミドルウェア関数を使う時にnextってするのか、なるほど。わからん。

# 書いてみる

[stackoverflow](https://stackoverflow.com/questions/27567119/typescript-express-middleware)
[teratail](https://teratail.com/questions/156658)

上記を参考に書いてみる。コードは[GitHub](https://github.com/yoshida-san/js-mvc.git)にありますので、必要があればそちらを参照ください。

```ts
import express from "express";
import hogeController from "./controller/hogeController";
const app = express();

app.set("view engine", "ejs");
app.set('views', './src/views')

class Foo {
    doPrivatefunc(req: express.Request, res: express.Response, next: Function): void {
        this.myFunc();
        next();
    }

    private myFunc(): void {
        console.log("myFunc");
    }
}
let foo = new Foo();

let bar = (req: express.Request, res: express.Response, next: Function): void => {
    console.log("bar");
    next();
}

let piyo = (req: express.Request, res: express.Response, next: Function): void => {
    console.log("piyo");
    next();
}

app.use(foo.doPrivatefunc.bind(foo));
app.use(bar);

app.get("/", (req: express.Request, res: express.Response, next: Function): void => {
    res.send("Hello world!");
});
app.get("/hoge", hogeController);
app.get("/hoge", (req: express.Request, res: express.Response, next: Function): void => {
    console.log("next 1 !!");
    next();
});
app.get("/hoge", (req: express.Request, res: express.Response, next: Function): void => {
    console.log("next 2 !!");
    next();
});
app.get("/hoge", piyo);

app.listen(3000, (): void => {
    console.log("listening on port 3000!");
});
export default app;
```

これを動かすと以下の結果が得られます。

```text
myFunc
bar
next 1 !!
next 2 !!
piyo
```

# 動かしてみて

ミドルウェア関数というのは皆が思う「一般的な関数」との認識で良さそう。
必要に応じて切り分けてメソッドチェーンみたいに繋いでいくイメージに近いのかも。getやpostの前にログを入れたりバリデーションかけたり使い所はありそうだけどnextで実装する必要があるかどうかはわからない。

# 終わり

どんな動きをするのかは何となくイメージ付いたけど何でnextを使うのか、どういう時にnextを使ったら良いのかあまりピンと来てない(´・ω・｀)
【Mac】git push heroku masterでusernameとpasswordを聞かれた際の対処

#問題
- herokuにpushを行おうとしたら、UsernameとPasswordを聞かれて、先に進めなくなった

#対応
- 結論的には、`heroku login` すれば解決する
- `heroku auth:token` で出てきたPasswordを通せば良い的な記事も見るが、Macでの開発環境では解決できなかった
  - ちなみに、打つと下記のようなerrorが吐き出される

```
›   Warning: heroku update available from 7.19.4 to 7.22.2
›   Warning: Invalid credentials provided.
›
›   Error ID: unauthorized
```
[自分用] gitHubへアクセスする鍵を複数登録する

# 前提
オンプレ版のgitHub等ですでに使っている鍵があるが、別の新たな鍵を作成し、その鍵を使ってgithub.comにアクセスしたい。

# 鍵の作成
すでに使っている鍵が`~/.ssh`があるので、以下のコマンドで鍵の名前を`-f`オプションで指定して別の鍵を作成する。

```
cd ~/.ssh
ssh-keygen -t rsa -C {メールアドレス} -f {鍵の名前}
```
ここで作成した鍵をgithub.comのアカウントページから登録しておく。

# SSHの設定
作成した鍵を使用してSSHを行う為に、`~/.ssh/config`ファイルに以下を追加する。

```
Host github.com
  HostName github.com
  User git
  Port 22
  IdentityFile ~/.ssh/{鍵の名前}
```

# 接続確認
以下のコマンドで正しく接続できるかを確認する。

```
ssh -T git@github.com
```

以下が表示されれば成功。

```
Hi {username}! You've successfully authenticated, but GitHub does not provide shell access.
```

# アカウントの設定
git管理されたリポジトリ内で以下のコマンドを使用することで、`~/.gitconfig`に記述された設定ではなく、個別にアカウント情報の設定をし、その設定を使用することができる。

```
git config user.name {ユーザー名}
git config user.email {メールアドレス}
```

ただし、以下のように`--global`オプションをつけると、`~/.gitconfig`の設定が変更されてしまうので注意。

```
git config --global user.name {ユーザー名}
git config --global user.email {メールアドレス}
```
Ubuntu18.04にVirtualBoxをインストール

# 概要

Ubuntu18.04にVirtualBoxを追加する手順。

# リポジトリ追加

```bash
$ sudo add-apt-repository "deb [arch=amd64] https://download.virtualbox.org/virtualbox/debian bionic contrib"
```

bionicはUbuntu18.04のこと。[arch=amd64] がCPUのアーキテクチャ指定。

# 公開鍵追加

```bash
$ wget -q https://www.virtualbox.org/download/oracle_vbox_2016.asc -O- | sudo apt-key add -
OK
```

成功するとOKと出る。そっけない。

# インストール

```bash
$ sudo apt-get update
$ sudo apt-get install virtualbox-6.0
```