Merge branch 'develop'
diff --git a/.gitignore b/.gitignore
index 2a3cfbd..ec6b6b7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
 build
 composer.phar
+composer.lock
 docs
 vendor
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..68b4dfe
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,10 @@
+language: php
+php:
+  - 5.5
+  - 5.4
+  - 5.3
+before_script:
+  - pear channel-discover pear.phing.info
+  - pear install phing/phing
+  - phpenv rehash
+  - phing
diff --git a/README.md b/README.md
index 673980d..6e2aa05 100644
--- a/README.md
+++ b/README.md
@@ -1,18 +1,43 @@
 PredictionIO PHP SDK
 ====================
 
+[![Build Status](https://travis-ci.org/PredictionIO/PredictionIO-PHP-SDK.png?branch=develop)](https://travis-ci.org/PredictionIO/PredictionIO-PHP-SDK)
+[![Scrutinizer Quality Score](https://scrutinizer-ci.com/g/PredictionIO/PredictionIO-PHP-SDK/badges/quality-score.png?s=bba570e3add382f4f56fcba65ec0b4f0b8622091)](https://scrutinizer-ci.com/g/PredictionIO/PredictionIO-PHP-SDK/)
+[![Code Coverage](https://scrutinizer-ci.com/g/PredictionIO/PredictionIO-PHP-SDK/badges/coverage.png?s=db1de9fde081fedd79346b4aba562ab56853ed45)](https://scrutinizer-ci.com/g/PredictionIO/PredictionIO-PHP-SDK/)
+
 Prerequisites
--------------
+=============
 
 * PHP 5.3+ (http://php.net/)
 * PHP: cURL (http://php.net/manual/en/book.curl.php)
 * Phing (http://www.phing.info/)
 * ApiGen (http://apigen.org/)
 
-Getting Started
----------------
 
-### By Composer
+Support
+=======
+
+
+Forum
+-----
+
+https://groups.google.com/group/predictionio-user
+
+
+Issue Tracker
+-------------
+
+https://predictionio.atlassian.net
+
+If you are unsure whether a behavior is an issue, bringing it up in the forum is highly encouraged.
+
+
+Getting Started
+===============
+
+
+By Composer
+-----------
 
 The easiest way to install PredictionIO PHP client is to use [Composer](http://getcomposer.org/).
 
@@ -20,7 +45,7 @@
 
         {
             "require": {
-                "predictionio/predictionio": "*"
+                "predictionio/predictionio": "~0.6.0"
             }
         }
 
@@ -37,7 +62,8 @@
         require_once("vendor/autoload.php");
 
 
-### By Building Phar
+By Building Phar
+----------------
 
 1. Assuming you are cloning to your home directory:
 
@@ -52,16 +78,18 @@
 3. Once the build finishes you will get a Phar in `build/artifacts`, and a set of API documentation.
    Assuming you have copied the Phar to your current working directory, to use the client, simply
 
-        require_once("predictionio.phar");
+        require_once("predictionio.phar");    
 
 
 Supported Commands
-------------------
+==================
 
-For a list of supported commands, please refer to the API documentation.
+For a list of supported commands, please refer to the
+[API documentation](http://docs.prediction.io/php/api/).
+
 
 Usage
------
+=====
 
 This package is a web service client based on Guzzle.
 A few quick examples are shown below.
@@ -72,50 +100,74 @@
 Many REST request commands support optional arguments.
 They can be supplied to these commands by the `set` method.
 
-### Instantiate PredictionIO API Client
 
-    use PredictionIO\PredictionIOClient;
-    $client = PredictionIOClient::factory(array("appkey" => "<your app key>"));
+Instantiate PredictionIO API Client
+-----------------------------------
 
-### Import a User Record from Your App
+```PHP
+use PredictionIO\PredictionIOClient;
+$client = PredictionIOClient::factory(array("appkey" => "<your app key>"));
+```
 
-    // assume you have a user with user ID 5
-    $command = $client->getCommand('create_user', array('pio_uid' => 5));
-    $response = $client->execute($command);
 
-### Import an Item Record from Your App
+Import a User Record from Your App
+----------------------------------
 
-    // assume you have a book with ID 'bookId1' and we assign 1 as the type ID for book
-    $command = $client->getCommand('create_item', array('pio_iid' => 'bookId1', 'pio_itypes' => 1));
-    $response = $client->execute($command);
+```PHP
+// assume you have a user with user ID 5
+$command = $client->getCommand('create_user', array('pio_uid' => 5));
+$response = $client->execute($command);
+```
 
-### Import a User Action (View) form Your App
 
-    // assume this user has viewed this book item
+Import an Item Record from Your App
+-----------------------------------
+
+```PHP
+// assume you have a book with ID 'bookId1' and we assign 1 as the type ID for book
+$command = $client->getCommand('create_item', array('pio_iid' => 'bookId1', 'pio_itypes' => 1));
+$response = $client->execute($command);
+```
+
+
+Import a User Action (View) form Your App
+-----------------------------------------
+
+```PHP
+// assume this user has viewed this book item
+$client->identify('5');
+$client->execute($client->getCommand('record_action_on_item', array('pio_action' => 'view', 'pio_iid' => 'bookId1')));
+```
+
+
+Retrieving Top N Recommendations for a User
+-------------------------------------------
+
+```PHP
+try {
+    // assume you have created an itemrec engine named 'engine1'
+    // we try to get top 10 recommendations for a user (user ID 5)
     $client->identify('5');
-    $client->execute($client->getCommand('record_action_on_item', array('pio_action' => 'view', 'pio_iid' => 'bookId1')));
+    $command = $client->getCommand('itemrec_get_top_n', array('pio_engine' => 'engine1', 'pio_n' => 10));
+    $rec = $client->execute($command);
+    print_r($rec);
+} catch (Exception $e) {
+    echo 'Caught exception: ', $e->getMessage(), "\n";
+}
+```
 
-### Retrieving Top N Recommendations for a User
 
-    try {
-        // assume you have created an itemrec engine named 'engine1'
-        // we try to get top 10 recommendations for a user (user ID 5)
-        $client->identify('5');
-        $command = $client->getCommand('itemrec_get_top_n', array('pio_engine' => 'engine1', 'pio_n' => 10));
-        $rec = $client->execute($command);
-        print_r($rec);
-    } catch (Exception $e) {
-        echo 'Caught exception: ', $e->getMessage(), "\n";
-    }
+Retrieving Top N Similar Items for an Item
+------------------------------------------
 
-### Retrieving Top N Similar Items for an Item
-
-    try {
-        // assume you have created an itemsim engine named 'engine2'
-        // we try to get top 10 similar items for an item (item ID 6)
-        $command = $client->getCommand('itemsim_get_top_n', array('pio_iid' => '6', 'pio_engine' => 'engine1', 'pio_n' => 10));
-        $rec = $client->execute($command);
-        print_r($rec);
-    } catch (Exception $e) {
-        echo 'Caught exception: ', $e->getMessage(), "\n";
-    }
+```PHP
+try {
+    // assume you have created an itemsim engine named 'engine2'
+    // we try to get top 10 similar items for an item (item ID 6)
+    $command = $client->getCommand('itemsim_get_top_n', array('pio_iid' => '6', 'pio_engine' => 'engine1', 'pio_n' => 10));
+    $rec = $client->execute($command);
+    print_r($rec);
+} catch (Exception $e) {
+    echo 'Caught exception: ', $e->getMessage(), "\n";
+}
+```
diff --git a/composer.lock b/composer.lock
deleted file mode 100644
index 8a36ad4..0000000
--- a/composer.lock
+++ /dev/null
@@ -1,221 +0,0 @@
-{
-    "_readme": [
-        "This file locks the dependencies of your project to a known state",
-        "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file"
-    ],
-    "hash": "c96d97d6408cbc90125b23bdf6fd9fc0",
-    "packages": [
-        {
-            "name": "guzzle/guzzle",
-            "version": "v3.3.1",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/guzzle/guzzle.git",
-                "reference": "v3.3.1"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/guzzle/guzzle/zipball/v3.3.1",
-                "reference": "v3.3.1",
-                "shasum": ""
-            },
-            "require": {
-                "ext-curl": "*",
-                "php": ">=5.3.2",
-                "symfony/event-dispatcher": ">=2.1"
-            },
-            "replace": {
-                "guzzle/batch": "self.version",
-                "guzzle/cache": "self.version",
-                "guzzle/common": "self.version",
-                "guzzle/http": "self.version",
-                "guzzle/inflection": "self.version",
-                "guzzle/iterator": "self.version",
-                "guzzle/log": "self.version",
-                "guzzle/parser": "self.version",
-                "guzzle/plugin": "self.version",
-                "guzzle/plugin-async": "self.version",
-                "guzzle/plugin-backoff": "self.version",
-                "guzzle/plugin-cache": "self.version",
-                "guzzle/plugin-cookie": "self.version",
-                "guzzle/plugin-curlauth": "self.version",
-                "guzzle/plugin-error-response": "self.version",
-                "guzzle/plugin-history": "self.version",
-                "guzzle/plugin-log": "self.version",
-                "guzzle/plugin-md5": "self.version",
-                "guzzle/plugin-mock": "self.version",
-                "guzzle/plugin-oauth": "self.version",
-                "guzzle/service": "self.version",
-                "guzzle/stream": "self.version"
-            },
-            "require-dev": {
-                "doctrine/cache": "*",
-                "monolog/monolog": "1.*",
-                "phpunit/phpunit": "3.7.*",
-                "symfony/class-loader": "*",
-                "zend/zend-cache1": "1.12",
-                "zend/zend-log1": "1.12",
-                "zendframework/zend-cache": "2.0.*",
-                "zendframework/zend-log": "2.0.*"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "3.3-dev"
-                }
-            },
-            "autoload": {
-                "psr-0": {
-                    "Guzzle\\Tests": "tests/",
-                    "Guzzle": "src/"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Michael Dowling",
-                    "email": "mtdowling@gmail.com",
-                    "homepage": "https://github.com/mtdowling"
-                },
-                {
-                    "name": "Guzzle Community",
-                    "homepage": "https://github.com/guzzle/guzzle/contributors"
-                }
-            ],
-            "description": "Guzzle is a PHP HTTP client library and framework for building RESTful web service clients",
-            "homepage": "http://guzzlephp.org/",
-            "keywords": [
-                "client",
-                "curl",
-                "framework",
-                "http",
-                "http client",
-                "rest",
-                "web service"
-            ],
-            "time": "2013-03-10 23:05:38"
-        },
-        {
-            "name": "symfony/event-dispatcher",
-            "version": "v2.2.1",
-            "target-dir": "Symfony/Component/EventDispatcher",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/symfony/EventDispatcher.git",
-                "reference": "v2.2.1"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/v2.2.1",
-                "reference": "v2.2.1",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.3"
-            },
-            "require-dev": {
-                "symfony/dependency-injection": ">=2.0,<3.0"
-            },
-            "suggest": {
-                "symfony/dependency-injection": "2.2.*",
-                "symfony/http-kernel": "2.2.*"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "2.2-dev"
-                }
-            },
-            "autoload": {
-                "psr-0": {
-                    "Symfony\\Component\\EventDispatcher\\": ""
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Fabien Potencier",
-                    "email": "fabien@symfony.com"
-                },
-                {
-                    "name": "Symfony Community",
-                    "homepage": "http://symfony.com/contributors"
-                }
-            ],
-            "description": "Symfony EventDispatcher Component",
-            "homepage": "http://symfony.com",
-            "time": "2013-02-11 11:26:43"
-        }
-    ],
-    "packages-dev": [
-        {
-            "name": "symfony/class-loader",
-            "version": "v2.2.1",
-            "target-dir": "Symfony/Component/ClassLoader",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/symfony/ClassLoader.git",
-                "reference": "v2.2.1"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/symfony/ClassLoader/zipball/v2.2.1",
-                "reference": "v2.2.1",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.3"
-            },
-            "require-dev": {
-                "symfony/finder": ">=2.0,<3.0"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "2.2-dev"
-                }
-            },
-            "autoload": {
-                "psr-0": {
-                    "Symfony\\Component\\ClassLoader\\": ""
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Fabien Potencier",
-                    "email": "fabien@symfony.com"
-                },
-                {
-                    "name": "Symfony Community",
-                    "homepage": "http://symfony.com/contributors"
-                }
-            ],
-            "description": "Symfony ClassLoader Component",
-            "homepage": "http://symfony.com",
-            "time": "2013-03-19 08:32:26"
-        }
-    ],
-    "aliases": [
-
-    ],
-    "minimum-stability": "stable",
-    "stability-flags": [
-
-    ],
-    "platform": {
-        "php": ">=5.3.2"
-    },
-    "platform-dev": [
-
-    ]
-}
diff --git a/examples/SampleImport.php b/examples/SampleImport.php
index dc1e48f..83c9adf 100644
--- a/examples/SampleImport.php
+++ b/examples/SampleImport.php
@@ -12,9 +12,6 @@
 $appkey = $argv[1];
 $input = $argv[2];
 
-// Instantiate a client
-$client = PredictionIOClient::factory(array("appkey" => $appkey));
-
 if (!file_exists($input)) {
 	print "$input not found!\n";
 	exit(1);
@@ -25,6 +22,9 @@
 	exit(1);
 }
 
+// Instantiate a client
+$client = PredictionIOClient::factory(array("appkey" => $appkey));
+
 // Scan sample data file and import ratings
 $handle = fopen($input, "r");
 while (!feof($handle)) {
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
new file mode 100644
index 0000000..d313305
--- /dev/null
+++ b/phpunit.xml.dist
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<phpunit colors="true"
+         verbose="false"
+         convertErrorsToExceptions="true"
+         convertNoticesToExceptions="false"
+         convertWarningsToExceptions="false"
+         bootstrap="vendor/autoload.php"
+        >
+    <testsuites>
+        <testsuite name="PredictionIO Unit Test Suite">
+            <directory>./tests/Unit</directory>
+        </testsuite>
+    </testsuites>
+
+    <filter>
+        <whitelist>
+            <directory>./src</directory>
+        </whitelist>
+    </filter>
+</phpunit>
diff --git a/src/PredictionIO/Command/CreateItem.php b/src/PredictionIO/Command/CreateItem.php
index c3928b8..ab02c35 100644
--- a/src/PredictionIO/Command/CreateItem.php
+++ b/src/PredictionIO/Command/CreateItem.php
@@ -10,7 +10,8 @@
  *
  * Create or re-create an information record for a item. Re-creation will remove all data of the current record.
  *
- * To supply custom item information, simply pass it in during command creation, or use the "set" method inherited from Guzzle\Common\Collection.
+ * To supply custom item information, simply pass it in during command creation,
+ * or use the "set" method inherited from Guzzle\Common\Collection.
  * <code>
  * $command = $client->getCommand('create_item', array('pio_iid' => 'foobar', 'custom1' => 'baz'));
  * $command->set('custom2', '0xdeadbeef');
@@ -27,117 +28,120 @@
  */
 class CreateItem extends AbstractCommand
 {
-  /**
-   * Set the "iid" parameter for the current command
-   *
-   * @param string $iid Item ID
-   *
-   * @return CreateItem
-   */
-  public function setIid($iid)
-  {
-    return $this->set("pio_iid", $iid);
-  }
-
-  /**
-   * Set the "itypes" parameter for the current command
-   *
-   * $itypes can be supplied as an array of strings, or a "," delimited list of strings.
-   *
-   * @param array|string $itypes Item types
-   *
-   * @return CreateItem
-   */
-  public function setItypes($itypes)
-  {
-    if (is_array($itypes)) {
-      return $this->set("pio_itypes", implode(",", $itypes));
-    } else {
-      return $this->set("pio_itypes", $itypes);
+    /**
+     * Set the "iid" parameter for the current command
+     *
+     * @param string $iid Item ID
+     *
+     * @return CreateItem
+     */
+    public function setIid($iid)
+    {
+        return $this->set("pio_iid", $iid);
     }
-  }
 
-  /**
-   * Set the "startT" parameter for the current command
-   *
-   * @param string $startT Start time
-   *
-   * @return CreateItem
-   */
-  public function setStartT($startT)
-  {
-    return $this->set("pio_startT", $startT);
-  }
+    /**
+     * Set the "itypes" parameter for the current command
+     *
+     * $itypes can be supplied as an array of strings, or a "," delimited list of strings.
+     *
+     * @param array|string $itypes Item types
+     *
+     * @return CreateItem
+     */
+    public function setItypes($itypes)
+    {
+        if (is_array($itypes)) {
+            return $this->set("pio_itypes", implode(",", $itypes));
+        }
 
-  /**
-   * Set the "endT" parameter for the current command
-   *
-   * @param string $endT End time
-   *
-   * @return CreateItem
-   */
-  public function setEndT($endT)
-  {
-    return $this->set("pio_endT", $endT);
-  }
+        return $this->set("pio_itypes", $itypes);
+    }
 
-  /**
-   * Set the "price" parameter for the current command
-   *
-   * @param float $price Price
-   *
-   * @return CreateItem
-   */
-  public function setPrice($price)
-  {
-    return $this->set("pio_price", $price);
-  }
+    /**
+     * Set the "startT" parameter for the current command
+     *
+     * @param string $startT Start time
+     *
+     * @return CreateItem
+     */
+    public function setStartT($startT)
+    {
+        return $this->set("pio_startT", $startT);
+    }
 
-  /**
-   * Set the "profit" parameter for the current command
-   *
-   * @param float $profit Profit
-   *
-   * @return CreateItem
-   */
-  public function setProfit($profit)
-  {
-    return $this->set("pio_profit", $profit);
-  }
+    /**
+     * Set the "endT" parameter for the current command
+     *
+     * @param string $endT End time
+     *
+     * @return CreateItem
+     */
+    public function setEndT($endT)
+    {
+        return $this->set("pio_endT", $endT);
+    }
 
-  /**
-   * Set the "latlng" parameter for the current command
-   *
-   * In "latitude,longitude" format, e.g. "20.17,114.08"
-   *
-   * @param string $latlng Latitude and longitude
-   *
-   * @return CreateItem
-   */
-  public function setLatlng($latlng)
-  {
-    return $this->set("pio_latlng", $latlng);
-  }
+    /**
+     * Set the "price" parameter for the current command
+     *
+     * @param float $price Price
+     *
+     * @return CreateItem
+     */
+    public function setPrice($price)
+    {
+        return $this->set("pio_price", $price);
+    }
 
-  /**
-   * Set the "inactive" parameter for the current command
-   *
-   * @param string $inactive Inactive flag (use "true" or "false" string)
-   *
-   * @return CreateItem
-   */
-  public function setInactive($inactive)
-  {
-    return $this->set("inactive", $inactive);
-  }
+    /**
+     * Set the "profit" parameter for the current command
+     *
+     * @param float $profit Profit
+     *
+     * @return CreateItem
+     */
+    public function setProfit($profit)
+    {
+        return $this->set("pio_profit", $profit);
+    }
 
-  /**
-   * Create the request object that will carry out the command. Used internally by Guzzle.
-   */
-  protected function build()
-  {
-    $this->request = $this->client->createRequest(RequestInterface::POST, 'items', null, $this->getAll());
-  }
+    /**
+     * Set the "latlng" parameter for the current command
+     *
+     * In "latitude,longitude" format, e.g. "20.17,114.08"
+     *
+     * @param string $lat Latitude
+     * @param string $lng Longitude
+     *
+     * @return CreateItem
+     */
+    public function setLatlng($lat, $lng = null)
+    {
+        if (null === $lng) {
+            return $this->set("pio_latlng", $lat);
+        }
+
+        return $this->set("pio_latlng", sprintf("%s,%s", $lat, $lng));
+    }
+
+    /**
+     * Set the "inactive" parameter for the current command
+     *
+     * @param string $inactive Inactive flag (use "true" or "false" string)
+     *
+     * @return CreateItem
+     */
+    public function setInactive($inactive)
+    {
+        return $this->set("pio_inactive", $inactive);
+    }
+
+    /**
+     * Create the request object that will carry out the command. Used internally by Guzzle.
+     */
+    protected function build()
+    {
+        $this->request = $this->client->createRequest(RequestInterface::POST, 'items', null, $this->getAll());
+    }
 }
-
-?>
\ No newline at end of file
diff --git a/src/PredictionIO/Command/CreateUser.php b/src/PredictionIO/Command/CreateUser.php
index 11e7979..0a3c380 100644
--- a/src/PredictionIO/Command/CreateUser.php
+++ b/src/PredictionIO/Command/CreateUser.php
@@ -10,7 +10,8 @@
  *
  * Create or re-create an information record for a user. Re-creation will remove all data of the current record.
  *
- * To supply custom user information, simply pass it in during command creation, or use the "set" method inherited from Guzzle\Common\Collection.
+ * To supply custom user information, simply pass it in during command creation,
+ * or use the "set" method inherited from Guzzle\Common\Collection.
  * <code>
  * $command = $client->getCommand('create_user', array('pio_uid' => 'foobar', 'custom1' => 'baz'));
  * $command->set('custom2', '0xdeadbeef');
@@ -22,51 +23,54 @@
  */
 class CreateUser extends AbstractCommand
 {
-  /**
-   * Set the "uid" parameter for the current command
-   *
-   * @param string $uid User ID
-   *
-   * @return CreateUser
-   */
-  public function setUid($uid)
-  {
-    return $this->set("pio_uid", $uid);
-  }
+    /**
+     * Set the "uid" parameter for the current command
+     *
+     * @param string $uid User ID
+     *
+     * @return CreateUser
+     */
+    public function setUid($uid)
+    {
+        return $this->set("pio_uid", $uid);
+    }
 
-  /**
-   * Set the "latlng" parameter for the current command
-   *
-   * In "latitude,longitude" format, e.g. "20.17,114.08"
-   *
-   * @param string $latlng Latitude and longitude
-   *
-   * @return CreateUser
-   */
-  public function setLatlng($latlng)
-  {
-    return $this->set("pio_latlng", $latlng);
-  }
+    /**
+     * Set the "latlng" parameter for the current command
+     *
+     * In "latitude,longitude" format, e.g. "20.17,114.08"
+     *
+     * @param string $lat Latitude
+     * @param string $lng Longitude
+     *
+     * @return CreateUser
+     */
+    public function setLatlng($lat, $lng = null)
+    {
+        if (null === $lng) {
+            return $this->set("pio_latlng", $lat);
+        }
 
-  /**
-   * Set the "inactive" parameter for the current command
-   *
-   * @param bool $inactive Inactive flag (use "true" or "false" string)
-   *
-   * @return CreateUser
-   */
-  public function setInactive($inactive)
-  {
-    return $this->set("pio_inactive", $inactive);
-  }
+        return $this->set("pio_latlng", sprintf("%s,%s", $lat, $lng));
+    }
 
-  /**
-   * Create the request object that will carry out the command. Used internally by Guzzle.
-   */
-  protected function build()
-  {
-    $this->request = $this->client->createRequest(RequestInterface::POST, 'users', null, $this->getAll());
-  }
+    /**
+     * Set the "inactive" parameter for the current command
+     *
+     * @param bool $inactive Inactive flag (use "true" or "false" string)
+     *
+     * @return CreateUser
+     */
+    public function setInactive($inactive)
+    {
+        return $this->set("pio_inactive", $inactive);
+    }
+
+    /**
+     * Create the request object that will carry out the command. Used internally by Guzzle.
+     */
+    protected function build()
+    {
+        $this->request = $this->client->createRequest(RequestInterface::POST, 'users', null, $this->getAll());
+    }
 }
-
-?>
\ No newline at end of file
diff --git a/src/PredictionIO/Command/DeleteItem.php b/src/PredictionIO/Command/DeleteItem.php
index 7f6f42b..c8df188 100644
--- a/src/PredictionIO/Command/DeleteItem.php
+++ b/src/PredictionIO/Command/DeleteItem.php
@@ -14,25 +14,23 @@
  */
 class DeleteItem extends AbstractCommand
 {
-  /**
-   * Set the "iid" parameter for the current command
-   *
-   * @param string $iid Item ID
-   *
-   * @return DeleteItem
-   */
-  public function setIid($iid)
-  {
-    return $this->set('pio_iid', $iid);
-  }
+    /**
+     * Set the "iid" parameter for the current command
+     *
+     * @param string $iid Item ID
+     *
+     * @return DeleteItem
+     */
+    public function setIid($iid)
+    {
+        return $this->set('pio_iid', $iid);
+    }
 
-  /**
-   * Create the request object that will carry out the command. Used internally by Guzzle.
-   */
-  protected function build()
-  {
-    $this->request = $this->client->createRequest(RequestInterface::DELETE, 'items/' . $this->get('pio_iid'));
-  }
+    /**
+     * Create the request object that will carry out the command. Used internally by Guzzle.
+     */
+    protected function build()
+    {
+        $this->request = $this->client->createRequest(RequestInterface::DELETE, 'items/' . $this->get('pio_iid'));
+    }
 }
-
-?>
\ No newline at end of file
diff --git a/src/PredictionIO/Command/DeleteUser.php b/src/PredictionIO/Command/DeleteUser.php
index e7eaee6..4df9c1d 100644
--- a/src/PredictionIO/Command/DeleteUser.php
+++ b/src/PredictionIO/Command/DeleteUser.php
@@ -14,25 +14,23 @@
  */
 class DeleteUser extends AbstractCommand
 {
-  /**
-   * Set the "uid" parameter for the current command
-   *
-   * @param string $uid User ID
-   *
-   * @return DeleteUser
-   */
-  public function setUid($uid)
-  {
-    return $this->set('pio_uid', $uid);
-  }
+    /**
+     * Set the "uid" parameter for the current command
+     *
+     * @param string $uid User ID
+     *
+     * @return DeleteUser
+     */
+    public function setUid($uid)
+    {
+        return $this->set('pio_uid', $uid);
+    }
 
-  /**
-   * Create the request object that will carry out the command. Used internally by Guzzle.
-   */
-  protected function build()
-  {
-    $this->request = $this->client->createRequest(RequestInterface::DELETE, 'users/' . $this->get('pio_uid'));
-  }
+    /**
+     * Create the request object that will carry out the command. Used internally by Guzzle.
+     */
+    protected function build()
+    {
+        $this->request = $this->client->createRequest(RequestInterface::DELETE, 'users/' . $this->get('pio_uid'));
+    }
 }
-
-?>
\ No newline at end of file
diff --git a/src/PredictionIO/Command/GetItem.php b/src/PredictionIO/Command/GetItem.php
index 4912fb2..368c595 100644
--- a/src/PredictionIO/Command/GetItem.php
+++ b/src/PredictionIO/Command/GetItem.php
@@ -15,25 +15,23 @@
  */
 class GetItem extends AbstractCommand
 {
-  /**
-   * Set the "iid" parameter for the current command
-   *
-   * @param string $iid Item ID
-   *
-   * @return GetItem
-   */
-  public function setIid($iid)
-  {
-    return $this->set('pio_iid', $iid);
-  }
+    /**
+     * Set the "iid" parameter for the current command
+     *
+     * @param string $iid Item ID
+     *
+     * @return GetItem
+     */
+    public function setIid($iid)
+    {
+        return $this->set('pio_iid', $iid);
+    }
 
-  /**
-   * Create the request object that will carry out the command. Used internally by Guzzle.
-   */
-  protected function build()
-  {
-    $this->request = $this->client->createRequest(RequestInterface::GET, 'items/' . $this->get('pio_iid'));
-  }
+    /**
+     * Create the request object that will carry out the command. Used internally by Guzzle.
+     */
+    protected function build()
+    {
+        $this->request = $this->client->createRequest(RequestInterface::GET, 'items/' . $this->get('pio_iid'));
+    }
 }
-
-?>
\ No newline at end of file
diff --git a/src/PredictionIO/Command/GetUser.php b/src/PredictionIO/Command/GetUser.php
index 988d4fa..0a1a0c4 100644
--- a/src/PredictionIO/Command/GetUser.php
+++ b/src/PredictionIO/Command/GetUser.php
@@ -14,25 +14,23 @@
  */
 class GetUser extends AbstractCommand
 {
-  /**
-   * Set the "uid" parameter for the current command
-   *
-   * @param string $uid User ID
-   *
-   * @return GetUser
-   */
-  public function setUid($uid)
-  {
-    return $this->set('pio_uid', $uid);
-  }
+    /**
+     * Set the "uid" parameter for the current command
+     *
+     * @param string $uid User ID
+     *
+     * @return GetUser
+     */
+    public function setUid($uid)
+    {
+        return $this->set('pio_uid', $uid);
+    }
 
-  /**
-   * Create the request object that will carry out the command. Used internally by Guzzle.
-   */
-  protected function build()
-  {
-    $this->request = $this->client->createRequest(RequestInterface::GET, 'users/' . $this->get('pio_uid'));
-  }
+    /**
+     * Create the request object that will carry out the command. Used internally by Guzzle.
+     */
+    protected function build()
+    {
+        $this->request = $this->client->createRequest(RequestInterface::GET, 'users/' . $this->get('pio_uid'));
+    }
 }
-
-?>
\ No newline at end of file
diff --git a/src/PredictionIO/Command/ItemrecGetTopN.php b/src/PredictionIO/Command/ItemrecGetTopN.php
index 10cad36..a319483 100644
--- a/src/PredictionIO/Command/ItemrecGetTopN.php
+++ b/src/PredictionIO/Command/ItemrecGetTopN.php
@@ -19,94 +19,102 @@
  */
 class ItemrecGetTopN extends AbstractCommand
 {
-  /**
-   * Set the "engine" parameter for the current command
-   *
-   * @param string $engine Engine Name
-   *
-   * @return ItemrecGetTopN
-   */
-  public function setEngine($engine)
-  {
-    return $this->set('pio_engine', $engine);
-  }
-
-  /**
-   * Set the "n" parameter for the current command
-   *
-   * @param integer $n N
-   *
-   * @return ItemrecGetTopN
-   */
-  public function setN($n)
-  {
-    return $this->set('pio_n', $n);
-  }
-
-  /**
-   * Set the "itypes" parameter for the current command
-   *
-   * $itypes can be supplied as an array of integers, or a "," delimited list of integers.
-   *
-   * @param array|string $itypes Item types
-   *
-   * @return ItemrecGetTopN
-   */
-  public function setItypes($itypes)
-  {
-    if (is_array($itypes)) {
-      return $this->set('pio_itypes', implode(',', $itypes));
-    } else {
-      return $this->set('pio_itypes', $itypes);
+    /**
+     * Set the "engine" parameter for the current command
+     *
+     * @param string $engine Engine Name
+     *
+     * @return ItemrecGetTopN
+     */
+    public function setEngine($engine)
+    {
+        return $this->set('pio_engine', $engine);
     }
-  }
 
-  /**
-   * Set the "latlng" parameter for the current command
-   *
-   * In "latitude,longitude" format, e.g. "20.17,114.08"
-   *
-   * @param string $latlng Latitude and longitude
-   *
-   * @return ItemrecGetTopN
-   */
-  public function setLatlng($latlng)
-  {
-    return $this->set('pio_latlng', $latlng);
-  }
+    /**
+     * Set the "n" parameter for the current command
+     *
+     * @param integer $n N
+     *
+     * @return ItemrecGetTopN
+     */
+    public function setN($n)
+    {
+        return $this->set('pio_n', $n);
+    }
 
-  /**
-   * Set the "within" parameter for the current command
-   *
-   * @param float $within Radius
-   *
-   * @return ItemrecGetTopN
-   */
-  public function setWithin($within)
-  {
-    return $this->set('pio_within', $within);
-  }
+    /**
+     * Set the "itypes" parameter for the current command
+     *
+     * $itypes can be supplied as an array of integers, or a "," delimited list of integers.
+     *
+     * @param array|string $itypes Item types
+     *
+     * @return ItemrecGetTopN
+     */
+    public function setItypes($itypes)
+    {
+        if (is_array($itypes)) {
+            return $this->set('pio_itypes', implode(',', $itypes));
+        } else {
+            return $this->set('pio_itypes', $itypes);
+        }
+    }
 
-  /**
-   * Set the "unit" parameter for the current command
-   *
-   * @param string $unit Unit of radius
-   *
-   * @return ItemrecGetTopN
-   */
-  public function setUnit($unit)
-  {
-    return $this->set('pio_unit', $unit);
-  }
+    /**
+     * Set the "latlng" parameter for the current command
+     *
+     * In "latitude,longitude" format, e.g. "20.17,114.08"
+     *
+     * @param string $lat Latitude
+     * @param string $lng Longitude
+     *
+     * @return ItemrecGetTopN
+     */
+    public function setLatlng($lat,$lng=null)
+    {
+        if ($lng === null) {
+            return $this->set("pio_latlng", $lat);
+        } else {
+            return $this->set("pio_latlng", sprintf("%s,%s", $lat, $lng));
+        }
+    }
 
-  /**
-   * Create the request object that will carry out the command. Used internally by Guzzle.
-   */
-  protected function build()
-  {
-    $this->set('pio_uid', $this->client->getIdentity());
-    $this->request = $this->client->createRequest(RequestInterface::GET, 'engines/itemrec/' . $this->get('pio_engine') . '/topn', null, $this->getAll());
-  }
+    /**
+     * Set the "within" parameter for the current command
+     *
+     * @param float $within Radius
+     *
+     * @return ItemrecGetTopN
+     */
+    public function setWithin($within)
+    {
+        return $this->set('pio_within', $within);
+    }
+
+    /**
+     * Set the "unit" parameter for the current command
+     *
+     * @param string $unit Unit of radius
+     *
+     * @return ItemrecGetTopN
+     */
+    public function setUnit($unit)
+    {
+        return $this->set('pio_unit', $unit);
+    }
+
+    /**
+     * Create the request object that will carry out the command. Used internally by Guzzle.
+     */
+    protected function build()
+    {
+        $this->set('pio_uid', $this->client->getIdentity());
+        $this->request = $this->client->createRequest(
+            RequestInterface::GET,
+            'engines/itemrec/' . $this->get('pio_engine') . '/topn',
+            null,
+            $this->getAll()
+        );
+    }
 }
-
-?>
\ No newline at end of file
diff --git a/src/PredictionIO/Command/ItemsimGetTopN.php b/src/PredictionIO/Command/ItemsimGetTopN.php
index 5108758..217f810 100644
--- a/src/PredictionIO/Command/ItemsimGetTopN.php
+++ b/src/PredictionIO/Command/ItemsimGetTopN.php
@@ -20,105 +20,113 @@
  */
 class ItemsimGetTopN extends AbstractCommand
 {
-  /**
-   * Set the "engine" parameter for the current command
-   *
-   * @param string $engine Engine Name
-   *
-   * @return ItemsimGetTopN
-   */
-  public function setEngine($engine)
-  {
-    return $this->set('pio_engine', $engine);
-  }
-
-  /**
-   * Set the "iid" parameter for the current command
-   *
-   * @param string $iid Item ID
-   *
-   * @return ItemsimGetTopN
-   */
-  public function setIid($iid)
-  {
-    return $this->set('pio_iid', $iid);
-  }
-
-  /**
-   * Set the "n" parameter for the current command
-   *
-   * @param integer $n N
-   *
-   * @return ItemsimGetTopN
-   */
-  public function setN($n)
-  {
-    return $this->set('pio_n', $n);
-  }
-
-  /**
-   * Set the "itypes" parameter for the current command
-   *
-   * $itypes can be supplied as an array of integers, or a "," delimited list of integers.
-   *
-   * @param array|string $itypes Item types
-   *
-   * @return ItemsimGetTopN
-   */
-  public function setItypes($itypes)
-  {
-    if (is_array($itypes)) {
-      return $this->set('pio_itypes', implode(',', $itypes));
-    } else {
-      return $this->set('pio_itypes', $itypes);
+    /**
+     * Set the "engine" parameter for the current command
+     *
+     * @param string $engine Engine Name
+     *
+     * @return ItemsimGetTopN
+     */
+    public function setEngine($engine)
+    {
+        return $this->set('pio_engine', $engine);
     }
-  }
 
-  /**
-   * Set the "latlng" parameter for the current command
-   *
-   * In "latitude,longitude" format, e.g. "20.17,114.08"
-   *
-   * @param string $latlng Latitude and longitude
-   *
-   * @return ItemsimGetTopN
-   */
-  public function setLatlng($latlng)
-  {
-    return $this->set('pio_latlng', $latlng);
-  }
+    /**
+     * Set the "iid" parameter for the current command
+     *
+     * @param string $iid Item ID
+     *
+     * @return ItemsimGetTopN
+     */
+    public function setIid($iid)
+    {
+        return $this->set('pio_iid', $iid);
+    }
 
-  /**
-   * Set the "within" parameter for the current command
-   *
-   * @param float $within Radius
-   *
-   * @return ItemsimGetTopN
-   */
-  public function setWithin($within)
-  {
-    return $this->set('pio_within', $within);
-  }
+    /**
+     * Set the "n" parameter for the current command
+     *
+     * @param integer $n N
+     *
+     * @return ItemsimGetTopN
+     */
+    public function setN($n)
+    {
+        return $this->set('pio_n', $n);
+    }
 
-  /**
-   * Set the "unit" parameter for the current command
-   *
-   * @param string $unit Unit of radius
-   *
-   * @return ItemsimGetTopN
-   */
-  public function setUnit($unit)
-  {
-    return $this->set('pio_unit', $unit);
-  }
+    /**
+     * Set the "itypes" parameter for the current command
+     *
+     * $itypes can be supplied as an array of integers, or a "," delimited list of integers.
+     *
+     * @param array|string $itypes Item types
+     *
+     * @return ItemsimGetTopN
+     */
+    public function setItypes($itypes)
+    {
+        if (is_array($itypes)) {
+            return $this->set('pio_itypes', implode(',', $itypes));
+        }
 
-  /**
-   * Create the request object that will carry out the command. Used internally by Guzzle.
-   */
-  protected function build()
-  {
-    $this->request = $this->client->createRequest(RequestInterface::GET, 'engines/itemsim/' . $this->get('pio_engine') . '/topn', null, $this->getAll());
-  }
+        return $this->set('pio_itypes', $itypes);
+    }
+
+    /**
+     * Set the "latlng" parameter for the current command
+     *
+     * In "latitude,longitude" format, e.g. "20.17,114.08"
+     *
+     * @param string $lat Latitude
+     * @param string $lng Longitude
+     *
+     * @return ItemsimGetTopN
+     */
+    public function setLatlng($lat,$lng=null)
+    {
+        if ($lng === null) {
+            return $this->set("pio_latlng", $lat);
+        } else {
+            return $this->set("pio_latlng", sprintf("%s,%s", $lat, $lng));
+        }
+    }
+
+    /**
+     * Set the "within" parameter for the current command
+     *
+     * @param float $within Radius
+     *
+     * @return ItemsimGetTopN
+     */
+    public function setWithin($within)
+    {
+        return $this->set('pio_within', $within);
+    }
+
+    /**
+     * Set the "unit" parameter for the current command
+     *
+     * @param string $unit Unit of radius
+     *
+     * @return ItemsimGetTopN
+     */
+    public function setUnit($unit)
+    {
+        return $this->set('pio_unit', $unit);
+    }
+
+    /**
+     * Create the request object that will carry out the command. Used internally by Guzzle.
+     */
+    protected function build()
+    {
+        $this->request = $this->client->createRequest(
+            RequestInterface::GET,
+            'engines/itemsim/' . $this->get('pio_engine') . '/topn',
+            null,
+            $this->getAll()
+        );
+    }
 }
-
-?>
\ No newline at end of file
diff --git a/src/PredictionIO/Command/RecordActionOnItem.php b/src/PredictionIO/Command/RecordActionOnItem.php
index 382db3f..09e3d57 100644
--- a/src/PredictionIO/Command/RecordActionOnItem.php
+++ b/src/PredictionIO/Command/RecordActionOnItem.php
@@ -16,64 +16,67 @@
  */
 class RecordActionOnItem extends AbstractCommand
 {
-  /**
-   * Set the "action" parameter for the current command
-   *
-   * @param string $action Action name
-   *
-   * @return RecordActionOnItem
-   */
-  public function setAction($action)
-  {
-    return $this->set('pio_action', $action);
-  }
+    /**
+     * Set the "action" parameter for the current command
+     *
+     * @param string $action Action name
+     *
+     * @return RecordActionOnItem
+     */
+    public function setAction($action)
+    {
+        return $this->set('pio_action', $action);
+    }
 
-  /**
-   * Set the "iid" parameter for the current command
-   *
-   * @param string $iid Item ID
-   *
-   * @return RecordActionOnItem
-   */
-  public function setIid($iid)
-  {
-    return $this->set('pio_iid', $iid);
-  }
+    /**
+     * Set the "iid" parameter for the current command
+     *
+     * @param string $iid Item ID
+     *
+     * @return RecordActionOnItem
+     */
+    public function setIid($iid)
+    {
+        return $this->set('pio_iid', $iid);
+    }
 
-  /**
-   * Set the "t" parameter for the current command
-   *
-   * @param string $t Time
-   *
-   * @return RecordActionOnItem
-   */
-  public function setT($t)
-  {
-    return $this->set('pio_t', $t*1000);
-  }
+    /**
+     * Set the "t" parameter for the current command
+     *
+     * @param string $t Time
+     *
+     * @return RecordActionOnItem
+     */
+    public function setT($t)
+    {
+        return $this->set('pio_t', $t * 1000);
+    }
 
-  /**
-   * Set the "latlng" parameter for the current command
-   *
-   * In "latitude,longitude" format, e.g. "20.17,114.08"
-   *
-   * @param string $latlng Latitude and longitude
-   *
-   * @return RecordActionOnItem
-   */
-  public function setLatlng($latlng)
-  {
-    return $this->set('pio_latlng', $latlng);
-  }
+    /**
+     * Set the "latlng" parameter for the current command
+     *
+     * In "latitude,longitude" format, e.g. "20.17,114.08"
+     *
+     * @param string $lat Latitude
+     * @param string $lng Longitude
+     *
+     * @return RecordActionOnItem
+     */
+    public function setLatlng($lat, $lng = null)
+    {
+        if (null === $lng) {
+            return $this->set("pio_latlng", $lat);
+        }
 
-  /**
-   * Create the request object that will carry out the command. Used internally by Guzzle.
-   */
-  protected function build()
-  {
-    $this->set('pio_uid', $this->client->getIdentity());
-    $this->request = $this->client->createRequest(RequestInterface::POST, 'actions/u2i', null, $this->getAll());
-  }
+        return $this->set("pio_latlng", sprintf("%s,%s", $lat, $lng));
+    }
+
+    /**
+     * Create the request object that will carry out the command. Used internally by Guzzle.
+     */
+    protected function build()
+    {
+        $this->set('pio_uid', $this->client->getIdentity());
+        $this->request = $this->client->createRequest(RequestInterface::POST, 'actions/u2i', null, $this->getAll());
+    }
 }
-
-?>
\ No newline at end of file
diff --git a/src/PredictionIO/PredictionIOClient.php b/src/PredictionIO/PredictionIOClient.php
index 4717bb0..3a5f3e2 100644
--- a/src/PredictionIO/PredictionIOClient.php
+++ b/src/PredictionIO/PredictionIOClient.php
@@ -3,6 +3,7 @@
 namespace PredictionIO;
 
 use Guzzle\Http\Message\RequestInterface;
+use Guzzle\Http\EntityBodyInterface;
 use Guzzle\Common\Collection;
 use Guzzle\Service\Client;
 use Guzzle\Service\Command\AbstractCommand;
@@ -13,7 +14,8 @@
  * This package is a web service client based on Guzzle.
  * A few quick examples are shown below.
  * For a full user guide on how to take advantage of all Guzzle features, please refer to http://guzzlephp.org.
- * Specifically, http://guzzlephp.org/tour/using_services.html#using-client-objects describes how to use a web service client.
+ * Specifically, http://guzzlephp.org/tour/using_services.html#using-client-objects describes
+ * how to use a web service client.
  *
  * Many REST request commands support optional arguments. They can be supplied to these commands using the set method.
  *
@@ -52,93 +54,92 @@
  */
 class PredictionIOClient extends Client
 {
-  private $apiuid = "";
+    private $apiuid = NULL;
 
-  /**
-   * Factory method to create a new PredictionIOClient
-   *
-   * Configuration data is an array with these keys:
-   * * appkey - App key of your PredictionIO app (required)
-   * * apiurl - URL of API endpoint (optional)
-   *
-   * @param array|Collection $config Configuration data.
-   *
-   * @return PredictionIOClient
-   */
-  public static function factory($config = array())
-  {
-    $default = array('apiurl' => 'http://localhost:8000');
-    $required = array('appkey');
-    $config = Collection::fromConfig($config, $default, $required);
+    /**
+     * Factory method to create a new PredictionIOClient
+     *
+     * Configuration data is an array with these keys:
+     * * appkey - App key of your PredictionIO app (required)
+     * * apiurl - URL of API endpoint (optional)
+     *
+     * @param array|Collection $config Configuration data.
+     *
+     * @return PredictionIOClient
+     */
+    public static function factory($config = array())
+    {
+        $default = array('apiurl' => 'http://localhost:8000');
+        $required = array('appkey');
+        $config = Collection::fromConfig($config, $default, $required);
 
-    $client = new self($config->get('apiurl'), $config);
+        $client = new self($config->get('apiurl'), $config);
 
-    return $client;
-  }
-
-  /**
-   * Identify the user ID that will be used by all subsequent recording of actions on items, and recommendations retrieval.
-   *
-   * @param string $uid User ID.
-   */
-  public function identify($uid)
-  {
-    $this->apiuid = $uid;
-  }
-
-  /**
-   * Returns the identity (user ID) that will be used by all subsequent recording of actions on items, and recommendations retrieval.
-   *
-   * @returns string
-   */
-  public function getIdentity()
-  {
-    if (empty($this->apiuid)) {
-      throw new UnidentifiedUserException("Must call identify() before performing any user-related commands.");
-    }
-    return $this->apiuid;
-  }
-
-  /**
-   * Create and return a new Guzzle\Http\Message\RequestInterface configured for the client.
-   *
-   * Used internally by the library. Do not use directly.
-   *
-   * @param string $method HTTP method. Default to GET.
-   * @param string|array $uri Resource URI
-   * @param array|Guzzle\Common\Collection $headers HTTP headers
-   * @param string|resource|array|Guzzle\Http\EntityBodyInterface $body Entity body of request (POST/PUT) or response (GET)
-   *
-   * @returns Guzzle\Http\Message\RequestInterface
-   */
-  public function createRequest($method = Guzzle\Http\Message\RequestInterface::GET, $uri = null, $headers = null, $body = null)
-  {
-    if (is_array($body)) {
-      $body['pio_appkey'] = $this->getConfig()->get("appkey");
-    } else {
-      $body = array('pio_appkey' => $this->getConfig()->get("appkey"));
+        return $client;
     }
 
-    // Remove Guzzle internals to prevent them from going to the API
-    unset($body[AbstractCommand::HEADERS_OPTION]);
-    unset($body[AbstractCommand::ON_COMPLETE]);
-    unset($body[AbstractCommand::DISABLE_VALIDATION]);
-    unset($body[AbstractCommand::RESPONSE_PROCESSING]);
-    unset($body[AbstractCommand::RESPONSE_BODY]);
-
-    if ($method == RequestInterface::GET ||
-        $method == RequestInterface::DELETE) {
-      $request = parent::createRequest($method, $uri, $headers, null);
-      $request->getQuery()->replace($body);
-    } else {
-      $request = parent::createRequest($method, $uri, $headers, $body);
+    /**
+     * Identify the user ID that will be used by all subsequent
+     * recording of actions on items, and recommendations retrieval.
+     *
+     * @param string $uid User ID.
+     */
+    public function identify($uid)
+    {
+        $this->apiuid = $uid;
     }
-    $request->setPath($request->getPath() . ".json");
-    return $request;
-  }
-}
 
-/**
- * Thrown when user-related commands are called before identify() is called.
- */
-class UnidentifiedUserException extends \Exception { }
+    /**
+     * Returns the identity (user ID) that will be used by all subsequent
+     * recording of actions on items, and recommendations retrieval.
+     *
+     * @return string
+     * @throws UnidentifiedUserException
+     */
+    public function getIdentity()
+    {
+        if (!isset($this->apiuid)) {
+            throw new UnidentifiedUserException("Must call identify() before performing any user-related commands.");
+        }
+
+        return $this->apiuid;
+    }
+
+    /**
+     * Create and return a new RequestInterface configured for the client.
+     *
+     * Used internally by the library. Do not use directly.
+     *
+     * @param string                                    $method  HTTP method. Default to GET.
+     * @param string|array                              $uri     Resource URI
+     * @param array|Collection                          $headers HTTP headers
+     * @param string|resource|array|EntityBodyInterface $body    Entity body of request (POST/PUT) or response (GET)
+     *
+     * @return RequestInterface
+     */
+    public function createRequest($method = RequestInterface::GET, $uri = null, $headers = null, $body = null)
+    {
+        if (is_array($body)) {
+            $body['pio_appkey'] = $this->getConfig()->get("appkey");
+        } else {
+            $body = array('pio_appkey' => $this->getConfig()->get("appkey"));
+        }
+
+        // Remove Guzzle internals to prevent them from going to the API
+        unset($body[AbstractCommand::HEADERS_OPTION]);
+        unset($body[AbstractCommand::ON_COMPLETE]);
+        unset($body[AbstractCommand::DISABLE_VALIDATION]);
+        unset($body[AbstractCommand::RESPONSE_PROCESSING]);
+        unset($body[AbstractCommand::RESPONSE_BODY]);
+
+        if ($method == RequestInterface::GET || $method == RequestInterface::DELETE) {
+            $request = parent::createRequest($method, $uri, $headers, null);
+            $request->getQuery()->replace($body);
+        } else {
+            $request = parent::createRequest($method, $uri, $headers, $body);
+        }
+        $request->setPath($request->getPath() . ".json");
+
+        return $request;
+    }
+}
\ No newline at end of file
diff --git a/src/PredictionIO/UnidentifiedUserException.php b/src/PredictionIO/UnidentifiedUserException.php
new file mode 100644
index 0000000..637fda1
--- /dev/null
+++ b/src/PredictionIO/UnidentifiedUserException.php
@@ -0,0 +1,11 @@
+<?php
+
+namespace PredictionIO;
+
+/**
+ * Thrown when user-related commands are called before identify() is called.
+ */
+class UnidentifiedUserException extends \Exception
+{
+
+}
diff --git a/tests/Unit/Command/CreateItemTest.php b/tests/Unit/Command/CreateItemTest.php
new file mode 100644
index 0000000..09d9a67
--- /dev/null
+++ b/tests/Unit/Command/CreateItemTest.php
@@ -0,0 +1,98 @@
+<?php
+
+namespace PredictionIO\Tests\Unit\Command;
+
+use PredictionIO\Command\CreateItem;
+
+/**
+ * Class CreateItemTest
+ *
+ * @package PredictionIO\Tests\Unit\Command
+ */
+class CreateItemTest extends \PHPUnit_Framework_TestCase
+{
+    public function testCreateItemSetIid()
+    {
+        $mockIid = '1234';
+        $createItemCommand = new CreateItem();
+        $createItemCommand->setIid($mockIid);
+
+        $this->assertSame($mockIid, $createItemCommand->get('pio_iid'));
+    }
+
+    public function testCreateItemSetItypesImplodesAnArrayToCommaDelimitedString()
+    {
+        $mockTypes = array(
+            'happy',
+            'mocked',
+            'types',
+        );
+        $createItemCommand = new CreateItem();
+        $createItemCommand->setItypes($mockTypes);
+
+        $this->assertSame(implode(',', $mockTypes), $createItemCommand->get('pio_itypes'));
+    }
+
+    public function testCreateItemSetItypesFromString()
+    {
+        $mockType = 'happy.mocked.type';
+        $createItemCommand = new CreateItem();
+        $createItemCommand->setItypes($mockType);
+
+        $this->assertSame($mockType, $createItemCommand->get('pio_itypes'));
+    }
+
+    public function testCreateItemSetStartTSuccess()
+    {
+        $mockStartT = 'mock.startT';
+        $createItemCommand = new CreateItem();
+        $createItemCommand->setStartT($mockStartT);
+
+        $this->assertSame($mockStartT, $createItemCommand->get('pio_startT'));
+    }
+
+    public function testCreateItemSetEndTSuccess()
+    {
+        $mockEndT = 'mock.endT';
+        $createItemCommand = new CreateItem();
+        $createItemCommand->setEndT($mockEndT);
+
+        $this->assertSame($mockEndT, $createItemCommand->get('pio_endT'));
+    }
+
+    public function testCreateItemSetPriceSuccess()
+    {
+        $mockPrice = '1234.56';
+        $createItemCommand = new CreateItem();
+        $createItemCommand->setPrice($mockPrice);
+
+        $this->assertSame($mockPrice, $createItemCommand->get('pio_price'));
+    }
+
+    public function testCreateItemSetProfitSuccess()
+    {
+        $mockProfit = '9876.54';
+        $createItemCommand = new CreateItem();
+        $createItemCommand->setProfit($mockProfit);
+
+        $this->assertSame($mockProfit, $createItemCommand->get('pio_profit'));
+    }
+
+    public function testCreateItemSetLatlngSuccess()
+    {
+        $mockLatlng = '20.17,114.08';
+        $createItemCommand = new CreateItem();
+        $createItemCommand->setLatlng($mockLatlng);
+
+        $this->assertSame($mockLatlng, $createItemCommand->get('pio_latlng'));
+    }
+
+    public function testCreateItemSetInactiveSuccess()
+    {
+        $mockInactive = 'true';
+        $createItemCommand = new CreateItem();
+        $createItemCommand->setInactive($mockInactive);
+
+        $this->assertSame($mockInactive, $createItemCommand->get('pio_inactive'));
+    }
+}
diff --git a/tests/Unit/Command/CreateUserTest.php b/tests/Unit/Command/CreateUserTest.php
new file mode 100644
index 0000000..15ff7ba
--- /dev/null
+++ b/tests/Unit/Command/CreateUserTest.php
@@ -0,0 +1,40 @@
+<?php
+
+namespace PredictionIO\Tests\Unit\Command;
+
+use PredictionIO\Command\CreateUser;
+
+/**
+ * Class CreateUserTest
+ *
+ * @package PredictionIO\Tests\Unit\Command
+ */
+class CreateUserTest extends \PHPUnit_Framework_TestCase
+{
+    public function testCreateUserSetIid()
+    {
+        $mockUid = '1234';
+        $createUserCommand = new CreateUser();
+        $createUserCommand->setUid($mockUid);
+
+        $this->assertSame($mockUid, $createUserCommand->get('pio_uid'));
+    }
+
+    public function testCreateUserSetLatlngSuccess()
+    {
+        $mockLatlng = '20.17,114.08';
+        $createUserCommand = new CreateUser();
+        $createUserCommand->setLatlng($mockLatlng);
+
+        $this->assertSame($mockLatlng, $createUserCommand->get('pio_latlng'));
+    }
+
+    public function testCreateUserSetInactiveSuccess()
+    {
+        $mockInactive = 'true';
+        $createUserCommand = new CreateUser();
+        $createUserCommand->setInactive($mockInactive);
+
+        $this->assertSame($mockInactive, $createUserCommand->get('pio_inactive'));
+    }
+}
diff --git a/tests/Unit/Command/DeleteItemTest.php b/tests/Unit/Command/DeleteItemTest.php
new file mode 100644
index 0000000..5ab8cad
--- /dev/null
+++ b/tests/Unit/Command/DeleteItemTest.php
@@ -0,0 +1,22 @@
+<?php
+
+namespace PredictionIO\Tests\Unit\Command;
+
+use PredictionIO\Command\DeleteItem;
+
+/**
+ * Class DeleteItemTest
+ *
+ * @package PredictionIO\Tests\Unit\Command
+ */
+class DeleteItemTest extends \PHPUnit_Framework_TestCase
+{
+    public function testDeleteItemSetIid()
+    {
+        $mockIid = '1234';
+        $deleteItemCommand = new DeleteItem();
+        $deleteItemCommand->setIid($mockIid);
+
+        $this->assertSame($mockIid, $deleteItemCommand->get('pio_iid'));
+    }
+}
diff --git a/tests/Unit/Command/DeleteUserTest.php b/tests/Unit/Command/DeleteUserTest.php
new file mode 100644
index 0000000..4b92e02
--- /dev/null
+++ b/tests/Unit/Command/DeleteUserTest.php
@@ -0,0 +1,22 @@
+<?php
+
+namespace PredictionIO\Tests\Unit\Command;
+
+use PredictionIO\Command\DeleteUser;
+
+/**
+ * Class DeleteUserTest
+ *
+ * @package PredictionIO\Tests\Unit\Command
+ */
+class DeleteUserTest extends \PHPUnit_Framework_TestCase
+{
+    public function testDeleteUserSetIid()
+    {
+        $mockUid = '1234';
+        $deleteUserCommand = new DeleteUser();
+        $deleteUserCommand->setUid($mockUid);
+
+        $this->assertSame($mockUid, $deleteUserCommand->get('pio_uid'));
+    }
+}
diff --git a/tests/Unit/Command/GetItemTest.php b/tests/Unit/Command/GetItemTest.php
new file mode 100644
index 0000000..3609abd
--- /dev/null
+++ b/tests/Unit/Command/GetItemTest.php
@@ -0,0 +1,22 @@
+<?php
+
+namespace PredictionIO\Tests\Unit\Command;
+
+use PredictionIO\Command\GetItem;
+
+/**
+ * Class GetItemTest
+ *
+ * @package PredictionIO\Tests\Unit\Command
+ */
+class GetItemTest extends \PHPUnit_Framework_TestCase
+{
+    public function testGetItemSetIid()
+    {
+        $mockIid = '1234';
+        $getItemCommand = new GetItem();
+        $getItemCommand->setIid($mockIid);
+
+        $this->assertSame($mockIid, $getItemCommand->get('pio_iid'));
+    }
+}
diff --git a/tests/Unit/Command/GetUserTest.php b/tests/Unit/Command/GetUserTest.php
new file mode 100644
index 0000000..0c6f8eb
--- /dev/null
+++ b/tests/Unit/Command/GetUserTest.php
@@ -0,0 +1,22 @@
+<?php
+
+namespace PredictionIO\Tests\Unit\Command;
+
+use PredictionIO\Command\GetUser;
+
+/**
+ * Class GetUserTest
+ *
+ * @package PredictionIO\Tests\Unit\Command
+ */
+class GetUserTest extends \PHPUnit_Framework_TestCase
+{
+    public function testGetUserSetIid()
+    {
+        $mockUid = '1234';
+        $getUserCommand = new GetUser();
+        $getUserCommand->setUid($mockUid);
+
+        $this->assertSame($mockUid, $getUserCommand->get('pio_uid'));
+    }
+}
diff --git a/tests/Unit/PredictionIOClientTest.php b/tests/Unit/PredictionIOClientTest.php
new file mode 100644
index 0000000..2333eee
--- /dev/null
+++ b/tests/Unit/PredictionIOClientTest.php
@@ -0,0 +1,146 @@
+<?php
+
+namespace PredictionIO\Tests\Unit;
+
+use Guzzle\Common\Collection;
+use Guzzle\Http\Message\RequestInterface;
+use Guzzle\Service\Command\AbstractCommand;
+use PredictionIO\PredictionIOClient;
+
+/**
+ * Class PredictionIOClientTest
+ *
+ * @package PredictionIO\Tests
+ */
+class PredictionIOClientTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @expectedException \Guzzle\Common\Exception\InvalidArgumentException
+     * @expectedMessage   Config must contain a 'appkey' key
+     */
+    public function testFactoryThrowsExceptionWithNoAppKey()
+    {
+        $config = array();
+        PredictionIOClient::factory($config);
+    }
+
+    public function testFactoryReturnsNewClient()
+    {
+        $config = array(
+            'appkey' => 'mock.appkey',
+        );
+        $client = PredictionIOClient::factory($config);
+
+        $this->assertInstanceOf('\PredictionIO\PredictionIOClient', $client);
+        $this->assertSame($config['appkey'], $client->getConfig('appkey'));
+    }
+
+    public function testFactoryWithDefaultApiUrlSuccess()
+    {
+        $defaultApiUrl = 'http://localhost:8000';
+        $config = array(
+            'appkey' => 'mock.appkey',
+        );
+        $client = PredictionIOClient::factory($config);
+
+        $this->assertSame($defaultApiUrl, $client->getConfig('apiurl'));
+    }
+
+    public function testFactoryWithDefinedApiUrlSuccess()
+    {
+        $config = array(
+            'appkey' => 'mock.appkey',
+            'apiurl' => 'http://mock.api:1234',
+        );
+        $client = PredictionIOClient::factory($config);
+
+        $this->assertSame($client->getConfig('apiurl'), $client->getConfig('apiurl'));
+    }
+
+    public function testFactoryWithCustomConfigSuccess()
+    {
+        $config = array(
+            'appkey' => 'mock.appkey',
+            'customconfig' => 'mock.option',
+        );
+        $client = PredictionIOClient::factory($config);
+
+        $this->assertSame($client->getConfig('customconfig'), $client->getConfig('customconfig'));
+    }
+
+    /**
+     * @expectedException        \PredictionIO\UnidentifiedUserException
+     * @expectedExceptionMessage Must call identify() before performing any user-related commands.
+     */
+    public function testGetIdentityThrowsExceptionWhenNotSet()
+    {
+        $client = new PredictionIOClient();
+        $client->getIdentity();
+    }
+
+    public function testSetGetIdentitySuccess()
+    {
+        $mockId = "0";
+        $client = new PredictionIOClient();
+        $client->identify($mockId);
+
+        $this->assertSame($mockId, $client->getIdentity());
+    }
+
+    public function testCreateRequestReturnsRequestObject()
+    {
+        $client = new PredictionIOClient();
+        $request = $client->createRequest();
+
+        $this->assertInstanceOf('\Guzzle\Http\Message\Request', $request);
+    }
+
+    public function testCreateRequestSetMethodSuccess()
+    {
+        $mockMethod = RequestInterface::POST;
+        $client = new PredictionIOClient();
+        $request = $client->createRequest($mockMethod);
+
+        $this->assertSame($mockMethod, $request->getMethod());
+    }
+
+    public function testCreateRequestSetUriSuccess()
+    {
+        $mockUri = 'http://mock.uri/method';
+        $expectedUri = $mockUri.'.json?pio_appkey=';
+        $client = new PredictionIOClient();
+        $request = $client->createRequest(RequestInterface::GET, $mockUri);
+
+        $this->assertSame($expectedUri, $request->getUrl());
+    }
+
+    public function testCreateRequestSetHeadersSuccess()
+    {
+        $headers = array(
+            'mock.header' => 'mock.value',
+        );
+        $client = new PredictionIOClient();
+        $request = $client->createRequest(RequestInterface::GET, null, $headers);
+
+        $this->assertTrue($request->getHeader('mock.header')->hasValue($headers['mock.header']));
+    }
+
+    public function testCreateRequestUnsetsGuzzleInternals()
+    {
+        $body = array(
+            AbstractCommand::HEADERS_OPTION => 'mock.HEADERS_OPTION',
+            AbstractCommand::ON_COMPLETE => 'mock.ON_COMPLETE',
+            AbstractCommand::DISABLE_VALIDATION => 'mock.DISABLE_VALIDATION',
+            AbstractCommand::RESPONSE_PROCESSING => 'mock.RESPONSE_PROCESSING',
+            AbstractCommand::RESPONSE_BODY => 'mock.RESPONSE_BODY',
+        );
+        $client = new PredictionIOClient();
+        $request = $client->createRequest(RequestInterface::GET, null, null, $body);
+
+        $this->assertNull($request->getQuery()->get(AbstractCommand::HEADERS_OPTION));
+        $this->assertNull($request->getQuery()->get(AbstractCommand::ON_COMPLETE));
+        $this->assertNull($request->getQuery()->get(AbstractCommand::DISABLE_VALIDATION));
+        $this->assertNull($request->getQuery()->get(AbstractCommand::RESPONSE_PROCESSING));
+        $this->assertNull($request->getQuery()->get(AbstractCommand::RESPONSE_BODY));
+    }
+}