OmniAICreator/Qiita-1.07M huggingface dataset:
React.Fragment の活用タイミング

#### はじめに
本記事はReact.Fragmentの使い方に関して記載します。
恥ずかしながら、筆者はReact開発をはじめて数ヶ月後に、React.Fragmentの存在を知りました。。涙
このテクニックをご存知でない方向けに記事を書きました。

#### 問題点

Reactにて複数のエレメントをrender()関数にて返す必要がある場合、１つのタグにまとめる必要があります。

```React
class Table extends React.Component {
  render() {
    return (
      <table>
        <tr>
          <Columns column1="col1" column2="col2" />
        </tr>
      </table>
    );
  }
}

class Columns extends React.Component {
  render() {
    const { column1, column2 } = this.props;
    // Error!!!
    return (
      <td>{column1}</td>
      <td>{column2}</td>
    );
  }
}

ReactDOM.render(<Table />, document.getElementById("root"));
```

このとき、下記エラーが発生します。

```bash
index.js: Adjacent JSX elements must be wrapped in an enclosing tag
```

Columnsクラスにて２つのタグを返そうとしていますが、これはReactではNGです。

```React
    // NG case. 1つのタグにまとめる必要あり
    return (
      <td>{column1}</td>
      <td>{column2}</td>
    );
```

しばらくは私は<div>タグを追加して、エラーを回避していました (<b>!!これは間違い</b>)

```React
  return (
    <div>
      <td>{column1}</td>
      <td>{column2}</td>
    </div>
  );
```

divタグを追加するとエラーは解消しますが、無駄なタグがふくまれてしまいます。


```HTML
<table>
  <tr>
    <div> <!-- このdivは不要 -->
      <td>col1</td>
      <td>col2</td>
    </div>
  </tr>
</table>
```

#### 解決策

ReactにはReact.Fragmentタグが存在しており、このタグを追加することで、エラーは回避可能で、かつ無駄なタグが含まれることもなくなります。

```React
class Columns extends React.Component {
  render() {
    const { column1, column2 } = this.props;
    return (
      <React.Fragment>
        <td>{column1}</td>
        <td>{column2}</td>
      </React.Fragment>
    );
  }
}
```

生成されるHTMLは下記になります。無駄なタグは生成されません。

```HTML
<table>
  <tr>
    <td>col1</td>
    <td>col2</td>
  </tr>
</table>
```

サンプルコードはこちら
https://codepen.io/japanese-engineer/pen/yxrQNv


#### 補足
- ツールによっては short syntax (<></>) の指定も可能です。ただ、多くのツールではshort syntax はサポートされてないので注意が必要です。

- React.Fragmentはkeyを指定可能です。必要に応じてkeyを追加する必要があります。
  下記例ではReact.Fragmentを配列として返しています。この場合、keyを追加しないと、Reactは警告を出します

```React
function Glossary(props) {
  return (
    <dl>
      {props.items.map(item => (
        // Without the `key`, React will fire a key warning
        <React.Fragment key={item.id}>
          <dt>{item.term}</dt>
          <dd>{item.description}</dd>
        </React.Fragment>
      ))}
    </dl>
  );
}
```

#### まとめ
React にて複数の子エレメントを返す場合、React.Fragmentタグを使うことで、無駄なタグを省くことができます。

参照　https://reactjs.org/docs/fragments.html
Aidemy4回目　メモ　「9/22」

Aidemy | 10秒で始めるAIプログラミング学習サービスAidemy［アイデミー」
https://aidemy.net/

本日4回目メモ。

#Aidemy4回目メモ
##辞書型
複数のデータを扱うオブジェクトには、リスト型の他に辞書型がある。
辞書型の場合にはインデックスが割り振られず、キー(key) と バリュー(値) をセットで格納する。
(JSON形式に相当)

```{キー1: バリュー1, キー2: バリュー2, ...}```

という形になる

```py

dic ={"Japan": "Tokyo", "Korea": "Seoul"}
print(dic)
```

##辞書の要素を取り出し
辞書からの要素の取り出しは```辞書名["キー"]```という形で指定して取り出す。
**※キーを囲むのは、{}でなく[]であることに注意。**

```py
dic ={"Japan": "Tokyo", "Korea": "Soul"}
print(dic["Japan"])  # Tokyoと出力される
```
Haskell開発環境をWindows 10に構築したメモ(Windows Subsystem for Linux + stack)

# 大まかな手順
※実際に試した手順とは異なる(後述)

1. Windows Subsystem for Linuxをインストール
1. bashからstackをインストール
1. stack ghci

# Windows Subsystem for Linuxをインストール
「 [Windows Subsystem for Linuxをインストールしてみよう！][1]」の手順通り。
以降は全て`bash`上の操作(インストールしたUbuntuを起動)。
[1]:https://qiita.com/Aruneko/items/c79810b0b015bebf30bb

### `/etc/apt/sources.list`の編集はやめておく
`/etc/apt/sources.list`を編集するとハマった。
`haskell-platform`がインストールできなかった。
最低限`sed`する前にバックアップをとっておく。

```
$ sudo apt-get install haskell-platform
Reading package lists... Done
Building dependency tree
Reading state information... Done
E: Unable to locate package haskell-platform
```

デフォルトの`/etc/apt/sources.list`では無事インストールできたが、最終的に`apt-get purge`した(後述)。

# stackのインストール
結論から書くとこれ

```
curl -sSL https://get.haskellstack.org/ | sh
```

### (おまけ)haskell-platformをインストールしたけど、~~ghci~~もstackも入ってない

__※(追記)ghciは実際には入っていて、単なるtypoで見つからなかった可能性大__

```
sudo apt-get install haskell-platform
```

で`haskell-platform`をインストールした。
`ghc`も`runghc`も動いた。
しかし..

```
$ stack ghci
Command 'stack' not found, but can be installed with:
sudo apt install haskell-stack

$ gchi
Command 'gchi' not found, did you mean:
..
```

__※(追記)typo [正]ghci [誤]gchi__
..さようなら、`haskell-platform`。


```
sudo apt-get purge haskell-platform
```

### apt-getでインストールしたstackが動かない

```
$ sudo apt-get install haskell-stack
..
$ stack ghci
Writing implicit global project config file to: /home/hugin/.stack/global-project/stack.yaml
Note: You can change the snapshot via the resolver field there.
Using latest snapshot resolver: lts-12.10
Downloaded lts-12.10 build plan.
AesonException "Error in $.packages.cassava.constraints.flags['bytestring--lt-0_10_4']: Invalid flag name: \"bytestring--lt-0_10_4\""
```

