OmniAICreator/Qiita-1.07M huggingface dataset:
[AngularJS] angular-ui-router 0.2.x から 1.0.x への移行

サービスを数ヶ月ぶりに開発するため、npmのpackageを一斉にupdateしていた。

いつも通り

```bash
ncu -u
```
で何も考えずにupdate。

すると `angular-ui-router` が `@uirouter/angularjs` に変わったと言われたのでついでに書き換え。
多分この時か `ncu -u` のタイミングでversionが1.xに変わったと思う。いくつか動かないポイントがあったのでメモ書き程度に残しておく。
（今更AngularJS?という話は置いておいて・・・）

## $stateChangeStart
`$stateChangeStart`イベントを`listen`しているところがどうも動かない。調べてみると

https://stackoverflow.com/questions/37163811/angular-js-ui-router-statechangesuccess-event-not-firing
>If you are using the new ui-router (v1.0.0), the `$stateChange*` events will not work. You must use `$transitions.on*` hooks from now on.

ほう。。。
というわけで以下のように修正

```javascript
-    $rootScope.$on('$stateChangeStart', (event, next, params) => {
+    $transitions.onStart({}, trans => {
+      const next = trans.to();
+      const params = trans.params();
```
callback関数への引数はこの辺にdocumentがある
https://ui-router.github.io/ng1/docs/latest/classes/transition.transition-1.html

## The transition has been superseded by a different transition
上の修正で表面上は動くようになったが、見出しのエラーが出てる。

https://github.com/angular-ui/ui-router/issues/2977
>In ui-router legacy, people wondered why their transitions were failing silently. In 1.0, we added a default error handler which is printing the message that the original transition (to an auth state) was superseded by the new one (to guest). Read more here

なるほど。

恐らくベストは `$state.go('hoge');` してるところをissueの通りに書き直すソリューション。けど設計が良くなくて該当箇所が必ずイベント内から呼び出させれる保証はなかったので、諦めてエラーを握りつぶすことに。

```javascript
+    $state.defaultErrorHandler(function() { /* do nothing */});
```

## hash path
前までは `/#/home` みたいなリンクに飛ぶと `/home` のstateを読み込んでくれたけれど、それが動いてなかった。

`params` の内容を見てみると `#` 以下がパラメーターとして扱われている。

色々悩んだ末・・・

```javascript
console.log($locationProvider.hashPrefix());  // => '!'
```
これかー。確かにこれだと `/#!/home` にしないとルーティングしてくれなさそう。

どこかでデフォルト変わった・・・？と思って探したら記述が見つかった。=> https://docs.angularjs.org/guide/migration#commit-aa077e8

以下の設定を追加して解決

```javascript
-  $locationProvider.html5Mode(true);
+  $locationProvider.html5Mode(true).hashPrefix('');
```
厳密にはこれは ui-router じゃなくて AngularJS の変更ですが。

## 最後に
まあ少なくとも最初の二つに関しては、まず https://ui-router.github.io/guide/ng1/migrate-to-1_0 を読んでからやれって話です。
react virtualizedで件数の多いリストデータを効率よく描画する

