OmniAICreator/Qiita-1.07M huggingface dataset:
Macのスクリーンショットをいろんな画像形式で保存してみよう

普段意識しないところではあるのですが、Macのスクリーンショットはデフォルトで.png保存されます。
後から拡張子を書き換えることもできるっちゃできるのですが、
「デフォルトでjpg」の画像ファイルが必要な要件があったため残しておきます。

#手順
1. ターミナルを起動

2. $`defaults write com.apple.screencapture type jpg`と入力

3. スクリーンショットを撮って「情報を見る」

4. jpgで保存されているのがわかります
<img width="367" alt="スクリーンショット 2020-04-10 17.11.38.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262145/d2a22a39-0ad0-a621-569f-a7bd4ec56c5d.jpeg">


#その他の拡張子でもいけるのか？
pngに戻すことはもちろん、gif、tiff、bmpが使用可能でした。
その他の拡張子をコマンドで指定すると、pngで保存されてしまうようです。


#参考
http://seotech.jp/837
Redmineのチケット一覧エクスポート時にInternal errorが発生


#事象
チケット一覧画面からフィルタでチケットを抽出し、
「他の形式にエクスポート」からファイルをエクスポートしました。

その際、「選択された項目」では正常に出力されましたが、
「すべての項目」を出力した際にInternal errorが発生しました。

#調査
- 「すべての項目」を選択してもエラーが発生しない場合もありました。
- オプションから、**表示項目を大量に選択した場合**、フィルタ適用時に同様のエラーが発生しました。
- エラーページのURLを見ると、パラメータ末尾が途中で切れていました。（末尾「cf_xxx」となるはずが「cf_」で終わっていた。）

#原因
**原因は、URLが最大桁数（2,083文字）に達したことでした。**

Redmineの仕様として、チケット一覧のフィルタや
エクスポートの条件には、条件をURLパラメータで渡して処理をしている様です。

今回は、以下の理由でURLが長くなっていたようです。
- フィルタの条件を大量に指定したこと。（特にプルダウン項目の複数指定）
- カスタムフィールドが増えすぎていること（200列弱）

#対策
- フィルタの条件を抑えてエクスポートし、GrepやExcelのフィルタ機能で処理する。
- 項目（列）を分割して出力し、後でマージする。
- カスタムフィールドを見直す。


エクスポート時、URLパラメータで条件を送る仕様な以上、
根本的な解決には、もうプラグインを作成するしかないような。。
最後の人がシャットダウンする運用だけど、Windows に誰がログインしているかわからない・・・。を解決する方法

# 背景

下記のようなスタイルで開発を進めています。

- 昨今の事情により、プロジェクトメンバーは基本テレワークで開発
- クラウドのWindowsに複数人でログインして作業
- 最後の人がWindowsシャットダウン

# やりたい事

今までは、オフィスで開発していたので、声かけあって最後の人がシャットダウンしてたけど、テレワークになってわざわざチャット確認するのも手間まなのと、すぐに確認取れないこともあるので、「だれがログインして利用しているのか」をコマンドで確認する方法を紹介します。

# やり方

コマンドプロンプトを開いて"query session"と打つだけ。

結論からいうと、自分のrdp-tcp のセッションだけがActiveの状態であれば、他の人はログインしていないので、個人的にはシャットダウンしてOKとしています。

### Administrator, user01 がログインして利用中の際の実行例
rdp-tcp セッションにユーザが表示され、状態がActiveになっています。

```
C:\Users\user01.EC2AMAZ-CQCAJLU>query session
 セッション名      ユーザー名               ID  状態    種類        デバイス
 services                                    0  Disc
 console                                     1  Conn
>rdp-tcp#17        user01                    4  Active
 rdp-tcp#14        Administrator             5  Active
 rdp-tcp                                 65536  Listen
```

### user01がログインして利用中で、AdministratorがログオフせずにRDPの画面を閉じた状態の実行例
Administrator の状態がDiscになっています。


```
C:\Users\user01.EC2AMAZ-CQCAJLU>query session
 セッション名      ユーザー名               ID  状態    種類        デバイス
 services                                    0  Disc
 console                                     1  Conn
>rdp-tcp#17        user01                    4  Active
                   Administrator             5  Disc
 rdp-tcp                                 65536  Listen
```

正直、Discの状態だと、作業中だけどRDPの画面を切っただけなのか、本当に作業が終わったのか分からないのです。
その場合は、ユーザを利用している人に確認してあげるのが一番親切ですが、、


### 他人のセッションにログインする
ログインしたいセッションのユーザのパスワードがわからないとできませんが、こんな方法もあります。
query session で確認できるセッションのIDに対して tsconを実行します。

```
C:\Users\user01.EC2AMAZ-CQCAJLU>tscon 5 /password:パスワード
```

・・・そこまですることはないと思いますが、こういった方法もあります。
ちなみに、Activeの状態であってもtsconでセッション奪うことが可能です。

### 最後に自動化
Acitveのrdp-tcpセッションがなかったらシャットダウンするバッチかパワーシェルつくって、20時以降15分おきにループ実行されるように仕込んだら楽だなーと思いつつ、そこまでは作ってないです。
バッチファイルをやめてPowerShellにするメモ

# はじめに
環境構築が要らないとはいえバッチファイルなんて書きたくない人のためメモです。
私見ですがおススメの理由は3つです。

- バッチファイルに比べて書きやすい（遅延環境変数とか考えなくて済む）
- Visual Studio Codeでデバッグできる
- 最悪メモ帳でも編集できる

複雑な処理は実行ファイル作った方がいい部分も多いので、上手く住み分けることが大切かなと思います。

# この記事で紹介すること
```
hoge/
　├ hoge1/
　　　　　hoge1_1.txt
　　　　　hoge1_2.txt
　├ hoge2/
　　　　　hoge2_1.txt
　　　　　hoge2_2.txt
　└ hoge3/
　　　　　hoge3_1.txt
　　　　　hoge3_2.txt
```
このような構成で```_1.txt```ファイルだけを対象に処理を行う方法です。

