OmniAICreator/Qiita-1.07M huggingface dataset:
Re:Dashで便利な小技まとめ

# はじめに

皆さん、分析ツールは何を使用していますか？
弊社では、非エンジニアでも気軽に且つ多方面からデータ分析できるようRe:Dashを導入しております。
また画面を作りたくないエンジニアにとってもRe:Dashはとっても簡単・便利！
今回は使用するにあたり便利だった設定や小技をメモとして残しておきます。

# 日付のフォーマットを変更したい

何も設定しないと日付フォーマットが「DD/MM/YY」になってしまうので
下記のように指定しrestartをかけてあげると反映されます。

```/opt/redash/.env
export REDASH_DATE_FORMAT="YYYY/MM/DD"
```

>sudo supervisorctl restart redash_server

# クエリの値を動的に変更したい

{{}}で囲むと囲んだ名前で入力フォームが出現。

入力フォームに値を入力するか
{{}}で囲んだ名前に「p_」を付けたパラメータを該当クエリURLに付与すると値を動的に指定できるようになります。

```
http://example.com/queries/[クエリID]?p_[パラメータ名]=[値]
```

また入力フォーム横に設定ボタンがあり
>Text
>Number
>Date
>Date and Time
>Date and Time(with seconds)

から型を指定することも可能。
入力フォームに入力し、保存した値がデフォルト値になります。
(未入力のままクエリを保存するとクエリ結果が「Error running query: missing value for id parameter.」になります。)


例) 

![redash_param.png](https://qiita-image-store.s3.amazonaws.com/0/142453/b996dbb5-2672-2857-df4d-8477a0df95d3.png)


※上記のように作成したクエリIDが1の場合のURL
http://example.com/queries/1?p_id=2


# クエリ結果に画像を表示したい

concatを使えばクエリ結果にタグを埋め込むことができます。
例えば下記のように画像を埋め込むことも可能です。

```
select concat('<img src="[画像のURL]">') as img
```

例)

