OmniAICreator/Qiita-1.07M huggingface dataset:
Rails6 のちょい足しな新機能を試す108（multi-db abort_if_pending_migrations編）

# はじめに

Rails 6 に追加された新機能を試す第108段。 今回は、 multi-db abort_if_pending_migrations 編です。
Rails 6 では、 `rails db:abort_if_pending_migrations` が multi database に対応しました。

Ruby 2.6.5, Rails 6.0.0 で確認しました。 (Rails 6.0.1 がリリースされていますが、確認した時点ではリリースされていませんでした。）

```shell
$ rails --version
Rails 6.0.0
```

今回は、簡単なスクリプトを作って確認します。

# Rails プロジェクトを作成する

```shell
$ rails new rails_sandbox
$ cd rails_sandbox
```

今回は複数のDBを作って、それぞれ、 User と Book のCRUD を作ってから、 `rails db:abort_if_pending_migrations` を実行して確認します。

# config/database.yml を編集する

`config/database.yml` を編集して複数データベースにします。

```yaml:config/database.yml
...
development:
  backbone:
    <<: *default
    database: backbone_development
  library:
    <<: *default
    database: library_development
    migrations_paths: db/library_migrate
...
```

# User の CRUD を作成する

`User` の CRUD を作成します。


```shell
$ bin/rails g scaffold User name
```

# Book の CRUD を作成する

`Book` の CRUD を作成します。

```shell
$ bin/rails g scaffold Book title --db library
```

# Book モデルを編集する

データベースの接続先を `library` に変更します。

```ruby:app/models/book.rb
class Book < ApplicationRecord
  connects_to database: { writing: :library, reading: :library }
end
```

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

```shell
$ bin/rails db:create db:migrate
```

# `rails server` を実行する

別に実行しなくても良いのですが、別の事象に遭遇したので、ここで実行します。

```shell
$ bin/rails s
```

# マイグレーションを作成する

rails server を実行したのとは、別のコンソールから、books に published_at カラムを追加するマイグレーションを作成します。

```shell
$ bin/rails g migration add_published_at_to_books published_at:datetime --db library
```

# db:abort_if_pending_migrations を実行する

`rails db:abort_if_pending_migrations` を実行すると、ちゃんと `rails db:migrate` を実行しろとメッセージが出ます。

```shell
$ rails db:abort_if_pending_migrations
You have 1 pending migration:
  20191022023755 AddPublishedAtToBooks
Run `rails db:migrate` to update your database then try again.
```

# ブラウザでアクセスする

どういう訳か、http://localhost:3000/users または、 http://localhost:3000/books にブラウザからアクセスしても `ActiveRecord::PendingMigrationError` になりませんでした。
予想と違ったので、 [Issue として報告](https://github.com/rails/rails/issues/37524) しておきました。


# 試したソース

試したソースは以下にあります。
https://github.com/suketa/rails_sandbox/tree/try108_multi_db_pending

# 参考情報

* [Add support for multiple databases to `rails db:abort_if_pending_migrations`](https://github.com/rails/rails/pull/36440)
[ゼロから作るDeep Learning]Relu関数使用時のニューラルネットワークの重み初期値

#はじめに
この記事は**ゼロから作るディープラーニング 7章学習に関するテクニック**を自分なりに理解して分かりやすくアウトプットしたものです。
文系の自分でも理解することが出来たので、気持ちを楽にして読んでいただけたら幸いです。
また、本書を学習する際に参考にしていただけたらもっと嬉しいです。

# ニューラルネットワークの重みの初期値について
今までニューラルネットワークの重みの初期値は、randomメソッドを使って乱数を出していましたが、それだと学習の成功具合に幅ができてしまいます。

重みの初期値と、ニューラルネットワークの学習は非常に関係が強く、適切な初期値の場合は良い学習結果になるし、不適切な初期値だと悪い学習結果になってしまいます。

そこで今回はRelu関数を使用したニューラルネットワークに適切な重みの初期値を設定してあげる方法を実装していきたいと思います。

# Heの初期値
Relu関数を使ったニューラルネットワークに一番適しているとされる重みの初期値はHeの初期値というものです。

```python
scale = np.sqrt(2.0 / all_size_list[idx - 1])
self.params['W' + str(idx)] = scale * np.random.randn(all_size_list[idx-1], all_size_list[idx])
```

Heの初期値は、2 ÷ 前の層のノード数にルートをつけたものを計算して、それをrandomで得られた乱数にかけてあげることで作り出すことができます。
Node-REDでラズパイのシャットダウンとリブートを快適にしよう！

#概要
　ラズパイを持ち歩いていると、撤収や動きがおかしいときにシャットダウンやリブートをしますよね。私の場合、ラズパイにLCDを組み付けてサイネージ化したデモを持ち歩いています。
　そんな時、困るのが**シャットダウン**。シャットダウンするにはこんな面倒があると思います。

- ssh接続いてコマンド打つのは面倒
- 物理的なボタンは断線やスペースの問題でメンテナンスが面倒

　これらの面倒をNode-REDで解決してみました！

#実現した事
　「**Node-REDで作成したWebページにコマンド実行ボタンを用意し、ボタンを押すと対応したコマンドが実行される**」

　WebページにはNode-REDのDashBoardを使用し、次のようなフローを作成しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183282/1bbb79da-241c-e566-4863-f2b27abb4b60.png)

　ダッシュボードのWebページを開くと次のようにボタンが２つ並んでおり、ボタンを押すと対応したコマンドが実行されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183282/0b4f6593-0462-8fce-3cca-1057981c02b1.png)

#実際の様子
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">Node-REDのダッシュボードで、ラズパイをシャトダウン/リブートするボタンを作ってみました！<a href="https://twitter.com/hashtag/noderedjp?src=hash&amp;ref_src=twsrc%5Etfw">#noderedjp</a> <a href="https://t.co/zVTMXXCTjv">pic.twitter.com/zVTMXXCTjv</a></p>&mdash; まえぷー@とりあえず連繋してみる人 (@kmaepu) <a href="https://twitter.com/kmaepu/status/1199528821973610496?ref_src=twsrc%5Etfw">November 27, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> 

#フローのソースコード

```json
[{"id":"8c097990.a47498","type":"tab","label":"フロー 1","disabled":false,"info":""},{"id":"ce69ad84.b4785","type":"ui_button","z":"8c097990.a47498","name":"","group":"ef8cfd1d.26343","order":0,"width":"2","height":"1","passthru":false,"label":"シャットダウン","tooltip":"","color":"","bgcolor":"","icon":"","payload":"","payloadType":"str","topic":"","x":160,"y":80,"wires":[["e8e257d0.a9e248"]]},{"id":"e8e257d0.a9e248","type":"exec","z":"8c097990.a47498","command":"sudo shutdown -h now","addpay":true,"append":"","useSpawn":"false","timer":"","oldrc":false,"name":"","x":420,"y":80,"wires":[[],[],[]]},{"id":"5e5ec1e1.c0b4c","type":"ui_button","z":"8c097990.a47498","name":"","group":"ef8cfd1d.26343","order":0,"width":"2","height":"1","passthru":false,"label":"リブート","tooltip":"","color":"","bgcolor":"","icon":"","payload":"","payloadType":"str","topic":"","x":140,"y":140,"wires":[["3b29b4c0.041d8c"]]},{"id":"3b29b4c0.041d8c","type":"exec","z":"8c097990.a47498","command":"sudo reboot","addpay":true,"append":"","useSpawn":"false","timer":"","oldrc":false,"name":"","x":390,"y":140,"wires":[[],[],[]]},{"id":"ef8cfd1d.26343","type":"ui_group","z":"","name":"コマンド","tab":"b5051da0.fade4","disp":true,"width":"6","collapse":false},{"id":"b5051da0.fade4","type":"ui_tab","z":"","name":"Command","icon":"dashboard","disabled":false,"hidden":false}]
```


#おわりに
　Webページを開ければ誰でもコマンド実行できていまうので、セキュリティ面に問題があります。趣味レベルのものでデモ展示など頻繁に電源ON/OFFする場面ではかなり便利だと思います。
【Git】特定のファイルをGit管理したいときの手順（~/.vimrc, ~/.zshrcをバックアップ）

## はじめに
これまでディレクトリ全体、`git add .`とか`git add -A`ばかり使用していたので、調べました。

**特定のファイルだけをGit管理**するときの手順をまとめています。

今回は以下２点のファイルを管理したい場合を例にしています。

- `~/.vimrc` vimの設定ファイル
- `~/.zshrc` zshの設定ファイル

## この記事が役に立つ方
- 特定のファイルをGit管理したい方

## この記事のメリット
- 特定のファイルだけをGit管理する方法が分かる

## 環境
- macOS Catalina 10.15.1
- zsh: 5.7.1

## 【準備】
GitHubなどでリモートリポジトリを事前に作成しておく。

※今回自分で管理したかったのは設定ファイルなので、リモートリポジトリは**public**でなく、**private**にしておきました。
## 【手順】

### 1.`init`
```
cd
```
該当ファイルのある場所（今回はホームディレクトリ）に移動。

```zsh
git init
```
Git管理するためにローカルリポジトリを作成。

---

### 2.`add`
```zsh
git add .vimrc .zshrc 
```
**半角スペース区切り**で複数ファイルを一度に`add`可能。

ファイル名に共通項があるのであれば、以下のようなコマンドでも問題なし。

```zsh
git add .*rc
```
`*`がワイルドカードなので、隠しファイルで末尾がrcで終わるファイルが全て対象になる。

```zsh
git add -n .*rc
```
`-n`オプションをつけると、どのファイルが`add`されるかを確認することが可能。（実際は`add`されない）

---

### 3.`commit`

```zsh
git commit -m "first_commit"
```
適当なコミットメッセージをつけてローカルリポジトリに保存。

---

### 4. `push`
まずリモートリポジトリの設定をします。

```zsh
git remote add リポジトリ名 リモートリポジトリURL
```

- リポジトリ名：任意で設定。
- リモートリポジトリURL：GitHubなどで**事前に作成**しておいたものを使用。URLをコピペする。


```zsh
git push essentials master
```
これで`push`して完了です。

大事なファイルなのでリモートリポジトリ名は"essentials"としました。

---

### 5. 確認

```zsh
git ls-files
```
現在Git管理されているファイル一覧が出る。

ちゃんと管理したかったファイル名が表示されていればOK。

---

### 6. 次回からの`add`

```zsh
git add -u
```
２回目からは`add`はこのコマンドで対応可能。

`-u`オプションをつけるとGit管理されているファイルのみを対象として`add`してくれる。

## おわりに
最後まで読んで頂きありがとうございました:bow_tone1:

エディタは**vim**、シェルは**zsh**を愛用していて、この２つの設定ファイルが一度消えて超ショックだったので、バージョン管理することにしました。

出来れば上書き保存したら勝手に`git add`→`git push`されるように**自動化**していきたい。

Guardとシェルスクリプトとか活用すれば出来そうな感覚はあるんですが...また挑戦します。

もし実際に自動化してるよ！という方がいれば教えて頂きたいです:relaxed:
sudoの「大いなる力」の元ネタを探して

# 「大いなる力には大いなる責任が伴うこと」の由来は？

## 君はsudoコマンドのlectureを見たことがあるか？

UNIX系OSという世界の中で、あらゆることが可能なrootユーザーのように振舞える魔法のことば、
`sudo`

これを唱えたとき、~~MPが足りない~~ 権限が足りなかったりすると
以下のような警告が表示されます。

```
あなたはシステム管理者から通常の講習を受けたはずです。
これは通常、以下の3点に要約されます:

    #1) 他人のプライバシーを尊重すること。
    #2) タイプする前に考えること。
    #3) 大いなる力には大いなる責任が伴うこと。

[sudo] [貴方のユーザ名] のパスワード:
```

## 大いなる力...
１も２も、まぁ、わかります。
プライバシーは大事だし、
本当に`sudo`で実行して良いコマンドなのか、一呼吸おいて考えることが出来ます。

気になったのは、３です。（アメコミ好きなそこの貴方、気になりますよね）

**「大いなる力には大いなる責任が伴うこと。」**

そう、スパイダーマンにも出てくる言葉です。

英語だと、
「With great power comes great responsibility.」
リピートアフターミー。

初出は、Amazing Fantasy #15 (August 1962)のキャプションから、
ということなので、**1962年**からあるんですね。
※wikipedia調べ（以下、特に記載ない情報はwikipediaによります）
※ちなみに筆者は原作を知りません。ごめんなさい。


## sudoとスパイダーマンどっちが早かった？

では、Linuxのsudoの警告とスパイダーマン、どっちが早いでしょうか？

sudoの歴史は、下記のsudoのプロジェクトサイトに記載があります。
> https://www.sudo.ws/sudo/history.html
> A Brief History of Sudo
> Sudo was first conceived and implemented by Bob Coggeshall and Cliff Spencer around 1980 at the Department of Computer Science at SUNY/Buffalo. 

ふむ、作られたのは**1980年**のようですね。

当初から「大いなる力には...」と実装していたわけではないと思いますが、

スパイダーマン（1962年） < sudo（1980年）

この時点で、スパイダーマンが元ネタだろう、という推測が成立しました。

sudoにこのセリフが導入されたタイミングや「本当にネタ元なのか？」を調べるならば、
おそらく上記のsudoプロジェクトのコミットログやメーリングリストの履歴を読み込むのがベストでしょう。

が、追っていると年越してしまいそうなので、やめておきます。
（筆者が検索した限りでは、特定できませんでした。ダンジョンに繰り出す勇者を待ちます）

スパイダーマンのこのセリフの由来は、少しネットの世界を検索してみると、
フランス語のノブレス・オブリージュ「高貴さは（義務を）強制する」や
聖書に原典を求める説もあるようです。


## 原典に当たることの大切さ
rootユーザーは、絶大な権限を持ちますので、
パスワードを入力させるというステップを設けることで、ユーザーに自覚を持たせ、
一時的にその権限を付与する、というsudoの設計思想には普遍性を感じられ、感服いたします。

今回、ひょんなことから、sudoのプロジェクトのWebサイトまでたどり着きました。
コマンドのヘルプにはいつもお世話になっておりますが、
各プロジェクトの原典となるサイトを訪れることは、なかなかやりません。

実際、筆者もsudoの設計思想を考えたことが無く、良い機会になりました。

この記事を読んでくださった皆様も、ぜひ普段お使いのコマンドやツールの作者の意図や意志、
その歴史を、原典まで遡って、追いかけてみてはいかがでしょうか。
pycharmでpygameを実行できなかった話

プログラミング初心者がpythonの勉強を初めて１ヶ月。
なんとなく基本的な動作を理解できたところでpygameをやってみよう！と決意。
環境を整えている際に起こった出来事の記録です。

「ゲームを作りながら楽しく学べるPythonプログラミング」
ゲームウィンドウの表示の部分を実行しようとしたら…

```
Traceback (most recent call last):
  File "C:/Users//PycharmProjects/projects/test1.py", line 1, in <module>
    import pygame
ModuleNotFoundError: No module named 'pygame'
```
と表示され一行に先に進まなくなってしまった…
色々pycharmについて調べていると
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/516313/7ca2b106-4fc0-bb85-ddeb-d3bbd66479ce.png)
※ここにはすでにpygameが追加されています。