参考にさせていただいたサイトは[こちら](http://suyamasoft.blue.coocan.jp/PowerShell/Tips/File/GetChildItem/index.html)

# フォルダやファイルを取り出す
```find.ps1
# チェックするフォルダのフルパス.
$searchPath = "***\hoge"

# hoge_*のフォルダ名取得（一応directoryに限定）.
$dirPath = Get-ChildItem -Path $searchPath -Directory -Filter hoge? 

# 出力.
Write-Host $dirPath[0].Name
Write-Host $dirPath[0].FullName
```

これを実行すると、

```
Name: hoge1
FullName: ***\hoge\hoge1
```

と出てくるので、Nameにフォルダ名, FullNameにそのパスが入ることがわかります。
[参考サイト](http://suyamasoft.blue.coocan.jp/PowerShell/Tips/File/GetChildItem/index.html)に記載されている通り```-Filter hoge? ```でフィルタをかけ、欲しい名前のものだけを取り出しています。

あとはこれをループさせるだけです。

# 実際に作ったものとハマった部分

```hogehogefind.ps1
# チェックするフォルダのフルパス.
$searchPath = "***\hoge"

# hoge_*のフォルダ名取得（一応directoryに限定）.
$dirPath = @(Get-ChildItem -Path $searchPath -Directory -Filter hoge? )

for ($i = 0; $i -lt $dirPath.Length; $i++) 
{
    # _1,_2などのファイル名取得.
    $textName = @(Get-ChildItem -Path $dirPath[$i].FullName -File -Filter hoge?_1.txt)

    for ($j = 0; $j -lt $textName.Length; $j++) 
    {
        Write-Host $textName[$j].FullName
    }    
}
```

基本的には```find.ps1```をフォルダ, ファイルに対して実行するだけですが、```$dirPath = @(Get-ChildItem -Path $searchPath -Directory -Filter hoge? )```だけ変更してあります。
[こちら](http://winscript.jp/powershell/131)に記載されておりますが```Get-ChildItem```はファイルが1つしか見つからなかった場合に配列を返してくれないので、```$textName.Length```が0になってしまいfor文に入らないのです。

ファイル操作などを行う場合は```Write-Host```の部分をexeなどに変えて行うことができます。

追記
コメントにありますように配列にならない件は```foreach```やパイプラインを使うことで解決できました！ありがとうございます！

# おまけ
- PS1を実行するバッチ.（ご指摘いただき ```-File``` を追記いたしました）

```run.bat
powershell -NoProfile -ExecutionPolicy Unrestricted -File .\hogehogefind.ps1
```
t検定とは？ 数式なしで感覚的に理解するための記事

この記事は、統計初心者のために数式を一切使わずに「t検定」について説明した記事です。
実在する会社や団体とは一切関係ありませんのでご注意ください:sweat:

## t検定とは

t検定とは、**「平均値の差が意味のある差なのか」**を検証する方法です。

例えば、ス●ードラーニングという教材を使って英語を勉強する場合を考えてみましょう。

5人のグループを2組用意して、片方はス●ードラーニングで、もう一方は普通の教材で勉強させます。1週間後にテストを受けて2つのグループの点数を比較するという実験を行いました(架空の話ですよ！)

|  ス●ードラーニング組の平均点  |  普通の教材組の平均点  |
| ---- | ---- |
|  80  |  70  |  

このような結果が出たとの広告を見たとき、あなたはス●ードラーニングを購入しますか？
ス●ードラーニングが優れた教材だから差がついたのか、個人差のばらつきの範疇なのかわかりませんよね。10点の差が「意味のある差」つまり**有意差**なのかどうかの判断が必要です。

このような判断を行うときにt検定が活躍します。

## データのばらつきと有意差
平均値は同じでも、データのばらつきによって有意差があるかどうかは変わってきます。

|  ス●ードラーニング組の点数  |  普通の教材組の点数  |
| ---- | ---- |
|  80  |  65  |  
|  85  |  70  | 
|  75  |  68  | 
|  82  |  70  | 
|  78  |  72  | 

この結果を見ると、ス●ードラーニングは効果ありそう。

|  ス●ードラーニング組の点数  |  普通の教材組の点数  |
| ---- | ---- |
|  100  |  90  |  
|  90  |  70  | 
|  70  |  70  | 
|  70  |  70  | 
|  70  |  50  | 

一方この場合だと、「たまたまス●ードラーニング組に頭がいい子がいただけちゃう？」ってなりますね。

平均値が同じでも、データのばらつきによって「集団による差」なのか「個人による差」なのかが変わってきます。

t検定はこの部分を見抜くために使われます。


## t検定のざっくりとした手順
### 1. 帰無仮説を立てる
高校数学の「背理法」って覚えてますか？
「1は整数ではない」ことがありえないと証明することにより、「1は整数である」が正しいことを証明するという方法でしたね。

t検定の**帰無仮説**はそれと良く似た考え方です。
「二つのグループの間に差はない」という**帰無仮説**を立て、これを否定(**棄却**)できたら「二つのグループに有意差がある」とみなします。

上の例を挙げると、「ス●ードラーニングをやった組とやってない組の間に有意な差はない」という仮説を立てるわけです。

### 2. 「p値」を求める
次に、p値を計算します。
p値とは、「ス●ードラーニングをやった組とやってない組の間に有意な差はない」という帰無仮説があるにもかかわらず、

|  ス●ードラーニング組の点数  |  普通の教材組の点数  |
| ---- | ---- |
|  80  |  65  |  
|  85  |  70  | 
|  75  |  68  | 
|  82  |  70  | 
|  78  |  72  | 

このような実際に起こった結果を生む確率のことです。

p値というと難しいですが、ただの確率です。「p=0.3」なら30％の確率ということです。
「差がないのに実際に起こった事実が起こるのはどれだけ珍しいのか」という数値。


ここでは感覚的な理解を目的としているので数式は省略しますが、
p値は、平均値およびデータのばらつきから計算されます。

### 3. 有意水準とp値を比べる
**有意水準**とは、「これは珍しすぎてありえない！」という基準のことです。
この数字は通常5%と決められています。これは統計界の決まり事です。

>有意水準=一律5%

先ほど計算したp値は「2グループの差がないのにテスト結果がああなる確率」でした。

この確率が「5%以下」なら「これは珍しすぎてありえない！」といえるわけです。
その結果、「二つのグループの間に差はない」という帰無仮説が棄却され、「ス●ードラーニングは有意に英語の成績を上げる」ということが言えるわけです。

逆に、p値が「5%以上」なら「2グループの差がないのにテスト結果がああなる可能性もある」ということになり、「ス●ードラーニングは有意に英語の成績を上げるとは言い切れない」という結果になります。

実際にp値をもとめてみましょう。p値は、手動で計算することは難しいですが、エクセルの分析ツールなどを使えば簡単に求めることができます。

|  ス●ードラーニング組の点数  |  普通の教材組の点数  |
| ---- | ---- |
|  80  |  65  |  
|  85  |  70  | 
|  75  |  68  | 
|  82  |  70  | 
|  78  |  72  | 

この例の場合、p=0.004。
「二つのグループの間に差はない」のにこのような分布になる確率は0.4%ということ。
この場合は「ス●ードラーニングは有意に英語の成績を上げる」と断言できるでしょう。

|  ス●ードラーニング組の点数  |  普通の教材組の点数  |
| ---- | ---- |
|  100  |  90  |  
|  90  |  70  | 
|  70  |  70  | 
|  70  |  70  | 
|  70  |  50  | 

この例の場合、p=0.266。
「二つのグループの間に差はない」のにこのような分布になる確率は26.6%以下もあります。
この場合は「ス●ードラーニングは有意に英語の成績を上げる」とは言い切れません。


##まとめ
ご覧いただきありがとうございました。
難しい内容なので、ざっくり理解していただけたらOKです。
ちなみに、ス●ードラーニングはきっと有意に効果がある教材だと思います！笑
Google Colab で kaggle APIを使う




ColabからKaggleのデータセットを使用する方法をメモしておきます。


## 事前にやること
1. Kaggleのアカウントページの**API**から`kaggle.json` をダウンロードする。
2. ダウンロードしたファイルをColabにアップロードする。 

## Colab上でコマンド実行

[Kaggle API with Colab](https://colab.research.google.com/drive/1eufc8aNCdjHbrBhuy7M7X6BGyzAyRbrF#scrollTo=y5_288BYp6H1&forceEdit=true&offline=true&sandboxMode=true)を参考にしました。

まず kaggle パッケージをインストールします。
ちなみに Colab で コマンドを使用する時は、 `!cd`とか`!ls` のように先頭に!をつけて実行します。

```
!pip install kaggle
```

次に Kaggle API をセッティングします。

```python
from googleapiclient.discovery import build
import io, os
from googleapiclient.http import MediaIoBaseDownload
from google.colab import auth


auth.authenticate_user()

drive_service = build('drive', 'v3')
results = drive_service.files().list(
        q="name = 'kaggle.json'", fields="files(id)").execute()
kaggle_api_key = results.get('files', [])

filename = "/root/.kaggle/kaggle.json"
os.makedirs(os.path.dirname(filename), exist_ok=True)

request = drive_service.files().get_media(fileId=kaggle_api_key[0]['id'])
fh = io.FileIO(filename, 'wb')
downloader = MediaIoBaseDownload(fh, request)
done = False
while done is False:
    status, done = downloader.next_chunk()
    print("Download %d%%." % int(status.progress() * 100))
os.chmod(filename, 600)

```

```terminal
Download 100%.
```

無事ダウンロード完了です。これで、Colabから Kaggle APIが使えます。


コンペのページからデータをダウンロードしてみます。赤枠の部分をそのままコピーしてコマンドラインに貼り付けます。




<img width="781" alt="Screenshot 2020-04-10 at 16.42.24.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407366/f30eb2e9-b06a-2511-df49-f305efd8433a.png">


```python
!kaggle competitions download -c web-traffic-time-series-forecasting
```


```terminal
Downloading train_1.csv.zip to /content
 98% 100M/102M [00:00<00:00, 78.9MB/s] 
100% 102M/102M [00:00<00:00, 111MB/s] 
Downloading key_2.csv.zip to /content
 91% 92.0M/101M [00:00<00:00, 85.9MB/s]
100% 101M/101M [00:00<00:00, 115MB/s]  
Downloading train_2.csv.zip to /content
 87% 130M/150M [00:01<00:00, 67.9MB/s]
100% 150M/150M [00:01<00:00, 94.2MB/s]
Downloading key_1.csv.zip to /content
 97% 93.0M/96.0M [00:00<00:00, 64.4MB/s]
100% 96.0M/96.0M [00:00<00:00, 110MB/s] 
Downloading sample_submission_2.csv.zip to /content
 91% 62.0M/68.2M [00:00<00:00, 55.1MB/s]
100% 68.2M/68.2M [00:00<00:00, 91.4MB/s]
Downloading sample_submission_1.csv.zip to /content
 76% 50.0M/66.0M [00:00<00:00, 43.3MB/s]
100% 66.0M/66.0M [00:00<00:00, 79.8MB/s]
```
ダウンロード完了です。
zipファイルのデータは unzipします。

```terminal
!unzip train_1.csv.zip -d train_1.csv
!unzip key_1.csv.zip -d key_2.csv
```

これで、Colabから kaggleの csvデータが使えるようになりました！

他にも Kaggle APIには便利な機能が色々あるみたいなので、詳しくは GitHubにあげられている Kaggle APIのREADMEをご参照ください。↓
https://github.com/Kaggle/kaggle-api
初心者がVSCodeのターミナルが別Windowで表示されてハマった話

新しいPCを買ってうきうきでセットアップをしてたらVSCodeでハマった話。
なんで、ターミナルが別Windowで表示されるの、、、？
デフォルトの設定間違ってない、、、？？？？

### 環境
Windows 10 Home
Visual Studio Code 1.44.0(user setup)

## 事象（VSCodeでターミナルが別Windowsで起動する）
ただ、”hello world”を表示させたかっただけなのに、なんだこれは:innocent:
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206754/fc8e03b5-1eef-5fec-0994-9dc204a2c2d8.png)

こんなものは求めていないので、コマンドプロンプトを”×”で閉じると、VSCodeの右下にエラーぽいのが表示される。

`システムで従来のコンソール モードが有効になっているため、端末が正しく起動されませんでした。これを修正するには、"従来のコンソールを使用する" cmd.exe のプロパティをオフにします。`
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206754/74b1c87b-5eb7-b868-8ad5-511efbc1aa0c.png)


## 解決策（コマンドプロンプトのオプションを1箇所変更する）
ものすごく簡単に解決します。
こんなので半日もかかったら、エンジニア失格ですね（わたしはエンジニア失格です:relaxed:）

**コマンドプロンプトを起動してオプションを表示して、以下のチェックを外しましょう。**
ちなみに、Windowsの再起動はしなくても大丈夫でした。（たぶんコマンドプロンプトの再起動のことを指してる）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206754/f06fe51d-b8b9-a5cb-797b-8c1afb5e466b.png)

そうすると、あら不思議
VSCodeだけで”hello world”が表示されるように。これだよこれ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206754/e72d65fa-d4b5-275b-15cd-2e31c43d0a92.png)
パケット交換とは

