OmniAICreator/Qiita-1.07M huggingface dataset:
nuxt.js は axios を捨てて ky になる様子

nuxt.js は node.js でもブラウザ上でも動作することが求められるため、統一したインターフェースで HTTP リクエストを行うには、何かしらのライブラリを利用する必要があります。

これまで nuxt.js が公式でサポートし、強く推奨していたのは [axios](https://axios.nuxtjs.org/) と呼ばれるライブラリです。

これは、ブラウザでは `XMLHttpRequest` を用い、 node.js では `http` モジュールを用いる基本的なユニバーサル HTTP リクエストライブラリです。

しかし、 service worker によるサポートを受けるためには [fetch API](https://developer.mozilla.org/ja/docs/Web/API/Fetch_API) を利用する必要があったり、 axios の実装自体が結構煩雑で使いづらいように見えたりと、弱点もありました。

そこで、コミュニティでは新しく [@nuxt/http](https://github.com/nuxt/http) というモジュールを開発し始めました。

現在では WIP ですが、ほとんどの機能において十分な状態になっていると思います。

この新しいモジュールは [sindresorhus/ky](https://github.com/sindresorhus/ky) ライブラリをベースとしています(初めて聞いた)。

[awesome-nodejs](https://github.com/sindresorhus/awesome-nodejs) などを公開しているかなり JavaScript 界隈に強い人のプロダクトのようです。

axios と比べると、

- 軽量
- fetch API を利用するので service worker との親和性が向上
- node.js 側は [node-fetch](https://github.com/bitinn/node-fetch) を用いてほぼロジックなしで対応(強い)

と、いろいろ良い感じに見えます。

致命的な弱点として、 **リクエスト Progress が取得できない** です。

これは、 fetch API 自身がその機能を提供していないため、ライブラリレベルではどうしようもないですね。

もし Progress が必要な場合(ファイルのアップロードとか)は、諦めて XMLHttpRequest を利用しましょう。

[追記: 2019/05/22]

コメントで @yuta0801 さんに教えてもらいましたが、 fetch API でも [ReadableStream](https://developer.mozilla.org/en-US/docs/Web/API/Streams_API/Using_readable_streams) を使って Progress を取得出来るようです。

これは [ある程度最新のブラウザ](https://caniuse.com/#feat=streams) では既にサポートされているので、例えば [ky であれば `onDownloadProgress` オプションで](https://github.com/sindresorhus/ky/blob/5a0e901daf914a4062b8a96eb326d01cec2644e2/index.js#L332) 進捗を取得することが可能でした。

また、リクエストのキャンセルも [AbortController](https://caniuse.com/#feat=abortcontroller) を使えるブラウザであればキャンセル可能です。

IE さえ捨てれば XMLHttpRequest(≒axios) も捨てれる世界になりつつありますね。
PWAについて調べてみた件

#きっかけ
アルバイト先のサービスにPWAを導入したので、使ったうえで知識を深めるためにももう一度しっかり調べてみようと思ったためです。

#そもそもPWAって？
PWAはプログレッシブウェブアプリの略で、2015年にGoogleからリリースされた技術です。
イメージはWeb経由で提供されるネイティブアプリのようなものかな？
ネイティブアプリとモバイルブラウザのいいとこどりをしたようなものともいわれているようです。
Service Workerを使って構築されているようです。
ブラウザのバックグラウンドでJsを実行するので、プッシュ通知などが使えるようです。

#なんでまた注目されてるの？
2015年にリリースされてから少したってるのになぜ昨年（2018年）からまた盛り上がってるのか？
それは2018年3月にSafariがPWAに対応したため、iOSのユーザーに対してPWAのページが提供できるようになったためではないでしょうか？
これは調べているうちに思ったので完全なる個人的見解です。

#PWAの特徴
##いいところ
- 通常のWebページに比べてページの読み込みが速い
⇒バックグラウンドで読み込んでおくので
- アプリを端末にインストールする必要がない
- ホーム画面にアイコンを追加できる
- UIをネイティブアプリによせられる（フルスクリーン表示など）
- プッシュ通知を使える
- キャッシュを使うことでオフラインでの動作が可能になる
- 動作するOSをあまり考えず作れる

##気になるところ
- ブラウザによって挙動が異なる点がある
- ダウンロード数やアンインストール数が把握できない

#PWAとネイティブアプリの違い
|PWA  |項目  |ネイティブアプリ  |
|---|---|---|
|なし※1  |アプリストアの有無  |あり  |
|クロスプラットフォーム（考慮しなくてよい）  |プラットフォーム  |考慮しないといけない＝開発コストがかかる  |
|検索エンジンでアプリ内のコンテンツも！|検索（SEO）|タイトルとタグで検索|
※1現在ではGoogle Play Storeで配信可能　TWAを使うことで可能にしているようです

#PWAとモバイルブラウザの違い

|PWA |項目 |モバイルブラウザ |
|---|---|---|
|瞬時（バックグラウンドであらかじめ読み込んでおくため）  |読み込み速度  |ものと環境によりけり  |
| フルスクリーンなど |表示  |URL欄など表示がある  |

#終わりに
まだまだ知らないことが多いので来週いくPWA Nigthで色々吸収してきたいと思います。
MarkdownをWordのテンプレートを充てつつdockerのpandocでWordに変換する

設計書をMarkdownにしてGitで管理出来ないかという話が出てきたので、
環境構築及びMarkdownファイルにテンプレートを充てるまで実施してみる。

## 確認環境

* Mac OS Mojave 10.14.3

## 前提

* [docker](https://www.docker.com/products/docker-engine)がインストールされていること。

## 手順

サンプル用のMarkdownファイルを取得。

```shell
$ curl https://raw.githubusercontent.com/mitsuaki1229/Sample/master/Documents/ForPandockConversionFile/ForPandockConversionFile.md -o ForPandockConversionFile.md
```

変換時にレイアウトとして充てる無料のテンプレートを拝借し、解凍。

```shell
$ curl http://siland.jp/data/manual.zip -o manual.zip
$ docker run --rm -v `pwd`:/data ca54makske/ubuntu-unzip -Ocp932 ./manual.zip
```

拝借したテンプレートを充てつつMarkdownファイルからWordファイルを生成。

```shell
$ docker run -v `pwd`:/source jagregory/pandoc -f markdown -t docx README.md -o README.docx --reference-doc='業務マニュアル（テンプレート）/グリーン.docx'
```

### 結果

```shell
$ open README.docx
```

![Screen Shot 2019-04-10 at 16.43.30.png](https://qiita-image-store.s3.amazonaws.com/0/25578/d96b250b-bf2f-6b3d-be9a-912d2b7a85db.png)

以前いた職場で設計書やマニュアルをMarkdownからpandocを利用してWordやPDFに変換していた際は、
ローカルのPCに環境を構築するのが大変だった記憶があるが、dockerだとすぐ出来て楽。
Wordのテンプレートのレイアウトと、Markdownのタグを上手く脳内マッピングすればいい感じに出来そうだけど、
良い感じの変換結果にしたい場合、Wordのレイアウトを作成する知識がある程度必要そう。

## 参考

* [SILAND.JP](http://siland.jp/)
* [Mac で Windowsで作られてしまった日本語ファイル名混じりなzipファイルを解凍したい](https://qiita.com/ca5@github/items/98241be7f53be13b8cae)
* [Pandoc User’s Guide](https://pandoc.org/MANUAL.html)
* [Extended Syntax](https://www.markdownguide.org/extended-syntax/ )
もそ、プログラミングを学ぶ【Ruby & Rails】〜これを読めば君もMVCマスター！〜

試験当日を迎えた もそはそわそわしていた。


試験中はへんな汗をかきっぱなしでしたが、無事に合格できました！
いえ〜〜い！！

ブラック・サバスの試練を乗り越えてスタンドを発動した気分です。


![無題1204.jpeg](https://qiita-image-store.s3.amazonaws.com/0/372174/29d3b34d-af3d-f09d-be74-dcbbd1b2b5e4.jpeg)

↑イメージ図。

とはいえ、まだまだ知識不足だな〜と感じているのが正直なところ。
最強のスタンド使い（※Rails使い）を目指して、応用カリキュラムも進めていこうと思います！


#これで完ぺき！MVCとデータベース！

今回はRails処理についての総集編。
MVCについては[過去の記事](https://qiita.com/moso/private/4a61da06c33fb019b7ab)でも書いてきましたが、勉強している中で

「なんだかMVCとデータベースの関係性がわかりづらいな〜」
「そもそもマイグレーションファイルってどこで出てきて、どんな役割があったっけ？」

と感じることが多かったので、ひとつの図にまとめてみました。

それがこちら！

![無題1195.jpeg](https://qiita-image-store.s3.amazonaws.com/0/372174/3a6950ea-d163-aad0-7d09-33f35d0a562d.jpeg)


この図を見れば一連の処理の流れだけでなく、**マイグレーションファイルの実行**や**アソシエーション**についても理解がしやすいかなと思います。
勉強中の方はぜひ参考にしてみてくださいね。

--
新しいカリキュラムも始まり、いろいろなことを学ぶのが楽しみになってきました。
ゴールド・エクスペリエンス・レクイエム（グーグル変換、予測変換で単語出てきた...すご...）並の力を得るため頑張ろうと思います。
...続く。
HTTP メソッドの定義

# よくある捉え方
CRUD に合わせて以下のように考えがち。

- Create → POST
- Read → GET
- Update → PUT
- Delete → DELETE

しかーし！　ここで多くの人が詰まる。この４つで足りない処理は？　と。
実際にシステムを作ってみればわかるが、この４つでは足らないのが普通なのだ。
しかし、HTTP メソッドを創作するわけにはいかない。何かが間違っているのだ。

# メソッド本来の意味

POST はポスティングのポストである。つまり、投函のイメージ。やった回数分だけ反映される。
GET は取得。何度取得しても、取得したことによって変化を生じさせない。
PUT は置くこと。日本語で言ってしまえば **登録**。何度やっても１度やるのと変わらない。
DELETE は削除。何度やってもよい。成功すりゃ消えとるしね。

# まとめると……

ここで注目したいのが、POST と PUT との違い。POST は呼ばれるたびに作用する。PUT は何度やっても同じデータを登録するだけ。つまり、データベースで ID（主キー）を持つようなデータの登録は、PUT なのだ。いくらそれが初登録で、SQL で言えば INSERT 文であろうと、それは PUT の仕事なのだ。つまり、「日本語で言ってしまえば **登録**」と書いたが、UPSERT とか MERGE と言われる処理全般において、それは PUT の仕事なのだ。ただし、ID（主キー）が自動生成で、呼ばれるたびに増えていくものであれば、ID を示しているわけではなく、新しいものを生成し追加してちょ！ という意味なので、それは PUT ではなく、POST ということになる。つまり、こういうことだ。

| HTTP メソッド | DB 操作 | CRUD | 説明 |
|:-:|:-:|:-:|:-:|
| PUT | INSERT, UPDATE | C, U | 登録 |
| GET | SELECT  | R | 取得 |
| DELETE | DELETE | D | 削除 |
| POST | 単純ではないヤツ | どれでも | 指示、命令、要求など |

POST だけ仲間はずれ。そう、POST は汎用的に使えるメソッドなのだ。つまり、指示書を投函（POST）するイメージ。他の３つは、リソースに対して登録・取得・削除するということ。だから、POST を使用するときは指示の内容は Body に JSON などで書くべき。URL は、その指示書を投函する窓口を指すものであるのが望ましい。
vue.js テキストの改行を有効に

ドラえも～んテキスト改行したいよぉ。
以下のスタイルを適用するだけで自動で改行できるよぉ。

```

<p style="white-space: pre-wrap;" v-text="data.profiles[0].body"></p>

```

かんたんだろ。
PythonでLINEメッセージ送信

# 背景
ただなんとなく…。

# 設定
まずアクセストークンを取得する必要があります。
1. [LINE Notify](https://notify-bot.line.me/ja/)にログインします。
2. マイページの「アクセストークンの発行（開発者向け）」のトークンを発行します。
3. 通知の際に表示されるトークン名とトークルームを選択し発行ボタンを押します。
4. 発行されたトークンが表示されるのでメモします。
5. LINE Notify を連携するグループに招待します。

下準備はここまでです。

# コード
簡易的なコードを記載します。

```py
import requests

url = 'https://notify-api.line.me/api/notify'
token = #アクセストークンを入力
headers = {'Authorization' : 'Bearer ' + token}
message =  #メッセージを入力
payload = {'message' : message}
r = requests.post(url, headers=headers, params=payload)
```

# 備考
実は先にC#で作っちゃいました。

```c#
using System.Net;

var token = //アクセストークンを入力;
var url = "https://notify-api.line.me/api/notify";
var line_enc = Encoding.UTF8;
var payload = "message=" + //メッセージを入力;
using (var wc = new WebClient())
{
    wc.Encoding = enc;
    wc.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
    wc.Headers.Add("Authorization", "Bearer " + token);
    var response = wc.UploadString(url, payload);
}
```

# 参考サイト
* https://webbibouroku.com/Blog/Article/line-notify
* https://qiita.com/tadaken3/items/0998c18df11d4a1c7427
reactアプリをPWA、apk、electronを用いたデスクトップアプリにする方法

## はじめに
reactでPWAを開発し、リリースするまでの手順を説明する。

以下のサイトを参考にした。
[・Reactで学ぶPWA (Progressive Web App)](https://qiita.com/YIPG/items/47f9d025a32effdadcad)
[・Netlifyで静的サイトのホスティングをする](https://qiita.com/sugo/items/2ee64887d682b0dae635)

## PWA化
create-react-appをした際にあるindex.jsを編集
serviceWorkerに登録する

~~~index.js
- serviceWorker.unregister();
+ serviceWorker.register();
~~~

あとはgithubにレポジトリをつくってNetlifyで公開すればよい
「google lightHouse」でPWAになっているかを確認できる

## apk化

pwa2apkというサービスを使う。
https://appmaker.xyz/pwa-to-apk/
あとは手順にそってapkを作成し、play consoleに公開すれば良い。

## electron化

### electronをinstall
とりあえず以下をインストール
~~~ 
npm install --save electron electron-packager electron-is-dev electron--prebuilt electron-log electron-builder concurrently wait-on
~~~

### electron.jsを作成
react-electron-shellを使えばelectronを用いた雛形が簡単にできる

~~~
create-react-app [yourAppName]
cd [yourAppName]
npm install --save react-electron-shell
npm run dev
~~~

electron移行に必要な手順をまとめてやってくれる。
あとはsrcやpublicをコピペすれば良い

### Mac用にpackage化

electron-packagerをインストール
~~~
npm install -d electron-packager
~~~

~~~
"electron-build": "electron-packager ./ todoApp --platform=darwin --arch=x64 --electronVersion=4.1.3 --icon=public/images/icon.icns"
~~~
todoAppは任意のアプリ名にする。--platformはmacなのでdarwinにする。--archは64bitであればx64。--electronVersionは今使っているelectronのバージョン。--iconはicnsファイルのパスを通す。


### windowsにpackage化
上のようにやるとエラーが発生するので以下のサイトを参考にする
http://otiai10.hatenablog.com/entry/2017/10/26/174912
Zabbix で、値が取れるか確認する

# 概要

新しくテンプレートを作ったときなどに、値がうまくとれるか確認したいとき。

Zabbix Serverが動いているホストから、
`zabbix_get` を使う


# 結論

以下のように指定する

```
zabbix_get -s ホスト -k キー[ユーザーパラメータ]
```


# 参考情報

- [ZabbixでアイテムがNot supportedになってからのrefresh時間の設定 - Qiita](https://qiita.com/manabuishiirb/items/fe40d9d423f51a035a7a) 
- [Zabbixでアイテムの状態がNot supported, Unknown などになったときに、通知をもらえるようにする。 - Qiita](https://qiita.com/manabuishiirb/items/5ee84838f6eb21637c88)
セミナーメモ：AWSセミナー　マイグレーション事例祭　デジタルビジネス編

# 概要
2019/4/9 @Amazon目黒

[アジェンダ](https://pages.awscloud.com/AWSMigrationMatsuri20190409-jp.html)
# オープニング
* AWS Ground Station 人工衛星からの信号処理サービス


# グリー：「グリーにおけるAWS移行の必然性」
* 移行推進の背景
    * オンプレ老朽、メンテコスト
    * サーバリソースの効率的利用→柔軟性
    * オンプレ環境のEOLリスク（ルータ、スイッチ、サーバetc）→1機器のリスク（EOL、セキュリティ含めて）が全体に影響

* 反対意見:オンプレ向けの設計コードや内製ツールをクラウド向けに書き換える必要がある、など。

* 移行がもたらしたもの
    * 費用削減効果
        * 2000台のサーバを移設し、39.1%のサーバ費用削減

* 移行のメリット
    * サーバリソース管理
    * 調達リードタイム
    * OS、ミドルのバージョンアップ、レガシー脱却
    * システムの柔軟性、セキュリティ、拡張性の向上

* デメリット
    * 同一ホストに複数インスタンスの場合、複数同時障害の可能性
    * インスタンス確保が難しい場合がある
    * プロダクトごとにアカウントを、わけると一元管理できない
    * 予定イベント（メンテ等）による作業コストあり

* 運用面変化
    * GUI：インフラ作業の敷居低下
    * イベント前後のインフラ作業は増加
    * OSレイヤーレベルで運用しないサービス増加（RDS、ElasticCacheなど）

* 移行の際の反省点
    * テストパターン不足による不具合
    * 移行メンテナンス中にテスト実施できなかった　メンテナンス中の動作環境準備ができなかった
    * 移行後のリソース負荷増大　構成見積りしきれない部分でインスタンス等の構成変更が発生

* 経営と組織マネジメントとエンジニアの相互理解と協力が必須

* 事前の考慮
    * 一気に移行ではなく、中長期的視点が必要
    * システム特性：負荷、トランザクションなど
　　

# CyberZ：「分析環境を AWS Athena に移行とその後1年間の運用課題を振り返る」
* F.O.X.:スマホアプリ向けの広告効果測定ツール
* 手作業での分析処理箇所を"Presto"利用からAWS Athena環境に移行
* Athenaとは？
    * インタラクティブなクエリベースの分析サービス（フルマネージド）
    * クラスタレス、サーバレス
    * JDBC/ODBC


# マッチングエージェント：「 AWS での漸進的なアーキテクチャ変更 at タップル誕生」

* システム刷新の難易度
    * リスク　エラー、通信障害、データロスト
    * その移設は今やる意味があるの？への説明
    * 計画　工程がふえれば不確実性増
    * 影響確認　問題切り分け
    * 切り戻し　可逆性の担保

* 同時に発生する要素は少ないほうが良い
    * 単一の目的に絞っていること
    * 変化の種類　add.update.delete.refacter

* 漸進的　順を追って小さな変化をおこす
    * 影響が起きえることを理解しておくことで正しく対応可能

* 既存システムの課題
    * 構成管理コスト
    * 課題は山積み
        * 優先順位
        * コンテナ化、オートスケール
        * データベースはインスタンス、クラスタ再構築
* 移設を3つのフェーズに分割
    * DBをクラウドAWS移設、Apはプライベート:通信スループット大丈夫？？
        * AWS DirectConnect
        * 専用線でプライベートクラウドとAWSを接続
    * EC2への移設
        * ECSのまえにEC2？
            * パフォーマンス、オートスケール優先
            * 既存のansibleが活用可能
            * 変更要素が少ない
        * Route53 Traffic flow
            * 複雑なルーティングポリシーをわかりやすく設定可能
            * 予期せぬトラブル時にすぐ切り戻しできる
    * ECSへの移設
        * EC2でクラスタ運用
        * Fargateを使わなかった理由
            * 大規模トラフィックを扱う知見がなかった
        * コンテナ化のハードル
            * 以前からコードリファクタで12factorを意識しながら改修：日頃からの意識が重要
        * Traffic Flow利用
        * コンテナ化のメリット
            * 同じイメージ利用で信頼性
            * イミュータブルなので開発言語などのバージョンアップが気軽に
            * オートスケール簡単
            * ロールバック処理容易
                * 以前のタスク定義再適用でロールバック
* 今後の展望
    * マイクロサービス
        * よりスケーラブルな組織、システム
    * マッチングアルゴリズム、不正ユーザ検知
        * データ分析、機械学習
* まとめ
    * システム変化の必要性
    * 漸進性　変化のハードルを下げる

# ニフティ：「リフト＆シフトから始めるレガシー脱却への挑戦～大規模コンテンツ配信サービスの移行実例～ 」

* 独自のJavaフレームワーク　2004年から利用
* 延べ100くらいのサービスで開発運用
    * 開発効率あがらない→レガシーからの脱却

* 社内セキュリティルールにどう適合させるか？

* クラウドベンダー選定
    * 選定基準を先に決める
        * 社内セキュリティ基準への適合
        * 技術者育成の容易さ
        * 拡張性
* 今後
    * AWS内製研修
    * 新規は原則AWS
        * Cognito,Lambda,APIGateway
    * 移行後、モダンシステムに再構築
    * 社内OAのAWS活用:VDI検討中
  
# AWS:「ビジネス基盤をクラウドに移行する際のポイント」
* マネージドサービス
    * 移行大変（アプリを対応させる必要性）
* ベーシックサービス
    * ほぼそのまま持っていくことも可能
* まずはベーシック移行、その後マネージドへ対応
* TSO Logic
* CloudEndure
Pythonのかっこいい書き方まとめ

## TL;DR
人のコードを見ていて、かっこいいなと思ったものをまとめていこうと思います。
かっこいい、かっこ悪いの感じ方には個人差があります。
順次更新 190512

## zipを使って2つのリストを一気にfor loopを回す
普段は

```python
a = [1, 2, 3, 4, 5]
b = [11, 12, 13, 14, 15]
```

上のようなリストのそれぞれ対応している部分をループさせるときにはindexを指定してやってたんですが、zipを使うと同時に回せることを知りました。

```python
#かっこよくないやつ
for i in range(len(a)):
  print(a[i], b[i])
#かっこいいやつ
for x, y in zip(a, b):
  print(x, y)
```

## enumurateを使ってリストとindexを同時に回す
毎回cnt=0を定義してcntを更新するという愚行を繰り返してたんですがenumurateを知ってから非常にいい感じにかけるようになりました。

```python
#かっこよくないやつ
cnt=0
for x in a:
  cnt+=1
  print(cnt, x)
#かっこいいやつ
for i, x in enumerate(a):
  print(i, x)
```

## 全探索するときにitertools.productを使う

a, bの要素を全探索する際にnestを使って二重ループをすると思います。
しかしitertools.productを使うとイテレーターを使って全探索してくれるので綺麗にかけることを最近知りました。

```python
#かっこよくないやつ
for x in a:
  for y in b:
    print(x, y)
#かっこいいやつ
import itertools
for x, y in itertools.product(a,b):
  print(x,y)
```

## numpyアレイの全要素に順番にアクセス
`shape`でアレイの形とってきて、それを使って全探索とかしてましたがこれも`numpy.nditer`を使えばシンプルにかけるようです。書いてて思ったけどめちゃくちゃシンプルになってるかと言われるとわからない。でもかっこいいので。

```python

import numpy as np
arr=np.random.randn(3,3)
print(arr)

column, row=arr.shape
for i in range(column):
    for j in range(row):
        print("("+str(i)+","+str(j)+")")
        print(arr[i,j])

nditer = np.nditer(arr, flags=['multi_index'])
while not nditer.finished:
    print(nditer.multi_index)
    print(arr[nditer.multi_index])
    nditer.iternext()
```

## カレントディレクトリの特定拡張子のファイルリストの取得
osモジュールを使えばできるんですが、globモジュールを使うとシンプルです。`.jpg`ファイルを取得してみます。

```python
import os
import glob

#かっこよくないやつ
jpgs = [file for file in os.listdir('.') if file.endswith('.jpg')]

#かっこいいやつ
jpgs = glob.glob('*.jpg')
```

## 再帰的にディレクトリ内のファイルを取得
os.walkを使ってぐちゃぐちゃやってましたが、これもglob使えばできるらしく
`glob`はすごい！

```python
glob.glob("path/**", recursive=True)
```

## tqdmを使ってプログレスバーを表示する
長いループ回してる時にこれ終わるのか？みたいなことがありますよね。そこでtqdmを使えば簡単にプログレスバーを出すことができます。使い方はiteratorの前にtqdm.tqdmで囲むだけ。

```python
import tqdm

for i in tqdm.tqdm(range(10000)):
  pass
```

こんな感じのプログレスバーが簡単に書けます。

```
100%|██████████| 10000/10000 [00:00<00:00, 1360197.17it/s]
```

## matplotlibの日本語化
基本的にmatplotlibは日本語を認識しません。よくある日本語化手法としては、フォントをいじったりとかが挙げられますが、1行で日本語化できることを知りました。

```
import japanize_matplotlib
```

あ、`pip install japanize_matplotlib`は必要なので、厳密には最初だけ2行ですね。
Raspberry Pi + Apache + Google Cloud Vision API + Slack API を使ってみる

### 目的
- Raspberry Pi をセットアップする。
- Webサーバー (Apache HTTP Server) をインストールする。
- Webカメラで撮影する。
- Google Cloud Vision API でラベリングをする。
- ラベリング結果を Slack に送信する。

### 全体像

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254604/6d13b176-54d1-7170-cdd9-e527953efd32.png)

### 動作確認

http://192.168.x.x/test.jpg
(Raspberry Pi の IPアドレス）

![image.png](https://qiita-image-store.s3.amazonaws.com/0/254604/71bbca7f-19bb-de9a-60e8-969df48bc0ed.png)

受信したスラック

![image.png](https://qiita-image-store.s3.amazonaws.com/0/254604/a2a1b34d-1b45-9a83-f409-99d08ff49519.png)


### Apache
```text
sudo chmod 777 /var/www/html
```

### Python
test.py

```python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import os
import io
from time import sleep
from datetime import datetime
import subprocess
import requests
import json
from google.cloud import vision
from google.cloud.vision import types

def exec_cmd(cmd):
    #r = subprocess.check_output(cmd, shell=True)
    #return r.decode('utf-8').strip()
    subprocess.call(cmd, shell=True)

def take_photo():
    #now = datetime.now()
    #f = now.strftime('%Y-%m-%d_%H-%M-%S') + '.jpg'
    f = 'test.jpg'
    exec_cmd('fswebcam ' + f)

def get_label(file_name):
    #key_path = '/home/pi/*/yourkey.json'
    #os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = key_path

    client = vision.ImageAnnotatorClient()

    with io.open(file_name, 'rb') as image_file:
        content = image_file.read()

    image = types.Image(content=content)
    response = client.label_detection(image=image)
    labels = response.label_annotations
    d = labels[0].description
    s = labels[0].score
    text = 'label: ' + d + ' score: ' + '{:.2f}'.format(s)
    return text

def send_slack(text):
    WEB_HOOK_URL = 'https://hooks.slack.com/services/xxx'
    requests.post(WEB_HOOK_URL, data = json.dumps({
        'text': text,
        }))

if __name__ == '__main__':
    take_photo()
    txt = get_label('test.jpg')
    send_slack(txt)
```

### シェルスクリプト
test.sh

```text
sleep 3
python3 test.py
cp test.jpg /var/www/html/ 
```
apt備忘録: バージョン指定でパッケージを削除/導入するとき

## 経緯
公式・非公式リポジトリを併用しているUbuntu 16.04 でRubyのビルドを行う際、

- [`openssl` パッケージのバージョン由来の問題](https://github.com/rbenv/ruby-build/issues/1173)に突き当たる
- 同名パッケージが各リポジトリにある
- 非公式リポジトリ版が適用済で、公式リポジトリのパッケージに切り換えたい

ことがありました。
これはその際に行った作業の簡単なメモです。

## `dpkg -l`
まずはインストール済のパッケージを確認。
`openssl` 関連のパッケージを一通りチェックします。

```
$ dpkg -l | grep ssl
ii  libgnutls-openssl27:amd64          3.4.10-4ubuntu1.4                          amd64        GNU TLS library - OpenSSL wrapper
ii  libssl-dev:amd64                   1.0.2g-1ubuntu4.15                         amd64        Secure Sockets Layer toolkit - development files
ii  libssl-doc                         1.0.2g-1ubuntu4.15                         all          Secure Sockets Layer toolkit - development documentation
ii  libssl1.0.0:amd64                  1.0.2g-1ubuntu4.15                         amd64        Secure Sockets Layer toolkit - shared libraries
ii  openssl                            1.1.0h-2.0+ubuntu16.04.1+deb.sury.org+1                         amd64        Secure Sockets Layer toolkit - cryptographic utility
```

## `apt show`
続いてパッケージ情報の確認。

```bash
$ apt show openssl
Package: openssl
Version: 1.1.0h-2.0+ubuntu16.04.1+deb.sury.org+1
Priority: optional
Section: utils
Maintainer: Debian OpenSSL Team <pkg-openssl-devel@lists.alioth.debian.org>
Installed-Size: 1,255 kB
...（中略）...
```

出力の最後に以下のメッセージが出る場合は同名パッケージが複数あります。

```
...(中略)...

N: There are 2 additional records. Please use the '-a' switch to see them.

```

`-a` オプションをつけると、残りの同名パッケージもまとめて確認できます。

```bash
$ apt show -a openssl
```

## `apt remove`
インストール済のパッケージをまず削除。
`--purge` オプションで `*.deb` パッケージも含めた完全削除としました。

```
$ sudo apt remove --purge libssl-dev
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following packages will be REMOVED:
  libssl-dev*
0 upgraded, 0 newly installed, 1 to remove and 62 not upgraded.
After this operation, 8,142 kB disk space will be freed.
Do you want to continue? [Y/n] Y
(Reading database ... 69775 files and directories currently installed.)
Removing libssl-dev:amd64 (1.1.1b-1+ubuntu16.04.1+deb.sury.org+1) ...
```

## `apt install`

`apt show` で調べた `Version` 文字列を指定して、特定バージョンのパッケージを導入。
今回は

> Version: 1.0.2g-1ubuntu4.15

を導入したいので、

```
$ apt install openssl=1.0.2g-1ubuntu4.15
```

## 終わりに
**なるべくなら Ubuntu 18.04 LTS つかおうね！！！**

## 参考文献

- [aptコマンドチートシート - @SZUKI_Masaya](https://qiita.com/SUZUKI_Masaya/items/1fd9489e631c78e5b007)
- [Ubuntuでadd-apt-repository: command not foundと言われた時の対策](https://blog.sioyaki.com/entry/2018/05/01/144646)
OAuth2認証のフローを図で簡単に解説

#OAuth2とは？

OAuth2は、ユーザーが自分のデータにアクセスしたり自分に代わって別のWebサービス（OAuthプロバイダー）で何かを実行したりするためにWebサービスまたはアプリケーションに許可を付与するプロセスを合理化するための仕組みです。 4つの異なるOAuth2フローがあり、あなたのニーズに最も合うものを理解するためには、こちらの[記事（英語）](https://blog.oauth.io/choose-oauth2-flow-grant-types-for-app/)を参照してください。この記事では、エンジニア、プロジェクトマネージャ、および投資家が、OAuth2フロー図を通じて、各OAuth２フロータイプの流れを一目で理解できるようにする簡単な紹介になります。

前回公開した[Qiita記事](https://qiita.com/RingCaptcha/items/ac3660b78e3303dda1f9)では、４つのOAuth2グラントタイプをセキュリティー、実装の難しさ、活用度の３つの観点から比べて説明しました。この記事では、４つ並べてやり取りの仕組みを比べまました。そして、各OAuth2タイプに置いて（ユーザー、ウエブブラウザー/ネイティブAPP、ウエブサービス、OAuthプロバイダー）の間でのデーターのやり取りをわかりやすく比べています。

#全てのOAuth2フローでの共通する事柄

全てのOAuth2フローは、同じ目的をゴールにしています。

* ユーザーから一連の権限を委譲された事を表す認証キー/アクセストークンを取得し、ユーザーに代わって何かを実行する。

上記のゴールを達成する為に、２つの方法があります。

1. アクセストークンの取得
    * ユーザの認証キー/アクセストークンをOAuthプロバイダ（例：Twitter）から取得します。 
1. アクセストークンを使用する
    * 承認キー/アクセストークンを使用して、ユーザーに代わり保護されたAPIエンドポイントを呼び出すことで何かを実行します（ツイートを投稿するなど）。

#全てのOAuth2フローでの異なる事柄

全てのOAuth2付与タイプフローは、メインフローの最初の部分だけが異なります。

* アクセストークンの取得方法が違います。

原則として、アクセストークン取得フローには5つのステップがあります（下の図を参照）。

1. クライアントID/クライアントシークレットを取得するために、OAuthサーバーにクライアント（アプリ）を事前登録する。
2. OAuthサーバーは、ユーザーがクライアントIDで、紐付けされたアプリのソーシャルログインボタンをクリックしたときに、ユーザーを認証します。
3. OAuthサーバーは、アプリがユーザーに代わって、何かを実行できるようにするためにユーザーの許可を求めます。
4. OAuthサーバーはシークレットコードをアプリに送信します。
5. アプリは、シークレットコードとクライアントシークレットを提示することによって、OAuthサーバーから認証キー/アクセストークンを取得します。

<img width="1198" alt="OAuth-Flow-Comparison.png" src="https://qiita-image-store.s3.amazonaws.com/0/192668/5a097cdf-eaa8-824e-ae86-cdbc20bb392f.png">
OAuthフロー図解

注釈：

* 雲のアイコンは、アプリ
* wwwアイコンは、ユーザー/ブラウザ
* 金庫のアイコンは、OAuthプロバイダー
* ”ー”は「該当なし」を意味します。つまりそのステップは必要ありません。

##認可コードタイプ(Authorization Code Grant Type)

認証コード（左から3番目）のグラントタイプフローが5つのステップすべてを含み、そして、キー/アクセストークンはApp（バックエンド）に対してのみ発行されるため最も安全であることが簡単にわかります。これは十分に保護されているため（ステップ＃5）、システムの攻撃される対象が少ないです。

##インプリシットタイプ(Implicit Code Grant Type)
インプリシットタイプフロー（右端）は、ステップ＃4が必要ありません。つまりOAuthサーバーがキー/アクセストークンをユーザーブラウザに直接返すことを除いて、認証コードタイプと最も似ています。これにより、キー/アクセストークンがブラウザに保存されるため、システムの攻撃される対象が多いです。なぜなら、App（バックエンド）よりもインターネットに晒されています。更新出来ない、有効期限が短いプロビジョニングキー/アクセストークンによってリスクを軽減出来ます。
インプリシットタイプは、シングルページアプリ（SPA）やネイティブモバイルアプリなど、アプリにバックエンドがない場合に有効です。

##クライアント・クレデェンシャルタイプ(Client Credential Grant Type Flow)
クライアント・クレデェンシャルタイプのフロー（一番左）は簡単で、2つのステップしかありません。
しかし、ユーザーがアプリと同じ主体であることを要求します。なぜなら、ステップ＃5でOAuthサーバーと通信するとき、ユーザーは自分自身を識別するためにアプリのクライアントID /クライアントシークレットを使用するからです。したがって、このグラントタイプの使用例は限られていますが、キー/アクセストークンがApp（バックエンド）に渡されるので安全です。

##リソースオーナー・パスワード・クレデンシャルタイプ(Resource Owner Password Credential Grant Type Flow)
リソース所有者パスワード資格付与タイプのフローも2つのステップだけで簡単ですが、ステップ＃2でユーザーはアプリにユーザー名/パスワードを渡す必要があります。 アプリとOAuthサーバーが同じエンティティに属していない限り、アプリにユーザー名/パスワードを渡すと、ユーザーとしてすべての権限を持つアプリに権限が与えられます。これはセキュリティリスクです。

##まとめ
４つのOAuth2タイプは、アクセストークンの取得とアクセストークンの使用フローの2つの仕組みで構成されています。 後者はすべてのOAuth2タイプで同じですが、前者はタイプによって異なります。一般的に5つのステップに分割することができ、差は、各ステップに関与する主体から生じます。

OAuthを実装する際の複雑さに対処したくない場合、OAuthをWebサービスとして簡単に利用したい場合、プラットフォームとしてOAuthプロバイダになる場合、またはシングルサインオン（SSO）用のOAuthを使用する場合は、OAuth.ioの専門担当へ[インターコム](https://oauth.io/?utm_source=qiita&utm_campaign=introduction-oauth2-flow-diagrams&utm_medium=article)、[メール](mailto:support@oauth.io)からご連絡をお願いします。お手伝いいたします（日本語対応可）！
または、こちらから[デモ](https://calendly.com/oauthio)の予約を受けたまります。
AWS CloudWatch にデータが反映されない

スナップショットからボリュームを作成し、新たに作成したインスタンスにボリュームをアタッチして稼働させたところ、いつまで経っても新しいインスタンスのメトリックスが AWS CloudWatch に反映されなかった。その際に対応した内容をメモしておく。

## 最初に結論

> **CloudWatchClient.pm モジュールは、インスタンスのメタデータをローカルでキャッシュします。モニタリングスクリプトを実行しているインスタンスから AMI を作成すると、キャッシュ TTL (デフォルト: 6 時間、Auto Scaling グループでは 24 時間) 以内にこの AMI から起動したすべてのインスタンスは、元のインスタンスのインスタンス ID を使用してメトリクスを出力します**。キャッシュ TTL 期間が経過した後は、スクリプトは新しいデータを取得し、モニタリングスクリプトは現在のインスタンスのインスタンス ID を使用します。これをすぐに修正するには、次のコマンドを使用してキャッシュされたデータを削除します。<br>[Amazon EC2 Linux インスタンスのメモリとディスクのメトリクスのモニタリング - Amazon Elastic Compute Cloud](https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/mon-scripts.html)

30分ぐらい右往左往して気がついたきっかけは、

- 停止しているインスタンスのメトリックスが出力されている
- コマンドからメトリックスを送信したところ、稼働中のインスタンスと異なるインスタンス ID が出力されている

ことに気がついたからだった。

### ログインしているインスタンス ID を出力する

これは当然、正しいインスタンス ID を返す。

```shell-session
$ curl -s http://169.254.169.254/latest/meta-data/instance-id
i-yourinstanceid
$
```

### CloudWatch モニタリングスクリプトを手動で実行する

コマンドの実行は成功しているが、上記の `i-yourinstanceid` とは異なる `i-wronginstanceid` が出力されていた。

```shell-session
$ /opt/aws-scripts-mon/mon-put-instance-data.pl --mem-util --mem-used --mem-avail --swap-util --swap-util --swap-used --disk-path=/dev/xvda --disk-space-util --disk-space-used --disk-space-avail --verbose
... Payload: {"MetricData":[{"Timestamp":1554877228,"Dimensions":[{"Value":"i-wronginstanceID","Name":"InstanceId"}] ...
Received HTTP status 200 on attempt 1

Successfully reported metrics to CloudWatch. Reference Id: 6be2c02f-5b59-11e9-93ef-71bdfa0e6067
$
```

### メタデータのキャッシュを削除する

古いインスタンス ID のキャッシュデータを削除して、CloudWatch にメトリックスが反映されるか確認する。

```shell-session
$ sudo rm /var/tmp/aws-mon/wronginstance-id
Pythonでexeテスト実行

# 背景
exeファイル作っていくつかあるテストケースを実行して確認しようという時に、
「これ、一括でテスト実行できないかな？」と思ったのが発端です。

# 構成
* Windowsを想定しています。
* exeの名前は「sample.exe」とします。
* exeにはPATHが通ってるものとします。
* exeを実行すると「result.txt」というファイルが出力されます。
* テストケースは下記構造になっているものとします。

> C:\\test\\TestCase01
> C:\\test\\TestCase02
> C:\\test\\TestCase03
> …

# 実行
```py
import os
import subprocess

exe_name = 'sample.exe'
curr_dir = 'C:\\test\\'
sub_dirs = [d for d in os.listdir(curr_dir)]
for sub_dir in sub_dirs:
    os.chdir(os.path.join(curr_dir, sub_dir))
    # 実行状況確認用出力
    print 'Execute : ' + sub_dir
    # exeファイル実行
    subprocess.call(exe_name)
    os.chdir('../')
```

テスト一括処理スクリプトの完成です。

# データ差分確認

exeファイルを更新した時に、
実行前と実行後で差分が出ていないか心配になりますよね？
そんな時にこんなスクリプトが役に立ちます。

```py
import glob
import filecmp

# 更新前テスト実行結果
old_dir = 'C:\\test\\old'
# 更新後テスト実行結果
new_dir = 'C:\\test\\new'
# 比較対象ファイル指定
diff_file = os.path.join(new_dir, 'TestCase*/result.txt')
# 差分確認
match, mismatch, errors = filecmp.cmpfiles(
    old_dir, new_dir, glob.glob(diff_file))
```

matchには一致したファイルがリストに格納されております。
mismatchは不一致ファイルがリストに格納されており、
errorsはファイルが存在しないなど、
差分確認できないファイルがリストに格納されております。

# 余談

ぶっちゃけ差分確認ツール使えばできるんですけどね（笑）

ただツールだとexeで複数ファイルが出力された場合、
「各フォルダのファイルAのみを比較したい」
なんて時に、
「このフォルダ差分出てるけど、差分出てるの他のファイルじゃん」
って時にglobで指定できるから楽なんです。

~~ツールに条件設定すれば…~~

最後にツールも起動させちゃいましょう。

```py
import subprocess
cmd = '[差分確認ツール(WinMergeなど)] ' + old_dir + ' ' + new_dir
subprocess.call(cmd)
```

これでmismatchにリストアップされたファイルを確認することができます。
LaradockのNginxをSSL化する

Laravelプロジェクトのローカル環境を簡単に構築できる [Laradock](https://laradock.io/) 。
最近かなり重宝しています。

ローカル環境でSSL化したい場合にも簡単にできました。
今回はNginxを使用します。

# Version
Laradock: 7.14
Composer: 1.8.4

# 手順
## 1. Laradock内のnginx設定ファイルを修正

元々コメントアウトされていた `# For https` のブロックを有効にします。

```nginx:laradock/nginx/sites/default.conf
server {

    listen 80 default_server;
    listen [::]:80 default_server ipv6only=on;

    # For https
    listen 443 ssl default_server;
    listen [::]:443 ssl default_server ipv6only=on;
    ssl_certificate /etc/nginx/ssl/default.crt;
    ssl_certificate_key /etc/nginx/ssl/default.key;

~ 以下略 ~
}
```

## 2. nginxのコンテナを再起動

```
$ docker-compose restart nginx
```

以上です。
　
　
確認すると

```
$ docker ps -a
```

こんなかんじになっている。

```
PORTS                                               NAMES
0.0.0.0:8080->80/tcp, 0.0.0.0:4430->443/tcp         my-laradock_nginx_1
9000/tcp                                            my-laradock_php-fpm_1
0.0.0.0:2222->22/tcp                                my-laradock_workspace_1
2375/tcp                                            my-laradock_docker-in-docker_1
```
　
　
これで
`https://localhost:{PORT}`
でアクセスできるようになっているはず。
論理素子

##論理素子
###デジタル回路を構成する部品
####1つ以上の入力と1つ以上の出力がある。入力に応じて出力が変化。

##NOT回路
####1つの入力と1つの出力を持ち、入力を反転して出力。
####入力が1ならば0を、0ならば1を出力。

##Or回路
####2つ以上の入力と1つの出力を持ち、全ての入力が0ならば0を、それ以外の場合は1を出力。
####3入力以上のOr回路も可能。

##And回路
####2つ以上の入力と一つの出力を持ち、全ての入力が1ならば1を、それ以外の場合は0を出力。

##Xor回路
####2つ以上の入力と1つの出力を持ち、入力の1の個数が奇数ならば1を、それ以外の場合は0を出力。

###これら、素子の入力・出力の関係を表した表を真理値表と呼ぶ。
【Jupyter Notebook】jupyterthemesでテーマを変えると行番号が変になる問題の解決法

# はじめに
Jupyter Notebookのデフォルトのテーマはちょっと眩しいです．
僕みたいな陰キャには難しいテーマですよね．

そこで~~陰キャ御用達テーマの~~ Monokai を jupyterthemes で導入した人は結構いると思います．

ところが・・・

あらら
![Screenshot from 2019-04-10 15-04-44.png](https://qiita-image-store.s3.amazonaws.com/0/284136/91070f8a-a76b-45af-fd03-f25853fefb36.png)

Lキーとかで行番号を表示させるとこの有様です．
nbextensionガッツリ有効にしたのでそれが悪さしてるのかもしれませんが，試してないです．
試すより先にCSSいじってました．


# 解決方法
custom.cssをいじります．
いじったあとに
`% jt -t monokai`
みたいなことをするとリセットされてしまうので要注意．

それっぽいところをエディタで検索して編集してください．

```css:custom.css
.cm-s-ipython .CodeMirror-gutters {
 background: #49483e;
 border: none;
 border-radius: 0px;
 width: 64px; /* 変更 */
}
.cm-s-ipython .CodeMirror-linenumber {
 color: #d6d6d6; /* 変更 */
}
```

![Screenshot from 2019-04-10 15-20-26.png](https://qiita-image-store.s3.amazonaws.com/0/284136/32556340-9373-e85e-07bc-2c5ece48ea60.png)

うーん，コードの折りたたみの▼が行番号の左に出てしまうのがなんか違和感あるし，▼の右半分がクリックしても反応しないのがなんかやだな．
ていうか横幅も使い過ぎなような．

困ったな．
誰かもっと良い解決方法があったら教えて欲しいです．
CognosAnalytics 11.1.1 を無人インストールする方法

Cognos11.1.1から11.0のころに比べて、インストール方法が少し変わったことは既にこちらのQiitaにも紹介されている通りです。

[参考：Cognos Analytics 11.1.1 インストール時の注意点3個](https://qiita.com/shinyama/items/89793c89837afea0f1f4)

今回はGUI環境が使用できない環境でインストールする方法について実際に検証してみたので紹介します。準備するモジュールについては上記リンク先に同じです。
では、さっそく始めましょう。

作業①　応答ファイルを作成する
無人インストールをするには、インストールオプションを指定した応答ファイルが必要です。応答ファイルの作成方法は、テンプレートをマニュアルからコピーして作成するか、どこかでGUIインストーラーを起動して操作し、サマリー画面まで進んだところで「キャンセル」をすれば作成できます。
今回は、後者の方法で作成しました。ポイントは以下の2点です。

(ポイント1)　GUI起動コマンド実行時に -r オプションをつけて応答ファイルを指定する
![image.png](https://qiita-image-store.s3.amazonaws.com/0/148873/d58c352e-9c68-332b-22a6-b3ff54924a13.png)
(ポイント2)　インストールサマリー画面に来たら「キャンセル」で終了させる
![image.png](https://qiita-image-store.s3.amazonaws.com/0/148873/e6bef332-1c43-29c1-9bcf-d28c6fcbf91b.png)

特に2つ目でうっかり「インストール」を押してしまうと普通にインストールされてしまうので忘れずにキャンセルするようにしてくださいね。
キャンセル後に応答ファイルを確認してみると何故か指定した名前ではなく「installer.properties」という名前で保存されていました。が、中身を確認すると、確かに今回指定したものと同じでしたのでひとまず良しとします。

```[install.propertiesファイルの中身]
# cat installer.properties 
# Mon Apr 08 17:53:33 JST 2019
# Replay feature output
# ---------------------
# This file was built by the Replay feature of InstallAnywhere.
# It contains variables that were set by Panels, Consoles or Custom Code.



#true
#--------
BISRVR_CA_INSTALL=1
BISRVR_CA_TOOLS_INSTALL=0

#
#
USER_INSTALL_DIR=/opt/ibm/cognos/analytics
BISRVR_FEATURE_DATATIER=1
BISRVR_FEATURE_APPTIER=1
BISRVR_FEATURE_GATEWAY=1
```


作業②インストール
先程作成した応答ファイルを指定して、インストーラーを実行します。
installディレクトリが空であることを確認してから実施してください。何かしら存在しているとエラーになってしまいます。（lsコマンドで確認して/opt/ibm/cognos以下に何も無ければOKです）
特に、一度インストールがコケてしまうとそのログファイルを/opt/ibm/cognos/analytics/logsディレクトリ以下に作成されるので要注意です。失敗した場合は、一度analyticsディレクトリ以下を削除してからリトライするようにしてください。

上記を確認したら以下のようにコマンドを実施します。
暫くするとインストールが完了してコマンドプロンプトが戻るので、echo $?で確認しましょう。

```[サイレントインストールの実行]
# ./ca_installer_linuxi38664_2.0.bin -DREPO=/work/module/ca_server_linuxi38664_11.1.1.zip -l ja -f /work/module/installer.properties -i silent
# echo $?
0
```

インストールディレクトリ先に移動して、以下のログファイルを見てみます。
/opt/ibm/cognos/analytics/logs/install_configuration.log
このファイルには、導入時に設定されたポート番号やホスト名、IPアドレスなどの情報が記載されており、それらの情報が/opt/ibm/cognos/analytics/configuration/cogstartup.xmlに保存されたと書かれています。


　
作業③初期設定して起動できるようにする

次に、ContentStoreの準備をします。GUIが使える場合は、CognosConfigurationからDDLを生成できるのですが、使用しない時は、<インストールディレクトリ>/configuration/schemas/content/db2以下の"createDb.sql.template"ファイルをコピーしてDB名やDBインスタンス名を編集して作成してください。（※今回はDB2を使用しています）
作成したファイルを実行してDBができたら、次にConfigurationの値を変更して起動できるようにします。
GUIを使わずに構成変更する方法は以下の記事に書かれていますので参考にしてください。

[(参考）Cognos Configurationの設定変更をGUIの無い環境で実施する](https://qiita.com/shinyama/items/f5bfa41df0d7cfe44932)

ContentStore等の設定後、GUI環境の場合は右クリックでテストができるのですが、使用しない場合はそうもいきません。そんなときは、<インストールディレクトリ>/bin64/ccogconfig.shの-testオプションを使うと設定ファイルの検証が可能です。
検証結果は、<インストールディレクトリ>/logs以下の、"config_response.csv.yyyymmdd_xxxxxx.log"に出力されるので、中身を見て問題ないことを確認してください。
問題なければ、今度はcogconfig.shに -s オプションをつけてCognosの初期起動をしてください。

あとは、logs以下に出力されるcogaudit.log等を確認したりブラウザからアクセスしたりしてインストール後の動作確認することなどは、GUIで起動したときと同じです。

(2019.7 追記)
検証用の環境にて、CA11.1.2用にintaller.propertiesファイルを作成して11.1.1と比較しましたが、差分はありませんでした

以上
RestTemplateのリクエスト・レスポンスをログ出力する

# 概要

Springフレームワークで提供されている`RestTemplate`によるWebAPIの実行をログ出力したい。

## 環境

- Java 8
- SpringBoot 2.1.3.RELEASE
- Spring 5.1.5.RELEASE
- Lombok 1.18.6

## `RestTemplate`に`ClientHttpRequestInterceptor`を差し込む

- `RestTemplate`のリクエスト・レスポンスに介入するインターセプタを利用する

### ログ出力を行うインターセプタ

- **注意点**
    - レスポンスボディは一回しか読めない。ログ出力のためにインターセプタでレスポンスボディを読み込むと、`RestTemplate`の呼び出し元には空のボディが返ってしまう。
        - 後述のBean定義における`BufferingClientHttpRequestFactory`の設定で回避する。

```java:RestTemplateのインターセプタ
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.util.StreamUtils;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.UUID;

@Slf4j
public class RestTemplateLoggingInterceptor implements ClientHttpRequestInterceptor {

    @Override
    public ClientHttpResponse intercept(HttpRequest request,
                                        byte[] body,
                                        ClientHttpRequestExecution execution) throws IOException {
        val requestUuid = UUID.randomUUID();
        logRequest(requestUuid, request, body);
        val response = execution.execute(request, body);
        logResponse(requestUuid, response);
        return response;
    }

    private void logRequest(UUID requestUuid, HttpRequest request, byte[] body) {
        if (log.isInfoEnabled()) {
            log.info("[API:Request({})] Request=[{}:{}], Headers=[{}], Body=[{}]",
                requestUuid,
                request.getMethod(),
                request.getURI(),
                request.getHeaders(),
                new String(body)
            );
        }
    }

    private void logResponse(UUID requestUuid, ClientHttpResponse response) throws IOException {
        if (log.isInfoEnabled()) {
            log.info("[API:Response({})] Status=[{}:{}], Headers=[{}], Body=[{}]",
                requestUuid,
                response.getStatusCode().value(),
                response.getStatusText(),
                response.getHeaders(),
                StreamUtils.copyToString(response.getBody(), StandardCharsets.UTF_8)
            );
        }
    }

}
```

### `RestTemplate`のBean定義

- ログ出力を行うインターセプタを設定した`RestTemplate`をBean定義する。
    - `BufferingClientHttpRequestFactory`を利用し、ログ出力インターセプタの問題を回避する。

```java
@Configuration
public class ExternalApiConfig {

    @Bean
    RestTemplate restTemplate() {
        return new RestTemplateBuilder()
            .requestFactory(() -> new BufferingClientHttpRequestFactory(new SimpleClientHttpRequestFactory()))
            .additionalInterceptors(new RestTemplateLoggingInterceptor())
            .build();
    }

}
```

# 参考

[RestTemplateでリクエストやレスポンスの中身をログに出す](https://qiita.com/shotana/items/14972c681e5fc315deec)
VRoidのVRMをVRChatにアップロードした備忘録

## 使用したもの
* Unity 2017.4.15f1
* VRChat SDK
* UniVRM 0.51.0
* VRM Converter for VRChat 6.0.2

## 留意事項
* アップできるVRMのポリゴン数は7万が上限
* VRChatのアカウントがチュートリアルを卒業していること

## 1. プロジェクトの作成
Unity 2017.4.15f1でプロジェクトを作成して以下のpackageをすべてImportする。

* VRChat SDK
* UniVRM
* VRM Converter for VRChat

※ 足りないものがあるとエラーになることがあるので最初にすべてImportすることを推奨します。

## 2. VRMをVRChat用に変換

VRMファイルをAssetsにドラッグ＆ドロップする。
VRMのPrefabを選択して以下を実行する。

**メニュー：VRM > Duplicate and Convert for VRChat**
![スクリーンショット 2019-04-10 16.30.33.png](https://qiita-image-store.s3.amazonaws.com/0/393774/dcef15f8-5c87-89ee-aa5e-bdb7e07edf6c.png)

出てきたダイアログの、
・「Default Animation Set」で性別を選択（女の子ならFemaleにする）
・「視線追従を有効化」のチェックを外す
・未検証：（揺れ物の貫通が気になるなら）「揺れ物」にSpring Bone Collider Groupsを含めたほうが良いかと思われる

![スクリーンショット 2019-04-10 16.38.15.png](https://qiita-image-store.s3.amazonaws.com/0/393774/bdab58e4-5d4c-c45f-08ff-b9bcde0dd345.png)
「複製して変換」を実行する。
変換されたアバターの保存先を求めるダイアログが表示されるので保存する（Assetsのままで問題ない）。
保存すると、変換されたアバターがシーンに配置される。

## 3. Unityの再起動

シーンを保存する（保存先はAssetsのままで問題ない）。
Unityを再起動する。
プロジェクトを再度開く。

## 4. 一人称視点の調整

Hierarchyのアバターを選択する。
Inspectorの「View Position」の座標をいじって灰色の玉をアバターの両目の中間に移動させる。
![スクリーンショット 2019-04-10 16.41.11.png](https://qiita-image-store.s3.amazonaws.com/0/393774/d49db0fe-1939-70fe-7fae-0a0ad61aa6f8.png)

#### 目安
X : 0　Y : 1.48　Z : 0.09
![スクリーンショット 2019-04-10 15.48.12.png](https://qiita-image-store.s3.amazonaws.com/0/393774/bcadd220-fd29-69ec-b8fc-4eca157ee470.png)
値を変更しても灰色の玉が移動しない場合はアバターを再選択すると反映される。

## 5. VRChatにアップロード

**メニュー：VRChat SDK > Settings** を開き、
![スクリーンショット 2019-04-10 16.30.46.png](https://qiita-image-store.s3.amazonaws.com/0/393774/3d640999-1f79-4368-6c2c-731506d1896d.png)

* VRChatにサインインする
* 「Future Proof Publish」のチェックを外す（必須ではないが外しておくとアップロード時のエラーを回避できる）

**メニュー：VRChat SDK > Show Build Control Panel** を開く。
![スクリーンショット 2019-04-10 16.30.54.png](https://qiita-image-store.s3.amazonaws.com/0/393774/156a9c6d-5ef2-bbfa-4d86-0dd20cbb568a.png)
「Build & Publish」を実行する。

GameViewにVRChat用の入力欄が表示されるので、

* アバターの名前を入力する
* 該当する属性にチェックを入れる
* 「The above information 〜」に同意する
* Uploadボタンをクリックする

Complete!的なダイアログが出たら完了です。
![スクリーンショット 2019-04-10 15.59.07.png](https://qiita-image-store.s3.amazonaws.com/0/393774/78f2f092-a8ca-58ab-4fc3-72c86cf1b795.png)

※GameViewにテキストが表示されていなかったり、反応しなかったら一時停止されている可能性があるので解除する。

## エラーが出た場合
アップロード時に以下のエラーが出るようなら、「Future Proof Publish」のチェックが外れていない可能性があるので外す。

> Error updating content. Unity package upload failed.
> Failed to optimize file for upload.

## アップロード成功したはずなのにVRChat内に表示されない場合

シーンのアバターを選択してInspectorのPipeline Managerの「Detach」をクリックするとBlueprint IDが空の状態になるので、そしたらもう一度アップロードするといけるかも？
元々の値（モザイクの部分）がある場合はメモっといたほうがいいかも。
![スクリーンショット-2019-04-11-10.40.50.gif](https://qiita-image-store.s3.amazonaws.com/0/393774/6f88f770-4200-7f05-10b4-13be413d5641.gif)

以上です。
おつかれさまでした。
pythonでタイムゾーンを意識して日時を扱う方法

# はじめに
pythonで`datetime`モジュールを使って日時を扱う時はタイムゾーンを意識する必要がある場合があります。
でも、変換方法を毎回調べてる自分がいたので、まとめておこうと思った次第。

# TL;DR
```python
from datetime import datetime, timezone, timedelta

JST = timezone(timedelta(hours=+9), 'JST')
c = datetime(2019, 4, 1, 23, 0, 0).replace(tzinfo=JST)
print(c)    # 2019-04-01 23:00:00+09:00

now = 1554127200    # 2019-04-01 23:00:00（日本時間）のunix timestamp
c = datetime.fromtimestamp(now, JST)
print(c)            # 2019-04-01 23:00:00+09:00
```

# 何も指定しないとこうなる
```python
from datetime import datetime

year = 2019
month = 4
day = 1
hour = 23

c = datetime(year, month, day, hour, 0, 0)
print(c)    # 2019-04-01 23:00:00
```

一見良さそうです。
ただし、これは`2019-04-01 23:00:00`がどこのタイムゾーンの話なのか分かりません。

UNIXタイムスタンプからの変換結果も、そのまま出力しようとするとUTCでの日時が出てきます。

```python
from datetime import datetime

now = 1554127200    # 2019-04-01 23:00:00（日本時間）のunix timestamp
c = datetime.fromtimestamp(now)
print(c)            # 2019-04-01 14:00:00 <- UTC
```

# timezone
`datetime.timezone`は、タイムゾーンを扱うクラスです。

datetimeオブジェクトは、自身がタイムゾーンの情報を持つ場合（`aware`）と、持たない場合（`naive`）があります。
明示的に指定しないと`naive`となり、タイムゾーン情報を持たせる場合は`replace`メソッドを使用します。

```python
from datetime import datetime, timezone, timedelta

year = 2019
month = 4
day = 1
hour = 23

JST = timezone(timedelta(hours=+9), 'JST')
c = datetime(year, month, day, hour, 0, 0).replace(tzinfo=JST)
print(c)            # 2019-04-01 23:00:00+09:00

now = 1554127200    # 2019-04-01 23:00:00（日本時間）のunix timestamp
c = datetime.fromtimestamp(now, JST)
print(c)            # 2019-04-01 23:00:00+09:00
```

UTC については`datetime.timezone.utc`が標準で用意されています。

```python
from datetime import datetime, timezone

year = 2019
month = 4
day = 1
hour = 23

c = datetime(year, month, day, hour, 0, 0).replace(tzinfo=timezone.utc)
print(c)            # 2019-04-01 23:00:00+00:00

now = 1554127200    # 2019-04-01 23:00:00（日本時間）のunix timestamp
c = datetime.fromtimestamp(now, timezone.utc)
print(c)            # 2019-04-01 14:00:00+00:00
```

# おわりに

`datetime`モジュールのみを使用することを想定しています。
別のライブラリを使用する例もありますが、UTCとJSTだけを扱えれば良いのであれば上記の形で十分かと。
（日本でも夏時間を扱うとなったら話は別ですが...）
Custom Map(カスタム・マップ)を使ったLooker上での可視化

Lookerでは、自作した境界データを利用して地図上での可視化を行うことが可能です。これにより、営業エリアが複数の市区町村をまたがっている場合などでも、棒グラフ・円グラフなどだけではなく地図上での塗分けによる可視化を行うことが可能になります。
今回は、東京都の人口データを利用した可視化を行ってみたいと思います。

```
(注：本文中に記載のリンクは本記事執筆時のものでありリンク先URLが変更になっている可能性があります。
また、こちらに記載の内容については、弊社サポートチームにお問合せ頂いても対応致しかねる場合がございます点についてご留意ください）
```

##領域データの準備##
上記可視化を行うためには、各地域の地形シェイプデータおよび各地域情報を含めたデータが必要になります。
Lookerでは、地図上の領域を表現するために[TopoJson](https://github.com/topojson/topojson)という形式のデータを利用します。地形データは複雑な地形になってくるとデータサイズが巨大になってしまいますが、このTopoJsonを利用することで軽量化を行うことができます。
TopJsonについては、shapefileフォーマットやgeoJson形式のデータをお持ちになられていれば、Mapshaperというオンラインツールで簡単に変換することが可能です。変換方法については、こちらの[記事](https://discourse.looker.com/t/converting-shapefiles-to-topojson/4226)を参照ください。
今回は、以下のように東京都の人口数・世帯数のデータを地図上に表現したいと思います。
<img width="579" alt="Screen Shot 2019-04-10 at 14.31.21.png" src="https://qiita-image-store.s3.amazonaws.com/0/394509/5f87d941-ea46-5f21-d1fd-ddaea57ed31d.png">

東京都の人口データについては、こちらの[東京都の人口（推計）](http://www.toukei.metro.tokyo.jp/jsuikei/js-index.htm)からのリンク先PDFを使って作成しました。
また、東京都の境界データについては、こちらの[国土数値情報 行政区域データ](https://nlftp.mlit.go.jp/ksj/gml/datalist/KsjTmplt-N03-v2_3.html#prefecture13)からダウンロードしました。
geoJson形式のファイルもダウンロードすることができるため、topoJson形式に変換して利用します。このファイルは、`N03_004`というプロパティに市区町村名が入っているようなので、この項目でマッピングをしていきます。
##境界データのアップロード##
Lookerでアップロードしたいプロジェクトを開き、topoJsonファイルをドラッグ・アンド・ドロップすることでインポートすることができます。これにより、LookMLコードとともにリポジトリへコミットすることが可能です。![Screen Shot 2019-04-10 at 14.21.28.png](https://qiita-image-store.s3.amazonaws.com/0/394509/a5610ae0-5ba1-2c6a-cc79-d9fdbfc3e954.png)
##Mapレイヤーの作成##
地図の境界データがアップロードできましたので、LookML上にMapレイヤーを作成していきます。
以下のようにモデルファイルに追加します。

```
map_layer: tokyo_map {
  format: topojson
  property_key: "N03_004"
  file: "tokyo.topojson"
}
```

`file`パラメータは、プロジェクトにある地図データを参照しています。`property_key`パラメータにて元のデータと領域を紐付ける際に利用する項目名を指し示しています。
> `file`プロパティの代わりに`url`パラメータを利用してtopoJsonがホスティングされているURLを指定して利用することも可能です。

##Mapレイヤーとデータの関連付け##
最後に行っているのは、viewのdimensionと新しく作成したMapレイヤーを関連付けるだけです。

```
  dimension: city {
    label: "市区町村"
    type: string
    map_layer_name: tokyo_map
    sql: ${TABLE}.CIty ;;
  }
```

##地図表示##
上記のように定義したLookMLを利用したExploreで世帯数を表示すると以下のようになります。
![Screen Shot 2019-04-10 at 14.56.45.png](https://qiita-image-store.s3.amazonaws.com/0/394509/d11110af-43cd-9722-f760-8aaf91e1e1cb.png)
> なお、上記はUser Attributeで`Locale (beta)`を**ja_JP**に変更しているため地図中の市区町村などの表記が日本語名に変更されています。ヘルプの[ロケールへのユーザーの割り当て](https://docs.looker.com/ja/data-modeling/learning-lookml/model-localization#users)に記載があります。


ご参考になりますと幸いです。以降もTipsをお届けしたいと思います。
mkdir で必要に応じて中間ディレクトリも作って欲しいときのオプション

いつも忘れるのでメモ。



`-p` オプション（ `--parents` オプション）が使える。

```
$ mkdir -p PATH_TO/foo/bar
```

一緒に併用することがありそうなのが `-v` オプション（ `--verbose` オプション）
ディレクトリを作成した結果の一覧してくれる。

```
$ mkdir -vp PATH_TO/foo/bar
mkdir: ディレクトリ ❛PATH_TO/foo❜ を作成しました
mkdir: ディレクトリ ❛PATH_TO/foo/bar❜ を作成しました
```

おわり。
MongoDBをHomebrewを使ってインストールできない　Reason: TemplateNotFound()

brew install mongodbでインストールが上手くいかなかった時の解決法。

# 手順１　brew doctorで原因特定
ターミナルから以下のコマンドを叩いて問題を特定する。

```
brew doctor
```
今回私の場合は以下の様なレスポンスが帰ってきた。

```
$ brew doctor
Please note that these warnings are just used to help the Homebrew maintainers
with debugging if you file an issue. If everything you use Homebrew for is
working fine: please don't worry and just ignore them. Thanks!

Warning: You have unlinked kegs in your Cellar
Leaving kegs unlinked can lead to build-trouble and cause brews that depend on
those kegs to fail to run properly once built. Run `brew link` on these:
  python なんちゃら
```
ここからはエラーによって解決法は異なると思う。
# 手順2 
今回の事象はpythonがlinkできてない？といったエラー内容だったので以下のコマンドでlinkしてあげた。

```
brew link python なんちゃら
```

# 手順3 
これで解決を思いきや、brew install mongodbコマンドを叩くと、以下の様なエラーが返ってきた。

```
==> make html
Last 15 lines from /Users/oleksandr-yefymov/Library/Logs/Homebrew/python@2/05.make:
writing output... [ 98%] whatsnew/2.1
writing output... [ 98%] whatsnew/2.2
writing output... [ 98%] whatsnew/2.3
writing output... [ 99%] whatsnew/2.4
writing output... [ 99%] whatsnew/2.5
writing output... [ 99%] whatsnew/2.6
writing output... [ 99%] whatsnew/2.7
writing output... [100%] whatsnew/index

generating indices... genindex py-modindex
writing additional pages... download index
Theme error:
An error happened in rendering the page index.
Reason: TemplateNotFound()
make: *** [build] Error 2

READ THIS: https://docs.brew.sh/Troubleshooting
```
Homebrew/python@2配下で、make htmlをしようとしてる時に上手くいってないみたいなので、以下のコマンドを叩いてデバッグ。

```
brew install --debug --verbose python@2
```

# 手順4

以下の様に１〜５までどちらを選択するか聞かれるので、「2」を選択してenter

```
debrew.rb:11:in `raise'
BuildError: Failed executing: make html
1. raise
2. ignore
3. backtrace
4. irb
5. shell
Choose an action: 2 // ⬅︎ 選択している
==> Cleaning
```

再度 brew install mongodb コマンドを叩いたら無事インストールできました。
Ruby

##initializeメソッド
###オブジェクトの初期化に利用される特殊なメソッド。
####newクラスメソッドでオブジェクトを作成したときに自動的に呼び出される。
####初期化されていなくても参照できるが、自動的にnilが設定される。

##インスタンス変数(@)
###オブジェクトの処理対象となるデータで格納する変数。
####アクセスできるのは、インスタンス変数を持つオブジェクトのメソッドに限定。外部からは、アクセスできない。
##クラスが持つのは、定義。実体を持つのは、オブジェクト（インスタンス）。

##attr_accessorメソッド
###引数で指定したシンボル(:文字列)と同名のインスタンス変数にアクセスするメソッドを自動的に用意する。


##オブジェクト
###基本的にオブジェクトの状態は、メソッドの呼び出しで変わるもの。オブジェクト自身が管理し、外部に対して公開しない。
##しかし、
###オブジェクト内部の処理に応じて、状態が変わるのではなく環境の変化によって外部から操作される方が自然な場合もある。（例：View上のテキスト・ボタン）
###このような外部に公開する状態を属性と呼ぶ。
sourcetreeがファイル名の変更を検知しないのでignorecaseをfalseにする

Gitはデフォルトでファイル名の大文字・小文字の変更は検知しない設定になっているようで、sourcetreeもそれに当てはまります。
どこかで設定できないかと探しましたらありましたのでメモ

---

一番右の`設定`をクリック
![4198e2ec0bb4d507996a16d1842f900b.png](https://qiita-image-store.s3.amazonaws.com/0/206790/e5df779a-afa6-45be-aa84-cf9f21d2b915.png)

リモートタブの、`Configファイルを編集・・・`をクリック
![c5f1a235ba7307daadb062334e36119c.png](https://qiita-image-store.s3.amazonaws.com/0/206790/943899ab-11a7-00a5-0db9-7e959ab7c417.png)

`ignorecase`を`false`にする。
![57a2a2eb953ef28354bcf33b5465b747.png](https://qiita-image-store.s3.amazonaws.com/0/206790/c2380c1b-fab9-f70e-429a-a4721a52941a.png)
#Twitter で ツイートIDを指定して URL を得る方法 ( リダイレクトを利用 )

# Twitter URL is so strange it has user name

https://twitter.com/YumaInaura2nd/status/1115097414388596736

# Even if you specified any user name in URL then it will be redirected to original users URL

https://twitter.com/YumaInaura/status/1115097414388596736
https://twitter.com/YumaInaura3rd/status/1115097414388596736
https://twitter.com/YumaInauraPhoto/status/1115097414388596736

# So You can use `@twitter` user and use that URL

https://twitter.com/twitter/status/1115097414388596736

because When `@twitter` user closed its the time Whole twitter service is overed


# Original by Github issue

https://github.com/YumaInaura/YumaInaura/issues/1160








<!-- Update From Qiita API -->

# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ





# Twitter


https://twitter.com/YumaInaura


<!-- Update From Qiita API -->
Quarkusで作ったアプリをHerokuで動かしてみる

# はじめに

Webアプリケーションを無料で手軽に動かす時にHerokuを使いますよね？
ただ無料で使う場合、アプリケーションを30分以上放置する（リクエストがない）と、サーバがスリープしてしまいます。

スリープ後にアプリケーションにアクセスすると、レスポンスが返ってくるまでに時間がかかってしまいます。そこで、起動時間を短縮するために、最近注目されているGraalVMとGraalVM上でJavaのWebアプリケーションを動かすことができるQuarkusを使ってみました。

今回はQuarkusをHerokuで動かす方法と、SpringBootとの起動時間の比較を行ってみたいと思います。

# 前提条件

- Herokuのアカウントを持っていること

# Quarkusアプリケーションの用意

## アプリケーションの作成

以下の記事を参考にアプリケーションの作成を行ってください。

[Javaのフレームワーク「Quarkus」を試してみた](https://qiita.com/mr-hisa-child/items/92e0417460adc328596a)


## Dockerファイル作成

今回はDockerレジストリにHerokuのコンテナレジストリを使います。

以下のファイルを作成してください。

```dockerfile:src/main/docker/Dockerfile.web
FROM registry.fedoraproject.org/fedora-minimal
WORKDIR /work/
COPY *-runner /work/application
RUN chmod 775 /work
EXPOSE 8080
CMD ["./application", "-Dquarkus.http.host=0.0.0.0", "-Dquarkus.http.port=${PORT}"]
```

```-Dquarkus.http.port=${PORT}``` はHerokuで指定されたポートで起動するために必要です。これがないと起動できません。
ちなみに${PORT}の部分を変更することで、Quarkusアプリの起動ポートを変更できます。

## Herokuコンテナにログイン

```console
heroku container:login
```

## Heroku上にアプリケーションを作成

```console
heroku create <アプリケーション名>
```

以降はプロジェクトルートで行ってください。

## Dockerレジストリにプッシュ

```console
heroku container:push -R -a <アプリケーション名>
```

## Docker起動

```console
heroku container:release web -a <アプリケーション名>
```

## 動作確認

```
curl https://<アプリケーション名>.herokuapp.com/hello
```

helloが出力されることを確認します。

# SpringBootアプリケーションの用意

## アプリケーションの作成

```java:RestController
@SpringBootApplication
@RestController
public class DemoApplication {

	public static void main(String[] args) {
		SpringApplication.run(DemoApplication.class, args);
	}

	@RequestMapping("hello")
	public String home() {
		return "hello";
	}
}
```

## Dockerファイルの作成

```dockerfile:Dockerfile
FROM openjdk:8-jdk-alpine
VOLUME /tmp
COPY target/app.jar app.jar
CMD ["java","-jar","app.jar","--server.port=${PORT}"]
```


**以降の手順はQuarkusと同様のため割愛します。**


# スリープ後の起動時間を計測

herokuサーバが以下のような状態になるまで待ちます。
![スクリーンショット_2019-04-10_12_35_14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/53830/7acad938-7246-2a3b-9a27-839bf324841f.png)

以下のコマンドを実行し計測してみます。

### Quarkusアプリケーションの計測
```console
curl https://<Quarkusアプリケーション名>.herokuapp.com/hello -o /dev/null -w  "%{time_starttransfer}\n" -s
7.038011
```

### SpringBootアプリケーションの計測
```console
curl https://<SpringBootアプリケーション名>.herokuapp.com/hello -o /dev/null -w  "%{time_starttransfer}\n" -s
15.208555
```

**QuarkusはSpringBootの1/2の時間で起動するという結果になりました**