OmniAICreator/Qiita-1.07M huggingface dataset:
Post/Redirect/Get (PRG) パターン

# はじめに

最近、Flaskで個人用のWebアプリを開発していて、

***Post/Redirect/Get パターン***

というものを知ったのでメモ。

# Post/Redirect/Get (PRG) とは

一言で言うと、フォームデータの二重送信を防止する手法の一つです。

フォームデータをPOSTした後、リダイレクトせずに画面を表示し、ブラウザを再読み込みすると、もう一度POSTしようとしてしまいます。

しかし、POST後にリダイレクトして画面を表示するようにすれば、ブラウザを再読み込みしても送信されるのはGETリクエストなので、フォームデータの二重送信が防げるというものです。

もちろん、リダイレクトしなくてもこのような二重送信を防ぐ方法はありますが、その場合、ブラウザの再読み込み時に以下のようなダイアログが表示されてしまいます。

![dialog-only.png](https://qiita-image-store.s3.amazonaws.com/0/18659/62c950c5-483f-d175-8bd8-1d86e2da478c.png)

リダイレクトすればこのようなダイアログは表示されないため、ユーザビリティも良くなるわけですね。

# サンプルコード（リダイレクトなし）

せっかくなので、Flaskで簡単なサンプルを書いてみます。

フォームで name を送信し、次の画面で表示するというものです。

まずは、リダイレクトしない場合です。

```py3:app.py
from flask import Flask, render_template, request
app = Flask(__name__)


@app.route('/')
def index():
    return render_template('index.html')


@app.route('/post', methods=['POST'])
def post():
    name = request.form['name']
    return render_template('hello.html', name=name)

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

```jinja:templates/index.html
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>PRG Sample</title>
</head>
<body>
  <h1>What's your name?</h1>
  <form action="{{ url_for('post') }}" method="post">
    <input type="text" name='name' placeholder="name"/>
    <button type="submit">Submit</button>
  </form>
</body>
</html>
```

```jinja:templates/hello.html
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>PRG Sample</title>
</head>
<body>
  <h1>Hello, {{ name }} !</h1>
</body>
</html>
```

実行してみます。

```shell-session
$ python app.py
 * Running on http://127.0.0.1:5000/
```

ブラウザでアクセスし、名前を入力して画面遷移します。

![index.png](https://qiita-image-store.s3.amazonaws.com/0/18659/de0c9678-3c9a-f6ff-367f-6b0f7de2ff1e.png)
![hello.png](https://qiita-image-store.s3.amazonaws.com/0/18659/42d38015-66fd-2c38-8409-ab989c585fb1.png)

ここまでは問題ありませんが、ブラウザの再読み込みを行うと、フォームを再送信してもよいかどうかの確認ダイアログが表示されてしまいました。

![dialog.png](https://qiita-image-store.s3.amazonaws.com/0/18659/c6f1eccf-6a13-8132-88e6-9cd3b939c352.png)

# サンプルコード（リダイレクトあり）

次に、リダイレクトを行う場合です。

```py3:app.py
from flask import Flask, render_template, request, session, redirect, url_for

app = Flask(__name__)
app.secret_key = 'seacret_key'


@app.route('/')
def index():
    return render_template('index.html')


@app.route('/post', methods=['POST'])
def post():
    session['name'] = request.form['name']
    return redirect(url_for('hello'))


@app.route('/hello')
def hello():
    if 'name' not in session:
        return redirect(url_for('index'))
    return render_template('hello.html', name=session['name'])

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

`templates/index.html` と `templates/hello.html` は同じです。

これでフォームを送信後、ブラウザの再読み込みをしても、ダイアログは表示されなくなります。

リクエスト内容を確認しても、GETリクエストであることが確認できます。

# 終わりに

結構昔からある手法のようで、私が知ったのが今更といった感じですね…。

とはいえ、現在私が利用している某サービスで、ログイン後にブラウザの再読み込みをしてみたら、フォームを再送信しようとしているものがあったので、知っておいたほうが良い手法だと思いました。

# 参考

* [Post/Redirect/Get](http://en.wikipedia.org/wiki/Post/Redirect/Get)
* [第28回　フォーム送信とブラウザ・ボタンと使い勝手（前編）～PRGパターンをご存じですか](http://itpro.nikkeibp.co.jp/article/COLUMN/20071112/286994/)
[blackbird-redis] blackbird で Redis をモニタリングする

# blackbird Redis plugin

この plugin では Redis から様々な情報を取得し、backend にデータを送信します
現在のところ、下記の情報をモニタリングすることができます。

* `INFO` の値
* `CONFIG GET` の `maxmemory` 及び `maxclients`
* 特定 key に対する responce time (`GET` / `SET`)

動作確認は 2.6.x と 2.8.x で行ってます

# Install

## blackbird 本体

[こちら](http://qiita.com/makocchi/items/9166016b2ad4cc43e83f)を参考に install してください

## Install Redis plugin

setup.py で入れる方法と rpm で入れる方法があります

### setup.py で install

```bash
git clone https://github.com/Vagrants/blackbird-redis.git
cd blackbird-redis
python setup.py install
```

### rpm で install

```bash
yum install blackbird-redis --enablerepo=blackbird
```

# plugin の設定をする

config は `/etc/blackbird/conf.d/redis.cfg` にあります

```ini:/etc/blackbird/conf.d/redis.cfg
[redis]
module = redis

# if you set 'requirepass' in redis.conf, please set auth.
#
#auth = password

# for response time check
# if you do not want to check, please comment out.
response_check_key = __zabbix_check

# default values
#
#host = 127.0.0.1
#port = 6379
#db = 0
```

`redis.conf` で `requirepass` の設定をしている場合は `auth = password` を設定してください
`response_check_key` は response time 計測時に `GET` / `SET` する時の key の名前になります

設定が終わったら `blackbird` を再起動させます

```bash
sudo /etc/init.d/blackbird restart
```

# Zabbix 上でデータが入ってきているか確認する

Zabbix の Template は Zabbix 2.2 から export したものが [github の repository](https://github.com/Vagrants/blackbird-redis/tree/master/templates)にあります
Zabbix に import して対象のサーバーに適用させて下さい

しかしこの Template、**Trigger の依存エラーで 2.4 系だと import できない問題があります**
import 時に Trigger の部分の checkbox を外せば import できるんですが・・

**Zabbix 上の host 名と blackbird が起動しているサーバーの host 名が違う場合は `/etc/blackbird/conf.d/redis.cfg` 上で hostname を設定してあげる必要があります**
Zabbix 上と合わせてください

```ini:/etc/blackbird/conf.d/redis.cfg
hostname = your_static_hostname
```

また、監視間隔も変更できます (デフォルトでは 60 秒、LLD は 600 秒)

```ini:/etc/blackbird/conf.d/redis.cfg
interval = 30
lld_interval = 300
```

# Response Time について

この plugin では `GET` / `SET` の response time を計測し、Zabbix 上では `Performance - Get response time` と `Performance - Set response time` としてデータを収集します
**この response time ですが、純粋な response time ではありません**
実際には内部で python でいろいろ処理する時間も含まれています
ですのであくまで**参考程度**にお考えください
(今後まじめに作るかも)

# LLD について

LLD では `INFO` の Keyspace の情報を Discovery します

```
# Keyspace
db0:keys=123,expires=0,avg_ttl=9
db1:keys=2345,expires=456,avg_ttl=99
db2:keys=34567,expires=789,avg_ttl=999
...
```

# その他

* 一応 1 つの Template で mode が `standalone` `slave` `sentinel` をカバーできるようにはしてありますが将来的には分けるかもしれません
SwiftのWebAPIのInterfaceのコードを自動生成する


はじめに
======

[構造を定義したJSONを安全に扱うSwiftコードを自動生成する](http://qiita.com/mokemokechicken/items/30d4a0296d5ac41329df) の続きです。
今度はWebAPI用のコードをお手軽に生成することを考えてみます。

任意のHTTP Requestをお手軽に実行する優れたLibraryは本当にたくさんあって、どれにするか迷うくらいです。
ただ、通常のサービスや自分で作っているWebAPIの場合はInterfaceが事前に決まっているにもかかわらず、
リクエストパラメータやレスポンスデータを処理する部分は仕様書を睨みながらコードを書き起こす必要があります。
可能ならばこの辺を省力化したり、型安全の恩恵を受けたいと思うところです。

WebAPI Interfaceの自動生成
=========

Qiita API V2 の一部を例にやってみます。
https://qiita.com/api/v2/docs#get-apiv2items の辺りです。

APIの定義
-------
Qiita API の中から以下の４つを取り出して定義してみます。

* GET /api/v2/items
* POST /api/v2/items
* GET /api/v2/items/:id
* PATCH /api/v2/items/:id

定義はこんな感じになります。

```qiita_api.yml
api_prefix: QiitaAPI
entity_prefix: Qiita

api:
  ListItem:
    get: items
    params:
      page?: Int
      per_page?: Int
    response: [Item]

  GetItem:
    get: items/{id}
    response: Item

  PostItem:
    post: items
    body:
      body: String
      coediting: Bool
      gist?: Bool
      private: Bool
      tags: [Tag]
      title: String
      tweet?: Bool

  PatchItem:
    patch: items/{id}
    body:
      body: String
      coediting: Bool
      private: Bool
      tags: [Tag]
      title: String

entity:
  Tag:
    name: String
    versions: [String]

  Item:
    body: String
    coediting: Bool
    created_at: String
    id: String
    private?: Bool
    tags: [Tag]
    title: String
    updated_at: String
    url: String
    user: User

  User:
    description?: String
    facebook_id?: String
    followees_count: Int
    followers_count: Int
    github_login_name?: String
    id: String
    items_count: Int
    linkedin_id?: String
    location?: String
    name?: String
    organization?: String
    profile_image_url?: String
    twitter_screen_name?: String
    website_url?: String
```

Swiftコードの生成
========

こんな感じで生成します。

```sh
git clone https://github.com/mokemokechicken/ObjectJsonMapperGenerator.git
cd ObjectJsonMapperGenerator
ruby bin/make_ojm.rb -l swift -t api -c qiita_api.yml > qiita_api.swift 
```

今のところ出力結果はこうなります。
https://gist.github.com/mokemokechicken/ec01464d4e48b04ebc15

使ってみる
---------

生成したコードをプロジェクトに追加しておくと、以下の様な感じで使うことができます。

```swift:main.swift
import Foundation

private let config = QiitaAPIConfig(baseURL: NSURL(string: "http://qiita.com/api/v2/")!)
private let apiFactory = QiitaAPIFactory(config: config)

apiFactory.createListItem().setup(perPage: 3).call { res, items in
    items?.map { item in
        println("\(item.user.id): \(item.title)")
    }
    return
}

CFRunLoopRun()
```

実行結果

```
mikoski01: Composerを使ってCakePHP環境を楽々構築！(Windows)
mutz0623: CentOSのデフォルトのApacheで、デフォルトのRubyでmod_mrubyをビルド
gam0022: Rails4のアプリをHerokuで動かす
```

さいごに
=======

こういう風にやると、YAMLで書いた定義がAPI仕様書みたいになるのでなかなか便利に使えますね。
YAMLで記述するとaliasが使える(ある部分を`&`で定義して、`*`や`<<: *`で参照できる)のですが、
これは意外と使える！と思っていたりします(Railsみていて最近気がついた)。

まあ、まだまだ課題はありますが、色々なAPIで試しつつ潰していきたいと思います。
ファイルアップロード、ダウンロードのプログレスバーとか。。。まあ、それくらいなら書いても大したことないけど。。

後はこれを使うModelを似たような感じでひな形が作れれば良いんだけどなぁと思っていますが、
Modelはひな形をベースにしてどんどんコードを追加していく感じになるので、
コード生成という観点ではどういうアプローチがいいのか難しいところです。

ある程度Swift版ができたらJava版も作りたいです。
コードジェネレーターを作るのも少しずつ慣れてきました。何事も練習ですね。
それにしてもコードを全部書き直したい病がしばしば発症するなー
Streamでソートした結果をSetやMapで取得したいとき

# Collectors.toSet()は順序が保証されない

StreamAPIで結果をSetで取得したいときはCollectorsのtoSet()を使用するが、toSet()は結果の順序が保証されない。

ソースを見ると、toSet()はHashSetのインスタンスを生成している。

```java:Collectors.java
    public static <T>
    Collector<T, ?, Set<T>> toSet() {
        return new CollectorImpl<>((Supplier<Set<T>>) HashSet::new, Set::add,
                                   (left, right) -> { left.addAll(right); return left; },
                                   CH_UNORDERED_ID);
    }
```

その為、Streamのsorted()でソートしても結果を取得する時にtoSet()を使うと順序がおかしくなってしまう。

```java:toSet()では結果の順序がおかしくなる
        Set<Integer> set = Stream.of(30, 20, 50, 10, 40)
                .sorted()
                .peek(x -> System.out.print(x + " ")) // => 10 20 30 40 50
                .collect(Collectors.toSet());
        
        System.out.println(set); // => [50, 20, 40, 10, 30]
```

# ソート結果をSetで取得する

ソート結果をSetで取得したい時は、~~collect()~~`Collectors.toCollection()`でLinkedHashSetを指定すれば良い。

```java:ソート結果をLinkedHashSetで取得
        Set<Integer> set = Stream.of(30, 20, 50, 10, 40)
                .sorted()
                //.collect(LinkedHashSet::new, Set::add, Set::addAll);
                .collect(Collectors.toCollection(LinkedHashSet::new));

        System.out.println(set); // => [10, 20, 30, 40, 50]        
```

あるいは、`Stream.sorted()`を使用せずに、~~`collect()`で~~`Collectors.toCollection()`でTreeSet(SortedSetの実装クラス)を指定する。

```java:TreeSetで結果を取得
            Set<Integer> set = Stream.of(30, 20, 50, 10, 40)
                    //.collect(TreeSet::new, Set::add, Set::addAll);
                    .collect(Collectors.toCollection(TreeSet::new));

        System.out.println(set); // => [10, 20, 30, 40, 50]        
```

# ソート結果をMapで取得する

Mapの場合も引数が少ないほうのtoMap()では順序が保証されない。

```java:toMap()でソート結果がおかしくなる
        Map<Integer, String> map = Stream.of(30, 20, 50, 10, 40)
                .sorted()
                .peek(x -> System.out.print(x + " ")) // => 10 20 30 40 50
                .collect(Collectors.toMap(Function.identity(), String::valueOf));
        System.out.println(map); // => {50=50, 20=20, 40=40, 10=10, 30=30}
```

ソート結果をMapで取得するには、引数でmapSupplierを指定するtoMap()を使用してLinkedHashMapかTreeMapを指定すれば良い。


```java:toMap()でLinkedHashMapを指定する
        Map<Integer, String> map = Stream.of(30, 20, 50, 10, 40)
                .sorted()
                .collect(Collectors.toMap(
                        Function.identity(),
                        String::valueOf,
                        (u, v) -> v,
                        LinkedHashMap::new
                ));
        System.out.println(map); // => {10=10, 20=20, 30=30, 40=40, 50=50
```
```java:toMap()でTreeMapを指定する
        Map<Integer, String> map = Stream.of(30, 20, 50, 10, 40)
                .collect(Collectors.toMap(
                        Function.identity(),
                        String::valueOf,
                        (u, v) -> v,
                        TreeMap::new
                ));
        System.out.println(map); // => {10=10, 20=20, 30=30, 40=40, 50=50
```
Composerで CakePHPのプラグインをインストールする際に、インストール先フォルダを指定する


Composer で、CakePHP とそのプラグインをインストールするとき。

```json
{
    "require": {
       "cakephp/cakephp": "~2.5",
       "cakephp/debug_kit": "2.*"
    }
}
```

composer.json に上記のように書いて `composer install` すると、フォルダ構成がこんな感じになる。

```
- vendor
  - cakephp
    - cakephp
- Plugin
  - DebugKit
```

デフォルトでは CakePHP のプラグインがルートの `Plugin` というフォルダに入るのだけど、このフォルダを任意で指定したい場合、どんな書き方をすればいいか調べた。

---

Composerのサイトの FAQ にそれっぽい記述があり、

> [How do I install a package to a custom path for my framework?](https://getcomposer.org/doc/faqs/how-do-i-install-a-package-to-a-custom-path-for-my-framework.md)

`extra.installer-paths` の部分に書くことで、typeごとにプラグインのインストール先フォルダを指定できる。

たとえば composer.json にこう書いて、

```json
{
    "require": {
       "cakephp/cakephp": "~2.5",
       "cakephp/debug_kit": "2.*"
    },
    "extra": {
        "installer-paths": {
            "cakeapp/Plugin/{$name}": ["type:cakephp-plugin"]
        }
    }
}
```

`type:cakephp-plugin` のものは `cakeapp/Plugin/プラグイン名` というフォルダに保存されるように設定。

上記を `composer install` すると、こんな構成になる。

```
- vendor
  - cakephp
    - cakephp
- cakeapp
  - Plugin
    - DebugKit
```


というかんじです。
【AndroidStudio：もっとお手軽☆パッケージ名変更】build.gradleから簡単に！

何かをやるたびに、オチャメな緑の妖精さん☆に籠絡されて毎晩参っているワタシです。

パッケージ名変更の記事を書いたばかりですが、
AndroidStudioだと実はメチャクチャ楽に変更できることがわかりました。
※Eclipseは導入していないのでわかりかねます

![app_build_gradle_-__app__-_ICF_inputter_-____AndroidStudioProjects_ICFinputter__-_Android_Studio__Beta__0_8_14.jpg](https://qiita-image-store.s3.amazonaws.com/0/58253/0975de5c-6321-1e1a-32b5-fc510df0b1a5.jpeg)

buile.gradleのapplicationIdを変更して、右上のSync nowを忘れずに押すだけ！

…これで今宵も妖精さんとガップリと四つに組めそうdeath！！

…はやくちゃんとマトモなスタートを切りたいよう･ﾟ･(つД｀)･ﾟ･
Blenderのウィンドウシステム

# Default Screen
![blender_w_system.png](https://qiita-image-store.s3.amazonaws.com/0/43250/e9e332a3-72c7-ee00-1420-6e8f626dd80b.png)

Blenderを初めて立ち上げた時、上図の画面を目にすることになると思います。たくさんのボタンやメニューにめまいを覚える瞬間ですが、まず基本となる画面の構成を理解すれば混乱は収まります。
基本は単純です。Blenderの画面は複数のウィンドウから構成されています。上図は５つのウィンドウで構成されています。それぞれのウィンドウは形や内容こそ色々ですが、すべて等しくウィンドウです。（Blenderの公式マニュアルでWindowと記述されているので、それに習いますが、「パネル」と読み替えると理解しやすいと思います）
ここからが他のソフトとは違うところなんですが、この５つのウィンドウは内容を簡単に変更することが可能です。各ウィンドウの左上または左下にアイコン（赤丸）がありますが、これがウィンドウ・タイプ・セレクタ−（またはエディター・タイプ・セレクタ）と呼ばれるメニューで、ここで選択することによって内容が変わります。デフォルトでは

1. Info
1. 3D View
1. Timeline
1. Outliner
1. Properties

となっていますが、それぞれ自由に切り替えながら作業を行います。

# Window Type
ウィンドウには以下の種類があります。

+ 3D View　一番利用する。シーン全体を3Dで表示
+ Properties Editor オブジェクトのプロパティを操作
+ Outliner オブジェクトをツリー形式で表示・操作
+ Node Editor ノードを繋げることによりマテリアル操作やコンポジティングを行う。
+ File Browser ファイルを開く、保存する
+ Image/UV Editor イメージやUVなどのマップを操作
+ Info Window 主にメニューなどを表示
+ User Preferences オプション設定
+ Timeline アニメーションのタイムライン操作
+ Graph Editor アニメーションのキーを操作
+ Dope Sheet アニメーションにおけるシーン内のアクションを操作
+ NLA Editor アニメーションのアクション構成を操作
+ Video Sequence Editor ビデオ編集
+ Text Editor テキストエディター。メモやPythonスクリプトを記述
+ Logic Editor ゲームの作成
+ Console Pythonプログラムを直接起動する

（私が良く使う順番に並べています。使ったことの無いタイプも多数あり）

# Screen Layout
ウィンドウのタイプの変更に加えて、サイズを変えたり隣のウィンドウと結合させたりすることで自分の作業に適したレイアウトを作って作業を行うわけですが、あらかじめ作業別の画面レイアウトが用意されているので、最初はここから選んで作業を行うのが良いと思います。
（Ctrlキーを押しながら左右の矢印キーを押してみてください）

# おわりに
さすがに毎日はキツイのですが、もう少し書きたいと思っています。
CentOSのデフォルトのApacheで、デフォルトのRubyでmod_mrubyをビルド

#はじめに
あちこち調べて出てくる情報をつなぎ合わせればどうにかなるけど、そのままトレースできる手順が欲しかった。

##環境
```
# cat /etc/redhat-release
CentOS release 6.6 (Final)
```



#CentOSのRubyが古いので http://blog.hifumi.info/2014/12/04/ngx_mruby-memcached-in-rhel/ を参考に、mod_mrubyビルド用にruby2.1を導入

```
# cd /usr/local/src
# git clone https://github.com/sstephenson/ruby-build.git
# cd /usr/local/src/ruby-build
# ./install.sh
# ruby-build 2.1.5 /usr/local/ruby21
# ll /usr/local/ruby21
# export PATH=/usr/local/ruby21/bin:$PATH
```

#http://qiita.com/hkusu/items/ca8622c83b0bfc2cac72 を参考にmod_mrubyをビルド&インストール

```
# yum install httpd-devel
# whereis apxs
# whereis apachectl
# git clone git://github.com/matsumoto-r/mod_mruby.git
# cd mod_mruby/

# cp -p build_config.rb build_config.rb.org
# vim build_config.rb
# diff build_config.rb.org build_config.rb
27c27
<   conf.gem :github => 'matsumoto-r/mruby-redis'
---
>   #conf.gem :github => 'matsumoto-r/mruby-redis'
#
# APXS_PATH_ENV='--with-apxs=/usr/sbin/apxs' APACHECTL_PATH_ENV='--with-apachectl=/usr/sbin/apachectl' sh build.sh
# make install
# apachectl configtest
# service httpd restart
# mkdir /etc/httpd/mruby

# cat /etc/httpd/mruby/test.rb
Apache.echo "Hello World"
# cat /etc/httpd/conf.d/mruby.conf
<Location /mruby>
    mrubyHandlerMiddle /etc/httpd/mruby/test.rb
</Location>

# service httpd restart
```

#ブラウザで ```http://[IPアドレス]/mruby``` にアクセス
```"Hello World"```って表示されればおk
githubとgoogleを利用して世界征服の意図を調べる

## php による世界制服の崩壊
少し前に、php のworld dominationが取り消されたらしい、という話をききました。

その時はなんとも思っていなかったのですが、ちょうどblameの話に良さそうだ、と思い立ったので、そのコードがいつ入ったのかを調べてみようと思います。

# 修正されたコミットの検索
1. git でコミットをなかったことにするといったら `revert` でしょ！ということで、とりあえず、`php world domination revert`あたりで[ぐぐります](https://www.google.co.jp/search?q=php+world+domination+revert&oq=php+world+domination+revert&aqs=chrome..69i57.505j0j9&sourceid=chrome&es_sm=122&ie=UTF-8)

2. それっぽいのが見つかりました。
[[PHP-INTERNALS] Huge breach of PHP policy regarding World Domination](http://grokbase.com/t/php/php-internals/128ptn5hm0/huge-breach-of-php-policy-regarding-world-domination)

3. 嬉しい事に修正コミットへのリンクが貼られているのでとんでみます
https://github.com/php/php-src/commit/a90170e6f803f283d6c8e4e8d6b7bd8b7bd011a4

4. `NEWS` ファイルから `world domination` が削除されているのが確認できました。
![revert_world_domination.PNG](https://qiita-image-store.s3.amazonaws.com/0/18789/995dd815-4ff6-9178-341b-6181d99f2776.png)

5. 削除される前の状態で色々調べたいので、この修正が入る前のコミットに移動します(parent [596e855 をクリック](https://github.com/php/php-src/commit/596e855feb6855c236552c792d45c6259dcee406)する)
![parent_of_world_domination.PNG](https://qiita-image-store.s3.amazonaws.com/0/18789/fc691faa-476d-712f-07d7-68fcbcee60d9.png)

6. このコミット(596e855)の時点でのコードがみたいので [Brouse code](https://github.com/php/php-src/tree/596e855feb6855c236552c792d45c6259dcee406)を押します
![brouse_code.PNG](https://qiita-image-store.s3.amazonaws.com/0/18789/663b302f-c6d3-dd2b-603d-c31804e86f02.png)

7. [596e855 時点のrootフォルダ](https://github.com/php/php-src/tree/596e855feb6855c236552c792d45c6259dcee406)に `NEWS` ファイルがあることが確認できるのでそれを[クリック](https://github.com/php/php-src/blob/596e855feb6855c236552c792d45c6259dcee406/NEWS)します

8. どの行が、どのコミットで入ったのかを調べるために、[blameをクリック](https://github.com/php/php-src/blame/596e855feb6855c236552c792d45c6259dcee406/NEWS)します
![blame_world_domination.PNG](https://qiita-image-store.s3.amazonaws.com/0/18789/031291dc-6337-b78e-9a7f-0f5867c89e89.png)

9. `world domination` でページを検索し、`c500bd3` というコミットで入ったことが確認できました
![world_domination_commit.PNG](https://qiita-image-store.s3.amazonaws.com/0/18789/1d77f5cf-e7df-0865-1019-e572351ef698.png)

10. だれが入れたのか？を知りたいと思った人は、ここで調査を終了すると、通常の業務においても人間関係を壊さなくてすむので、この先には進まずに調査を終了することをおすすめします。

11. どんな意図で入ったのか、入ってしまったのか？を知りたいと思った人は、`c500bd3` をクリックし、今後に活かすといいかと思います。

### まとめ
+ blameは`誰が？`ではなく、`なぜ？`を知るために使おう
+ github すごい
+ google すごい
    + どのタイミングで修正のコミットが入ったのかを調べるのが一番大変かと思っていたのですが、ぐぐったら一発でした。
これだけ強大なgoogle帝国の力を見せつけられては、世界征服の断念もやむなしと感じました。
MySQLテスト

# 前書き

MySQLを触るのが久しぶりだったのとかで、ちょっと色々実験がてらメモ。

# とりあえずディレクトリ移動

```
$ mkdir ~/mysql-test
$ cd ~/mysql-test/
```

## データベース作成

```
$ echo CREATE DATABASe test1 > create_test1.sql

$ mysql -u root -p < create_test1.sql
Enter password:
```

特に結果などなく終了。

## データベース一覧

```
$ echo show databases > show_databases.sql

$ mysql -u root -p < show_databases.sql
Enter password:
Database
information_schema
mysql
performance_schema
test1
```

## テストテーブル作成

```
$ echo "CREATE TABLE test1.person (id int, name varchar(20), code int)" > create_table_test1.person.sql

$ mysql -u root -p < create_test1.person.sql
Enter password:
```

desc見てみる

```
$ mysql -u root -p -e "desc test1.person"
Enter password:
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | int(11)     | YES  |     | NULL    |       |
| name  | varchar(20) | YES  |     | NULL    |       |
| code  | int(11)     | YES  |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+
```

ちょっと逐一保存するのが面倒になったので直接。

## テストデータ作成

```
$ cat insert_test1.person.sql
INSERT INTO test1.person (id, name, code) VALUES (1, 'Tanaka', 10);
INSERT INTO test1.person (id, name, code) VALUES (2, 'Suzuki', 10);
INSERT INTO test1.person (id, name, code) VALUES (3, 'Sato', 11);

$ mysql -u root -p < insert_test1.person.sql
Enter password:


$ cat select_test1.person.sql
SELECT * FROM test1.person

$ mysql -u root -p < select_test1.person.sql
Enter password:
id	name	code
1	Tanaka	10
2	Suzuki	10
3	Sato	11
```

## テストデータ２作成

```
$ cat create_test2.sql
CREATE DATABASE test2;
CREATE TABLE test2.code (id int, name varchar(20));
INSERT INTO test2.code (id, name) VALUES (10, 'hoge');
INSERT INTO test2.code (id, name) VALUES (11, 'fuga');

$ mysql -u root -p < create_test2.sql
Enter password:

$ mysql -u root -p -e "SELECT * FROM test2.code"
Enter password:
+------+------+
| id   | name |
+------+------+
|   10 | hoge |
|   11 | fuga |
+------+------+
```

## 結合してSELECT

```
$ mysql -u root -p -e "SELECT * FROM test1.person p LEFT JOIN test2.code c ON p.code = c.id"
Enter password:
+------+--------+------+------+------+
| id   | name   | code | id   | name |
+------+--------+------+------+------+
|    1 | Tanaka |   10 |   10 | hoge |
|    2 | Suzuki |   10 |   10 | hoge |
|    3 | Sato   |   11 |   11 | fuga |
+------+--------+------+------+------+
```

# 実験終了

ほとんど自分用メモみたいなものですが、違うDB同士の結合とか気軽にできたっけ・・・とかちょっと試しておきたかったのでした。
ApacheアクセスログにPHPから任意の値を出力

2通りご紹介。
例として、"mykey"というキーの値を設定したいとする。

#①apache_noteを使う

##httpd.conf
例えば以下のようになっていたら

```
LogFormat "%h %l %u %t \"%r\" %>s %b" combined
CustomLog /var/log/httpd/foobar-access.log combined
```

こうする（"%{mykey}n"を追加）。

```
LogFormat "%h %l %u %t \"%r\" %>s %b %{mykey}n" combined
```

%{mykey}nのnの意味は以下参照。
> %{Foobar}n	他のモジュールからのメモ Foobar の内容
http://httpd.apache.org/docs/2.2/ja/mod/mod_log_config.html

でもどっちかというとLTSVにしてるときの方がラベル張れて使いやすい。
LTSVならこうする。

```
LogFormat "host:%h\t .... \tmy_key:%{mykey}n" combined
```

##php

以下実行

```php
apache_note("mykey", "hoge");
```

> apache_note — Apacheリクエスト記号(note)を取得/設定する
http://php.net/manual/ja/function.apache-note.php

#②HTTPヘッダを使う

①の方法でもいいんだけど、リバースプロキシのログでも値が見たいときとかに不便。
なのでHTTPヘッダを使う。

##httpd.conf
LTSVだとこう。

```
LogFormat "host:%h\t .... \tmy_key:%{Mykey}o" combined
```

%{Mykey}oのoの意味は以下参照。
> %{Foobar}o	応答の Foobar: ヘッダの内容
http://httpd.apache.org/docs/2.2/ja/mod/mod_log_config.html

##php
以下実行

```php
header('Mykey: hoge'); 
```

>header — 生の HTTP ヘッダを送信する
http://php.net/manual/ja/function.header.php
RubyのMechanizeで画像をPOSTする方法


### Rubyで画像をPOSTしたい

curl コマンドでもいいのですが、プログラムで画像をPOSTしたい時に、スクレイピングなどでも利用される [Mechanize gem](https://github.com/sparklemotion/mechanize) が使えるのでメモ。


```ruby:Gemfile

source 'https://rubygems.org'

gem 'mechanize'

```

### bundler でインストール
```
$ gem install bundler

```

```
$ bundle install --path vendor/bundle
```

```ruby:run.rb
require 'mechanize'

# 画像のpathを指定
IMAGE_PATH  = '/path/to/sample.png'
# POSTするURLを指定
REQUEST_URL = 'http://moss.moss/api/image/uploader'

agent = Mechanize.new

# 処理を10回繰り返す
10.times do |i|
  response = agent.post(REQUEST_URL, {
    text: 'mossmossmoss', # 一緒にPOSTしたいデータがある時
    image:  File.open(IMAGE_PATH),
  })

  # responseがある場合にprintされる
  print "#{i+1}: #{response.code} #{response.body}\n"
  
  # sleep なんかを入れないと攻撃になってしまう
  sleep 3
end

```
### スクリプトを走らせる

```
$ bundle exec ruby run.rb

```

#### responseがある場合の結果
```

1: {response.code} {response.body}
2: {response.code} {response.body}
3: {response.code} {response.body}
...
10: {response.code} {response.body}

```
sleepを入れないと、軽い攻撃になってしまう恐れがあるので注意が必要です。試す時はくれぐれも3秒待つ（sleep 3）などして優しくしてあげてください。
LinuxサーバでDOSられた時にさくっと確認する方法

**WEB(TCP:80番)の場合**
これで、80番にDOS食らってる時は、どこから来てるかの判断ができるはず( ｰ`дｰ´)ｷﾘｯ
あとは、ファイアウォールで止めるなりなんなり・・・よしなに。

```コマンド
netstat -nat | grep 80 | awk '{ print $5}' | cut -d ":" -f 1 | sort | uniq -c | sort -r
```

# 解説

##1(netstat -nat)
接続されているTCPコネクションの一覧を取得
##2(grep 80)
ポート80番のみとする
##3(awk '{ print $5}')
5行目を抜き出す
##4(cut -d ":" -f 1)
IPとポートを「：」にて切り分けます。
##5(sort )
sortで並び替えます
##6(uniq -c)
unic -cでユニークIPの件数を数えます
##7(sort -r)
件数の多い順に並び替え
MyBatisで2次キャッシュを全部消す

MyBatisにはローカルキャッシュ(SqlSession側にあるキャッシュ)と、2次キャッシュ(SqlSessionFactory側にあるキャッシュ)があります。

ローカルキャッシュは `sqlSession.clearCache()` でいいんですが、2次キャッシュの消し方がなかなか分からず、、我流で下記のようなコードを書きました。

```java
for (Cache cache : sqlSessionFactory.getConfiguration().getCaches()) {
    cache.clear();
}
```

まるっと全て消すコードになります。消す理由が自動テストのためだったので問題はないですが、そもそも有効・無効を切り替えられるように頑張った方がいいかなー。。
お手軽配列生成

Range を使用してお手軽に長めの配列を生成する方法を習得したので備忘録的にメモ。

(1..21).step
=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21]

オワリ




2014/12/14 追記
上記のやり方で得られるのはEnumrator なので、配列を得るなら下記のようにするのが良いと思われる。

(1..21).to_a
=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21]
Webフォントをassetとしてロード

## 時代はWebフォント！

[Google Fonts](http://www.google.com/fonts)とかもあるしね。

@YFukuyamaさんが[こちらの記事](http://qiita.com/YFukuyama/items/3a4a1d4b7b395cc32bd4)で書いていらっしゃるように環境依存を回避したいですし、ゲームの雰囲気に合ったフォントを使っていきたくもあります。

## tm.scene.LoadingSceneでフォントをロードしたい

フォントもアセットの一種なので、画像や音声と同じようにLoadingSceneを使ってロードしたいですね。

そこでこんなコードを書いてみました。

```js:webfont.js
tm.define("tm.asset.WebFont", {
    superClass: "tm.event.EventDispatcher",

    init: function(path, key) {
        this.superInit();

        var testElement = tm.dom.Element("body").create("span");
        testElement.style
            .set("color", "rgba(0, 0, 0, 0)")
            .set("fontSize", "40px");
        testElement.text = "QW@HhsXJ=/()";

        var before = testElement.element.offsetWidth;

        testElement.style
            .set("fontFamily", "'{0}', 'monospace'".format(key));

        var fontFaceStyleElement = tm.dom.Element("head").create("style");
        fontFaceStyleElement.text = "@font-face { font-family: '{0}'; src: url({1}) format('truetype'); }".format(key, path);

        var retryCount = 30;
        var checkLoadFont = function() {
            retryCount -= 1;
            if (testElement.element.offsetWidth !== before || retryCount === 0) {
                testElement.remove();
                this.flare("load");
            } else {
                setTimeout(checkLoadFont, 100);
            }
        }.bind(this);
        setTimeout(checkLoadFont, 100);
    },
});

tm.asset.Loader.register("ttf", function(path, key) {
    return tm.asset.WebFont(path, key);
});
```

以前[ここ](http://www.dev7.jp/?p=289)で書いた内容を、tm.asset.Loaderの形式に倣って書きなおしたものです。

これを使い、本体側のコードでこのように書いてみます。

```js:main.js
var loadingScene = tm.scene.LoadingScene({
    assets: {

        // フォントファイルIndieFlower.ttfをロード
        mainFont: "fonts/Indie_Flower/IndieFlower.ttf",

        // フォントファイルLobster-Regular.ttfをロード
        subFont: "fonts/Lobster/Lobster-Regular.ttf",

    },
    nextScene: MainScene,
});
```

これで行けるか……！？ と思いきや、**これだけではうまくいきません**。
tmlib.js本体にも少しだけ手を加える必要があります。

```js:tmlib.js
6801:-            var asset = tm.asset.Loader._funcs[type](path);
6801:+            var asset = tm.asset.Loader._funcs[type](path, key);
```

これでうまくいきます。

ロードしたフォントを使う時はこのようにfontFamilyを指定してください。

```js:main.js
tm.display.Label("Cure Cure Pretty!", 100)
    .setFillStyle("pink")
    .setFontFamily("mainFont"); // ロード時にassetsオブジェクトで指定したキー
```

http://daishihmr.github.io/tmlib.js-adventcalendar-2014_2

![demo.png](https://qiita-image-store.s3.amazonaws.com/0/30568/2780e7e2-43be-1b33-626c-9870019958e5.png)


ソースコードは[こちら](https://github.com/daishihmr/tmlib.js-adventcalendar-2014_2/archive/master.zip)からダウンロードできます。
外部html呼び出し時の備忘録

##備忘録
外部html呼び出し時にIEだと表示されるのにFirefoxだと表示されない現象の備忘録

###原因
$.get()を使う時にdataTypeを指定してなかった

----

```hoge.html
<html>
	<head>
		<script type="text/javascript" charset="utf-8" src="../js/jquery-1.7.1.min.js"></script>
		<script type="text/javascript" charset="utf-8" src="../js/jquery.tmpl.js"></script>
		<script type="text/javascript" charset="utf-8" src="../js/hoge.js"></script>
	</head>
	<body>
		<div id="main"></div>
	</body>
</html>
```

```hogehoge.html
    <p>${dispName}</p>
```

↓dataType未指定

```hoge.js
$(function () {
    $.get(
        'hogehoge.html',
        null,
        function (data) {
            $.tmpl(data, { dispName: "テスト画面" }).appendTo("#main");
        }
    );
});
```

↓dataTypeにhtmlを指定

```hoge.js
$(function () {
    $.get(
        'hogehoge.html',
        null,
        function (data) {
            $.tmpl(data, { dispName: "テスト画面" }).appendTo("#main");
        },
        "html"
    );
});
```

なんでIEは表示されるんですかねぇ┐(´∀｀)┌
awscliのインストールでハマった

awscliのインストールしようとしたところで、pythonに慣れてなかったこともあって若干ハマったのでメモ



```
$ sudo pip install awscli

$ aws --version
Traceback (most recent call last):
  File "/usr/local/bin/aws", line 23, in <module>
    sys.exit(main())
  File "/usr/local/bin/aws", line 19, in main
    return awscli.clidriver.main()
  File "/usr/local/lib/python2.7/dist-packages/awscli/clidriver.py", line 49, in main
    driver = create_clidriver()
  File "/usr/local/lib/python2.7/dist-packages/awscli/clidriver.py", line 58, in create_clidriver
    event_hooks=emitter)
  File "/usr/local/lib/python2.7/dist-packages/awscli/plugin.py", line 44, in load_plugins
    modules = _import_plugins(plugin_mapping)
  File "/usr/local/lib/python2.7/dist-packages/awscli/plugin.py", line 61, in _import_plugins
    module = __import__(path, fromlist=[module])
  File "/usr/local/lib/python2.7/dist-packages/awscli/handlers.py", line 61, in <module>
    from awscli.customizations.opsworks import initialize as opsworks_init
  File "/usr/local/lib/python2.7/dist-packages/awscli/customizations/opsworks.py", line 24, in <module>
    from six.moves import shlex_quote
ImportError: cannot import name shlex_quote
```

awsコマンドのインストールはできたけど`shlex_quote`が無くて怒られているっぽい

sixっていうpython2と3の互換ライブラリがあって、
* https://pythonhosted.org/six/
これの1.8から`shlex_quote`が追加されたと。

なのでsix 1.8.0をインストールして解決

```
$ sudo pip install six==1.8.0
Downloading/unpacking six==1.8.0
  Downloading six-1.8.0-py2.py3-none-any.whl
Installing collected packages: six
  Found existing installation: six 1.5.2
    Uninstalling six:
      Successfully uninstalled six
Successfully installed six
Cleaning up...

$ aws --version
aws-cli/1.6.7 Python/2.7.6 Linux/3.13.0-24-generic
```
MySQL5.6のインストール

# 前書き

サーバにMySQLをインストールすることになったので、メモ的に残しておこうかと。

内容はほとんど参考リンクのままだけど、微妙にバージョンとか違います。

# インストール

## rpmダウンロード

普通にyumでインストールしようとすると5.1系なのでwgetしてくる

```
$ mkdir ~/mysql
$ cd ~/mysql
$ wget http://dev.mysql.com/get/Downloads/MySQL-5.6/MySQL-client-5.6.22-1.el6.x86_64.rpm \
http://dev.mysql.com/get/Downloads/MySQL-5.6/MySQL-shared-compat-5.6.22-1.el6.x86_64.rpm \
http://dev.mysql.com/get/Downloads/MySQL-5.6/MySQL-server-5.6.22-1.el6.x86_64.rpm \
http://dev.mysql.com/get/Downloads/MySQL-5.6/MySQL-devel-5.6.22-1.el6.x86_64.rpm \
http://dev.mysql.com/get/Downloads/MySQL-5.6/MySQL-shared-5.6.22-1.el6.x86_64.rpm
```

## インストール

パッケージ依存関係の都合で2回に分けてyum install

```
$ sudo yum install MySQL-{client,devel,server,shared-compat}-5.6.22-1.el6.x86_64.rpm
$ sudo yum install MySQL-shared-5.6.22-1.el6.x86_64.rpm
```

### yumログ

ログでインストール履歴が見れる

```
$ sudo tail /var/log/yum.log
（略）
Dec 09 18:31:24 Installed: MySQL-devel-5.6.22-1.el6.x86_64
Dec 09 18:31:46 Installed: MySQL-server-5.6.22-1.el6.x86_64
Dec 09 18:31:47 Installed: MySQL-shared-compat-5.6.22-1.el6.x86_64
Dec 09 18:31:52 Installed: MySQL-client-5.6.22-1.el6.x86_64
Dec 09 18:31:52 Erased: mysql-libs
Dec 09 18:32:56 Installed: MySQL-shared-5.6.22-1.el6.x86_64
```

## 初期セットアップ

### MySQL起動

```
$ sudo service mysql start
Starting MySQL.. SUCCESS!
```

### 初期パスワード確認

```
$ sudo cat /root/.mysql_secret
# The random password set for the root user at Tue Dec  9 18:31:41 2014 (local time): aBcDeFgHiJkLmNoP
```

### 初回ログイン

先程確認したパスワードを使ってログイン

```
$ mysql -u root -p
```

#### パスワードを変えるまで何もできない

```
mysql> show databases;
ERROR 1820 (HY000): You must SET PASSWORD before executing this statement
```

#### パスワード変更

```
mysql> SET PASSWORD FOR root@localhost=PASSWORD('hogefuga');
Query OK, 0 rows affected (0.01 sec)
```

この時点でも一応使える状態

```
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| test               |
+--------------------+
4 rows in set (0.02 sec)
```


#### mysql_secure_installation

一度MySQLからは出て、mysql_secure_installationコマンドを打つ。

```
$ mysql_secure_installation
```

いくつかY/nを聞かれるけど、最初（rootパスワードの変更）だけn、あとは基本Yでオッケー。

後から思ったけど、ログインしてrootパスワード変更しなくてもこっちで変更すれば良かったのでは・・・

また次の機会に確認しよう。

# 参考
http://blog.manabusakai.com/2013/04/centos-mysql56-install/
Android Studioで *.jar, *.soを追加する


Android Studio 1.0 (以下AS)がリリースされた。と同時に eclipse ADT pluginのフェードアウトも発表されたため、今後の開発は ASに軸足を移していく必要がある。

一応 eclipseからのプロジェクトのインポート機能も用意されてはいるが、eclipseで安定して開発できているものを今から変更するのはあまり意味が無い気がするし、そもそも依存関係のあるプロジェクトの移行には弱いという印象がある。新しいプロジェクトだけ ASで開発していけば自分の作業環境としては問題がない。

今回は OCRライブラリの評価を進めるため、eclipseで作ったライブラリ(jar, so)を ASで再利用するための方法を調べた。

参考したのは http://tondol.hatenablog.jp/entry/20130521/1369111104 。ただ開発中バージョンに基づいた記事のため、現在では通じない記述があった。

#手順
## jar, soの用意
まず eclipseで作った tess-two, eyes-twoの jarファイルと共有ライブラリをひとまとめにした。必須の作業ではないが、色々なプロジェクトで使い回したいため。

* 共有ライブラリ(*.so)は jniLibsに
* jarは libsに

それぞれまとめておくといい。

![fig0.png](https://qiita-image-store.s3.amazonaws.com/0/3847/44f011d7-1796-e25f-cb81-66f54a3afcfb.png "fig0.png")

## プロジェクトを作る

ASを立ち上げて新規プロジェクトを作る。Wizardの質問には適当に答えて空の  MainActivityが作られればいい。

![fig2.png](https://qiita-image-store.s3.amazonaws.com/0/3847/5384b69a-92ed-ee72-038c-495a963ae087.png "fig2.png")

### ライブラリ(*.jar)の追加

先ほどまとめておいたjarを libsの下へ Copy & Pasteする。 Drag & Dropするとコピーでなく移動してしまうので注意。

![fig3.png](https://qiita-image-store.s3.amazonaws.com/0/3847/e049c659-dca9-374f-7323-bd7ca3ec6ab1.png "fig3.png")

tess-two.jarに対して右クリック → Add as Libraryを行う。なんでかよく分からないが libsに入っている他のjarも同時に処理されるっぽい。

![fig4.png](https://qiita-image-store.s3.amazonaws.com/0/3847/67234701-26df-3ef5-7a28-cffb8ab042ff.png "fig4.png")

次に appの build.gradleを編集する。

```Gradle:build.gradle編集前
dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:21.0.2'
    compile files('libs/tess-two.jar')
}
```

compileの3行目が必要ない。2つ上の行の記述だけで充分。

```Gradle:build.gradle編集後
dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:21.0.2'
}
```

これで jarファイルはプロジェクトに組み込まれた。

### 共有ライブラリ (*.so)の追加

共有ライブラリは app/src/main/jniLibsディレクトリを作り、そこに各プラットフォームのディレクトリと共有ライブラリを置いていく。

![fig5.png](https://qiita-image-store.s3.amazonaws.com/0/3847/e7077cd5-e430-64df-414a-9f2ad50eb1ce.png "fig5.png")


こちらはファイルを置くだけで設定することはない。ライブラリの置き場所は変更可能 (参照 : http://vividcode.hatenablog.com/entry/android-app/gradle-jnilibs)

# 実験: OCR

先日作った OCRのテストプロジェクトを ASで作りなおしてみた。

https://github.com/Nunocky/OCRTest01

![fig6.png](https://qiita-image-store.s3.amazonaws.com/0/3847/00a59390-e336-4fbc-3421-13b18fb15ec0.png "fig6.png")

Jolly good.
Xcode6のAutoLayoutについて

そもそもAutoLayout自体、よくわかってないのに、Xcode6でiPhone5/5s、iPhone6、iPhone6Plusの画面に同時に対応しなければならなくなったので、AutoLayoutのやり方から、各機種の対応方法までわかったことを記載していきたいと思います。

というか、AutoLayoutのわかりやすいサンプルってないのでしょうか？
Xcode5時代からどうにかして使いこなそうとがんばってみましたが、
制約ってやつがどうしてもなじめなくて、理解不能でした。

こんなあわれな子羊に快く説明して下さる方がどこかにいらっしゃらないもんなんでしょうか？

Help me!!
CakePHP3のORMを使う際に欠かせない概念について


諸事情あって、バタバタしているyandoです。
18時過ぎに自分の番である事に気がついてしまいましたが、この記事はCakePHP アドベントカレンダーの9日目です。

CakePHP3で一新されたORMは「結果が配列からオブジェクトになった」というだけではない違いがあります。
それが **Eager loading** と **Lazy loading** です。この概念を理解していないとORMの機能を間違って使ってしまうかもしれません。

# 何が起きるの? N+1問題

ORMからクエリを実行した時にJOINを使ったクエリを実行するか、シンプルなクエリを実行するかのルールが分かりますか？

従来のCakePHPではJOINの条件などに応じて自動的に決定されており、関連データを取得するためのクエリが大量に実行される場合がありました。たとえば画面に表示している20件のデータを取得するクエリを実行し、その後に20件のデータに紐づく関連データを取得するクエリが20回実行されるという形です。これを N+1 問題と呼びます。

# Eager Loding

Eager LoadingはJOINを使って可能な限り、一度のクエリで関連データの取得まで一括で行います。
これによりクエリの実行回数は最小になりますが、扱うデータが多い場合はクエリが複雑になる場合があります。
実際のデータの構造によってはこのアプローチを離れる必要があります。

コントローラーからORMを使う場合などは基本的にEager Loadingとなります。
従来のCakePHPと同じ感覚で使うと、より複雑なクエリが少ない回数実行されることになります。

# Lazy Loading

Lazy LoadingはJOINを使わずにシンプルなクエリを実行します。画面に表示した20件のデータのうち、何らかのカテゴリのデータについては、さらに別テーブルのデータを参照するというような場合です。
CakePHP3ではエンティティクラスからクエリを実行する形にすることで必要な時に後からクエリを実行する事ができるようになりました。

Lazy loadingはORMの機能としてまだ実装されていませんが、エンティティクラスにメソッドを追加する事で実現できるようになっています。

```
namespace App\Model\Entity;

use Cake\ORM\Entity;
use Cake\ORM\TableRegistry;

class Article extends Entity {

    protected function _getComments() {
        $comments = TableRegistry::get('Comments');
        return $comments->find('all')
            ->where(['article_id' => $this->id])
            ->all();
    }

}
```

上記のようなメソッドをエンティティに作成しておくと、アクセサ経由で下記のように暗黙的に実行できます。

```
$article = $this->Articles->findById($id);
foreach ($article->comments as $comment) {
    echo $comment->body;
}
```

# 資料

- http://book.cakephp.org/3.0/en/orm/entities.html#lazy-loading-associations
- https://github.com/cakephp/cakephp/issues/4829
digital ocean でnode.jsサーバー立てるまで


#ターミナルからログイン
1. `ssh root@IP`
2. ドロップレット作成時にアカウント宛に届いたパスを入力
3. パスワード変更

#環境構築
1. `sudo apt-get update`
2. `sudo apt-get install nodejs`
3. `sudo apt-get install npm`
4. `sudo apt-get install git`

#gitデプロイつなぎ込み
[解説記事](https://www.digitalocean.com/community/tutorials/how-to-set-up-automatic-deployment-with-git-with-a-vps)


1. `/var/repo/site.git/` を作成して `git init —bare`
2. `/var/repo/site.git/hooks/` へ移動
3. `cat > post-receive` で`post-receive`ファイルを作成
4. `vim`モードにするなどして以下記入`:x`で保存  
	#!/bin/sh  
	git --work-tree=/var/www/ディレクトリ名 --git-dir=/var/repo/site.git checkout -f
5. `chmod +x post-receive`

6. ローカルレポジトリにgitパスをつなぎ込み
	`ssh://root@IP/var/repo/site.git`

7. `SSHキー`の登録（新規アカウント作成時のみ）

8. プッシュしてデプロイ

#サーバー永続化
`npm`の`pm2`をインストール
`pm2 start app.js` でサーバー永続化
AWSで遊んでたWikiを放置してたらえらい目に合った


ちょっと前に、勉強がてらWikiを作ってみーよう！と思いAmazon AWSの無料枠を使ってMedia wikiをインストールした。
で、しばらく遊んで飽きて「まー無料だし気が向いたらそのうちいじろ」と放置していたら

![20141209174652.jpeg](https://qiita-image-store.s3.amazonaws.com/0/55641/326f9132-776d-58bf-dd0f-2c033ad51b49.jpeg "20141209174652.jpeg")

**$52.33/月** の請求がきて死んだ。


## 何が起きたのか

詳細をみてみよう

![20141209174850.jpeg](https://qiita-image-store.s3.amazonaws.com/0/55641/aeb568ed-2926-ef76-8e2a-014bb2154e22.jpeg "20141209174850.jpeg")

EC2がとんでもないことになっている。

さらに詳細。

![20141209175058.jpeg](https://qiita-image-store.s3.amazonaws.com/0/55641/8224b2c9-5f4d-c392-9699-8cf0cf717623.jpeg "20141209175058.jpeg")

ん...?

![20141209175259.jpeg](https://qiita-image-store.s3.amazonaws.com/0/55641/cea164d9-b3b1-6788-d919-303ca2c86d8d.jpeg "20141209175259.jpeg")

 **なんじゃこりゃ**
 
 
とんでもない量のI/Oリクエストが飛んできている。Wiki自体は編集中で、そんなに人がくるコンテンツもまだないはず...


### 検証...したいけど
金額を見た瞬間ビビりすぎて即刻EC2のインスタンスをterminateしてしまったので実際に何が起こったのかは詳しく検証できず...
(というかそもそも検証する知識と経験がない。困った)

### とりあえずGoogleのキャッシュを追う

キャッシュを追ってトップページをみてみると...

![20141209180131_masked.jpg](https://qiita-image-store.s3.amazonaws.com/0/55641/27ed302a-cbed-96f8-7787-cd43950f101a.jpeg "20141209180131_masked.jpg")

全然覚えのない記述が。
(マスクはWiki名やドメイン名)

![20141209180921_masked.jpg](https://qiita-image-store.s3.amazonaws.com/0/55641/a0c5829b-1f52-12fe-9f75-7773bff9a1ee.jpeg "20141209180921_masked.jpg")


さらに見覚えのないユーザーの書き込み

![20141209183001.jpeg](https://qiita-image-store.s3.amazonaws.com/0/55641/c72308c4-9eae-d7f9-c991-b1a507773b20.jpeg "20141209183001.jpeg")


そして謎のアクセス数


 **こ、これは...**

## オチ
Wikiの編集権限を限定せずに、 **全てのユーザーが編集できる** 状態で放置してしまったためにSEO対策業者(もしくは愉快犯的スパム)にページを乗っ取られ、好き放題されてしまった。(おそらく)

で、そういう個人の放置ページがスラム化するのはザラにあるというか、常識もいいとこでネタにもならん話で、僕も過去いろんな空き家を作ってきたので正直それに関しては気にしてもいなかった。

しかしそれはあくまで定額制のレンタルサーバに置いてるブログとかの話であって、 **従量課金制のAWSではページの乗っ取りが個人の深刻なダメージになる** ということを全くこれっぽっちも考えてなかった。

ああ...馬鹿だ... **バカすぎる...!!!**

## 教訓
AWSの無料枠で遊ぶ場合はキッチリ監視して、継続した管理をするのが重要。とっても重要。

そしてスパム対策はめんどくさがらずにしっかりやる。これも死ぬほど重要。

及び、 

> **あそんだら ちゃんと おかたづけする**

じゃないと来月質素な生活をおくることになる。

僕レベルのバカはたぶんあまりいないだろうが...
cocos2d-x 3.3rc2をインストールしてみた(3.3も追記)

Cocos2d-x 3.2が動いているmacにCocos2d-x 3.3rc2を入れてみたのでメモ。インストールだけならほとんど問題なさそう。

## ダウンロード

### 3.3rc2
```
$ wget http://www.cocos2d-x.org/filedown/cocos2d-x-3.3rc2.zip
```

### 3.3
```
$ wget http://www.cocos2d-x.org/filedown/cocos2d-x-3.3.zip
```


## インストールとか設定とか

### 3.3rc2
``` bash
$ unzip cocos2d-x-3.3rc2.zip
$ cd cocos2d-x-3.3rc2
$ python setup.py
```

### 3.3
``` bash
$ unzip cocos2d-x-3.3.zip
$ cd cocos2d-x-3.3
$ python setup.py
```

いつもどおり.bash_profileに追記されている。新しく環境変数が足されてる？
templateフォルダのパスって何に使うんだろう。

``` .bash_profile
## Add environment variable COCOS_X_ROOT for cocos2d-x
export COCOS_X_ROOT=/Users/user_name/cocos2d-x-3.3rc2
export PATH=$COCOS_X_ROOT:$PATH

# Add environment variable COCOS_TEMPLATES_ROOT for cocos2d-x
export COCOS_TEMPLATES_ROOT=/Users/user_name/cocos2d-x-3.3rc2/templates
export PATH=$COCOS_TEMPLATES_ROOT:$PATH
```

./bash_profileを読み込み直して、cocosコマンドのパスが変わっていることを確認。

``` bash
$ . ~/.bash_profile
$ which cocos
/Users/user_name/cocos2d-x-3.3rc2/tools/cocos2d-console/bin/cocos
```

## プロジェクトを作ってみる

とりあえずプロジェクト作成

``` bash
$ cocos new cocos2dx33rc2 -p com.mettoboshi.cocos2dx33rc2 -l cpp --ios-bundleid com.mettoboshi.cocos2dx33rc2
```

エラーでた。

```
$ cocos new cocos2dx33rc2 -p com.mettoboshi.cocos2dx33rc2 -l cpp --ios-bundleid com.mettoboshi.cocos2dx33rc2
Traceback (most recent call last):
File "/Users/user_name/cocos2d-x-3.3rc2/tools/cocos2d-console/bin/cocos.py", line 22, in <module>
    import cocos_project
  File "/Users/user_name/cocos2d-x-3.3rc2/tools/cocos2d-console/bin/cocos_project.py", line 4, in <module>
    import cocos
File "/Users/user_name/cocos2d-x-3.3rc2/tools/cocos2d-console/bin/cocos.py", line 25, in <module>
    import ConfigParser
ImportError: No module named 'ConfigParser'
```

コレあれだ。python3.4.2使ってるからだ。cocos2d-x v3.2使ってた時はv2じゃないとだめだよみたいなエラーが出てたような気がしたけど。どうだったかな。

Xcodeで作成したプロジェクトを開いて、ビルド->実行してみたらとりあえずサックリ動いた。

![cocos3.3rc2.png](https://qiita-image-store.s3.amazonaws.com/0/42925/dcfb40e5-5210-39e3-b152-bb33b49d794e.png)

Androidもいけるっぽい。

![cocos2dx33rcAndroid.png](https://qiita-image-store.s3.amazonaws.com/0/42925/c9c7347a-07e5-055c-1abd-a4bdc0da9539.png)

Androidはどっちかっていうと、スクリーンショット取るためにエミュレーターを回転させる「ctrl + fn + f11」を思い出す方が大変だった。。

細かいとこはまた今度。

## その他

あんまり関係ないけど、以下のURLに3.3のプログラマーズガイドがある。PDFやePub版も。
http://cocos2d-x.org/programmersguide/

まだちゃんと読んでないけど読む価値はありそうな気配が。
KnockoutJsでのko.computedが発火しなくてハマったのでメモ

# これは何？

* kockoutjs で ko.computedが発火しなくてハマってしまったのでメモ
* Js初心者なので当たり前なのかもしれないけど･･･戒めとして。

# 状況説明

## 正常動作例

```html
<p>ファーストネーム: <input data-bind="value: firstName, valueUpdate: 'afterkeydown'" /></p>
<p>ラストネーム: <input data-bind="value: lastName, valueUpdate: 'afterkeydown'" /></p>
<h2>Hello, <span data-bind="text: fullName"> </span>!</h2>
```

```js
var ViewModel = function(first, last) {
    var self = this;
    self.firstName = ko.observable(first);
    self.lastName = ko.observable(last);
      
    self.fullName = ko.computed(function() {
        return self.firstName() + " " + self.lastName();
    }, self);
};

ko.applyBindings(ViewModel);
```

ソースの元ネタは、[Hello World デモ](http://kojs.sukobuto.com/tips/helloWorld)　です。

## 動かない例

```js
    // 略
    self.fullName = ko.computed(function() {
        return self.firstName + " " + self.lastName;
    }, self);
　　// 略
```

# 解決策

1. 値の呼び出しに、```self.firstName```や```self.lastName```をプロパティとして呼び出している点がだめ。```self.firstName()```や```self.lastName()```として呼び出す必要あり。
2. ```<p>ファーストネーム: <input data-bind="value: firstName, valueUpdate: 'afterkeydown'" /></p>```　の時、値の設定になるので、```firstName```で呼び出す。```firstName()```ではないということ。

ハマった理由として、エラーにもならないし、ko.comuputedのメソッドも発火しないし･･･なんなんだ？という感じでした。

なんでそうなるか？についてはよくわからない。Jsへの理解語りないのかもしれない。教えてもらえるとうれしい･･･。
Googleスプレッドシートで行を削除するショートカット

Googleスプレッドシートの行を削除するショートカットです。環境はMacです。

```
Control + Option + e
```
上記のショートカットを叩くと、編集メニューが開きます。

<img src="https://qiita-image-store.s3.amazonaws.com/0/1624/ad404f26-8ba9-3e47-1c55-220dd21783c3.png" width=200 />

ココで削除は(D)とあるのでdを叩きます。

```
d
```
行が削除されました。

# 参考
Google スプレッドシートのキーボード ショートカット
https://support.google.com/docs/answer/181110?hl=ja
UnityでGooglePlayGameServicesのプラグインを使うとき、iOSを除外する

https://github.com/playgameservices/play-games-plugin-for-unity/issues/276

ここに書いてあるとおりなんだけど、
プロジェクト内のGooglePlayGamesサブディレクトリ配下の、

```
#if（UNITY_ANDROID || UNITY_IPHONE）
```

を

```
#if UNITY_ANDROID
```

に変更して、

```
#if UNITY_IPHONE
```
内部をコメントアウト
にして、XcodeのLibrary内のGooglePlayGameServices関連のファイル全部けせばだいじょうぶ。

はまった…。
MacでSublime Text 3のインストールと日本語化メモ

# Sublime Text 3をダウンロードし、インストールする
##### 1. DownloadからOSX版のdmgファイルをダウンロードする。
![MacでSublime Text 3のダウンロード](https://qiita-image-store.s3.amazonaws.com/0/37964/3600bcba-bf63-a720-e8ce-5d9c1318d14a.png)
[Sublime Text - Download](http://www.sublimetext.com/3)

##### 2. ダウンロードしたdmgファイルを開き、Sublime TextをApplicationsフォルダへ。
![MacでSublime Text 3のインストール](https://qiita-image-store.s3.amazonaws.com/0/37964/e13ddad6-afba-493a-8afa-850ac0f77c9d.png)

# 日本語化ファイルのインストール
##### 1. Sublime Textを起動する。
![MacでSublime Text 3の日本語化](https://qiita-image-store.s3.amazonaws.com/0/37964/3b152da8-90d6-73f3-cf60-1061bbe1ea1d.png)
リリースノートが表示されますが（表示されない場合もあり）、読み飛ばし…

##### 2. メニューバーから **View > Show Console** を選択するか、短縮コマンド **Control＋Shift＋`** でコンソールウインドウを呼び出す。
![MacでSublime Text 3の日本語化](https://qiita-image-store.s3.amazonaws.com/0/37964/61575aea-3310-babb-6444-c7b28d119c17.png)

##### 3. コンソールウインドウに以下を入力して、Return（Enter）を押す。
![MacでSublime Text 3の日本語化](https://qiita-image-store.s3.amazonaws.com/0/37964/0a0d4b5d-ce2d-b6ca-4fc8-328c8c2eece5.png)

```bash:Console
import urllib.request,os; pf = 'Package Control.sublime-package'; ipp = sublime.installed_packages_path(); urllib.request.install_opener( urllib.request.build_opener( urllib.request.ProxyHandler()) ); open(os.path.join(ipp, pf), 'wb').write(urllib.request.urlopen( 'http://sublime.wbond.net/' + pf.replace(' ','%20')).read())
```

##### 4. メニューバーから **Tools > Command Palette...** を選択するか、短縮コマンド **Shift＋Command＋P** でコマンドパレットを呼び出す。ここに **install** と入力すると **Package Control: Install Package** と出てくるのでこれを選択。
![MacでSublime Text 3の日本語化](https://qiita-image-store.s3.amazonaws.com/0/37964/ea1b8aa4-61c4-e929-498d-f2398d363081.png)

##### 5. さらに **japan** と入力すると **Japanize** という日本語化ファイルが見つかるので、これを選択する。
![MacでSublime Text 3の日本語化](https://qiita-image-store.s3.amazonaws.com/0/37964/0269f729-3513-bf5c-9b54-221b5ce6d49c.png)

##### 6. **Package Control Messages** が表示されれば、日本語化ファイルのインストールは完了。
![MacでSublime Text 3の日本語化](https://qiita-image-store.s3.amazonaws.com/0/37964/0a102ebf-7904-c652-ece7-86efd1758271.png)

# 日本語化ファイルを適用する
インストールしただけでは動作しないので、以下の適用をおこないます。

##### 1. Finderのメニューバーから **移動 > フォルダへ移動...** を選択し **/Users/ユーザー名/Library/Application Support/Sublime Text 3/Packages/** と入力するか、上記ディレクトリまで移動する。
##### 2. JapanizeフォルダとUserフォルダがあるので、ここに **Defaultフォルダを作成** する。
![MacでSublime Text 3の日本語化](https://qiita-image-store.s3.amazonaws.com/0/37964/ca6a840e-1f04-6145-991f-9565974c4e2a.png)

##### 3. japanizeフォルダ内にある **.jpと付いているファイル** を **Defaultフォルダへコピー** する。
- Context.sublime-menu.jp
- Indentation.sublime-menu.jp
- Main.sublime-menu.jp
- Side Bar Mount Point.sublime-menu.jp
- Side Bar.sublime-menu.jp
- Tab Context.sublime-menu.jp

##### 4. **Defaultフォルダへコピーしたファイル名から、すべて「.jp」を取る。** （拡張子を.jpから.sublime-menuに変更する）
![MacでSublime Text 3の日本語化](https://qiita-image-store.s3.amazonaws.com/0/37964/ee47f46f-997b-aa4b-8fc0-f2d424f817bb.png)

##### 5. japanizeフォルダ内にある**Main.sublime-menu** を **Userフォルダへコピー** する。

##### 6. これで日本語化は完了です。
![MacでSublime Text 3の日本語化](https://qiita-image-store.s3.amazonaws.com/0/37964/dafe606c-ddb1-e0b5-8062-1a5934be3115.png)

## ちなみに…
Preferences まわりは日本語化しない模様。
個人的によく使うgoogle検索のオプション4個

久しぶりにQiitaを書かねば！と思いよく使う検索でも書いてみます。
下記サイトに便利なまとめがあったので、このページでは「どういう時に使っているのか？」に視点を置いて書いてみます。

* [Google検索がもっと便利になる検索オプション・テクニックまとめ](http://liginc.co.jp/web/service/google/86222)

# filetype
* 特定のファイルタイプを表示
* 以下のようなものをよく指定します.
 * conf
 * text
 * txt

```
filetype:txt site:example.com
```
* 『example.comさんにtxtファイルが落ちてないかな〜？』って時ですね

# site
* 特定ドメイン以下を検索対象にします

実際には特定ドメインというより特定のパス以下という印象があります。
なので、以下のような検索が出来ますね。

```
プラズマクラスター site:twitter.com/sharp_jp
```
* 過去にシャープさんが"プラズマクラスター"と呟いた一覧ですね
* ピンと来たかもしれませんが、"プラズマクラスター"の部分を、"4sq"とか"幼稚園"とか"帰宅"とかに換えてググる人も居たりすると思います
 * twitterだけではなく、公開される全サイト上では、『他人に見せても良い事だけ』を呟くようにしましょう！

他にも外部のサイトで要らん事を書いている社員が居ないか、チェックする時とかにも使えますかね？

```
aaaa site:qiita.com
```
* qiitaで技術公開している社員さんが多数居る会社とか？


# inurl
『特定のファイル名で公開されていないかな？』って時に使います。
このオプションは重ねて書けるので、以下のような感じですかね。

```
inurl:admin inurl:php site:example.com
```

実際に似たような検索をしてみたら、何かのテストページが出て来た事があります。
中身はほんとにテストデータっぽくダミーだったので、忘れさられたんでしょうね。

# cache
『ググったら出て来たのに、アクセスしたらページないやん！orz』って事たまにありますよね。
その時は、そのページの先頭にcache:を付けます。

```
cache:qiita.com/ionis_h/items/6eeccc4cab88b31d0ae8
```

キャッシュが存在していた場合は、いつ取得したキャッシュとか付けて表示してくれるので、最後の手段としては便利ですよ。
キャッシュもなくなれば見えないので、どうしても保存しておきたい情報はevernoteにメモるとか、魚拓を取る方が良いでしょうけどね。

# まとめ
再度、個人的によく使うオプションを残していきます。

| オプション | 説明 |
|:--|:--|
| site | 該当のドメイン内を検索する |
| filetype | 特定のファイルタイプを表示 |
| inurl | URLに特定の単語が含まれているページを表示 |
| cache | 該当URLのキャッシュを表示 |

今回記載しなかったオプションの中にも便利なものがありますし、調べてみると面白いと思います。
とりあえず、siteだけでも、検索の幅が広がっていくと思いますよ！