OmniAICreator/Qiita-1.07M huggingface dataset:
Hyper-V + VagrantでCentOSを動かしてフォルダ共有をしようとしたメモ

## 結論

Vagrantのバージョンを最新版（2.0.2)に上げたことでフォルダの共有はできた。
ただし、双方向の同期についてはまだ分かっていない。

`vagrant rsync-auto`で、ホストのファイルをゲストに同期することはできた。

```ruby:Vagrantfile
Vagrant.configure("2") do |config|
  config.vm.box = "centos/7"

  config.vm.provider "hyperv" do |h|
    h.differencing_disk = true # Faster cloning and uses less disk space
  end

  config.vm.synced_folder '.', '/vagrant', type: "rsync"
end
```

## はじめにやろうとしたこと。

vagrantでhyper-vを扱うためにいくつかの参考サイトを確認した。

[VagrantでプロバイダーにWindowsのHyper-Vを使ってみる](https://www.beeete2.com/blog/?p=1325)
[Windows 10でHyper-Vを使ってVagrantを動かす](https://qiita.com/nibral/items/94de6b9787e2aface2aa#fn1)
[Windows10のHyper-Vを使ったVagrantのBoxファイル作成方法](http://truffe093.hatenablog.com/entry/2017/01/22/193241)
[Learning to Use Vagrant on Windows 10](https://blogs.technet.microsoft.com/virtualization/2017/07/06/vagrant-and-hyper-v-tips-and-tricks/)

とりあえず、以下のVagrantfileを作って、`vagrant up --provider=hyperv`。

```ruby:Vagrantfile
Vagrant.configure("2") do |config|
  config.vm.box = "centos/7"
end
```

仮想スイッチの外部ネットワークのネットワークアダプタにうっかりローカル接続のアダプタを選んでIPが取得できないなどのエラーはありつつも、実際に接続しているWifi接続のアダプタに修正することが立ち上がるところまでは無事に終了。
ただし、共有フォルダのマウントがされなかった。ここからが長かった。


共有フォルダを認識させるためにsambaを利用しているところが多かったため、同じようにやろうとした。
が、エラーが続出

```
CIFS VFS: No username specified
CIFS VFS: Error connecting to socket. Aborting operation
CIFS VFS: cifs_mount failed w/return code = -115
```

```
No host IP was given to the Vagrant core NFS helper. This is
an internal error that should be reported as a bug.
```

```
This is an internal bug with Vagrant and an issue should be filed.
```

winnfsdを使おうとしても失敗[*](https://github.com/winnfsd/vagrant-winnfsd/issues/119)

```
No valid IDs were given to the NFS synced folder implementation to
prune. This is an internal bug with Vagrant and an issue should be
filed.
```

と、調べているうちに、vagrantが最新になっていないことにきづいた。
Vagrant2.0.2にアップデートしてみると、最初に書いた通り、すんなりと通った。
更新はちゃんとしよう。。。

## 余談

dockerもいれてみた。[*](https://docs.docker.com/install/linux/docker-ce/centos/#os-requirements)

```ruby:Vagrantfile
Vagrant.configure("2") do |config|
  config.vm.box = "centos/7"

  config.vm.provider "hyperv" do |h|
    h.differencing_disk = true # Faster cloning and uses less disk space
  end

  config.vm.synced_folder '.', '/vagrant'

  config.vm.provision "shell", inline: <<-SHELL
    if ! docker > /dev/null 2>&1; then
      yum install -y yum-utils \
        device-mapper-persistent-data \
        lvm2
      yum-config-manager \
        --add-repo \
        https://download.docker.com/linux/centos/docker-ce.repo
      yum install -y docker-ce
      yum list docker-ce --showduplicates | sort -r
      systemctl start docker
      docker run hello-world
    fi
    if ! /usr/local/bin/docker-compose > /dev/null 2>&1; then
      curl -L https://github.com/docker/compose/releases/download/1.19.0/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
      chmod +x /usr/local/bin/docker-compose
    fi
  SHELL
end
```
Windowsタスクスケジューラーのスリープ解除実行でハマったこと

**毎日同じ時間にプログラムを自動で走らせたい**ってことありますよね。
学校or会社行ってる間に自動で処理させておいて、帰ってきたら結果を確認するみたいな・・・
そういうことは**普通のWindowsのノートPCでも出来る**ようになってまして、
**タスクスケジューラー**というのがあります。

これが
・**曜日指定**　だとか
・**ユーザーがログオンしているかどうかに関わらず実行する**　だとか、
それなりに条件を細かく設定できます。
ただし、基本的には**電源を切ってしまうとダメ**で、かといって付けっぱなしも嫌だなぁと思っていたら、
<font color="Magenta">**タスクを実行するためにスリープを解除する（下図赤枠）**</font>というのがあるんですね。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/237551/a8443feb-25a4-691f-5105-bdcf2afa9317.png)

ただ、**ここにチェックを入れただけでは当方のPCでは機能せず、
解決するのに少し苦労した**ので本記事で共有したいと思います。

確認方法としては、現在日時をテキストに吐き出すというプログラムで試しました。
そうすると、**指定した時刻ではなく、自分がPCを触ってスリープが解除された時点で実行されていた**ことが分かりました。

検索しても原因が分からず、一つ一つ問題を切り分けていって、やはり「スリープを解除する」点だけが上手くいってない。結局、何が問題だったかというと・・・

コントロール パネル > ハードウェアとサウンド > 電源オプション > プラン設定の編集 > **詳細な電源設定の変更**　というところにですね、

<font color="Magenta">**スリープ解除タイマーの許可（下図赤枠）**</font>
というのがありまして、

![image.png](https://qiita-image-store.s3.amazonaws.com/0/237551/a1eba223-2dd9-151f-0ad0-2e329ba5ea3c.png)

これを有効にすることで、やっとタスクスケジューラーのスリープ解除実行が機能した、というお話でした。

いやこれは分からないでしょ・・・　END
ユーザが勘違いを防ぐための施策

# 概要

ユーザの勘違いが起こしやすい状態にすることによってサーバなどの負荷が上がるのは避けたいと思ったらやると良い施策を並べる。私の場合Ajax周りの送信でこのようなことが起きることが多かったため、Ajaxのタグもつけているが、コードのサンプルはありません。悪しからず。


# ユーザが何回も押したくなるのは？

理由として主に二つの理由が存在すると考えている。

1. 処理が遅い
2. 処理が走っているかわからない


# 解決策

送信のボタンを何回も押すことでなんとかしようとするユーザのなんと多いことか。(自分もそう)焦るのがわかるが待ってくれ。押せないんだ！ということを示すための施策は二つある。


1. buttonをdisabledにする
2. 処理走ってるぜ感を出す

## 1. buttonをdisabledにする

これは言わずと知れた方法ですね。そもそも押せなきゃいいじゃんってやつです。
ただあまりにも長すぎるとイライラするといった問題はあります。


## 2. 処理走ってるぜ感を出す

処理走ってるぜ感出すには有名なクルクル回るやつとか使える。
ただ、これは長すぎるともう一度ボタンを押されるという危険性を孕んでいる。

1と組み合わせて使うと多分良い。


# そもそも処理早くしろよ問題

処理が遅いからこうなっているのだ。と思っているそこのあなた。
処理が遅くても誤魔化す方法はあります。
処理を早くする努力はするけども、それだけでは足りない方はUXを意識すると良いです。

例えば、instantclickのようなライブラリを使って、検索を先に走らせておくなどの工夫をするとユーザの認識する処理の速度は速くなるので、なんとかなります。その辺り工夫していきましょ。今回はここまで。
一時的に使うEC2インスタンス


* 検討
	* 必要な時だけ立ち上げる
	* できればセキュアにしたい
		* ssl+basicAuth
	* 更新は常にしたい
		* プライベート権限のS3へアップ
	* CF+S3でやるのはアクセス制御が面倒そう

* 手順
	* EC2にインスタンスを作る
	* EIPを関連づける
	* S3のバケットを作る
	* Let's Encryptを使う
		* 参考：https://qiita.com/HeRo/items/f9eb8d8a08d4d5b63ee9
		* セキュリティグループで80を許可する
		* 独自ドメインのルーティングを振り向ける（Route53利用）
		* 認証利用のディレクトリ以外は80から443へのリダイレクトをnginxに行う
			* 認証の一瞬に攻撃を受けることはないのかしら
	
			```
			location ^~ /.well-known/acme-challenge/ {
			  default_type "text/plain";
			  root         /var/www/html/;
			}
			location / {
			  # Redirect all HTTP requests to HTTPS with a 301 Moved Permanently response.
			  return 301 https://$host$request_uri;
			}
			```
	
		* Basic認証を追加
	
		    ```
		    location / {
		            # First attempt to serve request as file, then
		            # as directory, then fall back to displaying a 404.
		    auth_basic "Basic Auth";
		    auth_basic_user_file /etc/nginx/.htpasswd;
		    proxy_pass http://s3.hogehoge.amazonaws.com;
		            #try_files $uri $uri/ =404;
		    }
		    ```
	
		* 定期更新（時間はずらしてもいいのかも）
			`0 4 1 * * /usr/bin/certbot-auto renew && /bin/systemctl reload nginx`
	* nginxを用意
	* 必要に応じてインスタンスを立ち上げる（モバイルにアプリをいれる）
tarコマンドのかわりにpaxコマンドを使う

衝撃の事実！！！`tar`はPOSIXコマンドじゃなかった！！！
[`pax`](http://pubs.opengroup.org/onlinepubs/9699919799/utilities/pax.html)がtarアーカイブを扱えるPOSIXコマンドのようなので、こちらを使ってみます。

日本語情報としては[AIXマニュアルのpaxコマンドの項](https://www.ibm.com/support/knowledgecenter/ja/ssw_aix_72/com.ibm.aix.cmds4/pax.htm)が良いのではないかと思います。

# 例

ここで挙げる例は、以下のようなファイルとディレクトリのツリーを前提とします。

```shell-session
$ tree
.
├── dst
└── src
    ├── aaa
    ├── bbb
    ├── ccc
    ├── data
    │   └── hoge
    └── tmp
        └── fuga

4 directories, 5 files
```

## アーカイブの作成

```shell-session
$ cd src
$ pax -w * > ../archive
```

## アーカイブの展開

```shell-session
$ pax -r < ../archive
```

## アーカイブ作成時、ディレクトリの中身だけ除外する

`data`ディレクトリと`tmp`ディレクトリの「中身を」除外してアーカイブを作成する

paxはパスを正規表現で置換することで、ファイル/ディレクトリの除外/リネームを行うことができる.
`..*` は正規表現で、任意の1文字以上を示す.

```shell-session
$ pax -w -s '/data\/..*//' -s '/tmp\/..*//' * > ../archive
```

## アーカイブ展開時、ディレクトリを作成してその中に展開する

`app`ディレクトリを作成してその中にアーカイブを展開する

```shell-session
$ pax -r -s '/..*/app\/&/' < ../archive
```

## 圧縮 -> sshで転送 -> 展開 を同時にやる

- debianだとcompress/uncompressコマンドは最初から入っていないようなので、`apt-get install ncompress`で入れます
- macOSにはもちろん最初から入っています（POSIX準拠なので）

### 簡単な例

サーバ（`vhub.local`）上にあるログが格納されているディレクトリ（`dht12_log`）をローカルに持ってきたいと思います。

```shell-session
$ (ssh vhub.local 'pax -w dht12_log | compress') | uncompress | pax -r
$ ls
dht12_log
```

compress/uncompressコマンドは引数なんもつけないと標準入力を圧縮して標準出力に書き出すという動作になるので、きれいなワンライナーが書けた。

### 少し複雑な例

- ローカルのカレントディレクトリの中身を圧縮しつつsshで送って、リモート(sakura-rg)の`armbian`ディレクトリに展開します
- アーカイブを作成する際、`.git`ディレクトリは除外します

最初以下のようにやってみたら、シンボリックリンクがおかしくなった。

```sh
pax -w -s '/.git//' * |
compress -c |
ssh sakura-rg '
rm -rf armbian;
cat |
uncompress -c |
pax -r -s "/..*/armbian\/&/"
'
```

とりあえず次のようにしてごまかした。

```sh
pax -w -s '/.git//' * |
compress -c |
ssh sakura-rg '
rm -rf armbian;
mkdir armbian;
cd armbian;
cat |
uncompress -c |
pax -r
'
```
とにかく`frozon_string_literal` をぶっ込みまくる

# おさらい

## :snowflake: `freeze`
コード中の文字列リテラルのうち、それ自体を破壊的に変更されたくない場合、`freeze` メソッドを使って、immutableにすることができる。



## :hash: マジックコメント `frozon_string_literal`  

けれど、毎度毎度、そういった文字列リテラルに`frozon`を書くのは面倒。
そこでRuby 2.3から取り入れられたのが、`frozon_string_literal`というマジックコメント。これを先頭行に以下のように追加することで、そのファイル中の文字列リテラルは全て`freeze`が呼ばれたのと同じ状態になる。


# とにかくマジックコメントをぶっ込みまくる

ということで、とりあえず全部にぶっ込んでみた。

```bash
$ find ./lib -type f -name '*.rb' -exec sed -i '.back' -e '1i\
\# frozen_string_literal: true' -e '1G' {} \;
```

これで先頭行にマジックコメントが追加できた。
あとはゴミを始末する。

```bash
$ find ./lib -type f -n '*.back' -exec rm {} \;
```
Marxico + TextExpanderでスニペット展開されない場合の対処

## 環境

- Windows 10
  - Marxico 1.8.0 (Vimキーバインド)
  - TextExpander for Windows 1.5.10

- MacOS Sierra 10.12.5
  - Marxico 1.8.0 (Vimキーバインド)
  - TextExpander 6.2.5

## 発生事象

タイトルの通りMarxico上でキーワードをタイプしてもスニペットに展開してくれない。

## 対処

挿入モードへ変更後にスペース/改行/タブ等、何かしらのキー入力をしてからキーワードを入力する。

## 雑記

物凄くニッチな情報のような気がするけど、WindowsでもMacでも発生してて気が付くまで時間がかかったのでメモしておく。
TextExpander側の設定で改善するかもしれないけど、とりあえず運用でカバーする。
秘密鍵をスマホに保管して管理するKryptonを試してみた

複数台のマシンを使う機会が増えてきていちいちセットアップするのも面倒になってきたので
楽をしたく、お勉強用の環境もクラウドIDEやオンラインストレージなどを利用することが多くなってきました。

勉強利用とはいえ、クラウドIDEのコンテナの中に秘密鍵を置くのは嫌だなーと思っていたところ、面白いソリューションを見つけたので試した結果の備忘録を残します。

秘密鍵をスマホに保管して管理
https://krypt.co/

秘密鍵をスマホに保管することでセキュリティを高めるというコンセプト。

スマホなくしたら接続できなるじゃんとか、色々と使わない理由はあげれますが勉強用の環境へのアクセスなので細かいことを気にしなくてもいいので速攻で導入。

## インストール手順（デバイス）
今回は、CodeanywhereのUbuntu 14.04のBlankスタックにインストール

````
$ sudo apt-get update
$ curl https://krypt.co/kr | sh
```
これで終わり。楽チン。色々とインストールされるが細かいことは気にしない。

## インストール手順（iPhone）
1. App Storeから該当のアプリをインストール

終わり。こちらも楽チン。

## 設定手順
1. アプリを立ち上げて GENERATE KEY PAIR を押下
1. メールアドレスを登録
1. QRコードスキャナを起動。
1. 先ほどkrをインストールしたクライアントで `kr pair` というコマンド実行
1. QRコードがターミナル上に表示されるのでスマホアプリでQRコードを読み込む
1. QRコードを読み込むとアプリで piar するか聞かれるので pair を押下

これで終わり。楽チン。
注意点として登録時点ではpairするタイミングではデバイス名を変更できない。
デバイス名はマシンのホスト名となるのでコンテナのようなホスト名が同じになる環境で利用する場合は、デバイス登録後にアプリ上でデバイス名を変えておかないといけない。
（同名のデバイスを登録すると上書きされる？？ぽい）

## 利用手順
```
$ kr me
```
で公開鍵が表示される。
他にも、

```
$ kr github
$ kr digitalocean
$ kr aws
  .
  .
  .
```

などがある。
どれも公開鍵を表示して、それぞれの環境への公開鍵にインポート方法も教えてくれる。

AWS EC2（Amazon Linux）に接続する場合は、あら感じめ公開鍵をインポートしておき、証明書を指定せずにsshするだけ。

```
$ ssh ec2-user@IPとか
```

そうするとターミナルに以下の文字が出る

```
Krypton ▶ Requesting SSH authentication from phone
```

スマホに通知が来るので接続の許可か拒否を行う。
許可は「一度だけ許可」、「同じホストへ3時間許可」、「全てのホストへ3時間許可」から選べる。
※アプリ側の設定を変えると「常に許可」状態にすることも可能みたいだが未検証。

許可するとターミナルに以下の文字が出る

```
Krypton ▶ Success. Request Allowed ✔
```

拒否した場合は、以下の文字がでる

```
Krypton ▶ Request Rejected ✘
```

## 仕組み
krをインストールすると、~/.ssh/configに以下の内容が追加される。

```
# Added by Krypton
Host *
        PKCS11Provider /usr/lib/kr-pkcs11.so
        ProxyCommand /usr/bin/krssh %h %p
        IdentityFile ~/.ssh/id_krypton
        IdentityFile ~/.ssh/id_ed25519
        IdentityFile ~/.ssh/id_rsa
        IdentityFile ~/.ssh/id_ecdsa
        IdentityFile ~/.ssh/id_dsa

```

ssh実行時にKryptonのプロキシを経由する設定に書き換わってる。
他のプロキシを通したい場合などは以下を参考にすれば良さそう。
https://krypt.co/docs/ssh/using-a-bastion-host.html

元のconfigは、 ~/.ssh/config.bak.kr という名前で残っていて、Kryptonで利用する公開鍵も ~/.ssh/id_krypton.pub という名前で置いてある。

アンイントールは少し手間が必要で自分で設定ファイルを戻さないと行けない
https://krypt.co/docs/start/installation.html

秘密鍵は、GENERATE KEY PAIR を実行した際に生成されたものが使い回される。
（pair毎に用意されているわけではない。）

同じスマホでpairしたデバイスで `kr me` で確認した公開鍵は同じものになっていた。
試していないけど、スマホ側で秘密鍵と公開鍵を削除できるようなので、これをすれば秘密鍵が作り直されそう。
（もちろん、pairした情報全部やり直しだろうけど。）

## その他
- 公開鍵はスマホアプリからメールとかSMSで送信ができる。
- GitHubへのssh接続も同等にKryptonを通せる。
- 利用しなくなったデバイスの設定はスマホアプリから削除すればおしまい。
- デバイス側で新たにKryptonの設定をしなおしたい場合は、設定手順をやり直すだけ。 `kr pair` の時に新しく作り変えるか聞かれるので y と答えれば新しい設定を作り直してくれる。
- AppleWatchに来る通知でも許可と拒否を選ぶことができる。
- `kr transfer` というコマンドでバックアップができる？（未検証）

## まとめ
- 設定はすごく単純で難しいことは何もなく手軽に秘密鍵をセキュアに扱え、
サーバに設定を入れなくても良いのはとても助かる。
- 秘密鍵の端末間の共有（同期）やバックアップを考える事が減る。（完全になくなるわけではない。）
- Coreしか試していないが、PricingにあるCommandって方は「Two-Person Rule」っていう形で複数人が許可しなければ接続できないってのがある。

個人持ちの端末とお勉強用の環境へのアクセスにしか利用していないが、自分の判断で都度、接続の許可と拒否ができるのは安心感がある。
（お勉強環境を都度細かく監視したりはしないので）

Codeanywhereのスタック使ってsshする際はKryptonを利用してセキュリティを高めようと思います。
【超初心者向け】はじめてのデータベース設計

# はじめに
超初心者の私にわかりやすい、データベース設計の情報があまりなかったため、こちらで研究したものを書いていき、分かる方がいれば共有いただけると大変助かります。

# 設定環境
- OS
    - Mac OS X
        - 10.12.6
- Software
    - PostgreSQL
        - 10.1
    - Ruby
        - 2.5.0
    - Rails
        - 5.1.5

# Railsアプリを開発する上で必要なデータベースについて
ここではRailsアプリ向けのデータベース(DB)設計を効率よく理解し、作成する方法を研究していきたいと思います。

明確化したいことは以下です。
**・Railsアプリを作る時にデータベースどうすればいいの？**
**・DB設計の基礎？知っておくべきことは？**
**・ユーザー（userid, email, password)DBを作成してみよう**
**・ローカル環境でDB設定した場合、本番ではどうなるん？**

それでは上記４つを順番に研究していきましょう。

# Railsアプリを作る時にデータベースは必須
基本的にブログやウェブサービスなどを目的とするRailsアプリを作る場合は、
データベースがないとRailsアプリ自体が成り立ちません。
ですので、必ずデータベースを理解する必要があります。

ただデータベースという名前に初心者は恐れがちですので、
想像すべきはエクセルのテーブルを、Railsアプリ内のファイルで構築して、
テーブル内の情報を必要なときに持ってくるみたいなイメージらしいです。

# データベース設計の基礎は？
設計の基礎としてまず考えるべきことは、
まずRailsアプリの中でどのようなデータを持つことになるのかを考えることです。

Todoアプリの内容を登録する場合、
Todoテーブルを
タイトル
本文
ステータス
優先度
のような形で作ります。

これらの情報を残したいデータとして、データベースに残しておけば、
更新、削除、参照などができるようになります。

**初心者として引っかかりやすいのは、データベース設計が壮大なものに思えて、挫折してしまいがちな点です。**
**まずは簡単なテーブルを作ってみて、それをデータベースとしてみましょう。**

あとデータベースの基礎として以下を覚えておきたいです。
テーブル（例えばブログデータベースを持っていたら、ユーザーテーブル、記事テーブル、コメントテーブルなどを作っていくようです。）
・列（カラム）（例えば上記の記事のテーブルであれば、列はタイトルと本文）
・行（レコード・ロウ）（例えば上記の記事テーブルであれば、記事ひとつひとつを表すとのこと）
<img width="694" alt="スクリーンショット 2018-03-16 11.25.57.png" src="https://qiita-image-store.s3.amazonaws.com/0/108456/3ebd7c76-bebb-2498-b475-f414a6034641.png">

# ユーザーテーブルを作成してみよう

例えば先ほどのTodoアプリを置き換えて、ユーザーと企業のマッチングアプリを考えてみましょう。
仮のユーザーテーブルの内容は以下にします。
userid
email
password

こちら参考になります。
http://asobo.hatenablog.jp/entry/2016/01/17/120514
http://www.opentone.co.jp/news/release/article03/article0303.html

# もうひとつテーブルを作成して、テーブルを紐づけてみましょう

そしてこれとは別で企業テーブルを作ることとします。
企業ID
企業名
企業情報
のようなコンテンツが入ってるテーブルです。

２つのテーブルを作ったら、片方に関連付け用の情報を入れる
ユーザーテーブル
userid
email
password
ユーザーが興味のある企業:

このふたつのテーブルの関連付けがリレーションと言われるものらしいです。

# DBのリレーション

復習になりますが、例えばユーザーの情報が以下のデータベースで保管されているとすると、このユーザーが興味を持っている企業を関連づける場合にはこのような構成で考えるようです。

ユーザーDB
・userid:xxxxx
・email:test@test.com
・password:xxxxxx
・interest: 企業ID-A, 企業ID-B

企業DB
・企業ID:企業ID-A
・企業名:xxxxx
・企業情報:xxxxx

これから先を研究中です。

# ローカル環境でDB設定した場合、本番ではどうなるん？
Railsを使ってアプリを作っている場合は、ローカルでデータベース作成した場合は、STG,本番でもrake db/Migrateすれば使えようです。

逆に本番から取ってきて、落とし込むのはデータの中身を取ってくる時だけとのことです。

# pgAdminとは
Postgresqlのデータベースを簡単に管理または作成にあたり、
pgAdminというものがあるらしい。。（研究中）
https://allabout.co.jp/gm/gc/47328/


## 参考サイト
http://asobo.hatenablog.jp/entry/2016/01/17/120514
http://www.opentone.co.jp/news/release/article03/article0303.html
https://academy.gmocloud.com/know/20160425/2259
エンジニアの二年目病とその予防法①

春ですね。10分で生産的なミーティングができるWebサービス「[minmeeting](https://minmeeting.jp/)」を開発している伊勢川です。

<a title="minmeeting - 10分で生産的なミーティングができる会議ツール" href="https://minmeeting.jp/" target="_blank"><img width="100px" src="https://qiita-image-store.s3.amazonaws.com/0/199506/32e65577-a5bb-2c3b-4d30-4690c3c5ce0f.png" /></a>

3月に突入し、もうすぐ新人エンジニアの皆さんも二年目の先輩エンジニアになることでしょう。そこで、余計なお世話ですが、<B>二年目エンジニアが陥りがちな症状と予防法</B>を何回かの連載で書いてみたいと思います。新人エンジニアの皆さんはこの記事を参考にして、つまらない二年目病にかかることなく、ぜひすくすくとスーパーエンジニアに向けて進化を続けて頂きたいと思います。

# Google依存症
Google検索は便利で調べれば何でも答えが出てきます。そのせいかGoogle依存症のエンジニアが増えています。

## 症例
ログのエラーメッセージを読んで理解する前にググってしまう。

あるバグに直面した際に、エラーメッセージでググって解決策が出てこなければ、解決方法がないと思い込んでしまい、普通の問題の切り分けや解決の努力をしようともしない。

ある機能を実現しようとして、Googleで似たようなことを実現している人がいなければ、実現不可能と思ってしまう。

## 予防法
まずは調べ方が間違ってないかを確認しましょう。<B>Googleは日本語が苦手</B>なので、英語で聞いてみると答えが返ってくることが多いです。

確かにGoogleは便利ですが、その検索結果がすべてではありません。

<B>世の中にないものを作ろうとしたら、新しい問題に直面するのは当然</B>です。Googleで見つからないからといってすぐに諦めるのではなく、<B>理詰めで試行錯誤をして解法を見つけ出す</B>ようにしましょう。
各ツールにおける改行と投稿のキーバインドの違いがひどいのでまとめた

仕事等で以下のメッセンジャーツール・SNSを使うのですが、改行と投稿をよく間違えることがあり、この機会に改めてまとめてみました。（Windows版）

| キーバインド       |改行| 投稿|
|:-----------------|:------------------:|:------------------:|
| Twitter             |              Enter |        Ctrl+Enter        |
|    Facebook Messenger          |            Alt+Enter|       Enter      |
|    Slack          |            Alt+Enter (※1)|       Enter      
|    Skype          |            Shift+Enter|       Enter      |
|    Skype(Enterを改行に設定変更時)          |            Enter|       Ctrl+Enter     |
| Discord           |       Shift+Enter |       Enter       |
| LINE            |             Shift+Enter |       Enter       |
| LINE(投稿をAlt+Enterに設定変更時)            |             Enter |       Alt+Enter       |

割とデフォルト設定では「改行はShift+Enter、投稿はEnter」が多いような印象を受けます。
改行しようとして送信してしまうケースが最も悪いので、今後は単独でEnterを押すときは気を付けるようにします。

追記：
※1……SlackはCtrl+Enter, Shift-Enterでも改行でき、また言語を日本語に設定するとCtrl+Enterで投稿、Enterで改行となるようです。コメントでの情報提供ありがとうございます。
（日本語時にCtrl+Enterを改行に割り当てるのはよくわかりませんが……）
Linuxでディスク容量を食っているディレクトリを探す

ディスクの残りが少なくなってきて、容量を食っているディレクトリを探したいときのコマンドです。

```
$ sudo du / -d 2 | sort -n
```
`-d`でサマリーする階層のレベルを指定できます。
なお、上記ではルートから探索してますが、全データ探索してしまうので、
`/var`等、怪しいディレクトリに絞ったほうがいいかもですね。

あと、以下のようにすると、10M や 20G 等、human-readableに出力されます。

```
$ sudo du / -d 2 -h | sort -h
```

### 追記
- 参照権限のないファイルのサイズは取得できないので、sudo が必要です。
- ファイルの削除後もプロセスがデータを握っていることがあるので実際の値とずれることがあります。再起動してきれいな状態で実行すると、より正確な値が取得できます。
初心者がVue.jsの公式ガイドを勉強するメモ 状態管理編

# 状態管理編
## お題はこちらです。
### https://jp.vuejs.org/v2/guide/state-management.html

* App.vue

``` html
<template lang="pug">
  #app
</template>

<script>

const store = {
  debug: true,
  state: {
    message: 'Hello'
  },
  setMessageAction (newValue) {
    if (this.debug) console.log('setMessageAction', newValue)
    this.state.message = newValue
  },
  clearMessageAcion ( {
    if (this.debug) console.log('clearMessageAcion')
    this.state.message = ''
  })
}

export default {
  name: 'app',
  data () {
    return {
    }
  },
  components: {
  }
}
</script>
```

* コンポーネントを多用するとprops / emitでデータのやり取りをするのは、容易にdata property の管理が大変になることは目に見えています。（孫とかひ孫とか...）
  * 逆に、コンポーネントを使わなければいいのかもしれませんが、関数の羅列がずらーと並んでいるコードを見るのは、たとえ自分のコードでもいやになると思います。
  * それを集中管理しようとするのが状態管理をまとめる趣旨かと思います。


* 大事なのは、データとデータの書き換えが一箇所で管理ということらしいです。
  * まぁ、そうですよね。　ひ孫のコンポーネントから共用データを書き換えもするでしょう、ましてや、それがバグで意図しない書き換えだったら、バグ取りがとても困難になりますね。


* 上の例は、debug trueのときは、関数が実行された時(書き換えた時)に、ログが流れます。


* App.vue

``` html
<template lang="pug">
  #app
    button(@click="deleteAction()") Delete item button
    .parent
      my-awesome-list(:items="sharedState")
         li(
          slot="itemSlot"
          slot-scope="{ text }"
          class="my-fancy-item"
         )
          span {{ text }}

</template>

<script>
import Vue from 'vue'

const store = {
  debug: true,
  state: {
    items: [
      { name: 'apple' },
      { name: 'banana' },
      { name: 'Natto' },
    ],
    message: 'Hello'
  },
  deleteItemsAction () {
    if (this.debug) console.log('deleteItemsAction')
    this.state.items.pop()
  },
  setMessageAction (newValue) {
    if (this.debug) console.log('setMessageAction', newValue)
    this.state.message = newValue
  },
  clearMessageAcion () {
    if (this.debug) console.log('clearMessageAcion')
    this.state.message = ''
  }
}

Vue.component('my-awesome-list', {
  props: ["items"],
  template: `<ul>
    <slot name="itemSlot" :text="item.name" v-for="item in items"></slot>
  </ul>`
})

export default {
  name: 'app',
  data () {
    return {
      privareState: {},
      sharedState: store.state.items
    }
  },
  computed: {
  },
  methods: {
    deleteAction () {
      store.deleteItemsAction()
    }
  }
}
</script>
```

* store のdeta を Appのrootのデータに引っ張って来て、表示用に使っています。
* store のdata は直接削除せず、storeのメソッドを呼び出して削除しています。

* 今回はこれで、終わりです。
* 短いですが、すごく勉強になりました。 dataの扱い方やメンテナンスのし易いコードの書き方等を考えながらコードがかけるようになれば、初心者を卒業出来るのではないかと思います。
* これは、Vueに限らず応用範囲が広い考え方が出来るようになりますね。
* このながれでは、次はVuexでしょうか。(笑)
Xcodeで過去のデバッグ実行のログを確認する

# 「なんでログすぐ消えてしまうん」

通常、Xcodeのデバッグ実行時のログは、Xcodeの右下に出てくるコンソール部分で確認すると思います。ですが、ここはあくまでコンソール画面なので、次のデバッグ実行をしたりすると、それまでのログの内容は消えてしまいます。。。

なので、消えない様にコピペでログを保存したりする訳ですが、怪しげなログが出た時とか、再現性の低いバグとか、ものすごく手間のかかる手順の時に限って、ログの保存が出来てなくて「なんでログすぐ消えてしまうん」って悲しい思いをした人は少なくないと思います。

今回はそんな人に役立つかも知れない記事です。

# 過去のデバッグログを確認する

結論から言うと、Xcodeは過去のデバッグ実行時のログを**ある程度**、保存しています。
（あれだけ容量食うんだからそれくらい保存していて当然なのかも知れませんが、ありがたいですね）

保存されているログは、Xcodeの画面左端にあるナビゲーターエリアのレポートナビゲーターから確認できます。

<img width="360" src="https://qiita-image-store.s3.amazonaws.com/0/230873/dd7b1128-ab84-43f3-86b1-58e0c8673bb8.png">

Xcode9の場合は、一番右にある赤丸で囲んだアイコンを選択すると、レポートナビゲーターが表示されます。

▶︎`Debug`で表示されている項目がデバッグ実行時の履歴です。
ここで確認したいログを選択すると、右側のエディタ部分(赤枠内部)にデバッグ実行時のログが表示されます。

<img width="800" src="https://qiita-image-store.s3.amazonaws.com/0/230873/8a933463-e93e-f48f-0049-02b9a1cdefe7.png">

## ログの保存期間

ログが保存される期間や条件等は公式ドキュメントでも確認できませんでした。

が、いろいろと試した結果、どうやらプロジェクト（Xcode）を閉じると、最新のログ以外は消去される様です。

（ちなみに、今回のスクリーンショットの場合、3/6に撮影しているので条件が合えば１ヶ月以上前のログでも保存されていることが判ります）

いずれにせよ**過信は禁物**ですが、ログを取り忘れた場合のリカバリには十分だと思われます。

# 便利な使い方

このレポートナビゲーターからのログ表示は、過去分だけでなく実行中のデバッグのログも確認できます。

コンソールに比べて画面が広いので、ログを俯瞰したい場合に便利ですし、いちいちデバッグエリアをドラッグで最大化する手間もいりません。

また、コンソールのログにはフィルタが適用できるので、コンソールにフィルタを適用して特定のログの発生をコンソールで拾い、そのままレポートナビゲーターのログを見れば前後のログをすぐに確認できるというのも便利です。

さらに、地味に便利なのが、実機でのアプリ起動時にエラーがダイアログで出ることがありますが（証明書絡みとかで）、そのエラー内容がログの部分に出力される点です。よく判らないエラーの場合は、そのままコピーしてグーグル先生を頼ることができます。

# まとめ

これを覚えておけば、ログの取り忘れでヘコむことが無くなるかも知れません。
無事回収できたログでヘコむことになるかも知れませんが・・・
goofysはchmodできない 

[goofys](https://github.com/kahing/goofys)上のファイルはchmodできない。

> goofys doesn't support changing file permissions
https://github.com/kahing/goofys/issues/258

また、権限変更だけでなくメタデータをコピーすることもできないようだ。
goofys上でJupyter notebookを動かしたら、`shutil.copystat()`がエラーになってファイルが保存できなかった。

```
[D 2018-01-16 14:52:24.231 SingleUserLabApp fileio:56] copystat on /home/tommarute/notebook/.ipynb_checkpoints/sample-checkpoint.ipynb failed
    Traceback (most recent call last):
      File "/usr/local/conda/lib/python3.6/site-packages/notebook/services/contents/fileio.py", line 53, in copy2_safe
        shutil.copystat(src, dst)
      File "/usr/local/conda/lib/python3.6/shutil.py", line 225, in copystat
        _copyxattr(src, dst, follow_symlinks=follow)
      File "/usr/local/conda/lib/python3.6/shutil.py", line 165, in _copyxattr
        os.setxattr(dst, name, value, follow_symlinks=follow_symlinks)
    PermissionError: [Errno 13] Permission denied: '/home/tommarute/notebook/.ipynb_checkpoints/sample-checkpoint.ipynb'
```

ちなみに`rsync -p`も失敗するので、バックアップ用途でも使えなかった（もちろんrsync以外の方法を使えばできるのだろうけど）。

なお、[s3fs](https://github.com/s3fs-fuse/s3fs-fuse)はメタデータを変更できる。
ただしgoofysと比較するとかなり性能で劣る。

時間制約のないバックアップ目的で使うなら便利。

どちらにせよ上でアプリケーションが動くストレージとして使うのは厳しそう。
諦めてNFSにした。
ElmでPhantom Type (幽霊型)入門

# はじめに

elmは静的型付け言語です。コンパイラで静的にコンパイル時に、型チェックにすることによって、コードの安全性(型安全)が担保されます。このような型の存在のおかげて、プログラムに間違った値が関数に適用されていないかチェックすることができます。

このような「型」とはelmをある程度つかっているユーザであれば、別の見方をすれば「値の限定」と見なすことができるというのはすぐ理解できるんじゃないかと思います。例えば、String型やInt型の区別は、Intという値に限定するという見方ができるという見方をすることができます。型というのは、とある値の集合であり、そのある値が集合に属しているか属していないか?という確認のためのものだと言うこともできるでしょう。

さて、型は「値の限定」と言ったり「値の集合」と言ったりしましたが、たとえばString型などを、「もっと限定」したり、「値の部分集合」をとるにはどうしたら良いでしょうか? 

前回の記事で、実は、[Never](https://qiita.com/nobkz/items/bf31a9dfb4673a7bcfea)の記事にて、その一例を紹介しています。Neverを使うことによって、ある幅が広い型を限定しているという見方ができるのではないかと思います。たとえば,```Maybe Never```などは、絶対に```Nothing```になるように、限定しており、```Maybe a```の型の部分集合を取っているとも見なせると思います。

そのような値の部分集合を得るためのデザインパターンとして、Phantom Typeがあります。それを紹介してみましょう。

#  幽霊型の紹介

幽霊型とは、簡単に言えば値に出てこない型変数をつくるという型のデバインパターンです。たとえば、次のようなものです。

```elm
type Example phantom = Example
```

この```Example```という型ですが、```phantom```という型引数があります。しかし、値はExampleであり、値の中にphantomという情報はありません。このphantomという型変数を、幽霊型変数と言ったりします。

このphantomに型の世界で情報を与えることによって、値をもっと限定することができます。

##  空でないリスト

それではどうやってつかうのでしょうか? その例を上げてみましょう。たとえば、空でないリストをコンパイル時に判定したいとしましょう。普通のList aでは、それはできません。なぜなら、List aでわかる情報はただa型のリスト型ということであり、空か空でないかの情報はありません。

ここで、幽霊型をつかいます。

```elm 
type MyList isEmpty a = MyList (List a)
```

ここでこの、isEmptyは出てきません。このisEmptyによって、Listに空であるかないかの情報を入れていきます。ここで、isEmptyに入れるための型をつくります。


```elm 
type Empty = Empty 
type NonEmpty = NonEmpty
```

さて、これで、リストが空であるかないかの情報を型で表わせます。たとえば、空リストは次のようになります

```elm 
nil : MyList Empty a
nil = MyList []
``` 

そして、空でないリストは次のように表わすことができます。

```elm
intList : MyList NonEmpty Int
intList = MyList [1,2,3] 
```

さて、これで、型の上では「空でないリスト」ということを主張していますが、しかしながら、このままでは、値がある```MyList Empty Int```をつくれてしまいます。

```elm
intList1 : MyList Empty Int
intList1 = MyList [1,2,3] 
``` 

なので、moduleにして、MyListコンストラクタはMyListをopaque typeとして公開しないようにしましょう。

```elm
-- MyList(..)は公開しない。
module MyList exposing (MyList, nil, cons)
```

かわりに、MyListのコンストラクタとして、nilやconsを用意しておきましょう。

```elm
nil : MyList Empty a
nil = MyList []

cons : a -> MyList isEmpty a -> MyList NonEmpty a
cons a b = 
  case b of 
    MyList list -> MyList (a :: list)
``` 

これによって、空であるか、空でないかを保証することができます。どうやって、MyList Empty IntやMyList NonEmpty Intをつくるのでしょうか? MyList Empty Intは簡単です、nilから作れます。一方、MyList NonEmpty Intは、consを使います。このnilは必ず空を返すのと、consが必ず空でないリストを返すので、そういったことが保証できるのですね。

```elm
nilInt : MyList Empty Int
nilInt = nil

intList2 : MyList NonEmpty Int 
intList2 = cons 42 nil
```

もうひとつ関数をつくってみましょう。head関数です。head関数はリストの先頭要素を取得しますが、それは前提としてリストが空でないときです。なので、head関数は空でないリストが欲しいわけですが、それを保証することができます。

```elm
head : MyList NonEmpty a -> Maybe a
head a = 
  case a of 
    MyList list -> List.head list  
```

ここで、```Maybe a```を返してしまっていますが、```Just```しか返さないはずです。なので、```Maybe a```ではなく、```a```を返したいわけですが、内部に、elmのListの型を用いているので、Maybe aにしています。

# まとめ

最後にまとめましょう。

* 幽霊型とは、簡単に言えば値に出てこない型変数をつくるという型のデバインパターン

とりあえずそれだけ覚えておけばいいかと。最後にですが、幽霊型ですが、elmではあまり一般的なものではないのですが、しかしながら、GUIの状態の管理のために有効に利用できることもあり、覚えておいて損はないかなと思います。
Amazon Elastic Container Registry (ECR) へイメージをプッシュするシェルを書いた

IAMからECRへのイメージをアップロードするロールを作成します。
既存のポリシー`AmazonEC2ContainerRegistryPowerUser`を使っても良いと思います。
リージョンは`ap-northeast-1`前提で進みます。

`aws ecr get-login`コマンドで`login`コマンドを取得します。

アカウントIDが必要になるのですが、`jq`コマンドを使って逃げます。

```
aws sts get-caller-identity | jq .Account
```

## シェル

```bash:ecr-push.sh

#!/bin/bash

DOCKER_TAG="$1"

AWSID=$(aws sts get-caller-identity | jq -r  .Account)

LOGIN=$(aws ecr get-login --no-include-email --region ap-northeast-1)

${LOGIN}

# docker build -t $DOCKER_TAG .

docker tag $DOCKER_TAG:latest $AWSID.dkr.ecr.ap-northeast-1.amazonaws.com/$DOCKER_TAG:latest

docker push $AWSID.dkr.ecr.ap-northeast-1.amazonaws.com/$DOCKER_TAG:latest
```

### シェルの起動

```
sh ecr-push.sh docker-tag
```

## 注意点

`jq` コマンドで文字列にアクセスすると、"\"xxx\""とクオーテーションがエスケープされて出力されてしまう。
`jq -r`または`jq --row-output`オプションを付けることで文字列をシェル上の文字列として扱うことができる。
前処理で精度は上がるか？~特別編～

[前回](https://qiita.com/umesaku/items/da720c98a79ecd3574c9)、4つの前処理法を
（dataset）cacner_datasets
（メソッド）sklearn.svmのSVC
を使って試してみたところ、4つ全てで精度は向上しました。
今回は再現性を確認したいと思い、違うデータで試しました。

（dataset）boston_datasets
（メソッド）sklearn.linear_modelのLinearRegression
※boston_datasetsとはボストン住宅価格と特徴量のデータセットで超有名なものです。ただ、cacner_datasetsの分類（離散データ）と違い、価格の予測（連続データ）なのでSVCは使えません。
あと、私はboston datasetsをcsvでダウンロードしているのでパスを通してデータの読み込みをやっています。なので、パス部分は省略しています。
話それますが、最初のころは相対パスとか絶対パスとか、何のことやらさっぱりわかりませんでした。今でも苦手です（泣

##まずは、rawデータで精度を確認

```ruby:qiita.rb
#csvファイルはdataframeだと扱いやすいのでpandasを呼ぶ
import pandas as pd
from sklearn.model_selection import train_test_split
from pandas import Series,DataFrame
boston_df = pd.read_csv("boston_rawdata.csv")
boston_df.head()
```
もうすっかり有名なので、今更だが、データ構造はこんな感じ。
右端の”MEDV（住宅価格）”で目的変数のこと。他は説明変数で計13変数ある。
<img width="746" alt="boston_dataset.png" src="https://qiita-image-store.s3.amazonaws.com/0/241427/d8590ecb-1e37-d6b7-07e5-2dc6de8f31d5.png">

```ruby:qiita.rb
# 説明変数。dropメソッドでMEDVを落とす。つまりMEDV以外を選択。
X = boston_df.drop('MEDV',1)
# 目的変数
y = boston_df.MEDV

from sklearn.linear_model import LinearRegression
from sklearn.metrics import accuracy_score
# インスタンスを作る
lr=LinearRegression()
X_train,X_test,y_train,y_test=train_test_split(X,y,random_state=42)
#　データ形状を見ておこう
print(X_train.shape,y_train.shape)
(379, 13) (379,)

#訓練データとテストデータのモデルを作る。
lr_train=LinearRegression().fit(X_train,y_train)
lr_test=LinearRegression().fit(X_test,y_test)

#それぞれの精度を見てみよう
print("Scaled train set accuray:
　　　{:.2f}".format(lr_train.score(X_train,y_train)))
print("Scaled test set accuray:
　　　{:.2f}".format(lr_test.score(X_test,y_test)))
Scaled train set accuray:0.75
Scaled test set accuray:0.76
```
精度は訓練データが0.75でテストデータが0.76。over fittingも起こしてなさそうだし、精度も高そう。いいんじゃない？
ココから本番！前処理をすれば0.76以上になるのか？やってみよう！

##前処理　StandardScalerを使ってみた
個人的にこの手法がわかりやすいので今回はコチラで。

```ruby:qiita.rb
from sklearn.preprocessing import StandardScaler
scaler=StandardScaler()
scaler.fit(X_train)
#こんなアウトプットが出ます。
StandardScaler(copy=True, with_mean=True, with_std=True)

#では転換（fitとtransformはセットで覚える！）
X_train_scaled=scaler.transform(X_train)
X_test_scaled=scaler.transform(X_test)
lr=LinearRegression().fit(X_train_scaled,y_train)
```
さあ、これで準備が整いました。

```ruby:qiita.rb
print("Scaled test set accuray:
　　　　{:.2f}".format(lr.score(X_test_scaled,y_test)))
Scaled test set accuray:0.68
```
あれ？精度は0.68です。rawのtestデータの精度0.76と比較すると「89％」と1割以上も低下しています。

##結　論（とりあえず・・）

まったく心許ないサンプルで結論を出すのはホント恥ずかしいのだけど、
1.前処理をすれば必ず上がるわけではない？
2.前処理は目的変数は離散データのほうが当てはまりが良い？つまり分類？
3.私がどこかで間違えた？
のいずれかなのかなー、というのがとりあえずの結論です。
スッキリせず、すいません（汗
シェル上でテキストファイルを確認する時に便利なLinuxコマンド

ログファイルやデータファイル等のサイズの大きなファイルを
シェル上でいじくるときに便利なコマンドをまとめました。
他にもいろいろあるかと思いますが、とりあえずよく使うものを。

## ZIP圧縮ファイルの中身を見る
```
zcat file.gz
```
## 文字コードを変換して出力する
### 例）CP932のテキストをUTF8に変換する
```
iconv -c -f cp932 -t utf8
```
`-c` をつけると変換エラーをスキップしてくれます。
`iconv -l`で対応する文字コードが確認できます。

## 指定行のデータを抽出する
### 例）末尾10行の表示
```
tail -10
```

### 例）10行目以降の出力
```
tail -n +10
```
### 例）10行目から20行抽出
```
tail -n +10 | head -20
```

## 指定の文字列を含む行の抽出
### 例）xxx という文字列を**含む**行を抽出する
```
grep xxx
```
### 例）yyy という文字列を**含まない**行を抽出する
```
grep -v yyy
```

## ソート
### 例）カンマ区切りのCSVデータの3番目の項目を数値としてソートする
```
sort -t, -k3 -n
```

## 列の抽出
### 例）カンマで分割して5列目と10列目を表示
```
cut -d, -f5,10
```

## 重複の除去
```
uniq
```
※ 事前にソートされている必要があります。
Web Animations API お試し

書いたやつ
https://github.com/clngn/animation-study

これを真似た。トグルボタンはめんどかったので諦めた。
https://dribbble.com/shots/1749645-Contact-Sync

## パッケージ
https://github.com/web-animations/web-animations-js
最初動かなかったから入れたけど、最終的にはなくてもわりと動きそうな気がした(Chrome利用)。

## アニメーション
```javascript
const element = document.querySelector('.animation');
const animation = element.animate([
  {
    width: '10px',
    height: '10px',
    opacity: 0,
  },
  {
    width: '50px',
    height: '50px',
    opacity: 1,
  }
], {
  duration: 500,
  easing: 'ease-out',
});
```

animateの第一引数はkeyframes、第二引数はotions。

keyframesは配列に変化前と変化後のstyleを入れる。
両方のプロパティを揃えておかないとダメっぽい。

optionsはdurationやeasingなどが指定できる。

https://developer.mozilla.org/en-US/docs/Web/API/Element/animate

### 後処理
[コメント](https://qiita.com/clngn/items/acce6889120958c29f0c#comment-d50f46e666e3f38e8351)で指摘いただき、animateのoptionsで調整できることがわかったので修正。

```javascript
...
], {
  duration: 500,
  easing: 'ease-out',
  fill: 'forwards',
});
```

~~普通にanimateさせただけだとアニメーション終了時にもとのスタイルに戻る。~~
~~変化させたあとの状態を維持したい場合は終了時にスタイルを上書きする必要がある。~~

```javascript
// 上の続き
animation.onfinish = () => {
  element.style = {
    width: '50px',
    height: '50px',
    opacity: 1,
  };
};
```

https://developer.mozilla.org/en-US/docs/Web/API/Animation/onfinish

## 感想
JS内でスタイルいじるなら最初からCSS in JSでやった方が良いのでは？感があった。
それはそれでいろいろ面倒ごとありそうな気もするけど。

## 参考
- [Animation \- Web APIs \| MDN](https://developer.mozilla.org/en-US/docs/Web/API/Animation)
- [Web Animations API を使ってみる \- Qiita](https://qiita.com/mizchi/items/4def48e2467ae2b04da3)
- [Webアニメ実装の常識を変えるWeb Animations APIとは？ \- WPJ](https://www.webprofessional.jp/bringing-pages-to-life-web-animations-api/)
- [web\-animations\-jsで策定中のAPIを先取りする \- Qiita](https://qiita.com/haribote/items/a8fc84d6cc2fd4abbf72)
sudoなのにElectronがPermission Deniedでインストールできない問題を直す

2017年後半から一部の環境でこの問題が発生しているようです。

## 環境
```
OS: Antergos
Kernel: x86_64 Linux 4.15.6-1-ARCH
~ ❯❯❯ node -v // -> v8.9.4
```

## 問題
```
>>> sudo npm install -g electron
/// ~~~~~ ///

Error: EACCES: permission denied, mkdir '/usr/local/lib/node_modules/electron/.electron'
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! electron@1.8.3 postinstall: `node install.js`
npm ERR! Exit status 1
npm ERR! 
npm ERR! Failed at the electron@1.8.3 postinstall script.
```

## 解決
``sudo npm install -g electron --unsafe-perm=true --allow-root``

## 参考
[Error: EACCES: permission denied, mkdir &#39;/usr/local/lib/node_modules/electron/.electron&#39; · Issue #17268 · npm/npm - github](https://github.com/npm/npm/issues/17268)
Python > Subprocess > サブスクリプトが終了時にメインスクリプトを終了する

```txt:動作環境
GeForce GTX 1070 (8GB)
ASRock Z170M Pro4S [Intel Z170chipset]
Ubuntu 16.04 LTS desktop amd64
TensorFlow v1.2.1
cuDNN v5.1 for Linux
CUDA v8.0
Python 3.5.2
IPython 6.0.0 -- An enhanced Interactive Python.
gcc (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609
GNU bash, version 4.3.48(1)-release (x86_64-pc-linux-gnu)
scipy v0.19.1
geopandas v0.3.0
MATLAB R2017b (Home Edition)
ADDA v.1.3b6
gnustep-gui-runtime v0.24.0-3.1
Jaybird RUN (ワイヤレスイヤホン)
```

プロジェクト開始: https://qiita.com/7of9/items/4077c92b9a773e054193

### やりたいこと

- [MemoryEnhancer > MEGLV > udpGraph_180218.ipynb > v0.3 > ログ機能追加 | 動画測定とログ保存までの手順](https://qiita.com/7of9/items/7c4b8276da1808c0b84b)
- A. [UDP受信 + リアルタイムグラフ描画]ソフト
    - udpGraph_180218.ipynb
- B. [音声による作業者への指示]ソフト
    - order_gesture_180225.py
- AからBを起動する
- Bの処理終了時にAの処理も終了したい
    - TensorFlow用データの作成と整理を容易にするため

subprocessを使った同期方法を検討した。

### 参考

https://stackoverflow.com/questions/43274476/is-there-a-way-to-check-if-a-subprocess-is-still-running

### code

```main_upd_recv_180306.py
import time
import subprocess as sb

# on Python 3.5.2

'''
v0.1 Mar. 6, 2018
  - add main()
'''


def main():
    # run subprocess
    cmd = 'python3 sub_proc_180306.py'
    proc = sb.Popen(cmd.split(), shell=False)

    # main loop
    while True:
        time.sleep(1)  # sec
        print('hello')
        if proc.poll() is not None:
            break

main()

```

```sub_proc_180306.py
import time

time.sleep(3)  # sec
print('finish')

```

### 実行

```bash
$ python3 main_upd_recv_180306.py 
hello
hello
hello
finish
hello
```

1秒程度の誤差はあるが、許容内である。
Failed to decode response: zlib_decode() うんぬんというエラー


composerでLaravel Passportをインストールしようとしたら出たエラー。

![Screen Shot 2018-03-06 at 21.03.29.png](https://qiita-image-store.s3.amazonaws.com/0/109241/27d95fb7-6013-2cd6-3ac2-8052dfc930db.png "Screen Shot 2018-03-06 at 21.03.29.png")

## 原因
https://github.com/composer/composer/issues/4395
インターネットが遅すぎることによるっぽいです。（実際wifiの調子がよくなかった）
諦めずにもう一度トライしてみるべし。
ExcelからZaimに書き込む

Excelで何らかの計算を行った結果をZaimに転写したい ということ、ありますよね？え？ない？まあ、あるとして話をします。

本来であれば、外部アプリからZaimに投稿するときはZaim APIを使うのが筋なのでしょうが、面倒くさいですし、目的通りの入力ができたかどうかを確認したいので、IEオブジェクトでZaimの画面を表示することにしました。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/14499/12dc546a-431b-db10-3644-c4fef6cce878.png)

※ なお、VBAマクロを使うため、ファイルはxlsm形式で保存する必要があります。
#仕組み
仕組みは非常に簡単。IEオブジェクトを使ってZaimを表示し、フォームにデータを書き込みます(本来ならEdge等を使うべきところなのでしょうが、OLEでいじるための情報が見つかりませんでした…)。

今はIEからでもQuerySelector()を使って要素を取得・書き込みできるので楽になりました。

#コード
コードです。今回は「振り替え」のみのコードですが、入金時も出金時も大まかには同じはずです。

```vb
Public Sub ShowWindow(Amount As Integer, FromID As Long, ToID As Long, TransactionDate As String, Comment As String)
  Set IE = CreateObject("InternetExplorer.Application")
  IE.Visible = True
  Call IE.Navigate("https://zaim.net/money/new?toggle=transfer")
  Do While IE.Busy = True Or IE.readyState <> 4
    DoEvents
  Loop
  If IE.LocationURL <> "https://zaim.net/money/new?toggle=transfer" Then
    ' 目的のページにいけてないと言うことは、ログインがそもそもできてないと思われる。エラーで落とす
    Call MsgBox("ログインしてください")
    Exit Sub
  End If

  IE.Document.QuerySelector("#transfer_amount").Value = Amount
  IE.Document.QuerySelector("#transfer_from_account_id").Value = FromID
  IE.Document.QuerySelector("#transfer_to_account_id").Value = ToID
  IE.Document.QuerySelector("#transfer_date").Value = TransactionDate
  IE.Document.QuerySelector("#transfer_comment").Value = Comment
End Sub
```
Zaimでは、口座の情報はIDで管理されていますので、そのIDさえ指定すれば口座を指定できます(入出金ページなどをブラウザの開発者ツールで見ることで確認できます)。口座の数値は大きいので、IntegerではなくLongで指定しておきましょう。

また、日付についてはZaimは"yyyy年mm月dd日"しか受け付けてくれないようです(yyyy/mm/ddではダメでした)。あらかじめExcel側でyyyy年mm月dd日に日付の書式を設定しておき、それを引数に指定しましょう。


あとはExcel側からなんらかの方法を使ってこのメソッドを呼び出せば、値が全て設定されている状態で、振り替えウィンドウが表示されます。値を確認してから「入力」ボタンを押せば入力ができます。

他のWebサイト・WebサービスをExcelからいじるときにも応用が効くかなと。
Cloud NativeなIconを丸々ゲットする方法

Cloud NativeなIconを駆使してそれっぽい絵を描きたい
最近の話題や流行に乗っかりたいみたいな欲求ってありますよね。

そんな時には、Cloud Native Computing FoundationのLandscape/github リポジトリを丸々or一部cloneしましょう。

```
git clone git@github.com:cncf/landscape.git
```

こうすることによってlandscapeに乗っているIcon全部がダウンロードされます。
landscapeからちまちま抜き取るのもいいのですが、煩雑ですよね。
\#ファイルサイズ1.4Gくらいありますけど...w

```
.
├── cached_logos
├── hosted_logos
├── INSTALL.md
├── landscape
├── landscape.yml
├── LICENSE
├── package.json
├── package-lock.json
├── processed_landscape.yml
├── README.md
├── _redirects
├── serverless
├── src
├── tools
├── UPDATE.md
├── update_server
├── webpack.config.dev.js
├── webpack.config.prod.js
└── yarn.lock
```
hosted_logosというディレクトリの中にSVGイメージが展開されているようです。
そもそもは、landscapeを作るためのファイル置き場となっているようです。

あとは、ここから必要なものを必要なところで使うだけ。
ライセンスは。。。多分大丈夫なはず。

便利！
画像分類でのError Analysis

精度を上げるためにエラーを分析し、対処をしていく

#まずはトレーニング
```python
model = Sequential()
model.add(Conv2D(f, 3, 3, input_shape=(imagesize, imagesize, 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Conv2D(f*2, 3, 3))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Conv2D(f*4, 3, 3))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Conv2D(f*8, 3, 3))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Conv2D(f*16, 3, 3))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Flatten())
model.add(Dense(1024))
model.add(Activation('relu'))
model.add(Dropout(0.5))
model.add(Dense(classnum))
model.add(Activation('softmax'))
```

class:3(モンサンミッシェル、サクラダファミリア、タージマハル)
train:626枚
teat:128枚

![download.png](https://qiita-image-store.s3.amazonaws.com/0/239266/6875fb56-9d0f-0e0b-2be2-cfccc6504821.png)
![スクリーンショット 2018-03-06 19.57.47.png](https://qiita-image-store.s3.amazonaws.com/0/239266/fc467aea-2664-160e-f347-b56983beb55e.png)

error:5.5%

間違った画像が5枚あるということになる

#間違った画像を探す
Mont_Saint_Michel:1枚
Sagrada_Familia:0枚
Taj_Mahal:3枚
total:4枚

5枚あると思ったが、4枚しか見つからなかった


![スクリーンショット 2018-03-06 20.04.50.png](https://qiita-image-store.s3.amazonaws.com/0/239266/844e3473-3dc3-c241-8060-cf3e516528ec.png)
=======================================
![スクリーンショット 2018-03-06 20.11.51.png](https://qiita-image-store.s3.amazonaws.com/0/239266/ddc3dbcc-f411-828b-58af-c28801cee371.png)
=======================================
![スクリーンショット 2018-03-06 20.10.43.png](https://qiita-image-store.s3.amazonaws.com/0/239266/0edfd178-1ee3-280d-7933-363d26cd83ea.png)
=======================================
![スクリーンショット 2018-03-06 20.16.08.png](https://qiita-image-store.s3.amazonaws.com/0/239266/bb55cf4a-3fd7-175f-3723-cea827090df7.png)
=======================================

#エラー画像の特徴
・1枚目のモンサンミッシェルは他のモンサンミッシェルの画像に比べて、グレーのような色が多い
・残り3枚のタージマハルは、なぜ間違ったのかがわからない。特に変わった画像では無いと思う

#対処
もっと大きなデータセットであればエラー画像が何十、何百枚とあり、エラーの特徴が1クラスに偏っている、天気が悪い日の画像が多い等はっきりとしていれば、そこを重点的に対処するのだが、今回は枚数が少ないので全てのエラー画像に対して対処する

実際のエラー画像を水平に反転させたりしてtrainフォルダに突っ込み、学習させる
※もちろんエラー画像をそのままtrainフォルダに入れてはいけない

![images (52)のコピー3.jpeg](https://qiita-image-store.s3.amazonaws.com/0/239266/470357be-9a3e-829c-09f1-cc83657a0d68.jpeg)
![images-56のコピー.jpg](https://qiita-image-store.s3.amazonaws.com/0/239266/4fd77fd6-4d72-29f1-fb05-8b4c1d2482ee.jpeg)
![images-91のコピー.jpg](https://qiita-image-store.s3.amazonaws.com/0/239266/e64c0070-3a8d-f7f7-e64c-8ed5970020c6.jpeg)

#再びtrain

![スクリーンショット 2018-03-06 20.48.49.png](https://qiita-image-store.s3.amazonaws.com/0/239266/9f985771-2de9-242a-018a-1888c52dc457.png)
![download.png](https://qiita-image-store.s3.amazonaws.com/0/239266/2820c124-60ce-b772-22f1-1f30aa3add7d.png)

error:4%

1.5ポイント精度が上昇した
TinyTeXを使って10分で(R向けの)LaTeX環境を整える

[TinyTeX](https://yihui.name/tinytex/)はTeX LiveベースのLaTeXディストリビューションで、必要最小限の機能に絞ってインストールするので通常3時間くらいかかる[^1]LaTeXのインストールが10分くらいで終わる。

そして何よりRと相性が良い。というかRで完結するので、Rのパッケージくらいの気持ちでLaTeXを扱える。そして私はR以外でLaTeXを使うつもりがないので、この記事でR以外の話はしない。

[^1]: 最近LaTeXインストールした記憶が無いので実際どれくらいかかるのかは知らない…

## インストール(Rユーザー向け)

Rで以下の2行を実行するだけ。超簡単。

```r
install.packages(c('tinytex', 'rmarkdown'))
tinytex::install_tinytex()
```

R以外のユーザー向けにコマンドラインからのインストール方法もあるらしいけど試してないので詳しくは本家Webサイトで確認を。

- [TinyTeX - A lightweight, cross-platform, portable, and easy-to-maintain LaTeX distribution based on TeX Live - Yihui Xie | 谢益辉](https://yihui.name/tinytex/)


## R Markdownで日本語を使う

おそらくTinyTeXのインストールで6分くらい使ったと思うので、まだ4分くらい残ってるはずだ。残りの時間を日本語の設定にあてよう。

日本語はそのままでは通らないけど、フォントのインストールと少しの設定で使えるようになる。

- [ダウンロード(Download) | IPAexフォント/IPAフォント](https://ipafont.ipa.go.jp/node17#jp)からIPAexフォントをダウンロードしてインストール
- YAMLフロントマターに以下の内容を記述(参考: [Rmarkdownで日本語PDFを出力する - Qiita](https://qiita.com/Atsushi776/items/9ef1e5d744e2b91c61ee))
    - 注: bookdownを使うことを想定している。

```yml
--- 
site: bookdown::bookdown_site
output:
  bookdown::pdf_book:
    latex_engine: xelatex
    pandoc_args: --top-level-division=chapter
documentclass: bxjsbook
classoption: xelatex,ja=standard
geometry: no
---
```

あとはビルドするだけ。

## ハマったところ

### ! Package fontspec Error: The font "ipaexm" cannot be found.

`ipaexm`を探しに行ってしまうが、実際には`ipaex`をインストールする必要がある。Rのコンソールで以下を実行し、手動でインストールする。

```r
tinytex::tlmgr_install("ipaex")
```

### ! LaTeX Error: Option clash for package geometry.

geometryを重複して読み込んでいるのが原因らしい。pandocの--templete引数以下に書いてある場所にあるファイルを開いて、geometry読み込み部分をコメントアウトする。

```tex 
$if(geometry)$
%\usepackage[$for(geometry)$$geometry$$sep$,$endfor$]{geometry}
$endif$
```

- 参考: [Bookdownによる技術系同人誌執筆](https://teastat.blogspot.com/2019/01/bookdown.html)
gvimをタブエディタにする

#初期設定

今回は常時タブエディタとしたいので、以下の手順で設定を行った。
（尚、環境はWindows）

__①レジストリエディタを開きます__
　Win + R（ファイル名を指定して実行）から regedit でポチッと

__②以下のキーに値を設定します__
　キー　：HKEY_CLASSES_ROOT\Applications\gvim.exe\shell\open\command
　設定値："{ホームディレクトリ}\gvim.exe" -p --remote-tab-silent "%1"

　尚、事前にレジストリのバックアップは各自でアレしておいてください。

__③タブエディタ化を確認__
　適当なファイルを複数、gvimで開いてみてタブエディタ化していることを確認。


#後日談（タブにならなくなった）

ある日、何故かファイルを開いてもタブにならなくなった(´・ω・｀)

ﾅﾝﾃﾞﾅﾝﾃﾞ？などと思っているうちに、何故か__PHPファイル__を開いたときのみタブ化しないことに気付く。そして。再びレジストリを検索した結果、こんなキーが…

　キー　：__HKEY_CLASSES_ROOT\php_auto_file__
　設定値："{ホームディレクトリ}\gvim.exe" -p "%1"

こちらもサクッと設定値を -p --remote-tab-silent "%1" に変更して__問題解決！__

ちょっとした事だが、知っておけば次回から慌てず済むはず…！
gruntのsassで文字化けエラーが出る

Windowsでgrunt-contrib-sassでコンパイル時にエラーが出て、

Error: Invalid Windows-31J character "\xE3"

みたいな感じ。

で対処方

scssのファイルで、

```
@charset "utf-8";
```
を先頭につけましょう。

→この解決方法で**一緒に仕事する人がmacだと先方はエラーが起きてない**ので、こっちが一個一個につける。

**面倒くさい**。先方にも周知。マックに対して肩身が狭い


そもそもなんで発生してるのか？

コマンドプロンプトのデフォルトの文字設定がshift-jisになってる。
→scssに設定してあるコードがない。
→じゃあ、shift-jisって事かな？
→エラー

という状況らしい。**日本語に対応したshift-jisで日本語があるとエラーが起きる**。という糞を塗りたくった状況のエラーっぽい。

コマンドプロンプトの文字コードを変更しよう

```
chcp 65001
```
でエラーを回避できる。

が、毎回打つのが**面倒くさい**。

chcpをデフォルトで設定できるのか？→**結構不可能**。

毎回打つようにする？

またコマンドプロンプトの文字コードを変更するのはそれでそれで問題がでるかも。

→結構悩む

sassはrubyなので、rubyのデフォルトの文字を設定する。

環境変数で

```
RUBYOPT
-EUTF-8
```
を設定する。

そうすると、
sass
→文字コードの設定がない
→rubyでは文字コード設定なかったら-EUTF-8にします。
→エラーおきない。

この方法が一番いいと思った。
オフラインリアルタイムどう書く E22 の実装例

問題 : http://nabetani.sakura.ne.jp/hena/orde22numord/
解答リンク集 : https://qiita.com/Nabetani/items/99e38a39165e1905b415

正直言って、難しすぎるかとも思っていたんだけど、きっともっと簡単な解法があるに違いないとも思っていて、そんな感じで出してみたこの問題。
今のところ思いがけない簡単な解法はなく、やっぱり難しかった模様。

ナイーブじゃない実装の方針はいくつかあると思うんだけど、私が思いついたのは下記のようなものだけ。

```ruby:ruby2.5
# kc の範囲の数が digit より前に何件あるか。b進数。
def order_at( kc, digit, b )
  kc.sum{ |min, max|
    smin, smax = [min,max].map{ |m| m.to_s(b) }
    next 0 if digit <= smin
    next max-min+1 if smax < digit
    ( digit+"0"*100 )[0,smin.size].to_i(b) - min + ( digit.size<=smin.size ? 0 : 1 )
  }
end

# b 進数、kc の範囲の数で、 ord 番目の数の b 進数表現 を返す。
# min と max の間。頭は digit であるらしい。
def find( b, kc, digit, ord, min, max )
  val = digit.to_i(b)
  lo = order_at( kc, digit, b )
  return nil if ord<lo
  return digit if ! digit.empty? && lo==ord && min<=val && val<=max
  return nil if max.to_s(b).size<digit.size
  hi = order_at( kc, digit + (b-1).to_s(b)*100, b )
  return nil if hi<ord
  (0...b).inject(nil) do |acc, n|
    if digit.empty? && n==0
      acc
    else
      acc || find( b, kc, digit+n.to_s(b), ord, min, max )
    end
  end
end

def solve_impl(m,n,b,x)
  ketamin, ketamax = [m,n].map{ |e| e.to_s(b).size }
  kc = (ketamin..ketamax).map{ |k|
    nmin=[m,b**(k-1)].max
    nmax=[n,b**k-1].min
    nmin<=nmax ? [nmin, nmax] : nil
  }.compact
  find( b, kc, "", x-1, m, n )
end

def solve(src)
  m,n,b,x = src.split(",").map(&:to_i)
  solve_impl(m,n,b,x).to_i(b).to_s
end

DATA.map{ |line|
  num, src, expected = line.split(/\s+/)
  actual = solve(src)
  okay = actual == expected
  puts [ (okay ? "ok" : "**NG**" ), src, actual, expected].join(", ")
  okay
}.all?.tap{ |o| puts( o ? "okay" : "something wrong" ) }

__END__
0 2,15,3,8  14
1 6,8,8,1 8
2 6,6,5,1 6
3 4,11,5,2  6
35  26065964,66252692,18,29196596 63208819
36  66097362,104618756,16,32740764  98838125
```

先頭の桁から順に決めていくという戦略。
この戦略は、上記の「`order_at`」が割りと簡単に実装できることに依拠している。

まあでも難しいよね。ちょっと反省している。

それと。 Tweet したとおり、問題がシンプルなので既出じゃないかと疑っている。どうだろう。

ちなみに。
次回は明日（3/7 水) で、[F10]( https://yhpg.doorkeeper.jp/events/70864 )。こちらの問題はだいぶ簡単。
その次は 4/7 土 で、[E23]( https://yhpg.doorkeeper.jp/events/71800 )。こちらは作問未着手。
御用とお急ぎでなければ是非おいでください。
Laravel controllerからviewへ お手軽変数受け渡し


```php
class XxxController extends Controller
{
    public function action()
    {
        return view('[view_name]', compact(array_keys(get_defined_vars())));
    }
}
```

これでアクションごとにcompactの引数を変える必要がありません。
計算途中で作った変数など…多少不要な変数も渡してしまいますがっ
php7.0で確認した限りでは、get_defined_varsはメソッド内で作成した変数だけ返していました。
Laravel config DBで管理する


ある程度migration、model、commandの使い方が分かっている人向け。

# migration

```bash
php artisan make:migration create_laravel_config_table
```

```php:database/migrations/xxxx_create_laravel_config_table.phpを編集
Schema::create('laravel_config', function (Blueprint $table) {
    $table->increments('id');
    $table->string('config_name', 16)->comment('設定ファイル名');
    $table->string('config_key', 64)->comment('設定KEY');
    $table->text('config_value')->comment('設定値');
    $table->unsignedTinyInteger('is_json')->default(0)->comment('JSONフラグ');
});
```

# model

```bash
php artisan make:model LaravelConfig
```

```php:app/LaravelConfig.phpを編集
class LaravelConfig extends Model
{
    protected $table = 'laravel_config';
    public $timestamps = false;
}
```

# command

```bash
php artisan make:command CreateConfigFile
```

```php:app/Console/Commands/CreateConfigFile.phpを編集
protected $signature = 'batch:CreateConfigFile';

public function handle()
{
    $configs = [];
    $laravel_config = [];
    $config_data = LaravelConfig::get();
    if ($config_data->isNotEmpty()) {
        $list = $config_data->all();
        foreach ($list as $v) {
            $configs[] = $v->toArray();
        }
    }
    if (!empty($configs)) {
        foreach ($configs as $v) {
            if ($v['is_json'] == 1) {
                $value = json_decode($v['config_value'], true);
            } else {
                $value = $v['config_value'];
            }
            $laravel_config[$v['config_name']][$v['config_key']] = $value;
        }
    }
    if (!empty($laravel_config)) {
        foreach ($laravel_config as $config_name => $config) {
            $file_path = 'config/' . $config_name . '.php';
            $file_data = '<?php' . PHP_EOL;
            $file_data .= '/**' . PHP_EOL;
            $file_data .= '  Auto Created' . PHP_EOL;
            $file_data .= '  ' . date('Y-m-d H:i:s') . PHP_EOL;
            $file_data .= '*/' . PHP_EOL;
            $file_data .= 'return ' . var_export($config, true) . ';' . PHP_EOL;
            file_put_contents($file_path, $file_data);
        }
    }


    return 0;
}
```

laravel_configにデータを登録し、作成したコマンドを実行するとconfigディレクトリ配下に設定ファイルを作成します。
本番環境ではキャッシュ生成前に実行しておきます。

ただ、これだとファイル管理のままでよくないか…？

# 動的にconfig設定
これをアプリケーションの共通処理か何かに仕込んでおく。
こちらの方がDB化する意味あるかも。

```php
$configs = [];
$config_data = LaravelConfig::get();
if ($config_data->isNotEmpty()) {
    $list = $config_data->all();
    foreach ($list as $v) {
        $configs[] = $v->toArray();
    }
}
if (!empty($configs)) {
    foreach ($configs as $v) {
        if ($v['is_json'] == 1) {
            $value = json_decode($v['config_value'], true);
        } else {
            $value = $v['config_value'];
        }
        \Config::set($v['config_name'] . '.' . $v['config_key'], $value);
    }
}
```