| 'use strict' | 
|   | 
| var util = require('util') | 
| var isNode = require('detect-node') | 
|   | 
| // Node.js 0.8, 0.10 and 0.12 support | 
| Object.assign = (process.versions.modules >= 46 || !isNode) | 
|   ? Object.assign // eslint-disable-next-line | 
|   : util._extend | 
|   | 
| function QueueItem () { | 
|   this.prev = null | 
|   this.next = null | 
| } | 
| exports.QueueItem = QueueItem | 
|   | 
| function Queue () { | 
|   QueueItem.call(this) | 
|   | 
|   this.prev = this | 
|   this.next = this | 
| } | 
| util.inherits(Queue, QueueItem) | 
| exports.Queue = Queue | 
|   | 
| Queue.prototype.insertTail = function insertTail (item) { | 
|   item.prev = this.prev | 
|   item.next = this | 
|   item.prev.next = item | 
|   item.next.prev = item | 
| } | 
|   | 
| Queue.prototype.remove = function remove (item) { | 
|   var next = item.next | 
|   var prev = item.prev | 
|   | 
|   item.next = item | 
|   item.prev = item | 
|   next.prev = prev | 
|   prev.next = next | 
| } | 
|   | 
| Queue.prototype.head = function head () { | 
|   return this.next | 
| } | 
|   | 
| Queue.prototype.tail = function tail () { | 
|   return this.prev | 
| } | 
|   | 
| Queue.prototype.isEmpty = function isEmpty () { | 
|   return this.next === this | 
| } | 
|   | 
| Queue.prototype.isRoot = function isRoot (item) { | 
|   return this === item | 
| } | 
|   | 
| function LockStream (stream) { | 
|   this.locked = false | 
|   this.queue = [] | 
|   this.stream = stream | 
| } | 
| exports.LockStream = LockStream | 
|   | 
| LockStream.prototype.write = function write (chunks, callback) { | 
|   var self = this | 
|   | 
|   // Do not let it interleave | 
|   if (this.locked) { | 
|     this.queue.push(function () { | 
|       return self.write(chunks, callback) | 
|     }) | 
|     return | 
|   } | 
|   | 
|   this.locked = true | 
|   | 
|   function done (err, chunks) { | 
|     self.stream.removeListener('error', done) | 
|   | 
|     self.locked = false | 
|     if (self.queue.length > 0) { self.queue.shift()() } | 
|     callback(err, chunks) | 
|   } | 
|   | 
|   this.stream.on('error', done) | 
|   | 
|   // Accumulate all output data | 
|   var output = [] | 
|   function onData (chunk) { | 
|     output.push(chunk) | 
|   } | 
|   this.stream.on('data', onData) | 
|   | 
|   function next (err) { | 
|     self.stream.removeListener('data', onData) | 
|     if (err) { | 
|       return done(err) | 
|     } | 
|   | 
|     done(null, output) | 
|   } | 
|   | 
|   for (var i = 0; i < chunks.length - 1; i++) { this.stream.write(chunks[i]) } | 
|   | 
|   if (chunks.length > 0) { | 
|     this.stream.write(chunks[i], next) | 
|   } else { process.nextTick(next) } | 
|   | 
|   if (this.stream.execute) { | 
|     this.stream.execute(function (err) { | 
|       if (err) { return done(err) } | 
|     }) | 
|   } | 
| } | 
|   | 
| // Just finds the place in array to insert | 
| function binaryLookup (list, item, compare) { | 
|   var start = 0 | 
|   var end = list.length | 
|   | 
|   while (start < end) { | 
|     var pos = (start + end) >> 1 | 
|     var cmp = compare(item, list[pos]) | 
|   | 
|     if (cmp === 0) { | 
|       start = pos | 
|       end = pos | 
|       break | 
|     } else if (cmp < 0) { | 
|       end = pos | 
|     } else { | 
|       start = pos + 1 | 
|     } | 
|   } | 
|   | 
|   return start | 
| } | 
| exports.binaryLookup = binaryLookup | 
|   | 
| function binaryInsert (list, item, compare) { | 
|   var index = binaryLookup(list, item, compare) | 
|   | 
|   list.splice(index, 0, item) | 
| } | 
| exports.binaryInsert = binaryInsert | 
|   | 
| function binarySearch (list, item, compare) { | 
|   var index = binaryLookup(list, item, compare) | 
|   | 
|   if (index >= list.length) { | 
|     return -1 | 
|   } | 
|   | 
|   if (compare(item, list[index]) === 0) { | 
|     return index | 
|   } | 
|   | 
|   return -1 | 
| } | 
| exports.binarySearch = binarySearch | 
|   | 
| function Timeout (object) { | 
|   this.delay = 0 | 
|   this.timer = null | 
|   this.object = object | 
| } | 
| exports.Timeout = Timeout | 
|   | 
| Timeout.prototype.set = function set (delay, callback) { | 
|   this.delay = delay | 
|   this.reset() | 
|   if (!callback) { return } | 
|   | 
|   if (this.delay === 0) { | 
|     this.object.removeListener('timeout', callback) | 
|   } else { | 
|     this.object.once('timeout', callback) | 
|   } | 
| } | 
|   | 
| Timeout.prototype.reset = function reset () { | 
|   if (this.timer !== null) { | 
|     clearTimeout(this.timer) | 
|     this.timer = null | 
|   } | 
|   | 
|   if (this.delay === 0) { return } | 
|   | 
|   var self = this | 
|   this.timer = setTimeout(function () { | 
|     self.timer = null | 
|     self.object.emit('timeout') | 
|   }, this.delay) | 
| } |