Reactで数万件のデータを一度に描画した時に、スクロールが重くなってしまうので [react-virtualized](https://bvaughn.github.io/react-virtualized) を使って解決しました。
 

## `react virtualized`とは？

原理としてはスクロールに応じて、使っていないコンポーネントを次のデータ表示のために再利用しているといったイメージになります。

以下の記事が図を使っていてわかりやすい説明をしています。

https://developers.google.com/web/updates/2016/07/infinite-scroller


## 使ってみる

### インストール

```
$ npm install react-virtualized --save
$ # or
$ yarn add react-virtualized
```


### 導入

```
//これはアプリケーションの元ファイルで一度呼べばいい模様
import 'react-virtualized/styles.css'

```

`react virtualized` を使った簡単なテーブルの例です。
10万件のデータを表示してみます。

```virtualizedTable.js
import React from 'react';
import {AutoSizer, Table, Column} from 'react-virtualized';

export class VirtualizedTable extends React.Component {
  render() {
    let data = new Array(100000).fill({}).map((item, i) => ({number: i, text: `product ${i}`}));
    return (
      <AutoSizer>
        {({width, height}) => {
          return (
            <Table
              rowCount={data.length}
              rowGetter={({index}) => data[index]}
              rowHeight={30}
              width={width}
              height={500}
              headerHeight={30}
            >
              <Column 
                dataKey={'number'}
                label={'No'}
                cellDataGetter={({rowData}) => rowData.number}
                width={120}
                height={30}
              />
              <Column 
                dataKey={'text'}
                label={'テキスト'}
                cellDataGetter={({rowData}) => rowData.text}
                width={120}
                height={30}
              />
            </Table>
          )
        }}
      </AutoSizer>
    );
  }
}

```
![react-virtualized.mov.gif](https://qiita-image-store.s3.amazonaws.com/0/52622/13ae598c-9a96-87e2-5a4e-a98af828c6aa.gif)

これで滑らかな表示が可能となりました。
Electron製のアプリケーションにスタイルシートを埋め込む

Hangoutなど、公式のアプリがないWebサービスはnativefierを使ってスタンドアロンのアプリとして使っています。

画面の大きさが狭いとか、標準のCSSをカスタマイズしたくなったので備忘録として記録しておきます。

nativefierについてはこちらの記事が参考になります。

- Webページをデスクトップアプリ化 - nativefierを使ってみる
  [https://qiita.com/taiyoslime/items/98be154455e76710df9d]

※ 今回はMacを対象にしていますが

## Electron製のアプリケーションの中身

自作したHangout.appを開いてみるとこんな感じの構成になっています。Macの普通のアプリと同じで特に変わったものはありません。

- /Contents
  - /Frameworks
  - /MacOS
  - /Resources
    - /app ※
  - Info.plist
  - PkgInfo

Electronの起動などに使われるJavaScriptは``/app``ディレクトリに入っています。

## 書き換え対象のJS

Electronは起動すると``/lib/main.js``を起動します。その中で``/lib/static/preload.js``を読み込んでブラウザを起動するような仕組みになっています。

preload.jsは<head>に書いたJavaScriptのようなものなので、一番最初に読み込まれます。

## preload.jsの修正

inject用のディレクトリが/app/injectに用意されているので、そこにinject.cssを設置して読み込む形式とします。

CSSをinjectする関数``injectStylesheet()``を定義して、DOMContentLoadedの後ろで呼び出すのがわかりやすいと思います。

元々JavaScriptを読み込むための``injectScripts()``が定義されているのでそちらに合わせる形で作っています。

```js
function injectStylesheet(){

}

document.addEventListener('DOMContentLoaded', function () {
  //中略
  injectScripts();
  injectStylesheet(); //<- CSSの読み込みを行う
});
```

## ``injectStylesheet()``の実装

Electron製のアプリは内部でChromiumが使われています。そのため、制限として、ローカルのファイルをそのまま``<link>``で読み込むことが出来ません。

今回はCSSファイルを読み込んで、``<style>``タグで埋め込むことにしました。
そのために必要なパッケージは既にpreload.jsで定義されているので、特に追加する必要はありません。

```js
function injectStylesheet(){
  var styleSheet = _path2.default.join(__dirname, '../../', 'inject/inject.css');

  //cssを読み込む
  _fs.readFile(styleSheet, 'utf8', function (err, text) {
		
    var styleNode = document.createElement("style");
    styleNode.setAttribute("type","text/css")

    var content = document.createTextNode(text)
    styleNode.append(content)
    document.getElementsByTagName("head")[0].append(styleNode)
		
  });
}
```

`injectStylesheet()`では下記の流れで処理します。

1. `_path2.default.join()`を使ってCSSのパスを変換する
2. `_fs`を使ってCSSのファイルを読み込む
3. `<style>`タグを作る
Rails のローカル環境で 404 ページを確認する


## はじめに
404 ページに動的な要素を追加したい時は 404 ページを自作する必要があるが、ローカル環境でありもしない URL を叩いて確認しても Routing Error にあるだけなので、実際の表示を確認できるようにローカル環境で Routing Error ではなく 404 ページを表示させるようにする。
## 実装
`config/environments/development.rb` を以下のように `false` に書き換えたら終了！

```config/environments/development.rb
config.consider_all_requests_local = false
```
## まとめ
これでありもしない URL を叩くとちゃんと 404 ページが表示されるので、404 ページの改修作業等ある時は使えるかと。
ただちゃんと元に戻さないと他の人に迷惑なので、開発が終わればちゃんと `true` に戻しましょう。
AWS S3 でページを公開する

AWS S3 で Web ページを公開する方法です。
例えば、test-s3 というバケットを東京リージョンで作成するとします。

１）　バケットの作成
![s3_jan3001.png](https://qiita-image-store.s3.amazonaws.com/0/179446/c9f89d1b-2a7b-f9e4-8694-f99148fde51c.png)

２）　Static website hosting　の設定
プロパティ -> 静的ウェブサイトホスティング
![s3_sep26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/248c22a2-1d79-6a78-f6a9-ea52292e5807.png)


３）　パケットポリシー　の設定
[バケットポリシーの例](https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/dev/example-bucket-policies.html)
この例に対して、Resource を修正する必要があります。
![s3_jan3003.png](https://qiita-image-store.s3.amazonaws.com/0/179446/867ee192-2663-25db-41cf-76249ac3e869.png)

```json

{
  "Version": "2012-10-17",
  "Statement": [
     {
	"Sid": "PublicReadGetObject",
	"Effect": "Allow",
	"Principal": "*",
	"Action": "s3:GetObject",
	"Resource": "arn:aws:s3:::test-s3/*"
     }
  ]
}
```


４）　index.html ファイルのアップロード
次の URL でアクセスできるようになります。
http://test-s3.s3-website-ap-northeast-1.amazonaws.com/index.html

## https でアクセスする為には、CloudFront で設定 ##
オリジンドメイン　を test-s3.s3-website-ap-northeast-1.amazonaws.com
にします。
プルダウンでは設定できません。
プルダウンでは、test-s3.s3-ap-northeast-1.amazonaws.com
が出てきます。
v-htmlでfilterを使いたい

もっと簡単な方法があれば知りたい

```pug:vue
div(v-html="$options.filters.capitalize(message)")
```

```js:vue.entry.js
// グローバル・フィルター
Vue.filter('capitalize', function (value) {
    if (!value) return ''
    value = value.toString()
    return value.charAt(0).toUpperCase() + value.slice(1)
})
```

> [サンプル](https://codepen.io/pokkur/pen/KQwpyy)
HubotとTypeScriptでChatwork botを作ってみる

こちらの記事を参考にしてHubotとTypeScriptを使ってChatwork botを作ってみたいと思います。
https://qiita.com/S_Shimotori/items/3da73b05bfdc3c582995
http://hatappo.hatenadiary.jp/entry/2015/07/19/034412

## 今回作るbotに関して
* とりあえず、"hello"と送ったら"world"を返すような本当に簡単なもの
* HubotのscriptはTypeScriptで記述しコンパイルする
* 動かす環境はCentOS7系

## Node.jsの導入
```
$ sudo yum install epel-release
$ sudo yum install nodejs npm
```

## TypeScriptを入れる
```
$ npm install -g typescript
$ npm install @types/node --global
$ npm install @types/hubot --save
```

## hubotを入れる
```
$ npm install -g hubot hubot-chatwork yo generator-hubot
```

## とりあえずhubotを生成して動かしてみる
```
$ mkdir kevin
$ cd kevin
$ yo hubot --adapter chatwork
```

実行するとHubot君がでてきてメールアドレスやbotの名前などの入力を求められるので入力する(特に設定の必要がなければ適当にEnter押すだけでもでも可)

```
                      _____________________________
                    /                             \
   //\              |      Extracting input for    |
  ////\    _____    |   self-replication process   |
 //////\  /_____\   \                             /
 ======= |[^_/\_]|   /----------------------------
  |   | _|___@@__|__
  +===+/  ///     \_\
   | |_\ /// HUBOT/\\
   |___/\//      /  \\
         \      /   +---+
          \____/    |   |
           | //|    +===+
            \//      |xx|
? Owner   dummy@dummy.mail
? Bot name   kevin
? Description   Chatwork bot Test
```
生成が終わるとjsonファイルやらscriptsやらがいろいろ出来上がる。
動かすときにhubot-script.jsonでエラーがでるので削除。
external-scripts.jsonのheroku関連行を削除。
以下で実行`kevin ping`と打って、`PONG`が返ってくればOK

```
$ ./bin/hubot
kevin> kevin ping
kevin> PONG
```
## Chatworkアダプタの環境変数を設定
```
export HUBOT_CHATWORK_TOKEN="<CHATWORK_TOKEN>"
export HUBOT_CHATWORK_ROOMS="<ROOM_ID>"
export HUBOT_CHATWORK_API_RATE="<RATE>"
```

## Chatworkから実行してみる
以下を実行してbotを起動
```
$ ./bin/hubot -a chatwork -n test-bot
```
Chatworkの指定のROOMから`test-bot ping`を実行し、`PONG`が返ってくることを確認

## TypeScriptを書く
基本的な記法等は本やら記事やらがたくさん出回っているので省略。  
~~TypeScriptからJavaScriptを生成する際に型定義ファイルが必要となるが、今回使用するものは以下を参考にして作成する。~~
(@types/hubotをインストールしたことで必要がなくなったため打消し)
http://qiita.com/itoshiki/items/65d24b197d830054f501 

### hello.ts(/kevin/scripts/hello.ts)
```
import hubot = require("hubot");

module.exports = (robot: hubot.Robot): void => {
    robot.respond(/hello/i, (msg: hubot.Response)=>{
        msg.reply("world!");
    });
};
```

~~型定義ファイルを同じ階層に設置し、~~JavaScriptにコンパイルする。
```
$ tsc scripts/hello.ts
```
成功するとhello.jsが出来上がっている。
### 出来上がったhello.js
```
"use strict";
exports.__esModule = true;
module.exports = function (robot) {
    robot.respond(/hello/i, function (msg) {
        msg.reply("world!");
    });
};
```

これで準備OK。  
もう一度botを起動する。
```
$ ./bin/hubot -a chatwork -n test-bot
```
Chatworkから`test-bot hello`と送信し`world!`が帰ってくることを確認。
ということで一応完成になります。
初のQiita記事なので手順に抜け、記法の誤りなど多々あるかもしれませんが悪しからず…。

## 作ってみた感想
* 初めて手をつけた割には、思っていた以上にすんなりとできた。とても使いやすい。
* TypeScriptに関する知識がほぼ皆無だったので少し手こずった(ちゃんとした書き方がまだわかってない)。これを機に勉強しようと思う…。
* ChatworkでたたいてからResponseが来るまでが割と長いなーという印象

## 今後の展開
* 業務において使用。今回作ったbotを使ってpythonで作成したテストコードの自動実行をし、結果をChatworkにだせるようにする。
Nature Remoを使って時間差で連続シグナルを送る

#Nature Remoが届いた
１週間ほど前に注文していたNature Remoが届いたので手元にある赤外線で操作可能なものを動かしてみた。
と言ってもよくよく考えるとエアコンとシーリングライトぐらいしかないので、とりあえずこれらとGoogle Homeを連携させてみることにした。

#シーリングライトの制御がうまくいかない
エアコンは難なく設定できたのだけれど、うちにあるシーリングライトはリモコンのボタンを押すたびに明るさが切り替わるタイプで４回押してようやく電源が切れる。
これではスマホアプリから４回ボタンを押すかGoogle Homeに４回「OK Google, 電気消して」と言うしかない。

#IFTTT
IFTTTを使って`This`にGoogle Assistantを、`That`にNature Remoをそれぞれ設定すれば「電気消して」などをトリガーにしてNature Remoの操作を行うことができる。
しかし`That`に何個も追加でアクションを登録するようなことはできないようで、１つのトリガーに対して複数のアクションを定義したい時は同じ内容のトリガーでAppletを複数作成し、それらにそれぞれアクションを割り当てる必要があるらしい。
今回の場合はシーリングライトに対して４回同じシグナルを送信したいので同じAppletを4つ作ってみた。
しかしシーリングライト側が連続でシグナルを処理できないせいかうまく動かない。


#Cloud Functions for Firebase
IFTTTを使って数秒ごとにリクエストを送る方法がないかと調べてみたが見つからなかった。
Nature Remoの[API](https://swagger.nature.global/)を見つけたので仕方なくIFTTTのWebhook機能を使ってCloud Functionsを叩くことにした。
Access Tokenは[ここ](https://home.nature.global/home)で取得しておく。
Clound functionsにdeployしたファイルはこんな感じ。
無事動いた。

```ts
import * as functions from 'firebase-functions';
import {Observable} from 'rxjs';
import axios from 'axios';

exports.turnOffLight = functions.https.onRequest((request, response) => {
   //...
   //省略
   //...
   Observable.interval(6000).timeInterval().take(4).subscribe(val => axios.post('https://api.nature.global/1/signals/YOUR_SIGNAL_ID/send', null, { headers: { Authorization: "Bearer YOUR_ACCESS_TOKEN" } }).then(function (res) {
      console.log(val);
   }).catch(function (error) {
      console.log(error);
   }));
   //...
   //省略
   //...
});

```

#感想
今回の場合は素直にHueとか買った方が早いけど、家に赤外線で操作できる機器が多い人はこういうwebhookを用意しておくと便利かも。
Cloud Functions for Firebaseから外のAPIを叩きたい場合は有料プランを使わないとダメらしくちょっとハマった。
https://firebase.google.com/pricing/?hl=ja
Alibaba Cloud の VSwitch と VRouter について

Alibaba Cloud の VSwitch, VRouter について整理しておきます。

## VSwitch
- AWS でいうサブネットだと考えれば良いと思います。
- VPC を作り、その中に VSwitch を複数作ってサブネットを分けていくイメージです。
- 下の構成図では Zone ごとに 1 つの VSwitch（サブネット） が作られています。　
- VPC あたりの VSwitch 数の上限は `24` です。　

## VRouter
- VPC 内のゲートウェイです。　
- VPC 内の全ての VSwitch が接続されます。　
- VPC に 1 つだけ作ることができます。
- VRouter では 1 つのルートテーブルを管理します。
  - ルートテーブルのエントリ数の上限は `48` です。（チケット起票により解除可能）
- VPC:VRouter:ルートテーブルは 1:1:1 の関係です。
- VPC 内の全てのインスタンスがこの　1 つのルートテーブルによりルーティングされます。　

![1.png](https://qiita-image-store.s3.amazonaws.com/0/135946/59de59ac-d630-8459-12f1-b52436a7ed7f.png)
https://jp.alibabacloud.com/help/doc-detail/54095.htm
ApacheとPHP-FPMのphp_value設定

## 概要
.htaccessなどで、phpの設定を変更したりできますが、
php-fpmを使った場合、通常の書き方だとエラーになったのでメモしておく。

## 通常の書き方

```apacheconf:.htaccess
# PHP5.6 (E_ALL(32767) - E_NOTICE(8))
php_value error_reporting = 32759
```

## PHP-FPMの場合の書き方

```apacheconf:.htaccess
  # Docker PHP-FPM5.6 (E_ALL(32767) - E_NOTICE(8))
  SetEnv PHP_VALUE "error_reporting = 32759"
```

## 参考サイト
* [Equivalent of php_value under Apache + php-fpm
](https://stackoverflow.com/questions/35265082/equivalent-of-php-value-under-apache-php-fpm)
【エンジニア向け】3分で学べるデザインの基本

# 事始め
あなたはまるで下請けのようにデザイナからの指示にはいはいと従っていれば良いなんて思ってませんか？
いいえ、これからはエンジニアですらデザインを勉強し、デザイナとデザインに関してやりとりする必要が出てきています（と私は勝手に考えています）。
デザイナとエンジニアはお互いに歩み寄るべきパートナーであり、お互いの協力なくして最高のユーザー体験は生まれないでしょう。
デザインともなるとまるで畑違いな感覚的なもので分からないと思う方も多いとは思いますが、デザインは理論であり、エンジニアでも意外と基本を把握することは難しくないと思います。
そこでここでは本当に簡単、簡潔、単純に、デザインの基本中の基本部分だけを抜き出してまとめてみました。

# デザインとは
作り手の意図を明確に伝えるための技術。見た目だけではなく、それがどう機能するのかも含めたもの。

## デザイン原則
* 近接(Proximity)：関係する情報を近くに配置すること。関係するものは近く、関係ないものは遠くするということで余白が大切
* 整列(Alignment)：要素を左揃え/右揃え/中央揃え/上端揃えのように揃えること。近接した要素をさらに揃えて一体感を持たせる
* 強弱(Contrast)：重要な要素を目立たせること。太さ、フォント、サイズ、色で重要な要素とそうでないものをはっきり区別させる
* 反復(Repetition)：全体に一体感を持たせること。配色やアイコン、近接/整列/強弱のルールを全ての画面で統一する
    * 反復はWebサイトやアプリそのものから受ける印象に繋がる。一貫性を保つための表現のスタイルや方法などのルールのことを「トーン&マナー」という（デザイナさんがトンマナがどうとか言った場合は統一感とか一貫性とかそういう意味合いだと思えば良いと思います）

## デザインの要素
デザインを考える上で必要になる要素には以下のように様々なものがあります。
全てがユーザの体験に繋がるため、良いデザインにするためにはより多くの要素を正しく検討し、積み上げる必要があります。

* 色（後述の配色を参照のこと）
* フォント：丸文字だと可愛い、のようにフォント自体の持つ印象があるので、サービスイメージに合わせた選択が必要
* レイアウト：上述のデザイン原則に従い、全体の構造を設計する必要がある
* 写真：使用されている写真の色味などの統一感や明るさなども全体の印象に影響する
* 文量：情報が多いと人は認識が難しくなる。簡潔さ、単純さ、明確さを心掛けるのが大切
* 操作感：クリック時のアニメーションなど、ユーザ体験に関わる部分

# 配色
## 色の印象
色にはそれぞれが持つ印象があるので、色を決める際には伝えたいことやイメージと合致しているか確認しましょう。

* 赤：生命力、活力、情熱的、購買意欲、熱い
* 青：清潔、誠実、クール、冷たい
* 橙：親しみ、健康、楽しい気分
* 黄：興奮、注意喚起、賑やか

など。

## 配色の手順
* メインカラーを決める：サービスの意味を表す為の色。はっきりとした濃い目の色が選ばれやすい
* ベースカラーを決める：背景などで使う色。背景なので白や薄い色が選ばれやすい
* アクセントカラーを決める：重要な要素に対する強調色。メインカラーの対比色（色相で反対の色）が選ばれやすい

画面全体のうち、ベースカラーを70％、メインカラーを25％、アクセントカラーを5％くらいにすると比率的にはちょうど良いらしいです。

## 4色以上使いたい場合
先ほど決めた3色のうちどれかの色を分割しましょう。
色相が同じで[トーン(色調)](http://creators-manual.com/tone/)が違う色、
あるいはトーンが同じで色相が違う色
を使うのが望ましいです。

## 色を決める為の便利なサイト
[HUE/360](https://hue360.herokuapp.com/)がとても便利です。
理論をどうこうするよりここで色を決めることを習慣付ける方がきっと早いでしょう。
HUE/360紹介記事1：https://gigazine.net/news/20150730-hue-360/
HUE/360紹介記事2：https://www.internetacademy.jp/blog/ja/2016/04/20160420-hanabi.html

# デザインガイドライン
以上のデザインに関する原則について、より具体的にサービスごとにルールとして落とし込んだものがデザインガイドラインと呼ばれるものになります。
iOSであればHuman Interface Guidelines、AndroidであればMaterial Designが有名でしょう。
これらのガイドラインを学習することで、優れたデザインを実現することが可能になります。
詳細については公式ドキュメントの他、色々な解説記事がありますのでそちらに譲りますが、こうしたガイドラインを学習するだけでもデザイナとの話についていくことができるようになると思います。

# その他リンク
[エンジニアがWebデザインを学ぶ際のスライド13選](https://mayonez.jp/topic/1542)
[Human Interface Guidelines](https://developer.apple.com/ios/human-interface-guidelines/overview/themes/)
[Material Design](https://material.io/guidelines/)
StoreとLocalStorageを部分的に同期させる（備忘録）

同期は[redux-localstorage](https://github.com/elgerlambert/redux-localstorage)を使用して実現する
デフォルトだとStoreのState全て同期するため、設定用の関数(slicer)を定義する

本記事は本家READMEの実装サンプル的な位置づけ


## 実装ルール

- persistState関数に設定値を渡したものをcomposeする
- keyに設定した値がLacalStorage上のKeyとなる
- ValueはJSON形式で一括して保存される

Stateがこのような構造で定義されているとして、user: {id, name}だけ同期したいものとする

```js

const state = {
  user: {
    id: 1,
    name: "foo",
    address: "bar",
  },
  data: {
    /* ... */
  },
}
```

Storeの定義を以下のように書く

```js

import {compose, createStore} from 'redux'
import persistState from 'redux-localstorage'

const store = createStore(
  reducer,
  initialState,
  compose(
    middlewares,
    persistState("", {
      key: "hoge",
      slicer,
    })
  )
)


// slicerで以下のようにStateから必要な部分を切り出す

const slicer = () => (state) => ({
  user: {
    id: state.user.id,
    name: state.user.name,
  },
})
```

ブラウザ上では以下のように保存される

|Key|Value|
|:-------|:-------|
|hoge|{"user":{"id":1,"name":"foo"}}|

## 締めの感想

勝手に変換して同期してくれるので非常に楽だった


## 参考
https://github.com/elgerlambert/redux-localstorage
Alibaba Cloud クレジット

#概要
Alibaba Cloudの請求コンソールに`Alibaba Cloud クレジット` という機能が追加されていたので試そうとした話

#ビリングアラート
ドキュメントにありませんが新しく追加されているようです。
https://jp.alibabacloud.com/help/doc-detail/57276.htm?spm=a3c0i.q42445ja.b99.6.62669d78zkE8FK
![料金・支払い管理1 2.png](https://qiita-image-store.s3.amazonaws.com/0/234379/b7d0cac0-7654-6b97-17c0-2231607b93c3.png)


Alibaba Cloud クレジットを見てみます。
![料金・支払い管理_3.png](https://qiita-image-store.s3.amazonaws.com/0/234379/f3a36b24-5d82-ad1f-94c0-c836b3f845fa.png)


利用限度額が300,000JPYで設定されているようです。
![料金・支払い管理 4.png](https://qiita-image-store.s3.amazonaws.com/0/234379/f30a6b0f-c319-2f59-fc21-ba638838eea8.png)


なぜビリングアラートが二つあるのか分からないのでサポートに聞いてみました。
回答は
_Alibaba Cloud クレジットは請求書払いを利用するお客様が使う１つの支払い方法です。_
_一部の企業さんのみご利用いただけます。_

#まとめ
個人で使用する場合は必要なさそうですね。
Springの＠Asyncが便利すぎて鼻血でた

バタバタしているので後で見返せるようにザクッとメモ

# ポイント
- デフォルトでは@Asyncによる非同期処理が機能しないので@EnableAsyncをつける
- @Service内のメソッドやクラス単位で@Asyncを付与。これだけでその部分を非同期処理にすることができる。
- ExecutorをリターンするgetAsyncExecutorメソッドをオーバーライドすることで設定が書ける

```java
@Async // コメントアウトすると、メインスレッドで実行されるようになります。非同期処理はなされなくなりますが、コンパイルエラーにはなりません。
    public Future<User> findUser(String user) throws InterruptedException {
        logger.info("Looking up " + user);
        String url = String.format("https://api.github.com/users/%s", user);
        User results = restTemplate.getForObject(url, User.class);

        // 非同期処理を並列実行することによって、処理時間が短縮されることを分かりやすくするための sleep です。
        Thread.sleep(1000L);
        return new AsyncResult<>(results);
    }
```
関係ないけど参考記事のこの部分を見て、未だ利用したことのないRestTemplateに俄然興味を持った。
機会があればいじってみたい。ストックとして面白そうな記事を載せておく。
### 参考記事
[Spring Boot における非同期処理](https://www.qoosky.io/techs/2e9599819d)
[Springの@Asyncで非同期処理をする](http://kimulla.hatenablog.com/entry/2016/11/01/234211)
[Springbootで非同期処理はとっても簡単](https://qiita.com/aono-masashi/items/0ef2a0ddc8d901ff27dd)
[Javaの並列化コードサンプル集](https://qiita.com/thtitech/items/3b874fe589b61239506f#mpsd%E3%82%84mpmd%E3%81%AE%E4%B8%A6%E5%88%97%E5%8C%96)(MPSDやMPMDの並列化あたりはThread、Runnableの参考にできる)
[さあ、並列プログラミングをはじめよう](https://qiita.com/koduki/items/086d42b5a3c74ed8b59e)(ExecutorはThreadの上位互換っぽい)
[非同期処理にはThreadを直接使わずにExecutorServiceを使用する](http://javabayashi.hatenablog.com/entry/2014/05/29/193147)

### ストック
[SpringのRestTemplateが便利すぎて鼻血でた](https://qiita.com/yoshidasts/items/fd4e1f4434e3b6f40880)
Alibaba Cloud の VPC CIDR ブロックについて

Alibaba Cloud で VPC を作成する場合、CIDR ブロックは ***基本的*** に 3 つから選択する必要があるようです。

- 192.168.0.0/16
- 172.160.0.0/12
- 10.0.0.0/8

AWS の場合は自分で指定して入力できるので、AWS に使い慣れた方だと戸惑うかもしれません。一方、クラウド初心者やネットワークがあまり詳しくない方にとっては簡単で使いやすいのかなと思いました。

ただ、これ以外の CIDR ブロックを使いたい場合は、チケットを切って依頼すれば解除可能なようです。https://jp.alibabacloud.com/help/doc-detail/27750.htm

### Alibaba Cloud の VPC 作成画面
<img width="891" alt="スクリーンショット 2018-01-30 16.45.03.png" src="https://qiita-image-store.s3.amazonaws.com/0/135946/b7ee4ecf-2a2e-72dc-dcbf-cc54e78f211a.png">

### AWS の VPC 作成画面

<img width="688" alt="スクリーンショット 2018-01-30 16.46.52.png" src="https://qiita-image-store.s3.amazonaws.com/0/135946/ace32143-adaa-f0fe-86f8-e55848660e7f.png">
railsのバリデーションメッセージの多言語化とgettext

## 概要

今作成中のrailsアプリで、多言語化の仕組みは[gettext](https://github.com/grosser/gettext_i18n_rails)を採用しました（賛否両論あると思いますが私の好みです）。

ただ、バリデーションのエラーメッセージやテーブルのカラム名など、同じ文言を繰り返し使うようなものはデフォルトのrailsのI18nの仕組みの方が向いていると思い、併用するために調査しました。

デフォルトI18nで独自のメッセージを設定する方法と、調査中に出会ったgettextの不可解な挙動も合わせて、備忘録も兼ねて共有します。

ロケールの設定やI18n・gettextのセットアップについては触れません。

## デフォルトI18nのバリデーションメッセージについて

例えば、Shopモデルのname属性のpresenceバリデーションだけ特別なメッセージに変更したいとします（あまりないとは思いますが）。


で、パッと思いついたのはこんな感じ・・・

```rb
# app/models/shop.rb
class Shop < ApplicationRecord
  validates :name, presence: {message: I18n.t('activemodel.errors.models.shop.blank')}
```

これは当然ですが期待通り動きません。`validates`はクラスメソッドなので、最初にクラスがロードされる時に一度だけ評価されるので最初に読み込まれた時の言語で固定されてしまいます。

messageにはProcを渡すことが可能で、Procで渡せばリクエスト毎に評価されます。

```rb
# app/models/shop.rb
class Shop < ApplicationRecord
  validates :name, presence: {
    message: -> (rec, data) do
      I18n.t('activemodel.errors.models.shop.blank')
    end
  }
```

ちなみにlengthのように複数のメッセージがある場合はそれぞれ個別のキーで指定する必要があります。どんなキーがあるかは[ソース](https://github.com/rails/rails/blob/v5.1.4/activemodel/lib/active_model/validations/length.rb#L4)を見るのが手っ取り早いと思います。

```rb
  validates :name, length: {
    minimum: 1,
    too_short: -> (rec, data) do
      I18n.t('path.to.error.message')
    end
  }
```

では複数のモデルで使いまわしたいバリデーションのメッセージを変更する場合どうするか？

例えばbooleanの必須チェックは`inclusion`で行いますが、デフォルトのメッセージを変えてしまうのは本来の意味で使う時に不具合があるので、booleanのチェックで使う`inclusion`だけ変えたいと思います。

ところが、先ほどのメソッドを指定するパターンでは引数を渡すことができないため、カラム名を指定できないので親クラスに作っていくつかもモデルで使い回すことができません。

そういう場合はカスタムバリデーションクラスを書きます。

```rb
# app/validations/booloean_presence_validator.rb
class BooleanPresenceValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    # 第二引数に`:blank`と指定しているのは`I18n.t('errors.messages.blank')`と同義です。
    record.errors.add(attribute, :blank) unless [true, false].include?(value)
  end
end
```

```rb
# app/models/shop.rb
class Shop < ApplicationRecord
  validates :name, booloean_presence: true
```

こうしておけば複数のモデルで使い回せます。


## gettextの不可解な挙動

不可解というのは、デフォルトのバリデーションメッセージを多言語化する時に最初に試した失敗する方法で、gettextではちゃんと翻訳ができてしまった（ように見えた）のです。

```rb
# app/models/shop.rb
class Shop < ApplicationRecord
  validates :name, presence: {message: _('を入力してください。')}
```

この状態で、まず、日本語のページを開いて、のちに英語のページを開くとちゃんと英語に翻訳されたんです。クラスメソッドなので２度評価されることがないのにそんなはずはないと思ってコードを追って見ました。

バリデーションのエラーメッセージが生成される場所は[ActiveModel::Errors::generate_message](https://github.com/rails/rails/blob/v5.1.4/activemodel/lib/active_model/errors.rb#L388)メソッドで、その最後のところで`I18n.translate(key, options)`に渡され、keyからメッセージが生成されます。

[translate](https://github.com/svenfuchs/i18n/blob/v0.9.3/lib/i18n.rb#L156-L173)の中では、`config.backend.translate`に最終的に処理が渡され、gettext使用時は`config.backend`には`GettextI18nRails::Backend`が入ってるので[これ](https://github.com/grosser/gettext_i18n_rails/blob/v1.8.0/lib/gettext_i18n_rails/backend.rb#L18)が呼ばれます。

gettextでは辞書のキーはソースに書いた文言そのもの、「を入力してください。」がキーになっているので、それでうまい具合に翻訳が成功していたんですね。

つまり、最初に英語のページが表示されるとキーが` is required.`になってしまい、翻訳がうまくいきません。最初に「（ように見えた）」と書いた通り、gettextでも、クラスメソッドでメッセージを設定する方法はうまくいかないということです。
AWS Elastic Beanstalkで、デプロイ時に一つのインスタンスにだけ実行

Elastic Beanstalk へのデプロイで、一つのインスタンスにだけ実行するには `container_commands` に `leader_only` というフラグを立てれば良いと思われるが、上手く動作しなかった。しかもオートスケール時には動作しないらしい。

ので、ELB に問い合わせて自身のインスタンスIDと比較するという方法を取った。下記のスクリプトを配置すれば可能。

```bash
#!/usr/bin/env bash

if aws elb describe-load-balancers --query 'LoadBalancerDescriptions[].Instances' --region ap-northeast-1 --output text \
    | cat -n \
    | grep $(curl http://169.254.169.254/latest/meta-data/instance-id) \
    | awk '{print $1}' \
    | grep -q 3
then
    echo 'HOME=/tmp' | sudo tee /var/spool/cron/webapp
    echo '* * * * * php /var/app/current/artisan schedule:run >> /dev/null 2>&1' | sudo tee -a /var/spool/cron/webapp
fi
```

- `grep -q 3` は決め打ちの番号なので、環境で調整する必要あり。
- インスタンスの中で `curl http://169.254.169.254/latest/meta-data/instance-id` とすると、そのインスタンス自身のIDが取得できる。
- IAMロールの設定が別途必要。Elastic Beanstalkに振られているIAMロールに `AWSElasticBeanstalkFullAccess` を付与すれば良い。

参考

https://qiita.com/idaaki/items/a356d1785a59d4150358
rubyのinjectをcoolに書く方法


この二つは同じ

```Ruby
[1,2,3].inject(5){|init, v| init + v}
[1,2,3].inject(5, &:+)
```

追記；これも同じ

```Ruby
[1,2,3].inject(5, :+)
```


#####block、proc、&の説明

& operator to convert a symbol to a Proc and then to a block:

```Ruby
names = ['bob', 'bill', 'heather']
//これは全て同じ結果
names.map {|name| name.capitalize } 
names.map(&:capitalize.to_proc)
names.map(&:capitalize)
```

####to_procは何をやっているのか？

```Ruby
class Symbol
  def to_proc
    Proc.new {|x| x.send(self) }
  end
end
```
EditorModeのTestRunnerで非同期関数をテストする


非同期関数をTestRunnerで実行したところ常にPassしてしまってとまどったのでその結果をサンプルとして残しておきます。

``` Test_AsyncBehavior.cs
using UnityEngine;
using UnityEngine.TestTools;
using NUnit.Framework;
using System.Threading;
using System.Threading.Tasks;
using System.Collections;
public class Test_AsyncBehavior : MonoBehaviour
{
    ///非同期関数を使うユースケース
    void Start()
    {
        Task.Run(Function);
        var a = 10;
        Debug.Log(a);
        var result = Task.Run<int>(() => { return CalcFunction(a); }).Result;
        Debug.Log(result);
    }

    //Asyncに文字出力をする関数
    private async Task Function()
    {
        Debug.Log("begin function()");
        for (var i = 0; i < 5; ++i)
        {
            await Task.Delay(1000);
            Debug.Log(i);
        }
        //親がWaitしない場合にはこれ以前にTestが終了するためPassする
        //Assert.IsFalse(true);
        Assert.IsTrue(true);
        //親がWaitしない場合にはここまで到達しない。
        Debug.Log("end function()");
    }

    //Asyncに渡された数の2乗を結果として返す関数
    private async Task<int> CalcFunction(int n)
    {
        await Task.Delay(3000);
        //これは失敗する
        //Assert.IsTrue(false);
        return n * n;
    }

    /// 非同期関数のテスト
    [Test]
    public void Test_Asyncs()
    {
        //当然成功
        Assert.AreEqual(10, 10);
        //当然失敗
        //Assert.AreEqual(10, 20);
        //中にAssertを持つ関数を呼び出す
        var task = Task.Run(Function);
        Debug.Log("runs async function.");
        //非同期関数を呼び出して待つ
        var result = Task.Run<int>(() => { return CalcFunction(4); }).Result;
        Debug.Log("runs async calculation 4x4.");
        //成功
        Assert.AreEqual(16, result);
        Debug.Log("pass result of calculation.");
        //失敗する
        //Assert.AreEqual(25, result);
        //これをしないとFunctionの実行完了をまたずにTestを通過する
        task.Wait();
    }
}
```

問題となったのは

```
        var task = Task.Run(Function);
        ...
        task.Wait();
```

の部分で、Waitしてあげないと先にTestが終了してPassしてしまうよ、という至極当然なつまづきでした。このへん怪しいので次はPlaymodeのテストを書いてみたいです。

### 参考

[Unity Document TestRunner](https://docs.unity3d.com/2017.3/Documentation/Manual/testing-editortestsrunner.html)
MySQLが起動しない時の対応


```shell-session
[ERROR] Fatal error: Can't open and lock privilege tables: Table 'mysql.user' doesn't exist
```

システムテーブルをアップグレード

```bash
mysql_upgrade -uroot
```

```shell-session
ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: NO)
```

設定を変更

```my.cnf
[mysqld]
skip-grant-tables
```


```bash
mysqld_safe --skip-grant-tables &
```

```bash
mysql -uroot
```

```mysql
flush privileges;
```

```mysql
grant all privileges on *.* to 'root'@'localhost' with grant option;
```

```mysql
flush privileges;
```

```bash
service mysqld stop
```

```bash
service mysqld start
```

今度はloginできる

```bash
mysql -uroot
```

my.cnfをコメントアウト

```my.cnf
[mysqld]
#skip-grant-tables
```

```bash
service mysqld restart
```


```bash
mysql_upgrade -uroot
```
一つのNICに２つのIPを設定する


```bash
ip -4 addr
```

こういうケース

```
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 
    inet 127.0.0.1/8 scope host lo
    inet 172.27.111.152/32 brd 172.27.111.152 scope global lo:0
```

```bash
vi /etc/sysconfig/network-scripts/ifcfg-lo:0
```

```bash
DEVICE=lo:0
IPADDR=172.27.111.152
NETMASK=255.255.255.255
NETWORK=172.27.111.152
BROADCAST=172.27.111.152
ONBOOT=yes
NAME=loopback-dsr
```

```
vi /etc/sysconfig/network-scripts/ifcfg-lo
```

```bash
DEVICE=lo
IPADDR=127.0.0.1
NETMASK=255.0.0.0
NETWORK=127.0.0.0
# If you're having problems with gated making 127.0.0.0/8 a martian,
# you can change this to something else (255.255.255.255, for example)
BROADCAST=127.255.255.255
ONBOOT=yes
NAME=loopback
```

###こちらは通常のIP設定

```
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP qlen 1000
    inet 172.27.111.61/24 brd 172.27.111.255 scope global eth0
```

```
vi /etc/sysconfig/network-scripts/ifcfg-eth0
```


```bash
DEVICE=eth0
BOOTPROTO=static
IPADDR=172.27.111.61
NETMASK=255.255.255.0
NETWORK=172.27.111.0
BROADCAST=172.27.111.255
NM_CONTROLLED=no
IPV4_FAILURE_FATAL=yes
IPV6INIT=no
TYPE=Ethernet
ONBOOT=yes
```
サーバssh時にワンタイムパスを設定、自宅からの本番サーバsshを会社に認めさせたい。

会社＞　セキュリティ的に家にPCもってかえったらだめだから！
開発＞　ふぁ！？全員帰宅後に本番サーバ落ちたら明日の朝起こしますわー（拳で抵抗
会社＞　売り上げさがるんごね(´・ω・｀)

###【そこで妥協案】
1. 超セキュリティー頑丈な踏み台サーバ用意（公開鍵認証とワンタイムパスワードを組み合わせた
2. このサーバには本番環境の主要なサーバにsshできる権限を付与
3. 自宅PCの公開鍵はそこに登録しておkという事にしておく（頑張る）

![image.png](https://qiita-image-store.s3.amazonaws.com/0/69647/ff55dbc7-0c84-93cc-81a0-72e7d6b40ef9.png)


### 【超セキュリティー頑丈かもしれない2段階認証】
1. 公開鍵認証
2. ワンタイムパスワード

自宅PCを奪った悪い人がサーバに入る方法
1. PCを奪う
2. PC自体のパスワード解除する
3. ターミナルから踏み台サーバのipを見つけてユーザー名@ipアドレスと入力
4. スマホを奪う
5. スマホのロックを解除する
6. ワンタイムパスワードアプリ開いて数字入れる
7. ハッキング成功！

### 【踏み台サーバの利点】
1. 本番環境のauthkey一覧では社員リストにある公開鍵のみ管理するので管理が容易になる。
2. 踏み台サーバにワンタイムパスワードを設け、このサーバを介する時だけワンタイムを必須にできる。
3. ワンタイムはユーザーごとに作成できるので退職者がでたらユーザー削除だけで大丈夫。


# 導入方法
途中まで書いたけどだいたいこれを見ると導入できる、すごく簡単所要時間1時間くらい。
http://muramasa64.fprog.org/diary/?date=20140912

途中詰まるかもしれないところ　

```bash:sshコンフィグはここに大抵あります。
/etc/ssh/ssh_config
```

```bash:sshdを再起動
sudo service sshd restart
```

```bash:ユーザーを追加
sudo adduser test
sudo su test
```

```bash:ユーザー毎に公開鍵を設定するファイルが違うので注意してください。
/home/test1/.ssh/authorized_keys
/home/test2/.ssh/authorized_keys
/home/test3/.ssh/authorized_keys
```
aliyuncli を使ってみた


[前々回](https://qiita.com/ngratin/items/02f52f5ae8f9af49d647)、[前回](https://qiita.com/ngratin/items/03fdba7137be94e1935c) と aliyuncli のインストールから AccesKey の設定までを行いましたので、今回は実際にコマンドを叩いてみたいと思います。


## Usage
aliyuncli は 4 つのパートから成っています。

- aliyuncli コマンド自身
- command はサービス名を指定します
  - ecs, rds など
- operation は各サービスのサブコマンドです
- 最後は、出力のフォーマットを指定したり、表示する数を指定したりするオプションです


```
$ aliyuncli <command> <operation> [options and parameters]
```

## リージョン情報を取ってみる
おお、リージョン名が中国語です。

```bash
$ aliyuncli ecs DescribeRegions
3E290668-0A00-493E-99F3-735D62662294
REGION  华北 1  cn-qingdao
REGION  华北 2  cn-beijing
REGION  华北 3  cn-zhangjiakou
REGION  华北 5  cn-huhehaote
REGION  华东 1  cn-hangzhou
REGION  华东 2  cn-shanghai
REGION  华南 1  cn-shenzhen
REGION  香港    cn-hongkong
REGION  亚太东北 1 (东京)       ap-northeast-1
REGION  亚太东南 1 (新加坡)     ap-southeast-1
REGION  亚太东南 2 (悉尼)       ap-southeast-2
REGION  亚太东南 3 (吉隆坡)     ap-southeast-3
REGION  亚太南部 1 (孟买)       ap-south-1
REGION  美国东部 1 (弗吉尼亚)   us-east-1
REGION  美国西部 1 (硅谷)       us-west-1
REGION  中东东部 1 (迪拜)       me-east-1
REGION  欧洲中部 1 (法兰克福)   eu-central-1
```

json や table など出力フォーマットの指定ができます。

```
$ aliyuncli ecs DescribeRegions --output json
{
    "Regions": {
        "Region": [
            {
                "LocalName": "\u534e\u5317 1",
                "RegionId": "cn-qingdao"
            },
            {
                "LocalName": "\u534e\u5317 2",
                "RegionId": "cn-beijing"
            },
            省略　...
```

## HTTPS を使う場合
`--secure` オプションを付ける必要があるようです。

```bash
$ aliyuncli ecs DescribeRegions --secure
```
Platform毎にレスポンスが違う時のCloudFrontを効率よくキャッシュHITさせる方法

## 要件
今回のPlatform毎にレスポンスが違うというのは、iPhone、Android、（PC）毎にアプリケーションサーバが違うレスポンス返す場合を想定する。

## 問題点
アプリケーションサーバ側でUAを判定して、レスポンスを生成しているため
CloudFrontで用意されている下記のフラグだけでは判定が難しい。

```
CloudFront-Is-Desktop-Viewer
CloudFront-Is-Mobile-Viewer
CloudFront-Is-SmartTV-Viewer
CloudFront-Is-Tablet-Viewer
```
[デバイスタイプに基づいてオブジェクトをキャッシュするように CloudFront を設定する](https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/header-caching.html#header-caching-web-device
)

## 結論
１. Lambda@Edgeを使ってUAを書き換える

```javascript

'use strict';
exports.handler = (event, context, callback) => {

    // Get request and request headers
    const request = event.Records[0].cf.request;
    const headers = request.headers;
    
    if (headers['User-Agent']) {
        headers['User-Agent'] = headers['User-Agent'][0].match(/(Android|iPhone)/)? RegExp.$1: 'Other';
    }
    callback(null, request);
}
```

２. CloudFrontの `Whitelist Headers` に `User-Agent` を指定

![image.png](https://qiita-image-store.s3.amazonaws.com/0/210/13192885-f2a9-2b50-c059-0d6c7287be14.png)
警告が出るが無視。[参考](https://dev.classmethod.jp/cloud/aws/cloudfront-mobile-device-detection/)


## まとめ
警告にもあるが、UAをそのままキャッシュするとUA毎のキャッシュになってしまいキャッシュのHIT効率が落ちるため、UAを簡略化させて効率良くCloudfrontを活用できる。
別のカスタムヘッダーではなく、UAに詰め直したのはアプリーケーションサーバ側のコードを変更させたくなかったため。
IntelliJからAnaconda NavigatorのEnvironment作成を行う

**以下のメッセージが表示されてこのページを訪れた方へ**
```Anaconda installation is not found```

上記エラーはAnaconda3をEドライブなど既定のフォルダにインストールしていない場合に発生します。
DOSプロンプトを開いて、以下のコマンドを入力してください。最後の引数は自分がAnaconda3をインストールした場所を選択してください。

```mklink /D %HOMEPATH%\anaconda E:\Anaconda3```

その後、以下の手順でIntelliJ(Pycharm)からEnvironmentを作成します。

# Environments作成

- File -> Project Structureをクリック
- 左ペインのSDKsをクリック
- 右ペインの「＋」をクリック
![image.png](https://qiita-image-store.s3.amazonaws.com/0/161223/e89eadbf-0cb3-a437-7bc8-3870e054d6d0.png)


- Python sdkをクリック
- add localをクリックすると以下のダイアログが表示されるので左ペインからConda Environmentを選択
![image.png](https://qiita-image-store.s3.amazonaws.com/0/161223/382fce85-0d4c-bf6a-1b21-3bc7aab51958.png)

 

Locationには **E:\Anaconda3\envs\test_envなどを指定してください。この場合はtest_envがAnaconda Navigator上で表示されます。
- OKを押下してダイアログを閉じます。

# 作成したPython実行環境をProjectのSDKに変更する
- File -> Project Structureをクリック
- 左ペインの Projectをクリック
![image.png](https://qiita-image-store.s3.amazonaws.com/0/161223/c3db74b0-2b2b-d18d-b412-47f7bbc2f5f7.png)

- 右ペインのProject SDKを作成したSDKに変更する
- OKを押下してダイアログを閉じます

# Pythonパッケージの追加
ANACONDA Navigatorからパッケージの追加が可能です。追加と同時にIntellijでそのパッケージが利用できるようになります。
CircleCiは勝手にmysqlのバージョンを書き換えるので固定しよう。

# CircleCiでmysqlのバージョンが低い時に出るClient::SECURE_CONNECTION
本番環境とSTG環境
具体的なエラー

```bash:circleCiのconsole
rake aborted!
Bundler::GemRequireError: There was an error while trying to load the gem 'mysql2'.
Gem Load Error is: uninitialized constant Mysql2::Client::SECURE_CONNECTION
```

## gemのmysql2を使っている場合バージョンを固定しましょう。
いろいろとこのエラーの解決方法がネットにありますが全部無駄でした。
なので最終的にGemのバージョンを固定する事にしました


1. 基本的にはGemfile.lockが固定しているがcircle ciは専用のmysqlがあるらしく勝手に書き換える
2. その時にlockファイルのバージョンを参照してくれていないらしい
3. Gemfile自体に指定しましょう。


以下例になります（バージョンが古いのでご注意ください。）

```rb:Gemfile
gem 'mysql2' , '0.3.17'
```

ここにバージョン一覧がありますのでサービスのバージョンに合わせてご利用を。
https://rubygems.org/gems/mysql2/versions
Alexaでお金を稼ぐことはできるのか


スマートスピーカーといわれる、音声操作に対応したデバイスがここ数年話題になっている。

この記事では、Amazonが提供しているAmazon Alexaについて、
マネタイズができるのか、ということを調査してみた。

※この記事の情報は、12月2017年ころのものを参考にしています。


# Alexaとは
Amazon EchoやAmazon Echo Dot,Amazon Echo Show,また他のサードパーティのAlexaが使えるデバイスの中核となえる音声サービスのことです。

よりパーソナライズされた操作性を実現するにあたって、**Alexa Skills Kit(ASK)**と**Alexa Voice Service**が存在します。


# Alexa Skills Kit(ASK)とは
設計者や開発者、企業は、ASKを使って魅力的なスキルを開発し、数多くのユーザーにアピールすることができる。セルフサービスの一連のAPI、ツール、ドキュメント、コードサンプルなどが無料で公開されている。
それらを利用して**スキル**を作り出すことができます。

# Alexa Voice Service(AVS)
マイクとスピーカーを搭載したインターネットに接続するあらゆる端末にAVSを使用して音声制御機構を追加できます。

# スキルとは
スキルには主に4つのタイプに分類できます。

* **スマートホームスキル**
自宅の家電などをAlexaに学ばせることで、ユーザーの生活にハンズフリーの操作性を実現します。

* **カスタムスキル**
既存のサービスやアイディアを基に独自の対話モデルを構築し、様座な場面で活用できます。

* **ゲームとトリビアのスキル**
インタラクティブなアドベンチャーゲーム、トリビアスキルで仮想現実の世界を提供できます。

* **フラッシュブリーフィングスキル**
事前に録音されたオーディオクリップなどによって、最新のコンテンツをユーザーに届けることができます。


このようなスキルを開発して、企業はサービスを提供したり、様々な情報を音声で提供したりする。また、このスキルはプログラミングの知識があれば**誰でも**開発ができるようになっている。

そして、まだ日本国内ではリリースされていないが、スキルの開発で報酬を得るということもできるようになるらしい。
その他、企業目線で音声でどういったことが収益につながるか、以下にメモってみる。

# Alexa Developer Rewards
Alexa Developer Rewardsとは、Alexa Skillの**報酬プログラム**のこと。
Amazonが以下のカテゴリで最も高いカスタマーエンゲージメントを獲得できたスキルに対し、
毎月報酬を支払うというものである。

* Education & Reference
* Food & Drink
* Games, Trivia & Accessories
* Health & Fitness
* Lifestyle
* Music & Audio
* Productivity

カスタマーエンゲージメントの詳細は提示されていないが、スキルの使用者数や使用時間、
レーティングなどから総合的に判断されるのではないかということ。
現在対象としている国は、アメリカやイギリス、ドイツのみ。


# Skill内、追加コンテンツ販売
販売方式は買い切り、サブスクリプションが可能。

**例**: クイズ番組のスキル
$1.99を毎月払うことで、毎日提供されるクイズの数が2倍に。
よくよくはAmazon Primeに対してのディスカウント設定も可能だとか。

# 既存のビジネスとの連携
すでにあるビジネス、サービスと**アカウントリンク**などによって連携し収益化することが考えられる。
※アカウントリンクとは、Alexaに設定されているユーザーと、スキルのシステムのユーザーアカウントを結びつけること。


# Amazon Pay
Amazon Skill内での支払いにAmazon Payが使用できるようになった。
勿論、Amazonアカウントのみでの支払い。Alexaと連携すれば音声での買い物も楽になりそう。
※こちらも日本はまだ


# 広告事業について
広告事業については、まだ本国アメリカでも公にされていない。
15〜45秒で商品に紹介をユーザーの購買履歴をもとにして(勿論音声で)行うのではないかと思われる。
広告といえど、ささやかに提案するような言い回しになるらしい。笑

※02.10.2018に記事がでました。
https://news.yahoo.co.jp/byline/kokuboshigenobu/20180210-00081480/

# スキルの受託
ASKやAVSが提供されているので、開発者はスムーズに開発を始められる。
とくにAlexaを利用する業界が絞られているわけではないので、きちんと台本やら発話のサンプルを
用意しておけば開発で困ることはないだろう。
経験としておすすめは、Node.jsで開発することかな〜


# (おまけ) Alexa for Business
Alexaを使って、ビオジネス及び組織の仕事場で業務の効率化をはかること、ユーザーやスキルの一元管理をするためのAmazonが提供しているサービス。
 **料金**
共有デバイス: 7USD/デバイス
登録されたユーザー: 3USD/ユーザー
※2018.1.4現在バージニア北部リージョンで使用可能

例えば以下のようなことができます。

* 会議室からミーティングに参加
Alexaは、ビデオ会議装置の電源をつけ、電話会議用電話番号にダイヤルしミーティングを開始。

* 空いている会議室を探したり、用品のオーダー、来客の応対など。

* カレンダーをチェックし、ミーティングの手助け、ToDoリストを管理したりリマインダーをセットできる。

簡単にいうと、企業向けで、来客してきたお客様の対応とか、
(今でも受付で電話するところがおおいかな？ でも、一人で受付で「アレクサ！」とか言えるのか？ｗ)
家にいてもどこにいてもAlexaがあればミーティングに参加(社畜フラグww)できたり、
音声で開いている会議室とか確認予約できるようです。


## まとめ
* ユーザーに好まれる優良スキルを開発すること
* 既存ビジネスとの連携をして売り上げる(既存ビジネスに課金コンテンツがあれば)
* 高単価で受託をたくさんこなす(デプロイや開発環境効率化をまず整えたほうが良いかも〜)
* Skill内追加コンテンツが日本に導入されるまで待って、Skill内課金で売り上げる

サクッとしたメモでした。
データ分析で気を付けるたった3つの事

これまでの自分の経験に基づいて，データ分析の際に気を付けておくべきことを3つに纏めました．
後輩の進捗報告を聞く時などによく指摘する事で，データ分析の経験が浅い人が見落としがちな事を中心に書きました．

# 目的と手段
データ分析で一番最初に行うことは，目的の設定，もしくは目的を正しく理解することです．
前者は自分で目的を設定する場合，後者は目的が既に決まっている（例えば，上司や先輩が目的を設定してそれが担当者に降りてくる）場合です．

前者の場合は問題が起きることはほぼありませんが，後者の場合は手段が目的となってしまうという問題がよく起こります．
例えば，有料会員を増やすことが目的の場合に，上司や先輩が「まずはユーザをクラスタリングに掛けてみれば？」とアドバイスします．
そうすると，最初は目的を意識できているのですが，いつの間にかユーザをクラスタリングに掛けることが目的になっていたりします．
その結果，複雑なロジックでユーザをクラスタリングに掛けたものの，「So what?（だから何？）」になる事が多いです．

前記の例では，ユーザをクラスタリングに掛けることはあくまでも手段の一つなので，

- ユーザをクラスタリングに掛ける以外に，何か良い手段はないのか？
    - 例えば，離脱率が高いページを見つけ，そのページを改修する方が効果的かもしれません．
- ユーザをクラスタリングに掛けた後に，具体的にどういう施策を打てるのか？

について考える事にもっと時間を割いた方が良いかもしれません．
そして，その方が結果的にROI(Retrun On Investment)が高くなるというのはよくあります．

データ分析の際は，目的と手段を明確に意識しておくことが大切です．

# データの信頼性
目的と手段が整理できれば，いよいよ分析作業に取り掛かります．
但し，分析作業に取り掛かる前に確認すべき事があります．それがデータの信頼性です．

例えば，

- データが欠損している
- データは入っているが，正しくないデータが入っている

という事はよくあります．

後者の例として，ログデータのタイムスタンプが2030年などになっており，「未来のデータがやってきた！？」となるのはどの会社でもよく聞く話しです．
この場合，

- タイムスタンプが正しくない（例：未来の時刻になっている）データは分析対象から外す
- ログの取得部分のシステムを修正する
    - 前記の例では，クライアント側で設定している時刻を取得している事が多いので，サーバ側で設定している時刻をタイムスタンプとして取得するようにシステムを修正します．クライアント側の時刻はユーザが自由に変更できますが，サーバ側の時刻がズレているということはほぼないので．

の対応策を取る必要があります．

信頼性の低いデータから導き出された結果は，時に間違った結論になり得ることがあります．
データ分析の際は，データの信頼性を担保することが大切です．

また，データの取得条件を揃えることも重要です．
例えば，ユーザの過去一年分のログデータを分析する場合を考えてみましょう．
その際，Aさん，Bさん，Cさんの過去一年分のログデータを取得しようと思って，

``` sql
select
   *
from
   pv_log
where
   created_at < current_date
   and created_at >= current_date - interval '1 year'
   and user_id in ('A', 'B', 'C')
;
```

のようなSQLでデータを抽出しました．

ただ，上記の場合に一つだけ気を付けなければならない事が一つだけあります．
それは，上記で抽出したデータは必ずしも一年分のログとは限らないという事です．

どういう事かと言うと，

- Aさんは2年前に会員登録
- Bさんは1年半前に会員登録
- Cさんは1ヶ月前に会員登録

だった場合に，Cさんのデータは実質一ヶ月分しかないという事です．
一年分のデータと一ヶ月分のデータを比較すると，前者の方がページ総閲覧数や総滞在時間は多い可能性が高く，また，休眠ユーザになっている可能性も高いです．

それでは，どう対応すれば良いのかというと，例えば，1年以上前に会員登録したユーザだけに限定した上で会員登録後一年間のデータを抽出するというのが一つの解決策です．
そうすれば，データの取得条件がより等しくなり，同じ土俵の上で分析を行う事が可能になります．
もちろん季節要因（夏に会員登録したユーザと冬に会員登録したユーザはサイト上の動きは違うかもしれない）などの因子は等しくなっていませんが，今回はそこまで深掘りはしません．

# 比較対象
データの信頼性も担保できれば，いよいよ本丸の分析作業に取り掛かかります．
ただ，ここでも注意することがあります．それは，適切な（正確に言うと，可能な限り条件が等しい）比較対象を設定することです．

分かりやすい例として，ネット広告におけるCPA(Cost Per Action)の分析を考えます．

今，10,000円のバナー広告を出稿し，バナー広告経由の予約が5件発生したとします．
この場合，CPAは2,000円（=10,000円 / 5)となり，想定していたCPAよりも高い・安いでバナー広告の価値を判断することが多いと思います．

本当にこれでいいのでしょうか？
結論としては，これで判断することは非常に危ういです．

理由は，5件の予約の中に，バナー広告が掲出されなくても発生した予約があったかもしれないからです．
特にリターゲティング広告においては，後で予約しようと考えていた所にたまたまバナー広告が表示されたので，それをクリックして予約したという状況は十分に起こりえます．

それでは，どう対応すれば良いのかというと，適切な比較対象を設定するということです．
前記の例では，バナー広告が表示されないユーザ群も用意するということです．
そして，バナー広告が表示されたユーザ群と表示されなかったユーザ群の予約件数の差を計算し，それを基にCPAを計算します（下記の例ではCPAは5,000円となります）．

<img src="https://qiita-image-store.s3.amazonaws.com/0/127582/56b0f4d9-9ef0-fd7e-3c8d-0822d28ff810.png", width=50%>

実際のバナー広告ではユーザの制御（広告を表示するユーザと表示しないユーザの制御）が難しいので，期間で分ける事が多いです．
例えば，ある月の前半はバナー広告を出稿する一方で後半はバナー広告を出稿せずに，その予約件数の差を見るというものです．

A/Bテストは皆さんご存知だと思いますが，これはまさしく適切な比較対象を設定するための手法です．
データ分析の際は，適切な比較対象を設定することが大切です．
Mac x IntelliJ 環境で Gradle を認識させる

## 手順

```bash
# Gradle をインストール
$ brew install gradle

# Gradle のインストール場所を確認
# /usr/local/Cellar/gradle/4.5 みたいなの
$ brew info gradle
```

あとは、Gradleのインストール先のパスに`/libexec`を付け足したものを
IntelliJ の Gradle Home 部分に設定してやります。

<img width="551" alt="Screen Shot 2018-01-30 at 4.14.13 PM.png" src="https://qiita-image-store.s3.amazonaws.com/0/56635/592038d6-0332-c67d-437a-b3984049a360.png">
Rubyで新しい順から、ほしい数だけtweetを取得する

#はじめに
tweetの内、数を指定して、新しい順からtweetを抽出したかったのでRubyで書いてみました。今回は認証済みのユーザをユーザータイムラインを使っていますが、ユーザを指定すれば他のtweet群でも同じような処理ができると思います。

#gem
使うgemはtwitterです
twitter gem:  [GitHub](https://github.com/sferik/twitter)

```text
gem install twitter
```

#認証
以下のコードで認証を行います。

```ruby
client = Twitter::REST::Client.new do |config|
  config.consumer_key        = "YOUR_CONSUMER_KEY"
  config.consumer_secret     = "YOUR_CONSUMER_SECRET"
  config.access_token        = "YOUR_ACCESS_TOKEN"
  config.access_token_secret = "YOUR_ACCESS_SECRET"
end
```

#tweetを取得
コードは以下の通りです。

```ruby
def get_tweets(count)
    # countに満たないtweet数でも、エラーは起きない
    epoc_count = (count / 200) + 1

    tweets = [@client.user_timeline(count: 1)][0]
    epoc_count.times do
      @client.user_timeline(count: 200, max_id: tweets.last.id-1).each do |t|
        if tweets.count == count
          break
        end
        tweets << t
      end
    end

    # Array
    tweets.map! {|t| t.text}
  end
```
count引き数で欲しい数を指定しています。ちなみに抽出先ユーザのtweet数がcountに満たない場合でもエラーは起きません。ですが、本当はそこで分岐した方が良いかもしれません。(総tweet数はすぐ取れるのかな？）

`@client.user_timeline(count: 200, max_id: tweets.last.id-1)`という部分で、ユーザのタイムラインを抽出しています。一度のリクエストで200件までしか取れないみたいです。なのでmax_idを指定して、どのtweetから200件かを抽出する度に変えます。それを繰り返すことで、順々に古いものを抽出しています。

```ruby
tweets = [@client.user_timeline(count: 1)][0]
```

ちなみにここでは一番新しいtweetを配列の初期化の時に入れているのですが、これは一番新しいtweetのmax_idが分からないため無理やりこうしました...　

```ruby
t = TwitterContent.new()
tweets = t.get_tweets(140)
```
あとはこの様に指定すれば、最新から件数分のtweetを取得できます。

#参考
[Twitter API](https://developer.twitter.com/en/docs/tweets/timelines/api-reference/get-statuses-user_timeline)
[Twitter gem Document](http://www.rubydoc.info/gems/twitter/Twitter/REST/Timelines#user_timeline-instance_method)
[Twitter gem GitHub](https://github.com/sferik/twitter)
書いてる途中に気づきましたが、以前にも[Pythonで同じようなことしてました](https://qiita.com/hirohuntexp/items/f07fd27aa36c6ceab1e6)...
Project Euler Q73 【ある範囲内の分数の数え上げ】

Project Eulerをワンライナーで解いてみる。
間違っていたらコメントください。


## 問題
$n$と$d$を正の整数として, 分数 $\frac{n}{d}$ を考えよう. $n<d$ かつ $HCF(n,d)=1$ のとき, 真既約分数と呼ぶ.

$d ≤ 8$ について既約分数を大きさ順に並べると, 以下を得る:
$\frac{1}{8}, \frac{1}{7}, \frac{1}{6}, \frac{1}{5}, \frac{1}{4}, \frac{2}{7}, \frac{1}{3}, \frac{3}{8}, \frac{2}{5}, \frac{3}{7}, \frac{1}{2}, \frac{4}{7}, \frac{3}{5}, \frac{5}{8}, \frac{2}{3}, \frac{5}{7}, \frac{3}{4}, \frac{4}{5}, \frac{5}{6}, \frac{6}{7}, \frac{7}{8}$

$\frac{1}{3}$と$\frac{1}{2}$の間には3つの分数が存在することが分かる.

では, $d ≤ 12,000$ について真既約分数をソートした集合では, $\frac{1}{3}$と$\frac{1}{2}$ の間に何個の分数があるか?

## 解答

```bash
time seq 2 12000 |
awk '{for(i=int($1/3);i<=$1/2;i++){print $1,i,i/$1}}' |
awk '1/3<$3&&$3<1/2' |
awk '{a=$1;b=$2;r=a%b;while(r!=0){a=b;b=r;r=a%b};if(b==1){print}}' |
wc -l
7295372

real    0m23.675s
user    0m44.568s
sys     0m0.486s
```

このような数列をファレイ数列というらしい。
[ファレイ数列 - Wikipedia](https://ja.wikipedia.org/wiki/%E3%83%95%E3%82%A1%E3%83%AC%E3%82%A4%E6%95%B0%E5%88%97)

この問題もファレイ数列の性質を使うとスマートに解けるのかもしれないが、思いつかなった。

## 答え合わせ
こちらのサイト様と一致していればOKとした。
http://kingyojima.net/pje/073.html
Processing - 02 - lineとrandomを使った描画

<img width="500" alt="スクリーンショット 2018-01-30 16.05.14.png" src="https://qiita-image-store.s3.amazonaws.com/0/45520/fccfe486-ee76-f3ac-eea7-c256e9d011ff.png">

```java:
void setup () {
  size (500, 500);
  smooth ();
  strokeWeight (1);
  background (0);
}

void draw () {
  stroke(200,20);
  line(mouseX, mouseY, random (0, width), height);
}

```
Processing - 01 - translateとrotate及びPIを使った描画

<img width="598" alt="スクリーンショット 2018-01-30 16.00.08.png" src="https://qiita-image-store.s3.amazonaws.com/0/45520/867f3478-ecf0-a25e-35f2-9367d3fd87cb.png">


```java:
void setup () {
  size (600, 600);
}

void draw () {
  background (100);
  smooth ();
  strokeWeight (50);              //lineの太さ 

  translate(width/2, height /2);  //座標軸を 画面サイズの中央に
  stroke (255);                   //lineの色            
  line (0, 0, 250, 0);

  rotate(PI/6);                   //180度/6 = 30度→座標軸を 30°回転
  stroke (233.25);                //255 - 21.25 = 233.25
  line (0, 0, 250, 30);

  rotate(PI/6);
  stroke (212.5);
  line (0, 0, 250, 30);

  rotate(PI/6);
  stroke (191.25);
  line (0, 0, 250, 30);

  rotate(PI/6);
  stroke (170);
  line (0, 0, 250, 30);

  rotate(PI/6);
  stroke (148.25);
  line (0, 0, 250, 30);

  rotate(PI/6);
  stroke (127.5);
  line (0, 0, 250, 30);

  rotate(PI/6);
  stroke (106.25);
  line (0, 0, 250, 30);

  rotate(PI/6);
  stroke (85.5);
  line (0, 0, 250, 30);

  rotate(PI/6);
  stroke (63.75);
  line (0, 0, 250, 30);

  rotate(PI/6);
  stroke (42.5);
  line (0, 0, 250, 30);

  rotate(PI/6);
  stroke (21.25);
  line (0, 0, 250, 30);
}

```
表記揺れを考慮して、登録した値がマスタに登録されているかをマッチングしてみた

登録してあるレコードが、マスタに登録があるかをチェックする要件があったので実装してみました。

完全一致する必要はなかったので、ほどほど合致している値がマスタにあるのかを判定したいときに、今回の用途にバッチリあったライブラリを見つけました。

利用したのはdifflibです。
https://docs.python.jp/3/library/difflib.html#difflib.get_close_matches

# SequenceMatcherを利用したマッチング

## チェックする対象のデータ

```registration.csv
GOOGLE inc
google
COMPANY
google technology
```

## マスタに登録してあるデータ

```master.csv
GOOGLE
GOOGLE INC
goo
GOOGLE X
GOOD
```

## ロジック
まず、マスタをリストにします。その後、チェック対象のデータを１つずつループで回して、マスタに当てて、類似度をチェックするロジックです。

```python
from __future__ import with_statement
import difflib
import numpy as np

# マスタデータを内包表記でmasterListに入れる
with open("/Desktop/python/master.csv") as f:
    masterList=[line for line in f]

# チェック対象のデータを1つずつ、マスタデータ全体の値と当てる
with open("/Desktop/python/registration.csv") as f:
    for registrationLine in f:
        # チェック対象のデータ1つに対して、マスタを全ての値の類似度を計算
        # upper()を利用して、大文字小文字の差を無くす
        ratioList = [difflib.SequenceMatcher(None, registrationLine.upper(), masterLine.upper()).ratio() for masterLine in masterList]
        
        # 類似度が一番大きいデータ値とインデックスを取得する。複数ある場合は先頭の値
        npRatioList = np.array(ratioList)
        maxRatio = max(npRatioList)
        maxRatioIndex = npRatioList.argmax()
        
        # 類似度が0.8より大の場合はマスタに登録あり、小の場合は登録なし、とする
        if maxRatio > 0.80:
            print("登録あり:" + registrationLine.rstrip() + ":" + masterList[maxRatioIndex].rstrip() + ":" + str(maxRatio)) 
        else:
            print("登録なし:" + registrationLine.rstrip() + ":" + masterList[maxRatioIndex].rstrip() + ":" + str(maxRatio)) 
   
```

## 結果
```
登録あり:GOOGLE inc:GOOGLE INC:1.0
登録あり:google:GOOGLE:1.0
登録なし:COMPANY:goo:0.333333333333
登録なし:google technology:GOOGLE INC:0.571428571429
```
思っていた通りの結果になりました。名寄せテーブルなんかも作れそうです。

ただ、仕事で使ったデータでは、いまいちな結果も散見されました。例えば「red engineering」と「blue engineering」は異なる会社ですが、engineeringという長い文字列が一致しているため、類似度が高くなってしまいました。


ちなみにratio()よりも精度が低くて速いquick_ratio()とreal_quick_ratio()があるのですが、これらは精度が低すぎたので使えませんでした。


業務ではこのSequenceMatcherは遅すぎて利用できず、get_close_matchesを利用して解決しました。
データが少なければ、SequenceMatcherでも全然okかと思います。
get_close_matchを使ったロジックは別で書きます。