OmniAICreator/Qiita-1.07M huggingface dataset:
ログについて悩む

最近、開発業務でログの実装をちらほらやってます。
その際に悩むネタがあったので備忘録的にまとめます。
色々書いてはいるけど、最終的にはプロダクトの性質、方針の方に強く依存すると思います。

# 前提
- web系のコンポーネントの話です
- 今回対象とするログは、syslogやlog4jで取得するユーザーに直接見せないログです
- とりあえずLog4jを参考としてますが、昔からあるロギングライブラリは似たようなログレベルを持ちます

# ログレベル、細分化しすぎ問題
一般にログ取得のライブラリはログレベルを指定することができます。
例えばLog4JだとFATAL, ERROR , WARN , INFO , DEBUG , TRACE などにログは分類されます。
ログは環境に応じて出力するログレベルを選択することができます。

このような仕組みにより、開発環境では全てのログを出力し、運用環境ではINFO以上のログを出力するようにしたり、と言った制御が可能になります。

## ログレベルって、本当にこんなに種類必要・・・？
ログのポリシー設計をしていた時、思ったことです。
あれ、こんなにログレベルって必要なくない・・・？
ということで、設計時に考えたことをまとめてみます。
 
[参考、log4j](https://ja.wikipedia.org/wiki/Log4j#.E3.83.AD.E3.82.B0.E3.83.AC.E3.83.99.E3.83.AB)

| ログレベル |  Log4Jで説明された役割|検討内容|
|:-----------|:-------------|:------------|
| FATAL | 致命的なエラー。プログラムの異常終了を伴うようなもの。 |不要。プログラムの実行時エラーはERRORレベルで取得すべき。<br>プログラム異常が発生するのであれば監視システムなどからアラートを発行させるべき。|
| ERROR | エラー。予期しないその他の実行時エラー。|必要。問題になった要因、解決方法を調査可能なように出力する。 |
| WARN | 警告。廃要素となったAPIの使用、APIの不適切な使用、エラーに近い事象など、実行時に生じた異常とは言い切れないが正常とも異なる何らかの予期しない問題。| 不要。サービスが継続可能であれば、確認する必要がない。<br>ユーザー入力・操作などの問題であればUIで通知すべき。|
| INFO | 情報。実行時の何らかの注目すべき事象（開始や終了など）。従ってメッセージ内容は簡潔に止めるべき |不要。実行時に注目すべき動作はUIで通知すべき。 |
| DEBUG | システムの動作状況に関する詳細な情報	 |必要。開発時、検証時に正しく動いているかを確認しやすくできる。運用時は出力する必要がない。 |
| TRACE | トレース情報。更に詳細な情報。|不要。DEBUGと同じで良い<br>（syslogとかだとそもそもTRACE存在しないし）<br>あと、カバレッジテストやスタックトレースで開発時に担保する方が幸せになれそう|

ということで、今回はログポリシーを下記のようにまとめてみました。

| ログレベル |  内容|
|:-----------|:-------------|
| ERROR | エラー。処理が継続できない時に出力する。<br>エラーの原因を具体的に記述する。<br>リソース確保に失敗したなら、どのリソースが取れなかったかなどを明確にするなど。<br>復旧できない内容や、認証失敗など通知が必要なERRORはAlert通知を伴う|
| DEBUG | 検証時に必要な情報。トレースログなども必要に応じて取得する。	|

上記に加えて、UIに通知領域を追加。
大体下記のような内容を出力するようにする。

| 通知タイプ |  内容|
|:-----------|:-------------|
| Info |処理の実行状況や処理の終了など、システム的にユーザーが知りたそうなことを淡々と通知する |
| Alert |エラー発生時にユーザーに問題が発生したことを通知する。|
| Announce |メンテナンス情報など、運用側からユーザーに連絡したい内容を通知する|

ひとまずこんな感じで実装して不都合起きないか試してみようと思います。
rpm と yum を今更理解したい

# rpm と yum を今更理解したい
今日は１日コンソールとにらめっこしていました。私です。
```yum```とか```rpm```とかちゃんとわかっていないので、オラオラとコマンドを叩きまくっていました。
最終的に依存関係無視して強制インストールするという暴挙にもでました…
ここはエンジニアとしてちゃんと理解していないといけないと思って少しだけちゃんと勉強します。

## rpm

### rpmってなに？
「RedHat Package Manager」の略みたい。
Redhat系のディストリビューションで活躍する**パッケージ管理システムの１つ**です！

### パッケージの形式
ファイル名には命名規則があるっぽい。

![rpm_file.png](https://qiita-image-store.s3.amazonaws.com/0/182837/20d30a08-1da0-c45e-c259-8286ecfa1ca4.png)


こんな感じになってる。これで明日からファイル名を見ただけで「ほ〜バージョン4.3ですか…」とそれっぽいことが言えるようになる。

### rpmコマンド
```rpm``` ではコマンドでパッケージを追加したり、削除したり、更新したりする。
簡単には以下のような感じ。

・追加```-i```install

```bash
$ rpm -ivh <パッケージ名>
```

・更新```-U```update

```bash
$ rpm -Uvh <パッケージ名>
```

・削除```-e```erase(?)

```bash
$ rpm -e <パッケージ名>
```

あとは自分で調べてみてください。
ここまで読めば、一応パッケージをインストールしたり削除したりすることは出来るようになるはず。
でも```rpm```はパッケージ**管理システム**なのだ。管理・・・？インストーラーとかではなく？

### rpmは何を管理しているのか
一言で言うとrpmは**依存関係**を管理している。
「〇〇を使うには△△が必要だよ！」というのが依存関係。

例えると、「お化粧がしたい！」と思うとする。
rpmさんに「お化粧ができるようになりたい！」と相談すると、rpmさんは「お化粧を教えてあげるね！…でも『口紅』と『マスカラ』が最低限要るわ！出直してこい！」と言って依存関係を教えてくれるのです。

これはインストールするときも削除する時も同様で、「△△を消したい！」と言っても「〇〇で使ってるからダメ！」と指摘してくれるのです。
ここで大事なのは**指摘してくれる**というところ。

## yum
```rpm``` よりも使う頻度が高いので、```rpm```より目立つ彼。一体何をしているのでしょうか。

### yumってなに？
```yum``` は実はやっている事の本質は```rpm```と一緒です。というか**内部ではrpmコマンドが実行されています。**
では違うところは？最も違うのは**自動で依存関係を解決してくれる**というところです。

また、```yum```を利用する際には、パッケージファイルを準備する必要はありません。ではインストールする実体はどこに？
その答えは**リポジトリ**です。

リポジトリというのはたくさんの**パッケージを集めて保管している場所**です。
例えば安定したエンタープライズ向けの「EPEL」や最新バージョンが揃う「Remi」などが有名です。

### rpmとの違い
大きくは３つの特徴があります。

1. 依存関係の自動解決
これはさっきも言ったとおり、自動で依存関係を解決してくれます。
さっきの化粧の話でいうと、化粧道具一式買ってきてくれます。ほんとに居たらいい人通り過ぎて怖い。

2. インストール時にパッケージ名で指定できる
```rpm``` はパッケージファイルを準備して（もしくはURL指定で）インストールを行うが、```yum```はパッケージ名だけわかっていれば基本はOK。

3. インストールされていないパッケージを参照、検索出来る
マシンに存在していないパッケージの情報を得ることが出来る。
```rpm```は依存しているパッケージ名はわかっても、そこからすぐにインストールしたり、情報を得ることが出来ない。

こんな便利機能を備えたのが```yum```です。なので基本的には```yum```を使うことになります。

### yumコマンド

簡単には以下のような形で使います。

・追加 install

```bash
$ yum install <パッケージ名>
```

・削除 erase

```bash
$ yum erase <パッケージ名>
```

・インストール出来るパッケージの一覧を確認 list

```bash
$ yum list
```

```rpm``` と異なり、コマンドを打った後に、「本当にインストールしていい？」と基本的には聞いてくるので、返事をしてあげましょう。
こまかなコマンドについては調べてみてください。

## yumとrpmの使い分け
「自動で依存関係を解決してくれるのならyumだけでいいじゃん！」と思ったそこのあなた。間違っていません。
基本的には```yum```を使って管理をしていけばOKだと思います。

~~```rpm``` を使うタイミングとしては、まず**レポジトリに無いパッケージをインストールしたい時**にはrpmを使うしか無いですよね。~~
@angel_p_57 さんから指摘頂いたので追記
レポジトリに無いパッケージでも、rpmファイルを準備すればyumコマンドでインストール可能みたいです。

```bash
$ yum install <RPAファイル名>
```

更にこの方法でインストールした場合、```yum list installed```でインストールしたパッケージ一覧を表示した際に、リポジトリ名が ```@XXX``` ( ```@base```や```@epel```等 ) ではなく ```installed``` となっていて区別できるそうです！yumはやっぱり出来るやつやで…
…じゃあ```rpm```はいつ使うんだ？　皆さんの経験を教えてください！僕では経験不足！！
・・・インストール先がかなり特殊だとか、開発中の不安定なパッケージを試したいとか、そんなときでしょうか。

# まとめ
* rpmはRedhat系のディストリビューションで使われるパッケージ管理システム。
* yumはrpmを拡張し、リポジトリという考え方で依存関係を自動的に解決する事ができるようになったもの。
* 基本的にはyumを使っていれば問題ないが、時と場合に応じて使い分ける。

といったところでしょうか。
yumとrpmの違いと、何をやっているのかわかってなんとなくスッキリしましたね。
NavigationDrawerを普通のButton(ImageButton)から開く

### はじめに
ツールバーはスタイリッシュではない気がするので
自作のボタンからドロワーを起動できるようにしてみました。
### コード
.MainActivity

```java
ImageButton drawer_open_button = (ImageButton) findViewById(R.id.drawer_open);
        drawer_open_button.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View view) {
                DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
                drawer.openDrawer(GravityCompat.START);
            }
        });
```

### 違い
ツールバー有りver
![toolbar.PNG](https://qiita-image-store.s3.amazonaws.com/0/135101/1bff00ca-9daa-bed8-6475-95d21c297417.png)

自作ImageButton使用ver
![Notoolbar.PNG](https://qiita-image-store.s3.amazonaws.com/0/135101/3120101e-fda4-d0c6-acb2-f086829eb816.png)
S2Strutsのチュートリアルをやってみよう(#0_yymmdd)

#この取り組みの目的
　・自宅でのGitHubと連携した開発環境の構築
　・Seasar2(というかS2Struts)を仕事で使うんでその勉強
　　Maven、Gitも

#この取り組みの目標
　・完全動作版のS2StrutsプロジェクトをGit上に公開　
　・チュートリアルのAntの仕組みをMavenに置き換え

#今後の進め方
　・Qiitaで進捗報告(作業日ベース)
　・完了したらGitHubのサイトを公開

#その他
　・正直、需要はないと思ってる
　・将来的にはSpringやら、Hibernateやら、聞いたことある、興味がある、けど
　　使ったことは無い技術について、目標を設定してちょいちょいやっていきたい

ということでどのくらいかかるかはわかりませんが、いったん18年度1Q目標に頑張ります
chrome(v66以降)でseleniumテストが動画の自動再生でハングする

# 条件
- chrome(v66以上)
- seleniumを利用した自動テストを行っている
- 自動再生のEventを引っ掛けようとしている

# 解決法

- `--autoplay-policy=no-user-gesture-required`を利用する。

## 具体的には

```javascript

var webdriver = require('selenium-webdriver');
var chromeCapabilities = webdriver.Capabilities.chrome();
var chromeOptions = {
'args': ['--autoplay-policy=no-user-gesture-required']
};
chromeCapabilities.set('chromeOptions', chromeOptions);
var driver = new webdriver.Builder().withCapabilities(chromeCapabilities).build();
```
# 概要

かねてから噂されていたらしい、Chromeの自動再生拒否のバージョンがついにやってきた。
（実装はちょっと前からされてたみたい、デフォルトにされたのが今回のアプデ）

seleniumでの設定方法でもつまずいたが、ブラウザ経由で自動再生のフラグを変更したいなら `chrome://flags/#autoplay-policy`で操作する。

一応、以下の三種類が用意されている。

- No user gesture is required.
- User gesture is required for cross-origin iframes.
- Document user activation is required.

一ユーザーとしてはありがたい限りの機能だが、テストが落とされるのは困ったので共有したい。

ちなみに、IMEとやらでサイトごとに自動再生を許可するドメインを確定する仕組みがあるみたい。
ただ、自分の`chrome://media-engagement`を見ても全部、拒否られてたのでよくわかんない。

![image](https://cdn-ak.f.st-hatena.com/images/fotolife/n/nukisashineko/20180423/20180423225002.png)


自動再生拒否を回避してどうしても自動再生で動画を流したい人は[Google公式](https://developers.google.com/web/updates/2017/09/autoplay-policy-changes)行けばいいと思います。
[回避できる手段について日本語でまとめたものがQiitaにあったのでペタリ](https://qiita.com/ktknest/items/e81b3a4caac540098fc8#chrome)


休日が開けたら、テストが`timeout`してて月曜日から憂鬱な気分に振り回される人が少なくなるように祈ります。

参考：

- https://developers.google.com/web/updates/2017/09/autoplay-policy-changes
- https://gist.github.com/anandsunderraman/e351485319a8a0e7df7e
【Rails】CSSやJavaScriptを読み込む小さなメモ

デフォルトのマニフェストファイル(application.css,application.js)にある記載

●CSS

```css
*= require_tree .　★全てのアセットを読み込む
*= require_self　★自身も読み込む
```

●js

```javascript
//= require rails-ujs　★Railsが提供するJavaScriptヘルパ
//= require turbolinks　★Ajax化する仕組み
//= require_tree .★全てのアセットを読み込む
```

上記だと、 `require_tree` によってapp/assets/[js or css]/下の全てのファイルが読み込まれてしまうため、treeの記載を削除し、個別に定義する定義ファイル( `config/initializers/assets.rb` )に読み込むアセットを指定する(↓は `test.js` `test.css` の場合。scssにするならscssで指定)

```ruby
Rails.application.config.assets.precompile += %w(test.js test.css)
```

ビューで以下を定義

```erb
    <%= stylesheet_link_tag    'test' %>
    <%= javascript_include_tag 'test' %>
```
Google Compute Engineで作ったインスタンスにターミナルからssh接続する

GCEで作成したインスタンスにターミナルからsshコマンドを使って使用する方法を紹介する。

google-cloud-sdkをインストールしてgcloudコマンドを使ったり、ブラウザでインスタンスのターミナルをいじることもできる。
しかし、sdkをインストールする必要があったり、動作がもっさりする。

そこでsshコマンドを使って快適にGCEのインスタンスを利用する。

# sshキーの生成

まず、自分のpcのsshキーを生成する。
以下のようにssh-keygenコマンドを実行しよう。
ここで`-C`オプションに続く[ユーザ名]はgceのインスタンスのユーザ名になる。
また、ssh-keygenコマンドを実行するとsshキーを保存するpathとパスフレーズが求めらるので好きなものを入れる。

下の例ではsshキーを保尊するpathを`/Users/name/.ssh/gcloud_id_rsa`とした。

```ｓｈ:sshキーの生成
$ ssh-keygen -t rsa -b 4096 -C [ユーザ名]
Generating public/private rsa key pair.
Enter file in which to save the key (/Users/name/.ssh/id_rsa):/Users/name/.ssh/gcloud_id_rsa
Enter passphrase (empty for no passphrase):
```

# 公開鍵の登録

公開鍵の登録は[Google Cloud Console](https://console.cloud.google.com)から登録する。
Google Cloud ConsoleのCompute Engine->メタデータ->ssh認証鍵->編集をクリックすると、公開鍵の登録画面が開く。

![スクリーンショット 2018-04-23 22.08.55.png](https://qiita-image-store.s3.amazonaws.com/0/74937/16b6e3fb-09aa-c37c-3a17-f0804a9153f8.png)

![スクリーンショット 2018-04-23 22.32.16.png](https://qiita-image-store.s3.amazonaws.com/0/74937/3b357806-0a9e-4336-5d3f-a49fa023cccd.png)

登録画面の認証鍵全体を入力と書かれたフォームに公開鍵を入力する。
macの場合はpbcopyを使うとターミナル上でクリップボードにコピーできる。
コピーしたらフォームに入力して保存する。

```sh:公開鍵のコピー
$ pbcopy < gcloud_id_rsa.pub
```

これで登録した鍵を使って、Compute Engineで生成した全てのインスタンスにssh接続できるようになる。

# インスタンスにssh接続

Google Cloud ConsoleのCompute Engine->VMインスタンスを開き、接続したいインスタンスの外部IPを確認する。

![スクリーンショット 2018-04-23 22.44.19.png](https://qiita-image-store.s3.amazonaws.com/0/74937/c3babcd2-ea56-697e-59ec-68989f28170b.png)

ユーザ名,外部IP,秘密鍵のpath(例では`~/.ssh/gcloud_id_rsa`)を指定して、sshコマンドを実行する。

```
$ ssh [ユーザ名]@[外部IP] -i ~/.ssh/gcloud_id_rsa
```
jQueryで上部からにゅっと表示される更新メッセージ

# フロントエンド勉強 #1

```html
<?php
    if ( !empty($_POST['post']) ) {
        $printNotifyMessage = '更新しました。';
    }
?>
<!DOCTYPE html>
<head>
<title>update message</title>
</head>
<body>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script type="text/javascript">
$(function () {
    $(document).ready(function() {
        $("#notifyMessage").slideDown().delay(5000).slideUp();
    });
});
</script>

<?php
    if ( !empty($printNotifyMessage) ) {
        echo '<div id="notifyMessage">' . $printNotifyMessage . '</div>'."\n";
        $printNotifyMessage = "";
    }
?>
 
<form method="post" name="send" action="">
<input type="submit" name="post" value="メッセージ表示" />
</form>
    
<style type="text/css">
<!--
#notifyMessage{
	position: absolute;
    display: none;
    top: 0px;
    margin: 0 auto;
    padding: 15px 0;
    width: 80%;
    text-align: center;
    font-size: 13px;
    color: #fff;
    background-color: rgba(51,51,51, 0.8);
}
-->
</style>
</body>
</html>
```
外部システムスタブ「Subuta」(導入編)

## はじめに
システム開発していると、HTTPで外部のシステムにリクエストしたり、FTPでファイルのやりとりなどをする機能を作ったりします。
単体試験ではこういった外部のシステムの代わりにスタブを使ったりするんですが、固定なレスポンスを返すぐらいだったらいいんですが、リクエストデータ毎にスタブのレスポンスを変えたいとかいう要望があるわけです。
そういうことは外結で試験すればいいじゃない、とかいう意見もあるのですがその対向システムにテストデータを作成できないとか申請が面倒とかあるわけです。基幹系なシステムとかだと。

## 作ってみた
そういうわけで、リクエストデータ毎にレスポンスデータを自由に変えるようなスタブを作ってみました。その名も「Subuta(すぶた)」です。
https://sites.google.com/site/subutapj/

オープンソースというわけでもなくGitにあげているわけでは無いのですが、いちおうソースはダウンロードできるので、ソースオープンソフトという感じでしょうか。

## できること
・REST
・FTPサーバ
・SMTPサーバ
機能を持っています。FTPとSMTPは単純にサーバとしてです。FTP、SMTPの試験を行うのにいちいちFTPサーバなどをインストールするのは面倒なので実装しました。しかしながら、サーバ以上の機能は持っていません。
Subutaのメイン機能はRESTの方で、上記のとおり、リクエスト毎にレスポンスを変更することが可能です。

## インストール
SubutaはJavaのWEBアプリですので、WARで配布しています。
こちらからダウンロードしてください。
https://sites.google.com/site/subutapj/subuta

Tomcat環境があれば動きます。%TOMCAT_HOME%/webapps配下にWARを配置してTomcatを起動しておしまいです。
http://[IP]:[PORT]/subuta
にアクセスしてみてください。↓のような画面が表示されるはずです。
<img width="984" alt="" src="https://qiita-image-store.s3.amazonaws.com/0/245365/a300a970-e976-ac78-814f-73f5fed2046d.png">

はい。これで前準備は完了です。

## Dependencies
・Java7以降
・Tomcat6以降
単にこれ以前のバージョンは動作確認していないだけなので、これ以外でも動くかもしれません。
DBはSQLite使っています。

## その他
SQLiteファイルやSubutaが生成するファイルは%TOMCAT_HOME%配下に出力されます。subutaはたまに更新されますが、基本的には下位互換でWARを置き換えるだけでバージョンアップ可能です。

次回はAPIの作り方を説明します。
SpringBootのapplication.properties内で環境変数を使う

# 目的

環境依存値をアプリケーション内に埋め込むのではなく外部化しましょうという話はもはや常識になっていますが、特にSpringBootの場合は様々な方法があります。公式ガイドでも1章まるまるその話題に費やしています。

> [24. Externalized Configuration](https://docs.spring.io/spring-boot/docs/2.0.1.RELEASE/reference/htmlsingle/#boot-features-external-config)

環境ごとにプロパティファイルを分けるとか、いや、せっかくSpringBootなんだからConfigurationサーバを使うべきだとかいろいろ流儀はあると思いますが、今回は[The Twelve-Factor App](https://12factor.net/ja/config)に従って環境変数を考えてみます。

アプリケーション内で環境変数を参照するためには`@Value`アノテーションを使う方法がありますが、JPAのようにapplication.propertiesに設定をゴリゴリ書く場合はその方法は使えません。そこで、application.properties内で環境変数を使う方法がありました。

# 方法

`${環境変数:デフォルト値}`の形式で記述します。

```application.properties
hoge.fuga = ${FOO:bar}
```

いや、当たり前でしょとは言わないでください。意外にこれ、ガイドにきちんと書いてなかったりします（書いてあったらごめんなさい）。

個人的には、環境によってビルドパラメータを変えるとか、あるプロパティはソースコード内で取得して、別の値はフレームワークにまかせて、というのは健全ではないと思っているので、設定を集約できるのはいいことだと思っています。

また、デフォルト値を入れられるのもいいです。例えばDB接続でUT時はデフォルトでlocalhost、IT以降は基盤が提供する環境変数が示すホストにつなぐということが、プロパティファイルを切り替えずにできるわけです。

はやりのKubernetes(k8s)でも便利です。k8sではServiceのホスト名とポート名が同じネームスペース内であれば環境変数で参照できますので、マイクロサービスのディスカバリーとしても使えます。

以上です。
Unity 2017.4.1f1 と Mac でマルチディスプレイ実行

# やりたいこと
* Unityプロジェクトをマルチディスプレイで実行したい
* モニターn枚に対してdisplayで指定されている内容を映したい
  * cameraとdisplayの紐付けについてはこちらが参考になります  
  [【Unity】Unityでマルチディスプレイする方法 \- テラシュールブログ](http://tsubakit1.hateblo.jp/entry/2015/12/18/235514)
* 要は手元の操作用PCの画面にも追加モニターの画面にも、別々の内容が映せれば成功

# 検証環境
* Unity 2017.4.1f1
* Mac High Sierra ver 10.13.4
* HDMI接続したモニター1枚

# 設定
## ディスプレイのActivate
実行開始時にDisplay.Activateされるよう、以下で紹介されているコードを書いて、
適当なオブジェクトにアタッチしておく(マニュアルではデフォルトカメラにつけると紹介されている)
[マルチディスプレイ \- Unity マニュアル](https://docs.unity3d.com/jp/current/Manual/MultiDisplay.html)

以下、上記より引用

```csharp

    void Start()
    {
        Debug.Log("displays connected: " + Display.displays.Length);
        // Display.displays[0] は主要デフォルトディスプレイで、常に ON。
        // 追加ディスプレイが可能かを確認し、それぞれをアクティベートします。
        if (Display.displays.Length > 1)
            Display.displays[1].Activate();
        if (Display.displays.Length > 2)
            Display.displays[2].Activate();
        ...
    }
```

## Player 設定
1. File > Build Setting > Player Setting > Setting for PC, Mac & Linux Standalone > Other Settings > Rendering > Auto Graphics API for Mac のチェックをはずす
2. Graphics APIs for Mac 欄の順序で OpenGLCore が一番上にくるようにリストを操作する

参考URL :
[Multi\-Display Support \(Unity 5\.3 Mac\) \- Unity Answers](https://answers.unity.com/questions/1114019/multi-display-support-unity-53-mac.html)

## build
### 注意点
1番モニター、2番モニター…とあった時に

* 1番モニターとなる画面上で実行する
    * Unityの画面あるいはfinderの画面を1番モニターの画面上に配置して実行する
    * 2番モニターの画面上で実行すると、2番モニターに1番モニターの内容が表示されて1番モニターが仕事をサボることになる
* 全画面表示で実行する。Windowedにチェックした状態で実行しても上手くいかなかった

### ログの確認
buildして実行している間、Debug.Logの内容は Mac では ~/Library/Logs/Unity/Player.log に記録される。
上記で引用したActivate用のコードを走らせると、ディスプレイの数がカウントされて印字されているはずなので、確認しておく。

[ログファイル \- Unity マニュアル](https://docs.unity3d.com/jp/current/Manual/LogFiles.html)
UiPath勉強一回目




# UiPathとは
RPA(Robotic Process Automation)ソフトウェアを
提供している企業のこと。
無償版の製品(UiPath Studio Community)が使用できるためRPA
について学んでいきたいとについて考えている人におすすめです。


## UiPath Studio Community

UiPath Studio Communityの使用方法に関しては下記の
URLから行える。

[UiPath](https://www.uipath.com/ja/)

## 実際に触ってみる

実際にダウンロードが完了したら一つプロジェクトを作ってみる。



![1.PNG](https://qiita-image-store.s3.amazonaws.com/0/246340/cebd9d0c-891a-316b-f94c-5be890a76533.png)

MessageBoxを画面中央にドラッグアンドドロップ。

![2.PNG](https://qiita-image-store.s3.amazonaws.com/0/246340/41965945-ffe7-9e2a-68f4-754ad2598031.png)



MessageBoxの中に文字を入力。

![3.PNG](https://qiita-image-store.s3.amazonaws.com/0/246340/a6531703-36bb-4283-be96-d57ce67b9a98.png)


入力を終えたらDESIGNタブにあるRunを実行。

![3.5.PNG](https://qiita-image-store.s3.amazonaws.com/0/246340/191c12eb-4e01-604e-9065-3d5de5b43b13.png)


しばらくすると下記のような実行結果が表示。

![4.PNG](https://qiita-image-store.s3.amazonaws.com/0/246340/a5c2f734-b801-b5c9-1f70-ca63e9da8aa3.png)
Ionic3に入門してみる～その5 Angular4チュートリアル③～

前回までで作ったコードを変更していきます。
## Hero クラスを作成する
これはそのままチュートリアル通り。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/196422/7e184821-ed01-caad-9538-bf49f666c347.png)

importのパスが違うので気をつける。
今更ですが、NgModuleは使わないのでimportしなくても良いです。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/196422/594480e1-91f1-d40b-8391-d2f713b4f3a7.png)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/196422/441723ed-aafa-dfdd-fe54-6437f4af87df.png)

ビルドしてみるとこんな感じになります。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/196422/aad39b47-60bb-6773-f002-e51bbeeece9a.png)

## UppercasePipe で書式設定する

特に苦労することなくチュートリアルがそのまま動きます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/196422/60294266-f4f1-7f1f-a9d6-6d76e932efd9.png)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/196422/e331ea42-fa49-b683-dfb9-0035a479d399.png)

## 双方向データバインディング
inputタグから受け取った文字列をアプリケーション側で受け取ります。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/196422/1104b2a9-3679-5f00-4927-f6b369609dd8.png)

なお、チュートリアルではエラーが出る云々と話が続きますが、Ionicではエラーが出ません。
...何でだろう？
Ionicフレームワークを見た感じでは特に説明もない。

module.d.tsには下記の記載があった。
>By passing a root component, IonicModule will make sure that all of the components,
>directives, and providers from the framework are imported.

つまり、

>ルートコンポーネントを渡すことによって、IonicModuleは、フレームワークのすべてのコンポーネント、ディレクティブ、およびプロバイダがインポートされるようにします。

ということなので、もしかしてこれに含まれてるのかも？

今回はここまで。
Cordova（PhoneGap）でアプリ内課金を実装

こちらのプラグインを使用します。
https://github.com/j3k0/cordova-plugin-purchase

README翻訳

## 概要
このプラグインは、CordovaとPhoneGapから作られたAndroid/iOS/Windowsアプリのアプリ内課金を可能にします。
シングルコードで全てのプラットフォームを操作できます。

## インストール
### Cordovaの場合

```
cordova plugin add cc.fovea.cordova.purchase
```
・Androidも作る場合

```
cordova plugin add cc.fovea.cordova.purchase  --variable BILLING_KEY="<BILLING_KEY>"
```

Billingキーの取得方法はこちら
https://github.com/j3k0/cordova-plugin-purchase/wiki/HOWTO#add-android-billing-key

### PhoneGap Buildの場合

```xml
<gap:plugin name="cc.fovea.cordova.purchase" source="npm" version="6.0.0" />
```
・Androidも作る場合

```xml
<gap:plugin name="cc.fovea.cordova.purchase" source="npm" version="6.0.0">
   <param name="BILLING_KEY" value="MIIB...."/>
</gap:plugin>
```

## 機能
consumable purchases (e.g. virtual currencies)
non consumable purchases (e.g. features unlocking)
paid and free subscriptions
receipts validation
restoring of purchases made on other devices
downloadable content (iOS)

## サポート端末
iOS 6.0以上
Android 2.2 (APIレベル8)以上、Google Play 3.9.16以上
Windows Store/Phone 8.1以上

## Minimam Exsample

```javascript

// We must wait for the "deviceready" event to fire
// before we can use the store object.
document.addEventListener('deviceready', initializeStore, false);

function initializeStore() {

    // 多くのものをみるために、高い冗長レベルで設定
    // コンソール内で (何が起きているかわかるので）
    store.verbosity = store.INFO;

    // ダミー商品を登録
    store.register({
        id:    "com.example.app.inappid1",
        alias: "100 coins",
        type:  store.CONSUMABLE
    });

    // Storeを準備完了にする
    store.ready(function() {
        console.log("\\o/ STORE READY \\o/");
    });

    // セットアップが終わったらリフレッシュする
    store.refresh();
}
```
Androidでキーボードを閉じる方法メモ

```EditView``` などで文字列を入力後などに、キーボードを非表示にしたい場合の方法メモ。


```
class ContentFragment : Fragment() {

    private fun hideKeyboard() {
        val view = activity.currentFocus
        if (view != null) {
            val manager = activity.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
            manager.hideSoftInputFromWindow(view.windowToken, 0)
        }
    }

}
```
Vue.jsをお手軽に導入する

# 概要

Vue.jsを手軽に導入してみます。

方針は、

- WebpackやNode.jsは使わない

ということで、単純なHTMLとJSだけでVue.jsをとりあえず使ってみましょう。

## サンプルコード

まずは、サンプルコードです。


```html
<!-- Vue.js(このサンプルではCDNを使用する) -->
<script src='https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js'></script>

<!-- x-templateでテンプレートを定義 -->
<script type='text/x-template' id='app-template'>
  <div>
    <p>sampleNumber: {{ sampleNumber }}</p>
    <p>sampleText: {{ sampleText }}</p>
    <p>sampleComputedNumber: {{ sampleComputedNumber }}</p>
  </div>
</script>

<!-- appのマウント先となるHTML要素 -->
<div id='app-mount-element'>
</div>

<!-- ロード時に実行されるscript -->
<script>
  // Vueインスタンスを生成する
  var app = new Vue({
    // テンプレート
    template: '#app-template',
    // データオブジェクト
    data: {
      sampleNumber: 100,
      sampleText: 'abc'
    },
    // 算出プロパティ
    computed: {
      sampleComputedNumber: function() {
        return (this.sampleNumber * 2);
      }
    }
  });

  // VueインスタンスをHTMLにマウントする
  app.$mount('#app-mount-element');
</script>
```
<p data-height="265" data-theme-id="0" data-slug-hash="NYZLgG" data-default-tab="html,result" data-user="pale2f" data-embed-version="2" data-pen-title="NYZLgG" class="codepen">See the Pen <a href="https://codepen.io/pale2f/pen/NYZLgG/">NYZLgG</a> by pale2f (<a href="https://codepen.io/pale2f">@pale2f</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

## 最初に知っておくべきこと

最初に、

- Vue.jsのテンプレートは(専用の文法に従った)単純な文字列である

ということを理解しておく必要があります。

`el`オプションを使用すると、指定した要素の内容を置換してくれるので、HTMLに値をバインドしているかのようにみえますが、そうではないのです。

また、以下の制限にも要注意です。

- [DOM テンプレート解析の注意事項](https://jp.vuejs.org/v2/guide/components.html#DOM-%E3%83%86%E3%83%B3%E3%83%97%E3%83%AC%E3%83%BC%E3%83%88%E8%A7%A3%E6%9E%90%E3%81%AE%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A0%85)

上記のリンク先に記載されているとおり、HTML上でテンプレートを定義する場合、ブラウザがHTMLを解釈する方法に注意が必要です。


このサンプルコードでは、

- x-templateでテンプレートを定義する

という手法で、上記の制限を回避しています。

詳しくは、以下のリンク先をご参照ください。

- [コンポーネント - x-template](https://jp.vuejs.org/v2/guide/components.html#x-template)
- [API - template](https://jp.vuejs.org/v2/api/#template)


## Vueインスタンスを意識する

- Vueのコンストラクタ(`new Vue(...)`)で指定するのは、Vueインスタンス生成のオプション

↑改めて文章にしてみたら当たり前すぎました。
しかし、Vue.jsの場合、この当たり前のことに混乱しがちです。

- `data`も`computed`も、Vueコンストラクタのオプションに過ぎない

ということを忘れないようにしましょう。

このサンプルコードでは、敢えて変数に代入する事でインスタンスを意識しやすくしています。

また、Vueインスタンスのマウント処理も敢えて明示的に書いています。

[API - vm.$mount](https://jp.vuejs.org/v2/api/#vm-mount)

## 最後に
Vue.jsは非常に便利なので色々なシーンで使いたいのですが、最近のフロントエンド界隈は、環境構築のハードルが(いろんな意味で)高いので、手軽に導入するためのサンプルを書いてみました。
これぐらいなら、jQueryぐらいの導入コストで、Vue.jsを使えるのではないかと思っています。

無論、Webpackなどが使える環境であれば、Vue.jsの魅力をもっと引き出せるのはいうまでもありませんが、この程度の使い方でも、Vue.jsは充分便利です。本当に隔世の感があります。
おすすめのJSドラッグ＆ドロップライブラリ

## Packery（パッケリー？）
公式サイト
https://packery.metafizzy.co/


### つかいかた
CDNで読み込み

```html
<script src="https://unpkg.com/packery@2/dist/packery.pkgd.min.js"></script>
<script src="https://unpkg.com/draggabilly@2/dist/draggabilly.pkgd.min.js"></script>

<style>
  .grid-item { width: 25%; }
  .grid-item--width2 { width: 50%; }
</style>

<body>
  <div class="grid">
    <div class="grid-item">...</div>
    <div class="grid-item grid-item--width2">...</div>
    <div class="grid-item">...</div>
  </div>
  <script>
    var $grid = $('.grid').packery({
      itemSelector: '.grid-item',
      // columnWidth helps with drop positioning
      columnWidth: 100
    });

    // make all grid-items draggable
    $grid.find('.grid-item').each( function( i, gridItem ) {
      var draggie = new Draggabilly( gridItem );
      // bind drag events to Packery
      $grid.packery( 'bindDraggabillyEvents', draggie );
    });
  </script>
</body>
```
メイソンリーも対応していて、アニメーションもなめらか。

## shopify draggable
Shopifyがつくったらしい

公式サイト
https://shopify.github.io/draggable/



## interact JS
DnDだけでなく、様々なインタラクティブ動作に対応。

公式サイト
http://interactjs.io/
[GAS] Gmailの下書きを定期的に自動生成する

# ポイント
**レンダリング(太字や箇条書き)**を行う場合、オプション引数のhtmlBody要素を必ず指定するだけでなく、<font color="RED">**プレーンテキストにも何らかの文字を指定する**</font>こと。

# スクリプト

```javascript

function createDailyGreetingDraft () {
  // 本文(プレーンテキスト)
  const mailBody = 'HTMLが表示できません'
  // 本文(HTML)
  const mailHtmlBody = 'おはよー<br><br>いえ〜い'

  // 宛先 To
  const mailTo = "aaa@example.com, bbb@example.com, ccc@example.com"
  // 宛先 Cc
  const mailCc = "ddd@example.com, eee@example.com"

  // オプションでCcを指定
  var mailArgs = { 
    cc: mailCc,
    htmlBody: mailHtmlBody //HTMLレンダリングを適用する場合は、これの指定が必須
  }
  
  // 下書きを生成
  GmailApp.createDraft(
    mailTo,         //To
    createTitle(),  //件名
    mailBody,       //本文
    mailArgs        //オプション
  )
}

// 件名の生成
function createTitle() {
  // 件名の日時フォーマット
  const date_format = 'yyMMdd'
  
  var now = new Date()
  var date = Utilities.formatDate( now, 'Asia/Tokyo', date_format)
  var title = date + "の挨拶 "
  
  return title
}
```

あとは、**時計ボタンを押して、定期的な実行を設定**すれば完了。
[Python]エラトステネスのふるいで素数を求める

# C#で書いたものをPythonで書いてみた
[昨日のエントリ](https://qiita.com/jinka1997/items/535dfba4ec7dbd75f5a7)で書いたC#のコードを、Pythonだとどうなるか書き換えてみた。

## Pythonのコード
※ 2018/4/24修正
変数名「dict」を「dic」に修正。(「dict」は組み込み関数名なので、変数名として適切でない)

```python
fr = 1
to = 200

# ディクショナリ初期化
# keyは整数、
# valueはステータス(0：判定前、1:消した(素数でない)、2:○をつけた(素数))
dic = {}
for i in range(1, to + 1):
    dic[i] = 0

# 単数の1を消す   
dic[1] = 1

prime_number = 2

# 素数の2乗が範囲内のところまでループ
while prime_number * prime_number < to:
    # 未判定の最小値を素数とする
    prime_number = min([item[0] for item in dic.items() if item[1] == 0])
    # ○をつけた(2を立てる)
    dic[prime_number] = 2

    # 未判定の値のうち、素数の倍数のリスト取得
    target_numbers = [item[0] for item in dic.items() if item[1] == 0 and item[0] % prime_number == 0]
    for n in target_numbers:
        # 合成数として消す(1を立てる)
        dic[n] = 1

# 残った値は全部素数として○をつける(2を立てる)
remain_numbers = [item[0] for item in dic.items() if item[1] == 0]
for n in remain_numbers:
    dic[n] = 2

# 素数と判定された値を出力
prime_numbers = [item[0] for item in dic.items() if item[1] == 2]
print (prime_numbers)
```
## 出力結果
以下の通り出力。OK！
![image.png](https://qiita-image-store.s3.amazonaws.com/0/221879/4b56f023-8868-c315-69f1-da22a7a35b4a.png)

C#でLinq to Object使いまくりだったので、
Pythonだとめんどくさいかも？と思ったけど、そうでもなかった。
リスト内包表記がすごく便利でした。
【GAS】ファイル名からファイルを取得する

この記事は移行しました！[最新の内容はこちら](https://naoqoo2.github.io/blog/GAS-%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E5%90%8D%E3%81%8B%E3%82%89%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%92%E5%8F%96%E5%BE%97%E3%81%99%E3%82%8B/)をご覧ください😀

ファイル名で検索したいとき[getFilesByName](https://developers.google.com/apps-script/reference/drive/folder#getFilesByName(String))という便利な関数がありますが、
Filesとあるように複数ファイル取得が前提でFileIteratorが返ってきます。

このフォルダ配下は必ず一つしか存在しないんだよーってときはこちらをどうぞ。


```javascript
function getFileByName(file_name, folder) {
  var files = DriveApp.getFolderById(folder.getId()).getFilesByName(file_name);
  while (files.hasNext()) {
    // 一つ目のファイルを返す（複数存在した場合は考慮しない）
    return files.next();
  }
  return null;
}
```
Bitbucket を 使用して Git の プライベートリポジトリを立ててみよう

# はじめに
個人で利用できる、無料のプライベートリポジトリってないのかしら？
と探してみたところ 
[Bitbucket](https://ja.atlassian.com/software/bitbucket) を 見つけたので
早速使ってみました。

# Bitbucket とは

[Atlassian] (https://ja.atlassian.com/) が提供しているコラボレーションツールの一つです。


## 料金体系 と 機能 
https://ja.atlassian.com/software/bitbucket/pricing?tab=cloud

- 無料トライアル
- スタンダート
- プレミアム

の3タイプ

無料トライアルでも 最大5ユーザまで無料 で 無制限 の プライベートリポジトリが使用できます。


Atlassian が提供している [Jira](https://ja.atlassian.com/software/jira)とも連携ができます。

# Bitbucket を使用する
## まずはアカウントを取得しましょう。
https://bitbucket.org/product にアクセスし 「Get started for free」をクリックします
![FireShot Capture 1 - Bitbucket I The Git solution for professional _ - https___bitbucket.org_product.png](https://qiita-image-store.s3.amazonaws.com/0/240814/40d0c1a0-ecaa-5a3a-59c4-82de09f89553.png)



メールアドレスを入力し「Continue」をクリックします。
![FireShot Capture 3 - アカウントを作成 - https___bitbucket.org_account_signup_.png](https://qiita-image-store.s3.amazonaws.com/0/240814/f4b98471-7848-d7af-c1af-282b182b7d04.png)


フルネームとパスワードを設定します。 フルネームは ユーザー名とは異なり、画面上に表示されるあなたの名前となります。
私はロボットではありませんをチェックして「Continue」をクリックします。
![FireShot Capture 4 - アカウントを作成 - https___bitbucket.org_account_signup_.png](https://qiita-image-store.s3.amazonaws.com/0/240814/c0f56fd0-ef73-9b1a-e6d7-67fc66c12138.png)


メールを送信したと表示されますので、メールを確認してください。
![FireShot Capture 6 - Verify your email - https___bitbucket.org_socialauth_verify-email_.png](https://qiita-image-store.s3.amazonaws.com/0/240814/670ec093-56d5-5735-aed8-c8fe64b029c5.png)


下記のようなメールが届くので「Verify my email address」をクリックします。
![FireShot Capture 8 - Please verify your _ - https___mail.google.com_mail_u_0_#inbox_1620599e41c53b74.png](https://qiita-image-store.s3.amazonaws.com/0/240814/2f9def49-bd3a-c862-ae00-198b27521805.png)


メールアドレスの検証が行われると下記のような画面が表示されますのでユーザー名を入力します。
![FireShot Capture 9 - Pick a username_ - https___bitbucket.org_socialauth_signup_.png](https://qiita-image-store.s3.amazonaws.com/0/240814/f2bae173-9f09-4e64-5ba7-56baca1b832d.png)


登録が完了すると下記のような画面が表示されます。
![FireShot Capture 11 - Welcome to Bitbucket - https___bitbucket.org_account_welcome_.png](https://qiita-image-store.s3.amazonaws.com/0/240814/b4a1b0fa-f028-f547-3e00-7b8bcbb4abef.png)

##リポジトリの作成
上記の画面で、「リポジトリの作成」を選択すると、下記の画面が表示されます。リポジトリ名を入力し「リポジトリの作成」ボタンを押します。
![FireShot Capture 12 - リポジトリの作成 — Bitbucket - https___bitbucket.org_repo_create.png](https://qiita-image-store.s3.amazonaws.com/0/240814/0312c08a-7b42-4d66-6400-fa5c11ce99cb.png)

リポジトリが作成されます。
![FireShot Capture13.png](https://qiita-image-store.s3.amazonaws.com/0/240814/6ff1fbb3-3dcc-0568-6290-36e0e56dce88.png)


##リモートリポジトリからプロジェクトをコピー
[コマンドラインからGitを使う（for Windows）](https://qiita.com/taiponrock/items/632c117220e57d555099)を参考にさせていただき
Git をコマンドラインで使えるように準備済みの状態で
コマンドプロンプトを立ち上げて下記のコマンドを実行します。

```
cd [プロジェクトをコピーするディレクトリ]
git clone https://[ユーザー名]@bitbucket.org/[ユーザー名]/[リポジトリ名].git
```

![コマンドライン.png](https://qiita-image-store.s3.amazonaws.com/0/240814/66c761c8-0633-b73c-129a-d2ee65e188f2.png)

アカウント情報の入力を求められるので、ユーザー名 と パスワードを入力します。
※一度入力したユーザ名とパスワードは
「コントロール パネル\すべてのコントロール パネル項目\資格情報マネージャー」 に保存されるので
２回目以降は入力の必要がありません。

指定された場所にプロジェクトがコピーされます。
Raspberrypi3 にvolumio



Fuji255127

4月22日 21:40 JST

昨日volumioをｲﾝｽﾄｰﾙしたﾏｲｸﾛSDをﾗｽﾞﾊﾟｲ３に差し込み、家のルーターに有線ランケーブルでﾗｽﾞﾊﾟｲ3を接続して
WINDOWS１０のデスクトップパソコンのモニターの右下WIFIマークのところでVOLUMIOが出てきました。
パスワードに「volumio2」を入力して正常に接続できました。表示は英語でした。100％になる前に
切り替えたせいかVOLUMIOはアクセスから消えてしまいました。
その後今日になって何回も接続を試みましたが、volumioのWIFIが立ち上がりません。
何故でしょうか。
それからﾗｽﾞﾊﾟｲ３は無線LANができるので有線LAN ｹｰﾌﾞﾙなしで設定できますか？
まだ当方は無線LAN設定が出来てません（ﾗｼﾞﾘﾋﾟｱﾝOSの場合無線ラン設定は出来ています）
方法を教えてください

追伸
　別のネット情報ではVOLUMIOのﾏｲｸﾛSDを入れたﾗｽﾞﾊﾟｲで、
　HDMIｹｰﾌﾞﾙでモニターにつないでVOLUMIOを確認する方法がありました。
　WINDOWS10のパソコン、モニターでVOLUMIOを確認する方法と
　異なると思います。
　違いを教えてください。
Promiseでの処理順指定の最低限メモ

とにかく最低限。説明も最低限。

# Promiseとは
非同期なJSの処理をしっかり順番指定してやるためのやつです。きれいにかけます。

# もっと簡単なPromiseの使い方
180727追記です

```javascript
// 上から順番に実行するやつ
Promise.resolve()
    .then(実行したい関数名) // 関数名がaならa()ではなくaとだけ書く
    .then(実行したい関数名)
    .then(実行したい関数名)
    .then(() => {
      console.log('ここで宣言もできる')
    })
```

# Promise使い方
関数A→B→Cの順番で処理をするなら

```javascript
new Promise((resolve, reject) => {
  // 処理A
  resolve(引き継ぐ情報（なかったら適当に）)
}).then((いわゆるreturn値が入る変数名(なかったら省略可)) => {
  // 処理B
  // resolveとrejectは引き続き使える
}
```

関数で置きたいなら

```javascript
const funcA = () => {
  return new Promise((resolve, reject) => {
    resolve()
  })
}

funcA().then(() => {})
```

最低限じゃない説明は↓で
【GAS】マイドライブからファイルを移動する

この記事は移行しました！[最新の内容はこちら](https://naoqoo2.github.io/blog/GAS-%E3%83%9E%E3%82%A4%E3%83%89%E3%83%A9%E3%82%A4%E3%83%96%E3%81%8B%E3%82%89%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%92%E7%A7%BB%E5%8B%95%E3%81%99%E3%82%8B/)をご覧ください😀

GASでフォームなどのファイル作成したあとにフォルダ移動したくなり、
id指定で動作する汎用的な関数を作りました。

ポイントとしては最後にマイドライブから消す必要がある。（消さない場合もファイルは同じものを参照する）

```javascript

function moveFromRootToFolder(file_id, folder_id) {
  var file = DriveApp.getFileById(file_id);
  DriveApp.getFolderById(folder_id).addFile(file);
  DriveApp.getRootFolder().removeFile(file);
}
```
とりあえずローカルに Ghost をインストール (Ghost-CLI 版)

Ghost-CLI を用いてローカルに Node.js 製の CMS である Ghost をインストールするまとめです。

参考「[Overview](https://docs.ghost.org/docs)」(Ghost のドキュメント)

# 1. Node のバージョン

2018/04/23 現在、Ghost の Node の推奨バージョンが 6.9 のようなので、6.9 にします。
(頑張れば、最新バージョンの Node でも動くかもしれませんが、何か不具合が出ると嫌なのでおとなしくバージョンを変更します)

自分の場合は `n` を使っていたので、すんなりできました。
`nvm` の場合は注意が必要そう…？

```shell:n&nbsp;の場合
sudo n 6.9
```

参考「[Supported Node Versions](https://docs.ghost.org/docs/supported-node-versions)」(Ghost)
参考「[Using nvm - Troubleshooting](https://docs.ghost.org/docs/troubleshooting#section-using-nvm)」(Ghost)
参考「[GitHub - tj/n: Node version management](https://github.com/tj/n)」(`n`)

# 2. Ghost インストール

作業したいディレクトリ内で、

```shell
npm init -y
npm i -D ghost-cli # ローカルで使用するだけと仮定して、おそらく -D で良いと思います

mkdir ghost
cd ghost

npx ghost install local # ローカルなので local
npx ghost stop # install が成功すると自動で start されるので、止めたいときは stop
```

自分がやったときは、install 中に通信エラーが発生して一度止まってしまったのですが、再度 `npx ghost install local` したら上手く行きました (再インストール時は ghost install しようとしているフォルダを空にする必要あり) 。

ローカルの場合は、特に config をいじらなくても良さそう。

(普通は -g で `ghost-cli` をグローバルインストールするのでしょうが、今回は「とりあえず」ということもあって、グローバルにせずやってみました)

参考「[Install (local / dev)](https://docs.ghost.org/docs/install-local)」(Ghost)

# 3. Ghost 動かす

```shell
npx ghost start
```

あとはブラウザで色々。

- `http://localhost:2368/`
- `http://localhost:2368/ghost` (管理画面)
pickleを試してみた

[pickle](https://wiki.kewl.org/dokuwiki/projects:pickle)というPIC用のライタープログラムの存在を知りMac OS X雪豹で試してみた。

ソースファイルをダウンローしてmakeしたところsrc/Makefileのリンク時のmapの設定を削除しないとビルドできなかったが、外してバイナリはできた。

とりあえずPIC32MX220F032Bで試してみて、FTのシリアルでの接続は以下の通りにした。

|FT|Pin|PIC32MX220F032B|Pin|
|:--|:--|:--|:--|
|TX|1|MCLR|1|
|RTS|3|PGC1|5|
|DTR(100Ω)|5|PGD1|4|
|CTS|4|PGD1|4|

この他に電源とグラントと通常通りつないでおきます。Vcapのコンデンサーも必要です。

バイナリーはインストールせずに試してみようと思ったが、pickleは実行ファイル名で処理を変えるようなので、p32からpickleへのシンボリックリンクを作ってみた。

設定ファイルは~/.pickleで以下を書いた。

```
DEVICE=/dev/tty.usbserial-000015FDA
SLEEP=0
BITRULES=0x001F
```

```
bash-3.2$ ./p32 id
[1D000000] [PROGRAM]  00002000 WORDS
[1F80F220] [DEVICEID] 04A00053 VER:0 DEV:4A00 MAN:053 PIC32MX220F032B
[1FC00000] [BOOT]     00000300 WORDS
[1FC00BF0] [DEVCFG3]  FFFFFFFF
[1FC00BF4] [DEVCFG2]  FFF8FFD9
[1FC00BF8] [DEVCFG1]  FF7FFEF8
[1FC00BFC] [DEVCFG0]  7FFFFFFF
```

```
bash-3.2$ ./p32 program test.hex
Total: 2556
```

非常に遅いです。wikiにあるPEを入れるとちょっと早くなるようですが、それでも結構遅いです。

src/MakefileをいじってlibftdiをリンクしてFTのbitbangを使えるようにしたのですが、シリアルでのアクセスより遅くなってしまいました。作者に聞いたら、ラズパイZeroは早いって事のようです。微妙に釈然としないのですが。。。
<input type="file"> で入力された画像をサムネイル表示する（Pure JS）

# 概要

画像のアップロードをする前にユーザが選択した画像をサムネイル表示する機能をライブラリを使わずに実装します。


# 実装

```index.html
<input type="file" onchange="onChangeFileInput(this)">
<div>
  <img id="thumbnail" accept="image/*" src="/img/icon_add.png">
</div>
```

```script.js
const onChangeInputFile = (e) => {
  if (e.target.files && e.target.files[0]) {
    const reader = new FileReader();
    reader.onload = function(e) {
      document.getElementById('thumbnail').setAttribute('src', e.target.result);
    };
    reader.readAsDataURL(e.target.files[0]);
  }
};
```
```style.css
#thumbnail {
  height: 100px;
  max-width: 100px;
  margin: 10px;
  border: solid thin lightgray;
  border-radius: 5px;
}
```

ファイルが選択されていない状態だと不自然なぺしゃんこ四角形ができるので、100×100 の画像（icon_add.png）をセットしています。

# 利用例

<img width="317" alt="before.png" src="https://qiita-image-store.s3.amazonaws.com/0/43328/f1eddf75-ffad-bf31-de90-757a1a7dffaa.png">
　:point_down:
<img width="264" alt="after.png" src="https://qiita-image-store.s3.amazonaws.com/0/43328/44414b42-6c2e-8cac-f8d0-36fd9b06df0f.png">

※ イラストの出典: [手巻き寿司のイラスト（いらすとや）](https://www.irasutoya.com/2013/05/blog-post_6945.html)

# 参考
* https://stackoverflow.com/questions/4459379/preview-an-image-before-it-is-uploaded
自然言語APIで京都の良い回しを感情分析してみた結果

自然言語のAPIを使って結果を眺めたり集計しています。そんな中でセンチメント分析の面白い傾向を見つけたのでメモ。

#皮肉っぽいコメントが分析数値が合ってなさそう問題
例えば、この記事 → [爆死案件が続々「クールジャパン」はこんなにひどいことになっていた](http://gendai.ismedia.jp/articles/-/55359)。見た感じ、うわーな案件だと思いまして、ネガティブなコメント結構ついてるかなとおもったら、ポジティブなスコアがちらほらありました。おやと思って、ポジティブ判定された文章の詳細を見ると、

| 文章       |     スコア |    分類   |
|:-----------------|------------------:|:------------------:|
| 関係者の財布がクールになってるからいいんじゃね（棒） | 0.9 | ポジティブ |
| COOLからHOTになっちまうよ | 0.8 | ポジティブ |
| 日本のことがよく分かって良かったですね | 0.8 | ポジティブ |
| こんなに期待通りになるんなんて流石に予想外だよ | 0.6 | ポジティブ |
| お友だちに国の金あげるジャパン | 0.6 | ポジティブ |
| 俺もなー 責任取らなくて良いお金で大手を振ってみたいもんだぜ | 0.6 | ポジティブ |

こんな感じで、皮肉っぽい文章は概ねポジティブと捉えられてしまうことを発見しました。人間が文章を読むと皮肉だと気づきますが、機械で判定するには難しいんですかね。言葉通りに受け取るとポジティブに捉えられてしまうという。

また、ひねった言い回しとかも感情分析の精度悪いような印象あります。

#京都の言い回しを感情分析してみる
皮肉といえば、最近京都の言い回し（ぶぶづけ食べる？的なやつ）が話題になってたなーと思いまして、その言い回しを感情分析するとどうなるんだろうと思ってやって見ました。

予想はスコアはポジティブになるだろうなという予想です、が結果はいかに、、、
参考：[Twitter発。『京都（人）、すげえ…』ってなる報告](https://matome.naver.jp/odai/2147434364894758501)

| 文章       |     スコア |    分類   |
|:-----------------|------------------:|:------------------:|
| 楽しそうでよろしおすなぁ | 0.9 | ポジティブ |
| はんなりしてはるわぁ | 0.1 | ニュートラル |
| あらまぁ、しっかりしてはるわぁ | 0.2 | ニュートラル |
| えらいお人どすなぁ | 0.2 | ニュートラル |
| お茶いる？　| 0 | ニュートラル |
| アンタいつ見ても元気そうやなぁ | 0.8 | ポジティブ |
| たいそう元気でいらっしゃいますなぁ、外で走ってきはったらええんちゃいます？ | 0.4 | ポジティブ |

でした。とはいえ、京都の言い回しに限らず、ストレートに受け取ったらポジティブに受け取る内容ですから、判断は難しいですね。というか人間でも判断できないかも。。

# まとめ
自然言語APIは言葉通りを分析するしかないため、皮肉な言い回しの文章のセンチメント分析は難しそうですね。皮肉も文章通りに受け取るとポジティブな内容ですからね、、、この部分も解析しようとするのは、、、そもそもできるのだろうか。
褒めてるようで本当は褒めてない、ような文章って結構多いですよね、、、こういった内容をどう扱って集計するのもテクニックの一つなのかなと感じました。
centOS7にGitLab環境構築

centOS7にGitLabのCEを構築する。
yumやcurlはプロキシ経由でアクセスする。

#yumにプロキシ設定
下記を追加する。

```/etc/yum.conf
proxy=http://{proxy}:{port}
```

#更新する
```
yum -y update
```

#curlにプロキシ設定
新規ファイルを作成する。

```~/.curlrc
proxy=http://{proxy}:{port}
```

#GitLabパッケージリポジトリを追加
curl https://packages.gitlab.com/install/repositories/gitlab/gitlab-ce/script.rpm.sh | sudo bash


#GitLab CEをインストールする
```
yum install -y gitlab-ce
```

#設定ファイルを修正
```/etc/gitlab/gitlab.rb
external_url 'http://XXXXX'
```
外部連携した場合のURLの「external_url」を修正する。

```/etc/gitlab/gitlab.rb
gitlab_rails['time_zone'] = 'Asia/Tokyo'
```
タイムゾーンを「Asia/Tokyo」に変更する。

#GitLabを起動する
設定再構築を行う

```
gitlab-ctl reconfigure
```

アクセスするとrootのパスワード設定画面が表示されるとOK！
正規表現でクォーテーションマークに囲まれた部分を抽出

# 概要

ログのパースなどで、クォーテーションマークに囲まれた部分を抽出したい

```sample.log
2018/03/31 08:00 text='this is my text.'
```

# コード

## 最初に考えた方法

囲まれた部分を抽出するので、[RegExp#exec](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/RegExp/exec) を利用します。

```js
const str = "text='this is my text.'";
const regex = /='(.*?)'/;
const matched = regex.exec(str);

if (matched) {
    console.log(matched[1]);
}
```

```text:output
this is my text.
```

ただしこの正規表現では、下記のようにエスケープされたシングルクォート「`\'`」が入った場合に正しく抽出できません。

```sample2.log
text='this is my son\'s text.'
```

```js
const str = "text='this is my son\\'s text.'";
const regex = /='(.*?)'/;
const matched = regex.exec(str);

if (matched) {
    console.log(matched[1]);
}
```

```text:output
this is my son
```

## エスケープ文字を考慮した正規表現

否定的後読み（`?<!`）を利用して、直前に「`\`」のあるシングルクォートを囲み文字としないようにします。

```js
const str = "text='this is my son\\'s text.'";
const regex = /='(.*?)(?<!\\)'/; // <- ここ
const matched = regex.exec(str);

if (matched) {
    console.log(matched[1]);
}
```

```text:output
this is my son\'s text.
```

否定的後読みについては↓のページがわかりやすかったです。

* [正規表現の先読み・後読みを極める！ | あらびき日記](https://abicky.net/2010/05/30/135112/)
macportsでパッケージがインストールができない時の対処法

macportsでパッケージをインストールしようとしたら、突然出来なくなった。
のでそんな時の対処法。

###エラー
portをsyncするとエラーが出る。
ちなみに、指示されたselfupdateをしてもダメ。

```
$ port search gcc
Warning: Can't open index file for source: rsync://rsync.macports.org/macports/release/tarballs/ports.tar 
Error: search for name gcc failed: No index(es) found! Have you synced your port definitions? Try running 'port selfupdate'. 
No match for gcc found
```

###対処法
####1.sources.confを書き換える
端的に言えばportを持ってくるurlを変更する。

```
$sudo vi /opt/local/etc/macports/sources.conf 
```
```
#rsync://rsync.macports.org/macports/release/tarballs/ports.tar [default]←コメントアウト
 http://www.macports.org/files/ports.tar.gz [default]
```

####2.portをアップデートする
Portをアップデートする。
下記のように上手くsync出来ていたらOK。

```
$ sudo port -d sync 
DEBUG: Copying /Users/XXXXXX/Library/Preferences/com.apple.dt.Xcode.plist to /opt/local/var/macports/home/Library/Preferences 
--->  Updating the ports tree 
Synchronizing local ports tree from http://www.macports.org/files/ports.tar.gz 
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current 
                                 Dload  Upload   Total   Spent    Left  Speed 
100   178  100   178    0     0    679      0 --:--:-- --:--:-- --:--:--   679 
100 32.7M  100 32.7M    0     0  3239k      0  0:00:10  0:00:10 --:--:-- 4352k 
```
GitLabとMattermostの連携

GitLabでpushやissue登録したら、Mattermostのチャネルにメッセージが連携されるようにする。

#Mattermost側のWebhookを設定する。
メニューの*統合機能*を選択する。

![mattermost_gitlab.png](https://qiita-image-store.s3.amazonaws.com/0/79214/4c144816-c0f6-3299-20f1-766bc78d9cca.png)

![mattermost_gitlab2.png](https://qiita-image-store.s3.amazonaws.com/0/79214/3a06a879-6e58-66f1-51ab-7171f9ac1121.png)

![mattermost_gitlab3.png](https://qiita-image-store.s3.amazonaws.com/0/79214/a93f1f7b-8fe5-e8ef-4e69-2b12a7f10bd3.png)
チャネルは連携したいチャネルを選択する。
内容を入力し登録する。
表示されるURLはGitLabに設定する。

#GitLab
![mattermost_gitlab4.png](https://qiita-image-store.s3.amazonaws.com/0/79214/61f4655f-9f89-1394-acc9-a74241d71b22.png)

Mattermost notificationsを選択すると、設定画面が表示される。
- WebhookにURLを設定する。
- 連携したい項目をチェックして登録する。

上記の設定だけで連携されます！
hidden_fieldにenumの値を持たせる

# はじめに

submitボタンのみを利用してdbの情報を更新したい時に、hidden_fieldをしようとすると、valueの持たせ方やenumの場合のvalueの持たせ方がすぐにみつからなかったので調べました。

## hidden_fieldの基本的な書き方
`hidden_field(オブジェクト名, プロパティ名 [, オプション])`

## enumを利用する場合の書き方
`<%= f.hidden_field :approval, {value: 'enumで定義したキー名'} %>`

## 例

```rails:model 
enum approval: { pending: 0, approved: 1, rejected: 2 }
```

```rails:view
<%= form_for　([@user, interview]) do |form| %>
  <%= f.hidden_field :approval, {value: 'approved'} %>
  <%= f.submit %>
<% end %>
```

# 参照
[Set a Rails form hidden field from enum model - Stack Overflow](https://stackoverflow.com/questions/25025685/set-a-rails-form-hidden-field-from-enum-model)
シェルピンスキーの三角形を描いてみる

# イントロ

興味あることをやろうとしていたら、シェルピンスキーの三角形と似た操作が出てきた。
これはこれでおもしろそうなので、参考がてらに軽く触れてみた。

Julia Notebook
https://gist.github.com/Lirimy/02d65e0d7589b7ab6a65dc0c4e22ac0a

シェルピンスキーの三角形の概要
https://en.wikipedia.org/wiki/Sierpinski_triangle

# パスカルの三角形

1. 左上のマスを１にする
2. 空きマスの値を、左と上の数字の和で求める
3. 繰り返して全てのマスを埋める
4. 奇数を白・偶数を黒で塗る

| 1 | 1 | 1 | 1 |
|---|---|---|---|
| 1 | 2 | 3 | 4 |
| 1 | 3 | 6 | 10|
| 1 | 4 | 10| 20|


![sier-pascal360.png](https://qiita-image-store.s3.amazonaws.com/0/202534/c5f84f9c-dbbc-3cad-d1ee-18c91e2c363c.png)

結局のところ偶奇だけが問題なので、演算は 0/1 に対して XOR をとればよい。
実装上もそうしてある。

# セル・オートマトン（ルール90）

http://atlas.wolfram.com/01/01/90/

1. 1行目に初期値を与える
2. 次の行のマスの値を、前の行の近傍３マスから求める
3. 繰り返す

近傍３マスのうち、実は真ん中のマスは次のマスに影響しない。
影響する両端２マスと出力マスだけに注目すると、 XOR の関係になっている。
よって、パスカルの三角形と同じ仕組みだと言える。

真ん中だけ１で初期化
![sier-rule90-360.png](https://qiita-image-store.s3.amazonaws.com/0/202534/dce55f48-f2ac-6131-d3e4-c728e05faf39.png)

乱数で初期化
![sier-rnd-360.png](https://qiita-image-store.s3.amazonaws.com/0/202534/59e5bc99-ef0c-92cc-c9a5-707f7206a3b1.png)

# カオス・ゲーム

http://paulbourke.net/fractals/gasket/

1. 三角形の頂点 （P1, P2, P3） を決める（下図の青丸）
2. 初期点 S を適当に決める（実装上は内部の点を指定した）
3. P1, P2, P3 からランダムに１点選び、P とする
4. S と P の中点を次の点 S にする
5. 繰り返し S を求める

1000 点プロットした
![sier-chaos-15dpi.png](https://qiita-image-store.s3.amazonaws.com/0/202534/d21042bc-aeae-59a9-a4a3-9299ab86f58c.png)
docker-compose V3 で extends っぽい事をする


docker-compose の V2 には`extends`ってのがありまして、これを使って別のサービスの設定を継承する事が出来たんですが、`V3`になってからは無くなってしまったようです。。

```yaml
---
# docker-compose.common.yml

version: '2'


services:
  base:
    image: php:7.2-apache
    volumes:
      - ./index.php:/var/www/html/index.php
    environment:
      TITLE: ドッカーコンポーズ

```

```yaml
# docker-compose.yml

---
version: '2'


services:
  front:
    extends:
      file: ./docker-compose.common.yml
      service: base
    container_name: front
    ports:
      - 8000:80
    environment:
      MESSAGE: フロントだよ

  admin:
    extends:
      file: ./docker-compose.common.yml
      service: base
    container_name: admin
    ports:
      - 8001:80
    environment:
      MESSAGE: アドミンだよ
```

上記を `version: '3'` にすると以下のエラーが出ます。

```console
ERROR: The Compose file './docker-compose.yml' is invalid because:
Unsupported config option for services.admin: 'extends'
Unsupported config option for services.front: 'extends'
```

なので、yamlの [アンカーとエイリアス](http://magazine.rubyist.net/articles/0009/0009-YAML.html#%E3%82%A2%E3%83%B3%E3%82%AB%E3%83%BC%E3%81%A8%E3%82%A8%E3%82%A4%E3%83%AA%E3%82%A2%E3%82%B9) を使ってあげると、それっぽい事が出来るようになりますよ。

```yaml
---
version: '3'


services:
  front: &front  # アンカー
    image: php:7.2-apache
    container_name: front
    volumes:
      - ./index.php:/var/www/html/index.php
    ports:
      - 8000:80
    environment:
      TITLE: ドッカーコンポーズ
      MESSAGE: フロントだよ

  admin:
    <<: *front  # エイリアス
    container_name: admin
    ports:
      - 8001:80
    environment:
      TITLE: ドッカーコンポーズ
      MESSAGE: アドミンだよ
```
MySQLのログイン

# LinuxからMySQLにログイン

#### 短縮する版
<pre>
$ mysql -u username -ppassword db_name
</pre>
#### 短縮しない版
<pre>
$ mysql --user=username --password=password db_name
</pre>

- 2018/05/10追記。コマンドを打ったらログインできなかった。でもシェルにして実行するとログイン出来た。
　
- -pの後にスペースなどを入れずにパスワードを入れること。
- db_nameは後で指定しても良い。
ログインした後にuse db_nameでDB変更できる。
- パスワードが見えちゃうから基本的にはおすすめしない。基本的には↓のログインを使う。

#### 普段はこちらでログイン
<pre>
$ mysql -u ユーザ名 -p
Enter password: password 
</pre>
- この方法だとパスワードは見えません。




参考
[6.3.1 ユーザー名とパスワード](https://dev.mysql.com/doc/refman/5.6/ja/user-names.html)
[MySQLコマンドまとめ](https://qiita.com/merrill/items/967884c02e10bd8f32f5
)
CoffeeScriptの小さなサンプルメモ

```coffeescript

console.log("Hello")

# 関数
myTest = (msg) ->
  console.log(msg)

myTest("hogehoge")

# 関数、戻り値あり
showTest = (msg) ->
  msg + "hogehoge" # return

console.log(showTest("---"))

# 連想配列
menu =
  coffee: 100
  cake: 200

console.log menu["coffee"]
console.log menu.cake

# クラス
class Test
  # コンストラクタ
  # 引数にそのまま @ をつけるとthisのプロパティとなる
  constructor: (param1, @param2) ->
    console.log("constructor")
    @param1 = param1 # @に入れることで、thisのプロパティとなる

  # メソッド
  tensu: ->
    console.log("misenai")

  # メソッド（引数）
  tensu2: (msg) ->
    console.log(msg)

  # 静的メソッド
  @seitekitensu: ->
    console.log("seiteki tensu")

  # 静的プロパティ
  @seitekivalue: "seitekivalue"

  show: ->
    console.log(@param1)
    console.log(@param2)

  show2: ->
    @show() # this.show()


test = new Test("param1", "param2")
test.tensu()
test.tensu2("222")
test.show()
test.show2()

Test.seitekitensu()
console.log Test.seitekivalue
```

```sh:実行結果
 % coffee hello.coffee 
Hello
hogehoge
---hogehoge
100
200
constructor
misenai
222
param1
param2
param1
param2
seiteki tensu
seitekivalue

```
[GAS]RocketChatへのPOSTがうまくいかなくなった話

# RocketChatへのPOSTがうまくいかなくなった話
なんだか、2018年4月に入ってから、GASからロケチャに飛ばしていたメッセージが空で飛んでしまう。
エラー内容とか送らせていたし困るなぁ・・・。
​
## 結論
公式ドキュメント通り手を抜かずにやりましょう!ということです。
​
### エラー出てたやつ
手を抜いて、 `contentType` とか省いてたんですよね。
いや、動いてたし。。。

```javascript
// ロケチャ送信用関数
function send_rocketchat(
  text
){
  res
    = UrlFetchApp
      .fetch(
        "https://chat.leverages.jp/hooks/Pi8sjveH3qYu8FeLx/mEB4kng92jPBhRLzCwjPYbD8gi2bYAtNcSYiAhwHavPJBACu"
        , {
          "payload" : JSON.stringify({
            "text" : text
          })
      });
  Logger.log(res);
}//func_send_rocketchat
```

### 直したやつ
きちんと明示したら動くようになりました。

```javascript
// ロケチャ送信用関数
function send_rocketchat(
  text
){
  var data
    =  {
      'text' : text
    };
  var options
    = {
       'method' : 'post'
     , 'contentType': 'application/json'
     // Convert the JavaScript object to a JSON string.
     , 'payload' : JSON.stringify(data)
    };
  res
    = UrlFetchApp
      .fetch(     "https://chat.leverages.jp/hooks/Pi8sjveH3qYu8FeLx/mEB4kng92jPBhRLzCwjPYbD8gi2bYAtNcSYiAhwHavPJBACu"
        , options
      );
  Logger.log(res);
}//func_send_rocketchat
```
​
## 備考(教訓)
公式ドキュメントはちゃんと読んで、準拠しようね。（笑）
[Class UrlFetchApp](https://developers.google.com/apps-script/reference/url-fetch/url-fetch-app)

そういえば、Slackは問題なかったんだろうか?
​
Flexible Heredoc and Nowdoc Coming to PHP 7.3

[Laravel News](https://laravel-news.com/)には良記事が満載なので、備忘録の意味合いも込めて、記事を簡単にまとめていこうと思います（翻訳ではないです）。

# 元記事
投稿日: 2018/04/19
タイトル: Flexible Heredoc and Nowdoc Coming to PHP 7.3
URL: https://laravel-news.com/flexible-heredoc-and-nowdoc-coming-to-php-7-3

# まとめ
PHP 7.3で使いやすくなるヒアドキュメントの説明です。
ヒアドキュメントは用途がよく分からないんで使ったことないので参考記事を参照してください…。
こんな便利な使い方あるよ！という方はぜひコメントで教えてください。

# 参考
[フレキシブルなheredocがやってくる](https://qiita.com/tadsan/items/3e5a094cd57e430b6ea9)
Kerasでepoch毎にモデルの予測結果を残す

# メモ
Kerasのfit_generatorを使って学習する際に、学習の進み具合をモデルの出力（predict)の結果として残しておきたかったので、callbackを使って実現しました。


```python
class SavePredictionCallback(keras.callbacks.Callback):
    def __init__(self, tests, **kwargs):
        super().__init__(**kwargs)
        self.tests = tests

    def on_epoch_end(self, epoch, logs={}):
        outputs = self.model.predict(self.tests, verbose=1)
        if not isinstance(outputs, list):
            outputs = [outputs]
        for i, output in enumerate(outputs):
            // 非正規化等の後処理
            // 保存。出力が画像であれば、以下のように保存してみたり。
            // cv2.imwrite('./out/epoch{}_{}.png'.format(epoch, i), output)

model.fit_generator(train_data_generator,
                    callbacks=[SavePredictionCallback(tests)])
```

# 参考資料
- [コールバック - Keras Documentation](https://keras.io/ja/callbacks/)