Implemented and working assets (todo: asset convenience methods)
diff --git a/helpers/build.js b/helpers/build.js
index 67fa0c9..0991638 100644
--- a/helpers/build.js
+++ b/helpers/build.js
@@ -6,6 +6,7 @@
     UsergridQuery = require('../lib/query'),
     UsergridEntity = require('../lib/entity'),
     UsergridAuth = require('../lib/auth'),
+    UsergridAsset = require('../lib/asset'),
     util = require('util'),
     version = require('../package.json').version,
     ok = require('objectkit'),
@@ -13,12 +14,44 @@
 
 var assignPrefabOptions = function(args) {
     // if a preformatted options argument passed, assign it to options
-    if (_.isObject(args[0]) && !_.isFunction(args[0]) && args.length <= 2) {
+    if (_.isObject(args[0]) && !_.isFunction(args[0]) && ok(this).has("method")) {
         _.assign(this, args[0])
     }
     return this
 }
 
+var setEntity = function(args) {
+    this.entity = _.first([this.entity, args[0]].filter(function(property) {
+        return (property instanceof UsergridEntity)
+    }))
+    if (this.entity !== undefined) {
+        this.type = this.entity.type
+    }
+    return this
+}
+
+var setAsset = function(args) {
+    this.asset = _.first([this.asset, ok(this).getIfExists('entity.asset'), args[1], args[0]].filter(function(property) {
+        return (property instanceof UsergridAsset)
+    }))
+    return this
+}
+
+var setUuidOrName = function(args) {
+    this.uuidOrName = _.first([
+        this.uuidOrName,
+        this.uuid,
+        this.name,
+        ok(this).getIfExists('entity.uuid'),
+        ok(this).getIfExists('body.uuid'),
+        ok(this).getIfExists('entity.name'),
+        ok(this).getIfExists('body.name'),
+        ok(args).getIfExists('2'),
+        ok(args).getIfExists('1')
+    ].filter(_.isString))
+    return this
+}
+
 var setPathOrType = function(args) {
     var pathOrType = _.first([
         this.type,
@@ -48,34 +81,14 @@
 
 var setBody = function(args) {
     this.body = _.first([this.entity, this.body, args[2], args[1], args[0]].filter(function(property) {
-        return _.isObject(property) && !_.isFunction(property) && !(property instanceof UsergridQuery)
+        return _.isObject(property) && !_.isFunction(property) && !(property instanceof UsergridQuery) && !(property instanceof UsergridAsset)
     }))
-    if (this.body === undefined) {
+    if (this.body === undefined && this.asset === undefined) {
         throw new Error(util.format('"body" is required when making a %s request', this.method))
     }
     return this
 }
 
-var setUuidOrName = function(args) {
-    this.uuidOrName = _.first([
-        this.uuidOrName,
-        this.uuid,
-        this.name,
-        ok(this).getIfExists('entity.uuid'),
-        ok(this).getIfExists('body.uuid'),
-        _.isArray(args) ? args[2] : undefined,
-        _.isArray(args) ? args[1] : undefined
-    ].filter(_.isString))
-    return this
-}
-
-var setEntity = function(args) {
-    this.entity = _.first([this.entity, args[0]].filter(function(property) {
-        return (property instanceof UsergridEntity)
-    }))
-    return this
-}
-
 module.exports = {
     uri: function(client, options) {
         return urljoin(
@@ -83,7 +96,14 @@
             client.orgId,
             client.appId,
             options.path || options.type,
-            _.first([options.uuidOrName, options.uuid, options.name, ""].filter(_.isString))
+            options.method !== "POST" ? _.first([
+                options.uuidOrName,
+                options.uuid,
+                options.name,
+                ok(options).getIfExists('entity.uuid'),
+                ok(options).getIfExists('entity.name'),
+                ""
+            ].filter(_.isString)) : ""
         )
     },
     headers: function(client) {
@@ -158,11 +178,11 @@
             callback: helpers.cb(args)
         }
         assignPrefabOptions.call(options, args)
+        setEntity.call(options, args)
         setUuidOrName.call(options, args)
         setPathOrType.call(options, args)
         setQs.call(options, args)
         setQuery.call(options, args)
-        setEntity.call(options, args)
         return options
     },
     PUT: function(client, args) {
@@ -191,12 +211,12 @@
             callback: helpers.cb(args)
         }
         assignPrefabOptions.call(options, args)
+        setEntity.call(options, args)
+        setAsset.call(options, args)
         setBody.call(options, args)
         setUuidOrName.call(options, args)
         setPathOrType.call(options, args)
         setQuery.call(options, args)
-        setEntity.call(options, args)
-
         return options
     },
     POST: function(client, args) {
@@ -220,6 +240,8 @@
             callback: helpers.cb(args)
         }
         assignPrefabOptions.call(options, args)
+        setEntity.call(options, args)
+        setAsset.call(options, args)
         setBody.call(options, args)
         setPathOrType.call(options, args)
         return options
@@ -246,14 +268,11 @@
             callback: helpers.cb(args)
         }
         assignPrefabOptions.call(options, args)
+        setEntity.call(options, args)
         setUuidOrName.call(options, args)
         setPathOrType.call(options, args)
         setQs.call(options, args)
-        setEntity.call(options, args)
         setQuery.call(options, args)
-        if (!_.isString(options.uuidOrName) && options.query === undefined && options.path === undefined) {
-            throw new Error('"uuidOrName", "query", or "path" is required when making a DELETE request')
-        }
         return options
     },
     connection: function(client, method, args) {
@@ -414,5 +433,30 @@
         )
 
         return options
+    },
+    qs: function(options) {
+        return (options.query instanceof UsergridQuery) ? {
+            ql: options.query._ql || undefined,
+            limit: options.query._limit,
+            cursor: options.query._cursor
+        } : options.qs
+    },
+    formData: function(options) {
+        if (ok(options).getIfExists('asset.data')) {
+            var formData = {}
+            formData.file = {
+                value: options.asset.data,
+                options: {
+                    filename: ok(options).getIfExists('asset.filename') || UsergridAsset.DEFAULT_FILE_NAME,
+                    contentType: ok(options).getIfExists('asset.contentType') || 'application/octet-stream'
+                }
+            } 
+            if (ok(options).has('asset.name')) {
+                formData.name = options.asset.name
+            }
+            return formData
+        } else {
+            return undefined
+        }
     }
 }