右側の＋をクリックして
モジュール一覧から特定のモジュールを追加しないとimportできないとありました。

初心者なので何もわかっておらず勉強不足を痛感しました。
monacaでandroidのプッシュアイコンを設定する方法

# config.xmlに以下の内容を記述


```
<platform name="android">
    <resource-file src="/res/android/hoge.png" target="/res/drawable/hoge.png"/>
    <config-file target="AndroidManifest.xml" parent="./application">
        <meta-data android:name="smallIcon" android:resource="@drawable/hoge"/>
        <meta-data android:name="smallIconColor" android:value="0x01a2c1"/>
    </config-file>
</platform>
```

android:value="0x01a2c1"のところで、16進数で色番を指定すると色がつけられるよ！

# monacaとのやりとり

### 問合せ

現在、アプリの設定でアイコンを設定しておりますが、ストアに表示されるアイコンと同一のものが通知でも表示されます。
その場合、白い四角で表示されます。
解決策としてはnotification用のアイコンを別途指定する必要がありそうですが、設定方法がわかりません。
ご教授のほど何卒、宜しくお願い致します。

参考資料
https://qiita.com/syarihu/items/95788cbab9b63100c4fb

### 回答

いつもお世話になっております。
Monacaサポート担当です。
お問い合わせいただき、誠にありがとうございます。

お問い合わせの件について、回答いたします。

Monacaバックエンドやニフクラ mobile backendからプッシュ通知を行った場合は、
「Androidアプリ設定」の「アイコン」に設定されている画像が使用されます。

Androidでは、Android 5.0から通知アイコンのファイル仕様が変更になっております。

Android 5.0から取り入れられたマテリアルデザインとしてアイコンが処理されるため、
これまで表示されていた通知アイコンは、「白い四角」のアイコンとして表示される場合があります。

白いアイコンは、アイコン画像のアルファチャネル（不透明な部分）を参照してOS側が作成します。
そのためアイコン画像が不透明な部分だけの場合、「白い四角」なアイコンとして表示されます。

Monacaバックエンドやニフクラ mobile backendからプッシュ通知を行った場合も、
基本的に、Android 5.0以降では「白い四角」なアイコンが表示されます。

端末によっては、端末の独自仕様として、
通常のAndroidの仕様とは異なる表示になるものもございます。

現状、Monaca側で行えるプッシュ通知時の通知領域の画像につきましては、
「Androidアプリ設定」の「アイコン」に、透過画像を設定していただく形となります。

ご了承のほど、よろしくお願いいたします。

以上、何卒よろしくお願いいたします。
Monacaサポート担当
Dockerを使って自分の環境を汚さずにjupyter notebookを使う方法

# Dockerのインストール
Dockerがインストールされてない場合はインストールします。

