| 'use strict'; | 
|   | 
| function Queue(options) { | 
|   if (!(this instanceof Queue)) { | 
|     return new Queue(options); | 
|   } | 
|   | 
|   options = options || {}; | 
|   this.concurrency = options.concurrency || Infinity; | 
|   this.pending = 0; | 
|   this.jobs = []; | 
|   this.cbs = []; | 
|   this._done = done.bind(this); | 
| } | 
|   | 
| var arrayAddMethods = [ | 
|   'push', | 
|   'unshift', | 
|   'splice' | 
| ]; | 
|   | 
| arrayAddMethods.forEach(function(method) { | 
|   Queue.prototype[method] = function() { | 
|     var methodResult = Array.prototype[method].apply(this.jobs, arguments); | 
|     this._run(); | 
|     return methodResult; | 
|   }; | 
| }); | 
|   | 
| Object.defineProperty(Queue.prototype, 'length', { | 
|   get: function() { | 
|     return this.pending + this.jobs.length; | 
|   } | 
| }); | 
|   | 
| Queue.prototype._run = function() { | 
|   if (this.pending === this.concurrency) { | 
|     return; | 
|   } | 
|   if (this.jobs.length) { | 
|     var job = this.jobs.shift(); | 
|     this.pending++; | 
|     job(this._done); | 
|     this._run(); | 
|   } | 
|   | 
|   if (this.pending === 0) { | 
|     while (this.cbs.length !== 0) { | 
|       var cb = this.cbs.pop(); | 
|       process.nextTick(cb); | 
|     } | 
|   } | 
| }; | 
|   | 
| Queue.prototype.onDone = function(cb) { | 
|   if (typeof cb === 'function') { | 
|     this.cbs.push(cb); | 
|     this._run(); | 
|   } | 
| }; | 
|   | 
| function done() { | 
|   this.pending--; | 
|   this._run(); | 
| } | 
|   | 
| module.exports = Queue; |