![redash_img.png](https://qiita-image-store.s3.amazonaws.com/0/142453/d41feac8-49d2-d0d6-f250-904dd039f5f8.png)


# クエリ結果を共通ヘッダー・フッターとして利用する

re:dashで作成するクエリは必ずしも実データを使用して作る必要はないんですよね。
便利な使い方として下記を紹介させて頂きます。

類似クエリ・ダッシュボードのリンク集などをクエリとして作成しておきダッシュボードに設置。
リンクを追加したいときは元のクエリに追加をすれば、設置済みのダッシュボード全てに反映されるので
修正・反映が容易な共通ヘッダー・フッター等として使用できます。

例)
![redash_footer.png](https://qiita-image-store.s3.amazonaws.com/0/142453/e65a50de-f74e-cfdc-741e-f38de68dcc2a.png)




# pythonデータソースを使ってデータをごにょごにょしたい

別々のクエリ結果(Data Sourceが異なる等)を使って更に処理したい時は
pythonデータソースを使って処理を書くことができます。

pythonでコードを書くので非エンジニアには少々難しいかもしれませんが
画面を作りたくない、けどちょっと複雑且つ別々のデータソース結果をごにょごにょして
さくっと作りたい！というエンジニアにとってはこれが結構便利！

クエリをごにょごにょする為の簡単なAPIが用意されていて
比較的容易に使用出来る為おすすめ。

こちらについては別記事でご紹介。詳しくは[こちらの記事](http://qiita.com/axm-aoki/items/4982cf8999aebc46b3d4)をどうぞ。

# さいごに

ごく一部ですが、便利だった設定や小技をご紹介させて頂きました。
まだ紹介し足りないところもあるので、それはまた後日別記事としてあげていけたらと思います。
皆様よきRe:Dashライフをお過ごしください♪


# 関連記事

[Re:Dashのアップグレードをしたい](http://qiita.com/axm-aoki/items/41e92722400e17513b78)
[Re:Dashでpythonデータソースを使ってクエリ結果をごにょごにょしたい](http://qiita.com/axm-aoki/items/4982cf8999aebc46b3d4
)
Re:Dashのアップグレードをしたい

# はじめに

Re:Dashでv1.0以前のものからv1.0以降のものにアップグレードしたので
その時の手順をメモとして残しておきます。

# /opt/redash/.envの修正

アップグレードの前に下記修正を行う必要があります。

## REDASH_DATABASE_URLの修正

`export REDASH_DATABASE_URL="postgresql://redash"`　から　`export REDASH_DATABASE_URL="postgresql:///redash"`　に変更。
※「/」が3つになります


## REDASH_STATIC_ASSETS_PATHの削除

`export REDASH_STATIC_ASSETS_PATH="../rd_ui/dist/"`　を削除

# アップグレード

```
$ wget https://raw.githubusercontent.com/getredash/redash/master/bin/upgrade
$ chmod +x upgrade
$ sudo ./upgrade
```

※v0.12以前のものからアップグレードする場合、`sudo upgrade --channel legacy`を実行してから　`sudo ./upgrade`　を実行すること

# さいごに

とっても簡単にアップグレードできました♪

# 関連記事

[Re:Dashで便利な小技まとめ](http://qiita.com/axm-aoki/items/23af956d333e4fe9115f
)
[Re:Dashでpythonデータソースを使ってクエリ結果をごにょごにょしたい](http://qiita.com/axm-aoki/items/4982cf8999aebc46b3d4)
Apache 2.4 で OPTIONS を拒否ったら 404 が返ってくるようになった

単純な見落としでハマってしまったので自戒のために書いておく。

# 事象

基本的にはタイトルのまんま。
Apache 2.4 on Linux で Web サーバのプロキシを立ていて、OPTIONS メソッドのリクエストを拒否る（403 を返す）ことになった。
もともと mod_rewrite を使っていたので /etc/httpd/conf.d/myproxy.conf に

```
RewriteEngine on
RewriteCond %{REQUEST_METHOD} ^OPTIONS [NC]
RewriteRule ^.*$ - [F,L]
```

こんなのを書いて即終了だと思ったらなんかおかしな動きをした。

```
curl -i -X OPTIONS http://example.com → 404 (NG)
curl -i -X OPTIONS http://example.com/ → 404 (NG)
curl -i -X OPTIONS http://example.com/path → 403 (OK)
```

Web ルート直下にあたるパスの場合に 403 ではなく 404 が返ってきた。
正規表現とかいろいろ変えて試してみたけどダメ。

# 原因

/etc/httpd/conf.d/welcome.conf に以下の記述があった。

```
<LocationMatch "^/+$">
    Options -Indexes
    ErrorDocument 403 /.noindex.html
</LocationMatch>
```

簡単に読み下すとこんな感じ。

* Webルートへのアクセスの場合
    * ディレクトリインデックス画面は見せちゃダメ
    * 403 エラーの場合は /.noindex.html を表示する

この2個めのルールのために /.noindex.html を表示しようとしたが、これに相当するパスを削除（無効化）してたためファイルが見つからないので 404 になってしまっていた。

mod_rewrite のログを ``LogLevel rewrite:trace8`` で出して確認してるときに Web ルートに対する OPTIONS メソッド処理の後に /.noindex.html に対する GET メソッド処理が走ってるのを見つけて気づけた。

# 対応

welcome.conf は初期構築時の確認のための設定ファイルだと思っているのと、そこに書かれている他のルールも今回は不要だと判断したのでファイルごと削除。

# 参考

[Apacheのwelcome\.confをちゃんと読んでみたら意外と勉強になった。 · DQNEO起業日記](http://dqn.sakusakutto.jp/2012/09/apache_welcome.conf.html)
ElasticSearchで日本語検索するためのローカル環境構築

:mag:ElasticSearch×形態素解析

## 環境構築してみる

[こちら](https://www.elastic.co/jp/downloads/elasticsearch)から最新バージョンをDL、適当なディレクトリに解凍する。
Javaのインストールとパスを通しておきましょう。

日本語で検索したいのでkuromoji pluginをインストールします。
私の環境ではproxyを通す必要がありました。
Windowsでは以下のコマンドでOK。[公式ドキュメント](https://www.elastic.co/guide/en/elasticsearch/plugins/5.4/_other_command_line_parameters.html)では"(ダブルクォート付き)の記述がありましたがうまく行かず、"を消せばインストールできました。

```
# set ES_JAVA_OPTS=-Dhttp.proxyHost=**.**.**.** -Dhttp.proxyPort=**** Dhttps.proxyHost=**.**.**.** -Dhttps.proxyPort=****
# elasticsearch\bin\elasticsearch-plugin install analysis-kuromoji
```
起動してみます

```
# elasticsearch\bin\elasticsearch.bat
```


http://localhost:9200 にアクセスして以下のようなJsonが取得できれば完了です。

```json
{
  "name": "aV33ZuH",
  "cluster_name": "elasticsearch",
  "cluster_uuid": "-rHtAb19QzKUiJ1_aq_-ig",
  "version": {
    "number": "5.4.1",
    "build_hash": "2cfe0df",
    "build_date": "2017-05-29T16:05:51.443Z",
    "build_snapshot": false,
    "lucene_version": "6.5.1"
  },
  "tagline": "You Know, for Search"
}
```
## 検索してみる

適当にデータを登録してみます

```
curl -XPOST http://localhost:9200/test/sample -d '{
  "id" : "1",
  "text" : "夏なのでアイスがおいしい季節になりました"
}'
```
```
curl -XPOST http://localhost:9200/test/sample -d '{
  "id" : "2",
  "text" : "桃アイスを頂いた"
}'
```
```
curl -XPOST http://localhost:9200/test/sample -d '{
  "id" : "2",
  "text" : "昨日桃ちゃんと遊んだよ"
}'
```
検索してみます

```
curl -XPOST http://localhost:9200/test/sample/_search -d '{
  "query": {
    "match": {
      "text": "アイスが"
    }
  }
}
```
```json
{
  "took": 1,
  "timed_out": false,
  "_shards": {
    "total": 3,
    "successful": 3,
    "failed": 0
  },
  "hits": {
    "total": 2,
    "max_score": 0.5398108,
    "hits": [
    {
      "_index": "test",
      "_type": "sample",
      "_id": "AVzERcmBSCe8bM-UJRG3",
      "_score": 0.5398108,
      "_source": {
        "id": "1",
        "text": "夏なのでアイスがおいしい季節になりました"
      }
    },
    {
      "_index": "test",
      "_type": "sample",
      "_id": "AVzERh6cSCe8bM-UJRG4",
      "_score": 0.2824934,
      "_source": {
        "id": "2",
        "name": "桃アイスを頂いた"
      }
    }
    ]
  }
}
```
検索ワードの「アイス**が**」の助詞が省かれていることがわかります。
jQueryで動的ボタンにアクションを追加する

# ボタンを押したら何かが起きてほしい。
　静的なボタンにアクション追加するときとjQueryで追加したボタンにアクションを追加するときで、書き方違ったので記録する。

##静的なボタンの場合

```html:index.html
<dl id="body">
  <button id="hoge">hoge</button>
  <button id="fuga">fuga</button>
  <button id="hoga">hoga</button>
</dl>
```

```js:button_action.js
$(function () {
    $("#hoge").click(function(e) {
    $(this).text("Hello World!");
  });
});
```
すると
![キャプチャ.PNG](https://qiita-image-store.s3.amazonaws.com/0/188058/ccc97f39-3407-2fb6-e850-aa4848e6ae7a.png)
が
![キャプチャ2.PNG](https://qiita-image-store.s3.amazonaws.com/0/188058/20877fd3-c431-b83f-bb4f-d5720b1fd684.png)
となる。
やっていることは、'hoge'というidにclickイベントを追加しているだけ。
clickされると、function(e)が実施され、

##動的なボタンの場合
なぜか静的なボタンのように記述してもうまくいかない。
実は、最近のjQueryではclickは推奨されておらずonを使用すべきということ。
onで書いてみる。（index.htmlに動的に要素追加する方法：[jQueryで画面にボタンを付ける - Qiita](http://qiita.com/teshima/items/2eaee98e55d596c4edfd)）

```js:button_action.js
$(function () {
    $("#hoge").on("click",function(e) {
    $(this).text("Hello World!");
  });
});
```

上記の記述は、onを使用してhogeというidにclickイベントを追加する書き方。
簡単ですね。

でも、実はこれ動きません。
動的なボタンにアクションが追加されない理由は、非推奨なclickを使っているからではないようで、
結局、"hoge"というidはindex.html起動時に存在しないため、探しても見つからないというのが原因のようです。

ということで、以下のように変更

```js:button_action.js
$(function () {
    $(document).on("click", "#hoge",function(e) {
    $(this).text("Hello World");
  });
});
```
ポイントは、onを呼び出す要素がdocumentになり、onの第二引数に"#hoge"が入っていること。
documentを指定すると、button_action.jsの呼び出し元がすべて対象になる。
そして、onの第二引数に要素を指定すると、 **onを呼び出した範囲で特定の要素のみにイベントを追加する** ということになる。
つまり、htmlファイル全体を走査し、その中でidがhogeの要素のみにイベントを追加する。という記述となる。

これで、動的なボタンにもイベントが追加出来ました。
iOS定期購読課金 アップグレード/ダウングレード Part1

前回の[クロスグレードについて](http://qiita.com/natty420/items/5979bee604271d03f8dc)の続編のアップグレード/ダウングレードの仕様についてです。

# アップグレード/ダウングレードとは

iTunes Connectにて登録する課金アイテムのうち、**同グループかつレベルが低いものから高いもの変更する** ときに適用されるのが **アップグレード**、**同グループかつレベルが高いものから低いもの変更する** ときに適用されるのが **ダウングレード**です。

ある定期購読アイテムから別のアイテムに変更する場合にスムーズに行えるためのものです。

## 仕様
以下は課金アイテムが同グループ内であることを前提としています。
レベルは1から順に高いものとします。
### アイテムの購読期間が同じ場合も異なる場合も仕様は同じです
|レベル       |アイテム      |期間　　　　　　|
|:-----------|------------:|:------------:|
|1           |アイテムA     |1ヶ月 　　　　　|
|2           |アイテムB     |1ヶ月 　　　　　|

|レベル       |アイテム      |期間　　　　　　|
|:-----------|------------:|:------------:|
|1           |アイテムA     |1ヶ月 　　　　　|
|2           |アイテムB     |12ヶ月 　　　 　|

アイテムA→Bがダウングレード、B→Aがアップグレードです。

#### アップグレード
即日課金され、乗り換え前の課金は登録日から乗り換え日までの金額をApple側で計算されて返金されます。
レシート検証するとAもBも有効期限内のレシートとなると思われます。(サンドボックスで検証するとそうなりました)
Bは有効期限後更新されず、Aのレシートは更新されていきます。

#### ダウングレード
乗り換え時にレシートを検証しても乗り換え前のレシートのみが有効という情報しかとれず、ダウングレードしたかどうかはわかりません。
バッチ処理等で乗り換え前のレシートの有効期限時にレシートを再取得すると、乗り換え前のアイテムは更新されず、乗り換えしたアイテムのレシートが新たに追加されています。

## まとめ

クロスグレード同様にユーザがスムーズに乗り換えることができますね。またユーザへの課金時の表記もStoreKitが「アップグレードしますよ」「ダウングレードしますよ」と出してくれるためアプリ側では特に実装を変更する必要もないようです。
サーバサイドのレシート検証と検証タイミングが重要かなと思います。
【今さら】AndroidStudioのショートカット

AndroidStudioのショートカット。

仕事の環境と、家の環境でAndroidStudioの動きが違くてやりにくい！！！！
仕事だと⌘◯で△△ができるのに。。。

となってしまったので、今更ですが、自分用にリストを作っておきます。
英語がよくわからないので、機能がスッと頭に入ってこないんですよね。

|キー名称|記号
|:--|:--
option |⌥|
control|⌃|
command|⌘
shift|⇧

Keymapの名称一覧

|名称|操作|元のキー設定
|:--|:--|:--
|Declaration|定義にジャンプする|F3
|Find in Path|パッケージ内検索|⌃H
|Find Usage|指定したクラスや変数を使用している箇所を検索|⌘⇧G
|Override Methods...|継承、実装クラスのOverrideメソッドの一覧を表示|⌥⌘O
|Structure|クラス内メソッドや変数の一覧を表示|⌘O
|Rename|クラスや変数の名前を変更|⇧F6
|Delete Line|コードの行を1行削除|⌘D
|Move Statement Up|対象コードの行を上に移動|⌥↑
|Move Statement Down|対象コードの行を下に移動|⌥↓
|Duplicate Entire Lines|対象コードを行を下にコピー|⌘⌥↓

AndroidStudio動かしながら「あ、これ」ってのあったら追記していきます。
今思いつくのはこれくらいです。
Debianのインストーラにおける「ソフトウェア」の選択項目で何がインストールされるか調べる方法

基本的には公式のWiKiである[tasksel - Debian Wiki](https://wiki.debian.org/tasksel)に記載されている。ググラビリティが低いのでメモを残す。

## タスク一覧

```bash
$ tasksel --list-tasks
u desktop	Debian desktop environment
u gnome-desktop	GNOME
u xfce-desktop	Xfce
u kde-desktop	KDE
u cinnamon-desktop	Cinnamon
u mate-desktop	MATE
u lxde-desktop	LXDE
u web-server	web server
u print-server	print server
u ssh-server	SSH server
u laptop	laptop
```

「ソフトウェアの選択」に出てくる項目は「タスク」と呼ぶらしい。

## タスクに紐付いているパッケージの確認

上記で表示されたタスク名に `task-` を付けた名前がメタパッケージになっているので `apt-cache show` などで見ることができる。

```bash
$ apt-cache show task-desktop
Package: task-desktop
Source: tasksel
Version: 3.31+deb8u1
Installed-Size: 21
Maintainer: Debian Install System Team <debian-boot@lists.debian.org>
Architecture: all
Depends: tasksel (= 3.31+deb8u1), xorg, xserver-xorg-video-all, xserver-xorg-input-all, desktop-base
Recommends: task-gnome-desktop | task-xfce-desktop | task-kde-desktop | task-lxde-desktop | task-cinnamon-desktop | task-mate-desktop, xdg-utils, avahi-daemon, libnss-mdns, anacron, eject, iw, alsa-utils, alsa-base
Description-en: Debian desktop environment
 This task package is used to install the Debian desktop.
Description-md5: 17cb4a1ed6025b48045cc576bf52317c
Section: tasks
Priority: optional
Filename: pool/main/t/tasksel/task-desktop_3.31+deb8u1_all.deb
Size: 954
MD5sum: 83e61e8758c18a39f8e69fd98d749113
SHA1: c2fc5ac8452249c693c153c511adf5331ca3ae55
SHA256: c48967767c5da4c386081daabdf0c4f5e2cb2cafa1197f0c5ed1798b29751f4f
```

## 標準システムユーティリティ

これについては特別に下記のコマンドで確認できる。なぜメタパッケージになってないのだろう。標準というわりには基本的に要らん気がするのは気のせいか…。

```bash
$ tasksel --task-packages standard
rpcbind
aptitude
bash-completion
doc-debian
info
install-info
exim4-base
libclass-isa-perl
nfs-common
host
exim4-daemon-light
at
aptitude-common
exim4
dnsutils
time
dc
exim4-config
python-reportbug
patch
bind9-host
mlocate
wamerican
bc
reportbug
libswitch-perl
texinfo
procmail
python-apt
debian-faq
mutt
ftp
apt-listchanges
```
【MySQL】DBのダンプとリストア時にはまった

##はじめに
MySQLのDBの複製を作りたくて、ダンプとリストアを実施した際に
はまったことのメモです。

ダンプとリストアは以下のサイトを参考に実施しました。
http://blog.flatlabs.net/20100420_061602/

###DBのダンプ
まずはDBのダンプを取得します。
以下のコマンドを実行すると`/root`直下にdbdump.sqlが作成されます。

``` console:console
# mysqldump -A -u user -p > dbdump.sql
```
###DBのリストア
次にDBのリストアをするのですが、今回は複製がしたいので
別途データベースを作成し、そこにリストアします。

``` console:console
# mysql -u user -p
Enter password:
...
mysql> CREATE DATABASE `database`;
ERROR 1044 (42000): Access denied for user 'user'@'localhost' to database 'database'
```

ここでERROR 1044...
よくよく調べてみたところ、`'user'@'localhost'`に
CREATE DATABSEの権限が付与されていなかったみたいです。

無理やり権限を付けました。

``` console:console
mysql>GRANT ALL PRIVILEGES ON *.* TO 'user'@'localhost' WITH GRANT OPTION;
mysql> show grants for user@localhost;
+---------------------------------------------------------------------+
| Grants for user@localhost                                           |
+---------------------------------------------------------------------+
| GRANT ALL PRIVILEGES ON *.* TO 'user'@'localhost' WITH GRANT OPTION |
+---------------------------------------------------------------------+
1 row in set (0.00 sec)
```

権限が付与されたので、もう一度データベースを作成してみます。

``` console:console
mysql> CREATE DATABASE `database`;
Query OK, 1 row affected (0.00 sec)
mysql> SHOW DATABASES;
+--------------------------------+
| Database                       |
+--------------------------------+
| database                       |
+--------------------------------+
1 rows in set (0.00 sec)

```
できた！！！

リストアします。

``` console:console
# mysql -u user -p  database < dbdump.sql
Enter password:
#
```

できた！！！
と思ってdbの中を見てみたらデータベースはできていたがテーブルが１つもできていなかった。

dbdump.sqlを見たところ、複製先のデータベースが違っていた。
`old_database`を`databese`に変えてもう一回リストアしてみたらできました。


``` sql:dbdump.sql
CREATE DATABASE /*!32312 IF NOT EXISTS*/ `old_database` /*!40100 DEFAULT CHARACTER SET latin1 */;

USE `old_database`;
...
```
JQueryでidをつける

#idをJQueryで追加する

以前、与えられたhtmlファイルに手でidを100個くらい追加していたが、デザイン変わったらやり直すのかーと思うと悲しくなったので、
idは別途追加したいと思った。

index.htmlのbodyの中身は以下

```html:index.html
<dl id="body">
  <button>hoge</button>
  <button>fuga</button>
  <button>hoga</button>
</dl>
```
このファイルに以下のjsファイルを読ませる

```js:menu.js
$(function () {
    $('button').attr('id', 'hoge');
});
```
するとindex.htmlにidが追加される。

```html:index.html
<dl id="body">
  <button id="hoge">hoge</button>
  <button id="hoge">fuga</button>
  <button id="hoge">hoga</button>
</dl>
```
idが振られた。

```js
    $('button').attr('id', 'hoge');
```
と書くと、buttonという要素に新たな要素'id'を要素値'hoge'で追加してくれる。

でも俺がやりたいのは、バラバラのidを付けることなので、menu.jsを変更

```js:menu.js
$(function () {
    $('button').eq(0).attr('id', 'hoge');
    $('button').eq(1).attr('id', 'fuga');
    $('button').eq(2).attr('id', 'hoga');
});
```

.eq()とすると、何番目かも指定できる。
するとidも変わる。

```html:index.html
<dl id="body">
  <button id="hoge">hoge</button>
  <button id="fuga">fuga</button>
  <button id="hoga">hoga</button>
</dl>
```

バラバラのidが付けられた。
今回はこれで良いが、以前の100個id手打ちはこのやり方では解決しないんじゃないかなぁ...


おわり
Swiftで安全性の高いGet Wild

[Hello World](http://qiita.com/rotors123/items/fe9a759ef779bc4b474b)したらGet Wildしたくなるのが技術者の性である。
そこで今回は、Swiftを用いたフルバージョンのGet Wild例を紹介したい。

なお、著作権的にsafetyな作りを実現する為、ソース上では[別のパブリックドメインソース](https://ja.wikipedia.org/wiki/%E3%81%A9%E3%82%93%E3%81%90%E3%82%8A%E3%81%93%E3%82%8D%E3%81%93%E3%82%8D)の大部分を仮として利用させてもらった。
実装時は個人の判断で、適宜読み替えて欲しい。

```swift:SafetyGetWild.playground
// SafetyGetWild.playground by rotors123

import UIKit

let array = [
    ["どんぐり ころころ どんぶりこ",
     "おいけにはまって さあたいへん",
     "どじょうがでてきて こんにちは",
     "ぼっちゃん いっしょに",
     ],
    ["どんぐり ころころ よろこんで",
     "しばらくいっしょに あそんだが",
     "やっぱりおやまが こいしいと",
     "ないては どじょうと",
     ]
]

let lastArray = [
    "BE TOGETHER",
    "COME BACK TO ASIA",
    "Come on Let's Dance",
    "Get wild and tough",
]

for (index, element) in lastArray.enumerated() {
    for word in array[index % 2] { print(word) }
    print(element + "\n")
}

```

```txt:出力結果
どんぐり ころころ どんぶりこ
おいけにはまって さあたいへん
どじょうがでてきて こんにちは
ぼっちゃん いっしょに
BE TOGETHER

どんぐり ころころ よろこんで
しばらくいっしょに あそんだが
やっぱりおやまが こいしいと
ないては どじょうと
COME BACK TO ASIA

どんぐり ころころ どんぶりこ
おいけにはまって さあたいへん
どじょうがでてきて こんにちは
ぼっちゃん いっしょに
Come on Let's Dance

どんぐり ころころ よろこんで
しばらくいっしょに あそんだが
やっぱりおやまが こいしいと
ないては どじょうと
Get wild and tough
```

### バージョン情報

Swift：3.1
Xcode：8.３.3 (Swift Playgrounds)

### ソースコード

https://github.com/rotors123/SafetyGetWild
WordPressの定数 俺のコピペ

よく使うやつ
```php
define( 'WP_SITEURL', 'http://localhost' );
define( 'WP_HOME', 'http://localhost' );
```

S3系のプラグインのやつ
```php
define( 'AS3CF_BUCKET', 's3のURL');
define( 'WPOS3_SETTINGS', serialize( array(
        'bucket' => 'バケット',
        'domain' => 'cloudfront',
        'cloudfront' => 'ドメイン(プロトコルはつけない)',
)));
```
XamarinでHello World

#はじめに
Xamarinを触る機会をもらったので、忘れないように備忘録を残すよ！
とりあえず、XamarinでiOSとAndroidのアプリケーションを作ってみるお！
まずは、Hello Worldだ！

#開発環境
iMac macOS 10.12.5
Visual Studio for Mac Community 7.0.1

#Hello Worldまでの手順
###1．新しいプロジェクトを作成
「ファイル」 -> 「新しいソリューション」
<img width="1930" alt="スクリーンショット 2017-06-19 22.14.50.png" src="https://qiita-image-store.s3.amazonaws.com/0/108396/57522c32-d809-a8ff-8e23-a6ea25f04a5d.png">

「Multiplatform」 -> 「アプリ」 -> 「Form App」 -> 「次へ」
<img width="1930" alt="スクリーンショット 2017-06-19 22.15.00.png" src="https://qiita-image-store.s3.amazonaws.com/0/108396/746b152d-13c5-0bb0-a585-7ce1c8825dd2.png">

「プロジェクト名」を入力 -> 「次へ」
「ソリューション名」は自動で入力される
<img width="1931" alt="スクリーンショット 2017-06-19 22.15.34.png" src="https://qiita-image-store.s3.amazonaws.com/0/108396/ce9c6168-a569-ee02-87fa-373417db3717.png">

新しいプロジェクトが作成される
パッケージの追加される
<img width="2560" alt="スクリーンショット 2017-06-19 22.16.09.png" src="https://qiita-image-store.s3.amazonaws.com/0/108396/43144fce-8aa2-f8dc-09cb-275d1e6e931c.png">

###2．シミュレーターで実行
####iOSの場合
「test.iOS」 -> 「Debug」 -> 「iPhone7 iOS 10.3.1」を選択
「▶︎」をクリックしてRun
<img width="2560" alt="スクリーンショット 2017-06-20 13.53.33.png" src="https://qiita-image-store.s3.amazonaws.com/0/108396/7337b574-aee6-2e2d-e76f-5b2a2e27bf6b.png">

シミュレーターだとこんな感じ(iOS)
<img width="375" alt="スクリーンショット 2017-06-20 3.13.49.png" src="https://qiita-image-store.s3.amazonaws.com/0/108396/ccd71689-180f-fe57-a5a5-77d699f03ba1.png">

####Androidの場合
「test.Droid」 -> 「Debug」 -> 「Android_Accelerated_x86」を選択
「▶︎」をクリックしてRun
<img width="2560" alt="スクリーンショット 2017-06-20 14.05.38.png" src="https://qiita-image-store.s3.amazonaws.com/0/108396/1b78f84e-a015-ba75-5f84-cb7071b6f6b0.png">

シミュレーターだとこんな感じ(Android)
<img width="587" alt="スクリーンショット 2017-06-20 14.09.17.png" src="https://qiita-image-store.s3.amazonaws.com/0/108396/0f3f43f7-dcbf-9323-753d-db30b1734aba.png">

#最後に
今回はコードを一切触らなかったけど、1つのプロジェクトでiOS、Androidのアプリを作れるXamarinさんに感動しました。
しかも、iOSとAndroidでレイアウトのデザインも変えられる！
iOSとAndroidでは、画面のレイアウトが違うので、これはありがたい！
今後もXamarinを触って行くので、Qiitaさんにいくつか投稿していこう。
【質問】pythonのplot_surfaceの使い方について

python3を使っております。ググったところ、matplotlibで球を書くには下のようなコードを書けばよいと出てきました。しかし、ここではplot_surfaceの引数として、x、y、zそれぞれに行列を用いています。これは、内部でどのような計算を行い、グラフをプロットしているのでしょうか？どなたか分かる方ご教授お願いします。
よろしくお願いします。

```
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np


fig = plt.figure()
ax = fig.gca(projection='3d')

# Make data
u = np.linspace(0, 2 * np.pi, 100)
v = np.linspace(0, np.pi, 100)
x = 10 * np.outer(np.cos(u), np.sin(v))
y = 10 * np.outer(np.sin(u), np.sin(v))
z = 10 * np.outer(np.ones(np.size(u)), np.cos(v))

# Plot the surface
ax.plot_surface(x, y, z, color='b')

plt.show()

```
jQueryで画面にボタンを付ける

#動的に画面を変化させるために、ほぼ空のindex.htmlにjsで画面構成を作る

jQueryの説明はいろんなところで見かけるので、それ以降の画面作りをつらつら書いていく。
基本は当たり前のことを書く感じで。


htmlのbodyは以下

```html:index.html
<!DOCTYPE html>
<html>

<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <title>jQuery画面</title>
  <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
  <script type="text/javascript" src="js/menu.js"></script>
</head>

<body>
  <dl id="body">
  </dl>
</body>

</html>
```

このhtmlファイルにjQueryでボタンを追加してみる

```js:menu.js
$(function () {
    $('#body').append('<button>hoge</button>');
    $('#body').append('<button>fuga</button>');
    $('#body').append('<button>hoga</button>');
});
```


index.htmlを開いてみる

![キャプチャ.PNG](https://qiita-image-store.s3.amazonaws.com/0/188058/58d5be18-4f9a-a5f1-e085-4517fa71ef25.png)

出来ました。

```js
    $('#body').append('<button>hoge</button>');
```
と書くと、id=bodyに、<button>hoge</button>と書き込んでくれる。
Chromeでindexの中身を見ると

```html
<html>
<head>...</head>

<body>
  <dl id="body">
    <button>hoge</button>
    <button>fuga</button>
    <button>hoga</button>
  </dl>

</body>
</html>
```

ちゃんと記述されていました。（当たり前だけど）

おわり
IE11で互換モードでもlocalStorageは利用可能

残念ながらIEの互換モードでの開発をいまだに強いられることがある。
そんな中でLocal Storageは互換モードに引っかかるかどうかを実験してみた。

結論としては利用できそう。
テストしたUAはIE11。

テストコードは下記のとおり。
metaでのX-UA指定をはずしてみたり、パターンはいくつか試したがいずれも大丈夫だった模様。

```html
<!DOCTYPE HTML>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=7" />
<script type="text/javascript">
<!--

function testLocalStorage(){
    //LocalStorageに登録がなかったときのために
    localStorage.setItem("LS_TEST", "" );
    for(var i in window.localStorage) {
        alert(i);
    }
}
//-->
</script>
</head>
<body>
<input type="button" value="LocalStorageのテスト" onclick="javascript:testLocalStorage()" />
</body>
</html>
```
Android SDK Visualizer でFFTしてみたけど、とれたデータの意味を理解してみた。

# Android SDK Visualizer

https://developer.android.com/reference/android/media/audiofx/Visualizer.html

具体的にどんな値がとれるのか？

`getFFT()`

> The capture is an 8-bit magnitude FFT, the frequency range covered being 0 (DC) to half of the sampling rate returned by getSamplingRate(). The capture returns the real and imaginary parts of a number of frequency points equal to half of the capture size plus one.


- **サンプリングレート**　*一秒間あたりの分割数*

` getSamplingRate()`


|Returns | |
|----|----|
|int | the sampling rate in milliHertz.|


デバッグした実際の値：`44100000`　（ｍｍHz)

`44,1　kHz`　（オーディオの一般的なサンプリングレート）



- **ビット深度**  サンプリング1つに対して **2^(ビット数)** の情報量


`8bit `　マニュアル記載より

- **キャプチャーサイズ**

` getCaptureSize()`


|Returns | |
|----|----|
|int | the capture size in bytes.|

デバッグした実際の値：`1024`　


- 最初の1バイト目（DC)は実部(real)、2バイト目は(sampling周波数/2)の周波数の実部(real)のみ
- それ以降は実数＋虚数で2つでセットのデータ　キャプチャーサイズn の時、全部で　( n -1 )/2 個のセットがある

>  1 (DC　実数) + 1 (n/2 実数)　+ 2(実数+虚数) * (n -1 ) /2 　= n バイト

44100(Hz) /( 2 * 1024 ) =(約） 21.5 Hz　刻み

バイトを整数に変換してデバッグすると、0ー255までの値になっている。

> i=0 .. 1024 {  (mBytes[i] & 0xff) }


|0|1|2|3|4|5|6|7|8|9|10|
|----|----|----|----|----|----|----|----|----|----|----|----|
| 0 | 249 | 3 | 241 | 12 | 37 | 198 | 3 | 246 | 248 |9|
ESP8266と3軸加速度センサーADXL345で振動を測定する


ESP8266と[3軸加速度センサーADXL345](http://akizukidenshi.com/catalog/g/gM-06724/)を使って振動を測定し、[IoTデーター可視化サービスAmbient](https://ambidata.io)で可視化します。

![Ambientで振動測定](https://ambidata.io/wp/wp-content/uploads/2017/06/bb6ba0234cdbea7c832615134bdd7c37.jpg)

# 3軸加速度センサーADXL345

ADXL345は次のような仕様の3軸加速度センサーです。

* 設定により±2Gから±16Gまで測定可能
* 分解能は1ビット当たり3.9mG(設定による)
* SPIとI2Cでアクセス可能

この他にもタップ、ダブルタップの検出、動きの有無の検出など豊富な機能を持っています。

ADXL345の制御にはESP8266を使います。ESP8266とADXL345はSPIで接続しました。

|ESP8266|ADXL345|
|:-----:|:-----:|
|3V3|VDD|
|GND|GND|
|IO14|SCL|
|IO12|SDO|
|IO13|SDA|
|IO5|CS|

# プログラム

振動と言っても様々な振動がありますが、今回は建物の振動を測ることにします。振動の周波数は建物によりますが、50Hzぐらいまでを測定することにして、10m秒間隔で加速度センサーの値をサンプリングすることにしました。

センサーのx軸、y軸を水平方向、z軸を鉛直方向になるように設置すると、x軸、y軸はほぼ0G、z軸は重力の約1Gの加速度がかかった状態になります。そこで最初に10m秒間隔で100回、x軸、y軸、z軸の加速度を測定して平均値を求め、これを基準値にします。振動の測定値はセンサーから読んだ値と基準値の差分にします。ADXL345の分解能は1ビット3.9mGなので3.9倍すると加速度が得られます。

プログラムでハマったのはSPIのモード設定でした。[ADXL345のデーターシート](http://akizukidenshi.com/download/ds/freescale/ADXL345_jp.pdf)には、次のように書いてあります。
> SCLK はシリアル・ポート・クロックであり、非伝送時にCSがハイレベルの場合、SCLK はハイレベルにしてください。データは、SCLK の立上がりエッジでサンプリングしてください。

この説明はSPI Mode3です。ところが

```cpp
SPI.setDataMode(SPI_MODE3);
```

とすると正しそうな値が取得できません。「[ESP8266 ( ESP-WROOM-02 ) SPI 通信高速化、その２](https://www.mgo-tec.com/blog-entry-esp8266-wroom-spi-speed-up-02.html)」というブログに「ESP8266 のSPI ライブラリでは、SPI.setDataMode(SPI_MODE2);　は　Mode 3 です！！」と書いてあるのを見つけ、

```cpp
SPI.setDataMode(SPI_MODE2);
```

としたところ、正しい値を取得することができました。

プログラムはGithubに公開しました。

* [AmbientVibration](https://github.com/TakehikoShimojima/AmbientVibration)

プログラムをビルドするにはAmbientのArduinoライブラリーが必要です。インストール方法は「[Arduino ESP8266で温度・湿度を測定し、Ambientに送ってグラフ化する](https://ambidata.io/docs/esp8266/)」をご覧ください。

# データー測定

プログラムをビルドして動かしてみました。Wi-Fiに接続し、基準となるx、y、z軸の加速度を測定して表示した後、10秒間、振動を測定します。試しにセンサーを置いた机をx軸方向、y軸方向、z軸(鉛直)方向に、それぞれ3回ずつ軽く叩いて見た時の様子が最初に載せたグラフです。

x軸、y軸、z軸それぞれの方向に叩いた時に対応する方向の振動が検出されているのが分かります。y軸方向に叩いた時はy軸だけでなくx軸にも振動が検出されていますが、これは机がx軸方向に揺れやすかったのかも知れません。

z軸方向のグラフを拡大してみたのが下の図です。

![z軸拡大](https://ambidata.io/wp/wp-content/uploads/2017/06/96dde2f8520ac9714a8c2a3e2609d020.jpg)

10m秒のサンプリングで振動は測定できているように思います。

測定結果は以下のアドレスで公開しています。

https://ambidata.io/ch/channel.html?id=1475
RailsアプリのリンクでURLの長すぎる場合の対応方法を整理しておく

URLの長さに関しては特に決まった制限はないものの、IEは約2000文字でブチッと切られるという仕様のようで、検索条件が大量にあるformだと検索はできるものの、画面に検索フォームに戻るリンクを作って移動するとクエリパラメータが壊れて検索条件が復元できなくなったりします。

## 通常の画面遷移編

そこで、検索フォームのメソッドをPOSTに変更し、検索フォームに戻るリンクでも`data-method="post"`にするようにしてみましたが、これでも結局クエリパラメータが渡されるため、壊れました。

```erb
<% # IEでダメなやつ %>
<%= link_to "戻る", search_path(search_params), method: :post %>
```

こうなると、`search_params`をループしてhiddenパラメータを作ったformを作らないといけないのか…と考えていたら、実はそういうメソッドがすでにあることを知りました。`button_to`メソッドです。

```erb
<%= button_to "戻る", search_path, params: search_params %>
```

画面遷移をする場合は、`button_to`メソッドを使えば楽ですね！
これは確認画面からフォームに戻るときにも使えそう。

## ソートのリンクやpaginationのリンク

通常の画面遷移のところで指摘したように、`link_to`メソッドのオプションに、`method: :post`にしただけでは壊れてしまいます。（URLが長すぎる場合）

しかし、Ajaxにしてこのように書くと、うまくいくらしいです。

```erb
<% # ちゃんと全てのパラメータがPOSTされる %>
<%= link_to "リンク",
            search_path,
            data: { params: search_params },
            method: :post,
            remote: true
%>
```

`data-params`にJSON形式でデータを渡すと、ちゃんとhiddenパラメータに変換してAjaxでPOSTされます。

これがうまくいくんだったら、`remote: true`を削除して通常の画面遷移でもうまくいきそう！に見えるんですが、削除すると`data-params`を完全に無視した結果になるだけです。辛い。

```erb
<% # ダメなやつ %>
<%= link_to "リンク",
            search_path,
            data: { params: search_params },
            method: :post
%>
```


現状としては、ransackやkaminariで作られたリンクで、URLが超長い場合はAjaxで画面描画するようにテンプレートを修正するのがいいのかなぁと考えています。
react日本語入力のmaxLength問題

## inputのmaxLength問題
html5のinputタグでmaxLength属性を設定するだけで、全てのケースがOKではありません。
日本語を入力する場合、キーボードの確定ボタンを押さなければブラウザのmaxlengthチェックが走りません。しかし、確定ボタンを押す前にonChangeイベントがすでに発生しています。

その為、いっぱいに入力して確定ボタンを押さないまま、Submitをクリックすると、最大文字数を超えた文字列がサーバに送信されてしまいます。

## 対応案
次の２つの案が考えられます。

# 案1:onChangeイベントを制御する
inputのonChangeイベントハンドラーで最大文字数超えたら、modelデータを更新しないようにすれば、modelロジックを変更せずに最大文字数の制限を実現できます。

```html
<input
  type="text"
  value={formData.name}
  onChange={(e) => {
    if (e.target.value.length <= 30) {
      this.props.nameChange(e);
    }
  }}
  maxLength={30}
/>
```

- デメリット
  最後２文字しか入らない状態で「最後」を入力しようとすると、「さいご」の「さい」までが入力されたら、キーボードが消えてしまいます。つまり、漢字に変更できない場合がありますので、ユーザビリティが低下します。

# 案2:validate処理で文字数をしっかりチェックする
modelクラスで入力内容の最大文字数チェックをおこなって、サーバに送信する前にチェックします。

- modelクラス

```js
setName(value) {
    return this.set('name', value)
      .setIn(['validations', 'nameIsValidated'],
        value.length > 0 && value.length <= 30);
  }
```

- submit処理

```js
submitData(e) {
  const formData = this.props.myState.formData;
  if (formData.getIn(['validations', 'nameIsValidated'] === true) {
    // ここでサーバに送信
  } else {
    // バリデーションエラーを表示
  }
}
```
UiPathでRPAを実践してみる(2) ～Excelを使ってみよう！～

さて、`Hello World`が出来たところで次はExcelの操作について書いていきましょう。
Excelの入出力がプログラムっぽく出来るのもUiPathの良いところです。
例題としてExcel化されたQiitaの投稿の一覧を「いいね」の順に並び変えてCSVに出力する、という事をやりたいと思います。
具体的な手順を書いていきます。

##1.Excelを使う為のパッケージをUiPath Studioにインストールする
　デフォルトではUiPath StudioにExcelを操作するためのActivityがインストールされていません。
　パッケージの追加から始めましょう。

　①ActivityペインのManage Packagesを選択します。
　![キャプチャ.PNG](https://qiita-image-store.s3.amazonaws.com/0/154110/d3c3f4e7-5d3e-385f-f6fc-6fb6a1976e57.png)

　②Manage Packagesが表示されたらAvailableを選択し、`UiPath.Excel.Activities`をインストールしましょう。
　![キャプチャ2.PNG](https://qiita-image-store.s3.amazonaws.com/0/154110/4e9e081c-e937-85f1-01bd-559ed1da7367.png)

　③ActivitiesにExcelとCSVが追加されたのを確認したら完了です。
　![キャプチャ3.PNG](https://qiita-image-store.s3.amazonaws.com/0/154110/0c4a06c3-cb64-09bc-0cbc-e4ae2a84d46f.png)

##2.Excelファイルを開いてみる
　さて、こちらはQiitaのページの情報をExcel化したものです。実はこのデータもUiPathの`data scraping`という技術を使って作成したものです。(手順の詳細を記述した記事は[こちら](https://qiita.com/motuo/items/ae5f6b6b47530492b97e)。)
　カラムとしては、タイトル・URL・いいねの数を持っています。
　※取得元のページ
　![キャプチャ4.PNG](https://qiita-image-store.s3.amazonaws.com/0/154110/4966cfc5-07c1-e8d5-34b1-a52a4d6a7ff6.png)

　※ページから情報を取得した結果のExcel
　![キャプチャ5.PNG](https://qiita-image-store.s3.amazonaws.com/0/154110/56eb38be-1306-262e-74e5-ba824688cbfd.png)
　入力としてはこのデータを使っていきましょう。

　Excelファイルを開くには、`Excel application scope`というActivityを使います。
　Inputは開きたいExcelのPathになります。プロジェクトフォルダの相対パスも使えますし、絶対パスでもOKです。
　データを取り出すには`Read cell`または、`Read Range`というActivityを使います。今回は`Read Range`を使っていきましょう。
　各Activityをドラッグ&ドロップで登録していきます。`Read Range`は`Excel application scope`の中にドロップしてください。
　完成形は下記の様になります。
![キャプチャ6.PNG](https://qiita-image-store.s3.amazonaws.com/0/154110/981b0a57-7f70-0923-d5cb-7ff02d02bb06.png)

　これは、UiPathのプロジェクトフォルダにある、`test.xlsx`というファイルを開いて、"sheet1"にあるデータを全て取ってくる、という命令になります。
　`Read Range`のRangeが""となっています。この様に何も指定しない場合はシート全体をコピーする、という命令になります。
　逆に"A1:B100"と書けば、A1セルからB100セルまでをコピーする、という命令になります。
　Outputの型はdatatableです。VB.netを使われている方にはおなじみですよね？
　ここでは`excelData`という変数を定義して、その中にExcelから取得したデータを格納しています。

##3.データを並び替える
　これは、UiPathというよりもVB.netのノウハウになります。AssignというActivityを使ってデータを並べ替えていきましょう。
　この`Assign`はプログラムでいうと、=の役目を果たします。
　①上記で作成した`excelData`を`DataView`に変換します。まず、Assignを追加して下記の様にします。
　　①-1 **DV**という名前のDataView型の変数を定義する。
　　①-2 **DV**を左辺にして、右辺には`new DataView(excelData)`とします。これにより、上記のexcelDataがDataView型になります。
　![キャプチャ7.PNG](https://qiita-image-store.s3.amazonaws.com/0/154110/13f22e8d-c36b-7d93-cd06-c8091d6366a9.png)

　②上記で作成した**DV**を`.sort`で並び替える。
　![キャプチャ8.PNG](https://qiita-image-store.s3.amazonaws.com/0/154110/0ad174c9-8b91-ca27-0c29-12d676fc575a.png)

##4.CSVにファイル出力する
  これには`write CSV`というActivityを使用します。これも、出力先のファイルはプロジェクトフォルダから見た相対パスでも絶対パスでも指定可能です。
　下記の場合は、プロジェクトフォルダ直下に**sortAfter.csv**というCSVファイルを作ってこれを書き出す処理になります。
　ちなみに、ファイルが存在している場合は上書き、存在していない場合は新規でファイルを作成してくれます。
　3のステップで作成した`DV`を`.ToTable`でdatatable化すればそのままデータを吐き出してくれます。(便利)
　![キャプチャ9.PNG](https://qiita-image-store.s3.amazonaws.com/0/154110/c160cb17-6129-11f2-0acb-fe6ac625116d.png)

　完成形がこちらです。
　![キャプチャ10.PNG](https://qiita-image-store.s3.amazonaws.com/0/154110/99d4b4fe-2cb1-a4ac-1c54-5a72d17cfcfd.png)

上手く、「いいね」の数順にデータを吐き出すことができました。

ExcelとWebの連携は使い勝手が良さそうなので、色々と応用できそうですね。

次はWebの操作について書こうかと思います…
Vyatta/VyOSの設定情報をそのまま、もしくはパスワード情報を隠蔽してコマンド形式で抽出する方法

#1. 現在実行中のVyatta/VyOSの設定をコマンド形式で抽出する方法

```
$ show configuration commands
もしくは
$ /opt/vyatta/sbin/vyatta-config-gen-sets.pl
```

#2. /config/config.bootに保管されている設定をコマンド形式で抽出する方法

```
$ /opt/vyatta/sbin/vyatta-config-gen-sets.pl /config/config.boot
```

#3. 現在の設定情報の中でパスワード情報や鍵情報を隠蔽する方法

誰かに渡す場合には、このどちらかでやりたい。

```txt:センシティブ情報を隠した設定ファイル
$ show configuration all 
```

```txt:センシティブ情報を隠した上でコマンド形式で抽出
$ show configuration all > /tmp/hoge.txt; /opt/vyatta/sbin/vyatta-config-gen-sets.pl /tmp/hoge.txt
```

#4. 構成ファイルのバックアップ
$ cp -pr /config/config.boot /config/config.boot_20170601
Rails migrationでintegerを使う時の注意点〜integerのlimitはバイト数だった〜

# limitの定義に注意:eyes:
マイグレーションファイルでintegerのカラムにlimitを定義する際に注意しないといけないことがある。

# integerのlimitとstringのlimitでは意味合いが違う:dancer:
例えば以下のように記述する。

```rb
t.integer :num, limit: 11, null: false, comment: "integerカラム"
t.string :str, limit: 100, null: false, comment: "stringカラム"
```

一見何も問題ないように見えるが以下のようなエラーがでる。

```sh
StandardError: An error has occurred, all later migrations canceled:
No integer type has byte size 11
/prj/db/migrate/20170620050536_tests.rb:3:in `change'
ActiveRecord::ActiveRecordError: No integer type has byte size 11
```

# integerのlimitはバイト数だった:rolling_eyes:
integerのlimitは桁数ではない。バイト数だった！
stringのlimitは桁数なのにね！

な！の！で！

```
num | int(11)    
```

というカラムを作りたい場合のlimitは4です

```rb
t.integer :num, limit: 4, null: false, comment: "integerカラム"
```

limitに4以外を指定した場合に生成されるカラムは以下を参照してください。
[Rails | マイグレーションで integer カラムを作る時の :limit は、桁数指定ではない ( バイト数指定だ )](http://qiita.com/Yinaura/items/cede8324d08993d2065c)
Modalを使った時にionViewDidLoadが動かない問題

Modalで呼び出した時、ionViewDidLoadが動かないので、調べるとionViewDidEnterを使えと。

お恥ずかしいけど、メモ。

https://github.com/ionic-team/ionic/issues/8414

よく見るとオフィシャルのドキュメントにもこう書いてありますね。

```
Runs when the page has loaded. This event only happens once per page being created.
If a page leaves but is cached, then this event will not fire again on a subsequent viewing.
The ionViewDidLoad event is good place to put your setup code for the page.
```

https://ionicframework.com/docs/api/navigation/NavController/
ルートドメインを Azure WebApp で構成している場合に雑にサブスクリプション移動するにはメンテ時間が必要

いくつかの要因が絡まって表題の結論に達しました。
こうやれば解決できるというアイデアがあればぜひ聞かせていただきたいです。

## 前提
- ルートドメインは A レコードに割り当てます(AWS のようなAレコードのLBはありません)
- WebApp ではカスタムドメインを使う場合、`TXT` レコードに元のドメインを割り当てて所有者確認します  
参考:[既存のカスタム DNS 名を Azure Web Apps にマップする](https://docs.microsoft.com/ja-jp/azure/app-service-web/app-service-web-tutorial-custom-domain#a-namemap-an-a-recordaa-レコードのマップ)
- サブスクリプション移動する場合、SSL 証明書は移動されません
- サブスクリプション移動はリソース数にもよるが、それなりに時間がかかる

## 実践したこと
サブスクリプション移動で SSL 証明書を割り当て直す必要があるため、一番手軽な移行方法は以下の手順です。

1. SSL バインディングを削除
1. SSL 証明書を削除
1. **サブスクリプション移動**
1. SSL 証明書をインポート
1. SSL バインディング

この場合、およそ10分くらいはアクセスできない状態が生まれてしまいます。
特に**サブスクリプション移動**はそれほど行う作業ではないため時間が読めず、不安です。
そこで別の方法で移行することを考えました。

1. Production と同じ内容の WebApp をダミーとして用意
1. (ダミー) SSL 証明書をインポート
1. (ダミー) カスタムドメインに設定
1. (ダミー) SSL バインディング
1. DNS でダミーにトラフィックを流す
1. (Production) SSL バインディングを削除
1. (Production) SSL 証明書を削除
1. サブスクリプション移動
1. (Production) SSL 証明書をインポート
1. (Production) カスタムドメインに設定
1. (Production) SSL バインディング
1. DNS で Production にトラフィックを流す

A レコードを使う場合は `TXT` レコードで所有者確認すれば、カスタムドメインを割り当てられるので、事前にやっておけば DNS 切り替えるだけで移行は完了するだろう、という魂胆です。
しかし、この手順はダメでした。

## 問題点
**WebApp のカスタムドメインの設定は `TXT` レコードの内容が自身のものでなくなった時点で消えます。**
あくまでも所有者確認なのでカスタムドメインに設定するとき一時的に `TXT` レコードがあればいいのだと予測していたのですが、そうではなかったのです。
上の手順の 「**(ダミー) カスタムドメインに設定**」 の時点でサイトが404を返すようになったというオチです。

## おわりに
ということで、(WebApp で対応する限りでは)どうあがいてもサイトに繋がらない時間が生まれてしまうという結論に至りました。
本当に落としてはいけないサービスの場合はダミーを IaaS で用意するのが筋なんでしょうか。

多少のダウンタイムは許容されるサービスだったため、以下の手順でサブスクリプション移動をしました。

1. Production と同じ内容の WebApp をダミーとして用意
1. (ダミー) SSL 証明書をインポート
1. (ダミー) カスタムドメインに設定(ここからサイト落ちる)
1. (ダミー) SSL バインディング
1. DNS でダミーにトラフィックを流す(ここでサイト復帰)
1. (Production) SSL バインディングを削除
1. (Production) SSL 証明書を削除
1. サブスクリプション移動
1. (Production) SSL 証明書をインポート(ここからサイト落ちる)
1. (Production) カスタムドメインに設定
1. (Production) SSL バインディング
1. DNS で Production にトラフィックを流す(ここでサイト復帰)

一番時間がかかりそうな**サブスクリプション移動**を回避できればまあよしというくらいの手順でした。

そもそもサブスクリプション移動しなくて済むように最初から適切な場所にデプロイしましょう。
Sequelなどの外部ツールからRDSへ接続する

# 概要
Sequelなどの外部ツールからRDSへ接続して中身を見れるようにしたい。

# 前提
RDS構築済み

# RDSのパブリックアクセスを許可する
## 設定を確認
RDS -> インスタンス -> インスタンスの操作 -> 詳細を表示
パブリックアクセス可能 はい
になって入ればok。

※いいえ になっている場合は変更する。オンラインで変更可能。
RDS -> インスタンス -> インスタンスの操作 -> 変更
すぐに変更 のチェックボックスにチェックを忘れずに。

## パブリックアクセスになったことを確認。
```cl:
 nslookup
> mydb1.xxxxxxx.ap-northeast-1.rds.amazonaws.com
 
Non-authoritative answer:
Name: mydb1.xxxxxxx.ap-northeast-1.rds.amazonaws.com
Address: 10.0.3.23
```

↓パブリックなホスト名とグローバルIPアドレスが返ってくるようになった。

```cl:
 nslookup
> mydb1.xxxxxxx.ap-northeast-1.rds.amazonaws.com

Non-authoritative answer:
xxx-dev.xxxxxxx.ap-northeast-1.rds.amazonaws.com canonical name = ec2-xxx-xxx-xxx-xxx.ap-northeast-1.compute.amazonaws.com.
Name: ec2-xxx-xxx-xxx-xxx.ap-northeast-1.compute.amazonaws.com
Address: xxx.xxx.xxx.xxx
```

# セキュリティグループの設定
このままだと誰でもアクセスできてしまうので、セキュリティグループの設定をします。

| タイプ | プロトコル | ポート範囲 | ソース |
|:-:|:-:|:-:|:-:|
| MYSQL/Aurora | TCP | 3306 | マイIP(任意) |

 
# Sequelから接続してみる

![スクリーンショット 2017-06-20 14.21.57.png](https://qiita-image-store.s3.amazonaws.com/0/71267/8439b244-2cde-52a2-9d7a-a2684199c53d.png)
ホスト名はRDS -> インスタンス -> インスタンスの操作 -> 詳細を表示 -> エンドポイント を設定

# ReadOnlyなユーザーを追加する(必要あれば)

```sql:
GRANT SELECT ON `%`.* TO read_only@`%` identified by 'read_only_pass';
```
react-modalのスクロール問題の解決

react-modalで作られた画面の後ろの画面がスクロールされてしまう問題の解決方法をメモします。

modalが表示されたbody部に追加されるクラス「ReactModal__Body--open」のCSS設定を記載することで、後ろ画面のスクロールを禁止します。

```css
.ReactModal__Body--open {
  position: fixed;
}
```

## 参考記事
[Don't scroll parent component when Modal is opened](https://github.com/reactjs/react-modal/issues/191)
CarrierWave+fog+fog-aws+s3(その他諸々のawsサービス)でiamのcredentialsを使う

# はじめに
carrierwaveでfogを使ってAWSにアクセスすると、大体↓の例に当たります。

```ruby:/config/initializers/carrierwave.rb
  config.fog_credentials = {
    provider: 'AWS',
    aws_access_key_id: 'アクセスキー',
    aws_secret_access_key: 'シークレットキー',
    region: 'ap-northeast-1'
  }
```
で、iamは？と思ったので調べた結果を記事にします。

# 結論
use_iam_profileオプションを使います。
aws_access_key_idとaws_secret_access_keyは内部で埋めてくれるので、設定してはいけません。

```ruby:/config/initializers/carrierwave.rb
    aws_credentials = {
      provider: 'AWS',
      region: 'ap-northeast-1'
      use_iam_profile: true,
    }
```

# 内部処理

やっつけですけど、options[:use_iam_profile]を見て
/latest/meta-data/iam/security-credentials/
を↓のロジックで叩いてrole取ってきています。
ということで、処理もそこそこ信頼出来る模様です。

```ruby
Excon.new(INSTANCE_METADATA_HOST)
```


```ruby:/lib/fog/aws/credential_fetcher.rb
              if ENV['AWS_CONTAINER_CREDENTIALS_RELATIVE_URI']
                connection = options[:connection] || Excon.new(CONTAINER_CREDENTIALS_HOST)
                credential_path = options[:credential_path] || ENV['AWS_CONTAINER_CREDENTIALS_RELATIVE_URI']
                role_data = connection.get(path: credential_path, idempotent: true, expects: 200).body

                connection = options[:metadata_connection] || Excon.new(INSTANCE_METADATA_HOST)
                az_data = connection.get(path: INSTANCE_METADATA_AZ, idempotent: true, expects: 200).body
              else
                connection = options[:connection] || Excon.new(INSTANCE_METADATA_HOST)
                role_name = connection.get(path: INSTANCE_METADATA_PATH, idempotent: true, expects: 200).body
                role_data = connection.get(path: INSTANCE_METADATA_PATH + role_name, idempotent: true, expects: 200).body
                az_data = connection.get(path: INSTANCE_METADATA_AZ, idempotent: true, expects: 200).body
              end
```

# 実際作ったソース

実際業務で使う場合はiam roleが取れないローカルでも開発する必要が有ります。
この場合、モック作ってuse_iam_profieをfalseにしてみました。

```ruby
Fog.mock!
```

だけでよしなにやってくれることを期待したのですがだめでした。(´・ω・`)

```ruby:/config/initializers/carrierwave.rb
    # iam設定
    iam_profile = true
    # iam role name check
    # @see Fog::AWS::CredentialFetcher
    begin
      Excon.new(Fog::AWS::CredentialFetcher::INSTANCE_METADATA_HOST)
           .get(path: Fog::AWS::CredentialFetcher::INSTANCE_METADATA_PATH, idempotent: true, expects: 200)
           .body
    rescue
      Fog.mock!
      iam_profile = false
    end
    aws_credentials = {
      provider: 'AWS',
      region: 'ap-northeast-1',
      use_iam_profile: iam_profile,
      path_style: true
    }
    unless iam_profile
      aws_credentials[:aws_access_key_id] = ''
      aws_credentials[:aws_secret_access_key] = ''
    end
    config.fog_credentials = aws_credentials
```

use_iam_profieの実装例があまりに少ないのですが、世の中一般的にどうやっているんでしょうか？？？
何か勘違いしているのかなぁ？
ImportError: No module named appengine.api - Google App Engine + Golang(Go言語)

Google App Engine + Golang(Go言語)で動かそうとすると

> No module named appengine.api

というエラーが出て何も出来ないとき対処方法

# エラー
```
% dev_appserver.py dev.yaml
Traceback (most recent call last):
  File "/usr/local/bin/dev_appserver.py", line 103, in <module>
    _run_file(__file__, globals())
  File "/usr/local/bin/dev_appserver.py", line 97, in _run_file
    execfile(_PATHS.script_file(script_name), globals_)
  File "/usr/local/Cellar/app-engine-go-64/1.9.54/share/app-engine-go-64/google/appengine/tools/devappserver2/devappserver2.py", line 26, in <module>
    from google.appengine.api import request_info
ImportError: No module named appengine.api
```


# protobufをアンインストール
Python用のProtocol Bufferのモジュールが競合して起こっているらしい

```
% pip uninstall protobuf
```

このコマンドで削除してあげると何事もなかったかのように動き出す
Amazon Elasticsearch Serviceでcluster_block_exceptionがでたら


# 症状

こんなエラー。
読み込みは出来るが、書き込みやインデックス作成は全て失敗するようになる。

```json
"error": {
  "type": "cluster_block_exception",
  "reason": "blocked by: [FORBIDDEN/8/index write (api)];"
}
```

```json
"error": {
  "type": "index_create_block_exception",
  "reason": "blocked by: [FORBIDDEN/10/cluster create-index blocked (api)];"
}
```

# 原因と対策

原因は主に2つある模様。

## ディスク容量不足

AmazonESのメトリックスで`FreeStorageSpace`を見ると0になっているはず。
インスタンスタイプかEBSの容量を上げればいいはず。

[Amazon ES ドメインの設定 - AmazonES 開発者ガイド](http://docs.aws.amazon.com/ja_jp/elasticsearch-service/latest/developerguide/es-createupdatedomains.html#es-createdomains-configure-cluster)
[EBS ベースのストレージの設定 - AmazonES 開発者ガイド](http://docs.aws.amazon.com/ja_jp/elasticsearch-service/latest/developerguide/es-createupdatedomains.html#es-createdomain-configure-ebs)

## メモリ容量不足

AmazonESのメトリックスで`JVMMemoryPressure`が92%を超えているはず。
超えているというか92%をキープしている。

![スクリーンショット 2017-06-20 14.35.10.png](https://qiita-image-store.s3.amazonaws.com/0/379/c9c634de-d5ad-f34b-e42b-138be083bcb4.png "スクリーンショット 2017-06-20 14.35.10.png")

t2特有の現象というわけでなく他のインスタンスタイプでも同じことが起きたので、単純にスケールアップしてメモリ増やせということだと思う。
この状態でもClusterHealthは青いままなので要注意。
`JVMMemoryPressure`は監視対象にしたほうがよさそう。

# 参考

[AWS サービスエラー処理 - AmazonES 開発者ガイド](http://docs.aws.amazon.com/ja_jp/elasticsearch-service/latest/developerguide/aes-handling-errors.html#aes-handling-errors-yellow-index-error)
[elasticsearchを利用するときは容量を管理しようという話 - Qiita](http://qiita.com/dorachan1029/items/f3b47f4d9859450d9b90)
CSS だけで画像の切り抜きをうまくやる

# CSS3  object-fit

概要は下記のページを参考。

> 1行追加でOK！CSSだけで画像をトリミングできる「object-fit」プロパティー
http://www.webcreatorbox.com/tech/object-fit/

# 実装したいこと
枠内に画像をうまく納める。
切り抜き位置を中央にしておきつつ、アニメーションで見える範囲を移動させる。

## 前提
- 画像の縦横幅がバラバラ
- 縦横の比率もバラバラで、横長も縦長も混在
- スマホ前提でレイアウトは１つ

## レイヤー
- div 
    -  img

## CSS
div

```
width: 60%;
max-height: 110px;
overflow: hidden;
```

img

```
width: 60%;
max-height: 110px;
object-fit:cover;
```

## ポイント
object-fit を指定した img に、幅・高さも指定しないと object-fit:cover が効かない。
div のサイズは外枠レイアウト用の幅高さ指定、img は画像の切り抜きサイズ、という考え方かな。

## 確認
画像が切れていても、 img にサイズ指定がない場合は、 div の overflow で見切れているだけの場合がある。
その場合は object-position が効かないので切り抜き位置が変えられない。
object-position が効いて、切り抜き位置を変えられるようならOK。

ex.
img

```
width: 60%;
max-height: 110px;
object-fit:cover;
object-position: 0% 0% ;
```

# アニメーション
position を @keyframes に書いて、 img の animation で指定する。

# 前提
- スマホWeb
転ばぬ先のAWSセキュリティ

# サービスが大きくなればなるほど、セキュリティは重要になってくる

---

# じゃあ最初から強固なものにしよう

---

1. 強固なパスワード
2. グループメール
3. MFA(多要素認証)
4. ルートアカウントのアクセスキーは使わない
5. CloudTrail有効化
6. git-secrets導入
7. IAMユーザー、グループ、ロール

■ 参考
[AWSリソースについてセキュリティベストプラクティスに従った設定をしよう！](http://dev.classmethod.jp/cloud/aws/20170613-security-best-practices/)
[git-secretsでAWSの不正利用を防ぐ](https://saku.io/preventing-aws-credential-leaks/)

---

1. 強固なパスワード
2. グループメール
3. MFA(多要素認証)
4. ルートアカウントのアクセスキーは使わない
5. **CloudTrail有効化 ← これ**
6. **git-secrets導入 ← これ**
7. **IAMユーザー、グループ、ロール ← これ**

これの部分を今日は話します

--- 

# CloudTrail

AWSの操作履歴がすべて取得できるようになる戦犯発見サービス。
グラフとかにもできるっぽい。ログはS3に保存される。

■ 参考
[TrailDashでCloudTrailを可視化する](http://dev.classmethod.jp/cloud/aws/visualize-cloudtrail-using-traildash/)

---

# git-secrets

リポジトリにアクセスキーなどが混入しないようにするためのAWS謹製Gitプラグイン。
アクセスキーやシークレットキーはgit管理すんなよというAWSからのお達し。

---

# 使い方(インストール)

```sh
$ brew update
$ brew install git-secrets
```

---

# 使い方(設定)

1. gitconfigにアクセスキーの標準パターンを登録
  => これだけだと無効なまま。一応ファイル内のスキャンはできる
2. gitコミット時のhookに設定
3. 例外があれば設定

具体的な設定方法は[こちらの記事](https://saku.io/preventing-aws-credential-leaks/)が参考になります

---

# IAMユーザー、グループ、ロール

---

# Identity and Access Management

---

# それぞれの役割

- ユーザー
    - コンソールサインイン、APIまたはCLIのリクエストを行うのに使用
- グループ
    - ユーザーの集合。グループに属するユーザーに一括で権限付与できる
- ロール
    - 特定タスクに応じてユーザーやサービスに権限付与できるもの
    - 認証情報(アクセスキー等)は関連付けられない

---

# 問題

IAMロールのユースケースをひとつあげてください

---

- EC2インスタンスから他のAWSサービスにアクセスする必要がある時に権限を与えるためアタッチする

■ 参考
[Amazon EC2 インスタンスで実行されるアプリケーションに IAM ロールを使用してアクセス権限を付与する](http://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/id_roles_use_switch-role-ec2.html)

---

- ルートアカウントだと権限が強すぎるので、必ずIAMユーザーを作成して適切な権限を付与
- アクセスキーはできるだけ作成せず、IAMロールで利用することを推奨

しましょう

---

さらにIAMのベストプラクティスを知りたい場合はこちらへどうぞ

[IAM のベストプラクティス](http://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/best-practices.html)

---

# ありがとうございました。
IPsecでIDir 'XXX' does not match to 'YYY'のエラーが出た場合

# 概要
`sudo ipsec up VPN1` とかすると `connection 'VPN1' established successfully` って言われてるのに全然繋がってなくてハマりました。
ipsecは問題ないなーと思って意識から消してましたが、実際はipsecが確立できてませんでした。
結論から言うとrightidの設定などの問題でした。

# 環境
- Linux Mint 18.1
- strongSwan 5.3.5-1ubuntu3.3

# 参考
- http://network.station.ez-net.jp/client/remote/vpn/l2tp-linux-fw.asp

# 詳細
以下に書いた問題などを解消して無事に繋がったように見えましたが、activeな接続を見ると0になっていました。
http://qiita.com/knqyf263/items/c619036ad2fa6b0d7c8f

```shell-session
# ipsec up VPN1
...
connection 'VPN1' established successfully
# ipsec status
Security Associations (0 up, 0 connecting):
  none
```

upした際のメッセージにはsuccessfullyって出てるし問題なさそうなので、0 upになっていても繋がっているのかと思ってVPNの設定をしたのですがxl2tpdの設定をどう直してもうまくいきませんでした。
仕方ないのでsyslogを眺めていたら以下のエラーが出ていました。

```shell-session
$ grep -i IDir /var/log/syslog
Jun 20 13:07:02 XXX charon: 15[IKE] IDir '172.0.0.1' does not match to '10.0.0.1'
```

他にそれらしきエラーもないので、これが関係しているだろうと調べていくと、どうやらrightidの設定に関するエラーのようでした。
特にrightidなどを指定しない場合、デフォルトだと設定ファイルでrightに指定されている値をrightidとみなすらしいです。
right側のサーバで特に指定していない場合、実装にもよると思われるがIPアドレスがidに指定される？っぽい。
VPNサーバがグローバルIPアドレスを持っていて繋ぐ場合は問題ないが、NAT配下にあるなどしてIPアドレスが異なる場合はきちんと指定しないと動かないということらしいです。
IPアドレスは環境によって異なるので、ログを見つつ正しいidを指定すれば動くと思われます。
もちろんサーバ側できちんとidを指定してそのidを指定しても良いはず。

最終的には以下のような設定になりました。
設定の意味を全ては理解していないので無駄はありそうですが、とりあえずrightidを指定したら動くようになりました。
rightid=%anyなどはエラーが出てしまって、どう使うと良いのかはまだ分かっていないです。

```shell-session
$ sudo vim /etc/ipsec.conf
conn VPN1
      keyexchange=ikev1
      authby=secret
      ike=3des-sha1-modp1024!
      esp=3des-sha1-modp1024!
      leftfirewall=yes
      keyingtries=3
      dpddelay=30
      dpdtimeout=120
      dpdaction=clear
      rekey=yes
      auto=start
      left=%defaultroute
      leftprotoport=17/1701
      right=X.X.X.X
      rightprotoport=17/1701
      rightid=172.0.0.1
      type=transport
$ sudo ipsec restart
$ sudo ipsec status
Security Associations (1 up, 0 connecting):
      VPN1[1]: ESTABLISHED 2 seconds ago, 192.168.1.18[192.168.1.18]...10.0.0.1[172.0.0.1]
      VPN1{1}:  INSTALLED, TRANSPORT, reqid 1, ESP in UDP SPIs: cd29336f_i dd95abb5_o
      VPN1{1}:   192.168.1.18/32[udp/l2f] === 10.0.0.1/32[udp/l2f]

```

上記のように `ipsec status` をしたら無事に繋がっていることが確認できました。

# まとめ
Macで普段VPN張るときには意識していませんでしたが、久しぶりにLinuxからやろうとしたら大ハマリしました。
前もハマった気がするので次はスムーズにできるように書いておきました。
rightidの指定は大事。実は自動でやってくれる設定とかもあるのかもしれないので、もしあったら知りたいです。
tableview cell tag error viewWithTag　取得エラー対応


最近テーブルビューを作ろうとした時にエラーの対応をしたので共有します。
Cellの中でラベルを作成し、tagと関連付けした時のエラーです。

# 成功例

```ruby:tavleView.swift
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        
        let cell = table.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)

        if let label10 = cell.viewWithTag(10) as? UILabel {
            label10.text = "No.\(indexPath.row + 1)"
        } else {
            print("no tag item")
        }
        return cell
}
```
ifで解決したらエラーは起きませんでした。
UILabelを作り出す際にnillを恐れているのかもしれません。
JupyterからカジュアルにBigQueryをクエリする時のコスト上限を指定する

# Jupyter上でPandasを使ってBigQueryをクエリする時のコスト上限を指定する

## 課題

Jupyter上でインタラクティブにコードを書きながらBigQueryにクエリを投げたりしていると、typoが思わぬ高額課金を引き起します。例えば3日分のデータを取得したい時に `TABLE_DATE_RANGE` に渡す日付を

- (正) `TABLE_DATE_RANGE(xxx_, TIMESTAMP('2017-05-01'), TIMETAMP('2017-05-03'))`
- (誤) `TABLE_DATE_RANGE(xxx_, TIMESTAMP('2016-05-01'), TIMETAMP('2017-05-03'))`

とtypoすると1年と3日分のテーブルがスキャン対象になる。これに気づくのは、クエリジョブを投入後、なかなか結果が帰ってこないので不信に思ってクエリを見直した時だったりします。

## 対策

書いて即時に実行していけるインタラクティブ環境の魅力を損なわずにこれを防ぐには、実行時にチェックがかかれば良い。幸いPandasのv0.20からオプションで指定できるようになった。

次の様な `pd.read_gbq` のラッパーを用意して1クエリあたりのコスト上限を指定可能にすると良い。

```python3
COST_LIMIT_PER_QUERY = 1 # USD
GBYTE = 1000000000
maximum_bytes_billed = int(COST_LIMIT_PER_QUERY * 200 * GBYTE)

def read_gbq(query):
    return pd.read_gbq(
        query, project_id=PROJECT_ID, verbose=False,
        configuration={'query':{
            'maximumBytesBilled': maximum_bytes_billed,
            'maximumBillingTier': 1 # 2になるのを見た事が無いので1固定
        }})
```

`maximumBytesBilled` の上限に引っかかると、クエリの実行に必要な値がエラーメッセージに入ってくる。

例
> GenericGBQException: Reason: bytesBilledLimitExceeded, Message: Query exceeded limit for bytes billed: 2000000. 20971520 or higher required.