#パケット交換とは
　大きなデータをパケットと呼ばれる単位に分割して、送信する仕組み
##パケットの中身
　・データの番号
　・宛先アドレス
　・送信元アドレス
　　　⇒ヘッダーと呼ばれる

　・小分けにされたデータ
　・データの分割元の情報

##ポイント
　情報の受け手と送り手がヘッダの定義・解釈を共有しておく必要がある
　　⇒データの中身を正しく解読するため
Vimの移動系コマンドをまとめてみる＞＜



# はじめに

もともとCLion+IdeaVimや、Pycharm+IdeaVimを使用していたのですが
Vimをきちんと勉強したいなと考えて

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211482/2b870f16-4bfa-aa97-494f-47e3d5878253.png)


ゴリラさんの「[Vimが好きになる本](https://booth.pm/ja/items/1513974)」を購入しました。

それを読みながらVimを勉強しています。

今回は本に載っている、載っていないに関わらず
自分用に「移動」や「モーション」に関するコマンドをまとめようと思います＞＜

# ノーマルモード

ノーマルモードは、いわゆるEscを押した状態で基本状態、卓球で言う構え状態ですね＞＜
（どの体勢にも移れるみたいな感じです）

この状態での移動をまとめておきます。

## カーソルの移動

### 1文字単位の移動

| Command | 説明 |
|:---:|:---:|
|h | 左に1だけカーソルを移動する |
|j | 下に1だけカーソルを移動する|
|k | 上に1だけカーソルを移動する|
|l | 右に1だけカーソルを移動する|


### 単語(文) 単位の移動

| Command | 説明 |
|:---:|:---:|
|w | 次の単語の先頭へ移動する |
|e |単語の末尾へ移動する|
|b | 前単語の先頭へ移動する|
|ge | 前単語の末尾へ移動する|
|w, e, b, geの大文字| 連続した文字列(非空白)を大きい一つの単語として見たときの移動|

### 大胆な移動


| Command | 説明 | 意味|
|:---:|:---:|:--: |
|0| カーソルのある行の先頭 |
|^| カーソルのある行の空白文字でない最初の文字 |
|$| カーソルのある行の末尾|
|+|次の行の最初の文字へ移動|
|-|前の行の最初の文字に移動|
|{count}G|{count}行に移動する|
|G|ファイルの末尾に移動する|
|gg|ファイルの先頭に移動する|
|H|現在の画面の上端に移動する| High|
|M|現在の画面の中央に移動する| Middle|
|L|現在の画面の下端に移動する|Low|
|zz|今のカーソルの位置が画面中央に来るようにスクロールする|
|zt|今のカーソルの位置が画面上に来るようにスクロールする|
|zb|今のカーソルの位置が画面下に来るようにスクロールする|
|Ctrl + o)|ジャンプリストのうち[count]だけ古いカーソル位置への移動|Older|
|Ctrl + i)|ジャンプリストのうち[count]だけ新しいカーソル位置への移動|キーボードでOの隣|

### 段落の移動

| Command | 説明 |
|:---:|:---:|
|{|カーソル行の上にある最初の空行||
|}|カーソル行の下にある最初の空行||
|(|カーソル行を含む段落の最初の文字||
|)|カーソル行を含む段落の最後の文字||


### 対応列の移動

| Command | 説明 | 
|:---:|:---:|
|%|対応する括弧への移動|

### 検索の移動

| Command | 説明 | 
|:---:|:---:|
|f[文字]|今の行にあるカーソルより右側の検索文字に移動する|
|F[文字]|今の行にあるカーソルより左側の検索文字に移動する|
|g;|直前[count]分に「変更を行った変更リスト」位置にカーソルを移動する|
|g,|直後[count]分に「変更を行った変更リスト」位置にカーソルを移動する|
|*|カーソルのある単語を検索して「n N」で移動する|
|/{pattern}|{pattern}を検索する nで下方向に移動する Nで上方向に移動する|
|?{pattern}|{pattern}を検索する nで上方向に移動する Nで下方向に移動する|
|||

## ページの移動


| Command | 説明 |  意味|
|:---:|:---:|:---: |
|Ctrl + f|1ページ進める|Front|
|Ctrl + b|1ページ戻る|Back|
|Ctrl + u|1/2ページ進める|Up|
|Ctrl + d|1/2ページ戻る|Down|
|Ctrl + y|1行戻る|Eと近いから？|
|Ctrl + e|1行進める|Extra lines|


# 参考文献

- [【入門】Vimで高速で移動~プラグインなしでの移動まとめ~](https://qiita.com/takeharu/items/9d1c3577f8868f7b07b5#%E5%A4%96%E9%83%A8%E3%82%A2%E3%82%AB%E3%82%A6%E3%83%B3%E3%83%88)
- [Vim初心者なのでカーソル移動まとめてみた](https://qiita.com/tpywao/items/bd119f0075e40d47c88b)
- [カーソル移動を爆速化してVimを制覇する](https://qiita.com/yasuo-ozu/items/0cddf0ba3ac6f7ad2a1d)
- [Vimの使い方 基本操作まとめ](http://motw.mods.jp/Vim/command.html) すごい丁寧！
- [Vim Mnemonic | Vim のコマンドの覚え方大全](http://haya14busa.com/vim-mnemonic/) すごい丁寧！
VPN時にGoogle Meet等の通信をVPNスルーさせる設定(IPv4 Only)

IT系企業の方は多くの方が在宅勤務を余儀なくされている今日このごろかと思います。
オンラインでのビデオMTGありますよね。

VPNにつないだままMeetやZoomに接続すると、VPNルータや回線に大きく負荷がかかってしまいます。
そのため、弊社ではCTOより`Meetにつなぐ際にはVPNを切るように`という指示が出ています。

でも、MTGのときにいちいちVPN切ったり、MTG終わったらVPNつなぎ直したり、超めんどくさくないですか？
そのお悩みを解消するためのスクリプトを書いてみました。

ちなみに、macOS Mojave, Catalinaでの動作を想定しています、
理論上はこれで経路分離できるはず。

Wi-Fi等のネットワークが変わった際にはスクリプトを再度流してやる必要があります。

```bash:vpnroute.sh
#!/bin/bash

# Default Gatewayの取得
ROUTE=$(route -n get 0.0.0.0 | grep gateway)
echo ${ROUTE}
# 区切り文字をコロンに変更
IFS=': '
# 取得したDefault Gatewayを変数に代入
set -- ${ROUTE}
GATEWAY=$2

# 以下指定経路をVPN通さないようにする
# Google Meet
sudo route add -net 74.125.250.0/24 ${GATEWAY}
# Amazon Chime
sudo route add -net 99.77.128.0/18 ${GATEWAY}
sudo route add -net 13.248.147.139/32 ${GATEWAY}
sudo route add -net 76.223.18.152/32 ${GATEWAY}
sudo route add -net 3.80.16.0/23 ${GATEWAY}
sudo route add -net 52.55.62.128/25 ${GATEWAY}
sudo route add -net 52.55.63.0/25 ${GATEWAY}
sudo route add -net 34.212.95.128/25 ${GATEWAY}
sudo route add -net 34.223.21.0/25 ${GATEWAY}
sudo route add -net 99.77.253.0/24 ${GATEWAY}

# Zoom
sudo route add -net 207.226.132.110 ${GATEWAY}
sudo route add -net 162.255.37.11 ${GATEWAY}
sudo route add -net 162.255.36.11 ${GATEWAY}
sudo route add -net 221.122.88.195 ${GATEWAY}
sudo route add -net 115.114.131.7 ${GATEWAY}
sudo route add -net 213.19.144.110 ${GATEWAY}
sudo route add -net 103.122.166.55 ${GATEWAY}
sudo route add -net 209.9.211.110 ${GATEWAY}
sudo route add -net 64.211.144.160 ${GATEWAY}
sudo route add -net 69.174.57.160 ${GATEWAY}
```
SPSS Modelerで列名を正規表現で変更する

Modelerでたくさんの列名に似たような変換をしたいことがあります。
そういう時にはModelerスクリプトで正規表現を使えば簡単に行うことができます。

例えば以下のように集計をした後の「_Sum」の文字を一括で取り除きたいとします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/f4a1737b-b292-ffd7-44ab-6ec5456b8566.png)

ツールのストリームのプロパティ―の実行でスクリプトのエディタを開きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/50a97728-926b-19a0-0987-80ebe317331e.png)

スクリプトが「Python」になっていることを確認し、以下のPythonコードを貼り付けます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/eb0d736e-9da4-54e7-2a9f-bce771d930db.png)

```python
import modeler.api
import re
stream = modeler.script.stream()
#フィルターをつなげたいノード名を指定します。。例はレコード集計
startnode   = stream.findByType(None, u"レコード集計")
filternode  = stream.createAt("filter",u"列名変更", startnode.getXPosition() + 120, startnode.getYPosition())
stream.link(startnode, filternode)

for c in filternode.getOutputDataModel().columnIterator():
    originalName = c.getColumnName()
    #置き換えたい文字列を指定。例は_sum
    p = re.compile('_Sum')
   #置換後の文字列を指定。例は''なので消去を意味します
    changedName = p.sub('',originalName)
    filternode.setKeyedPropertyValue("new_name", originalName, changedName)
```

貼り付けたら「このスクリプトを実行」ボタンをおして実行してみましょう。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/64af62ee-8e1d-3295-bf43-b0cf0087b70f.png)

「列名変更」というフィルターノードが追加されています。
プロパティをみると「_sum」の文字列が取り除かれています。
「プレビュー」ボタンをクリックして、プレビューを確認してみましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/8df23aa1-627c-1bc9-1349-d7323fec4e41.png)