「[AesonException Invalid flag name: \"bytestring--lt-0_10_4\""](https://github.com/commercialhaskell/stack/issues/4077)」に解決方法が。
> With 1.7.1, you should no longer get the AesonException
> I have uninstalled the system's `haskell-stack` and the one installed locally. I've run `curl -sSL https://get.haskellstack.org/ | sh` and now all is fine. Thank you.

haskell-stackをアンインストールせずに実行して失敗したので、下のコマンドを実行して無理やりインストールした(非推奨)。

```
curl -sSL https://get.haskellstack.org/ | sh -s - -f
```

# stack ghci

```
stack ghci
```

`ghci`がインストールされてない場合はインストールされる。
インストール完了後、`ghci`が起動する。

```
Prelude> :q
```

で終了する。

### ghciの起動も動作もサクサク

以下のような記事があって心配したが、実際はサクサク動いている。
SSDの恩恵か、単に最新の環境では解消しているのか。

```
$ time stack ghc -- -e 'print "Java + You"'
"Java + You"

real    0m0.315s
user    0m0.219s
sys     0m0.172s
```

> ghci（Haskellの対話実行環境）やビルドが異常に遅いのです。下記の簡単なワンライナー実行するだけで6秒もかかります。
> ― [Haskell入門しようとして環境構築で失敗。](https://gist.github.com/sys9kdr/2484ed09f5cb7ea86beae8f5222d9a3c)

> ghcやghciやrunghcの起動にいちいち2分ぐらいかかる。
> ― [Windows Subsystem for Linuxをインストールしてみよう！][1]

# 実際の手順
本記事の手順は、実際に実施した手順と異なるため失敗するかもしれない。
このように迷走したことにより、たまたまうまく行っているコマンドがあるかもしれない。

1. Windows Subsystem for Linuxをインストール
1. sudo apt-get install haskell-platform
1. sudo apt-get install haskell-stack
1. curl -sSL https://get.haskellstack.org/ | sh -s - -f
1. sudo apt-get purge haskell-platform
Raspberry Pi3 にてオーディオジャックから音声を出力する

#■はじめに
Raspberry Pi（以下ラズパイ）にHDMIを接続していると、ラズパイ側のオーディオジャックから音が出ないことがあります。明示的にオーディオジャックから音を出すようにします。

#■手順1. raspi-configの起動
root権限にて、raspi-configを起動します。
コマンド：`raspi-config`

```sh:
root@raspberrypi:~# raspi-config
```

>root権限でないとエラーが出ます。
>
```sh:
pi@raspberrypi:~ $ raspi-config
Script must be run as root. Try 'sudo raspi-config'
pi@raspberrypi:~ $
```

#■手順2. raspi-configの設定
青いraspi-configウィンドウが起動しますので、設定変更を掛けていきます。
矢印キーとenterキーで進めます。

①「7 Advanced Option」を選択
![image.png](https://qiita-image-store.s3.amazonaws.com/0/201787/cb3bc6e7-3df0-9718-1764-918fd9e16ee4.png)

②「A4 Audio」を選択
![image.png](https://qiita-image-store.s3.amazonaws.com/0/201787/afc3a9c6-bcc4-9795-bf43-372516917fd0.png)

③「1 Force 3.5mm ('headphone') jack」を選択
![image.png](https://qiita-image-store.s3.amazonaws.com/0/201787/b4853b07-ada4-7c03-ff97-d6575f143088.png)

④「\<Back>」を選択し、終了
＃矢印キーを左右に押すと下部の<Select>と<Back>を選べます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/201787/bb7a09a2-ec74-bab1-daa5-673369fe6645.png)

⑤コンソールの終了
raspi-configを終了すると、再びコンソールに戻ってくるため、exitします。
＃一番上の「raspi-config」は最初に打ったコマンド。

```sh:
root@raspberrypi:~# raspi-config
numid=3,iface=MIXER,name='PCM Playback Route'
  ; type=INTEGER,access=rw------,values=1,min=0,max=2,step=0
  : values=1
root@raspberrypi:~# 
root@raspberrypi:~# exit
```

#■完了
ネットがつながっている場合はyoutubeでも流してみれば、音声出力が確認できるかと思います。


#■参考/出典
AUDIO CONFIGURATION
https://www.raspberrypi.org/documentation/configuration/audio-config.md
＃あとで発見したけど、configの方が簡単だったかもしれない・・・

オーディオ設定
http://igarashi-systems.com/sample/translation/raspberry-pi/configuration/audio-configuration.html

Ras Pi 3 スピーカーから音を鳴らす！そしてOpen JTalkで日本語を喋らせる！
https://iot-plus.net/make/raspi/speaker-open-jtalk-japanese-speech/
Raspberry Pi3の日本語入力を有効にする

#■はじめに
Raspberry Pi（以下ラズパイ）にて、日本語入力が出来るようにします。
＃初期状態では、なぜか日本語表示はされますが、日本語入力が出来ないので・・・

#■インストール
・パッケージリストをアップデート
`sudo apt-get update`

・Google日本語入力の「Mozc」のパッケージをインストール
`sudo apt-get install fcitx-mozc`
＃特に入力や設定は不要

・インストールが完了したらOSリブート

#■日本語切替キーの設定
windowsでは「全角/半角 漢字」キーで半角英語と日本語を切替えられますが、ラズパイではその役割を設定してあげる必要があります。

①メニューから「設定」→「Fcitx設定」を選択します。

②「入力メソッドの設定」から「全体の設定」タブを選択します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/201787/5a068685-1a5d-b01f-a89d-8880d8ea892d.png)

③「ホットキー」の「入力メソッドのオンオフ」をクリックすると、キー入力待ちとなるので、日本語切替キーとしたいキーを押します。今回は「全角/半角 漢字」キーを押下しています。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/201787/00dd9b45-88c0-48b6-5a72-81305967e4b8.png)
↓
![image.png](https://qiita-image-store.s3.amazonaws.com/0/201787/d878e4e8-9de2-ea96-30a6-587b02841a00.png)


#■日本語入力の確認
テキストメモを開き、先ほど設定した日本語切替ホットキーを押下すれば、日本語入力が出来るようになりました。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/201787/45ec5eef-f435-99cf-9cca-18dbf6ce86db.png)



#■参考/出典
IT女子のラズベリーパイ入門奮闘記
第63回 Raspbian Stretchと日本語変換（fcitx-mozc）
https://deviceplus.jp/hobby/raspberrypi_entry_063/
キーボード組み立てやした ＿(　_´ω`)_ﾍﾟｼｮ

#【はじめに】どこから仕入れたん？？
仕入れたのは、KBDfansのサイトで購入しました(*‘∀‘)
[クリックするとサイトに飛ぶっす](https://kbdfans.cn/)
・TADA68 KEYBOARD DIY KIT：アルミブラック
・cherry RED
この２つを購入しましたぜ！！
なんとなく、"F1.8mm LED 100PCS" も買ってしまったがな(๑• ̀д•́ )✧+°ﾄﾞﾔｯ
<img src="https://qiita-image-store.s3.amazonaws.com/0/248438/57be7d4a-dd46-161d-3f0b-2bae3335fd86.jpeg" width=50%>
TADA68 KEYBOARD DIY KIT　製品リスト
・TADA68 PCB 
・TADA68アルミケース
・TADA68染料サブキーキャップ68keys
・USBケーブル
・プレート 
・スタビライザー
・マニュアル
・ゴム足
・スクリュー
・ねじ

#【必要な部品】何あれば良き？？
キーボードの部品としては、
・PCB(プリント回路基板)
・プレート(スイッチを固定)
・スイッチ
・キーキャップ
・スタビライザー(大きいキーキャップをサポート)
・キーボードケース
この６点があれば上出来じゃない(●´ω｀●)？ｳﾌﾌ
<img src="https://qiita-image-store.s3.amazonaws.com/0/248438/65af2561-1673-e74e-9e95-ce4f1545b600.jpeg" width=50%>

#【必要な道具】ぼく、〇ラえもん～
・はんだごて
・ドライバー

スイッチをPCBにつけるときに、はんだごてを使います。
はんだごてを使わないPCBがあるよ！
**Hot Swap**これだと使わないだすよ(`･ω･´)！！

#【組み立て】やっとこさ、作るよ
まず、プレートにスイッチとスタビライザーをハメ込むぜ...φ(・ω・｀)ﾎﾞｼｭﾎﾞｼｭ
<img src="https://qiita-image-store.s3.amazonaws.com/0/248438/1d8554ad-cb1d-8a67-3076-28cd06525ac0.jpeg" width=50%>
今回のスイッチはメカニカルですぞ！赤軸ですぞ！
種類はたくさんあるから調べると悩むことになるo(；△；)o

全部ハメ込んだら、スイッチの爪が "立っているか" を確認！
寝ているのを起こす！！
<img src="https://qiita-image-store.s3.amazonaws.com/0/248438/c859f3e4-5d24-5fa4-e808-13db4707f849.jpeg" width=50%>

#【組み立て】作ってる感が出てきたね
次にPCBの穴に、スイッチの爪を挿入！
ちゃんと穴に爪が入っているか確認だ！( ｰ`дｰ´)ｷﾘｯ
<img src="https://qiita-image-store.s3.amazonaws.com/0/248438/ce40d6c3-d1c0-f992-6306-a6bcde384e82.jpeg" width=50%>
全部、入っていることを確認が完了したら！
出ている爪をはんだごてで、固定していくぜぇいぜぇい！
<img src="https://qiita-image-store.s3.amazonaws.com/0/248438/449e0492-8a06-6029-292d-3f61f893d4c3.jpeg" width=50%>
固定を終えたら。。。

#【組み立て】いよいよ、クライマックス★
ケースに入れて、ドライバーとねじと気持ちで固定だぁぁぁああああ！！
<img src="https://qiita-image-store.s3.amazonaws.com/0/248438/45731bac-b4a6-2caa-11a7-24879705931c.jpeg" width=50%>

あとは、キーキャップを...φ(・ω・｀)ﾎﾞｼｭﾎﾞｼｭ

<img src="https://qiita-image-store.s3.amazonaws.com/0/248438/cbaca617-af7a-2194-a7a8-ead845ab138a.jpeg" width=50%>
聖なるキーボードの完成だよ。:hear_no_evil:ｷｬｰｰｰｰ素敵☆+:

#【組み立て】仕・上・げ・に…❤
おいおいおいおいおい！！クライマックスじゃねーじゃん！！(((((;｀Д´)≡⊃)｀Д)､;'.･
(ﾉ≧ڡ≦)てへぺろろん❤
これで完成ではないんです！ムムム！！
ちゃんとキーが反応するのかが重要なんです！
[クリックするとキーテストサイトに吹っ飛び](http://www.keyboardtester.com/)
私はここで事件が起こった。。。
あれ？んっ？！
「→」のキーが反応しねぇ。。。(´；ω；｀)(´；ω；｀)ﾌﾞﾜｯ…ｳｩ;;;;
PCBを確認したら、部品が失ってたよ。
![不備.jpg](https://qiita-image-store.s3.amazonaws.com/0/248438/58d700ae-0ef3-0fc7-2c56-1481efe541bb.jpeg)
あれ？キーキャップおかしくねぇ？ざわざわざわ………ざわざわ
<img src="https://qiita-image-store.s3.amazonaws.com/0/248438/a49b2474-da06-a3d1-d177-07817acf2636.jpeg" width=50%>
ページダウンの反応するんだけどよぉ。。
ページダウンは「Fn」って記述しなくねぇ？【審議中】　(　´・ω) (´・ω・) (・ω・｀) (ω・｀ )
審議の結果「不備の一点張り」⊂⌒~⊃｡Д｡)⊃ ﾄﾞﾃｯ

#【おわり】チャンチャン♪
PCを改造をしようと思いましたが、デスクではなくノートなのでなんか違うと思い
他を見渡したら、キーボードが目に入ったので作ってみました m9っ`･ω･´)ｼｬｷｰ:zap:

まぁ、不備は出ましたが楽しかったから(ﾟзﾟ)ｲｲﾝﾃﾞﾈｰﾉ?
一応問い合わせてはみるがな！
今回はUSキーボードの配置なので、覚える必要があるなぁ。。
配置変更もできるので、これまたオモシロイ:sparkles:
[クリックすると変更ができるサイトに、とぅぶよ](http://123.57.250.164:3000/tada68)
[クリックすると変更のやり方動画どすえ](https://www.youtube.com/watch?v=F-tKs628LV0のプログラミング方法 )

キーボードについてまだまだ、話したいことがある(:.;ﾟ;Д;ﾟ;.:)ﾊｧﾊｧ
これはのちにっつーことで！

以上、**「キーボード組み立てやした ＿(　_´ω`)_btnﾍﾟｼｮ」**でした。
コミット漏れがあればCIを失敗させたい

コミット漏れがあったときCIを失敗させたい。
ビルド結果などコミットしないといけない場合など必要になる。

つまり、gitでuntrackやmodifiedファイルがあった場合にステータスコードをエラーにしたい。
なにかそういったgitコマンドのオプションがあるような気がするが、見つけられなかったので適当に用意した。

```bash

#!/bin/bash
set -ev

STATUS=`git status -s`  # -s をつかって出力があるかどうか確認する

if [ x"${STATUS}" != x ]
then
  git status # 失敗したときはgit statusをだしておけば原因がわかりやすい
  false
fi
```
音を周波数帯ごとに分けるプログラム

初投稿になります．

音を低周波数帯，高周波数帯，その間に分けるプログラムを作ったので需要があるかどうかはわかりませんが上げておきます．

soxでhighpass,lowpass処理はできるにはできるのですが，sox([link](http://sox.sourceforge.net/sox.html#EFFECTS))の説明を読む限り設定した周波数から音の大きさを減少させていく感じになっているとになっていました．

なので，1つのwavファイルに対して一回STFTでスペクトログラムにしたあと，特定の周波数帯以外を0にしてISTFTして完全に他の周波数帯が入らないようにしました．

##configの説明
---
codeでのconfigに対する説明になります．
* N_FFTとHOP_LENは短時間フーリエ変換，短時間逆フーリエ変換を行う際のパラメータなのでここはいじらなくても大丈夫だと思われます．
* LOWCUT_HZ:ここは実際の周波数帯を打ち込むのではありません．(すいません紛らわしくて)現状では10でだいたい300Hzぐらいです．
* HIGHCUT_HZ:ここも実際の周波数ではありません(30でだいたい1000Hzぐらいです

##requirement
---
 * librosa
 * tqdm
 * numpy
 * matplotlib

##おまけ
それぞれカットされたものがどのようなスペクトログラムになっているのかを表すコードもつけておきました．使うときには'''を外してください

```python
fig,axes = plt.subplots(ncols=3,nrows=1,figsize=(12,9))
plt.subplot(3,1,1)
display.specshow(spec_high,hop_length=HOP_LEN,x_axis='time',y_axis='hz')
plt.subplot(3,1,2)
display.specshow(spec,hop_length=HOP_LEN,x_axis='time',y_axis='hz')
plt.subplot(3,1,3)
display.specshow(spec_low,hop_length=HOP_LEN,x_axis='time',y_axis='hz')
plt.show()
```

##Codeの場所
ここ([link](https://github.com/morikwa/relative_sound/blob/master/sound_cut_by_Hz.py))にあります．
git 超超初級　ディレクトリ作成　ファイル作成

アウトプットメモです！
一応僕みたいに超超初心者の方が見てくれた時の為にわかりやすーい感じで書きます！
gitがとても便利なんだなって少しずつ分かってきた。
gitが楽しくなってきた。
ファイルを作ったり、ディレクトリ（フォルダ）を作る所からつまずいた。

１、ディレクトリ作成。　

```
　mkdir （ディレクトリ名）
```
２、作ったディレクトリに移動。

```
　　cd （ディレクトリ名）
```
３、作ったディレクトリを今から使うよーって宣言する！。

```　　
git init
```
４、ディレクトリの中にファイルを作る。　

```
　vim （ファイル名）
```

ここから超超初心者の僕は忘れがち&理解するのに少し時間がかかった。

５、使ったファイルを登録する様な感覚？

```
　　git add （ファイル名）
```
６、登録？した後に、登録しただけではなんのファイルか分からないから名前をつけて保存してあげる、分かりやすい名前を！　　

```
git commit -m "(コミット名)"
```
７、ファイルを編集する　　

```
vim (ファイル名）
```
８、編集したファイルを再度登録！　

```
　git add （ファイル名）
```
９、そしてまた名前をつけて保存、ここでは編集した事とかを簡単に名前にする！

```
　　git commit -m "（ファイル名）"
```

こんな感じで、ディレクトリを作ってファイルを作って、そのファイルを登録？して名前をつけて保存してあげる、そして編集したらまた登録？して名前をつけて保存をする。

branchとmergeの概念も理解出来てgitが楽しくなってきました！
gitを使いこなせる様に頑張って勉強しよー。
アウトプットも頑張って更新しよう！
人に見せれる様にするのって本当に難しい。
アウトプットの仕方も勉強しないと。
もし間違っている所とかあればご指摘の程お願いいたします。
flowtypeで始めるsealed case pattern

皆さん、こんにちは！！
ちょっと社内でScalaのsealed pattern matchみたいに全ての型を網羅できるか検証する方法が話題になったのでまとめておきます。

* [Pattern matching via switch should not require default case if all cases are handled](https://github.com/facebook/flow/issues/1835)
* [Empty type ](https://github.com/facebook/flow/issues/2225)

元ネタに関しては上記2つのissueをご参照ください。

# ユースケース

例えば下記のように`A | B`というUnion Typeを全網羅する`switch`を書いたときに、この`switch`が全網羅されていることを担保したい時がありませんか？
仮に`A | B | C`のようにUnion Typeが追加されたさいに`C`が新しいケースとして追加されるべきなのに、そこの対応を漏らして`default`になってしまっていたとかよくある話だと思います。

```js
type A = { type: 'A' };
type B = { type: 'B' };

declare var o: A | B;

switch (o.type) {
  case 'A':
    // ...
    break;
  case 'B':
    // ...
    break;
  default: // ...
}
```

そういった問題を防ぐためにsealedして新しい型が追加されたときにケースの追加漏れを防ぎます。

# sealed case

```js
type A = { type: 'A' };
type B = { type: 'B' };
type C = { type: 'C' };

declare var o: A | B;

switch (o.type) {
  case 'A':
    console.log(`type A == ${o.type}`);
    break;
  case 'B':
    console.log(`type B == ${o.type}`);
    break;
  default: (o:empty)
}
```

[Try Flow](https://flow.org/try/#0PQKgBAAgZgNg9gdzCYAoVAXAngBwKZgCCYAvGAN5jb4BcYA5IfWAL4DcmuBAQqRVVzr1uzdp3xgAwn0rU8QyaI6oAJngDGMAIYAnAgDddYOHWIAfMN2UBnBAEsM6gBZgAFHAB0cgJQVUYMHUtawJGehp-AMC4ADtrOBg8D3gAc1cAAzkiUjIAEnJPORZ07w4osAAjPS0AazLA4NCRCPL1WPjE5Lg0zK5LHLB8wq5i0siAqrxa+rUoLQBXGAw6dxo8AFscbG9UFiA)

やり方は簡単で`default`ケースにて`(o:empty)`と`empty`にキャストするだけです。簡単ですね！！
仮に`declare var o: A | B; | C`のように`C`を追加すると、`empty`へのキャストでエラーが出るようになります。

何故、このような動きをするのかというと[Type Refinement](https://flow.org/en/docs/lang/refinements/)が関わってきます。
今回の場合で言うと`case 'A'`のステートメントでは`o`は`A`型としてType Refinementされます。
逆に言えばその他のswitch内のステートメントでは`A | B`から`A`を除いた`B`型であるといえます。
次の`case 'B'`のステートメントでは`o`は`B`型としてType Refinementされ、最後に残った`default`のステートメントでは`A | B`から`A`と`B`を除いた何にもマッチしない型（=`empty`）であるとType Refinementされることになります。
そのため、`default`のステートメントでは`o:empty`というキャストが成功することになります。

しかし、`A | B | C`の場合はどうでしょうか？
`A | B | C`から`A`と`B`を除いた型は`C`になるため`(o:empty)`で`C`を`empty`にキャストしようとして失敗します。

# 蛇足

蛇足話ですが、`A | B`から`A`を除外とか言うと`$Diff<A, B>`のことを思い出しますが、`$Diff<A, B>`を使っても同じようなことはできません。
`$Diff<A, B>`は`A`と`B`に`Object`型を指定して、`A`のプロパティから`B`のプロパティを除外するための型なので、同じことはできません。

さらに蛇足話ですが、`A & B`の場合はどちらも満たす型なので、常に一つめのケースにマッチします。
（というか今回のケースだと`A & B`を満たす型の値は絶対に作れないのでアレですけど）

# まとめ

と言う訳でいかがでしたでしょうか。
昨今のJSではよくstring literalのenumを作ることが多いので結構登場頻度の多い技術かと思います。
`$Keys`や`$Values`、`$ElementType`などenumと組み合わせて使えるUtility Typeもあるので、sealedと組み合わせてより良き型安全の世界を楽しんでください。
【初心者向け&メモ】react-native initしてwelcome画面出すまで

# やりたいこと
ただ、公式ドキュメントの通り手順を進めて
```react-native run-ios```コマンドでビルドしたい（welcome画面を表示したい）...
てだけ。

<img width="250" alt="スクリーンショット 2018-09-23 23.43.01.png" src="https://qiita-image-store.s3.amazonaws.com/0/283557/fb49d3fc-d8c0-e4d8-a91f-13e1fc25bfe3.png">

公式ドキュメント↓
https://facebook.github.io/react-native/docs/getting-started


ただし、パッケージ管理はyarnでやりたい！（今回はnpm使いたくない）

# 手順
#### 公式ドキュメントに言われた通りに手順を踏んでいく。
nodeのインストール
https://qiita.com/kuriya/items/36ae29366df0b7c95dec

- node, watchmanのインストール
　インストール後、
```node --version```
```v8.5.0```
```watchman --version```
```4.9.0```
て感じ。

- react-native-cliのインストール
```npm install -g react-native-cli```の代わりに
```yarn global add react-native-cli```を実行した。
ちなみに、yarnのバージョンは1.7.0です。
バージョン確認すると、
```react-native --version```
```react-native-cli: 2.0.1```
という感じに。

#### 初期設定
これも言われた通りにやっていく(プロジェクトの名前はとりあえずAwesomeAppにした)

```react-native init　AwesomeApp```

React Nativeのバージョンを指定したければ、
（多分こっちの方がいいんじゃないかと思う。）
```react-native init　AwesomeApp　--version 0.55.4```
を実行する。

#### ビルド
```cd AwesomeApp```
```react-native run-ios```

これで目的の画面出るはず。
ここで、例えばbabel関係のエラー出てビルド失敗することがあるらしい。
その時はreact nativeのバージョンが0.57だったのでバージョンを指定したら治ったそう。
RTX2080の学習速度をざっくり検証（追加）

と言うわけで、RTX2080を買ってみました

計算速度を比較するためにVGG16のファインチューニングを
下記の設定でやってみました。
GTX1080Tiは違うパソコンでやったため参考でお願いします

~~GTX1080TiとRTX2080との速度比較ですが~~
~~**RTX2080のほうが11%ほど早い**結果となりました。~~

GTX1080Tiの端末に新しく仮想環境を作成しRTX2080と各種ライブラリを
同じバージョンにしたところ**GTX1080Tiのほうが3%ほど早くなりました（泣**

機械学習をするだけであればメモリが3GB多く、値段が4万円安い
GTX1080Tiのほうが良さそうですね・・・

※△１　CUDAを9.0->9.2の計算結果も掲載
※△２　GTX1080Tiの結果を追加
※△３　GTX1080Tiのライブラリのバージョン等を同じに
※△４　GTX1070のノートとGV100追加

#計算内容
　・トータルパラメーター：18,918,213
　・training：2548枚
　・validation：150枚
　・バッチサイズ：32
　・エポック：50

#計測環境
CPU:i7-8086K
メモリ：16GB
OS:Windows10Home
cuda:9.0.176
CuDNN：v7.3
python：3.6.6
tensorflow：1.10.0
keras：2.2.2

#計測結果(CUDA9.0+CuDNNv7.3)

timeはスタートから50エポック完までです。

|GPU|CUDA Cores|Tensor Core|Memory Bandwidth|time(sec)|
|---|---|---|---|---|
|GTX1070|1920|N.A|256.3 GB/s|1547|
|GTX1080Ti|3584|N.A|547.2 GB/s|実施無|
|RTX2080|2944|368|448 GB/s|1065|

#計測結果(CUDA9.2+CuDNNv7.3)

timeはスタートから50エポック完までです。
GTX1080Tiは**マシーンが違う（CPU:Xeon）**ので、参考記録としてください

|GPU|CUDA Cores|Tensor Core|Memory Bandwidth|time(sec)|
|---|---|---|---|---|
|GTX1070|1920|N.A|256.3 GB/s|1530|
|GTX1070_note|1920|N.A|?|2000|
|GTX1080Ti|3584|N.A|547.2 GB/s|1015|
|RTX2080|2944|368|448 GB/s|1048|
|GV100|5120|640|870GB/s|730|
Visual Studio Codeを日本語化する方法

Visual Studio Codeの日本語化手順のメモ書き。
現バージョンではlocale.jsonの編集で日本語化できるようだが、
`近い将来、VS Codeはマーケットプレイスの拡張機能のみをサポートします。`
とのことなので言語パックの導入方法を記述。

### 確認した動作環境

- Windows10(64bit)
- Visual Studio Code Version: 1.27.2(user setup)

### Setup直後の状態

英語表示で起動しました。
![vscode01.PNG](https://qiita-image-store.s3.amazonaws.com/0/294534/0f347810-db07-061d-67cf-b774018ae0da.png)

### マーケットプレイスで日本語パックを検索

MARKETPLACEで「Japanese Language Pack」を検索。
「install」（緑色の小さいやつ）をクリック。
![vscode02.png](https://qiita-image-store.s3.amazonaws.com/0/294534/f68b4dfa-c4db-8c22-78ce-f58ec80c245e.png)

### 再起動
インストールが完了すると右下に再起動を促すメッセージが表示されるので、「Yes」を選択して再起動。
![vscode04_trim.png](https://qiita-image-store.s3.amazonaws.com/0/294534/2570480c-f987-2bc4-40d8-6030d63fef8b.png)

### 日本語化完了
日本語表示で起動を確認。
![vscode05.PNG](https://qiita-image-store.s3.amazonaws.com/0/294534/6a53099c-07f8-a4d9-4e6b-a16af950caba.png)

---
Visual Studio Codeのダウンロードはこちら >[Visual Studio Code](https://code.visualstudio.com/)
Herokuにデプロイする方法（本番環境のデータベースはPostgleSQL）

# こんな人に見て欲しい
Herokuへのデプロイがうまくできない方へ
（本番環境のデータベースはPostgleSQL）

# 経緯

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">【学習メモ】28/70day 280.5/700hour<br><br>スクール通い出して早4週間<br>『デプロイできない…→できた！→viewが表示されない…→DB無いからだ！→DB作れない…→DB設定おかしいからだ！→DBできた！viewも表示された！きたー！』<br>っていうのをチームで経験できたのが一番の思い出<a href="https://t.co/24hV8F0ij6">https://t.co/24hV8F0ij6</a></p>&mdash; じーこ@目指せ筋肉エンジニア🐯 (@jiko797torayo) <a href="https://twitter.com/jiko797torayo/status/1043142162999693312?ref_src=twsrc%5Etfw">2018年9月21日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


ということで具体的にどうやったのか記録に残しておきます！

# 環境
- macOS High Sierra
- ruby 2.3.1p112 (2016-04-26 revision 54768) [x86_64-darwin17]
- Rails 5.0.7


# 手順
### ①本番環境でPostgleSQLを使用するよう設定する。

★Gemfileに以下のコードを記入する。

```Gemfile.
gem 'pg', 'バージョン', group: :production
# 本番環境でpostgresqlを使用するよう設定する。

gem 'mysql2', 'バージョン', group: [:development, :test]
# 上記に伴い、本番環境以外ではmysql2を使用するよう設定する。
# mysql2と記入している理由は元々mysql2を使用していたため。
# sqlite3を使用しているならsqlite3を記入する。
```

★gemをインストールする。

```terminal.
$ bundle install
```

### ②database.ymlを設定する。
★DATABASE_URLが表示されるか確認する。

```terminal.
$ heroku config
DATABASE_URL: postgres://〜〜〜
```

※DATABASE_URLが表示されなければ以下のコマンドでアドオンを追加してから、もう一度『heroku config』を実行する。

```terminal.
$ heroku addons:create heroku-postgresql:hobby-dev
```

★database.ymlに以下のコードを記入する。

```database.yml
production:
  <<: *default
  adapter: postgresql
  database: db/production.postgresql
  url: <%= ENV['DATABASE_URL'] %>
  # 環境変数DATABASE_URLを参照するよう設定する。
```

### ③Heroku上にアプリを作成する。
★Herokuにログインする

```terminal.
$ heroku login
# emailとpasswordを入力する。
```

★Heroku上にアプリを作成する。

```terminal.
$ heroku apps:create アプリ名
```

★リモートリポジトリを確認する。

```terminal.
$ git remote -v
# heroku上に正しくアプリを作成できていれば下記が表示される
heroku  https://git.heroku.com/アプリ名.git (fetch)
heroku  https://git.heroku.com/アプロ名.git (push)
```

★Herokuへpushする。

```terminal.
$ git push heroku master
```

★マイグレーションを実行する。

```terminal.
$ heroku run rake db:migrate
```

# おわりに
以上、Herokuにデプロイする方法（本番環境のデータベースはPostgleSQL）でした。
少しでも参考になればと思います。

『もっと簡単にできる方法あるよーーー！』『ここ間違っているよーーー！』等ございましたらご連絡いただけると幸いです。

※参考ページ
https://devcenter.heroku.com/articles/git
https://qiita.com/shou1012/items/bf55a185920e717f4011
https://qiita.com/NaokiIshimura/items/550ca82e8e57aaea5582
Laravel 5.6 で HTTPS が効かないときの対処法、の盲点

# TrustProxies の問題だと思っていた
環境は、次のとおり。

- Laravel 5.6
- Apache 2
- AWS ELB (ロードバランサー)

ロードバランサーを使っていると、HTTPS であっても Laravel には 80 ポート HTTP でアクセスするため、URL を http:// に置き換えてしまいます。
これに対する対処法は[公式ドキュメント](https://readouble.com/laravel/5.6/ja/requests.html)があり、Web 上に資料がたくさんあります。
しかし、どうにも HTTPS が効かなかった。
その理由は……

# ただの URL ミスでした
恥ずかしながらも、URL の末尾に / を付けるか否かで挙動が変わるようですね。
`<a href="/login/"><button>ログイン</button></a>`を
`<a href="/login"><button>ログイン</button></a>`
にしたらあっさり解決しました。
これは盲点。

# TrustProxies の仕様変更
現在 TrustProxies を検索すると、5.5 の情報がよく出てきます。
しかし、5.5 と 5.6 は微妙に仕様が変わっています。

[5.5 のドキュメント](https://readouble.com/laravel/5.5/ja/requests.html)
[5.6 のドキュメント](https://readouble.com/laravel/5.6/ja/requests.html)

最後の「信用するプロキシの設定」を見てください。
よーく見ると、

5.5 は`protected $proxies = '**';`
だけど 5.6 は`protected $proxies = '*';`

になってます。
あと、5.6 には AWS ELB を考慮した Request::HEADER_X_FORWARDED_AWS_ELB が追加されてるようですね。
これも盲点。
画面の描画前にjavascriptを実行する方法(DOMContentLoadedイベントを利用)

#画面の描画前にjavascriptを実行する方法
##説明
画面が表示されたが、ロード中の為リンクなどを押下されたくないということがある。
その際に、一般的にはよく知られている「onload」イベントで「pointer-events: none」を指定すると思うが、これでは画面が描画仕切ってから実行されることになってしまう為、ロード中にユーザが操作をしてしまい、想定外の挙動をしてしまう可能性がある。
そこで利用するのが、以下のイベントである。

**＜イベント＞**
**DOMContentLoaded**

これは、htmlの解析が完了した時に発生するイベントの為、html内の画像やCSSやJavascriptの読み込み前に発生している。
その為、このイベントを利用すれば、画面の描画前に実行したいjavascriptを実行することが出来る。
具体的な利用方法を以下に記載する。
##サンプルプログラム
ロード時にクリックをすべて無効化する指定を追加するプログラム

```javascript:サンプルプログラム
window.addEventListener('DOMContentLoaded', function () {
  //bodyタグを取得
  var obj = document.querySelector("body");
  //bodyタグにクリックイベントを無効化するstyleを追加
  obj.setAttribute("style", "pointer-events: none;");  
  //コンソールへのログ出力
  console.log("DOMContentLoadedイベントが実行されました。");
});
```
###検証
本当にonload前に実行されるのかを検証した結果を以下に記載する。

```html:検証プログラム
<html lang="jp">
<header>
    <meta charset="utf-8"/>
    <script>
        //onloadイベントとDOMContentLoadedの実行順について
        window.addEventListener('load', function () {
            var div = document.querySelector("div");
            var p = document.createElement('p');
            p.innerText = "loadイベントが実行されました。";
            div.appendChild(p);
            console.log("loadイベントが実行されました。");
        });
        window.onload=function () {
            var div = document.querySelector("div");
            var p = document.createElement('p');
            p.innerText = "onloadイベントが実行されました。";
            div.appendChild(p);
            console.log("onloadイベントが実行されました。");
        };
        window.addEventListener('DOMContentLoaded', function () {
            var div = document.querySelector("div");
            var p = document.createElement('p');
            p.innerText = "DOMContentLoadedイベントが実行されました。";
            div.appendChild(p);
            console.log("DOMContentLoadedイベントが実行されました。");
        });
    </script>
</header>
<body>
    <div>これは、onloadイベントとDOMContentLoadedの実行順について検証するhtmlです。</div>
</body>
</html>
```

###検証結果
![image.png](https://qiita-image-store.s3.amazonaws.com/0/204260/52849029-d581-bee6-5000-a29ffd36a394.png)
画面に「"DOMContentLoadedイベントが実行されました。"」が「"loadイベントが実行されました。"」より前に表示されている為、onload前に実行されていることが分かった。
オープンソースにPull Requestするメリット

## 概要

PlayFrameworkというオープンソースに小さなPull Requestを出した時の話。
オープンソースにPull Requestするメリットが大きかった為記載する。

### Pull Request提出時の修正内容

http requestを投げた時のエラーレスポンスコードが一部足りなかったので追加した。
javaファイルのみ修正。単体テストちょこっと。


・・・諸々レビューを受けた（後述）結果・・・

### Pull Requestがマージされた時の修正内容
・javaとscalaのレスポンスコード追加
・単体テスト追加・修正（修正メソッドのケースが綺麗にカバーされた）

では、何が起きたのかも踏まえて以下メリットを記載する。

## Pull Requestするメリット3点

### １.プロから無料でレビューしてもらえる。

Pull Request時以下の指摘をもらった。

1. javaだけでなくscalaコードもあるのでそっちも一緒に直してくれないか。
2. xxのケースの単体テストを書いてくれないか。※絶妙に考えるヒントも添えてくれた。

数行の簡単な修正に対し丁寧に教えてくれる人は何人いるだろうか。

大概が
・スルーでOKされる。
・答えのコードが書かれて"はよ終わらせや"オーラのコメントを添えられる。
っていう流れが大概ではないだろうか。

オープンソースのPull Requestは確実に丁寧にゆっくり正確に教えてくれる。

### ２.プロのコードから単体テストの書き方が学べる

単体テストの書き方に悩む人は少なくない。

Pull Requestは大概単体テストも直せと言われるので、
他の人(プロ)が実装した他の単体テストも読むことになる。
つまりプロの単体テストを見ながら書き方を学ぶことができるのだ。

普段からオープンソースの単体テストを読んでる人は不要かもしれないが、
ただ利用するだけでそこまで読み倒す人は殆どいないはずだ。

### 3.小さな修正でもContributorになれる

有名ソースのコミットログに名前が載るってなんだかんだ嬉しいものだ。
"有名オープンソースのPull Requestだしてマージされた。"
はそのコミッターか少しでも認めてくれたってこと。
今後エンジニアとして自信を持つための材料になることだろう。


## まとめ

オープンソースにPull Requestするメリットは以下3つ
・プロに時間をかけてレビューしてもらえる
・プロの単体テストの書き方が学べる
・ワタシコーディングチョットデキル感がでる

## おわりに

当時コミットしたこの修正は既にリファクタリングされ現コードから消えた。
だが現コードの中に当時修正した内容が踏襲されていた。
自分が持って走ったバトンがいつの間にか誰かが持って走って良くなっていく。

それもオープンソースの魅力。
OpenCV 以外の場所にある深層学習ベースの顔検出を調査中(3)

顔検出

PyPI [mtcnn 0.1.1 ](https://pypi.org/project/mtcnn/)

Multi-task Cascaded Convolutional Neural Networks for Face Detection, based on TensorFlow

github [MTCNN face detection implementation for TensorFlow, as a PIP package. ](https://github.com/ipazc/mtcnn)

Youtube [Face detection with MTCNN](https://www.youtube.com/watch?v=EuZzMOYLWrY)



Python3.4 +でのTensorFlow用のMTCNN顔検出器の実装
 これは、FacenetのDavid Sandberg（FaceNetのMTCNN）からMTCNNの実装を参考にして書かれています。 これは、Zhang、Kらの論文に基づいている。 （2016）[ZHANG2016]。


その[BENCHMARK](https://github.com/ipazc/mtcnn#benchmark)を示しており、どの程度実用的な速度がでるのかどうかを意識しているようだ。


[Joint Face Detection and Alignment using Multi-task Cascaded Convolutional Networks](https://arxiv.org/abs/1604.02878)

![1604.02878_pdf_fig1.png](https://qiita-image-store.s3.amazonaws.com/0/83761/ca8d1726-adaf-6d13-0006-56c250b27d52.png)

これは元となった論文のFig. 1です。顔検出と検出位置を改善すること。検出位置を改善したあとに、顔器官点の検出をする部分が別々のネットワークで実現しています。


![1604.02878_pdf_fig2.png](https://qiita-image-store.s3.amazonaws.com/0/83761/231ae3ce-e23d-afd9-21bf-48a0794c1068.png)

これは元となった論文のFig. 2です。それぞれのネットワークの構造を示しています。


https://github.com/ipazc/mtcnn#usage
に書かれている通りの動作を簡単に確かめることができました。

```
$ python3
Python 3.5.2 (default, Nov 23 2017, 16:37:01) 
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from mtcnn.mtcnn import MTCNN
>>> import cv2
>>> img = cv2.imread("ivan.jpg")
>>> detector = MTCNN()
2018-10-02 02:07:10.544632: I tensorflow/core/platform/cpu_feature_guard.cc:137] Your CPU supports instructions that this TensorFlow binary was not compiled to use: SSE4.1 SSE4.2 AVX AVX2 FMA
>>> print(detector.detect_faces(img))
[{'confidence': 0.9985162615776062, 'keypoints': {'nose': (303, 131), 'left_eye': (291, 117), 'mouth_right': (313, 141), 'mouth_left': (296, 143), 'right_eye': (314, 114)}, 'box': [277, 90, 48, 63]}]
>>> 
```

```
$ python3 example.py 
2018-10-02 02:10:58.197932: I tensorflow/core/platform/cpu_feature_guard.cc:137] Your CPU supports instructions that this TensorFlow binary was not compiled to use: SSE4.1 SSE4.2 AVX AVX2 FMA
[{'confidence': 0.9985162615776062, 'box': [277, 90, 48, 63], 'keypoints': {'left_eye': (291, 117), 'mouth_left': (296, 143), 'right_eye': (314, 114), 'mouth_right': (313, 141), 'nose': (303, 131)}}]
```

以下の検出結果のファイルが作成されました。

![ivan_drawn.jpg](https://qiita-image-store.s3.amazonaws.com/0/83761/4e1ce43f-5126-2215-58e7-6de66b0065ef.jpeg)

---

### [Modern Face Detection based on Deep Learning using Python and Mxnet](https://medium.com/wassa/modern-face-detection-based-on-deep-learning-using-python-and-mxnet-5e6377f22674)
 顔検出の紹介記事


## 小さな顔の検出
### https://github.com/alexattia/ExtendedTinyFaces

---


### github https://github.com/HiKapok/X-Detector

X-Detector is a collection of several object detection algorithms. And some of those have not appeared in any academic papers.

---

[OpenCV 以外の場所にある深層学習ベースの顔検出を調査中](https://qiita.com/nonbiri15/items/927d202e7d95e6e81ae5)
[matlab] スクリプト実行ディレクトリを絶対パスで取得する

[pythonでの方法](https://qiita.com/nagamee/items/b7d1b02074293fdfdfff)は知っていましたが，それのMatlab版をようやく見つけたので残しておきます。

```
fileparts(mfilename('fullpath'))
```

以下はテストコード。

```m:test.m
fprintf("mfilename('fullpath')            : %s \n", mfilename('fullpath'));
fprintf("fileparts(mfilename('fullpath')) : %s \n", fileparts(mfilename('fullpath')));
```

```m:実行結果
mfilename('fullpath')            : C:\Users\Ken\Documents\MATLAB\test 
fileparts(mfilename('fullpath')) : C:\Users\Ken\Documents\MATLAB 
```

なぜかファイルの拡張子が省略されます。詳細は[mfilename関数のドキュメント](https://jp.mathworks.com/help/matlab/ref/mfilename.html)を参照。昔調べたときはこの関数を見つけられなくて，Matlabではできないと思ってました。
CSSのみで画面上のリンクやボタンのクリックを無効化する方法(javascriptでタグにstyle埋め込み)

画面にあるボタンのダブルクリックを制御するために、Javascriptでフラグを立てたりと様々な方法で実現している。
ここでは、cssのみでクリックを無効化する方法を記載する。

クリックを無効化するオプションを以下の通り。

```css:クリック無効化オプション
pointer-events: none
```

上記の方法で指定されたものは一切クリックできなくなる。
上記オプションの利用参考例を以下に記載する。

```javascript:クリック無効化オプションの使用例
window.addEventListener('click', function () {
  //bodyタグを取得
  var obj = document.querySelector("body");
  //bodyタグにクリックイベントを無効化するstyleを追加
  obj.setAttribute("style", "pointer-events: none;");
  //5秒後に追加したstyleを削除
  setTimeout(function () {
    obj.setAttribute("style", "")
  }, "5000");
};
```
上記Javascriptは、画面の何れかがクリックされたら画面全体をクリックできないようにしてしまうjavascriptです。
ただし、5秒後には指定したcssを削除するようになっている為、仮にサーバから返答がなくても操作を継続することが出来る。
世界中の飛行機の情報をFreeでリアルタイムに入手する方法

#やろうと思った背景

リアルタイムで現実世界の情報を入手、可視化したいと思ったため

#準備

##EC2スポットインスタンス準備
デスクトップを起動し続けるより、クラウドでサーバを借りたほうが安いです。
※うちのデスクトップを動かすと400円/日 かかると怒られました。


##OpenSkyへの登録
OpenSkyでIDをとりましょう。正確にはとらなくてもデータは取得できる。
https://opensky-network.org/

もし、固定IPを持っている人がいれば、OpenSkyに協力してあげてほしいなぁ。

##NiFiのダウンロード＆実行
https://nifi.apache.org/

Download→Download Nifi→nifi-1.7.1-bin.tar.gz
そのあと表示される一覧からお好きなリンクをどうぞ。

![SnapCrab_NoName_2018-9-23_22-35-53_No-00.png](https://qiita-image-store.s3.amazonaws.com/0/121950/edbf07b0-8105-252d-e13e-44d254cc2960.png)

ダウンロードしたら、ファイルを展開して、以下を実行するだけ。

```
tar zxfv nifi-1.7.1-bin.tar.gz
nifi-1.7.1/bin/nifi.sh
```

##PostgreSQLインストール
PostgreSQLインストールしましょう。

```
sudo yum install -y postgresql96-server
/etc/init.d/postgresql96 initdb
vi /var/lib/pgsql96/data/postgresql.conf
追加：listen_addresses = '*'
```

##Metabaseインストール

可視化ツールとして、今回はMetabase使ってみましょう。
Dockerであれば楽勝です。

```
docker run -d -p 3000:3000 --name metabase metabase/metabase
```


#情報取得 ＆ レコード保存

あとは、APIの仕様に従って、リアルタイム情報を取得するだけです。
https://opensky-network.org/apidoc/

Rest APIが公開されているので、
```https://ユーザ名:パスワード@opensky-network.org/api/states/all
```

私の場合、プログラムが面倒なので、NiFiを用いて、データ取得からPostgreSQLに突っ込むところまでやります。

![SnapCrab_NoName_2018-9-23_22-23-27_No-00.png](https://qiita-image-store.s3.amazonaws.com/0/121950/f53bf507-5968-60cc-dad8-a159f5406c13.png)

![SnapCrab_NoName_2018-9-23_22-41-5_No-00.png](https://qiita-image-store.s3.amazonaws.com/0/121950/1dee1d2a-1cd9-5992-287a-e38548ca36e0.png)

最後にDBに突っ込めばいいと思います。

![SnapCrab_NoName_2018-9-23_22-44-53_No-00.png](https://qiita-image-store.s3.amazonaws.com/0/121950/9daa8ff2-fa04-195d-d74a-3422cdac2636.png)

対象のテーブルは以下のように作成すればよいかと思います。

```SQL:テーブル作成
create table ADSB(
    time int,
    icao24 text,
    callsign text ,
    origin_country text ,
    time_position int ,
    last_contact int ,
    longitude float ,
    latitude float ,
    geo_altitude float ,
    on_ground boolean ,
    velocity float ,
    true_track float ,
    vertical_rate float ,
    sensors int ,
    baro_altitude float ,
    squawk text ,
    spi boolean ,
    position_source int
);
```

#可視化

Metabaseに接続しましょう。
ポートは3000です。

sshでのポートフォワーディングが楽でしょう。

Metabaseの初期化が始まります。（しばらくかかります）

![SnapCrab_NoName_2018-9-23_11-52-12_No-00.png](https://qiita-image-store.s3.amazonaws.com/0/121950/2038cc92-d1c7-ecb3-28fd-3f0d292a0078.png)

途中、Databaseの設定などあるので、ホスト側のPostgreSQLへの接続設定を行いましょう。

host: ホストサーバのIPアドレス。（Docker LANのIPでいいです）
Port、Database、ユーザ名、パスワードはPostgreSQL、またはDBの設定に合わせてください。

![SnapCrab_NoName_2018-9-23_23-10-1_No-00.png](https://qiita-image-store.s3.amazonaws.com/0/121950/93bed231-91ff-4af8-e0e8-ed859c8edd5e.png)

あとは、SQLを適当に実行してMAP表示すると、最新の飛行機の位置が表示されます。
※この時、表示件数が多すぎると表示されないため500程度に絞ったほうがよいでしょう。

```SQL:500台の飛行機の位置表示
select 
 distinct callsign ,latitude,  longitude, avg(Velocity)
from
 adsb
where
 time = (select max(time) from adsb)  
group by 
 callsign, latitude, longitude
 limit 500
```

![SnapCrab_NoName_2018-9-23_14-46-15_No-00.png](https://qiita-image-store.s3.amazonaws.com/0/121950/75a74887-9bc5-e865-72c4-0658f5cc5e51.png)

Pin表示しかできないのが残念ですね。
Google colaboratoryからGoogleDriveの画像読み書きテスト

タダで使えるGoogle ColabとGoogleDriveの連携技をやってみた。
CPUパワー＆ストレージを仮想マシンが持ってくれて、Azureみたいなことがタダでできちゃう。

```GoogleDriveFileOpen.py
#! pip install pydrive

# pydriveでGoogle Driveの認証設定
from pydrive.auth import GoogleAuth
from pydrive.drive import GoogleDrive
from google.colab import auth
from oauth2client.client import GoogleCredentials

auth.authenticate_user()
gauth = GoogleAuth()
gauth.credentials = GoogleCredentials.get_application_default()
drive = GoogleDrive(gauth)

#ここは、GoogleDriveのURLから持ってくる「https://drive.google.com/drive/folders/XXXXXXXXXXXXXXX」
id = "XXXXXXXXXXXXXXX"

#ファイル一覧表示して、IDをチェック
filelist = drive.ListFile({'q': "'%s' in parents and trashed=false" % id}).GetList()

#とりあえずjpgファイル1つめ
for f in filelist:
  if "jpg" in f["title"]:
    print("filename:" + f["title"] + ", id:" + f["id"])
    fname = f["title"]
    fid = f["id"]
    break

#GoogleDriveでまずコンテンツを開く
drivefile = drive.CreateFile({'id': fid})
drivefile.GetContentFile(fname)

#ここからは普通の画像ファイルと同じ
from PIL import Image
from PIL import ImageOps
import numpy as np

img = Image.open(fname)
print(img.format, img.size)

# 画像を256x256にリサイズしてノーマライズしてみる
resizeimg = img.resize((256,256), Image.LANCZOS)
img2 = ImageOps.equalize(resizeimg)
# numpy配列にするなら以下
#array = np.asarray(img2)
#print(array)

#結果を別ファイルとして出力
outfilename = "normalized.jpg"
driveoutfile = drive.CreateFile({'title': outfilename, 'mimeType': 'image/jpeg'})
driveoutfile.SetContentFile(outfilename)
driveoutfile.Upload()
```

見た目はまんまJupiter Notebook
![スクリーンショット_2018-09-23_23-14-15.png](https://qiita-image-store.s3.amazonaws.com/0/283529/4716cd04-3c46-f2c3-2a45-569ce32080ec.png)


[参考]
https://qiita.com/pashango2/items/145d858eff3c505c100a
https://qiita.com/uni-3/items/201aaa2708260cc790b8
https://qiita.com/uni-3/items/201aaa2708260cc790b8
https://note.nkmk.me/python-numpy-image-processing/
SQL関連の色々

#DBの操作色々

メモ書きです。

- MySQL

mysqlコンソールからDBの作成

```:mysql
CREATE DATABASE training;
use training;
create table users (id int NOT NULL PRIMARY KEY AUTO_INCREMENT, 
 name varchar(20),gender varchar(20),age int);
insert into users(name,gender,age)values('john','m',18);
```
create table テーブル名(カラム名　データ型　オプション)でテーブル作成。
NOT NULL PRIMARY KEYはNullと重複を許さない。
AUTO_INCREMENTで勝手に番号振ってくれる。
データ作った後はprogateでやったような感じでデータ取得ができる。

[MySQL初心者入門講座](http://mysqlweb.net/)

- chrome mysql admin

chromeの拡張アプリでデータベースを見て操作できるguiツール。つよい。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/292031/e224c262-0674-75e0-2dba-16f12cf2906d.png)
こんな感じで見やすい。操作が英語なのとネット上に記事が少ないのが難点か。

- ActiveRecord

Rubyプログラム上でデータを参照、挿入することができる。railsと一緒に使われることが多いみたいだけど単体でも使える。

```rb:users.rb
require "rubygems"
require "active_record"

config = YAML.load_file( './database.yml' )
ActiveRecord::Base.establish_connection(config["db"]["development"])

class User < ActiveRecord::Base
end

User.destroy_all

user = User.create( name: "john", gender: "m",age:18)
user = User.create( name: "paul", gender: "m",age:20)
user = User.create( name: "alice", gender: "f",age:15)
user = User.create( name: "dabid", gender: "m",age:17)
user = User.create( name: "jasmin", gender: "f",age:17)

p User.all

male = User.where(gender: 'm').order('age ASC')
p male
```
テーブルの構造をいじる時はmysql adminからやって、プログラム上ではデータの挿入と取得をするって感じ。
[ActiveRecordを単体で使うには](https://tsuchikazu.net/active_record_single_use/)
[Active Record の基礎](https://railsguides.jp/active_record_basics.html#read)

- おまけ

バイト帰りに本買ってきたので載せる。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/292031/2df66faa-231a-9e94-f5a5-fd8dc3965d9f.png)

最近python触れてないから衝動買いしました。昨日発売らしい。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/292031/fb918bbd-df3d-4d51-065c-b326e271939b.png)

有名な松尾教授の本。夜勤中にでも読もう。
iOSアプリ開発を楽にできそうなライブラリの見つけ方


# 目的
個人や業務でアプリ開発するとき、
*「これ多分他の人がライブラリ化してるんだろうな」*
や
 *「この良くある機能作るの大変だ」*
と思う機能があると思います。そのとき、ライブラリの情報源を知っていると知っていないとでは開発効率に差が出るので、備忘録も兼ねて紹介します。

# 主な情報源

### 職場の人
まず手っ取り早いです。技術が好きなエンジニア勢の人であれば喜んで色々教えてくれます。
が、技術に興味のないエンジニアしか集まっていない職場や、そもそも個人開発している方には厳しいかもしれません。

### [awesome-swift](https://github.com/matteocrippa/awesome-swift)
ありとあらゆる分野のド定番の優良ライブラリが見つかる神ページ。こちらを見るだけでも十分参考になります。

### [cocoa controls] (https://www.cocoacontrols.com)
主にUI 系のライブラリがサムネイル付きで紹介されている神ページその２。UI/UX を凝ったアプリを開発する場合に非常にお世話になります。

### [Trending swift](https://github.com/trending?l=objective-c)
流行りのライブラリは何があるか調べるのに使えます。AFNetworking など、よく見るライブラリも多いものの、意外なライブラリが見つかることもあります。
phpからpythonを呼び出し実行結果を利用

#はじめに
この記事ではphpからpythonプログラムを実行し，その出力結果を文字列としてphpのプログラムで利用する方法について解説します．

#環境
一応書いたけど大体の環境で動くと思います．
__php__：5.5.38
__python__：3.6.4

#実行するpythonプログラム
とにかく分かりやすくしました:monkey: 文字列を二行出力するだけです．

```python:exec_from_php.py
print("1line")
print("2line")
```

当然こうなります．

```exec_from_php.pyの実行結果
$ python exec_from_php.py 
1line
2line
```

#phpからpythonを呼び出す
phpで下記のようにexecを呼び出すと，第一引数の文字列のコマンドを実行し，その出力の各行を要素として，第二引数を文字列の配列とします．つまり第二引数は出力される行の大きさの配列となります．第二引数の配列に，既に何らかの要素が含まれている場合，配列の最後に追加される点に注意．

```
exec($command,$output);
```

実際に使ってみました．第一引数には先程のpythonプログラムを実行するコマンドを指定しています．そのため，第二引数であるoutputは一つ目の要素が"1line"二つ目の要素が"2line"の配列となっているはずです．

```php:exec_py.php
<?php
$command="python exec_from_php.py ";
exec($command,$output);
print "$output[0]\n";
print "$output[1]\n";
?>
```

下記の実行結果から無事にoutputに代入されていることが確認できました．

```exec_py.phpの実行結果
$ php exec_py.php 
1line
2line
```

#まとめ
phpからpythonを呼び出すことができました．数値を扱いたい方は呼び出し後に，文字列を数値に変換するなりなんなりしたらいいと思います．
swift4でアプリの画面の明るさを変更させる✨

:star::star:備忘録もかねて:star::star:

```brightness.swift
import UIKit

// 0.0〜1.0で設定する
UIScreen.main.brightness = 1.0
```

0.0で真っ暗で、1.0で眩しくなります:sunglasses:
CGFloat型で設定してあげましょう。

import UIKitを入れ忘れて動かないな〜と、少し時間を潰してしまったのが残念:joy:
簡単にCSS1行だけで背景画像をパララックスする。

# LPなどで見るパララックス（視差）効果を簡単に出す方法

![parallax.gif](https://qiita-image-store.s3.amazonaws.com/0/127520/515393d2-16e5-465f-c3de-d017377df648.gif)

## 背景
- 工数かけずに簡単にパララックス効果を入れたい
- jsは使わない

### 施術
- 背景画像のCSSに `background-attachment: fixed` を記述するだけです

### 備考

- IEも11であれば`background-attachment`は対応しています
- 仮に`background-attachment`が効かない環境であれば、ただ単に視差効果が作動せず、普通のスクロールになるだけですので、基本的にはクライアントにご理解いただいた上でフォールバックの必要もあまり無いでしょう
https://caniuse.com/#feat=background-attachment

### 実装コード
<p data-height="520" data-theme-id="0" data-slug-hash="eLorjZ" data-default-tab="css,result" data-user="agdg" data-pen-title="OneLine Parallax" class="codepen">See the Pen <a href="https://codepen.io/agdg/pen/eLorjZ/">OneLine Parallax</a> by Asagiri (<a href="https://codepen.io/agdg">@agdg</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>
Go のソースコードからコメントを消す

go の `parser.ParseFile` で AST を取得して、この情報からコメントの情報を消して `format.Node` を使って再度コードに戻すことでコメントだけが消えたソースを生成することが出来ます。

```go
package main

import (
	"go/ast"
	"go/format"
	"go/parser"
	"go/token"
	"os"
)

var src = `
package p; // p package

/*
 * sample
 */
func main() {
	a := 1
	a++ // increment
}
`

func main() {
	fset := token.NewFileSet()
	f, _ := parser.ParseFile(fset, "example.go", src, 0)

	f.Comments = make([]*ast.CommentGroup, 0)

	format.Node(os.Stdout, fset, f)
}
```

実行結果

```
package p

func main() {
        a := 1
        a++
}
```

コメントが消えたソースが出力されていることを確認出来ました。


## 仕組み

`parser.ParseFile` を利用して AST を取得するのですが、このデータの実態は `ast.File` でその中の情報にソースコードのコメント一覧が格納されているフィールドがあります。( `Comments` )

https://github.com/golang/go/blob/release-branch.go1.11/src/go/ast/ast.go#L986

```go
type File struct {
	Doc        *CommentGroup   // associated documentation; or nil
	Package    token.Pos       // position of "package" keyword
	Name       *Ident          // package name
	Decls      []Decl          // top-level declarations; or nil
	Scope      *Scope          // package scope (this file only)
	Imports    []*ImportSpec   // imports in this file
	Unresolved []*Ident        // unresolved identifiers in this file
	Comments   []*CommentGroup // list of all comments in the source file
}
```

`format.Node` を使って `ast.File` をソースコードに変換する際に、コメント情報が `Comments` から取られるので `Comments` を何かしらの方法で値が空の状態にしてあげればコメント情報が戻せなくなるという訳です。

今回は `parser.ParseFile` 実行時のモード指定を `0` にしていたので各ノードにコメント情報が存在していませんでしたが、モードに `parser.ParseComments` を含めて `Comments` を `nil` で初期化するとソースコードを戻す際にノードのコメント情報も見るようになるので、今回の例だと一部のコメントは消されず戻ってきます。

https://github.com/golang/go/blob/release-branch.go1.11/src/go/printer/printer.go#L1114

```go
	} else if n, ok := node.(*ast.File); ok {
		// use ast.File comments, if any
		p.comments = n.Comments
	}

	// if there are no comments, use node comments
	p.useNodeComments = p.comments == nil
```

パース時に `parser.ParseComments` を指定して `Comments` を `nil` で初期化した ver

```go
func main() {
	fset := token.NewFileSet()
	f, _ := parser.ParseFile(fset, "example.go", src, parser.ParseComments)
	ast.Print(fset, f)

	f.Comments = nil

	format.Node(os.Stdout, fset, f)
}
```

実行結果

```
package p

/*
 * sample
 */
func main() {
        a := 1
        a++
}
```

なんで一部だけ戻ってきたのかはまだ詳しく見てないのでわかっていないです。。。（わかったら追記します）
OctoberCMSプラグイン作成：バックエンドのドロップダウンにデフォルト値を含める方法３つ

## 概要

バックエンドのフォームのドロップダウンにハードコードした選択肢ではなく、DBに入れたデータを使用する場合に、デフォルト値を設定する方法のメモ。

フォームにドロップダウンを表示するには、モデルにリレーションを定義するか、ドロップダウンコントロールを使う方法があるが、いずれも意図的にデフォルト値を入れてやらないと、未選択の状態でも選択肢のどれかが勝手に選択された状態になってしまう。

未選択の状態であることをデータ（0やnullなど）として入れるためには、未選択の状態がドロップダウンに表示されるようにする必要があるが、次の３つの方法が考えられる。

1. 選択肢にデフォルト値が含まれるようにデータを用意する
2. フィールド定義で `placeholder` を設定する
3. オプション取得メソッドで意図的にデフォルト値を入れる

## TL;TR
結論から言うと３番目の方法が一番良い。

## 1. 選択肢にデフォルト値が含まれるようにデータを用意する
リレーションかドロップダウンコントロールのいずれを使うにしても、選択肢となる元データにデフォルト値を含める方法。

下記のようなリレーションを使用してドロップダウンを表示する場合、`AnimalCategory`のはじめにデフォルト値を登録しておくことで実現できる。ただ、これはデータが既に入っている場合に対応できないなど柔軟性に欠け、あまりスマートな方法ではない。

```php
class Animal extends Model
{
    public $belongsTo = [
        'category' => ['Pikanji\Zoo\Models\AnimalCategory'],
    ];
    ...
}
```

```php
class Animal extends Model
{
    public function getAnimalCategoryOptions()
    {
        return AnimalCategory::all()->pluck('display_name', 'id');
    }
    ...
}
```

## 2. フィールド定義で `placeholder` を設定する
こちらは、フィールドに`dorpdown`タイプを使用する場合。
フィールド定義ファイル`models\animal\fields.yaml`で下記のように`placeholder`を指定することで実現できる。

```yaml
fields:
    animalCategory:
        label: Animal Category
        span: auto
        type: dropdown
        placeholder: '-- 選択してください --'
```

設定だけで実現できるのできれいだが、一度選択肢たら未選択の状態に戻せないという欠点がある。

## 3. オプション取得メソッドで意図的にデフォルト値を入れる
こちらもフィールドに`dorpdown`タイプを使用する方法だが、上記いずれの方法の問題点を克服している。

２で紹介した`placeholder`は使用せずに、オプション取得メソッドで選択肢配列の一番前に未選択状態の選択肢を突っ込んでやる。（下記の例ではselect optionの`value`は選択肢データの`id`カラムを使用している前提。）

```php
class Animal extends Model
{
    public function getAnimalCategoryOptions()
    {
        $options = AnimalCategory::all()->pluck('display_name', 'id');
        $options->prepend('-- 選択してください --', 0);
        return $options;
    }
    ...
}
```

特殊なことをしていない限りDBのデータは1から始まるので、keyを0で配列（またはCollection)の先頭に未選択状態の選択肢を挿入してやる。
「ゼロから作る Deep Learning」: argmaxの振る舞いの整理

# 目的
「ゼロから作る Deep Learning」 を読んでいて、argmaxの振る舞いが直感的に理解できなかったので整理しました。

# argmax とは
最大値の"index"を取得します。
第一引数が対象の配列、そして理解しにくいのが第二引数です。
[公式](https://docs.scipy.org/doc/numpy/reference/generated/numpy.argmax.html
)を見てもあまりよくわからず。

## 一般的な使い方: `np.argmax(data)`
これはdataを渡せば、その中の最大値のインデックスを取得します。
例えば、
`data = np.array([[1, 2, 3],[3,4,5]])`の2×3の行列だと、結果はインデックス5が返ります。

## axis=0の指定: `np.argmax(data, axis=0)`
これは「列指定」になります。
`data = np.array([[1, 2, 3],[3,4,5]])`の2×3の行列だと、列で見ます。
`[1,2,3]
[3,4,5]`
だと、[1,3], [2,4], [3,5]の組み合わせで見るので、結果は[1,1,1]のインデックスが返ります。

## axis=1の指定: `np.argmax(data, axis=1)`
これは「行指定」になります。
`data = np.array([[1, 2, 3],[3,4,5]])`の2×3の行列だと、行で見ます。
`[1,2,3]
[3,4,5]`
だと、[1,2,3], [3,4,5]の組み合わせで見るので、結果は[2,2]のインデックスが返ります。

## ポイント

- axisの指定(0がどっちだっけ..)になりやすいこと → 定数で記録しておくとよい
- その場合の振る舞いがわかりにくい → 簡単な例で振る舞いを理解しておけば複雑になっても理解しやすい

だと思います。
RailsのActive StorageでGoogle Cloud Storageを使うときの補足

## 概要
Rails5.2より導入されたActive Storageにより、GCS(Google Cloud Storage)やAmazon S3などのクラウドストレージとRails Appを連携させることがぐっと楽になりました。

[Active Storage の概要 | RAILS GUIDES](https://railsguides.jp/active_storage_overview.html)

基本的に↑のガイドの通り行えばよしなに構築が行えます。
が、GCSを連携させようとしてこのガイドの「2.4 Google Cloud Storage Service」を見るといきなり「サービスを宣言してください」と言われます。これをやっていく過程で少し詰まったので、やり方をメモしておきます。

## やり方

### Google Cloud Platformに登録する
GCSはGCP(Google Cloud Platform)というプラットフォームの1機能であり、まずこれに登録する必要があります。

[Google Cloud Platform](https://cloud.google.com/)

↑をクリックしてお使いのGoogleアカウントでログインすると、「$300の無料クーポンが...」みたいなメッセージが出てきます。

![2018-09-23 (2).png](https://qiita-image-store.s3.amazonaws.com/0/208875/cec2a1c6-77f7-9db1-0280-671a6c589da3.png)

もらえるものはありがたくもらっておきましょう。このクーポンは1年間有効ですが、$300というのはかなりのアクセス数がないと使いきれない金額です[^1]。つまり実質1年間無料です。

### GCPコンソールにアクセスし、プロジェクトを作成する

[ここです。](https://console.cloud.google.com/?hl=ja)
新しくプロジェクトを作成するよう言われるので、作成しましょう。

### GCSのページにアクセスし、バケットを作成する

コンソールの左上のナビゲーションメニューから、「ストレージ」→「Storage」→「ブラウザ」でGCSのページにアクセスします。
その後ページ上部にある「バケットを作成」をクリックすると次のような画面に移ります。

![2018-09-23 (1).png](https://qiita-image-store.s3.amazonaws.com/0/208875/9494e484-0974-219d-e203-5a2316f12673.png)

- 名前: Active Storageを素直に使う場合はなんであれ動作します
- デフォルトのストレージクラス: Webサービスの場合「Multi-Regional」か「Regional」かと思われます。Regionalのほうが若干安くなります。NearlineやColdlineはめったに使いません。[詳細はこちら](https://cloud.google.com/storage/docs/storage-classes?hl=ja#regional)
- 場所: 日本からのアクセスが多そうなら「アジア(Multi-Regional)」か「東京(Regional)」にしましょう。

### サービスアカウントを作成する

RailsがGCSの内部を操作できるようにするためのロボット用アカウントを発行する必要があります。
ナビゲーションメニューから、「APIとサービス」→「認証情報」→「認証情報の作成」→「サービスアカウントキー」で作成できます。

![2018-09-23 (3).png](https://qiita-image-store.s3.amazonaws.com/0/208875/87c5d272-b731-03fe-ffe2-a09b7c913cd4.png)

「新しいサービスアカウント」を選択し、適当にアカウント名とIDをつけましょう。
役割はストレージのアップロードや削除、閲覧など広く行うので「ストレージ管理者」としました[^2]
キーのタイプは「JSON」を選択してください。

これを作成するとtxtファイルがダウンロードされます。これは次のRailsの設定で使います。

### Rails側の設定

ここまで来て、ようやく最初のガイドが言っていた「サービス」の作成が完了します。
あとは先程ダウンロードしたtxtファイルの内容をconfig/storage.ymlにコピればOK...とみせかけて、落とし穴があります。

#### credentialsを使おう

先程のtxtファイルの中身はGCSにアクセスするためのキーです。
もしこれを素直にconfig/storage.ymlに丸コピしてしまい、Githubのパブリックリポジトリにpushなんてしてしまったら...全世界の人間があなたのGCSにアクセスし放題になってしまいます。これはとても危険です。
そういったことを防ぐためにRailsにはcredentialsという機能があります(Rails 5.2より)。これを使いましょう。

credentialsについて詳細に述べてしまうと少し長くなってしまうので、わかりやすいこちらの記事を引用させていただきます。

[Rails 5.2の新機能Credentialsでパスワード等を管理する | 動かざることバグの如し](http://thr3a.hatenablog.com/entry/20180408/1523156956)

また、この時にconfig/storage.ymlの書き方に少しだけクセがあるのですが、それについて記した私の記事もよろしければ御覧ください。

[Active StorageにおいてYAML syntax errorが出る問題](https://qiita.com/furikake6000/items/2be2752d2a803474ee42)

## できた！！！

あとは最初のガイドの通り進めれば、よしなにできると思います。
Active Storageはファイルのアップロードや提供、Modelとの関連付けなどが驚くほど簡単にできる素晴らしい機能です。
ぜひ使っていきましょう！

[^1]: あくまで個人制作のサービスの話です。また、総DLサイズに応じて課金されるため、1リクエストで何回もアクセスするようなコードの場合は課金額が膨れ上がる恐れがありますので気をつけましょう。
[^2]: ここはもしかしたらもっと小さい権限で行けるかもしれません...(要検証)