\ No newline at end of file
diff --git a/lib/asset.js b/lib/asset.js
index e69de29..d5f25b2 100644
--- a/lib/asset.js
+++ b/lib/asset.js
@@ -0,0 +1,75 @@
+'use strict'
+
+var Usergrid = require('../usergrid'),
+    validator = require('validator'),
+    readChunk = require('read-chunk'),
+    fileType = require('file-type'),
+    helpers = require('../helpers'),
+    stream = require('stream'),
+    util = require('util'),
+    ok = require('objectkit'),
+    _ = require('lodash')
+
+var UsergridAsset = function() {
+    var self = this
+    var args = helpers.args(arguments)
+
+    var __contentType
+    var __binaryData = []
+
+    if (args.length === 0) {
+        throw new Error('A UsergridAsset object was initialized using an empty argument')
+    }
+
+    if (_.isObject(args[0])) {
+        _.assign(self, args[0])
+    } else {
+        self.filename = _.isString(args[0]) ? args[0] : undefined
+        self.data = validator.isBase64(args[1]) || Buffer.isBuffer(args[1]) ? args[1] : []
+        self.originalLocation = _.first([args[2], args[1]].filter(function(property) {
+            return (_.isString(property) && !validator.isBase64(property))
+        }))
+        self.contentType = _.isString(args[3]) ? args[3] : undefined
+
+        stream.PassThrough.call(self)
+        self._write = function(chunk, encoding, done) {
+            __binaryData.push(chunk)
+            done()
+        }
+        self.on('finish', function() {
+            self.data = Buffer.concat(__binaryData)
+        })
+    }
+
+    Object.defineProperty(self, 'contentLength', {
+        get: function() {
+            return (self.data) ? self.data.byteLength : 0
+        }
+    })
+
+    Object.defineProperty(self, 'contentType', {
+        get: function() {
+            if (__contentType) {
+                return __contentType
+            } else if (Buffer.isBuffer(self.data)) {
+                __contentType = fileType(self.data).mime
+                return __contentType
+            }
+        },
+        set: function(contentType) {
+            if (contentType) {
+                __contentType = contentType
+            } else if (Buffer.isBuffer(self.data)) {
+                __contentType = fileType(self.data).mime
+            }
+        }
+    })
+
+    return self
+}
+
+util.inherits(UsergridAsset, stream.PassThrough)
+
+
+module.exports = UsergridAsset
+module.exports.DEFAULT_FILE_NAME = 'file'
\ No newline at end of file
diff --git a/lib/entity.js b/lib/entity.js
index cc81e17..cc17872 100644
--- a/lib/entity.js
+++ b/lib/entity.js
@@ -9,7 +9,7 @@
     var self = this
     var args = helpers.args(arguments)
 