全ての列名から「_Sum」の文字列が取り除かれました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/359c114c-e86b-f437-9329-209466f32d78.png)

少しプログラムを見てみます。
以下の行でフィルターノードを連結するノードを指定しています。「_Sum」は「レコード集計」ノードの処理後に付加されるので、「レコード集計」ノードの後ろにつけています。

```python
startnode   = stream.findByType(None, u"レコード集計")
```

以下の部分で文字列の置き換えをしています。
p = re.compile('_Sum')の'_Sum'が置換の対象文字です。
changedName = p.sub('',originalName)の''が置換後の文字です。これは空文字なので結果的には文字を消去するという意味です。

```python
    #置き換えたい文字列を指定。例は_sum
    p = re.compile('_Sum')
   #置換後の文字列を指定。例は''なので消去を意味します
    changedName = p.sub('',originalName)
```


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/a4d47a33-dffe-75e4-56ea-1a0c0ab37244.png)

正規表現が使えるので様々な変換ができます。
例えば
p = re.compile('_.+')
とすれば、'_Sum'も'_Mean'も'_Sdev'もすべて変換対象にできます。

以下の記事などを参考にしてください。
正規表現 HOWTO
https://docs.python.org/ja/2.7/howto/regex.html#search-and-replace

サンプルのStreamファイルは以下にあります。
https://github.com/hkwd/spsssample/raw/master/200410%E5%88%97%E5%90%8D%E5%A4%89%E6%9B%B4modeler%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%97%E3%83%88/200410%E5%88%97%E5%90%8D%E5%A4%89%E6%9B%B4modeler%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%97%E3%83%88.str

## テスト環境
SPSS Modeler 18.2.1
Windows 10
自分のサイトにYouTubeのチャンネル登録のボタンを埋め込む

# はじめに
YouTubeにログインして、Subscribe Buttonの「ボタンを設定する」で設定します。
下記のURLから飛べます。
https://developers.google.com/youtube/youtube_subscribe_button

# 設定
オプションの中の「チャンネル名または [ID](https://www.youtube.com/account_advanced?hl=ja)」の所に、自分のチャンネル名または [ID](https://www.youtube.com/account_advanced?hl=ja)を入力します。チャンネル名が分からない人は、[ID](https://www.youtube.com/account_advanced?hl=ja)のボタンを押すと、[自分のIDが分かる場所](https://www.youtube.com/account_advanced?hl=ja)に移動します。
設定したら、[プレビュー]()のボタンを押してみて、ちゃんと反映されているか確認できます。
<img width="948" alt="スクリーンショット 2020-04-10 午後4.09.10.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216701/d9275f63-ce42-4328-6af0-ecd1522fa0b4.png">

#　細かい設定
- レイアウトでは、「フル」にすると、トップの画像と名前を表示することができます。
- テーマでは、「ダーク」にすると、バックグラウンドを黒区する事ができます。
- チャンネル登録者数では、「非表示」にすると、数字を隠すことができます。

# 最後に
テーマ、チャンネル登録コードに書いてあるコードを、ご自身のサイトに入れるだけです。

```sample.html
<script src="https://apis.google.com/js/platform.js"></script>

<div class="g-ytsubscribe" data-channel="NJTVnetwork" data-layout="full" data-theme="dark" data-count="hidden"></div>
```
正しく表示されて、ページ遷移できれば成功です。
``` data-channel```の部分を自分の「チャンネル名または [ID](https://www.youtube.com/account_advanced?hl=ja)」に変更すれば、そのまま使えると思います。
履歴を残したままサブディレクトリをリポジトリに昇格させる

# 前提
`git@github.com:mafuyuk/infra.git`というリポジトリが存在し、その配下にインフラ関係のものをサブディレクトリを切り詰め込んでいた(とする)

```sh
$ tree -L 1                                                                                                                  
.
├── ansible
├── eksctl
├── k8s
└── terraform
```

k8sのマニフェストはCI/CDのタイミングなどによって別でリポジトリ立てたいなーけど、履歴もちゃんと持っていきたいなーってときにした対応方法の備忘録

# 手順
###1 GitHubでリポジトリを新規で作成し、URLを取得しておく 
  ex) `git@github.com:mafuyuk/manifest.git`

###2 履歴を残したままサブディレクトリをリポジトリに昇格させる

```sh
$ git remote add manifest git@github.com:mafuyuk/manifest.git                                                       
$ git subtree push --prefix k8s manifest master
```

###3 掃除

```sh
$ git remote remove manifest
$ rm -rf k8s
```
スターウォーズを読んで初めて知ったこと

#エピソード1　ファントムメナス


####・このころのタトゥイーンの支配者はジャバ・ザ・ハットではなく、ガーデュラ・ザ・ハット。ジャバの親友でもあり、ライバルでもある。性別は女。

####・このころのアナキンの友達のローディアンはグリードではなく、ウォルド。


####・*C-3POの3は3人目の家族という意味を込めてアナキンが名付けた。*

####・本書のあとがきに「アナキン・スカイウォーカーが暗黒面に堕ちていく壮大な物語をぜひお楽しみください」という壮大なネタバレが書かれてる。
float(css)についてまとめる。

#floatについて
floatは浮かせて、左や、右によせる。
よって、浮いているので、特に指定のない限り、要素が上に詰めて配置されてしまう。
そこで浮かせた後の要素に以下の要素を追加する必要がある。
###html

```
<div id="under"></div>
```
###css
```
#under{
  /* float: leftされた要素を解除 */
  clear: left;
}
```

これだと、 floatを使うたびに要素を追加し、cssにも追加が必要。
よって一般的には以下のコードを使う。(親要素にclass="clearfix"を追加しとく）
###css

```
clearfix:after {
  content: "";
  display: block;
  clear: both;
}
```
[Unity]ARCoreのmin_apk_versionでつまづいた話

## はじめに
PlayConsoleでapkファイルをアップロードしようとしたら，こんなエラーが出てしまった．
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/487681/7b81fc72-9031-d105-b883-861cf553bdd4.png)

今回はこのエラーをどうやって解消して無事にリリースできたかを書いていきます．

※いろんな方法でやってみましたが，失敗していた方法もあるので参考程度に見てください．

Unityのバージョン: 2018.4.1.f1
Vuforiaのバージョン: 8.3.8
### 方法1:(失敗した)
http://nn-hokuson.hatenablog.com/entry/2019/09/05/221336　
の真ん中にある記事`ARCoreのmin_apk_versionでひっかかる`を参考にaarファイルを設置してみます．
記事にある`core-1.9.0.aar`と最新版1.16.0の両方を試しました．
ARCoreの最新版は，
https://github.com/google-ar/arcore-unity-sdk/releases　
にありダウンロードして，Unityに.unitypackageをインポートします．
この時のバージョン番号(ex)1.16.0)で下のリンクを開きダウンロードします．

```
https://dl.google.com/dl/android/maven2/com/google/ar/core/core-<バージョン番号>.aar

ex) https://dl.google.com/dl/android/maven2/com/google/ar/core/core-1.16.0.aar
```

ダウンロードされたファイルを`Assets/Plugins/Android/`以下において終わりです．Androidのフォルダがない時は手動で作成しても問題ないです.

この状態でビルドしてアップロードを試みても，同じエラーがでて解消されませんでした．

### 方法2:(これも失敗)
方法１で試して失敗したので，別の方法を試みました．
似たような事例で,https://teratail.com/questions/242175 があったので，同じようにやってみました．
`Window/Vuforia Configuration`を開き(Ctrl+Shift+V)，ARCore Requirementの項目を`DONT_USE`に変更します．

これでビルドしてアップロードしてもまたエラーが出た．

### 方法3:これは成功！
Vuforiaのフォーラムで似たような事例を発見．
https://developer.vuforia.com/forum/unity/play-store-submission-error-comgooglearcore
ここでも方法1でいっているやり方をとっている人もいれば，同じように方法１で失敗している人もいる．

この中に書いてあったAndroidManifest.xmlに書き込む方法を行う．
AndroidManifest.xmlは`Assets/Plugins/Android/`のなかにあります．
(ない方は,いったんアプリをビルドした後に，`プロジェクト/Temp/StagingArea/AndroidManifest.xml`をコピーすればいいです．)

このAndroidManifest.xmlに

```AndroidManifest.xml
<meta-data android:name="com.google.ar.core.min_apk_version" android:value="24" />
<meta-data android:name="com.google.ar.core" android:value="optional" />
```

を書き込みます．書き込む場所は`<application android:label ...>ここ！</application>`です．ここ！のところに書けば大丈夫です．

これでビルドしアップロードすると無事に成功しました．

