Demo for query storing

Change-Id: I947bcac841992c3f6cfd01ab337c265b0d01cb70
diff --git a/node_modules/cloneable-readable/.travis.yml b/node_modules/cloneable-readable/.travis.yml
new file mode 100644
index 0000000..c352b0e
--- /dev/null
+++ b/node_modules/cloneable-readable/.travis.yml
@@ -0,0 +1,13 @@
+language: node_js
+sudo: false
+node_js:
+  - "0.10"
+  - "0.12"
+  - "4"
+  - "5"
+  - "6"
+  - "7"
+  - "8"
+  - "9"
+  - "10"
+  - "12"
diff --git a/node_modules/cloneable-readable/LICENSE b/node_modules/cloneable-readable/LICENSE
new file mode 100644
index 0000000..ecf6245
--- /dev/null
+++ b/node_modules/cloneable-readable/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2016 Matteo Collina
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/node_modules/cloneable-readable/README.md b/node_modules/cloneable-readable/README.md
new file mode 100644
index 0000000..17b25a2
--- /dev/null
+++ b/node_modules/cloneable-readable/README.md
@@ -0,0 +1,54 @@
+# cloneable-readable
+
+[![Greenkeeper badge](https://badges.greenkeeper.io/mcollina/cloneable-readable.svg)](https://greenkeeper.io/)
+
+[![Build Status](https://travis-ci.org/mcollina/cloneable-readable.svg?branch=master)](https://travis-ci.org/mcollina/cloneable-readable)
+
+Clone a Readable stream, safely.
+
+```js
+'use strict'
+
+var cloneable = require('cloneable-readable')
+var fs = require('fs')
+var pump = require('pump')
+
+var stream = cloneable(fs.createReadStream('./package.json'))
+
+pump(stream.clone(), fs.createWriteStream('./out1'))
+
+// simulate some asynchronicity
+setImmediate(function () {
+  pump(stream, fs.createWriteStream('./out2'))
+})
+```
+
+**cloneable-readable** automatically handles `objectMode: true`.
+
+This module comes out of an healthy discussion on the 'right' way to
+clone a Readable in https://github.com/gulpjs/vinyl/issues/85
+and https://github.com/nodejs/readable-stream/issues/202. This is my take.
+
+**YOU MUST PIPE ALL CLONES TO START THE FLOW**
+
+You can also attach `'data'` and `'readable'` events to them.
+
+## API
+
+### cloneable(stream)
+
+Create a `Cloneable` stream.
+A Cloneable has a `clone()` method to create more clones.
+All clones must be resumed/piped to start the flow.
+
+### cloneable.isCloneable(stream)
+
+Check if `stream` needs to be wrapped in a `Cloneable` or not.
+
+## Acknowledgements
+
+This project was kindly sponsored by [nearForm](http://nearform.com).
+
+## License
+
+MIT
diff --git a/node_modules/cloneable-readable/example.js b/node_modules/cloneable-readable/example.js
new file mode 100644
index 0000000..e980b97
--- /dev/null
+++ b/node_modules/cloneable-readable/example.js
@@ -0,0 +1,14 @@
+'use strict'
+
+var cloneable = require('./')
+var fs = require('fs')
+var pump = require('pump')
+
+var stream = cloneable(fs.createReadStream('./package.json'))
+
+pump(stream.clone(), fs.createWriteStream('./out1'))
+
+// simulate some asynchronicity
+setImmediate(function () {
+  pump(stream, fs.createWriteStream('./out2'))
+})
diff --git a/node_modules/cloneable-readable/index.js b/node_modules/cloneable-readable/index.js
new file mode 100644
index 0000000..a68765b
--- /dev/null
+++ b/node_modules/cloneable-readable/index.js
@@ -0,0 +1,153 @@
+'use strict'
+
+var PassThrough = require('readable-stream').PassThrough
+var inherits = require('inherits')
+var p = require('process-nextick-args')
+
+function Cloneable (stream, opts) {
+  if (!(this instanceof Cloneable)) {
+    return new Cloneable(stream, opts)
+  }
+
+  var objectMode = stream._readableState.objectMode
+  this._original = stream
+  this._clonesCount = 1
+
+  opts = opts || {}
+  opts.objectMode = objectMode
+
+  PassThrough.call(this, opts)
+
+  forwardDestroy(stream, this)
+
+  this.on('newListener', onData)
+  this.once('resume', onResume)
+
+  this._hasListener = true
+}
+
+inherits(Cloneable, PassThrough)
+
+function onData (event, listener) {
+  if (event === 'data' || event === 'readable') {
+    this._hasListener = false
+    this.removeListener('newListener', onData)
+    this.removeListener('resume', onResume)
+    p.nextTick(clonePiped, this)
+  }
+}
+
+function onResume () {
+  this._hasListener = false
+  this.removeListener('newListener', onData)
+  p.nextTick(clonePiped, this)
+}
+
+Cloneable.prototype.clone = function () {
+  if (!this._original) {
+    throw new Error('already started')
+  }
+
+  this._clonesCount++
+
+  // the events added by the clone should not count
+  // for starting the flow
+  this.removeListener('newListener', onData)
+  var clone = new Clone(this)
+  if (this._hasListener) {
+    this.on('newListener', onData)
+  }
+
+  return clone
+}
+
+Cloneable.prototype._destroy = function (err, cb) {
+  if (!err) {
+    this.push(null)
+    this.end()
+    this.emit('close')
+  }
+
+  p.nextTick(cb, err)
+}
+
+function forwardDestroy (src, dest) {
+  src.on('error', destroy)
+  src.on('close', onClose)
+
+  function destroy (err) {
+    src.removeListener('close', onClose)
+    dest.destroy(err)
+  }
+
+  function onClose () {
+    dest.end()
+  }
+}
+
+function clonePiped (that) {
+  if (--that._clonesCount === 0 && !that._readableState.destroyed) {
+    that._original.pipe(that)
+    that._original = undefined
+  }
+}
+
+function Clone (parent, opts) {
+  if (!(this instanceof Clone)) {
+    return new Clone(parent, opts)
+  }
+
+  var objectMode = parent._readableState.objectMode
+
+  opts = opts || {}
+  opts.objectMode = objectMode
+
+  this.parent = parent
+
+  PassThrough.call(this, opts)
+
+  forwardDestroy(parent, this)
+
+  parent.pipe(this)
+
+  // the events added by the clone should not count
+  // for starting the flow
+  // so we add the newListener handle after we are done
+  this.on('newListener', onDataClone)
+  this.on('resume', onResumeClone)
+}
+
+function onDataClone (event, listener) {
+  // We start the flow once all clones are piped or destroyed
+  if (event === 'data' || event === 'readable' || event === 'close') {
+    p.nextTick(clonePiped, this.parent)
+    this.removeListener('newListener', onDataClone)
+  }
+}
+
+function onResumeClone () {
+  this.removeListener('newListener', onDataClone)
+  p.nextTick(clonePiped, this.parent)
+}
+
+inherits(Clone, PassThrough)
+
+Clone.prototype.clone = function () {
+  return this.parent.clone()
+}
+
+Cloneable.isCloneable = function (stream) {
+  return stream instanceof Cloneable || stream instanceof Clone
+}
+
+Clone.prototype._destroy = function (err, cb) {
+  if (!err) {
+    this.push(null)
+    this.end()
+    this.emit('close')
+  }
+
+  p.nextTick(cb, err)
+}
+
+module.exports = Cloneable
diff --git a/node_modules/cloneable-readable/package.json b/node_modules/cloneable-readable/package.json
new file mode 100644
index 0000000..2bf2ea0
--- /dev/null
+++ b/node_modules/cloneable-readable/package.json
@@ -0,0 +1,67 @@
+{
+  "_from": "cloneable-readable@^1.0.0",
+  "_id": "cloneable-readable@1.1.3",
+  "_inBundle": false,
+  "_integrity": "sha512-2EF8zTQOxYq70Y4XKtorQupqF0m49MBz2/yf5Bj+MHjvpG3Hy7sImifnqD6UA+TKYxeSV+u6qqQPawN5UvnpKQ==",
+  "_location": "/cloneable-readable",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "cloneable-readable@^1.0.0",
+    "name": "cloneable-readable",
+    "escapedName": "cloneable-readable",
+    "rawSpec": "^1.0.0",
+    "saveSpec": null,
+    "fetchSpec": "^1.0.0"
+  },
+  "_requiredBy": [
+    "/vinyl"
+  ],
+  "_resolved": "https://registry.npmjs.org/cloneable-readable/-/cloneable-readable-1.1.3.tgz",
+  "_shasum": "120a00cb053bfb63a222e709f9683ea2e11d8cec",
+  "_spec": "cloneable-readable@^1.0.0",
+  "_where": "C:\\Users\\marcr\\Desktop\\KorAp\\Git\\Kalamar\\node_modules\\vinyl",
+  "author": {
+    "name": "Matteo Collina",
+    "email": "hello@matteocollina.com"
+  },
+  "bugs": {
+    "url": "https://github.com/mcollina/cloneable-readable/issues"
+  },
+  "bundleDependencies": false,
+  "dependencies": {
+    "inherits": "^2.0.1",
+    "process-nextick-args": "^2.0.0",
+    "readable-stream": "^2.3.5"
+  },
+  "deprecated": false,
+  "description": "Clone a Readable stream, safely",
+  "devDependencies": {
+    "flush-write-stream": "^1.0.0",
+    "from2": "^2.1.1",
+    "pre-commit": "^1.1.2",
+    "pump": "^3.0.0",
+    "standard": "^11.0.0",
+    "tap-spec": "^4.1.1",
+    "tape": "^4.9.0"
+  },
+  "homepage": "https://github.com/mcollina/cloneable-readable#readme",
+  "keywords": [
+    "readable",
+    "stream",
+    "clone"
+  ],
+  "license": "MIT",
+  "main": "index.js",
+  "name": "cloneable-readable",
+  "precommit": "test",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/mcollina/cloneable-readable.git"
+  },
+  "scripts": {
+    "test": "standard && tape test.js | tap-spec"
+  },
+  "version": "1.1.3"
+}
diff --git a/node_modules/cloneable-readable/test.js b/node_modules/cloneable-readable/test.js
new file mode 100644
index 0000000..35bb78b
--- /dev/null
+++ b/node_modules/cloneable-readable/test.js
@@ -0,0 +1,702 @@
+'use strict'
+
+var fs = require('fs')
+var path = require('path')
+var test = require('tape').test
+var from = require('from2')
+var crypto = require('crypto')
+var sink = require('flush-write-stream')
+var pump = require('pump')
+var cloneable = require('./')
+
+test('basic passthrough', function (t) {
+  t.plan(2)
+
+  var read = false
+  var source = from(function (size, next) {
+    if (read) {
+      this.push(null)
+    } else {
+      read = true
+      this.push('hello world')
+    }
+    next()
+  })
+
+  var instance = cloneable(source)
+  t.notOk(read, 'stream not started')
+
+  instance.pipe(sink(function (chunk, enc, cb) {
+    t.equal(chunk.toString(), 'hello world', 'chunk matches')
+    cb()
+  }))
+})
+
+test('clone sync', function (t) {
+  t.plan(4)
+
+  var read = false
+  var source = from(function (size, next) {
+    if (read) {
+      this.push(null)
+    } else {
+      read = true
+      this.push('hello world')
+    }
+    next()
+  })
+
+  var instance = cloneable(source)
+  t.notOk(read, 'stream not started')
+
+  var cloned = instance.clone()
+  t.notOk(read, 'stream not started')
+
+  instance.pipe(sink(function (chunk, enc, cb) {
+    t.equal(chunk.toString(), 'hello world', 'chunk matches')
+    cb()
+  }))
+
+  cloned.pipe(sink(function (chunk, enc, cb) {
+    t.equal(chunk.toString(), 'hello world', 'chunk matches')
+    cb()
+  }))
+})
+
+test('clone async', function (t) {
+  t.plan(4)
+
+  var read = false
+  var source = from(function (size, next) {
+    if (read) {
+      this.push(null)
+    } else {
+      read = true
+      this.push('hello world')
+    }
+    next()
+  })
+
+  var instance = cloneable(source)
+  t.notOk(read, 'stream not started')
+
+  var cloned = instance.clone()
+  t.notOk(read, 'stream not started')
+
+  instance.pipe(sink(function (chunk, enc, cb) {
+    t.equal(chunk.toString(), 'hello world', 'chunk matches')
+    cb()
+  }))
+
+  setImmediate(function () {
+    cloned.pipe(sink(function (chunk, enc, cb) {
+      t.equal(chunk.toString(), 'hello world', 'chunk matches')
+      cb()
+    }))
+  })
+})
+
+test('basic passthrough in obj mode', function (t) {
+  t.plan(2)
+
+  var read = false
+  var source = from.obj(function (size, next) {
+    if (read) {
+      return this.push(null)
+    } else {
+      read = true
+      this.push({ hello: 'world' })
+    }
+    next()
+  })
+
+  var instance = cloneable(source)
+  t.notOk(read, 'stream not started')
+
+  instance.pipe(sink.obj(function (chunk, enc, cb) {
+    t.deepEqual(chunk, { hello: 'world' }, 'chunk matches')
+    cb()
+  }))
+})
+
+test('multiple clone in object mode', function (t) {
+  t.plan(4)
+
+  var read = false
+  var source = from.obj(function (size, next) {
+    if (read) {
+      return this.push(null)
+    } else {
+      read = true
+      this.push({ hello: 'world' })
+    }
+    next()
+  })
+
+  var instance = cloneable(source)
+  t.notOk(read, 'stream not started')
+
+  var cloned = instance.clone()
+  t.notOk(read, 'stream not started')
+
+  instance.pipe(sink.obj(function (chunk, enc, cb) {
+    t.deepEqual(chunk, { hello: 'world' }, 'chunk matches')
+    cb()
+  }))
+
+  setImmediate(function () {
+    cloned.pipe(sink.obj(function (chunk, enc, cb) {
+      t.deepEqual(chunk, { hello: 'world' }, 'chunk matches')
+      cb()
+    }))
+  })
+})
+
+test('basic passthrough with data event', function (t) {
+  t.plan(2)
+
+  var read = false
+  var source = from(function (size, next) {
+    if (read) {
+      this.push(null)
+    } else {
+      read = true
+      this.push('hello world')
+    }
+    next()
+  })
+
+  var instance = cloneable(source)
+  t.notOk(read, 'stream not started')
+
+  var data = ''
+  instance.on('data', function (chunk) {
+    data += chunk.toString()
+  })
+
+  instance.on('end', function () {
+    t.equal(data, 'hello world', 'chunk matches')
+  })
+})
+
+test('basic passthrough with data event on clone', function (t) {
+  t.plan(3)
+
+  var read = false
+  var source = from(function (size, next) {
+    if (read) {
+      this.push(null)
+    } else {
+      read = true
+      this.push('hello world')
+    }
+    next()
+  })
+
+  var instance = cloneable(source)
+  var cloned = instance.clone()
+
+  t.notOk(read, 'stream not started')
+
+  var data = ''
+  cloned.on('data', function (chunk) {
+    data += chunk.toString()
+  })
+
+  cloned.on('end', function () {
+    t.equal(data, 'hello world', 'chunk matches in clone')
+  })
+
+  instance.pipe(sink(function (chunk, enc, cb) {
+    t.equal(chunk.toString(), 'hello world', 'chunk matches in instance')
+    cb()
+  }))
+})
+
+test('errors if cloned after start', function (t) {
+  t.plan(2)
+
+  var source = from(function (size, next) {
+    this.push('hello world')
+    this.push(null)
+    next()
+  })
+
+  var instance = cloneable(source)
+
+  instance.pipe(sink(function (chunk, enc, cb) {
+    t.equal(chunk.toString(), 'hello world', 'chunk matches')
+    t.throws(function () {
+      instance.clone()
+    }, 'throws if cloned after start')
+    cb()
+  }))
+})
+
+test('basic passthrough with readable event', function (t) {
+  t.plan(2)
+
+  var read = false
+  var source = from(function (size, next) {
+    if (read) {
+      this.push(null)
+    } else {
+      read = true
+      this.push('hello world')
+    }
+    next()
+  })
+
+  var instance = cloneable(source)
+  t.notOk(read, 'stream not started')
+
+  var data = ''
+  instance.on('readable', function () {
+    var chunk
+    while ((chunk = this.read()) !== null) {
+      data += chunk.toString()
+    }
+  })
+
+  instance.on('end', function () {
+    t.equal(data, 'hello world', 'chunk matches')
+  })
+})
+
+test('basic passthrough with readable event on clone', function (t) {
+  t.plan(3)
+
+  var read = false
+  var source = from(function (size, next) {
+    if (read) {
+      this.push(null)
+    } else {
+      read = true
+      this.push('hello world')
+    }
+    next()
+  })
+
+  var instance = cloneable(source)
+  var cloned = instance.clone()
+
+  t.notOk(read, 'stream not started')
+
+  var data = ''
+  cloned.on('readable', function () {
+    var chunk
+    while ((chunk = this.read()) !== null) {
+      data += chunk.toString()
+    }
+  })
+
+  cloned.on('end', function () {
+    t.equal(data, 'hello world', 'chunk matches in clone')
+  })
+
+  instance.pipe(sink(function (chunk, enc, cb) {
+    t.equal(chunk.toString(), 'hello world', 'chunk matches in instance')
+    cb()
+  }))
+})
+
+test('source error destroys all', function (t) {
+  t.plan(3)
+
+  var source = from()
+  var instance = cloneable(source)
+  var clone = instance.clone()
+
+  source.on('error', function (err) {
+    t.ok(err, 'source errors')
+
+    instance.on('error', function (err2) {
+      t.ok(err === err2, 'instance receives same error')
+    })
+
+    clone.on('error', function (err3) {
+      t.ok(err === err3, 'clone receives same error')
+    })
+  })
+
+  source.emit('error', new Error())
+})
+
+test('source destroy destroys all', function (t) {
+  t.plan(2)
+
+  var source = from()
+  var instance = cloneable(source)
+  var clone = instance.clone()
+
+  instance.on('end', function () {
+    t.pass('instance has ended')
+  })
+
+  clone.on('end', function () {
+    t.pass('clone has ended')
+  })
+
+  clone.resume()
+  instance.resume()
+
+  source.destroy()
+})
+
+test('instance error destroys all but the source', function (t) {
+  t.plan(2)
+
+  var source = from()
+  var instance = cloneable(source)
+  var clone = instance.clone()
+
+  source.on('close', function () {
+    t.fail('source should not be closed')
+  })
+
+  instance.on('error', function (err) {
+    t.is(err.message, 'beep', 'instance errors')
+  })
+
+  instance.on('close', function () {
+    t.fail('close should not be emitted')
+  })
+
+  clone.on('error', function (err) {
+    t.is(err.message, 'beep', 'instance errors')
+  })
+
+  clone.on('close', function () {
+    t.fail('close should not be emitted')
+  })
+
+  instance.destroy(new Error('beep'))
+})
+
+test('instance destroy destroys all but the source', function (t) {
+  t.plan(2)
+
+  var source = from()
+  var instance = cloneable(source)
+  var clone = instance.clone()
+
+  source.on('close', function () {
+    t.fail('source should not be closed')
+  })
+
+  instance.on('end', function () {
+    t.pass('instance has ended')
+  })
+
+  clone.on('end', function () {
+    t.pass('clone has ended')
+  })
+
+  instance.resume()
+  clone.resume()
+
+  instance.destroy()
+})
+
+test('clone destroy does not affect other clones, cloneable or source', function (t) {
+  t.plan(1)
+
+  var source = from()
+  var instance = cloneable(source)
+  var clone = instance.clone()
+  var other = instance.clone()
+
+  source.on('close', function () {
+    t.fail('source should not be closed')
+  })
+
+  instance.on('close', function () {
+    t.fail('instance should not be closed')
+  })
+
+  other.on('close', function () {
+    t.fail('other clone should not be closed')
+  })
+
+  clone.on('close', function () {
+    t.pass('clone is closed')
+  })
+
+  clone.destroy()
+})
+
+test('clone remains readable if other is destroyed', function (t) {
+  t.plan(3)
+
+  var read = false
+  var source = from(function (size, next) {
+    if (read) {
+      this.push(null)
+    } else {
+      read = true
+      this.push('hello')
+    }
+    next()
+  })
+
+  var instance = cloneable(source)
+  var clone = instance.clone()
+  var other = instance.clone()
+
+  instance.pipe(sink.obj(function (chunk, enc, cb) {
+    t.deepEqual(chunk.toString(), 'hello', 'instance chunk matches')
+    cb()
+  }))
+
+  clone.pipe(sink.obj(function (chunk, enc, cb) {
+    t.deepEqual(chunk.toString(), 'hello', 'clone chunk matches')
+    cb()
+  }))
+
+  clone.on('close', function () {
+    t.fail('clone should not be closed')
+  })
+
+  instance.on('close', function () {
+    t.fail('instance should not be closed')
+  })
+
+  other.on('close', function () {
+    t.pass('other is closed')
+  })
+
+  other.destroy()
+})
+
+test('clone of clone', function (t) {
+  t.plan(6)
+
+  var read = false
+  var source = from(function (size, next) {
+    if (read) {
+      this.push(null)
+    } else {
+      read = true
+      this.push('hello world')
+    }
+    next()
+  })
+
+  var instance = cloneable(source)
+  t.notOk(read, 'stream not started')
+
+  var cloned = instance.clone()
+  t.notOk(read, 'stream not started')
+
+  var replica = cloned.clone()
+  t.notOk(read, 'stream not started')
+
+  instance.pipe(sink(function (chunk, enc, cb) {
+    t.equal(chunk.toString(), 'hello world', 'chunk matches')
+    cb()
+  }))
+
+  cloned.pipe(sink(function (chunk, enc, cb) {
+    t.equal(chunk.toString(), 'hello world', 'chunk matches')
+    cb()
+  }))
+
+  replica.pipe(sink(function (chunk, enc, cb) {
+    t.equal(chunk.toString(), 'hello world', 'chunk matches')
+    cb()
+  }))
+})
+
+test('from vinyl', function (t) {
+  t.plan(3)
+
+  var source = from(['wa', 'dup'])
+
+  var instance = cloneable(source)
+  var clone = instance.clone()
+
+  var data = ''
+  var data2 = ''
+  var ends = 2
+
+  function latch () {
+    if (--ends === 0) {
+      t.equal(data, data2)
+    }
+  }
+
+  instance.on('data', function (chunk) {
+    data += chunk.toString()
+  })
+
+  process.nextTick(function () {
+    t.equal('', data, 'nothing was written yet')
+    t.equal('', data2, 'nothing was written yet')
+
+    clone.on('data', function (chunk) {
+      data2 += chunk.toString()
+    })
+  })
+
+  instance.on('end', latch)
+  clone.on('end', latch)
+})
+
+test('waits till all are flowing', function (t) {
+  t.plan(1)
+
+  var source = from(['wa', 'dup'])
+
+  var instance = cloneable(source)
+
+  // we create a clone
+  instance.clone()
+
+  instance.on('data', function (chunk) {
+    t.fail('this should never happen')
+  })
+
+  process.nextTick(function () {
+    t.pass('wait till nextTick')
+  })
+})
+
+test('isCloneable', function (t) {
+  t.plan(4)
+
+  var source = from(['hello', ' ', 'world'])
+  t.notOk(cloneable.isCloneable(source), 'a generic readable is not cloneable')
+
+  var instance = cloneable(source)
+  t.ok(cloneable.isCloneable(instance), 'a cloneable is cloneable')
+
+  var clone = instance.clone()
+  t.ok(cloneable.isCloneable(clone), 'a clone is cloneable')
+
+  var cloneClone = clone.clone()
+  t.ok(cloneable.isCloneable(cloneClone), 'a clone of a clone is cloneable')
+})
+
+test('emits finish', function (t) {
+  var chunks = ['a', 'b', 'c', 'd', null]
+  var e1 = ['a', 'b', 'c', 'd']
+  var e2 = ['a', 'b', 'c', 'd']
+
+  t.plan(2 + e1.length + e2.length)
+
+  var source = from(function (size, next) {
+    setImmediate(next, null, chunks.shift())
+  })
+
+  var instance = cloneable(source)
+
+  var clone = instance.clone()
+
+  clone.on('finish', t.pass.bind(null, 'clone emits finish'))
+  instance.on('finish', t.pass.bind(null, 'main emits finish'))
+
+  instance.pipe(sink(function (chunk, enc, cb) {
+    t.equal(chunk.toString(), e1.shift(), 'chunk matches')
+    cb()
+  }))
+
+  clone.on('data', function (chunk) {
+    t.equal(chunk.toString(), e2.shift(), 'chunk matches')
+  })
+})
+
+test('clone async w resume', function (t) {
+  t.plan(4)
+
+  var read = false
+  var source = from(function (size, next) {
+    if (read) {
+      this.push(null)
+    } else {
+      read = true
+      this.push('hello world')
+    }
+    next()
+  })
+
+  var instance = cloneable(source)
+  t.notOk(read, 'stream not started')
+
+  var cloned = instance.clone()
+  t.notOk(read, 'stream not started')
+
+  instance.on('end', t.pass.bind(null, 'end emitted'))
+  instance.resume()
+
+  setImmediate(function () {
+    cloned.on('end', t.pass.bind(null, 'end emitted'))
+    cloned.resume()
+  })
+})
+
+test('big file', function (t) {
+  t.plan(13)
+
+  var stream = cloneable(fs.createReadStream(path.join(__dirname, 'big')))
+  var hash = crypto.createHash('sha1')
+  hash.setEncoding('hex')
+
+  var toCheck
+
+  fs.createReadStream(path.join(__dirname, 'big'))
+    .pipe(hash)
+    .once('readable', function () {
+      toCheck = hash.read()
+      t.ok(toCheck)
+    })
+
+  function pipe (s, num) {
+    s.on('end', function () {
+      t.pass('end for ' + num)
+    })
+
+    var dest = path.join(__dirname, 'out')
+
+    s.pipe(fs.createWriteStream(dest))
+      .on('finish', function () {
+        t.pass('finish for ' + num)
+
+        var destHash = crypto.createHash('sha1')
+        destHash.setEncoding('hex')
+
+        fs.createReadStream(dest)
+          .pipe(destHash)
+          .once('readable', function () {
+            var hash = destHash.read()
+            t.ok(hash)
+            t.equal(hash, toCheck)
+          })
+      })
+  }
+
+  // Pipe in another event loop tick <-- this one finished only, it's the original cloneable.
+  setImmediate(pipe.bind(null, stream, 1))
+
+  // Pipe in the same event loop tick
+  pipe(stream.clone(), 0)
+
+  // Pipe a long time after
+  setTimeout(pipe.bind(null, stream.clone(), 2), 1000)
+})
+
+test('pump error', function (t) {
+  t.plan(1)
+
+  var err = new Error('kaboom')
+
+  pump([
+    cloneable(from(function () {
+      this.destroy(err)
+    })),
+    sink(function (chunk, enc, cb) {
+      t.fail('this should not be called')
+    })
+  ], function (_err) {
+    t.equal(_err, err)
+  })
+})