OmniAICreator/Qiita-1.07M huggingface dataset:
iTunesで再生中の曲の情報をツイートするアプリを作った

初めての試みだったのでざっくりと調べてみると、
AppleScriptで書いてみるのが良さそうだったので、AppleScriptに挑戦することにしました。
#ツイートするテキストの作成
iTunesから再生中の曲の情報(曲名とアーティスト名)をとってきて、それらを連結します。

```applescript
tell application "iTunes"
	set trackName to name of current track
	set trackArtist to artist of current track
end tell
	
set tweetText to trackName & "　by　" & trackArtist
```
めちゃくちゃ簡単ですね！

あとは、140字以内に収まるように調整します。

```applescript
if length of tweetText > 134 then
	set tweetText to text 134 thru 1 of tweetText & "..."
end if
```
#ツイート方法を考える
iTunesから曲の情報をとってくるのは簡単にできたのですが、
ツイートするのが一筋縄ではいかず、
できるだけ手間をかけずに作りたいな〜と思い、いくつかの案を考えました。

少し長いので、飛ばす方は「ツイート機能の実装」までどうぞ！
##案1 - ”インターネットアカウント”に紐付けたアカウントを利用する
Mac自体に紐付いたアカウントを利用するのは安全で至極当然だと考えました。
”インターネットアカウント”については[こちら](https://support.apple.com/kb/PH25682)を参照。

しかし調べてもAppleScriptからインターネットアカウントにアクセスする方法がわからず断念…。
##案2 - [Twitter Scripter](http://www.mousedown.net/mouseware/TwitterScripter.html)を使う
「AppleScript twitter」などというワードで調べてみると、
Twitter Scripterというアプリを使ってツイート機能を実現してる記事が多く見つかりました。
当該アプリが、インターネットアカウントに紐付けたアカウントとAppleScriptの橋渡しをしてくれるので、
AppleScriptでは当該アプリに向けてツイートや検索などの命令を行います。

直感的でわかりやすいのですが、できればサードパーティに頼りたくない(リスクをとりたくない)ので、今回は見送りました。
ただ、お試し用アカウントで連携してみる分には適切な選択肢だと思います。
##案3 - Twitter APIを直接叩く
(調べてませんが多分できると思います…。)
Twitterにアプリ登録をしなくてはならないので、すぐにやめました。
お試し用でアプリ登録するのはなんか違うなあと。
##案4 - ChromeでツイートURLを開き投稿する【採用】
ChromeでTwitterにログインしている前提ですが、
ツイートURLにツイートするテキスト(とハッシュタグ)を付与して、
それをChromeで開き、投稿ボタンを押してウィンドウを閉じる、という案です。

これなら、新しくアプリを入れる必要はないですし、Twitterにアプリを登録する必要もないので、
すぐに着手できるなと思い、この案を採用しました。
#ツイート機能の実装
##開くURLの生成する
単に文字列を連結するだけです。
これも簡単ですね。

```applescript
on createTweetUrlFromTweetText(tweetText)
	return "https://twitter.com/intent/tweet?text=" & tweetText & "&hashtags=nowplaying"
end createTweetUrlFromTweetText
```
##ChromeでツイートURLを開く
これ以降は以下のスコープ内でのコードとなります。

```applescript
tell application "Google Chrome"
    -- この中のコード
end tell
```
新しいウィンドウを開いて、開いたアクティブなタブにURLをセットします(開きます)。

```applescript
make new window
set URL of active tab of window 1 to tweetUrl
```
動作確認したのは、すでにウィンドウを一つ開いている状態だったので、
他の状態(ウィンドウを開いていない状態、等)では考慮が必要かもしれません。
##ローディングの完了を待機する
タブ開いた直後は投稿ボタンを押せないこともあるため、
ページのローディングが完了するのを待ちます。

```applescript
repeat until (loading of active tab of window 1 is false)
end repeat
```
ディレイで指定時間だけ待つのも簡単で良いですが、
ローディング速度に依らない処理にして安定性を高めました。
##投稿ボタンをクリックする
Chrome上で投稿ボタンを探してクリックするJavaScriptを実行します。
探し方(セレクターの指定方法)は他にもあると思うのでお好みで。

```applescript
execute active tab of window 1 javascript "document.getElementsByClassName('button selected submit')[0].click();"
```
かなりお手軽にJSを実行できるので、他にも色々ハックできそうです。
##投稿完了を待機してタブ(ウィンドウ)を閉じる
ページのローディング時と同様に、投稿完了を待ってからウィンドウを閉じて処理を終えます。

```applescript
repeat until (loading of active tab of window 1 is false)
end repeat

close active tab of window 1
```
#最後に
初めてのAppleScript作成でしたが、
最終的にアプリケーションにするまであまり躓くことなく進められました！
書き方も機能へのアクセスも直感的でわかりやすいのが良いですね。
ググったら情報がチラホラ出てくるのも助かりました。

スクリプト全体と参考にしたサイトは[このGist](https://gist.github.com/mosaicer/542cbc569dd641360bb5e29bd2ec9d6d)にまとめたので、興味があればご覧ください。
トイドローン Tello を Google Home を使って音声で制御

DJI と Intel が技術提供をしたことで話題のトイドローン Tello を Google Home を使って音声で制御できるようにしてみました。

「離陸して」

とか

「時計回りに10°回転して」

とか、こんな感じで音声で Tello を制御できます。

Tello を手のひらに置いて「離陸して」で離陸させて、「着陸して」で手のひらに着陸させれば間違いなくドヤ顔できます！

## 必要なもの

* Tello
* Raspberry Pi
    * Node 6以上
    * Wifiカード x 2
    * ngrok
* [Dialogflow](https://dialogflow.com/) アカウント
* Google Home または Google Assistant アプリ

## 仕組み

仕組みを解説すると以下のような感じです。

1. Raspberry Pi をインターネットと Tello それぞれに接続。このために2つの Wifi カードが必要です。
2. Raspberry Pi 内では Node で作った Webhook 用のエンドポイントが常駐。`ngrok` で外部からの接続を許可する。
3. Dialogflow でエージェントを作って、「離陸して」などの命令をインテントとして定義。
4. インテントが発火したら Webhook を蹴っ飛ばして、そこから Tello に UDP でメッセージを送信。

正直めんどくさかったです。ｗ

## 実装方法

### Raspberry Pi に必要なソフトをインストール

* Node 6.x 以上
* ngrok
* Wifi カード x 2

以上を必死こいて構築してください。

### Webhook 用のスクリプトをセットアップ

ソースは以下です。

https://github.com/miya0001/tello-api

手順がめんどくさくて説明するのもめんどくさいのでソースを読んでください。笑

このあたりがミソで、ここで Tello に送るメッセージをごにょごにょしています。

https://github.com/miya0001/tello-api/blob/master/index.js#L31-L51

起動するには以下のような感じです。

```
$ node index.js
$ ngrok http 8080
```

PC の Wifi を Tello につなぐと以下のような `curl` コマンドで制御することも可能です。

```
$ curl http://localhost:8080/ -X POST -H 'Content-Type:application/json' -d "$(cat test/post.json)"
```

`post.json` の中身は以下のような感じ。

```json
{
  "queryResult": {
    "intent": {
      "displayName": "up"
    }
  }
}
```

### Dialogflow でエージェントを作成

エクスポートしたデータを、上述の GitHub リポジトリにコミットしておきました。

https://github.com/miya0001/tello-api/tree/master/dialogflow

`.zip` で固めてインポートできます。

## 感想

まず、タコ糸とか釣り糸は必須です。あと外では試さないようにしましょう。ｗ
プロペラが２，３枚なくなることを覚悟してください！

1. 飛ばしてる最中に「テスト用アプリから応答がありません」って自体に陥ると天井に張り付いたままバッテリーが切れて落ちてくるのを待つことになります。。。なぜかフルパワーでプロペラがまわりはじめることもあって、この場合かなり激しい動きをしてくれるので外では試さないようにしましょう。
2. ドローンの音がうるさくて音声が認識されないことがあります。「着陸して」を聞き取ってもらえないときはつらい。
3. 「時計回りに９０°回転して」はやばい。精度が高いです。
4. 「10cm下がって」の下がってをうまく聞き取れないときは、上に行きます。笑

なにかの本で Drone はラジコンヘリの進化系ではなくて、空を飛ぶスマートフォンだというようなことを読んだのですが、音声コマンドで静かに部屋の中を飛び回るドローンというのは将来あるかもしれないと思った！
PX4 Development Guide 翻訳(1)

PX4での開発を始めました。
ここでは、PX4 Development Guide(https://dev.px4.io/en/) の翻訳をしていきます。
一人でも多くの方が、ドローン技術にコミットしていただければ嬉しいです。
**注意**　筆者はTOEIC300点台です(笑)
間違いがあればご指摘ください。

#introduction
>このガイドは主に、ソフトウェアの開発者とハードウェアインテグレーター向けです。
>サポートされているvehiclesを使用して飛行させるには[PX4 User Guide](https://docs.px4.io/en/)を参照してください。

このガイドでは以下について説明します。

* 最小の開発環境の構築、ソースコードからPX４をビルドする方法と、展開している多くのサポートしているオートパイロットについて
* PX４システムのアーキテクチャとその他のコア概念を理解する
* フライトスタックとミドルウェアの変更方法を学ぶ:
  * 飛行アルゴリズムを変更し、新しい飛行モードを追加する
  * 新しい機体をサポートする
* PX4に新しいハードウェアに統合する方法を学ぶ:
  * カメラやレンジファインダなど新しいセンサとアクチュエータのサポートについて
  * PX4を新しいオートパイロットハードウェアで実行する
* PX4のシミュレート、テストとログ/デバック
* 外部のロボットAPIと通信/統合

###Forums and chat

主な開発チームとコミュニティは以下のフォーラムとチャットチャンネルで活動しています。

* [PX4 Discuss](http://discuss.px4.io/) (推奨)
* [Slack](http://slack.px4.io/) (サインアップ)
* [Google+](https://plus.google.com/+PX4AutopilotProject)

>プラットフォームに貢献したい開発者は[Weekly call dev]()や別の[開発者イベント]()に参加するのも大歓迎です。

###貢献する
[Contributing & Dev Call](https://dev.px4.io/en/contribute/) はソースコードの使用方法について節名します。
[Documentation](https://dev.px4.io/en/contribute/docs.html)はドキュメントの変更方法と場所について説明しています。

###翻訳
このガイドには中国語と韓国語の翻訳があります。言語切り替えアイコンをクリックすると変更することができます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/254013/5a6d1b53-b4e9-4478-0897-4f0d98ff4be1.png)

###ライセンス
このコードは[BSDライセン３条項](https://opensource.org/licenses/BSD-3-Clause)の下、自由に使用および変更できます。
このドキュメントは[CC BY 4.0](https://creativecommons.org/licenses/by/4.0/) でライセンスされています。詳細は[licenses](https://dev.px4.io/en/contribute/licenses.html)を確認してください。
GlusterFSでボリュームを削除できない時に実行するコマンド(メタ情報を消す)

## エラーメッセージ

`gluster volume delete <ボリューム名>` で削除しただけでは再作成する時に下記のようなエラーが出ることがある。この場合はメタ情報も削除する必要がある。

```
# gluster volume create gv0 replica 3 storage01:/gv0/001 storage02:/gv0/001 storage03:/gv0/001
volume create: gv0: failed: /gv0/001 is already part of a volume
```

## 削除対象のディレクトリのメタ情報を確認するコマンド

```
getfattr -m - -d /gv0/001
```

### 実行例

```
[root@storage01 /]# getfattr -m - -d /gv0/001
getfattr: Removing leading '/' from absolute path names
# file: gv0/001
trusted.gfid=0sAAAAAAAAAAAAAAAAAAAAAQ==
trusted.glusterfs.volume-id=0sZMHRk56ETleyfiXJxDpQqA==
```

## メタ情報の削除

`trusted.glusterfs.volume-id` と `trusted.gfid` を削除する。表示されなかったものはやらなくてよい。

```
setfattr --remove=trusted.glusterfs.volume-id /gv0/001
setfattr --remove=trusted.gfid /gv0/001
```
特定フォルダ以下のすべての画像を圧縮するワンライナー

# 動機

ウェブサイトを作っていると、「のせる画像のサイズを制限したい」という欲望に駆られることが多いですが、コマンドラインで一つづつ圧縮していくのはめんどかったりします。

しかし、圧縮率とかを間違えて圧縮しすぎても困ります。ということでコピペに便利そうなワンライナーを書きました。

# 注意

使用しているコマンドは不可逆な変化を引き起こすので、gitでコミットするなりバックアップとるなりしてください。
また、画像以外の大きなファイルがあった場合は変な動作をするかもしれません。

# 本体

```bash
size=290 && ratio=99 && cmd='find . -size +'${size}'k' && while true; do string=`${cmd}` && array=(${string// / }) && if [ ${#array[@]} = 0 ];then break;fi && echo "----${#array[@]} file is over the size----" && for v in "${array[@]}";do echo $v; mogrify -resize ${ratio}% $v; done ; echo '';done
```
# 解説

仕組みとしては、`size`を超えるサイズの画像を`ratio`に定められた割合だけ`mogrify`で少しずつ画像のサイズを小さくしていき、`size`を超えるサイズの画像がなくなるまで繰り返すというものです。なくなった場合は止まります。

ループだったり文字列を配列に分割しているあたりは自分で調べてみてください。いい勉強になると思います。

`ratio`を100に近づけることで、`size`に近いサイズにすることができますが当然その分だけ時間がかかるのでそれに注意して数字を決めてください。まあ困ることは無いと思います。
ラズパイマウス セットアップ 個人メモ

# やったこと

- RaspberryPi Mouseの環境設定
- 動作確認

## イメージを入れる
SDカードにUbuntuMateのイメージをいれるところから。
[このへん](https://memoteki.net/archives/1308)を参考に。

## Wifiへの接続
WPA2に接続する[方法](https://qiita.com/tkyko13/items/1bc472ab777cc9375f06)はここにあるが，今回はUbuntu MateのGUIで接続したので余裕でした。

Raspbianを使っていた際には結構苦労した記憶。

## Chromeの導入
updateの後に何故かFirefoxが動かなくなったのでChromeを導入

```
sudo apt-get install chromium-browser
```

なんかやたら起動に時間掛かる…


## ROS Kineticのインストール
以下の記述を参考にROS Kineticをインストール

[公式](http://wiki.ros.org/ROSberryPi/Installing%20ROS%20Kinetic%20on%20the%20Raspberry%20Pi)
はRaspbianなので若干不安だったが[ubuntu mate版での記事](http://robonchu.hatenablog.com/entry/2017/03/28/192113)もあったのでこちらを参照。

とりあえずcatkin_wsを作って一通りコマンドが通ることを確認。

## RaspiMouseのセットアップ

出版社の[GitHub](https://github.com/rt-net/RaspberryPiMouse)をもとにセットアップを進めます。
[公式ページ](http://products.rt-net.jp/micromouse/raspberry-pi-mouse)をまずは熟読しましょう。
[ROSパッケージはこちら](https://github.com/ryuichiueda/raspimouse_ros_2)。


### GithubからのCloneのドライバインストール

```
git clone https://github.com/rt-net/RaspberryPiMouse.git
cd RaspberryPiMouse/utils
./build_install.ubuntu14.bash
```
エラーが出なかった場合は次の項目頭まで飛ばしてください。

なお，UbuntuMateではなんかエラーが出ました。（2018年5月）
`uname -r`の結果`4.4.38-v7+`を得たので'lib/Pi2B+'を見ていきます。
**なんと困ったことに`4.4.35-v7+`と`4.4.39-v7+`しか見つかりません。**

まぁ妥協して一歩古い方を入れます。

```
cd RaspberryPiMouse/lib/Pi2B+/4.4.35-v7+/
###install the kernel object
$ sudo insmod rtmouse.ko
```

### SPIをEnableする

sudoでraspi-configを呼び，Configウインドウを呼びます。
「3番」の入出力の設定でSPIをOnにします。
これだけ。


# ラズパイマウス用 ROSパッケージの導入

[ここのパッケージ](https://github.com/ryuichiueda/raspimouse_ros_2)を説明通りにインストールします。

## ドライバのセットアップ
ドライバの設定とデバイスへのアクセス権限を入手します。

```
sudo insmod ~/RaspberryPiMouse/lib/Pi2B+/4.4.35-v7+/rtmouse.ko
sudo chmod 666 /dev/rt*
```

## タイヤを回す
以下のようなコマンドでモータドライバを有効化できる。0を入力すると無効にできる。

```
echo 1 > /dev/rtmotoren0
```

周波数$f$を入れることでモータを回転させることができる。$\dfrac{f*2\pi}{400} [rad/s]$の回転数で回る。

```
echo 100 > /dev/rtmotor_raw_l0
```

一応計算式などをぶち込んでおく。[上田先生のプログラム](https://github.com/ryuichiueda/raspimouse_ros_2/blob/master/src/motors.cpp)とも矛盾はないはず。
![診療 - 3ページ.png](https://qiita-image-store.s3.amazonaws.com/0/188863/6f15188d-4408-45b9-2f58-de579ed69a6e.png)


# エラーメモ
## apt-get のエラー

apt-getで以下のエラーが発生

```
E: Could not get lock /var/lib/dpkg/lock - open (11: Resource temporarily unavailable)
E: Unable to lock the administration directory (/var/lib/dpkg/), is another process using it?
```


[次のサイト](https://qiita.com/jizo/items/9496496a3156dd39d91a)が参考になった。
最終手段らしいが以下のコマンドをうつ。

```
sudo rm /var/lib/apt/lists/lock
sudo rm /var/cache/apt/archives/lock

## 上記のみでダメなら下も実行してみる。
sudo rm /var/lib/dpkg/lock
sudo dpkg --configure -a
```
BigQueryのテーブルをリージョン移行する (asia-northeast1 > US)  

## 背景

2018年4月18日よりBigQueryにも東京リージョン (asia-northeast1)の提供が開始されました。

丁度新サービスで利用するタイミングと重なり、いざ東京リージョンで起動したところ、現状殆どのコマンドにLocation指定が必要なため、Redashも接続できなかったり不便すぎて、完全に早すぎました。1ヶ月後ならば全て解決している可能性あります。

仕事の都合上、今回はあまりこの辺に工数もかけられない & データも一部流し始めていたので、東京リージョンに残ったデータをキープしながらUSに移動を実施。

手順書があれば1分くらいで終わる作業を、色々細かいつまりポイントがあったので備忘録して記載。

## 前提

- 現状、基本的にはデータをリージョン間で跨ぐことは出来ない。今までのBQをデフォルトのUSリージョンで立てていて、今回からAsiaに作ると色々不便なことが発生する。具体的にはCopy Tableなどが出来ないことになる
- Cloud Storageのexportも同様に同一リージョンでないと動作しない
- 別リージョンのCloud Storageのデータを、BQのテーブル作成時などに読み込むことは出来る

## 方法

- バックアップのjsonデータ吐き出し先のbucketを作成する
- Storage に移動して、ストレージを `Regional: asia-northeast1` を選択して作成する
    - なお Multi-Regional で ASIA を選択しても動かないので要注意 

![image.png](https://qiita-image-store.s3.amazonaws.com/0/142932/6e3e5178-3e1b-ff69-ab42-f057d42fbb59.png)


- データ移行対象のDatasetに移動して、Google Cloud Storageに対して `Export Table` する
- この時にCSV形式はそのままimport処理できないので、JSON形式(gzip)を選択する
   - 初期値のCSVをそのままimport処理できないくらいならば、デフォルトJSONにしたほうが良いのではと思うのだが・・・

![image.png](https://qiita-image-store.s3.amazonaws.com/0/142932/53f756b3-8e3e-15a9-76b7-a98697bc01d3.png)

- 後は、BigQuery上でUSリージョンでDatasetを作成して、そこの新規テーブル作成のタイミングで、先程exportしたGoogle Cloud Storage上のjsonファイルを指定して、データを移行させる
Spring Tool Suite インストールと日本語化 for Windows

Eclipseベースの、Springでの開発に特化した統合開発環境である
**Spring Tool Suite (STS)**をインストールする手順です。

## Javaの確認
そもそもJavaが入っていないといけないので、Javaがインストールされているか確認。
コマンドプロンプトで
``` java -version  ```
と打てば、javaがインストールされているか、とjavaのバージョンがわかります。

![sts01.PNG](https://qiita-image-store.s3.amazonaws.com/0/140251/f1ac8119-f2bf-9033-ce5c-28f86730ff75.png)


こんな感じで表示されないのであれば、別途javaのインストールから。 
バージョン1.8以上なら大丈夫らしいので、今回はこのまま進めます。

## ダウンロード
以下リンクにアクセス
[Spring Tool Suite](https://spring.io/tools/sts/all)

![sts02.PNG](https://qiita-image-store.s3.amazonaws.com/0/140251/7dfc3885-c3e8-415b-9f53-a6b7726240de.png)


Windowsの「Based on Eclipse [バージョン]」をクリックして、自分のOSに対応している方をダウンロード。
ダウンロード先は適当に。

## インストール
ダウンロードしたzipファイルを解凍。

解凍すると「sts-bundle」というフォルダができるので、それを任意の場所に配置する。
sts-bundle > sts-3.9.4.RELEASE > STS.exe で立ち上がればとりあえずOK。
※ワークスペースをどこにするか聞かれるが、最初はとりあえずデフォルトのままでよい。

![sts03.PNG](https://qiita-image-store.s3.amazonaws.com/0/140251/4ed10124-1e0b-7fb6-f10a-03f12ce88ca8.png)


初めて起動した時の画面

## 日本語化
### ダウンロード
以下リンクより日本語化用のファイル(Pleiadesプラグイン)をダウンロード
[Eclipse 日本語化 | MergeDoc Project](http://mergedoc.osdn.jp/)

![sts04.PNG](https://qiita-image-store.s3.amazonaws.com/0/140251/bd5c7908-40ad-03e1-df04-ab89e1394da4.png)


ダウンロードするファイルは「Pleiades プラグイン・ダウンロード」から。
**※「Pleiades All in One ダウンロード」ではないので注意**

### 解凍
ダウンロードしたzipファイルを解凍する。
※Lhaplusで解凍したところ、エラー祭りだったので以下手順にて解凍。

1. zipファイル右クリック
2. プログラムから開く
3. エクスプローラー
4. ファイルをすべて展開（タブのところにあるやつ）

解凍すると、フォルダ内に「setup.exe」があるのでダブルクリック。

### セットアップ
* まず以下の画面が表示される。

![sts05.PNG](https://qiita-image-store.s3.amazonaws.com/0/140251/4e6db382-fa4b-f9b4-09b9-5e4ec6d13975.png)


* 「日本語化するアプリケーション」で先ほどインストールした「STS.exe」を選択

![sts06.PNG](https://qiita-image-store.s3.amazonaws.com/0/140251/3f746ea6-41dd-aca3-e8b1-3e70ee04e8ca.png)


* [日本語化する]を選択

![sts07.PNG](https://qiita-image-store.s3.amazonaws.com/0/140251/4f57aaff-fefc-abaa-ed47-8e2ef2d749ab.png)


* [終了]をクリック

![sts08.PNG](https://qiita-image-store.s3.amazonaws.com/0/140251/3438e61c-b125-ec4f-8d5c-6cb173afad4e.png)


### STSを起動して確認
* 日本語化されていれば完了

![sts09.PNG](https://qiita-image-store.s3.amazonaws.com/0/140251/425b2c33-1ed4-3c5c-4190-8f4c327fce96.png)


---
## 雑記
以前環境構築した時の日本語化は、
Pleiadesを解凍した後にいくつかのフォルダをSTS配下のどこかに置かないといけないなど
なんかやたら面倒だったのに、今回やったらsetup.exe叩くだけだったので驚いた。
HLSL を SPIR-V 経由で GLSL に変換してみた

HLSL を入力としたシェーダのトランスコンパイラをやってみたくなったので調べてみました。

準備
----------
DirectXShaderCompiler は Windows SDK に含まれていますが、SPIR-V のコードジェネレータは含まれていないようでした。

なのでコンパイラを自分でビルドします。

前提条件や公式の手順は [こちら](
https://github.com/Microsoft/DirectXShaderCompiler/wiki/SPIR%E2%80%90V-CodeGen) です。

```
git clone https://github.com/Microsoft/DirectXShaderCompiler.git
cd DirectXShaderCompiler
git submodule update --init

.\utils\hct\hctstart.cmd <dxc-src-dir> <dxc-bin-dir>
.\utils\hct\hctbuild.cmd -spirv
```

`<dxc-src-dir>` はクローンフォルダ、`<dxc-bin-dir>` はビルドのための一時フォルダです。

私の環境では Windows Driver Kit はすでにインストールされていたので、hctgettaef.py の実行はスキップしました。

ビルドが成功すると `<dxc-bin-dir>/Debug/bin/dxc.exe` に実行ファイルが出力されます。


変換してみる
----------

HLSLのシェーダを用意します。

```:test.hlsl
Texture2D txDiffuse : register(t0);
SamplerState samLinear : register(s0);
 
cbuffer ConstBuff : register(b0)
{
  matrix mtxProj;
  matrix mtxView;
  matrix mtxWorld;
  float4 Diffuse;
};
 
struct PS_INPUT
{
  float4 Pos : SV_POSITION;
  float2 Tex : TEXCOORD;
};
 
float4 main(PS_INPUT input) : SV_Target
{
  return txDiffuse.Sample(samLinear, input.Tex)*Diffuse;
}
```

dxc を使って SPIR-V に変換します。

```
> dxc -spirv -T ps_6_0 -E main test.hlsl -Fo test.spv
```

spirv-cross を使って GLSL に変換します。（spirv-cross は [VulkanSDK](https://vulkan.lunarg.com/sdk/home) に含まれています）

```
> spirv-cross --version 310 --es test.spv > test.frag
```

以下のようなコードが出力されました。

```glsl:test.frag
#version 310 es
precision mediump float;
precision highp int;

layout(binding = 0, std140) uniform type_ConstBuff
{
    layout(row_major) highp mat4 mtxProj;
    layout(row_major) highp mat4 mtxView;
    layout(row_major) highp mat4 mtxWorld;
    highp vec4 Diffuse;
} ConstBuff;

uniform highp sampler2D SPIRV_Cross_CombinedtxDiffusesamLinear;

layout(location = 0) in highp vec2 in_var_TEXCOORD;
layout(location = 0) out highp vec4 out_var_SV_Target;

void main()
{
    out_var_SV_Target = texture(SPIRV_Cross_CombinedtxDiffusesamLinear, in_var_TEXCOORD) * ConstBuff.Diffuse;
}
```
Git インストール for Windows

Git最新バージョンをwindowsでインストールする手順です。
※ 2018/05/01時点。Git version2.17.0

## インストールファイル入手
* 以下からインストール用ファイルを入手  
[Git for Windows](https://gitforwindows.org/)  
</br>

## インストールファイル実行
* ダウンロードしたexeファイルを実行する。

## ライセンス確認
![git01.PNG](https://qiita-image-store.s3.amazonaws.com/0/140251/7d8fbee2-0f42-b045-19d2-a14402517460.png)


* そのまま[Next >]をクリック  

## インストール先設定  
![git02.PNG](https://qiita-image-store.s3.amazonaws.com/0/140251/179cd02b-566c-39ee-020f-7ce7749eb41a.png)


* インストール先はデフォルトでよい。[Next >]

## コンポーネント設定
![git03.PNG](https://qiita-image-store.s3.amazonaws.com/0/140251/544b1fdc-9f50-0db7-7a96-1a29e4d88193.png)


* 何か特別に設定を加えるのでなければそのまま[Next >]  
  今回はそのままにする。

## スタートメニュー登録
![git04.PNG](https://qiita-image-store.s3.amazonaws.com/0/140251/ef58eea7-654a-9f7a-6779-54d0d64ca05d.png)


* そのまま[Next >]

## エディタ選択
![git05.PNG](https://qiita-image-store.s3.amazonaws.com/0/140251/84d3fb0d-3959-b69f-834c-1e1c3fabf671.png)


* 好みのエディタを選択  
とりあえずVimを選択して[Next >]

## 環境変数の設定  
* Use Git from Git Bash Only
  * GitコマンドをGit Bashでしか使えない状態にする。
* Use Git from the Windows Command Prompt
  * Gitコマンドをコマンドプロンプトからでも使えるようにする。
* Use Git and optional Unix tools from the Windows Command Prompt
  * Gitコマンドだけでなく、Unixコマンドもコマンドプロンプトから使えるようにする。

![git06.PNG](https://qiita-image-store.s3.amazonaws.com/0/140251/ee6555b6-b16c-3d1f-7424-7dec3af68867.png)


* 今回は「Use Git from the Windows Command Prompt」を選択して[Next >]

## SSLライブラリの設定
![git07.PNG](https://qiita-image-store.s3.amazonaws.com/0/140251/f6469b0e-c3cf-ca0e-7818-a78f4989b99c.png)


* デフォルトのまま[Next >]

## 改行コード設定
![git08.PNG](https://qiita-image-store.s3.amazonaws.com/0/140251/9ae8648c-e941-271e-8c61-485d7eadb66b.png)


* デフォルト設定(一番上)のままで[Next >]  
※参考リンクに詳しい解説あり

## コンソール設定
* コンソールにコマンドプロンプトを使用したければ Use Windows' default console windowを選択

![git09.PNG](https://qiita-image-store.s3.amazonaws.com/0/140251/5cf3ca57-934b-5ac2-8354-326330057055.png)

* 今回はデフォルトを選択し[Next >]

## gitconfigについての設定
* Enable file system caching
  * git status時などでの応答速度を改善するfscacheキャッシュを有効にするかしないかオプション
* Enable Git Credential Manager
  * GitHub等にアクセスする際の二段階認証に対応するかのオプション
* Enable symbolic links
  * シンボリックリンクの使用/不使用のオプション 

![git10.PNG](https://qiita-image-store.s3.amazonaws.com/0/140251/c6430cc1-2ca0-56f2-14c6-be930790db32.png)


* シンボリックリンクは使えた方が便利らしいので「Enable symbolic links」(一番下)にチェックを入れる。  
[Install]をクリック

## インストール
![git11.PNG](https://qiita-image-store.s3.amazonaws.com/0/140251/c64222b6-acbd-e335-dad5-d74d8cbb7824.png)


## インストール終了
![git12.PNG](https://qiita-image-store.s3.amazonaws.com/0/140251/a7df33df-c886-847c-6be8-375df5d6fd30.png)


* この画面が出ればインストール完了

> 参考記事
> * https://qiita.com/toshi-click/items/dcf3dd48fdc74c91b409
> * https://utano.jp/entry/2016/07/git-for-windows-install/
materialize.cssを使ってみて

#materialize.cssとは
[公式](http://materializecss.com/about.html)はこちらです。
CSSを生書きしなくても、使用できるフレームワークです。私自身、フロントにものすごく弱いのですごく活用させてもらってます。他にはBootstrapが有名かもしれません。

#使用方法
```html:application.html.erb
 <!-- Compiled and minified CSS -->
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0-beta/css/materialize.min.css">

    <!-- Compiled and minified JavaScript -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0-beta/js/materialize.min.js"></script>
```

Railsで使用するときは以上のようにURLからダウンロードしてとっていきます。application.html.erbのheadタグ内で記述します。ちなみに、オフラインの場合だと接続できないねと思いましたが、Webアプリ自体がオフラインだとアクセスできないのでまあいいか、思った次第であります。

https://www.youtube.com/watch?v=nqT8c5OFjEQ

上記のURLで動画で活用の仕方を丁寧に説明してくださっています。

#どんな感じになるか

<img width="1302" alt="スクリーンショット 2018-05-01 21.31.57.png" src="https://qiita-image-store.s3.amazonaws.com/0/253129/c4b17dc2-8e41-9289-2298-83a778116450.png">

挙げられているHTML/CSSをうまく活用して行くと上のようなページが完成しました。
Kivy + PythonでマルチプラットフォームなGUIアプリ開発を試してみる

# TL;DR

PyQtで（ライセンス的にもSAN値的にも）大幅に消耗したのでkivyを使ってみたらQOD（Quality of Developing）が向上した話

# kivyって何よ

[kivy](https://kivy.org/)は、Pythonでマルチプラットフォーム対応のGUIアプリケーションを作るためのライブラリです。

Kivyは、MITライセンスのもと、オープンソースで開発がされているため、Qt等とくらべてライセンス的にも嬉しい仕様になってます。Qtの場合、悪しき†LGPLv3†のおかげで、会社でコードを書く際にかなり頭を悩ませていました。しかし、Kivyを使用すれば、商用としてのマルチプラットフォームGUIアプリ開発のコストを大幅に削減することができます。すごい！

おまけにレンダリングにはOpenGLを使用しているため、GPUによる恩恵を十分受けることができます。

ちなみに、Kivyで作成されたアプリは、以下デバイスに対応することができます（すごい）

- Linux
- Windows
- Mac OSX
- Android
- iOS
- Raspberry Pi

# インストール方法

## Windowsの方

※以下インストール手順中に「**Permission denied**」といったようなエラーがでた場合は、コマンドプロンプトを管理者権限で実行してください。

### 1. pip等のコマンドを最新に更新

```bash
python -m pip install --upgrade pip wheel setuptools
```

### 2. 依存ライブラリの導入

```bash
python -m pip install docutils pygments pypiwin32 kivy.deps.sdl2 kivy.deps.glew
python -m pip install kivy.deps.gstreamer
```

#### `MemoryError`が出た場合

`pip install`のあとに`-no-chache-dir`フラグを追加して実行しなおして下さい。

```bash
python -m pip install –no-cache-dir --upgrade pip wheel setuptools
```

#### Pythonのバージョンが3.5以上の場合

`glew`の代わりに`angle`をバックエンドとして使用するらしいので、以下コマンドで導入してください。

```bash
python -m pip install kivy.deps.angle
```

### 3. kivy本体のインストール

```bash
python -m pip install kivy
```

### 4. （必要な人）サンプルプログラムのインストール

```bash
python -m pip install kivy_examples
```

サンプルプログラムは、Pythonがインストールされているフォルダの`share`フォルダ以下のインストールされます。

実際に起動する際は、以下のように直接パスを指定して起動します。

```bash
python share\kivy-examples\demo\showcase\main.py
```

## Macの方

※macOSX v10.7 Lion以降（32bitを除く）を使っている方は、開発に必要なpython3の開発環境と各種パッケージを同梱した`Kivy.app`というパッケージをkivy側が提供しています。[公式サイト](https://kivy.org/docs/installation/installation-osx.html#using-the-kivy-app)から入手してください。

### 1. Homebrew経由で必要なライブラリをインストール

```bash
brew install pkg-config sdl2 sdl2_image sdl2_ttf sdl2_mixer gstreamer
```

### 2. PyPI経由でCythonをインストール

```bash
pip install Cython==0.26.1
```

### 3. kivy本体のインストール

※【2018/5/1】現在、PyPIのリポジトリ経由でインストールすると、`MIX_INIT_*`の定数使用箇所でビルドが落ちてしまう不具合があります。そのため、以下手順では、kivyのmaster（dev version）をインストールしています。詳細→https://github.com/kivy/kivy/pull/5459

```bash
pip install https://github.com/kivy/kivy/archive/master.zip
```

## Linuxの方

LInuxの場合、ディストリビューションによってかなり手順が複雑・特殊なので、詳しくは[公式ドキュメント](https://kivy.org/docs/installation/installation-linux.html)を参照してください。

# ウィンドウを表示してみる

kivyのアプリを構成する最小限のコードは以下のとおりです。

```python:main.py
from kivy.app import App
from kivy.uix.widget import Widget
 

class MainWindow(Widget):
    pass


class HelloWorldApp(App):
    def build(self):
        return MainWindow()


if __name__ == '__main__':
    HelloWorldApp().run()
```

実行すると、以下のような黒いウインドウが出ます。これで、kivyアプリが作成されました。

<img width="801" alt="Screen Shot 2018-05-01 at 21.20.59.png" src="https://qiita-image-store.s3.amazonaws.com/0/61960/2d4b9110-bcd8-7047-b81d-c45fb1df6550.png">

# 公式チュートリアル

公式のチュートリアルとして、「Pong」と呼ばれるピンポンゲームを作るチュートリアルが公開されてます。

気になる方はやってみてください。

https://kivy.org/docs/tutorials/pong.html

# 参考文献

https://kivy.org/#home
pythonでYouTubeの再生数が指定回数以上の動画タイトルを取得

## 概要
人気のYoutube動画タイトルのデータセットを作ろうしたら意外と苦戦したので備忘録として．
全動画から検索はできなさそうだったので，人気YouTuberのチャンネルidを地道に手作業で集めて，各チャンネルに紐づく動画で再生数が多いもののみを取得しています．

## タイトル取得手順
YouTube Data API(v3)を用います．
指定再生数以上の動画リストをまるっと返してくれるような都合の良いリクエスト方法はないようで，以下のよう手順を踏んでいます．

1. 人気のあるチャンネルのid収集**（手作業）**
2. 各動画チャンネルに紐づく動画リストを取得
3. 各動画の再生数を取得
4. 再生数が指定回数以上ならタイトルを保存

取得部分の関数はこんな感じ.

~~~python
def getVideoTitle(ch, term_start, term_end, next):
  # チャンネルの指定期間内の動画一覧を取得
  request = urllib.urlopen("https://www.googleapis.com/youtube/v3/search?channelId=" + ch + "&part=id,snippet" + term_start + term_end + "&maxResults=50&key=***your api key***" + next)
  response = request.read()  # 文字列が返ってくる
  data = json.loads(response) #文字列をjson化

  id_list = []
  title_list = []
  for d in data["items"]:
    if "videoId" in d["id"]:
      id_list.append(d["id"]["videoId"])
      title_list.append(d["snippet"]["title"])

  videoid = "&id=" + ','.join(id_list)
  titles = []
  if len(id_list) > 0:
    # 取得した動画の再生数を取得し判定後，タイトルリストに追加
    request = urllib.urlopen("https://www.googleapis.com/youtube/v3/videos?part=statistics" + videoid + "&fields=items(statistics)&key=***your api key***")
    response = request.read()
    count = 0
    for item in json.loads(response)["items"]:
      if int(item["statistics"]["viewCount"]) > 1000000:  # 任意の再生数を指定
        titles.append(title_list[count])
      count += 1

  if "nextPageToken" in data["items"]:
    npt = data["nextPageToken"]
  else:
    npt = ""

  return [npt, titles]
~~~

チャンネルに紐づく動画情報には再生数がなく，取得したvideoIdで再リクエストして再生数含む動画情報を取得しています.

## 途中で動画情報が取得できなくなる
過去に他の方が同じ問題に直面していたようで，そちらを参考にしました．
[YouTubeの特定のチャンネルに紐付く動画を取得する。（YouTube Data API (v3) Search）](https://qiita.com/yuji_saito/items/8f472dcd785c1fadf666)
一定期間ごとに分けて繰り返し動画リストを取得することで解消できます．先ほどのコードで```start_term```と```end_term```を引数に与えていたのはこのためです．

以下のように，先ほどの関数を取得期間をずらしながら繰り返し呼びタイトルを取得しました．

~~~python
pageToken = "&pageToken="
TitleList = []
for i in range(36):
  before = "&publishedBefore=" + date.strftime("%Y-%m-%d") + time
  date = date - datetime.timedelta(weeks=4)
  after = "&publishedAfter=" + date.strftime("%Y-%m-%d") + time
  next = ""
  while next != pageToken:
    next, titles = getVideoTitle(ch, after, before, next)
    next = pageToken + next
    TitleList.extend(titles)
~~~
Create.jsでCanvas描画可能なライブラリをBitmapオブジェクトとして利用する


## BitmapクラスはCanvasエレメントを参照できる

[CreateJSの公式ドキュメント](https://createjs.com/docs/easeljs/classes/Bitmap.html)を参照すると、Bitmapクラスのコンストラクター引数は

>Bitmap ( imageOrUri )
>Defined in Bitmap:38
>
>Parameters:
>imageOrUri CanvasImageSource | String | Object
>The source image to display. This can be a CanvasImageSource (image, video, canvas), an object with a getImage method that returns a CanvasImageSource, or a string URL to an image. If the latter, a new Image instance with the URL as its src will be used.

となっており、Canvasエレメント自体がコンストラクターに渡せることがわかります。

## Canvasエレメントに描画した結果をCreate.jsで表示する

これを利用することで、Canvasに結果を描画するタイプのライブラリをCreate.jsの一部として取り込むことができます。

例として、Chart.jsの出力結果をCreate.jsのBitmapインスタンスとして使用してみます。

````js
const chartCanvas = document.createElement("canvas");
chartCanvas.width = w;
chartCanvas.height = h;
const canvasContext = chartCanvas.getContext("2d");

const chartBitmap = new createjs.Bitmap(chartCanvas);

//ここでChart.js用のChart.ChartConfigurationオプションデータを生成する。

let chart = new Chart(canvasContext, options);

stage.add( chartBitmap );
````

というような感じで、オフスクリーンのcanvasエレメントを生成、コンテクストを取得、コンテクストとチャートオプションを渡してChartを初期化、という手順を踏むとCreate.jsのDisplayObjectとしてChart.jsの出力結果を利用できます。

## Retinaディスプレイなど高DPI環境での問題

Chart.jsでは、Retinaディスプレイなど高DPI環境を判定してCanvasサイズを変更する処理を行っています。この処理が、Chart.jsをCreate.jsのBitmapインスタンスとして利用する際に問題となります。

Create.jsは動作環境での解像度を判定しません。そのためBitmapインスタンス化したChart.jsのチャートだけが倍のサイズになって表示されてしまいます。

Chart.jsでは`Chart.helpers.retinaScale`という関数で高DPI環境の判定と処理を行っています。この関数を上書きしてしまうことでこの問題を解消できます。

````js
var originalRetinaScale = Chart.helpers.retinaScale;

Chart.helpers.retinaScale = function(chart) {

    if( !chart.options.responsive && !chart.options.maintainAspectRatio )
    {
        return;
    }
    originalRetinaScale( chart );
};
````

上記の例ではresponsiveとmaintainAspectRatioの両方のオプションをfalseにした場合は、retinaScale関数の処理をスキップし、それ以外はオリジナルのretinaScale関数を実行するというものです。オプション指定のないチャートはスケーリング処理が行われるので、html側のチャートとCreate.js側のチャートが共存できます。
【jQuery】基本的なメソッドなど

##表示/非表示

```javascript
//表示
$('セレクタ').show();
//表示 時間指定
$('セレクタ').show(2000);
//非表示
$('セレクタ').hide();
//非表示　時間指定
$('セレクタ').hide(1500);
```

##スライド表示/非表示
```javascript
//スライド表示
$('セレクタ').slideUp();
//スライド表示 速度指定
$('セレクタ').slideUp(slow);
//スライド非表示
$('セレクタ').slideDown();
//スライド非表示　速度指定
$('セレクタ').slideDown(slow);
```

##クリックイベント
```javascript
$('セレクタ').click(function(){
 $('セレクタ').メソッド();
});
//thisで対象を絞り込む
$('セレクタ').click(function(){
 $(this).メソッド();
});
```

##hoverイベント
```javascript
$('セレクタ').hover(function(){
 //hover時
 $('セレクタ').メソッド();
},
function(){
//hover外した時
 $('セレクタ').メソッド();
})
```

##CSSの変更
```javascript
$('セレクタ').css('プロパティ名','値');
```

##文字の変更
```javascript
$('セレクタ').text('書き換える文字');
```

##htmlの挿入
```javascript
$('セレクタ').html('挿入するHTML');
```

##クラスの設定/クラスを外す
```javascript
//クラスの設定
$('セレクタ').addClass('クラス名');
//クラスを外す
$('セレクタ').removeClass('クラス名');
```

##クラス持っているか？ true falseを返す
```javascript
//クラスの設定
$('セレクタ').hasClass('クラス名');
//イメージ
if($('p').hasClass('test')){
  $(this).hide();
} else {
 $(this).show();
}
```

##変数の定義
```javascript
var $変数名 = $('セレクタ');
```

##メソッドチェーンで指定　　一つのセレクタに対して複数のメソッドを指定
```javascript
$('セレクタ').html('挿入するHTML').color('プロパティ','値').fadeOut();
```
OpenBSDのacme-clientでLet's Encryptの証明書を取得する

# OpenBSD
OpenBSDには独自のHTTPサーバーがあるのを知って調べると、ACMEのクライアントもあると知った[^1] [^2]。
ACMEのクライアントは、[`acme-client(1)`][acme-client.1]。OpenBSD 6.1から登場とのこと。
OpenBSD 6.3では、証明書やChallenge格納に必要なディレクトリは、あらかじめ作成されているようだ。早速使ってみたい。
環境は、現状最新のOpenBSD 6.3。

# 設定
## acme-clientの設定
実際の`/etc/acme-client.conf`を見れば一目瞭然。
変えたのは…

- `example.com`を自分のドメイン名に置き換え
- `alternative names`に、`{ mail.example.com ns.example.com www.example.com }`など、スペース区切りでSANSを記載

詳細は[`acme-client.conf(5)`][acme-client.conf.5]参照。

## httpdの設定
実際の`/etc/examples/httpd.conf`を見れば一目瞭然。
変えたのは…

- `example.com`を自分のドメイン名に置き換え
- TLS用の`server`セクションをコメントアウト

これを、`/etc/httpd.conf`に置く。

TLS用の`server`セクションとは、`port 443`が入ったセクション。証明書取得前は、証明書が無いので、証明書取得後に有効にしてみる。
証明書の格納先は、`acme-client.conf`と`httpd.conf`で一致していることを確認する(デフォルトで一致していた)。
ACMEのChallenge用の格納先は、下記の[`acme-client(1)`][acme-client.1]の記載が、exampleの`httpd.conf`にあらかじめ記載されているので、これをそのまま使う。

```httpd.conf
        location "/.well-known/acme-challenge/*" {
                root "/acme"
                root strip 2
        }
```

詳細は[`httpd.conf(5)`][http.conf.5]参照。

# 実行

```shell-session
# rcctl enable httpd
# rcctl start httpd
# acme-client -vAD example.com
```

上記example.comは、`acme-client.conf`の`domain`に書いた自分のドメインと一致させる。
30秒くらいで、あっという間に完成。
`acme-client.conf`に書いてある、`/etc/ssl/example.com.fullchain.pem`や`/etc/ssl/private/example.com.key`ができる。

# 証明書をhttpdで使う
先ほど用意した`/etc/httpd.conf`の`port 443`が入ったセクションを有効にして、

```shell-session
# rcctl reload httpd
```

その後、ブラウザでアクセスして確認。

# 証明書更新の自動化
[`acme-client(1)`][acme-client.1]によると、

> A daily cron(8) job can renew the certificates:
>            acme-client example.com && rcctl reload httpd

とのこと。daily cronは、`/var/cron/tabs/root` -> `/etc/daily`を追うと、`/etc/daily.local`というのを作れば良さそうに見える。
…というのが、後から[`daily(8)`][daily.8]を見てわかった。

```ksh:/etc/daily.local
acme-client example.com && rcctl reload httpd
```

更新されるとexit statusが0になって、httpdがreloadされるという仕掛けですね。
…で、動くと思う…(未確認)。

# 参考文献

やはりOpenBSDは`man`? 具体例もあり、充実している。

[^1]: [Easy Secure Web Serving with OpenBSD’s acme-client and Let’s Encrypt](https://spin.atomicobject.com/2016/09/20/openbsd-acme-client-lets-encrypt/)…cronへの言及もあり、わかりやすいが、コマンドラインオプションが少なくとも今と違うような?
[^2]: [Using Let's Encrypt on OpenBSD 6.1](https://www.vultr.com/docs/using-let-s-encrypt-on-openbsd-6-1)…比較的新しく、そのまま適用できそう

- [`acme-client(1)`][acme-client.1]
- [`acme-client.conf(5)`][acme-client.conf.5]
- [`httpd.conf(5)`][http.conf.5]
- [`daily(8)`][daily.8]

[acme-client.1]:https://man.openbsd.org/acme-client.1
[acme-client.conf.5]:https://man.openbsd.org/acme-client.conf.5
[http.conf.5]:https://man.openbsd.org/httpd.conf.5
[daily.8]:https://man.openbsd.org/daily.8
Meta2 Note

# Issue1 : Meta2 doesn't recognize hand position correctly when the meta camera rig has a parent.

Sadly, Meta2 SDK 2.7.0 is not smart enough to locate your hand position correctly when the camera rig is a child of some other objects. To solve this problem, you have to modify the SDK as below:

**Warning: You should put the MetaHands Prefab under the same hierarchy of MetaCameraRig!**

```c#:HandsProvider.cs

private void OnHandDataAppear(HandData handData)
{
    ...
    //handProxy.transform.SetParent(transform);
    handProxy.transform.SetParent(transform, false);
    ...
}
```
```c#:CenterHandsFeature.cs

public override Vector3 Position
{
    get
    {
        if (transform.parent != null)
        {
            return transform.parent.TransformDirection(HandData.Palm);
        }
        return HandData.Palm;
    }
}

private void FindObjectsWithinVicinity(float searchRadius)
{
    ...
    //var grabAnchor = HandData.GrabAnchor;
    var grabAnchor = Position;
    ...
}

````

```c#:TopHandFeature.cs

public override Vector3 Position
{
    get
    {
        if (transform.parent != null)
        {
            return transform.parent.TransformDirection(HandData.Top);
        }
        return HandData.Top;
    }
}
```
GKEがデフォルトで提供してくれるログ まとめ

GKEでは、自前でなにもしなくても _Stackdriver Logging_ を有効にしておくだけで自動でログを収集してくれているので、
 [ブラウズ](https://console.cloud.google.com/logs/viewer) したり、[ログベースのメトリクスでアラートを仕込んだり](https://app.google.stackdriver.com)できるようになる。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/27025/42f71472-6ed5-4544-3a40-12f13a108405.png)

以下、何がどこに送られてきているかのまとめ。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/27025/77704f9d-ad4a-ea65-78c2-fb1a8b65cf7f.png)

# GKE Container (`resource.type="container"`)

デプロイされた各コンテナの標準出力、標準エラー出力が送られてくる。

## namespace: kube-system

Kubernetesのシステム用（そのまんま）のコンテナからのログ。

以下、 Pod名と(コンテナ名)

* default-http-backend (default-http-backend)
* event-exporter-v0.1.7 (event-exporter, prometheus-to-sd-exporter)
* fluentd-gcp-v2.0.9 (fluentd-gcp, prometheus-to-sd-exporter)
* heapster-v1.4.3 (heapster, prom-to-sd, heapster-nanny)
* kube-dns (dnsmasq, kubedns, sidecar)
* kube-dns-autoscaler (autoscaler)
* kube-proxy-XXXXXX (kube-proxy)
* kubedash (kubedash, heapster)
* kubernetes-dashboard (kubernetes-dashboard)
* l7-default-backend (default-http-backend)

などがいる。（もしかしたら自分でデプロイしたものが混ざっているかもしれない）

## namespace: それ以外

自分でデプロイしたコンテナからのログ。

# GKE Cluster Operations (`resource.type="gke_cluster"`)

## events

Kubernetesのイベント（`kubectl get events` で見れるやつ）が送られてくる。

注意点として、 _location_ を選択してしまうと出てこなくなるので、 _All location_ を選ぶこと。（嵌った）

![image.png](https://qiita-image-store.s3.amazonaws.com/0/27025/93d415d1-9986-6461-af7d-a3c94da8f7f2.png)

# GCE VM Instance (`resource.type="gce_instance"`)

インスタンス上で直接動く各種プロセスからのログが送らてくる。

* kubelet
* kube-proxy
* docker
* node-problem-detector

これらのログはこっち。

# おわり

ガチになると自前でDatadogなどに送らないといけないのかもしれないけど、
デフォルトでもある程度は全然いけるGKE素敵。

蛇足

* GKE Node Pool Operations
* Kubernetes Cluster

というログもあるけど何のログかちゃんと調べられていない。。。

----

リファレンス

[ログ  |  Kubernetes Engine  |  Google Cloud](https://cloud.google.com/kubernetes-engine/docs/how-to/logging)

[Events in Stackdriver | Kubernetes](https://kubernetes.io/docs/tasks/debug-application-cluster/events-stackdriver/#google-kubernetes-engine)

[よくある質問  |  Container-Optimized OS  |  Google Cloud](https://cloud.google.com/container-optimized-os/docs/resources/faq?hl=ja#where_are_docker_and_kubelet_logs)
Convert m4a to mp3 with ffmpeg

Convert single file

```bash
ffmpeg -i foo.m4a -acodec libmp3lame -aq 2 bar.mp3
```

Or, for batch processing:

```bash
for foo in *.m4a; do ffmpeg -i "$foo" -acodec libmp3lame -aq 2 "${foo%.m4a}.mp3"; done
```


Reference: https://coderwall.com/p/zbevoq/convert-m4a-to-mp3-with-ffmpeg
Create.jsのText描画パフォーマンスを改善するキャッシュ処理


## はじめに

このドキュメントは、Create.jsのテキスト設定について、

1. グローバル設定による描画速度の変化
1. 描画速度低下の対策

の2点を解説するためのものです。

## Create.jsでのText描画

> Note: Text can be expensive to generate, so cache instances where possible.

[公式ドキュメント](https://www.createjs.com/docs/easeljs/classes/Text.html)にもあるとおり、Create.jsでのテキストの描画は比較的重い処理です。
とくにこんな場合に重くなります。

1. テキストにアウトラインフォントを設定している場合。
1. snapToPixelの設定を変更した場合。

````js
createjs.Text.prototype.snapToPixel = false;
````

このグローバル設定を行うとテキスト描画にアンチエイリアスがかかりますが、その分描画処理が重くなります。

## 描画速度の検証

アウトラインフォントの描画速度を改善する効果的な対策は、ビットマップキャッシュの適用です。

+ 通常のテキストを8000個ステージに並べる。（[CodePen](https://codepen.io/masatomakino/full/NMdqPq)）
+ テキストに個別にビットマップキャッシュをかける。（[CodePen](https://codepen.io/masatomakino/full/deNoJr/)）

手元の環境ではFPSでおおよそ3倍の差が出ます。

## テキストへのビットマップキャッシュの適用方法

テキストのビットマップキャッシュの適用にはバウンディングボックスの取得が必要になります。
しかしTextは、getBounds関数では厳密にはサイズを取得できません。

[公式ドキュメント](https://createjs.com/docs/easeljs/classes/Text.html#method_getBounds)

```js
const bounds = text.getBounds();
const margin = 8;
text.cache(
  bounds.x - margin,
  bounds.y - margin,
  bounds.width + margin * 2,
  bounds.height + margin * 2
);
```

上記の例では8pxですが、幾らかのマージンを与えると意図した通りの描画になります。

## ビットマップキャッシュの更新判定

キャッシュされたテキストは、更新のない間は高速に描画されます。
しかし再描画が必要になったり、キャッシュの縦横サイズを変更しなくてはならない場合は大きな負荷がかかります。

テキスト更新が発生した場合に、以下の条件で判定を行い、変更がない場合は再描画を抑制すると負荷が軽減できます。

* 文言が変更されている
* フォントが変更されている
* textAlignが変更されている : キャッシュのサイズが変化するので、uncacheをしてから再cacheする。
* 文字カラーだけが変更されている : キャッシュのサイズは変わらないので、updateCacheする。
* 文言の変化がない : キャッシュ処理をスキップ。

## 更新判定のモジュール化

これらの更新判定処理をまとめたモジュールを作成しました。

[![ReadMe Card](https://github-readme-stats.vercel.app/api/pin/?username=masatomakino&repo=createjs-cache-util)](https://github.com/masatomakino/createjs-cache-util)

```js
CreatejsCacheUtil.cacheText(textField, "textContents", option);
```

第一引数はcreatejs.Textオブジェクト、第二引数が更新するテキストの内容、第三引数がテキストの描画オプション（省略可能）です。なんらかの変更がある場合は第一引数のTextオブジェクトのビットマップキャッシュを更新し、必要がない場合は更新をスキップします。

## よりパフォーマンスを重視するならContainerにラップしてからキャッシュ生成

Textインスタンスに個別にビットマップキャッシュを適用するよりも、そのインスタンスをContainerにaddChildして、コンテナー丸ごとをビットマップキャッシュする方がパフォーマンス的には有利です。テキストの更新頻度が低く、大量のテキストを扱う場合はぜひContainerにラップしてください。
PythonでGoogleスプレッドシートを編集

PythonでGoogleスプレッドシートを編集してみました。

#環境
Python 3.5.2
pip 10.0.1
gspread 3.0.0 → https://github.com/burnash/gspread
oauth2client 4.1.2

#サービスアカウントキー取得

Googleスプレッドシートにアクセスするためのサービスアカウントキー(JSONファイル)を取得します。

##プロジェクト作成

こちらからプロジェクトを作成します。
https://console.developers.google.com/cloud-resource-manager

![a.png](https://qiita-image-store.s3.amazonaws.com/0/112075/e1627ac6-f200-4106-f9c1-af81dfa7cbff.png)

プロジェクト名を適当に入力します。今回は「gspread-sample」としました。

![b.png](https://qiita-image-store.s3.amazonaws.com/0/112075/46ccff77-6a41-8a57-1b48-bd3d2342516a.png)

##Google Drive APIを有効
ライブラリからAPIを検索します。

![n.png](https://qiita-image-store.s3.amazonaws.com/0/112075/8cf4c43a-1561-ebb8-88ca-bae01b3e9e26.png)

「drive」と入力すると「Google Drive API」が表示されるので選択します。

![e.png](https://qiita-image-store.s3.amazonaws.com/0/112075/8478b8e9-d7b5-b9f6-615a-f48f60b6f93b.png)

「Google Drive API」を有効にします。

![f.png](https://qiita-image-store.s3.amazonaws.com/0/112075/c838f1e1-ff98-5e5a-d06e-02b9b10ce894.png)

##Google Sheets APIを有効

「sheet」と入力すると「Google Sheets API」が表示されるので選択します。

![g.png](https://qiita-image-store.s3.amazonaws.com/0/112075/83fe78dc-afc5-27a0-302e-6efc26819e2b.png)

「Google Sheets API」を有効にします。

![h.png](https://qiita-image-store.s3.amazonaws.com/0/112075/2bcd4723-4d6e-1f93-8537-6ffbd34b2056.png)

##サービスアカウントキー作成

認証情報から認証情報を作成「サービスアカウント キー」を選択します。

![c.png](https://qiita-image-store.s3.amazonaws.com/0/112075/9a072ae3-0772-3a8f-8881-4ef6200eb8e0.png)

サービスアカウント名を適当に入力して、役割は「編集者」を選択、キーのタイプは「JSON」を選択します。

![d.png](https://qiita-image-store.s3.amazonaws.com/0/112075/e2f43263-6899-c511-c9e1-fa0467496fd1.png)

サービスアカウントキーを作成するとJSONファイルがダウンロードされます。

#スプレッドシート共有

こちらからスプレッドシートを作成します。
https://docs.google.com/spreadsheets/create

シート名を適当に入力します。今回は「gspreadサンプル」としました。

![k.png](https://qiita-image-store.s3.amazonaws.com/0/112075/71778cc4-7b0e-2e2a-b708-ced14a903aff.png)

シート右上の共有ボタンを押すと共有するユーザーのメールアドレスを入力するエリアが表示されるので
JSONファイルを開いて「client_email」行のメールアドレスをコピーして貼り付けます。

```json:JSONファイル(抜粋)
  "client_email": "xxxxx@gspread-sample-202808.iam.gserviceaccount.com",
```

![l.png](https://qiita-image-store.s3.amazonaws.com/0/112075/372c46ed-fcbf-98b0-fefd-ee2925a116c6.png)

#パッケージインストール

「gspread」と「oauth2client」をインストールします。

```bash:
$ pip install gspread
$ pip install oauth2client
```

#プログラム作成

Googleスプレッドシートを編集するプログラミングを作成します。

```py:gspread-sample.py
import gspread
from oauth2client.service_account import ServiceAccountCredentials

scope = ['https://spreadsheets.google.com/feeds',
         'https://www.googleapis.com/auth/drive']

credentials = ServiceAccountCredentials.from_json_keyfile_name('<JSONファイル名>.json', scope)
gc = gspread.authorize(credentials)
wks = gc.open('gspreadサンプル').sheet1

wks.update_acell('A1', 'Hello World!')
print(wks.acell('A1'))
```

#プログラム実行

作成したプログラムとJSONファイルを同じフォルダに入れて実行します。

```bash:
$ python gspread-sample.py
<Cell R1C1 'Hello World!'>
```

シートを開いて「Hello World!」と編集されていたら完成です。
https://docs.google.com/spreadsheets/

![m.png](https://qiita-image-store.s3.amazonaws.com/0/112075/ab17a785-b5b6-509a-e0a2-7487f6a70757.png)
PHPでエラー表示設定にしていても白画面

フレームワークを使用していない場合等でdisplay_errorsをOnにしていても白画面になってしまいログにもエラーが出力されない場合の原因を探る方法

以下を先頭に記述する

```php
function debug()
{
    var_dump(error_get_last());
}
register_shutdown_function('debug');
```
kube-prompt-bash作った

# kube-prompt-bashとは

Bashのpromptに、kubectlで使用している クラスタ名・Namespace名・ユーザ名 を表示します。
以下サンプルです。kubensと呼ばれるコマンドで namespace をスイッチしていることに追従して、プロンプトの表示が変わっています

```
[root@sugi-kubernetes110-master01 ~(kubernetes default kubernetes-admin)]# kubens test
Context "kubernetes-admin@kubernetes" modified.
Active namespace is "test".
[root@sugi-kubernetes110-master01 ~(kubernetes test kubernetes-admin)]# 
```

カッコの中に、クラスタ名・ネームスペース名・ユーザ名を表示しています。
以下GitHubです。すごい簡素な造りなので、動作しない場合は教えてください

https://github.com/Sugi275/kube-prompt-bash



# なんで作ったの？

Kubernetesを操作しているときに、どのネームスペースを操作しているのか、分からなくなる時が有りました。
プロンプト上に常に表示することで、現在操作している対象を確認したいため、作りました。

kube-ps1 とよばれるツールもありますが、私の環境では非常に重かったため、独自に作ってみました。
プロンプトでエンターを押す度に0.2秒ほどwait時間が発生しており、若干ストレスがありました。

https://github.com/jonmosco/kube-ps1



# 仕組み

以下のページをみればすぐわかりますが、kubectlが使用しているconfigファイルを読み込み、クラスタ名・Namespace名・ユーザ名を取得しています。
https://github.com/Sugi275/kube-prompt-bash/blob/master/kube-prompt-bash.sh

configファイルをparseしたいなと思いつつ、現状は grep や sed で取得しています。

環境依存っぽい気がしており、取得出来ない場合はすいません・・・。
気が向いたら改善していくかもしれません。
PHP5技術者認定初級取得備忘録

# 【前提】
RubySilver取得日に同時に取得したので記事を分けて備忘録に。
じゃあ行ってみましょう。

# 【本題】
[前提]
本人スペック:業務で少々javaったプチPG。web系へ転職活動中
試験結果：82/100 合格

公式サイト
https://www.phpexam.jp/summary/novice/

設問数：40問
試験時間：1時間
合格ライン：7割正解

出題範囲ははじめてのPHP5かららしいです。今知りました。

[勉強方法]
徹底攻略 PHP5技術者認定[初級]試験 問題集 [PJ0-100]対応 (ITプロ/ITエンジニアのための徹底攻略)
上記参考書で9割取れるようにする。
私はこれだけでいけましたが。自身の知識量にてはじめてのPHP５とかもばりばり読むようにしてください。

# 【後書き】
たまたま上記本黒本だけでさくっといけてしまったが、ちょっと足りない部分があって合格まで気が気ではなかったです、初めてのPHP5を１～２週くらい見れるなら見たほうがいいと思います。

この試験を受けてよかった事は深くはないがセキュリティ対策に少し触れ、DBアクセス周りに少し触れ、SQLに少し触れ、正規表現に少し触れ、ファイルに少し触れ、セッションクッキーに少し触れと幅広いのです。まさにTHEWEB系って感じ。巷ではPHPは言語的によろしくないと言われてたりしますが（私がちらっと調べた限りですが）入門としては凄くいいのでは？と感じました。DB接続もSQLも実務経験ないけどWEBアプリ作ったときとかVBAでアクセス触ったときとかでいじっていたので特に勉強するまでもなく読めたのが嬉しかったですね。上級になると流石に勉強時間がどきゃんとあがってしまうので少し様子見ですが、余裕ある時かじりたいですね。
自動化ツールの比較

最近どこの会社でも「働き方改革」を目的としてRPAの導入が加速しており、多くのコンサル会社やSIerがRPAツールを使ったソフトウェアロボットの取り組むようになってきてます。

そんな中、個人的にはもっと注目を浴びても良い気がしているのが、「AutoIt」「AutoHotkey」「UWSC」といった(ほぼ)無料で使える「自動化ツール(マクロツール)」です。

RPAツールのように使いやすいデザイナーツールや、遠隔から実行する仕組み等はないものの、

- RPAツールを使うまでも無い単純な作業を特定のマシン上で動かす(RPAツールのライセンス節約)
- RPAツールだけではちょっと機能的に足りない部分を補完する

上記のような用途では非常に有効なツールだと思っています。(特にエンドユーザでロボット開発をしない場合)

今回は、この「自動化ツール(マクロツール)」について簡単に(主観的に)比較してみました。

# 比較したツール

少し調査してみたところ、国内で使われているツールとしては、ほぼ以下の3つに集約される感じだったので、今回はこの3つに絞って比較してみました

1) AutoIt
2) AutoHotkey
3) UWSC

## AutoItについて

- BASICに似た構文で簡単にWindowsGUIの自動操作が可能となるWindows用マクロツール
- 簡単なGUIアプリケーションで「AutoIt」だけで開発できる
- スクリプトはインタプリタ形式でも実行形式(EXE)でも動作可能で、実行形式(EXE)はAutoItがインストールされていない環境でも動作する
- ドキュメントもヘルプ(英語)が充実している
- 付属の「AutoItX」というDLLで他言語から「AutoIt」の関数を呼び出せる
- 歴史の長いであるにも関わらずフォーラムも活発でライブラリも充実しており、現在も頻繁にメンテナンスされている
- フリーウェアであり、過去にGPLでソース公開していたが、現在はソース公開はしてない

## AutoHotkeyについて

- 基本的に「AutoIt」をベースに開発されたそうなので特長は「AutoIt」とほとんど同じ
- 最大の特徴としてはスクリプトでショートカットキーを定義することが出来、定義したショートカットで任意の実行ファイルを起動することができる
- GPLでソース公開されている

## UWSCについて

- BASICライクな言語で書くところはAutoItやAutoHotkeyとほとんど同じ
- 最大の特徴としては画像認識(画像のボタンを特定)は認識精度も高く、
- pro版はシェアウェア(6500円ぐらい)
- ソース公開はしてない
- 最近公式サイトにアクセスできない等が発生していたり、雲行きがあやしくなってきている(シェアウェアのpro版が買えない模様)

# 機能比較表

機能比較表を作成してみました。一応簡易な動作検証はしてみましたが、あまり時間かけて検証してません。

| 機能名 | AutoIt | AutoHotkey | UWSC | 備考 |
|:---:|:---:|:---:|:---:|:---:|
| Windowアプリ操作 | ○ | ○ | ○ ||
| Web操作  | ○ | ○ | ○ ||
| Excel操作  | ○ | ○ | ○(pro版のみ、未検証) ||
| 録画機能  | ○(うまく動作せず) | ○(うまく動作せず) | ○ ||

# 個人的順位

どのソフトウェアも(ほぼ)無償で使えるツールとしては機能的にすばらしく甲乙付け難いのですが、

1位: AutoIt
2位: AutoHotkey
3位: UWSC

自分は機能よりもアジャイルに(カジュアルに)使えることを最も重視しているため、学習コストが低い「AutoIt」を1位としました。もし、機能重視ということであれば「AutoHotkey」が1位になるのではないかと思います。
~~それと、「UWSC」は学習コストも低く、画像認識機能は優秀なのですが、大変残念な事に現在公式サイトがクローズ状態となってしまっており(2018/5現在)、現時点においては業務で使用するには不安がある感じです。~~

ということで、次回は「AutoIt」についてもう少し詳しく書こうと思います。

追記: 2021/2/15
情報掲載が大分遅くなってしまいましたが、「UWSC」の作者である"umiumiさん"は亡くなられているそうです。大変優秀な製品だっただけに非常に残念です。umiumiさんのご冥福を心よりお祈りします。
参考サイト: http://itot.blog.jp/archives/21432032.html
RubySilver取得備忘録

# 【前置き】
PHPと共に取得してきたので分けて記事にまとめます。
件名通り取得してきました。正式名称はRuby Association Certified Ruby Programmer Silver version 2.1。資格なんて役に立たないと思ってるが実務経験がないとどこまで求められるかわからない＋知識を定量的に示せないということで少し方針転換して取得を狙っていっています。じゃあ行きましょう。

# 【本題】
[前提]
本人スペック：実務少々でjavaったプチPG、rubyは未経験だがSESから転職目指す。
結果：92/100　合格
勉強時間：40時間くらいでは・・・？

公式サイトより
http://www.ruby.or.jp/ja/certification/examination/

|試験時間 |90 分 |
|:-----------------|------------------:|
|試験方法 |コンピュータ試験（CBT：Computer Based Testing） |
|問題数（方式） |50 問（選択式）| 
|合格ライン |75 %| 
|対象バージョン |Ruby2.1.x|

結構危ないなぁと思った所なぜかJAVAより点数はあって腑に落ちない・・・

[勉強方法]
以前備忘録にも載せたが以下通り。

模擬試験（50問＋α）
https://diver.diveintocode.jp/exam#exam-list
ミニツク（60問）
http://www.minituku.net/
公式模擬問題（50問）
https://gist.github.com/sean2121/945035ef2341f0c39bf40762cd8531e0
Ruby公式資格教科書 Ruby技術者認定試験Silver/Gold対応
演習問題30問/模擬試験50問

上記を9割取れていれば行けるんじゃないかと、
さらに私はもうひとつ面白いのを見つけたのでやってみました。

とある資格の勉強会～Ruby技術者認定試験編～
https://play.google.com/store/apps/details?id=jp.ne.poropi.quizapp.ruby&hl=en_US

上記アプリですが、参考書とかで見たような問題がいやらしい感じに改変されており、Silver試験よりクッソ難しいです。ですがアプリで100点取れるのはもう合格出来たと思っていい、なんならゴールドまでぶっとばしてもいい。

途中からメモるのを止めたが覚えないといけないだろう部分をメモったりしてます。
最終的には体が覚えた感じ。

簡易メモ
Map=collect←ブロックを繰り返し新しい配列を返す
find=detect←detectは要素に対してブロックを評価した値が真になった最初の要素を返す
find_all=select←ブロックを繰り返し真になった値の配列を返す
clear←空の配列、ハッシュを返す
chomp⇒文字列末尾の改行文字を削除する（\r \r\n \n）空文字指定した場合全ての改行コードを削除する
chop⇒文字列末尾文字を削除するメソッド
☆IO⇒rewind、seek、gets、read、readline
配列の演算
& ⇒ 両方含まれる
| ⇒ 一つでも含まれているもの
- ⇒ 左を右で引いたもの
+ ⇒ 自身同士を足す
<< ⇒ 配列を追加する
deleteは引数の各文字を削除して行く為ご注意
p cc.has_key?('nz')
p cc.key?('nz')
p cc.include?('nz')
p cc.member?('nz')
gets=readlineは1行読み込んで文字列を返す。getsはnil、readlineはEOF
"r" 読み込みモード
"w" 書き込みモード。ファイルが存在していればファイルを空にする。
"a" 書き込みモード。ファイルが存在していれば、ファイルの末尾から追記する。
"r+" 読み書き両用モード。ファイルの先頭から読み書きを行う。
"w+" 読み書き両用モード。ファイルが存在していればファイルを空にする。
"a+" 読み書き両用モード。ファイルの末尾から読み書きを行う。
split＋joinは実務的にもよく使いそう
?がついてるメソッドはtrueかfalseを返す。equal?の場合同じ参照かを判定する為注意が必要
inject⇒前ブロックの戻り値を渡す
atime(access time: 最終アクセス時間)はファイルを読み込んだ時に設定されます。
ctime(change time: 最終変更時間)はファイルのメタデータを変更した時、例えばアクセス許可、著作者、ファイル名を変更する時に設定されます。ctimeはファイルの内容を変更された時、mtimeと同じようにさらに変更されます。
mtime(modification time: 最終更新時間)はファイルに含むデータが変更された時に設定され、つまりデータの期間を表します。
IO#readlineメソッド, IO#readlinesメソッド, IO#getメソッドはすべて任意の引数の行区切り文字を受け取ります。
IO#write（1行）、puts（改行追加）、print（ほぼ一行）の違いについて
Filesplitはディレクトリ部分とファイル部分に分割し、末尾からスラッシュを取り除く
odd（奇数）even（偶数）

調べる限り簡単な方の資格に当たるので取得しようとキメて一週間勉強すれば行けるんじゃないかなぁと思います。実務経験ある方は土曜勉強して日曜受けるとかコンビニ行く感覚で行けるんじゃないかな・・・

# 【後書き】
次はrailsとってrubyセット基礎知識は大丈夫な感じに持って行きたいが結構難しいっぽいんですよねぇ。Silverで20～30%で黒本もあまりマッチしてなくて完全に実務経験者有利な感じ。bronzeで行けそうならさくっと取りに行こうと思います。転職するにしてもポリテク行くにしても仕事辞めたりとか手続き調べないとなのでハロワに訪問行く必要ありそうです。
Google Cloud DataStore 小ネタ

# Google Cloud DataStore 小ネタ

* Index されていないプロパティでのフィルターは出来ない
    * filter をかけてもヒット件数が 0 件になる

## [Objectify](https://github.com/objectify/objectify) 小ネタ

* 標準だと index は作られない
    * [Defining Indexes](https://github.com/objectify/objectify/wiki/Queries#defining-indexes)
    * 明示的に <span>@</span>Index アノテーションを付けてあげないと filter を一切利用できない
間違えて行ったmigrateを取り消す方法

Rails触っているときに間違えてmigrateをしてしまいました。
そんな時どうしたら良いか？
今回学んだことを記録しておきます。

---
- 今回間違えてしてしまったこと

blogsテーブルにtitleカラムを追加したかったので、titleカラムを追加するmigrationファイルを作成したが、カラムを追加する記述を間違えてnameにしてしまった。

```
$ rails g migration add_title_to_blogs
$ rails db:migrate
```

```ruby:migration_2
def change
  add_cloumn :blogs, :name, :string
end
```

---

- どう改善したか？

migrateしてすぐ気がついたので、今回はこのようなコマンドで改善した。
まず現在のmigrationがどこまで行われているか以下のコマンドで、スキーマのバージョンを調べる。

```
$ rails db:version
```
そしたら現在の最新のmigrationファイルが表示されるはず。
こんな感じで↓

```
Current version: migration_2（migrationファイル名）
```

今回のmigrateをなかったことにしたいので、rollbackを使ってスキーマを一つ前の状態に戻す。

```
$ rails db:rollback
```

これでもう一度以下コマンドでスキーマのバージョンを調べる。

```
$ rails db:version
```

そうすると一つ前のmigrationファイル名が表示されるはず。そしたらrollback成功！

```
Current version: migration_1（migrationファイル名）
```

最後に、間違えてmigrateしてしまったmigrationファイル(migration_2)の記述を正しく書き換えて、もう一度migrateして終了。

```
$ rails db:migrate
```