## さいごに
方法１,２でなぜ成功していないかはまだ分かっていません．しかし方法3で無事に成功してよかったです．

https://library.vuforia.com/content/vuforia-library/en/articles/Solution/arcore-with-vuforia.html によると，Vuforia8.5.8から，ARCoreが自動的に処理されるみたいなので，実はアップデートするほうが楽だったのかもしれません...
[html] すべてのタグの前後で改行させたい

### find

```
[\r\n\s]*(<[^>]+>)[\r\n\s]*
```

### replace

```
\n$1\n
```

### *

うーん。これだと連続する改行が残るし

`\n$1\n` を `$1\n` にするとテキストノードの後のタグが改行されない
まいっか。
CSSで縦組み・プロポーショナルメトリクス

これは備忘録です。

### 横組み・プロポーショナルメトリクス
```css
font-feature-settings: "palt";
```
### 縦組み・プロポーショナルメトリクス
```css
writing-mode: vertical-rl;
font-feature-settings: "vpal";
```

### 参考
1. https://qiita.com/tsuka-rinorino/items/3e3eaaba8cddb6ff08e9
2. https://helpx.adobe.com/jp/fonts/using/open-type-syntax.html

2のページには他にもいろんな`font-feature-settings`の値が載っています。
DB server management studio リストア　空き容量　不足

データベースバックアップ後の復元(リストア)でCドライブの空き容量が足りなくなった。
以下management studioでのファイル開放方法。

容量のデカいmdfや.ldfファイルを開放してあげる。

logファイルを見に行ったら案の定でかかった。
パスの例で自分のを載せる。
`C:\Program Files\Microsoft SQL Server\MSSQL13.SQLEXPRESS\MSSQL\DATA`


一応(お任せ)バックアップを取っておく。
対象のDBを右クリック→タスク→バックアップ。
現在のパスを削除して新規にバックアップ先を追加しOK。

完了したら
対象のDBを右クリック→タスク→圧縮。
ファイルの種類を「ログ」へ変更しOK。

バイト数が30GB程減った。
3000000 → 8000
Optiona型変数からguard letで値を取り出す

Optional型変数から値を取り出す際、そこにnilが入っているとエラーの原因となることがあります。そこで、gurad letを使用することでnilを識別し値を安全に取り出すことができます。

gurad letの使い方
---

```swift
guard let sampleNonNil = sampleOptionl else {
    //sampleOptionlがnilである場合
    return
}
//その後の処理
```

sampleOptionlがnilでなければその後の処理が実行され、sampleOptionlがnilであればreturnされます。
Power BI レポートの ビジュアル ヘッダーの非表示や調整するなど

ずーっとおかしいなぁおかしいなぁと思っていたのです。あまり気にかけていなかったけど。日本語への翻訳がよくなくね？と思っているのです。

# ビジュアル ヘッダーとは
ページに配置されたビジュアルごとに用意されるヘッダーでこんな感じのもの。で、ビジュアルが隣接していると他のビジュアルと重なってしまって、たまにイラっとすることがある。なので、ヘッダーが必要ないときには非表示にしておきたいよねと。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193509/1e5fac31-60d8-bf56-aa19-c155178e1d5e.png)

# ビジュアルごとに非表示にする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193509/b62dde8a-ead8-46ef-7f5f-6e08aba2f81b.png)
設定したいビジュアルをアクティブにして [Format] - [Visual header]で "Off" にすればヨシ 👈🐱他ビジュアルの機能アイコンごとでも設定できるのでお好みで。
# まるっと非表示にする
Power BI Desktop で設定するなら、[Option] - [Report settings] の "Hide the visulal header in reading view" を "ON"
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193509/c0cf846c-ff58-7452-97a5-5efb7629c4dc.png)

Power BI Service 上なら、設定したいレポートの [Settings] から "Hide the visulal header in reading view" を "ON"
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193509/f8b6cb69-4cf3-d1ed-c517-5620efdb82ec.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193509/498553af-89db-f114-5e85-3de7cc84ddaf.png)

# 思ったこと🙄
日本語環境向けの翻訳がよろしくないんですよね。"全画面表示" じゃなくて "読み取りビュー" ね
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193509/4d42f39b-0ff6-81d0-e0a7-fe2ca9f84ea7.png)