-    if (!args[0]) {
+    if (args.length === 0) {
         throw new Error('A UsergridEntity object was initialized using an empty argument')
     }
 
@@ -42,6 +42,8 @@
         }
     })
 
+    self.asset
+
     helpers.setReadOnly(self, ['uuid', 'name', 'type', 'created'])
 
     return self
@@ -121,7 +123,9 @@
             callback(error, usergridResponse, this)
         }.bind(this))
     },
-    attachAsset: function() {},
+    attachAsset: function(asset) {
+        this.asset = asset
+    },
     uploadAsset: function() {},
     downloadAsset: function() {},
     connect: function() {
diff --git a/lib/request.js b/lib/request.js
index 65dad4a..28e549e 100644
--- a/lib/request.js
+++ b/lib/request.js
@@ -4,33 +4,34 @@
     helpers = require('../helpers'),
     UsergridResponse = require('../lib/response'),
     UsergridQuery = require('../lib/query'),
-    util = require('util'),
+    UsergridAsset = require('../lib/asset'),
     ok = require('objectkit'),
     _ = require('lodash')
 
 var UsergridRequest = function(options) {
+    var self = this
     var client = helpers.client.validate(options.client)
     var callback = helpers.cb(helpers.args(arguments))
 
     if (!_.isString(options.type) && !_.isString(options.path) && !_.isString(options.uri)) {
         throw new Error('one of "type" (collection name), "path", or "uri" parameters are required when initializing a UsergridRequest')
     }
+
     if (!_.includes(['GET', 'PUT', 'POST', 'DELETE'], options.method)) {
         throw new Error('"method" parameter is required when initializing a UsergridRequest')
     }
 
     var uri = options.uri || helpers.build.uri(client, options)
+    var formData = helpers.build.formData(options)
+    var body = ((formData !== undefined) ? undefined : options.body)
 
-    request(uri, {
+    var req = request(uri, {
         headers: helpers.build.headers(client),
-        body: options.body,
+        body: body,
         json: true,
         method: options.method,
-        qs: (options.query instanceof UsergridQuery) ? {
-            ql: options.query._ql || undefined,
-            limit: options.query._limit,
-            cursor: options.query._cursor
-        } : options.qs
+        qs: helpers.build.qs(options),
+        formData: formData
     }, function(error, response) {
         var usergridResponse = new UsergridResponse(response)
         var returnBody = _.first([usergridResponse.user, usergridResponse.users, usergridResponse.entity, usergridResponse.entities, usergridResponse.body].filter(_.isObject))
diff --git a/lib/response.js b/lib/response.js
index 63a4b20..3cd21e1 100644
--- a/lib/response.js
+++ b/lib/response.js
@@ -26,7 +26,6 @@
                 }
                 return entity
             })
-
             _.assign(self, {
                 metadata: _.cloneDeep(response.body),
                 entities: entities
diff --git a/package.json b/package.json
index bfd5a32..d949ff1 100644
--- a/package.json
+++ b/package.json
@@ -2,12 +2,16 @@
   "author": "Brandon Shelley",
   "dependencies": {
     "async": "latest",
+    "file-type": "^3.4.0",
     "lodash": "~4.0",
     "lodash-inflection": "latest",
     "lodash-uuid": "latest",
     "objectkit": "latest",
+    "read-chunk": "^1.0.1",
     "request": "latest",
-    "url-join": "latest"
+    "through2": "^2.0.0",
+    "url-join": "latest",
+    "validator": "^4.5.0"
   },
   "description": "The official Node.js SDK for Usergrid",
   "devDependencies": {
diff --git a/tests/lib/asset.test.js b/tests/lib/asset.test.js
new file mode 100644
index 0000000..0911ea8
--- /dev/null
+++ b/tests/lib/asset.test.js
@@ -0,0 +1,122 @@
+'use strict'
+
+var should = require('should'),
+    urljoin = require('url-join'),
+    config = require('../../helpers').config,
+    UsergridEntity = require('../../lib/entity'),
+    UsergridAsset = require('../../lib/asset'),
+    UsergridClient = require('../../lib/client'),
+    util = require('util'),
+    request = require('request'),
+    fs = require('fs'),
+    _ = require('lodash')
+
+var _slow = 6000,
+    _timeout = 12000,
+    filename = 'old_man',
+    file = __dirname + '/image.jpg',
+    testFile = __dirname + '/image_test.jpg',
+    expectedContentLength = 109055
+
+describe('init from fs.readFile()', function() {
+    var asset = new UsergridAsset(filename, file)
+
+    before(function(done) {
+        fs.readFile(file, function(err, data) {
+            asset.data = data
+            done()
+        })
+    })
+
+    it('asset.data should be a binary Buffer', function() {
+        asset.data.should.be.a.buffer
+    })
+
+    it('asset.contentType should be inferred from Buffer', function() {
+        asset.contentType.should.equal('image/jpeg')
+    })
+
+    it(util.format('asset.contentLength should be %s bytes', expectedContentLength), function() {
+        asset.contentLength.should.equal(expectedContentLength)
+    })
+})
+
+describe('init from piped writable stream', function() {
+    var asset = new UsergridAsset(filename, file)
+    var writeTestAsset = new UsergridAsset('image_test', testFile)
+    before(function(done) {
+        var stream = fs.createReadStream(file).pipe(asset),
+            writeTest
+        stream.on('finish', function() {
+            fs.writeFile(testFile, asset.data)
+            writeTest = fs.createReadStream(file).pipe(writeTestAsset)
+            writeTest.on('finish', function() {
+                done()
+            })
+        })
+    })
+
+    it('asset.data should be a binary Buffer', function() {
+        asset.data.should.be.a.buffer
+    })
+
+    it('asset.contentType should be inferred from Buffer', function() {
+        asset.contentType.should.equal('image/jpeg')
+    })
+
+    it(util.format('asset.contentLength should be %s bytes', expectedContentLength), function() {
+        asset.contentLength.should.equal(expectedContentLength)
+    })
+
+    it('should write an identical asset to the filesystem', function() {
+        writeTestAsset.contentType.should.equal('image/jpeg')
+        writeTestAsset.contentLength.should.equal(expectedContentLength)
+    })
+})
+
+describe('upload via client.POST to a specific entity', function() {
+    
+    this.slow(_slow)
+    this.timeout(_timeout)
+
+    var client = new UsergridClient()
+    it('should upload a binary asset and create a new entity', function(done) {
+        var asset = new UsergridAsset(filename, file)
+            fs.createReadStream(file).pipe(asset).on('finish', function() {
+            client.POST(config.test.collection, asset, function(err, assetResponse, entityWithAsset) {
+                assetResponse.statusCode.should.equal(200)
+                entityWithAsset.should.have.property('file-metadata')
+                entityWithAsset['file-metadata'].should.have.property('content-type').equal('image/jpeg')
+                entityWithAsset['file-metadata'].should.have.property('content-length').equal(expectedContentLength)
+                entityWithAsset.remove(client)
+                done()
+            })
+        })  
+    })
+})
+
+describe('upload via client.PUT to a specific entity', function() {
+
+    this.slow(_slow)
+    this.timeout(_timeout)
+
+    var client = new UsergridClient()
+    it('should upload a binary asset to an existing entity', function(done) {
+        var entity = new UsergridEntity({
+            type: config.test.collection,
+            name: "AssetTestPUT",
+        })
+        var asset = new UsergridAsset(filename, file)
+        client.PUT(entity, function(err, entityResponse, createdEntity) {
+            fs.createReadStream(file).pipe(asset).on('finish', function() {
+                client.PUT(createdEntity, asset, function(err, assetResponse, entityWithAsset) {
+                    assetResponse.statusCode.should.equal(200)
+                    entityWithAsset.should.have.property('file-metadata')
+                    entityWithAsset['file-metadata'].should.have.property('content-type').equal('image/jpeg')
+                    entityWithAsset['file-metadata'].should.have.property('content-length').equal(expectedContentLength)
+                    done()
+                })
+            })
+        })  
+    })
+})
\ No newline at end of file
diff --git a/tests/lib/client.rest.test.js b/tests/lib/client.rest.test.js
index 75f17d2..7cf7074 100644
--- a/tests/lib/client.rest.test.js
+++ b/tests/lib/client.rest.test.js
@@ -3,6 +3,7 @@
 var should = require('should'),
     urljoin = require('url-join'),
     config = require('../../helpers').config,
+    chance = new require('chance').Chance(),
     UsergridClient = require('../../lib/client'),
     UsergridEntity = require('../../lib/entity'),
     UsergridQuery = require('../../lib/query'),
@@ -135,6 +136,22 @@
         })
     })
 
+    it('should support creating an entity by passing a UsergridEntity object with a unique name', function(done) {
+
+        this.slow(_slow)
+        this.timeout(_timeout)
+
+        var entity = new UsergridEntity({
+            type: config.test.collection,
+            name: chance.word()
+        })
+        client.POST(entity, function(err, usergridResponse) {
+            usergridResponse.entity.should.be.an.Object().with.property('name').equal(entity.name)
+            usergridResponse.entity.remove(client)
+            done()
+        })
+    })
+
     it('should support creating an entity by passing type and a body object', function(done) {
 
         this.slow(_slow)
@@ -203,9 +220,7 @@
         }
 
         client.POST(options, function(err, usergridResponse) {
-            usergridResponse.entities.forEach(function(entity) {
-                entity.should.be.an.Object().with.property('restaurant').equal(entity.restaurant)
-            })
+            usergridResponse.entity.should.be.an.Object().with.property('restaurant').equal(usergridResponse.entity.restaurant)
             done()
         })
     })
diff --git a/tests/lib/image.jpg b/tests/lib/image.jpg
new file mode 100644
index 0000000..32f4fa3
--- /dev/null
+++ b/tests/lib/image.jpg
Binary files differ
diff --git a/tests/lib/image_test.jpg b/tests/lib/image_test.jpg
new file mode 100644
index 0000000..32f4fa3
--- /dev/null
+++ b/tests/lib/image_test.jpg
Binary files differ
diff --git a/tests/main.test.js b/tests/main.test.js
index 87a2d05..581411e 100644
--- a/tests/main.test.js
+++ b/tests/main.test.js
@@ -2,6 +2,7 @@
 
 // module config
 var should = require('should'),
+    validator = require('validator'),
     _ = require('lodash')
 
 _.mixin(require('lodash-uuid'))
@@ -9,9 +10,17 @@
 should.Assertion.add('uuid', function() {
     this.params = {
         operator: 'to be a valid uuid'
-    };
+    }
     this.assert(_.isUuid(this.obj))
 })
+
+should.Assertion.add('buffer', function() {
+    this.params = {
+        operator: 'to be buffer data'
+    }
+    this.assert(Buffer.isBuffer(this.obj))
+})
+
 // end module config
 
 describe('Usergrid initialization', function() {
@@ -60,4 +69,8 @@
 
 describe('UsergridUser', function() {
     return require('./lib/user.test')
+})
+
+describe('UsergridAsset', function() {
+    return require('./lib/asset.test')
 })
\ No newline at end of file
diff --git a/usergrid.js b/usergrid.js
index 330fffa..d4fe3cd 100644
--- a/usergrid.js
+++ b/usergrid.js
@@ -1,7 +1,5 @@
 'use strict'
 
-var UsergridClient = require('./lib/client')
-
 var Usergrid = {
     isInitialized: false,
     isSharedInstance: true,
@@ -10,6 +8,7 @@
         if (self.isInitialized) {
             return self
         }
+        var UsergridClient = require('./lib/client')
         Object.setPrototypeOf(Usergrid, new UsergridClient(options))
         UsergridClient.call(self)
         self.isInitialized = true