[DockerをMacにインストールする（更新: 2019/7/13） - Qiita](https://qiita.com/kurkuru/items/127fa99ef5b2f0288b81)

## (Option) Dockerの補完コマンドを使う

Dockerのコマンドは長いものが多いのでシェル上で補完できるようにした方がいいです。

[コマンドライン補完 — Docker-docs-ja 17.06.Beta ドキュメント](http://docs.docker.jp/compose/completion.html)

[Docker for macのタブ補完 - ytooyamaのブログ](https://ytooyama.hatenadiary.jp/entry/2019/02/14/220956)

やり方はいっぱいGoogle先生が教えてくれるのでやってみてください。

# jupyterイメージをpull

Dockerをインストールしたら`pull`コマンドでjupyterのイメージをダウンロードさせます。

```shell
docker pull jupyter/datascience-notebook
```

# docker-compose.ymlの編集

```yaml
version: '3'
services:
  jupyter: 
    volumes:  # カレントディレクトリをdockerコンテナ内のmyappディレクトリにマウント
      - .:/myapp
    working_dir: /myapp  # コンテナのデフォルトのワーキングdirをmyappへ
    ports:
      - "8888:8888"  # コンテナ側：ホストマシン側
    image: "jupyter/datascience-notebook"
    container_name: "notebook"  # コンテナ名（設定すれば再起動時に楽）
```

`volumes`のところを↑のようにすることで、このyamlファイルをおいた場所でjupyter notebookを起動できます。
`/myapp`のところは好きに名前変えてください。
Pythonでゴリゴリデータをいじりたいときなど、いじりたいディレクトリ内に作りましょう。

# docker-compose up で起動

ここまでできたらそのままの場所で`docker-compose up`とします。
ターミナルにnotebookが起動したURLがプリントされるのでそこへ行けばjupyter notebookが使えるはずです。
SystemRescueCDはもう古い．NixOSこそが最強のレスキュー環境である．

## あらすじ

2019年初頭にGentooベースからArchベースに移行したSystemRescueCD．
その後すぐに音沙汰がなくなり，セキュリティホールなども放置されている模様．

SystemRescueCDを愛用していた難民の方に朗報です．
NixOSのインストールメディアが最高に使いやすい．

最新版はこっち
https://gist.github.com/ijaketak/5996f3d9d2d7fb6adad4c5eb6fe15f8b

## 使い方

### 起動

https://nixos.org/nixos/download.html
からisoファイルをダウンロードして，USB等に`dd`とかで焼くだけです．
レスキューならMinimalで十分．

ブートローダで`copytoram`が選択できます．
デフォルトで`nixos`ユーザに自動ログインしますが，`sudo`が使えるので，
`passwd`後`sudo systemctl start sshd`とか`ip a`とか．

### パッケージ追加 その1

パスに実行ファイル`git`が存在するようなシェルを開く

```shell
$ nix-shell -p git
...
$ git version
git version 2.23.0
$ (Ctrl-D)
```

パッケージ名で検索

```shell
$ nix-env -qaP '.*gpt.*'
nixos.gptfdisk  gptfdisk-1.0.4
```

パッケージツリーのアップデート

```shell
$ sudo nix-channel --update
...
```

パッケージ名がイマイチ直感的に対応しない場合があるのが唯一の欠点．

### パッケージ追加 その2

Minimalの場合`/etc/nixos`に配置される`configuration.nix`がコレ．

```nix
{ config, pkgs, ... }:
{
  imports = [ <nixpkgs/nixos/modules/installer/cd-dvd/installation-cd-minimal.nix> ];
}
```

起動中に環境を書き換えるだけなら，`configuration.nix`を

```nix
{ config, pkgs, ... }:
{
  imports = [ <nixpkgs/nixos/modules/installer/cd-dvd/installation-cd-minimal.nix> ];
  environment.systemPackages = with pkgs; [
    git zsh
    gptfdisk
    ];
}
```
のように変更した後，`sudo nixos-rebuild test`で環境が置き換わります．
つまり`environment.systemPackages`にパッケージを追加したら，そのパッケージが即座に使えるようになります．

`installation-cd-minimal.nix`などはNixOSのパッケージツリーに含まれています．
https://github.com/NixOS/nixpkgs-channels/tree/nixos-19.09/nixos/modules/installer/cd-dvd/installation-cd-minimal.nix

### インストール

NixOSは公式のマニュアル見て下さい．マジで全部載ってます．
https://nixos.org/nixos/manual/

大抵のディストリビューションでは，既存の環境からインストールする方法が用意されています．
例えばDebianはdebootstrapでインストールできます．
https://www.debian.org/releases/buster/amd64/apds03.ja.html

### 起動時の挙動

普通にNixOSを設定するのと同じように設定可能です．
https://nixos.wiki/wiki/Creating_a_NixOS_live_CD

## 結論

NixOSの世界観が非常に楽ですね．
もう戻れません．
結局Firebaseの無料プランSparkでは何ができるのか

# Firebaseの制限
Google Cloud Platform(GCP)の提供するFirebaseでは料金の一切かからないプランsparkが存在する。
諸兄等には十分ご存じのことと思うが、そのプランではいくつか機能に制限がかけられている。
その制限はどのぐらい許容できるのもなのだろうか。

## はじめに
私は仕事でFirebaseのBlazeを利用して開発を行っているが、
ふと強みの一つである無料プランが存在する利点を享受できていないのではと思い当たった。
そのため、この度Sparkプランで簡単なアプリを作成し、どのようなことが可能なのか、
また、その限界はどこなのかの一端を調べてみることにした。

## 検証した内容
![limit.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/528624/b4e51941-db71-0118-2158-179790427af7.png)
今回はこちらの「100秒当たりの制限」はどのぐらいで使いつくしてしまうかについて調べた。

## 開発環境
Firebase
nodejs(v8.16.2)
typescript(3.7.2)
vuejs(2.6.10)

## ソース
https://github.com/tecoKodera/firebase_spark_test_othello
書きなぐったコードで申し訳ないが、リポジトリは上記にある

## 動作の様子
![main.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/528624/aa384e91-b4d3-9adf-a105-c027cb573f28.png)
単純なオセロ＋チャットBOT

## 結果
複数回呼び出す場合もあるような冗長なつくりにしたが、5秒ごとに1/10の確率で話すBOTと、
オセロ10クリック程度で制限を使い切ってしまった。
![log.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/528624/c524989a-6b04-f48f-7be1-3855eaba11d9.png)
やはり複数回呼び出しかねない構造のFunctionsはよろしくないようだ。
今回チャット部の発言時間を自動で記録する処理が特に呼び出し回数を消費してしまっているようだった。
sparkプランで運用するには呼び出し自体を減らすよう設計する必要がある。

## 終わりに
Firebaseには他にも制限があり、思いがけないところでコツが必要になってくる。
慣れるまでは大変だが、やはりこの速さでwebアプリを作れることは大きな魅力に違いない。
これからも皆様におかれましては素晴らしいFirebaseライフを。
00. 文字列の逆順

## 00.文字列の逆順
文字列"stressed"の文字を逆に（末尾から先頭に向かって）並べた文字列を得よ．


###Go
```go
package main

import_ "fmt"

func main() {
	var data string = "stressed"
	var reverse string

	// 1.ループ
	for i := len(data) - 1; i >= 0; i-- {
		reverse += string(data[i])
	}

	fmt.Println(reverse)
}
```


###python
```python

# -*- coding: utf-8 -*-
data = "stressed"
reverse = ""

#   1.逆カウントのループ
i = len(data) - 1
while i >= 0:
    reverse += data[i]
    i-=1
print(reverse)

#   2.range->reversed
reverse = ""
for i in reversed(range(len(data))):
    reverse += data[i]
print(reverse)

#   3.reversed->join
print(''.join(reversed(data)))

#   4.スライス
print(data[::-1])
```


###Javascript
```Javascript
var data = "stressed";
var reverse = ""

//  1.逆カウントのループ
for (var i = data.length - 1; i >= 0; i--) {
    reverse += data[i];
}
console.log(reverse);

//  2.split->reverse->join
console.debug(data.split("").reverse().join(""));
```

## まとめ
goは日本語非対応。
問題ページとトップページ分割。

[トップ](https://qiita.com/naoshin1984/items/3d7814e2f8eb01eea8dd)
さくらVPS CENTOS 7 文字化け対策 ロケール設定変更

#１　日本語のUTF-8に設定

```
[hoge@sakura ~]# localectl set-locale LANG=ja_JP.utf8
```

#２　再読み込みさせて設定を反映

```
[hoge@sakura ~]# source /etc/locale.conf
```

１だけでは日本語UTF-8にならない為、このコマンドで設定を有効にします。localectlは有効オプションがない為locale.confを再読み込みする事で反映させます。localectlで設定したロケールは、/etc/locale.confに反映されます。

#３　確認其の１　cat /etc/locale.conf

```
[hoge@sakura ~]# cat /etc/locale.conf
LANG=ja_JP.utf8
```

#４　確認其の２　localectl status

```
[hoge@sakura ~]# localectl status
   System Locale: LANG=ja_JP.utf8
       VC Keymap: jp106
      X11 Layout: jp
```

#５　確認其の３　locale

```
[hoge@sakura ~]# locale
LANG=ja_JP.utf8
LC_CTYPE="ja_JP.utf8"
LC_NUMERIC="ja_JP.utf8"
LC_TIME="ja_JP.utf8"
LC_COLLATE="ja_JP.utf8"
LC_MONETARY="ja_JP.utf8"
LC_MESSAGES="ja_JP.utf8"
LC_PAPER="ja_JP.utf8"
LC_NAME="ja_JP.utf8"
LC_ADDRESS="ja_JP.utf8"
LC_TELEPHONE="ja_JP.utf8"
LC_MEASUREMENT="ja_JP.utf8"
LC_IDENTIFICATION="ja_JP.utf8"
LC_ALL=
```
#６　確認其の４　最終確認として日本語出力の確認

```
[root@]# hoge
bash: hoge: コマンドが見つかりません
```

bash: hoge: command not found

Lastly,I had changed the error that I above & keywords Japanese from English including several files like log or txt's content within 2 min..That's it.
dockerコンテナ内のmysqlでダンプを取るとき

#### dockerコンテナ内に入る
`docker exec -ti コンテナ名 sh`

#### dockerコンテナ内のmysqlでダンプを取るとき
`mysqldump -uwordpress -ppassword -r ファイル名.sql --single-transaction wordpress --protocol tcp`
* 特に完了メッセージなどは出ない

#### Dockerコンテナのmysqlに生成されたファイルをローカルにコピー
`docker cp mysql:/ファイル名 .`
playframework2.6(java)Migration/requestHandler => actionCreator 

play2.4からplay2.6にMigration中

既存アプリケーションでは「[Java Http Request Handlers - 2.4.x](https://www.playframework.com/documentation/2.4.x/JavaHttpRequestHandlers)」の要領で、`play.http.HttpRequestHandler`の`createAction`をOverrideしてすべてのリクエストをフックして、リクエストのログ出力等を行っています。

`Play2.6`にMigrationしたところこの部分でコンパイルエラーが発生しました。

`HttpRequestHandler`から`createAction`がなくなって、Implements対象は`handlerForRequest`となっています。ところが、handlerForRequestのパラメタは以下の通り`Request`でなく`RequestHeader`となっていて必要な情報（例えばAjax/POSTリクエストのbody）が取得できません。

```
@Override
public HandlerForRequest handlerForRequest(RequestHeader header)
```

困惑していたら`createAction`は`play.http.ActionCreator`というクラスに定義が移動しているようで、これを`Implements`してみました。

変更点は、廃止されたPlay独自定義の`Promise`をJava標準の`CompletionStage`に置きかえるだけです。（logRequestやupdateMenuItemは独自定義メソッドです）

```java:play2.4/createAction
  @Override
  public Action createAction(Request request, Method method) {
    logRequest(request, method);
    try {
      return new Action.Simple() {
        @Override
        public Promise<Result> call(Http.Context context) throws Throwable {
          updateMenuItem(request, context);
          return delegate.call(context);
        }
      };
    } finally {
    }
  }
```

```java:play2.6/createAction
  @Override
  public Action createAction(Request request, Method method) {
    logRequest(request, method);
    try {
      return new Action.Simple() {
        @Override
        public CompletionStage<Result> call(Http.Context context) {
          updateMenuItem(request, context);
          return delegate.call(context);
        }
      };
    } finally {
    }
  }
```

これでOKかと思って、アプリケーションを実行したら以下のエラーが発生しました。

```
Cannot load play.http.requestHandler
play.http.requestHandler [class java.lang.Class}] does not implement interface 
play.api.http.HttpRequestHandler or interface play.http.HttpRequestHandler.
```

色々と調べてみたところ、`application.conf`で当該クラスを紐付ける対象を変更して解決。
これで既存と同じ動きを実現できました。

前）play.http.`requestHandler` = "com.nyango.xxx.xxx.xxx.httpRequestHadler"
後）play.http.`actionCreator`  = "com.nyango.xxx.xxx.xxx.httpRequestHadler"

公式のMigration手順にも記載されておらず、そこそこ時間を要しました。
参考になれば幸いです。
Node.jsのfsモジュールの使い方

#fsモジュールとは
fsモジュールはファイルを扱うためのモジュールで、ファイルから書き出したり、ファイルに書き込んだりするときに役立ちます。
Node.jsがはじめから提供しているモジュールなので、Node.jsのインストールがしてあれば、fsモジュールのインストールの必要はありません。

##ファイルの読み込み

```JS
const fs = require('fs');

//fs.readFileSync(ファイルのパス, 文字コード, コールバック関数)
fs.readFileSync('./text.txt', utf-8, (err, data) => {
//dataがファイルの中身、errは読み込み時のエラー
  if(data) {
    console.log(data);
  } else {
    console.log(err);
  }
});
```

##ファイルへの新規書き込み

```JS
const fs = require('fs');

//fs.writeFileSync(ファイルのパス, 書き込む文字, 文字コード, コールバック関数)
fs.writeFileSync('./text.txt', "こんにちは", utf-8, (err) => {
  if(err) {
    console.log(err);
  }
});
```

##ファイルへの追加書き込み

```JS
const fs = require('fs');

//fs.appendFileSync(ファイルのパス, 書き込む文字, 文字コード, コールバック関数)
fs.appendFileSync('./text.txt', "こんにちは", utf-8, (err) => {
  if(err) {
    console.log(err);
  }
});
```

##ファイルの削除

```JS:index.js
const fs = require('fs');

//fs.unlink(ファイルのパス, コールバック関数)
fs.unlink(process.argv[2], (err) => {
  if (err) {
    console.error(err);
  } else {
    console.log('削除が終わりました');
  }
});
```
process.arg[2]はコマンドの第三引数を指すので、以下のようにファイルをコマンドの第三引数に書き、ファイルの実行を行います。

```console:console
$ node index.js ./text.txt
```


##ファイルの作成

```JS
const fs = require('fs');

//fs.open(新規作成ファイルのパス, 書き込む文字, コールバック関数)
fs.open('./text.txt', 'こんにちは', (err) => {
  if(err) {
    console.log(err);
  } else {
    console.log('ファイルが作成されました');
  }
});
```

##ストリーム
当初、ストリームを使う理由が分からなかったのですが、ストリームだとデータを必要な分だけ受け取ることができるようになるため、メモリを多く使わずに済むそうです。

参考：[Node.js Stream を使いこなす](https://qiita.com/masakura/items/5683e8e3e655bfda6756)

```JS
const fs = require('fs')

//読み込みストリームを作成
const rs = fs.createReadStream('./text.html');
//dataイベントが発生したら(データを受け取ったら)、chunkに'./text.html'のデータが入ります。
rs.on('data', (chunk) => {
  res.write(chunk)
});
```
#####普通のファイル読み込みで同じ処理をしてみると、
readFileSyncだと、同期的な読み込みになるため、すごく読み込みが遅いです。
そのため、readFileで非同期的な読み込みをしています。

```JS
const fs = require('fs');

//fs.readFile(ファイルのパス, コールバック関数)
fs.readFile('./text.html', (err, data) => {
//dataがファイルの中身、errは読み込み時のエラー
  if(data) {
    res.write(data);
  } else {
    console.log(err);
  }
});
```
今回は、./text.htmlファイルも大きくなく、この程度のファイルならばスピードに大きな違いはありませんでした。
ですが、これが大規模な開発になると違いが出てくると思われます。
【SES】ドナドナされる時の面談時に地雷案件をなるべく避けるための確認ポイント7選(iOS/Androidアプリ開発)

私は、客先常駐でアプリを開発、保守するのをメインに5年ほどお仕事してきました。
iOSとAndroidのどちらかを担当して、機能やスケジュールの提案をしつつ、もくもくと開発していることが多いエンジニアです。

常駐のため、現場が変わるごとに面談があり（法律なんか知らん）、その度にやばそうな雰囲気の出てる案件は基本的に避けるようにしています。
現場に入る前の面談で、これを確認すれば、地雷案件を少し回避できるポイントがなんとなくわかってきたので、メモっておきます。
**※あくまで個人的な指標であって、なんの根拠もないです！！**

## 保守案件の場合は、アプリのストア評価を確認

保守案件で、ストアの評価が低いアプリは可能な限り参画を回避します。

理由は、

* ストアの評価が低いものは、内部の品質が基本的に低い
* 新たな開発はできずに、既存バグの修正に追われて疲弊する
* ただのバグ修正ではスキルがつきにくい
* クソコードを見ると発狂する（コントローラにAPIリクエストが入っているとか無理）
* ひどい場合、gitすら使ってない
* その他色々

だからです。
何より、**過去に低評価アプリを3つほど、保守・機能追加を担当して、すごく苦労したので**

## アプリのアーキテクチャーを確認

* 全てをControllerに実装するアーキテクチャ
* MVC
* MVVM
* VIPER
* CleanArchitecture
* など

色々とありますが、開発するアプリのアーキテクチャが決まっている場合があるので、確認します。

保守開発の案件で、既存のアーキテクチャを教えていただけることがあるのですが、
なぜか「CleanArchitecture」を使用してると言われるプロジェクトは、クラス名だけCleanArchitectureで、中身はぐちゃぐちゃの地雷が多いです。

経験上、「CleanArchitecture」と「全てをControllerに実装するアーキテクチャ」は避けたい対象となっています。


## 常駐先の会社さんにアプリ開発をできるプロパーさんがいるか確認

受託開発の新規作成案件で、アプリを開発できるエンジニアさんがいない会社が受けた場合、要件定義や見積もりでやらかしている可能性がかなり上がります。
※**Web画面を作る感覚でアプリの見積もりをしてしまった**案件の場合は、開発工数がそもそも足りていない場合が多くあるイメージです。

見積もりが多い分には、常駐する側としては問題ないのでが、やらかしている可能性が高い案件の場合が多いので、なるべく避けるのがおすすめです。

## 開発者を複数人募集している案件は、他のメンバーのスキルを確認

最近の案件は、1アプリを2~3人くらいで新規開発をする案件がそこそこあるイメージです。
ただし、複数人開発と言えど、

* 新人さん(2年未満)
* アプリを一人で作ったことのない人

が相方として参画しそうな場合は、申し訳ないですが確実に避けるようにしています。
（他の人の面倒を見るのは避けたい。ただし、面倒を見る費用をもらえる場合は別途相談）

また、開発規模の割に人数が多い案件の場合は、
**スキルの低い人間を集めて、クライアントへの見積もりをカサ増ししている案件が多いです。**
(できる人が1人で2ヶ月できるのを、4人で半年とか）
結局、できる人間が全て作るハメになるので、避けるようにしています。

## SIer系は避ける

会社さんによりますが、古いルールとかに縛られていることがあるので、近づかないほうがいいイメージ。
特にスーツ必須のところは、ちょっと怖い。
※うちは、違うぜ！だ感じの会社さんはごめんなさい。経験上は、どうしても多いのです。

## フロアのエンジニアの残業状況を確認

面談の際に常駐先のエンジニアの残業状態を確認します。
残業をしている人が多い場合は、だらだら仕事する癖がついている or 仕事量がおかしい 現場の可能性が高いので、なるべく避けます。

質問は、自分から質問すると残業を避けたがるエンジニアのイメージがつく気がするので、営業から質問してもらえるようにお願いするのがベストです。

## スクラム開発の場合に、スクラムの前提を満たしているか確認

最近流行っているスクラム開発を取り入れている案件がそこそこ出てきました。
ただし、スクラムをやる上で、前提条件を満たしていない案件が多いので注意が必要です。

* 全機能ができる納期がある？？？？
* スキルがバラバラすぎる
* クライアントがスクラム開発に乗り気ではない（POさんがいないとか）
* スクラムを銀の弾丸と思っている人がいる（スクラムだから開発に成功するとか）

（前提条件を満たしていない時点で、スクラムではないと思いますが。。。）

また、これは個人的な都合ですが、以下の点でスクラム開発はちょっとやりにくいところがあります。

* 作業見積もりをごまかしにくい
* 最初に一気に開発して、開発期間の最後の方でゆっくりすることがしにくい（開発期間の余ったところでだらだらするのが趣味のため）
* 全員バラバラの所属で、ガッチリとしたチームプレーはちょっとめんどい

色々、ネガティブなことを書いてますが、**うまくはまっているスクラム開発は色々と新しいことができて楽しいのでおすすめです！！**

## 開発環境の確認

* Mac/PCの簡単なスペック（メモリ8GBじゃ辛い）
* iPhoneなどの実機の有無

などを念の為確認すると、あとで開発中にイライラするのを防げるかもしれないです。


## まとめ

色々書きましたが、結局は現場に参画してみないとわかりません。
**iOSアプリを開発すると聞いていて、Androidアプリを開発することはよくあるので。。。<br>スキルが複数ある場合は、しれっと他の案件にすり替わってることがあるので、回避不可能です。**

わざわざ、大変だったり辛い現場に行くのは勿体無いので、
お金をもらえながら、楽しくてスキルのつける現場になるべく行けるように、これからも頑張って面談していく予定です。
１０



勉強した当日よりも、
よく寝た翌日の方が頭に入ってくるなと実感！

rubyについてはできるまで、慣れるまで
手を動かそうと思い、とにかく
実践しながら身につけていこうと思います！

HTML・CSSは、親子の関係、
骨組みがどうなっているのか、
検証を使いながら身につけていく。

レイルズのバグ問題は、
現状と理想の状態を考える。
そうなるためには、と逆算して解いていく！！

練習あるのみ
頑張ります
ファイルをセーブしたら、bashコマンドを走らせる」というライブラリを１行で作る。

## 「ファイルをセーブしたら、npmスクリプトを走らせる」というライブラリがある日突然欲しくなりました。

[onchange](https://github.com/Qard/onchange)というライブラリが見つかりました。npmライブラリです。

使い方は簡単で、onchangeをグローバルにインストールした後、grobパターンで、監視するファイルとnpmスクリプトを記述するだけです。

```
npm install -g onchange
onchange 'app/**/*.js' 'test/**/*.js' -- npm test
```

しかしです...

**globパターンを記述するのが地味に面倒い！**
ルートフォルダ以下で変更があれば、npmスクリプトを走らせるだけでいいのに...

## そこでよりシンプルなライブラリを自作することにしました

作ったのが「save-run」というライブラリ。

名前は、save-runとして、npmに登録してあります。
[save-run](https://github.com/t-kabaya/save-run)

使い方は簡単で、npxを使用するまたはグローバルにインストールしてからrun-saveコマンドの後にnpmスクリプトを渡すだけ。

```
npx save-run npm test
または
npm install -g save-run
save-run npm test
```

幸せになれました〜〜〜

私は、react-nativeエンジニアなのですが、

```
save-run npm start
save-run python main.py
```
などに使っています。

## 実はこのライブラリは１行で実装されているので、興味のある方は読んでみてください。

```js
#!/usr/bin/env node

const { watch } = require('chokidar')
const { execSync } = require('child_process')

watch('.').on('change', () => execSync(process.argv.slice(2).join(' '), { stdio: 'inherit' }))
```

完！
Pythonのリストにおけるappendと+=の違い

PythonでCSVを扱っていてドハマりしたのでメモ。

## リストの結合操作

成績表のCSVを標準ライブラリで読み込んで、次のようなリストができているとする。
2人分の成績表。それぞれ数学と英語の点数が記録されている。

```python
paper1 = [
    ["Math", "90"],
    ["English", "75"]
]
paper2 = [
    ["Math", "38"],
    ["English", "100"]
]
```

このとき、成績表の束を管理するリストを作るには append と += のどちらを使えばよいだろうか？

## まずは+=

とりあえずREPLで見てみる。

```python
>>> papers = []
>>> papers += paper1
>>> papers += paper2
>>> papers
[['Math', '90'], ['English', '75'], ['Math', '38'], ['English', '100']]
```

おおっと？マージされてしまったぞ？これは期待した結果ではない。

## お次はappend

こちらもREPLで。

```python
papers = []
>>> papers.append(paper1)
>>> papers.append(paper2)
>>> papers
[[['Math', '90'], ['English', '75']], [['Math', '38'], ['English', '100']]]
```

2枚の成績表が分かれて入りました。期待してた結果はこっちですね。

## タネあかし

結論としては、+ や += 演算子は extend() メソッドを呼び出していました。
入れる先のリストを拡張していたんですね。リストの場合は結合されます。

一方、append() メソッドは、入れるオブジェクトがリストであっても結合せずに追加します。

参考文献
https://note.nkmk.me/python-list-append-extend-insert/
インストールディスクからCentOS8インストール

CentOS8インストール用ディスク作成
(https://qiita.com/kerry/items/b68be3b0e5d444615255)
後、継続してインストールディスクからCentOS8インストールすることに。

## インストールに必要なもの
・サーバー用のパソコン
・CentOS8のインストールディスク（link）
・USBキーボード
・USBマウス
・LANケーブル
・ルータ

## BIOSの設定
注意：
ディスクを入れる前にパソコンのBIOSと言われる初期設定から最初の軌道に使用する領域を変更しておく必要がある。

設定：
F2キーを押しながらサーバー用のパソコンを起動し、BIOS詳細タブの軌道デバイスの優先順位からCD/DVDドライブを選択する。

設定保存：
F10キーで設定を保存してから終了。

## CentOS8をインストール
CentOS8のインストールディスクをサーバー用のパソコンにセットし、パソコンを起動する。
![スクリーンショット 2019-11-27 11.18.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274686/eb5993e5-ef0f-f121-4afa-01cd51e43d0d.png)
三つの項目がありますが一番上の「Install CentOS Linux 8.0.1905」という項目を選択すると、下記のようにインストールが開始する。
![スクリーンショット 2019-11-27 11.19.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274686/fff249c4-57bb-d636-feb3-2dea895f2ad9.png)

インストール画面で使用する言語の選択後、「続行」ボタンを押してインストールを継続する。
![スクリーンショット 2019-11-27 11.20.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274686/4c928fd4-f944-d608-f074-3246ee649bdf.png)

## インストール概要
インストール言語の選択が終了すると、CentOS 8のインストールに必要なタスクを集めた「インストール概要」が表示される。
少なくとも黄色いアイコンが付いた項目の設定を済ませるまでインストールは開始できません。
![スクリーンショット 2019-11-27 11.20.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274686/9de5270c-cc98-62da-820b-6ff041305c21.png)

下記の項目以外は変更必要無し。
### 日付と時間の設定
アジア/東京を選択

### ソフトウェアの選択
今回の勉強の為に「最小限のインストール」を選択し、CUIでの開発にする。
GNOME（グノーム）というのを選択するとデスクトップが生成されGUIでの構築もできるが、バグで構築ができな時があるので良くない。

### インストール先の選択
「インストール先」をクリックすると、CentOSのインストールを行うことができるディスクが表示される。

空き容量が足りないとエラーが発生した。
![スクリーンショット 2019-11-27 11.21.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274686/6f4e490d-3c7a-e65b-3407-8bbb0c1b10dd.png)

「再利用」ボタンを押して既存を削除してエラーを解消した。

## CentOS 8 インストール
ここまででCentOSのインストールに必要な設定が全て完了しました。
右下に「インストールの開始」が青色になり、クリックできるようになっていれば、CentOSのインストールを行うことができる。
「インストールの開始」をクリックし、インストールを始めます。

### rootパスワードの設定
インストール中に幾つかの設定を行う必要があるが、先ずはシステムの管理者であるrootユーザーのパスワードを設定する。
![スクリーンショット 2019-11-27 11.21.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274686/a8e94e39-4170-d2ce-5b2e-7bf2528a776f.png)

画面下に「完了しました！」と表示されれば、CentOSのインストールは完了です。
![スクリーンショット 2019-11-27 11.24.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274686/096974b5-0a43-73e5-56ed-b7299e64a32d.png)

### 再起動
CentOS8のインストールディスクを外してから、「再起動」をクリックし、再起動を行う。
再起動中の画面は以下になります。
![スクリーンショット 2019-11-27 11.25.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274686/7ff856cf-5834-c74b-6bdd-a64aa822b1ca.png)

### ログイン
インストール中に設定したrootユーザーのパスワードでログインできる。

### 参考サイト
[http://souma-ism.xyz/archives/90
[AWK] 最大値・最小値のグループ集計

# やりたいこと
例えば下記のようなデータがあった時に、1列目をグループとして、2列目の最小値と3列目の最大値を抽出します。

```sh:もともとのデータ
cat input.txt
hoge 10 10
hoge 20 30
hoge 30 20
fuga 1 5
fuga 10 10
```

```sh:集計後
cat output.txt
hoge 10 30
fuga 1 10
```

#AWKのコード

```sh
# input.txtの生成
cat << EOF > input.txt
hoge 10 10
hoge 20 30
hoge 30 20
fuga 1 5
fuga 10 10
EOF

# 集計コード
cat input.txt |
awk '{if(min[$1] == "") min[$1]="inf"
if(min[$1]>$2) min[$1]=$2
if(max[$1]<$3) max[$1]=$3}
END{for(key in min) print key, min[key], max[key]}' \
> output.txt
```
# 工夫したところ
最小値を求めるときにはawkがとり得る最大値`inf`を代入します。
そのために`if(min[$1]) == 0`で`min[$1]`で、min[$1]の空配列の生成を行っています。
[PHP] 親の親のコンストラクタを呼び出す方法

PHPのコンストラクタ、```__construct()```。親クラスのコンストラクタを呼び出すときは```parent::__construct()```で呼び出せます。では、親の親というか、祖父母というか、2等身以上離れたクラスのコンストラクタを呼び出すにはどうするのでしょう？親クラスのコンストラクタを実行せず、2等身先のコンストラクタを呼び出したい場合です。

# 対象のクラス名::__construct()

↑のとおりです。感覚的にstaticな呼び出しと同じ書き方なので、プロパティの設定が意図通り動作するのか不安になりますが、大丈夫なようです。

確認したバージョンは7.1.5とか7.3系。5.6系でもいけそう…？

コード例はこちら。```C1 -> C21 -> C321```という流れで継承しています。

```PHP
<?php
class C1
{
    // 動作確認用のプロパティ。各コンストラクタで値を設定。
    protected $prop;
    function __construct()
    {
        // C1のコンストラクタを実行した証としてC1を設定
        $this->prop = "C1";
    }
    // 動作確認用の出力関数
    function echo()
    {
        echo $this->prop . PHP_EOL;
    }
}

// C1を親に持つクラス
class C21 extends C1
{
    function __construct()
    {
        // C21のコンストラクタを実行した証としてC21を設定
        $this->prop = "C21";
    }
}

// C1を祖父母、C21を親に持つクラス
class C321 extends C21
{
    function __construct()
    {
        // C321のコンストラクタを実行した証としてC321を設定
        $this->prop = "C321";
        $this->echo(); // -> C321

        // C321の親 = C21のコンストラクタ。prop上書き。
        parent::__construct();
        $this->echo(); // -> C21

        // C1のコンストラクタ。prop上書き。
        C1::__construct();
        $this->echo(); // -> C1

        // parentではなくC21と直接指定も可能。prop上書き。
        C21::__construct();
        $this->echo(); // -> C21
    }
}

// C321のコンストラクタを実行
new C321();
```

# 余談　系譜にいない先祖クラスのコンストラクタを呼び出したら？

当たり前ですがエラーになります。```cannot be called statically```。コード例はこちら。

```PHP
// C1を親に持つ。C21は系譜に含まれない。C1は前のコード例参照
class C41 extends C1
{
    function __construct()
    {
        // C41のコンストラクタを実行した証としてC41を設定
        $this->prop = "C41";
        $this->echo(); // -> C41

        // C41の親 = C1のコンストラクタ。prop上書き。
        parent::__construct();
        $this->echo(); // -> C1

        // C1のコンストラクタ。prop上書き。
        C1::__construct();
        $this->echo(); // -> C1

        // C21のコンストラクタ。親にいないからエラー
        C21::__construct(); // error
        $this->echo(); // ↑でエラーなので実行されない
    }
}

// C41のコンストラクタを実行
new C41();
```

# おわりに

そもそも親の親のコンストラクタを直接呼び出すべきでない、呼ぶのは親クラスのコンストラクタだけで、その中で祖父母コンストラクタを呼びだすべき…なんですが、横着したいときにでも知ってると便利かも？
Golang - Incorrect CPU Numbers of GOMAXPROCS in Docker

The runtime.GOMAXPROCS(??) will read the host machine's CPU numbers instead of container's (--cpus=??). We can use UBER's ***automaxprocs*** to solve it.

```
go get -u go.uber.org/automaxprocs
```

```golang
import _ "go.uber.org/automaxprocs"

func main() {
  // Your application logic here.
}
```

https://github.com/uber-go/automaxprocs

https://mp.weixin.qq.com/s/Lk1EbiT7WprVOyX_dXYMyg

http://vearne.cc/archives/39195

https://colobu.com/2017/10/11/interesting-things-about-GOMAXPROCS/

http://www.ojit.com/article/204492
CORS許可されているかをcURLで確認する方法

いっつも忘れてしまうので備忘録として。

``` bash
curl -H "Origin: #{アクセス元のドメイン}" \
     -H "Access-Control-Request-Method: #{メソッド}" \
     -X OPTIONS --verbose \
        #{アクセス先のURL}
```

### 使用例
``` bash
curl -H "Origin: localhost:3000" \
     -H "Access-Control-Request-Method: GET" \
     -X OPTIONS --verbose \
        https://qiita.com/api/v2/items

```
Re: 10秒で衝突するUUIDの作り方

元ネタは下記リンクを参照。
「UUID生成はライブラリを使え　自分で書くな」との結論は全く同意。

10秒で衝突するUUIDの作り方 - Speaker Deck
https://speakerdeck.com/tanakahisateru/10miao-dechong-tu-suruuuidfalsezuo-rifang


# セキュアコーディング

　元ネタ前半の実装のように、アプリケーション開発者が乱数シードを指定して乱数を生成するような実装だと、第三者がシードの値を推測して「次に生成されるUUIDを予測する」ことができるかもしれない。(下記リンクはJavaにおける類例の解説である。)

MSC02-J. 高品質の乱数を生成する
https://www.jpcert.or.jp/java-rules/msc02-j.html

また、生成される可能性のあるUUIDの種類が少ない場合、第三者が総当たりで「どれでもいいので既存のUUIDのどれかに衝突させる」ことができるかもしれない。

　例えばセッションIDを第三者が上述のような方法で推測または意図的に衝突させると、セッションハイジャック攻撃が可能になる場合がある。セッションIDは推測困難な方法で生成するべきである。

OWASP CheatSheet - Session ID Generation and Verification: Permissive and Strict Session Management
https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html#session-id-generation-and-verification-permissive-and-strict-session-management

> The session tokens should be handled by the web server if possible or generated via a cryptographically secure random number generator.

　では、どんな乱数生成はセキュアな必要があり、どんな乱数生成はセキュアでなくてよいか？　「生成された乱数を他人が知った場合、何にアクセスしてどのような操作ができるようになるか」によって決まる。　個人情報を含むWebアプリケーションのセッションID生成はセキュアな必要がある。Windowsアプリのソリティアで初期配置を決める乱数の生成はセキュアでなくてもよいように思う。

# 暗号学的に安全な実装の例

いずれも PHP7

## hex

php - Generating cryptographically secure tokens - Stack Overflow
https://stackoverflow.com/questions/18830839/generating-cryptographically-secure-tokens

> $token = bin2hex(random_bytes(16));


## 英数

PHP random string generator - Stack Overflow
https://stackoverflow.com/questions/4356289/php-random-string-generator/31107425#31107425


## 英数記号

上記リンクの英数ランダム文字列生成を改変、高速化


```php
<?php


function random_str(
    int $length = 20
): string {
    if ($length < 1) {
        throw new \BadMethodCallException('Length must be a positive integer');
    }
    // $keyspace length should be (1<<6) = 64
    $keyspace = '-_0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
    
    $randomStr = [];
    while (true) {
	    $randomInt = random_int(0, 1 << (10 * 6));
	    for ($i = 10; $i > 0 ; $i--) {
	        $randomStr []= $keyspace[$randomInt % 64];
	        if (count($randomStr) >= $length) {
	        	break 2;
	        }
	        $randomInt = intdiv($randomInt, 64);
	    }
    }
    return implode('', $randomStr);
}

```

Hope this helps.
MSYS2でscreenのビルド&インストール

MSYS2環境にはscreenのパッケージは用意されていないので自分でビルドしてインストールしないと使えない。分かってしまえばさほど大変じゃない。

# 前提
 - MSYS2がインストールされている
 - gccコマンドが利用できる (`pacman -S gcc`で入るはず)
 - makeコマンドが利用できる (`pacman -S make`で入るはず)

筆者の環境にはWindows用の別のmakeコマンドが入っていて、それが原因でmakeが失敗した。なんかおかしいと思ったらShellから正しいコマンドが実行されているか確認すると良いと思う。

# 必要ライブラリのインストール
筆者の環境だと以下のライブラリをインストールする必要があった。

```
$ pacman -S ncurses-devel
$ pacman -S libcrypt-devel
```

# ソースの取得と展開
```
$ wget https://ftp.gnu.org/gnu/screen/screen-4.7.0.tar.gz
$ tar xzvf screen-4.7.0.tar.gz
$ cd screen-4.7.0
```

# ソースの修正
http://proglab.blog.fc2.com/blog-entry-35.html とかにも書いてあるが、フォルダのパーミッションチェックのコードがMSYS2環境だとうまく動かないのでその部分をコメントアウトする。`screen.c`ファイルを以下のように修正。（多分バージョンによって行数は変わるので同じ部分を探す）

```screen.c
  1109         n = (eff_uid == 0 && (real_uid || (st.st_mode & 0775) != 0775)) ? 0755 :
  1110             (eff_gid == (int)st.st_gid && eff_gid != real_gid) ? 0775 : 0777;
  1111         /* コメントアウト
  1112         if (((int)st.st_mode & 0777) != n)
  1113           Panic(0, "Directory '%s' must have mode %03o.", SockDir, n);
  1114           */
  1115       }
  1116       sprintf(SockPath, "%s/S-%s", SockDir, LoginName);
...

  1147   }
  1148
  1149   /* コメントアウト
  1150   if ((st.st_mode & 0777) != 0700)
  1151     Panic(0, "Directory %s must have mode 700.", SockPath);
  1152     */
  1153   if (SockMatch && index(SockMatch, '/'))
  1154     Panic(0, "Bad session name '%s'", SockMatch);
```

# configure & make & make install


```
$ ./configure --enable-colors256
$ make
$ make install
```
# 起動
```
$ screen
```
で起動すればOK
Android Chrome/78.0.3904.108 にて起こっているpreload問題とその暫定的対応

## 何が起こっているのか

- [AndroidのChrome 78のPreload問題](https://qiita.com/m_kumamomi/items/3b01bf0336d30f84f4b5)

内容は上記の記事を見てもらうとすごくわかりやすくまとめてくれています。（同僚さんの記事です）
おそらく、ページ内の行動履歴？に関係する関連の高いaタグのhrefの中身を「自動で」preloadしてしまっているという問題

## で、フロントとしてどうしたのか
まず、被害の大きい箇所、ページを調べて

```
a href="/hogehoge/bar"
```
を

```
span data-href="/hogehoge/bar"
```
という風に書き換えた上で、あとはJS側でdata-hrefの中身をclickでlocation.hrefに入れて飛ばす方法で暫定対応。
それか

```
a data-href="/hogehoge/bar"
```
という風にして、load時にdata-hrefの中身を抜き取ってhrefに入れるとかでも行けそうな。

## 雑感
ひとまず、被害の大きい箇所だけの暫定対応とはいえ、まだ対応ページがそこまでではなかったのでできる技かなと。
これでも完璧ではないので、追っかけ対応になることもありえる。
サイト規模の大きいところはその限りではないだろうから大変かと思います。

早くchrome側のアップデートなりで修正されることを望むばかり
【Mac】Gitコマンドが使えるまでの準備


##Gitインストール方法
下記のどちらかの方法でインストール可能。
・公式サイトからダウンロード→インストール
・homebrewを使用してインストール



##公式サイトからダウンロード→インストール
①[公式サイト](https://git-scm.com/downloads)よりダウンロードをクリック。

②インストーラを実行。

③以下のコマンドで、インストールを確認。※バージョンが表示されればOK

```shell-session
$ git --version
```



##homebrewを使用してインストール
①インストール

```shell-session
$ brew install git
```

②（必要に応じて）Gitアップデート

```shell-session
$ brew upgrade git
```
データベース検索（インデックス有無による処理速度の検証）

# 目的 
- インデックス有無が処理速度にどれだけ差を生むのか検証したい
- その過程で、B木についても少し理解したい

# 対象読者
- データベースについて学んでいる方
- CSについて学び始めた学生

# 始める上での準備と環境
- 今回使用した環境はGoogleが提供する[Colaboratory](https://colab.research.google.com/notebooks/welcome.ipynb?hl=ja)
- 使用言語はpython
- 使用するデータは予めcsv等にまとめておく
- 使用データは1147620行のデータ

# コードについて
- [僕のgithub](https://github.com/Retsuki/indexValidation/blob/master/index.py)
- コード内容は僕が使用したデータに合わせてあるので、都度書き直して、、、

# 検証結果
#### 範囲が10000~10100を検索
- インデックスなし : 0.290917145000094
- インデックスあり : 4.710936333000063

#### 範囲が10000~10010を検索
- インデックスなし : 10.85402692900015
- インデックスあり : 0.285733380000237

#### 範囲が10000~10001を検索
- インデックスなし : 68.63662464900017
- インデックスあり : 0.263980986000206

# 検証結果より
インデックスの有無で探索処理時間にこれだけの差が生まれることが証明された。


B木のアルゴリズムやらビットマップやらが用されているらしいが、
細かいことについては

[データベース性能を向上させる「インデックス」を理解する](https://www.atmarkit.co.jp/ait/articles/1703/01/news199.html)

が非常に丁寧に書かれているのでおすすめだ。

以上。。。。。。。
GitHubが勝手にSecurity Alertsのプルリクを作ってきた

リポジトリの設定次第だと思いますが、ある日突然GitHubのbotがプルリクを作ってくるようになりました。
主に`package_lock.json`の依存パッケージのバージョンをセキュリティのために更新しているようでした。

設定をオフにするには`Security`タブの`Automated security updates`のチェックを外せばよいです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18273/d6f50d16-aad1-c8b6-208f-da6b7ed5fbc6.png)

今回はCI連携していてデプロイが走りまくってしまったので、一旦オフにしました。
テストしっかりかけてるプロジェクトだとこのプルリクをそのままマージしたりしてもいいんだろうか。
パッケージが依存しているパッケージのバージョンとかもちゃんとやってくれてるのかな :thinking: 
便利そうだけどまだちょっと使うのは怖かったです。
catalinaにしたらラズパイやjetson nanoのイメージを焼けなかったのでメモ

# CatalinaにアップデートしてからEtcherが機能しなかったのでメモ

久々にJetsonNanoのイメージをEtcherでコピーしようとしたらよくわからないエラーを吐くようになった。

<img width="355" alt="etcher.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/441037/8354ec5b-f124-0974-bdd9-e41019eb1d03.png">

調べるとCatalinaにアップデートするとうまく動かないようだ。

この時のバージョンは
macOS Catalina 10.15
balenaEtcher == 1.5.33

ターミナルで以下のコマンドで起動する必要がある

```terminal
sudo /Applications/balenaEtcher.app/Contents/MacOS/balenaEtcher
```

コマンドで起動しても同じエラーが起きた。

Etcherのバージョンが最新ではなかったので、バージョンを上げた。
アップデート方法がわからなかったので、今のアプリを消去して、新たに[公式](https://www.balena.io/etcher/)から最新バージョンをダウンロードした。

最新バージョン（投稿日でのバージョンは1.5.63）で同じコマンドで起動したら、エラーは起きずにイメージを焼くことができた。
遠隔で接続しているサーバ情報を確認する方法

#`uname`コマンドを使用して情報を確認する
みなさんは、遠隔で接続しているものをコマンドラインで操作していると、普段使っているコマンドがなぜか使えないことがあることはありませんか？
私は、いろいろなサーバに接続することがあるので、今自分が使っているサーバやノードがなんのOSを使っているかなどが分からなくなってしまうことがあります。
そこで利用するのが`uname`です。`uname`と入力すると接続しているもののOSが分かります。（ちなみに、当然のことですが、普通に自分のパソコンの情報を調べるのにも利用できます。)

##オプション
- `-m`,`--machine`:マシンのタイプを表示する。
- `-n`,`--nodname`:マシンのネットワークノードのホスト名を表示する
- `-r`,`--release`:OSのリリースを表示する。
- `-s`,`--sysname`:OSの名称を表示する。
- `-v`:OSのバージョンを表示する。
- `-a`,`--all`:以上の情報をすべて表示する。
- `--help`:標準出力に使用方法のメッセージを出力ｓひて正常終了する。
- `--version`:標準出力に「uname」コマンドのバージョン情報を出力して正常終了する。

#その他の方法
##`/proc`配下のファイルから調べる(linuxの場合）

- /proc/[number]/cmdline:プロセスの完全なコマンド行。
- /proc/[number]/environ:プロセスの環境変数
- /proc/[number]/maps:現在マップされているメモリ領域とそのアクセスパーミッション
- /proc/[number]/stat:プロセスの状態についての情報。ps コマンドが使用する。
- /proc/pci:すべての PCI デバイスのリストとその設定。
- /proc/scsi/scsi:カーネルが知っているすべての SCSI デバイスのリスト。
- /proc/interrupts:IRQ ごとの割り込み回数の記録に使われる。
- /proc/ioports:現在登録され使われている I/O ポート領域のリスト。
- /proc/meminfo:システムの未使用および使用中のメモリ量 (物理メモリとスワップ) と、カーネルに使われている共有メモリとバッファの情報。
- /proc/swaps:使用中のスワップ領域。
- /proc/cpuinfo:各 CPU についての情報。
- /proc/version:現在稼働しているカーネルのバージョン

##`sysctl`コマンドで調べる
このことについて自分はあまり理解したいないので下記のサイトを参照してください。
[Mac OS Xには/procが無いのでsysctl使う](http://shin.hateblo.jp/entry/2014/05/25/154014)

なにかいい情報があれば教えて下さい！
A-FRAME: 物理演算でボーリングっぽい動きを実現してみる６（ピンの形状）

A-Frameをつかって物理演算ができるようにしてみます。
ピンに物理的な形状を設定してみて、振る舞いの違いをみてみます。

ピンは細長いひょうたん型で、プリミティブにはそのような形状はありません。
cylinderがふさわしいような気がしますが、自動的に割り当てた場合にどのような形状が割当たるのでしょうか。

### 例１）shape=auto
autoは使用可能な形状から自動的に選択されます。
![shape1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/423506/f492e8eb-d4cb-6876-ee41-0fce9af966df.gif)[demo](https://k38.github.io/aframe/physics-system/pin_shape_auto.html)
boxが選択されたようです。

### 例２）shape=primitive
primitiveは平面/円柱/球の内、対応するAフレームプリミティブが自動的に使用されます。
![shape2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/423506/5c4d17d4-9d58-c283-130e-f8b78ad6a6a9.gif)[demo](https://k38.github.io/aframe/physics-system/pin_shape_primitive.html)
boxが選択されたようです。
説明にはboxは候補として書かれていないですが、置いておきましょう。

### 例３）shape=box
boxを設定します。
![shape3.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/423506/31696eeb-41a9-2b83-c5cd-a1473ad041eb.gif)[demo](https://k38.github.io/aframe/physics-system/pin_shape_box.html)
ピンの形状にマッチしたboxが設定されました。

### 例４）shape=hull
hullはシュリンクラップのようなモデルをラップします。
hullという単語には殻や外皮といった意味があります。
![shape4.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/423506/87847dee-5ec2-5391-19ec-a05658cc1e4b.gif)[demo](https://k38.github.io/aframe/physics-system/pin_shape_hull.html)
レーンをすり抜けていきました。
ボールにhullを設定した時はレーンを転がっていったので、思っていたのと違う感じがします。

### 例５）shape=mesh
meshはJS物理エンジンでモデル化するのが難しく、特定の他のシェイプを「フォールスルー」し、パフォーマンスに重大な制限があります。
![shape5.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/423506/3f557d84-3617-e64d-7bf6-9d92e33c3f91.gif)[demo](https://k38.github.io/aframe/physics-system/pin_shape_mesh.html)
hullと同じように、レーンすり抜けていきました。
ボールにmeshを設定した時もレーンをすり抜けたので、この振る舞いはボールと同じように感じます。

### 例６）shape=none
noneは衝突ジオメトリを追加しません。
![shape6.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/423506/27771890-d54a-08ab-f395-46641334a3b0.gif)[demo](https://k38.github.io/aframe/physics-system/pin_shape_none.html)
ボールにnoneを設定した時と同様、レーンをすり抜けていきました。

### 例７）shape=sphere
sphereを設定します。
![shape7.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/423506/42724334-4522-4f8c-8f3b-517061879181.gif)[demo](https://k38.github.io/aframe/physics-system/pin_shape_sphere.html)
ピンは球体とは異なるので、違和感が大きいです。
あと、sphereの中心とピンの中心がずれているように見えます。
boxの場合はboxの中心とピンの中心は一致していました。

### 例８）shape=cylinder
最後にもっとも有力に思っていたcylinderを設定します。
![shape8.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/423506/163e1748-3952-c812-549c-5387dafc64b6.gif)[demo](https://k38.github.io/aframe/physics-system/pin_shape_cylinder.html)
cylinderもsphereと同様に、sphereの中心とピンの中心が一致していません。

## まとめ
ピンの物理的な形状は、自動で設定するとboxが選択されてcylinderにはなりませんでした。
そして、今回設定した形状はどれもしっくりきませんでした。

今回みえた課題としては、
- sphereとcylinderを設定した時に、ピンと物理的な形状の中心が一致しない原因が何か
- 複合シェイプを利用する事で、中心の不一致に対応する事もできそう(noneの本来の使い方っぽい)
- hullを設定した時の振る舞いがボールとピンで異なる

があるので、次以降で見ていきます。
メモ: MySQL 4.0 と 4.1 の違いについて

## ベンチマークテストの結果

MySQL 4.0 : CentOS 8 で ベンチマークテストが失敗する(ATISなど)。
    そのため 4.0を使えるのはCentOS 7まで。
MySQL 4.1 : CentOS 8 で ベンチマークテストは9つ全て成功する。

## 4.0から4.1に上げる前の動作確認

```go:/etc/my.cnf
[mysqld-4.0]
new
```

newオプションをつけると、4.1モードの動作確認ができる。

## 注意する点

* TIMESTAMP 型の変更
    * `YYYY-MM-DD HH:MM:SS` 形式になった。

* パスワードの保存形式が変わった [MySQL4.0系→MySQL5.0系 | feedforce Engineers' blog](http://tech.feedforce.jp/mysql_40_to_50.html)

```go:/etc/my.cnf
[mysqld-5.0]
old-passwords
```

varcharも長さが変わったので注意。
4.0→5.0 : varchar(100)→varchar(33)


## その他

* [MySQL :: MySQL 4.1 リファレンスマニュアル :: 2.5.1 バージョン 4.0 から 4.1 へのアップグレード](http://download.nust.na/pub6/mysql/doc/refman/4.1/ja/upgrading-from-4-0.html)

* [MySQLをアップデートする話 - Hatena Developer Blog](https://developer.hatenastaff.com/entry/2019/01/15/120431)
    * 各バージョンの変更履歴が詳しく書いてある
GitLab CIでDokkuに自動deployする

運用で[Dokku](http://dokku.viewdocs.io/dokku/)を使っているのですが、GitLab-CIでdeployの自動化ができないか悩んでいました。ググるとやり方はもちろんあるのですが、ssh-keyの転送とか面倒くさいなーと思っていたらなかなか手がつけられていませんでした。

調べたらそのあたりをDocker Image化したものがあったので使ってみると簡単に実現できたのでメモしておきます。

# 設定方法

## GitLab設定->CI/CD

- Variables
キー：SSH_PRIVATE_KEY
　値：←Deploy用のPrivateKeyをコピペ

- Runner
「共有Runnerを有効化」
 or Runnerを指定

## CIコード

```..gitlab-ci.yml
stages:
  - deploy

variables:
  APP_NAME: demo

# https://github.com/IlyaSemenov/gitlab-ci-git-push
# set $SSH_PRIVATE_KEY to GitLab

deploy-prod:
  image: ilyasemenov/gitlab-ci-git-push
  stage: deploy
  environment:
    name: production
    url: http://$APP_NAME.dokku.me/
  only:
    - master
  script:
    - git-push ssh://dokku@dokku.me:22/$APP_NAME
```

※APP_NAMEとdokku.meは実際に使うものに変更が必要です。

# developブランチをテストリリースする方法

以下のように、dokkuでdeploy-branchを設定します。

```dokku git:set myapp deploy-branch develop```

参考：
http://dokku.viewdocs.io/dokku/deployment/methods/git/#changing-the-deploy-branch

## CIコード

```..gitlab-ci.yml
stages:
  - deploy

variables:
  APP_NAME: demo
  APP_NAME_DEV: demo-dev

# https://github.com/IlyaSemenov/gitlab-ci-git-push
# set $SSH_PRIVATE_KEY to GitLab

deploy-staging:
  image: ilyasemenov/gitlab-ci-git-push
  stage: deploy
  environment:
    name: production
    url: http://$APP_NAME_DEV.dokku.me/
  only:
    - develop
  script:
    - git-push ssh://dokku@dokku.me:22/$APP_NAME_DEV

deploy-prod:
  image: ilyasemenov/gitlab-ci-git-push
  stage: deploy
  environment:
    name: production
    url: http://$APP_NAME.dokku.me/
  only:
    - master
  script:
    - git-push ssh://dokku@dokku.me:22/$APP_NAME
```

※APP_NAME, APP_NAME_DEVとdokku.meは実際に使うものに変更が必要です。

# メモ

Dokku以外にもHerokuやDeis等、Gitレポジトリーでデプロイするような物に共通で使えるようです。

https://github.com/IlyaSemenov/gitlab-ci-git-push

やっている事はPrivate Keyの転送とかググれば出てくる手順なのですが、一発でできてSSH_PRIVATE_KEYの設定だけで良いので便利です。