# その他
- [Power BI 勉強会 - connpass](https://powerbi.connpass.com/)
- [Power BI Desktop を使い始めるには](http://qiita.com/PowerBIxyz/items/6c4735cb5b5712e70981)
- [Excel で Power Query を使い始めるには](http://qiita.com/PowerBIxyz/items/52e563037b855a099ca9)
IE11でエラーが出るjavaScriptを条件分岐で読み込まなくする方法

# IE11だけコードエラーが出る
jQueryのmouseenter/mouseleaveが、IE11だけエラーが出て動作せず困ってしまいました。。。
（Edgeは大丈夫だったのに）
他のブラウザでは問題ないので、
とにかくIE11はこのjavaScriptを起動させないようにしようと思い、
色々試してみました。

# 条件分岐でIE11のエラー回避を試す
## javaScriptを使った判定

こちらを参考にさせていただきましたm（_ _）m
[https://developers.wano.co.jp/311/](https://developers.wano.co.jp/311/)

```javascript
var userAgent = window.navigator.userAgent.toLowerCase();
if( userAgent.match(/(msie|MSIE)/) || userAgent.match(/(T|t)rident/) ) {
  //IEの時、mouseenter/mouseleaveが効かないため、静止svgを挿入
	jQuery('.icon-facebook').html('<img src="images/common/facebook.svg" alt=""/>');
} else {
  //他のブラウザで svg animationを起動させる
  //(↓下は記述例として入れているだけで、これだけでは動かないです。)
  var directionFacebook = 1;
    iconFacebook.addEventListener('mouseenter', (e) => {
    animationFacebook.setDirection(directionFacebook);
    animationFacebook.play();
  });
    iconFacebook.addEventListener('mouseleave', (e) => {
    animationFacebook.stop();
  });
}
```

これは効果があったが、else内も読み込むので、
その中にIE非対応のコードがエラーで出てしまいました。。
IE11回避策としては失敗。。
## PHPとHTMLを使った判定
こちらを参考にさせていただきましたm（_ _）m
[https://16deza.com/put-ie-in-separate-html/](https://16deza.com/put-ie-in-separate-html/)
(ここでは、IE8,9の判定方法も書いてくださっています)

WordPressで使う場合は、
functions.phpに以下のように記載。
（普通のPHPサイトのhead内でも使えるそうです。）

```PHP
// IE11判定
function is_ie11() {
    if(preg_match('/(?i)trident/',$_SERVER['HTTP_USER_AGENT'])) {   
        $is_ie11 = true;
    } else {
        $is_ie11 = false;
    }
    return $is_ie11;
}
```

footer.phpのjs読み込み部分

```PHP
<?php if(is_ie11()): ?>
   <script src="<?php echo esc_url( get_template_directory_uri() ); ?>/js/anime--ie.js" type="text/javascript"></script>
<?php else: ?>
	<script src="<?php echo esc_url( get_template_directory_uri() ); ?>/js/anime--other.js" type="text/javascript"></script>
<?php endif; ?>
```

これでうまく条件分岐して、エラーを回避することが出来ました！
# 追記
~~初投稿もあって、コードのMarkdownがうまくいかないようです。。~~
~~```` ``` ```` でコードを囲ったら、黒っぽい背景にならないので困っています。。。~~
~~どなたかご教示していただけると有難いですm（_ _）m~~
htsign様のご教示で解決しました！投稿してから数分で解決するなんてすごい！
本当にありがとうございました！！
CompositionAPIでの$refsの扱い方

`$refs`といえば

```vuejs
<!-- vm.$refs.p は DOM ノード -->
<p ref="p">hello</p>

<!-- vm.$refs.child は child-component のインスタンス -->
<child-component ref="child"></child-component>
```
このref要素を`this.$refs.p`, `this.$refs.child`というように取得できるAPIですが、CompositionAPIではどうやればよいのか

```vue.js
<p ref="p">hello</p>

...

setup() {
  const p = ref(null)
  onMounted(() => {
    p.value // DOMノードが取得できる
  })
  return {
    p
  }
}
```
このようにCompositionAPIのRef関数でテンプレート側の`ref="p"`に対応する変数を定義しておいてマウント後に取得できるようになります。
簡単でしたね
ScalaFXで特定ObjectのBindingができない

## 結論
現状できないので、Bindingを使わずに、イベントが起こるごとに状態変化させるようなコードをコツコツ書きましょう。

## 内容
こんなコードを書いた。

```scala
val buffer: ObservableBuffer[String] = new ObservableBuffer[String]()
val imageView: ImageView
imageView.image <== createObjectBinding(() => {
    buffer.headOption match {
        case None => new Image("empty_image_url.png")
        case Some(url) new Image("url")
    }
}, buffer)

buffer.add("url1")
```

これをコンパイルするとこんなエラー。

```
error: overloaded method value <== with alternatives:
(v: scalafx.beans.value.ObservableValue[_ <: javafx.scene.image.Image, _ <: javafx.scene.image.Image])Unit
(v: javafx.beans.value.ObservableValue[_ <: javafx.scene.image.Image])Unit
cannot be applied to (scalafx.beans.property.ObjectProperty[scalafx.scene.image.Image])
imageView.image <== createObjectBinding
```

`<==`メソッドのJavaFXオブジェクトを受ける版と、ScalaFXオブジェクトを受ける版の２つのオーバーロードメソッドがあるが、どちらの定義も適用できるため、どちらのメソッドを呼び出せばいいのかがわからないようだ。

下記issueを見ていただければわかるが、現状解決していない。
https://github.com/scalafx/scalafx/issues/14

## ということで、
Bindingはあくまで特定のプロパティの変化を監視しているだけなので、そのプロパティが変化するところでBindingに定義したイベントハンドラを呼び出すようにしてあげればよい。
コード的には見通しが悪くなるが、仕方なし。
オンラインビデオ会議remo.coを使ってみた

# はじめに

COVID-19の影響による強制フルリモートワークにより、私のチームのメンバーも全員オフィスにいない状況が続いています。
元々コミュニケーションツールとしてslack、Trello、Backlog、Teams、Googleドキュメント等を利用しており
リモートワーク自体もコロナ禍以前から継続して行われているので、仕事をする分には全く支障は出ていないのです・・・が

**雑談が圧倒的に足りていない！**

slackがあるのでチャットで雑談するのがベストなんでしょうけども
チャットツールは使う人はめっちゃ使いますが、使わない人は全く使わないという状況が生れるのが問題です。

とはいえ、わざわざ雑談のためだけにslack通話を繋げるのは
結構心理的ハードル高いのでどうにかならんかなと思っていました。

そんな時、 [remo.co](https://remo.co/) 良いんじゃね？的な話がslack上で噴出し、トライアルですが実際に全社で使い始めたので
その使い心地や感想を記載していきます。

# remo.coとは

remo.coはビデオ会議の為のWebサービスですが、一般的なビデオ会議とはちょっと違った面白い仕組みを採用しています。

* 大小いくつかの部屋があり、参加者は自由に部屋を行き来できる
* 小さい部屋は4人、一番大きな部屋だと30人まで入ることが可能
* **部屋の中の通話はその部屋の中にいる人しか聞くことが出来ない**
* 部屋はロックを掛けることが可能
* ロックされている部屋に入りたいときは、ノックをすれば中の人に参加可否のダイアログが表示される

[![Remo.co](http://img.youtube.com/vi/AvfjiukhgnE/0.jpg)](http://www.youtube.com/watch?v=AvfjiukhgnE)

# remo.coを使ってみた

試行錯誤しながらどんな風に使えるか試してみましたが
プロジェクトメンバー同士で作業しながら仕事の会話や雑談するのに向いていると思います。
特に明確にルール化はしていないので各自の自由ですが私は以下のように使用しています。

* リモート出社したらとりあえずremoのプロジェクト部屋に入る
* スピーカーは常時オンにしておき、マイクは喋る時だけオンにする
* カメラはオフでも良いですが、物足りないので適当にFaceRigのアバターを表示

![mosa_5.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536869/48d47f16-2fb3-4ebe-a064-0dd2ad1ca993.jpeg)

チームメンバーが部屋に入ってきたら

**「おはようございまーす」**

と挨拶を交わしそのまま黙々と作業を続けつつ

**「そういえば、〇〇ってどうなってます？」
「△△みたいにリファクタしようと思うですけどどう思います？」
「□□についてslackで投げたんでチェックお願いしまーす」
「mergeしようと思ったらconflict地獄で死ぬ！（笑）」
「今朝のニュースで～」**

みたいにゆるーく会話しています。

ちょっと息抜きしたい時は別の部屋に移動してみて
今まであまり話した事のない人とも雑談をしてみたりして
むしろ物理的なオフィスにいる時より会話する人の人数自体は増えています。

業務終了後はそのままだらだらと雑談を続けて
「ちょっと飯食ってから酒持って戻ってくるよ」
みたいな流れで幹事的な人が居なくてもそのまま自然に飲み会の流れになるのも面白いですね。

![mosa_pic8 21.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536869/e18ac035-55cb-3535-8e3b-859f623e349c.jpeg)

この感覚何となく覚えがありますがアレですね、**ネトゲのフレンド同士の会話**のノリですね。
上手く活用できれば会社というネットゲームをプレイしてる感覚で仕事出来るようになるかもしれません。

# remo.coを使ってみての感想とかいろいろ

* 「今から会話します」のような事前のネゴシエーションが不要なのでビデオ通話の**心理的ハードルが低い**
* remo.co上でのステータス見れば話しかけて良さそうか分かるので気軽に話しかけやすい
* slack通話やTeamsと比べて大人数でわいわい話すのに向いている**音声品質は高い**
* **試用期間中はパスワード掛けられないのでURL知っていれば誰でも入れちゃう**
* ホワイトボード機能はちょっと不安定なので使えない
* 回線が遅い人は6人以上集まるとROMになってしまう

オフィスで隣にいる人に話しかける感覚でゆるーく繋がれるツールという印象でした。
弊社の社長も気に入ってるのでたぶん利用を継続するんだと思います。

何となくですが、コロナ禍によりこういったリモートオフィスが一般化していくと

**「もしかして全社員が入れるデカいオフィス要らないんじゃないか」**

ということに気付き始める人が増えるじゃないかなと思ったりしました。
京大VpnにUbuntuからつなぐ

なんか色々オンラインになってるので昔書いたものを投稿します。


公式サイトになかったのでまとめます
OpenVpnを使用します

# 下準備
- OpenVpn用のクライアントをインストール

```
$ sudo apt -y install network-manager-openvpn-gnome
```
- [京大クライアント証明書発行ページ](https://shibcert.iimc.kyoto-u.ac.jp/ja)（学内限定）で証明書の発行を受けてください。そこで`*.p12` みたいなファイルをダウンロードします。（この辺りの手順はどのクライアントでも共通なのでサイトに記載があります。[公式サイト](http://www.iimc.kyoto-u.ac.jp/services/cert/client_cert/client_certificate_manual_20200423.pdf)）

# 設定
あとは簡単です

1. 設定からネットワーク接続を開き、追加ボタンを押します。
2. openVpnの項目があると思うのでこれを選択してプロファイルを作成します。
3. 以下のように設定します
 
|項目|内容|
|:--|:--|
|ゲートウェイ|openvpn0.kuins.kyoto-u.ac.jp|
|ユーザー証明書、CA証明書、秘密鍵|path/to/*.p12|
|秘密鍵のパスワード|もらったpin|
"LZOデータ圧縮を利用" と "TCP接続を利用" にチェック

これで保存します

その後タスクバーのwifiメニュー等からvpn接続を選択すれば行けると思います
pytorch での正規分布(normal distribution)の実装(CPU)メモ

glow/flow で, 正規分布のサンプリング(`normal()`. https://pytorch.org/docs/stable/distributions.html )をよく使うので, CPU で実装がどうなっているか調べました.

ATen の DistributionTemplates.h に実装があります.

https://github.com/pytorch/pytorch/blob/master/aten/src/ATen/native/cpu/DistributionTemplates.h

(Torch/ATen はいろいろ階層が深くてコード追うのがめんどうですね...)
16 個以上で並列化できるときと, scalar でコードパスが違います.

アルゴリズムはどちらも普通の Box-Muller 法(https://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform)です.

## 16 並列生成版

16 個で sin, cos で半分づつ(8 こづつ)に分けて生成しています. AVX2 の場合は, 明示的な AVX instrinsics 関数を使って並列化しています(e.g. _mm_sincos256_ps など). SSE2 のコードパスが無いのは, C++ コンパイラが賢ければ自動で SSE2 命令で置き換えてくれる...はずだからでしょうか.
 
## scalar 版

`at::normal_distribution` で実装されています.

https://github.com/pytorch/pytorch/blob/master/aten/src/ATen/core/DistributionsHelper.h

サンプルした値を cache しておいて, cache があればそれを使う, なければあらたに生成する, というアプローチをとっています. ちょっと実装が面倒ですね.

## テスト

自前で normal distribution generator を実装したときなど, それが正しく正規分布しているか確かめる.

scipy に normaltest 関数があります.

https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.normaltest.html


その他統計テスト用関数

https://docs.scipy.org/doc/scipy/reference/stats.html

## おまけ

もうひとつ乱数を生成して, それを元に cos を使うか sin を使うか判定に使うというのもあります.

https://github.com/thomas-moulard/gazebo-deb/blob/master/media/materials/programs/camera_noise_gaussian_fs.glsl

GPU やアクセラレータで cache を持つのが面倒ときに使えますね.
[datadog]利用料金について

#はじめに
　AzureでいくつかのVirtual Machineを用意したのでまとめて監視をしたいと思い、たどり着いたのが今流行のDATADOG
　https://www.datadoghq.com/ja/
　
　一番わかりにくかった
　使ってみるといくら課金されるのかを記録しておく。

#環境
　WEBサーバー　１台　Nginx
　APサーバー　２台　Java
　DBサーバー　２台　MySQL
　バッチサーバー　１台　Shell

　の合計６台の監視を行う

#監視対象
| サーバー       |       監視対象 |
|:-----------------|:------------------|
| WEBサーバー             |              CPU,Memory,HDD,Nginxログ|
| APサーバー           |            CPU,Memory,HDD,Javaログ |
| DBサーバー           |            CPU,Memory,HDD,MYSQL,MySQLログ |
| バッチサーバー           |            CPU,Memory,HDD,Shellログ |

#監視方法
###CPU,Memory,HDD
　　エージェントをインストールすることで監視される

###MySQL
　　IntegrationsからMySQLをインストールすることで監視される

###各種ログ
　　エージェントの設定ファイルでLog監視をenableにすることで監視される

#で、課金額
　それぞれの設定方法に関しては各所にドキュメントがあるため結論を。

　サーバー１台あたり　＄１０/月
　監視ログ１００万行あたり　＄１．５２４/月
　　※ 2020/4/10時点

　で、今回の環境では
　　＄６０(サーバーx６台) + ＄４．５６(ログx３M）
　で契約し、
　　＄６４．５６（＝7000円弱)
　となった。

#ログの計算方法
　コンソール上で、Logs→Searchと進み、
　すべてのフィルタを外した上で右上のタイムフレームをPast Weekする。
　→直近1週間のログ件数が中央に -- results found として表示される。

　その値を4倍し、100万件単位に繰り上げるとおおよその数値を見積もれる。
【解決方法】rails db:rollbackができないエラー

#rails db:rollbackができないときの解決方法

チーム開発中にアプリケーションのテーブルを修正することになりました。
dbをrollbackした際に以下のエラーが発生したので、、、、

<strong>rails aborted!
ActiveRecord::UnknownMigrationVersionError: </strong>

単純な作業内容ですが、備忘録として残します。
##rails db:rollbackを実行してみた
まず、テーブル修正のため、railsのマイグレーションファイルをデータベースからrollbackすることに

```
$ rails db:rollback
```
エラーが発生し、rollbackできない


```
rails aborted!
ActiveRecord::UnknownMigrationVersionError: 
```

##一度、データベースごとrails db:drop　

ただ、この方法はdb内のデータを全て消してしまうので、実行には注意が必要です。

```
Dropped database 'アプリケーション名 development'
Dropped database 'アプリケーション名'
```

そして、アプリケーション立ち上げ時と同様にrails db:createをしましょう

```
Created database 'アプリケーション名 development'
Created database 'アプリケーション名'
```

無事にアプリケーションのデータベースを作ることができました。

##マイグレーションファイルの修正を確認したら、rails db:migrateを実行

```
== 20200402084559 DeviseCreateUsers: migrating ================================
-- create_table(:users)
   -> 0.0100s
-- add_index(:users, :email, {:unique=>true})
   -> 0.0190s
-- add_index(:users, :reset_password_token, {:unique=>true})
   -> 0.0078s
== 20200402084559 DeviseCreateUsers: migrated (0.0370s) =======================

== 20200407090006 CreateProducts: migrating ===================================
-- create_table(:products)
   -> 0.0112s
== 20200407090006 CreateProducts: migrated (0.0113s) ==========================

== 20200409054432 CreateImages: migrating =====================================
-- create_table(:images)
   -> 0.0174s
== 20200409054432 CreateImages: migrated (0.0175s) ============================

```

無事、マイグレートできた様子。
一応、rails db:migrate:statusでも確認

```
database: アプリケーション名　development

 Status   Migration ID    Migration Name
--------------------------------------------------
   up     20200402084559  Devise create users
   up     20200407090006  Create products
   up     20200409054432  Create images

```

statusがアップになっているので、データベースにも反映されているようだ。
downだと、マイグレーションファイルがpendingされているとエラーが出てしまうので注意。

念のため、sequelProで確認したところ、しっかりと反映されていました。

簡単なエラーでしたが、何かの役に立てば幸いです。
SageMakerでencountered a problem and was stoppedと怒られたときの対応

SageMaker Studioでdelete-app出来ないときにcreate-appで救われた、という話です。
(環境:SageMaker Studio:2020/04/09, aws cli:aws-cli/1.18.39 Python/3.6.9 Linux/4.15.0-1065-aws botocore/1.15.39)

みんな大好きAWS Sagemaker Studioですが、ときどき
"The JupyterServer app default encountered a problem and was stopped"などと表示して、Web画面からのRestartも出来なくなってしまいます。

対策として
https://forums.aws.amazon.com/thread.jspa?threadID=314388

にあるようにaws cliからdelete-appすることが多いらしいんですが、私の見ている環境だと

~~~ bash
 > aws sagemaker delete-app --domain-id xxx --user-profile-name yyy --app-type JupyterServer --app-name default --region us-east-2

 An error occurred (ValidationException) when calling the DeleteApp operation: State transition from [Failed] to [Deleting] is not allowed.
~~~

と怒られてしまいました。

~~~ bash
> aws sagemaker describe-app --domain-id xxx --user-profile-name yyy --app-type JupyterServer --app-name default --region us-east-2 | jq -r '.Status'
Failed
~~~

こういう状態だとdelete-appできんらしい。
で、sagemakerのサブコマンドを眺めたんですがstatus failedをどうこうできそうなのが見当たらないのでひとつ思い切ってcreate-appしてみました。すると

~~~ bash
> aws sagemaker create-app --domain-id xxx --user-profile-name yyy --app-type JupyterServer --app-name default --region us-east-2
{
    "AppArn": "arn:aws:sagemaker:us-east-2:zzz:app/xxx/yyy/jupyterserver/default"
}
~~~

と呑んでいただいて、しばらくすると

~~~ bash
> aws sagemaker describe-app --domain-id xxx --user-profile-name yyy --app-type JupyterServer --app-name default --region us-east-2
 | jq -r '.Status'
InService
~~~

動いたー

実際には
1. InServiceだったKernelGatewayをdelete-app -> 
2. KernelGatewayをcreate-app -> 
3. KernelGatewayのStatusがPendingの間にfailedなJupyterServerをcreate-app実行
という手順でしたが、1. KernelGatewayのdelete-app/2. create-appはいらんのではないかと思います。もし3だけでダメだった場合は1 2 3の手順を試してみてください。

これでStudioのアクセスも出来ました。
テーブルの主キー情報を取得する

```
SELECT A.TABLE_NAME, A.POSITION,A.COLUMN_NAME FROM USER_CONS_COLUMNS A 
WHERE EXISTS (SELECT 1 FROM USER_CONSTRAINTS B WHERE TABLE_NAME = A.TABLE_NAME AND CONSTRAINT_NAME = A.CONSTRAINT_NAME AND CONSTRAINT_TYPE = 'P')
AND A.TABLE_NAME IN ( 
'テーブル名1',
'テーブル名2',
'テーブル名3'
)
ORDER BY TABLE_NAME, POSITION
```


参考URL:http://toronto12.seesaa.net/article/137563650.html
postcss-loaderでstylelintする

# 始めに
webpackでstylelintするを調べるとstylelint-webpack-pluginが紹介され、以下のような設定をみると思います。

```javascript:stylelint-webpack-pluginの設定
const StyleLintWebpackPlugin = require('stylelint-webpack-plugin');

module.exports = {
  plugins: [
    new StyleLintWebpackPlugin({
      configFile: path.resolve(__dirname, '.stylelintrc.yml'),
      files: ['**/*.scss'],
    }),
  ]
};
```

ただこの設定は一つ難点がありまして、`files`で設定した全てのファイルをチェックするため、importしていようがしてなかろうがチェックされてしまいます。これによって例えばJSしか変更していなくてもlintチェックが走ってしまい余計な時間を使ってしまうこともあります。
ふと疑問に思ったのが、なんでeslint-loaderは対象ファイルだけlintチェックするのに、stylelintは全体チェックしていることです。色々調べてみるとpostcss-loaderの中でstylelintをすることができるので、それを試したので記事にまとめてみました。

# postcss-loaderでstylelintする設定
早速本題ですが、postcss-loaderでstylelintするにはpluginとして入れるとできるようです。これならビルドと並行してlintもできそうですがとりあえずeslint-loaderと合わせてみたかったので`pre`で設定します。

```javascript:postcss-loaderでstylelintする設定
module.exports = {
  module: {
    rules: [
      {
        enforce: 'pre',
        test: /\.(sass|scss)$/,
        exclude: /node_modules/,
        use: [
          {
            loader: 'postcss-loader',
            options: {
              parser: 'postcss-scss',
              plugins: [
                require('stylelint')({
                  configFile: path.resolve(__dirname, '.stylelintrc.yml'),
                }),
                require('postcss-reporter')({
                  clearReportedMessages: true,
                }),
              ]
           }
         ],
       }
     ]
  }
};
```

これでloader側でlintすることができて以下のようなものがターミナルに出るのですが、なぜか警告として表示されました。

<img width="483" alt="スクリーンショット 2020-04-10 14.38.06.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/187768/04514833-55cd-4b01-a4cc-275054c7399f.png">

個人的にはエラーとして出したかったので色々調べていたのですが、どうやら**警告しか出力できない**ようです。

> The stylelint plugin registers warnings via PostCSS. 

https://stylelint.io/user-guide/usage/postcss-plugin

これだと開発中にエラーに気づけないし、ビルドも成功してしまうのでなんとかできないか調べたところ、`postcss-reporter`に`throwError`オプションをつけると警告でもエラーにしてくれるのでそれを試してみたところ、ブラウザ上で以下のものが出るようになりました。

![スクリーンショット 2020-04-10 14.43.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/187768/87f0934e-4e6a-4461-339a-9c21fe7a96a3.png)

いやなんのエラーか全然分からないw まぁ確かにターミナルみたら先ほどのキャプチャのような警告は出てますけど、パッと見わかりづらいですよね・・・
ちなみにstylelint-webpack-pluginを使った時のブラウザ上のエラー表示は以下になります。とても分かりやすいですね。

![スクリーンショット 2020-04-10 14.45.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/187768/a02cc452-458b-dd53-c62c-ec82616d2362.png)

# 終わりに
以上がpostcss-loaderを使ってstylelintする方法でした。こちらでもlintはできるのですが、警告になってしまうという制約のせいであまり使い勝手はよく無いのかなとは感じました。
postcssのプラグインも他のやり方の方がいいよと勧められてしまっていますし。

>However, if a dedicated stylelint task runner plugin is available (e.g. gulp-stylelint) we recommend you use that rather than this plugin, as they provide better reporting.

https://stylelint.io/user-guide/usage/postcss-plugin


lintチェックに時間がかかる問題は、そもそもpre-commitの時にlintするとか、別なやり方を考えた方がいいのかなとも思ってきました。普段の開発はVSCodeだとエディタ上でエラー分かりますし、autofixでほとんどのエラーは解決できそうですし。
GitLab CI/CD機能における出力ログ上限の超過対策

# はじめに

GitLab CI/CDにて、実行ジョブのログが大量である場合、上限設定に引っかかりログが消失する恐れがある。
そういったときの対策。

# 環境

* CentOS 7.6
* GitLab 12.9.2

# 事象

ジョブ実行結果の最後に下記のように表示され、全てのログが表示されていない。

```
 Job's log exceeded limit of 4194304 bytes.
```

# 理由

gitlab-runnerにおいて、ログの出力上限設定が存在するから。デフォルトの上限は`4MB`となっている。

# 対策

単純。上限を引き上げれば良いだけ。
gitlab-runnerの設定ファイルに`output_limit`設定を追加し、キロバイト(KB)単位で任意の値を指定する。
恐らくデフォ状態では、パラメーター自体が存在しないはず。この場合、デフォルトの値である`4MB`が採用されている。


 
```/etc/gitlab-runner/config.toml
[[runners]]
  name = "example-runner"
  url = "https://example.local"
  token = "example-token"
  output_limit = 40960  <-- コレ (この場合10倍に増やしている)
  executor = "docker"
  [runners.custom_build_dir]
  [runners.cache]
    [runners.cache.s3]
    [runners.cache.gcs]
  [runners.docker]
    tls_verify = false
    image = "example"
    privileged = false
    disable_entrypoint_overwrite = false
    oom_kill_disable = false
    disable_cache = false
    volumes = ["/cache"]
    shm_size = 0
```

再起動して適用。

```
systemctl restart gitlab-runner.service
```

# 参考

* [https://docs.gitlab.com/runner/configuration/advanced-configuration.html#the-runners-section](https://docs.gitlab.com/runner/configuration/advanced-configuration.html#the-runners-section)
USBがフォーマットできなかった時

# 参考
[★こちらを参考にしました★](https://amzn.to/3aXJ6LT)

# USB名を調べる
```
fdisk -l
```
# fdiskコマンドで確実にフォーマットを実行する
1. dを押す   (パーティション削除)
2. Enter    (デフォルトパーティション削除)
3. 1と2をパーティションがなくなるまで繰り返す
4. nを押す   (パーティション新規作成)
5. pを押す   (プライマリパーティション作成)
6. 1を押す   (パーティション１を作成)
7. Enter    (first)
8. Enter    (last)
9. wを押す   (書き込み完了)

# USBをアンマウント
```
umount /dev/sdb1
```

# FATファイルシステム作成
```
mkfs.vfat -F 32 /dev/sdb1
```

# もう少し知りたい方
[★こちらを参考にしました★](https://amzn.to/3aXJ6LT)
Goの環境構築方法

# はじめに
最近、仕事でGo触り始めたので、改めて環境構築の手順の確認と、今後Goを触りたいっていう人の参考になればなぁと思います。

ちなみに、自分の手元の環境は以下。
OS : macOS Catalina 10.15.2
→ 好奇心でzshにも切り替えてます。

# 環境構築方法
以下の2つをまとめていこうかな、と思います。
どちらも簡単なので、パーっと終わるかと。
あとPATH通したりの作業は必要ですが、Homebrewでインストールもできます。

- 公式からDLしてインストール
- goenvを使ってインストール


## 公式からダウンロード
https://golang.org/doc/install

### インストール
インストーラに従って進めるのみ。

###  PATHを通す
```
// bash使ってる人は、.bash_profileとかに置き換えてくださいー。
% echo 'export PATH="$PATH:/usr/local/go/bin"' >> ~/.zshenv
```

### GOPATHの確認
```
% go env GOPATH
/Users/hogehoge/go
```
GOPATHは、Goのワークスペースを指定する環境変数です。
上のディレクトリに`src`ディレクトリを作成し、その中にプロジェクトを作成していきます。
`{$HOME}/go`がデフォルトみたいですね。

もしGOPATH変えたい人は、以下でGOPATHの変更が可能です。

```
% go env -w GOPATH=お好きなディレクトリ
```

詳しくは[こちら](https://github.com/golang/go/wiki/SettingGOPATH)を参照ですね。
他にもGoは、色々な環境変数が準備されていて、`go env`を実行すれば、他の環境変数を確認できます。
今回は環境構築ということで、無視します。


## goenvを使ってインストール
https://github.com/syndbg/goenv

### goenvって??
ざっくりいうと、goのバージョン管理を行うためのツールです。
プロジェクト毎に、goのバージョン指定できるので、Aプロジェクトは1.12で、Bプロジェクトは1.13みたいな感じでバージョン指定ができます。
pyenvとかrbenvとかのgo版です。gitページにもpyenv等に倣うって書いてあります。

### goenvのインストール
```
% git clone https://github.com/syndbg/goenv.git ~/.goenv
// brew 入ってる人はbrew installでいけます〜。
```

### セットアップ
```
// bash使ってる人は,.bash_profileとかに置き換えてくださいー。
% echo 'export GOENV_ROOT="$HOME/.goenv"' >> ~/.zshenv
% echo 'export PATH="$GOENV_ROOT/bin:$PATH"' >> ~/.zshenv
% echo 'eval "$(goenv init -)"' >> ~/.zshenv
% exec $SHELL
```

### 確認
```
% goenv -v
goenv 2.0.0beta11

% goenv install -l
Available versions:
  1.2.2
  ... // 過去のモノからたっくさん出てきます。
  1.13.8
  1.14beta1
  1.14rc1
```

### バージョンの設定
↓のような感じで、`goenv local x.x.x`を実行すると、そのプロジェクトのバージョン指定ができます。
`goenv local`を実行すると、`.go-version`ファイルが作成され、その中にgoのバージョンが書かれています。
他にもいくつかコマンドありますけど、いつか記事にできたら、と思いますー。

```
% goenv local 1.13.7
% cat .go-version
1.13.7
% go version
go version go1.13.7 darwin/amd64
```

## ということで、動作確認
```
% cd $GOPATH
% mkdir -p src/hello
% vi hello.go
```

以下、公式から持ってきたソースをコピペ〜。

```:hello.go
package main

import "fmt"

func main() {
	fmt.Printf("hello, world\n")
}
```

buildします。

```
% go build

// buildして、helloという実行ファイルが作成されました。
% ls
hello		hello.go
```

では、実行します!!

```
% ./hello
hello, world
```

出ましたーーーーー!!
お馴染みのhello world!!

ということで、ざざっとgoの環境構築は完了になります。
あとは、goの基本文法とかは [A Tour of Go](https://tour.golang.org/welcome/1)で学ぶことができます。
【Firestore】配列へのデータの追加で Cannot read property 'arrayUnion' of undefined

# arrayUnion を使用する

```test.firestore.js
var washingtonRef = db.collection("cities").doc("DC");

// Atomically add a new region to the "regions" array field.
washingtonRef.update({
    regions: firebase.firestore.FieldValue.arrayUnion("greater_virginia")
});

// Atomically remove a region from the "regions" array field.
washingtonRef.update({
    regions: firebase.firestore.FieldValue.arrayRemove("east_coast")
});
```

[データの追加 | Firestore | Google Cloud](https://cloud.google.com/firestore/docs/manage-data/add-data?hl=ja#update_elements_in_an_array)

# エラーと変更

```err.bash
TypeError: Cannot read property 'arrayUnion' of undefined
```
arrayUnionがundefined??

```def.js
const admin = require('firebase-admin')
var fireStore = admin.firestore()
fireStore
    .collection('hoge')
    .doc('fuga')
    .update({
+      regions: admin.firestore.FieldValue.arrayUnion('additional_i')
-      regions: fireStore.FieldValue.arrayUnion('additional_i')
    })
```

## 原因

(しかしこれがどうして治ったのかよくわからないので、強い人コメントで教えていただけると嬉しいです…！） と書いていたところ、[@sgr-ksmt](https://qiita.com/sgr-ksmt) さんからコメントをいただき原因が判明しました。

### `admin.firestore()` と `admin.firestore` の混同

> admin.firestore() と admin.firestoreの違いによるものかと思います。前者はオブジェクト、後者は型になります。
> 個人的には以下のようにしてこの誤用を防ぐようにすると良いかなと思っています。(typescriptの場合ですが)
@google-cloud/firestoreから参照できるFieldValueと、 admin.firestore.FieldValue は同一のものになります。

```answer.js
import { FieldValue } from '@google-cloud/firestore';
import * as admin from 'firebase-admin'

admin.firestore()
    .collection('hoge')
    .doc('fuga')
    .update({
      regions: FieldValue.arrayUnion('additional_i')
    })
```

Qiitaコミュニティ最高ですね…