diff --git a/message.model.js b/message.model.js index 1ad6a52..f914fb7 100644 --- a/message.model.js +++ b/message.model.js @@ -7,8 +7,9 @@ const MessageSchema = mongoose.Schema({ subject: { type: String, required: true }, message: { type: String, required: true }, user: { type: String, required: true }, - tag: [{type: String, index: true }], + tag: [{type: String }], //createtime: { type: Date, default: Date.now }, }); +MessageSchema.index({tag:'text'}); module.exports = mongoose.model('Message', MessageSchema); diff --git a/mong.js b/mong.js new file mode 100644 index 0000000..2cb9c0f --- /dev/null +++ b/mong.js @@ -0,0 +1,84 @@ +db = db.getSiblingDB('omdb') + +print(db.getCollectionNames()) +db.messages.insert( + [ + { + "subject": "DOLORE LABORIS AUTE", + "message": "Ex sunt elit elit in ex ad labore minim. Elit amet irure sit aliquip excepteur sit qui et aute qui mollit cillum.", + "user": "Jaime Potter", + "tag": [ + "sit", + "in", + "dolore", + "ullamco" + ] + }, + { + "subject": "NON IPSUM MOLLIT", + "message": "Ut laborum proident magna magna qui non in voluptate reprehenderit labore. Qui consectetur dolor nisi culpa cillum quis.", + "user": "Goff Durham", + "tag": [ + "aliqua", + "sunt", + "labore", + "minim" + ] + }, + { + "subject": "ESSE IPSUM INCIDIDUNT", + "message": "Esse enim amet laboris proident do do ut cupidatat laborum ex. Sit esse id laborum aliqua id.", + "user": "Helena Mercado", + "tag": [ + "fugiat", + "nisi", + "incididunt", + "ullamco" + ] + }, + { + "subject": "PARIATUR DOLOR SUNT", + "message": "Exercitation officia ad consequat est voluptate est incididunt ut culpa consectetur. Consectetur irure veniam ipsum sint sit anim minim aute exercitation ullamco nostrud reprehenderit consequat.", + "user": "Christi Walker", + "tag": [ + "consectetur", + "sint", + "qui", + "ipsum" + ] + }, + { + "subject": "TEMPOR ID VOLUPTATE", + "message": "Anim ex commodo officia consequat in magna esse sunt mollit sunt commodo. Ex sit aute reprehenderit elit magna sunt irure pariatur cupidatat labore.", + "user": "Kent Schroeder", + "tag": [ + "adipisicing", + "nulla", + "tempor", + "veniam" + ] + }, + { + "subject": "LOREM EST AUTE", + "message": "Irure excepteur laborum quis tempor officia cillum officia est ea adipisicing duis enim aliqua. Est dolor laborum officia elit ullamco.", + "user": "Dominguez Stevens", + "tag": [ + "mollit", + "amet", + "consectetur", + "dolore" + ] + }, + { + "subject": "ESSE MOLLIT CILLUM", + "message": "Eu culpa laborum consequat sunt aliqua excepteur. Voluptate pariatur deserunt consequat id nostrud do magna occaecat sint nulla non nostrud.", + "user": "Terrell Padilla", + "tag": [ + "Lorem", + "consequat", + "fugiat", + "aliqua" + ] + } +] +) diff --git a/node_modules/.bin/bunyan b/node_modules/.bin/bunyan new file mode 120000 index 0000000..3555ac7 --- /dev/null +++ b/node_modules/.bin/bunyan @@ -0,0 +1 @@ +../bunyan/bin/bunyan \ No newline at end of file diff --git a/node_modules/.bin/ldapjs-add b/node_modules/.bin/ldapjs-add new file mode 120000 index 0000000..2d799de --- /dev/null +++ b/node_modules/.bin/ldapjs-add @@ -0,0 +1 @@ +../ldapjs/bin/ldapjs-add \ No newline at end of file diff --git a/node_modules/.bin/ldapjs-compare b/node_modules/.bin/ldapjs-compare new file mode 120000 index 0000000..135f796 --- /dev/null +++ b/node_modules/.bin/ldapjs-compare @@ -0,0 +1 @@ +../ldapjs/bin/ldapjs-compare \ No newline at end of file diff --git a/node_modules/.bin/ldapjs-delete b/node_modules/.bin/ldapjs-delete new file mode 120000 index 0000000..b62ac42 --- /dev/null +++ b/node_modules/.bin/ldapjs-delete @@ -0,0 +1 @@ +../ldapjs/bin/ldapjs-delete \ No newline at end of file diff --git a/node_modules/.bin/ldapjs-modify b/node_modules/.bin/ldapjs-modify new file mode 120000 index 0000000..f8be167 --- /dev/null +++ b/node_modules/.bin/ldapjs-modify @@ -0,0 +1 @@ +../ldapjs/bin/ldapjs-modify \ No newline at end of file diff --git a/node_modules/.bin/ldapjs-search b/node_modules/.bin/ldapjs-search new file mode 120000 index 0000000..97401ae --- /dev/null +++ b/node_modules/.bin/ldapjs-search @@ -0,0 +1 @@ +../ldapjs/bin/ldapjs-search \ No newline at end of file diff --git a/node_modules/.bin/ncp b/node_modules/.bin/ncp new file mode 120000 index 0000000..1c02648 --- /dev/null +++ b/node_modules/.bin/ncp @@ -0,0 +1 @@ +../ncp/bin/ncp \ No newline at end of file diff --git a/node_modules/ansi-escapes/index.js b/node_modules/ansi-escapes/index.js index 1122cbf..f201915 100644 --- a/node_modules/ansi-escapes/index.js +++ b/node_modules/ansi-escapes/index.js @@ -78,6 +78,15 @@ x.scrollUp = ESC + 'S'; x.scrollDown = ESC + 'T'; x.clearScreen = '\u001Bc'; + +x.clearTerminal = process.platform === 'win32' ? + `${x.eraseScreen}${ESC}0f` : + // 1. Erases the screen (Only done in case `2` is not supported) + // 2. Erases the whole screen including scrollback buffer + // 3. Moves cursor to the top-left position + // More info: https://www.real-world-systems.com/docs/ANSIcode.html + `${x.eraseScreen}${ESC}3J${ESC}H`; + x.beep = BEL; x.link = (text, url) => { diff --git a/node_modules/ansi-escapes/package.json b/node_modules/ansi-escapes/package.json index 9b182c8..bc11c4b 100644 --- a/node_modules/ansi-escapes/package.json +++ b/node_modules/ansi-escapes/package.json @@ -1,27 +1,27 @@ { - "_from": "ansi-escapes@^3.0.0", - "_id": "ansi-escapes@3.1.0", + "_from": "ansi-escapes@^3.2.0", + "_id": "ansi-escapes@3.2.0", "_inBundle": false, - "_integrity": "sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw==", + "_integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", "_location": "/ansi-escapes", "_phantomChildren": {}, "_requested": { "type": "range", "registry": true, - "raw": "ansi-escapes@^3.0.0", + "raw": "ansi-escapes@^3.2.0", "name": "ansi-escapes", "escapedName": "ansi-escapes", - "rawSpec": "^3.0.0", + "rawSpec": "^3.2.0", "saveSpec": null, - "fetchSpec": "^3.0.0" + "fetchSpec": "^3.2.0" }, "_requiredBy": [ "/inquirer" ], - "_resolved": "http://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz", - "_shasum": "f73207bb81207d75fd6c83f125af26eea378ca30", - "_spec": "ansi-escapes@^3.0.0", - "_where": "/home/erik/Documents/workspace_brackets/BME_Project_Ohm/om/node_modules/inquirer", + "_resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "_shasum": "8780b98ff9dbf5638152d1f1fe5c1d7b4442976b", + "_spec": "ansi-escapes@^3.2.0", + "_where": "/home/erik/Documents/workspace_brackets/a1_BME_Project_Ohm/om/node_modules/inquirer", "author": { "name": "Sindre Sorhus", "email": "sindresorhus@gmail.com", @@ -78,5 +78,5 @@ "scripts": { "test": "xo && ava" }, - "version": "3.1.0" + "version": "3.2.0" } diff --git a/node_modules/ansi-escapes/readme.md b/node_modules/ansi-escapes/readme.md index 38b459f..513ef60 100644 --- a/node_modules/ansi-escapes/readme.md +++ b/node_modules/ansi-escapes/readme.md @@ -117,7 +117,11 @@ Scroll display down one line. ### clearScreen -Clear the terminal screen. +Clear the terminal screen. (Viewport) + +### clearTerminal + +Clear the whole terminal, including scrollback buffer. (Not just the visible part of it) ### beep diff --git a/node_modules/asn1/.npmignore b/node_modules/asn1/.npmignore new file mode 100644 index 0000000..eb03e3e --- /dev/null +++ b/node_modules/asn1/.npmignore @@ -0,0 +1,2 @@ +node_modules +*.log diff --git a/node_modules/asn1/.travis.yml b/node_modules/asn1/.travis.yml new file mode 100644 index 0000000..09d3ef3 --- /dev/null +++ b/node_modules/asn1/.travis.yml @@ -0,0 +1,4 @@ +language: node_js +node_js: + - 0.8 + - 0.10 diff --git a/node_modules/asn1/LICENSE b/node_modules/asn1/LICENSE new file mode 100644 index 0000000..9b5dcdb --- /dev/null +++ b/node_modules/asn1/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2011 Mark Cavage, All rights reserved. + +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/asn1/README.md b/node_modules/asn1/README.md new file mode 100644 index 0000000..7cebf7a --- /dev/null +++ b/node_modules/asn1/README.md @@ -0,0 +1,50 @@ +node-asn1 is a library for encoding and decoding ASN.1 datatypes in pure JS. +Currently BER encoding is supported; at some point I'll likely have to do DER. + +## Usage + +Mostly, if you're *actually* needing to read and write ASN.1, you probably don't +need this readme to explain what and why. If you have no idea what ASN.1 is, +see this: ftp://ftp.rsa.com/pub/pkcs/ascii/layman.asc + +The source is pretty much self-explanatory, and has read/write methods for the +common types out there. + +### Decoding + +The following reads an ASN.1 sequence with a boolean. + + var Ber = require('asn1').Ber; + + var reader = new Ber.Reader(new Buffer([0x30, 0x03, 0x01, 0x01, 0xff])); + + reader.readSequence(); + console.log('Sequence len: ' + reader.length); + if (reader.peek() === Ber.Boolean) + console.log(reader.readBoolean()); + +### Encoding + +The following generates the same payload as above. + + var Ber = require('asn1').Ber; + + var writer = new Ber.Writer(); + + writer.startSequence(); + writer.writeBoolean(true); + writer.endSequence(); + + console.log(writer.buffer); + +## Installation + + npm install asn1 + +## License + +MIT. + +## Bugs + +See . diff --git a/node_modules/asn1/lib/ber/errors.js b/node_modules/asn1/lib/ber/errors.js new file mode 100644 index 0000000..ff21d4f --- /dev/null +++ b/node_modules/asn1/lib/ber/errors.js @@ -0,0 +1,13 @@ +// Copyright 2011 Mark Cavage All rights reserved. + + +module.exports = { + + newInvalidAsn1Error: function(msg) { + var e = new Error(); + e.name = 'InvalidAsn1Error'; + e.message = msg || ''; + return e; + } + +}; diff --git a/node_modules/asn1/lib/ber/index.js b/node_modules/asn1/lib/ber/index.js new file mode 100644 index 0000000..4fb90ae --- /dev/null +++ b/node_modules/asn1/lib/ber/index.js @@ -0,0 +1,27 @@ +// Copyright 2011 Mark Cavage All rights reserved. + +var errors = require('./errors'); +var types = require('./types'); + +var Reader = require('./reader'); +var Writer = require('./writer'); + + +///--- Exports + +module.exports = { + + Reader: Reader, + + Writer: Writer + +}; + +for (var t in types) { + if (types.hasOwnProperty(t)) + module.exports[t] = types[t]; +} +for (var e in errors) { + if (errors.hasOwnProperty(e)) + module.exports[e] = errors[e]; +} diff --git a/node_modules/asn1/lib/ber/reader.js b/node_modules/asn1/lib/ber/reader.js new file mode 100644 index 0000000..0a00e98 --- /dev/null +++ b/node_modules/asn1/lib/ber/reader.js @@ -0,0 +1,261 @@ +// Copyright 2011 Mark Cavage All rights reserved. + +var assert = require('assert'); + +var ASN1 = require('./types'); +var errors = require('./errors'); + + +///--- Globals + +var newInvalidAsn1Error = errors.newInvalidAsn1Error; + + + +///--- API + +function Reader(data) { + if (!data || !Buffer.isBuffer(data)) + throw new TypeError('data must be a node Buffer'); + + this._buf = data; + this._size = data.length; + + // These hold the "current" state + this._len = 0; + this._offset = 0; +} + +Object.defineProperty(Reader.prototype, 'length', { + enumerable: true, + get: function () { return (this._len); } +}); + +Object.defineProperty(Reader.prototype, 'offset', { + enumerable: true, + get: function () { return (this._offset); } +}); + +Object.defineProperty(Reader.prototype, 'remain', { + get: function () { return (this._size - this._offset); } +}); + +Object.defineProperty(Reader.prototype, 'buffer', { + get: function () { return (this._buf.slice(this._offset)); } +}); + + +/** + * Reads a single byte and advances offset; you can pass in `true` to make this + * a "peek" operation (i.e., get the byte, but don't advance the offset). + * + * @param {Boolean} peek true means don't move offset. + * @return {Number} the next byte, null if not enough data. + */ +Reader.prototype.readByte = function(peek) { + if (this._size - this._offset < 1) + return null; + + var b = this._buf[this._offset] & 0xff; + + if (!peek) + this._offset += 1; + + return b; +}; + + +Reader.prototype.peek = function() { + return this.readByte(true); +}; + + +/** + * Reads a (potentially) variable length off the BER buffer. This call is + * not really meant to be called directly, as callers have to manipulate + * the internal buffer afterwards. + * + * As a result of this call, you can call `Reader.length`, until the + * next thing called that does a readLength. + * + * @return {Number} the amount of offset to advance the buffer. + * @throws {InvalidAsn1Error} on bad ASN.1 + */ +Reader.prototype.readLength = function(offset) { + if (offset === undefined) + offset = this._offset; + + if (offset >= this._size) + return null; + + var lenB = this._buf[offset++] & 0xff; + if (lenB === null) + return null; + + if ((lenB & 0x80) == 0x80) { + lenB &= 0x7f; + + if (lenB == 0) + throw newInvalidAsn1Error('Indefinite length not supported'); + + if (lenB > 4) + throw newInvalidAsn1Error('encoding too long'); + + if (this._size - offset < lenB) + return null; + + this._len = 0; + for (var i = 0; i < lenB; i++) + this._len = (this._len << 8) + (this._buf[offset++] & 0xff); + + } else { + // Wasn't a variable length + this._len = lenB; + } + + return offset; +}; + + +/** + * Parses the next sequence in this BER buffer. + * + * To get the length of the sequence, call `Reader.length`. + * + * @return {Number} the sequence's tag. + */ +Reader.prototype.readSequence = function(tag) { + var seq = this.peek(); + if (seq === null) + return null; + if (tag !== undefined && tag !== seq) + throw newInvalidAsn1Error('Expected 0x' + tag.toString(16) + + ': got 0x' + seq.toString(16)); + + var o = this.readLength(this._offset + 1); // stored in `length` + if (o === null) + return null; + + this._offset = o; + return seq; +}; + + +Reader.prototype.readInt = function() { + return this._readTag(ASN1.Integer); +}; + + +Reader.prototype.readBoolean = function() { + return (this._readTag(ASN1.Boolean) === 0 ? false : true); +}; + + +Reader.prototype.readEnumeration = function() { + return this._readTag(ASN1.Enumeration); +}; + + +Reader.prototype.readString = function(tag, retbuf) { + if (!tag) + tag = ASN1.OctetString; + + var b = this.peek(); + if (b === null) + return null; + + if (b !== tag) + throw newInvalidAsn1Error('Expected 0x' + tag.toString(16) + + ': got 0x' + b.toString(16)); + + var o = this.readLength(this._offset + 1); // stored in `length` + + if (o === null) + return null; + + if (this.length > this._size - o) + return null; + + this._offset = o; + + if (this.length === 0) + return retbuf ? new Buffer(0) : ''; + + var str = this._buf.slice(this._offset, this._offset + this.length); + this._offset += this.length; + + return retbuf ? str : str.toString('utf8'); +}; + +Reader.prototype.readOID = function(tag) { + if (!tag) + tag = ASN1.OID; + + var b = this.readString(tag, true); + if (b === null) + return null; + + var values = []; + var value = 0; + + for (var i = 0; i < b.length; i++) { + var byte = b[i] & 0xff; + + value <<= 7; + value += byte & 0x7f; + if ((byte & 0x80) == 0) { + values.push(value); + value = 0; + } + } + + value = values.shift(); + values.unshift(value % 40); + values.unshift((value / 40) >> 0); + + return values.join('.'); +}; + + +Reader.prototype._readTag = function(tag) { + assert.ok(tag !== undefined); + + var b = this.peek(); + + if (b === null) + return null; + + if (b !== tag) + throw newInvalidAsn1Error('Expected 0x' + tag.toString(16) + + ': got 0x' + b.toString(16)); + + var o = this.readLength(this._offset + 1); // stored in `length` + if (o === null) + return null; + + if (this.length > 4) + throw newInvalidAsn1Error('Integer too long: ' + this.length); + + if (this.length > this._size - o) + return null; + this._offset = o; + + var fb = this._buf[this._offset]; + var value = 0; + + for (var i = 0; i < this.length; i++) { + value <<= 8; + value |= (this._buf[this._offset++] & 0xff); + } + + if ((fb & 0x80) == 0x80 && i !== 4) + value -= (1 << (i * 8)); + + return value >> 0; +}; + + + +///--- Exported API + +module.exports = Reader; diff --git a/node_modules/asn1/lib/ber/types.js b/node_modules/asn1/lib/ber/types.js new file mode 100644 index 0000000..8aea000 --- /dev/null +++ b/node_modules/asn1/lib/ber/types.js @@ -0,0 +1,36 @@ +// Copyright 2011 Mark Cavage All rights reserved. + + +module.exports = { + EOC: 0, + Boolean: 1, + Integer: 2, + BitString: 3, + OctetString: 4, + Null: 5, + OID: 6, + ObjectDescriptor: 7, + External: 8, + Real: 9, // float + Enumeration: 10, + PDV: 11, + Utf8String: 12, + RelativeOID: 13, + Sequence: 16, + Set: 17, + NumericString: 18, + PrintableString: 19, + T61String: 20, + VideotexString: 21, + IA5String: 22, + UTCTime: 23, + GeneralizedTime: 24, + GraphicString: 25, + VisibleString: 26, + GeneralString: 28, + UniversalString: 29, + CharacterString: 30, + BMPString: 31, + Constructor: 32, + Context: 128 +}; diff --git a/node_modules/asn1/lib/ber/writer.js b/node_modules/asn1/lib/ber/writer.js new file mode 100644 index 0000000..d9d99af --- /dev/null +++ b/node_modules/asn1/lib/ber/writer.js @@ -0,0 +1,316 @@ +// Copyright 2011 Mark Cavage All rights reserved. + +var assert = require('assert'); +var ASN1 = require('./types'); +var errors = require('./errors'); + + +///--- Globals + +var newInvalidAsn1Error = errors.newInvalidAsn1Error; + +var DEFAULT_OPTS = { + size: 1024, + growthFactor: 8 +}; + + +///--- Helpers + +function merge(from, to) { + assert.ok(from); + assert.equal(typeof(from), 'object'); + assert.ok(to); + assert.equal(typeof(to), 'object'); + + var keys = Object.getOwnPropertyNames(from); + keys.forEach(function(key) { + if (to[key]) + return; + + var value = Object.getOwnPropertyDescriptor(from, key); + Object.defineProperty(to, key, value); + }); + + return to; +} + + + +///--- API + +function Writer(options) { + options = merge(DEFAULT_OPTS, options || {}); + + this._buf = new Buffer(options.size || 1024); + this._size = this._buf.length; + this._offset = 0; + this._options = options; + + // A list of offsets in the buffer where we need to insert + // sequence tag/len pairs. + this._seq = []; +} + +Object.defineProperty(Writer.prototype, 'buffer', { + get: function () { + if (this._seq.length) + throw new InvalidAsn1Error(this._seq.length + ' unended sequence(s)'); + + return (this._buf.slice(0, this._offset)); + } +}); + +Writer.prototype.writeByte = function(b) { + if (typeof(b) !== 'number') + throw new TypeError('argument must be a Number'); + + this._ensure(1); + this._buf[this._offset++] = b; +}; + + +Writer.prototype.writeInt = function(i, tag) { + if (typeof(i) !== 'number') + throw new TypeError('argument must be a Number'); + if (typeof(tag) !== 'number') + tag = ASN1.Integer; + + var sz = 4; + + while ((((i & 0xff800000) === 0) || ((i & 0xff800000) === 0xff800000 >> 0)) && + (sz > 1)) { + sz--; + i <<= 8; + } + + if (sz > 4) + throw new InvalidAsn1Error('BER ints cannot be > 0xffffffff'); + + this._ensure(2 + sz); + this._buf[this._offset++] = tag; + this._buf[this._offset++] = sz; + + while (sz-- > 0) { + this._buf[this._offset++] = ((i & 0xff000000) >>> 24); + i <<= 8; + } + +}; + + +Writer.prototype.writeNull = function() { + this.writeByte(ASN1.Null); + this.writeByte(0x00); +}; + + +Writer.prototype.writeEnumeration = function(i, tag) { + if (typeof(i) !== 'number') + throw new TypeError('argument must be a Number'); + if (typeof(tag) !== 'number') + tag = ASN1.Enumeration; + + return this.writeInt(i, tag); +}; + + +Writer.prototype.writeBoolean = function(b, tag) { + if (typeof(b) !== 'boolean') + throw new TypeError('argument must be a Boolean'); + if (typeof(tag) !== 'number') + tag = ASN1.Boolean; + + this._ensure(3); + this._buf[this._offset++] = tag; + this._buf[this._offset++] = 0x01; + this._buf[this._offset++] = b ? 0xff : 0x00; +}; + + +Writer.prototype.writeString = function(s, tag) { + if (typeof(s) !== 'string') + throw new TypeError('argument must be a string (was: ' + typeof(s) + ')'); + if (typeof(tag) !== 'number') + tag = ASN1.OctetString; + + var len = Buffer.byteLength(s); + this.writeByte(tag); + this.writeLength(len); + if (len) { + this._ensure(len); + this._buf.write(s, this._offset); + this._offset += len; + } +}; + + +Writer.prototype.writeBuffer = function(buf, tag) { + if (typeof(tag) !== 'number') + throw new TypeError('tag must be a number'); + if (!Buffer.isBuffer(buf)) + throw new TypeError('argument must be a buffer'); + + this.writeByte(tag); + this.writeLength(buf.length); + this._ensure(buf.length); + buf.copy(this._buf, this._offset, 0, buf.length); + this._offset += buf.length; +}; + + +Writer.prototype.writeStringArray = function(strings) { + if ((!strings instanceof Array)) + throw new TypeError('argument must be an Array[String]'); + + var self = this; + strings.forEach(function(s) { + self.writeString(s); + }); +}; + +// This is really to solve DER cases, but whatever for now +Writer.prototype.writeOID = function(s, tag) { + if (typeof(s) !== 'string') + throw new TypeError('argument must be a string'); + if (typeof(tag) !== 'number') + tag = ASN1.OID; + + if (!/^([0-9]+\.){3,}[0-9]+$/.test(s)) + throw new Error('argument is not a valid OID string'); + + function encodeOctet(bytes, octet) { + if (octet < 128) { + bytes.push(octet); + } else if (octet < 16384) { + bytes.push((octet >>> 7) | 0x80); + bytes.push(octet & 0x7F); + } else if (octet < 2097152) { + bytes.push((octet >>> 14) | 0x80); + bytes.push(((octet >>> 7) | 0x80) & 0xFF); + bytes.push(octet & 0x7F); + } else if (octet < 268435456) { + bytes.push((octet >>> 21) | 0x80); + bytes.push(((octet >>> 14) | 0x80) & 0xFF); + bytes.push(((octet >>> 7) | 0x80) & 0xFF); + bytes.push(octet & 0x7F); + } else { + bytes.push(((octet >>> 28) | 0x80) & 0xFF); + bytes.push(((octet >>> 21) | 0x80) & 0xFF); + bytes.push(((octet >>> 14) | 0x80) & 0xFF); + bytes.push(((octet >>> 7) | 0x80) & 0xFF); + bytes.push(octet & 0x7F); + } + } + + var tmp = s.split('.'); + var bytes = []; + bytes.push(parseInt(tmp[0], 10) * 40 + parseInt(tmp[1], 10)); + tmp.slice(2).forEach(function(b) { + encodeOctet(bytes, parseInt(b, 10)); + }); + + var self = this; + this._ensure(2 + bytes.length); + this.writeByte(tag); + this.writeLength(bytes.length); + bytes.forEach(function(b) { + self.writeByte(b); + }); +}; + + +Writer.prototype.writeLength = function(len) { + if (typeof(len) !== 'number') + throw new TypeError('argument must be a Number'); + + this._ensure(4); + + if (len <= 0x7f) { + this._buf[this._offset++] = len; + } else if (len <= 0xff) { + this._buf[this._offset++] = 0x81; + this._buf[this._offset++] = len; + } else if (len <= 0xffff) { + this._buf[this._offset++] = 0x82; + this._buf[this._offset++] = len >> 8; + this._buf[this._offset++] = len; + } else if (len <= 0xffffff) { + this._buf[this._offset++] = 0x83; + this._buf[this._offset++] = len >> 16; + this._buf[this._offset++] = len >> 8; + this._buf[this._offset++] = len; + } else { + throw new InvalidAsn1ERror('Length too long (> 4 bytes)'); + } +}; + +Writer.prototype.startSequence = function(tag) { + if (typeof(tag) !== 'number') + tag = ASN1.Sequence | ASN1.Constructor; + + this.writeByte(tag); + this._seq.push(this._offset); + this._ensure(3); + this._offset += 3; +}; + + +Writer.prototype.endSequence = function() { + var seq = this._seq.pop(); + var start = seq + 3; + var len = this._offset - start; + + if (len <= 0x7f) { + this._shift(start, len, -2); + this._buf[seq] = len; + } else if (len <= 0xff) { + this._shift(start, len, -1); + this._buf[seq] = 0x81; + this._buf[seq + 1] = len; + } else if (len <= 0xffff) { + this._buf[seq] = 0x82; + this._buf[seq + 1] = len >> 8; + this._buf[seq + 2] = len; + } else if (len <= 0xffffff) { + this._shift(start, len, 1); + this._buf[seq] = 0x83; + this._buf[seq + 1] = len >> 16; + this._buf[seq + 2] = len >> 8; + this._buf[seq + 3] = len; + } else { + throw new InvalidAsn1Error('Sequence too long'); + } +}; + + +Writer.prototype._shift = function(start, len, shift) { + assert.ok(start !== undefined); + assert.ok(len !== undefined); + assert.ok(shift); + + this._buf.copy(this._buf, start + shift, start, start + len); + this._offset += shift; +}; + +Writer.prototype._ensure = function(len) { + assert.ok(len); + + if (this._size - this._offset < len) { + var sz = this._size * this._options.growthFactor; + if (sz - this._offset < len) + sz += len; + + var buf = new Buffer(sz); + + this._buf.copy(buf, 0, 0, this._offset); + this._buf = buf; + this._size = sz; + } +}; + + + +///--- Exported API + +module.exports = Writer; diff --git a/node_modules/asn1/lib/index.js b/node_modules/asn1/lib/index.js new file mode 100644 index 0000000..d1766e7 --- /dev/null +++ b/node_modules/asn1/lib/index.js @@ -0,0 +1,20 @@ +// Copyright 2011 Mark Cavage All rights reserved. + +// If you have no idea what ASN.1 or BER is, see this: +// ftp://ftp.rsa.com/pub/pkcs/ascii/layman.asc + +var Ber = require('./ber/index'); + + + +///--- Exported API + +module.exports = { + + Ber: Ber, + + BerReader: Ber.Reader, + + BerWriter: Ber.Writer + +}; diff --git a/node_modules/asn1/package.json b/node_modules/asn1/package.json new file mode 100644 index 0000000..dbb3576 --- /dev/null +++ b/node_modules/asn1/package.json @@ -0,0 +1,65 @@ +{ + "_from": "asn1@0.2.3", + "_id": "asn1@0.2.3", + "_inBundle": false, + "_integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=", + "_location": "/asn1", + "_phantomChildren": {}, + "_requested": { + "type": "version", + "registry": true, + "raw": "asn1@0.2.3", + "name": "asn1", + "escapedName": "asn1", + "rawSpec": "0.2.3", + "saveSpec": null, + "fetchSpec": "0.2.3" + }, + "_requiredBy": [ + "/ldapjs" + ], + "_resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", + "_shasum": "dac8787713c9966849fc8180777ebe9c1ddf3b86", + "_spec": "asn1@0.2.3", + "_where": "/home/erik/Documents/workspace_brackets/a1_BME_Project_Ohm/om/node_modules/ldapjs", + "author": { + "name": "Mark Cavage", + "email": "mcavage@gmail.com" + }, + "bugs": { + "url": "https://github.com/mcavage/node-asn1/issues" + }, + "bundleDependencies": false, + "contributors": [ + { + "name": "David Gwynne", + "email": "loki@animata.net" + }, + { + "name": "Yunong Xiao", + "email": "yunong@joyent.com" + }, + { + "name": "Alex Wilson", + "email": "alex.wilson@joyent.com" + } + ], + "dependencies": {}, + "deprecated": false, + "description": "Contains parsers and serializers for ASN.1 (currently BER only)", + "devDependencies": { + "tap": "0.4.8" + }, + "homepage": "https://github.com/mcavage/node-asn1#readme", + "license": "MIT", + "main": "lib/index.js", + "name": "asn1", + "repository": { + "type": "git", + "url": "git://github.com/mcavage/node-asn1.git" + }, + "scripts": { + "test": "tap ./tst" + }, + "version": "0.2.3" +} diff --git a/node_modules/asn1/tst/ber/reader.test.js b/node_modules/asn1/tst/ber/reader.test.js new file mode 100644 index 0000000..062fd7e --- /dev/null +++ b/node_modules/asn1/tst/ber/reader.test.js @@ -0,0 +1,208 @@ +// Copyright 2011 Mark Cavage All rights reserved. + +var test = require('tap').test; + + + +///--- Globals + +var BerReader; + + + +///--- Tests + +test('load library', function(t) { + BerReader = require('../../lib/index').BerReader; + t.ok(BerReader); + try { + new BerReader(); + t.fail('Should have thrown'); + } catch (e) { + t.ok(e instanceof TypeError, 'Should have been a type error'); + } + t.end(); +}); + + +test('read byte', function(t) { + var reader = new BerReader(new Buffer([0xde])); + t.ok(reader); + t.equal(reader.readByte(), 0xde, 'wrong value'); + t.end(); +}); + + +test('read 1 byte int', function(t) { + var reader = new BerReader(new Buffer([0x02, 0x01, 0x03])); + t.ok(reader); + t.equal(reader.readInt(), 0x03, 'wrong value'); + t.equal(reader.length, 0x01, 'wrong length'); + t.end(); +}); + + +test('read 2 byte int', function(t) { + var reader = new BerReader(new Buffer([0x02, 0x02, 0x7e, 0xde])); + t.ok(reader); + t.equal(reader.readInt(), 0x7ede, 'wrong value'); + t.equal(reader.length, 0x02, 'wrong length'); + t.end(); +}); + + +test('read 3 byte int', function(t) { + var reader = new BerReader(new Buffer([0x02, 0x03, 0x7e, 0xde, 0x03])); + t.ok(reader); + t.equal(reader.readInt(), 0x7ede03, 'wrong value'); + t.equal(reader.length, 0x03, 'wrong length'); + t.end(); +}); + + +test('read 4 byte int', function(t) { + var reader = new BerReader(new Buffer([0x02, 0x04, 0x7e, 0xde, 0x03, 0x01])); + t.ok(reader); + t.equal(reader.readInt(), 0x7ede0301, 'wrong value'); + t.equal(reader.length, 0x04, 'wrong length'); + t.end(); +}); + + +test('read 1 byte negative int', function(t) { + var reader = new BerReader(new Buffer([0x02, 0x01, 0xdc])); + t.ok(reader); + t.equal(reader.readInt(), -36, 'wrong value'); + t.equal(reader.length, 0x01, 'wrong length'); + t.end(); +}); + + +test('read 2 byte negative int', function(t) { + var reader = new BerReader(new Buffer([0x02, 0x02, 0xc0, 0x4e])); + t.ok(reader); + t.equal(reader.readInt(), -16306, 'wrong value'); + t.equal(reader.length, 0x02, 'wrong length'); + t.end(); +}); + + +test('read 3 byte negative int', function(t) { + var reader = new BerReader(new Buffer([0x02, 0x03, 0xff, 0x00, 0x19])); + t.ok(reader); + t.equal(reader.readInt(), -65511, 'wrong value'); + t.equal(reader.length, 0x03, 'wrong length'); + t.end(); +}); + + +test('read 4 byte negative int', function(t) { + var reader = new BerReader(new Buffer([0x02, 0x04, 0x91, 0x7c, 0x22, 0x1f])); + t.ok(reader); + t.equal(reader.readInt(), -1854135777, 'wrong value'); + t.equal(reader.length, 0x04, 'wrong length'); + t.end(); +}); + + +test('read boolean true', function(t) { + var reader = new BerReader(new Buffer([0x01, 0x01, 0xff])); + t.ok(reader); + t.equal(reader.readBoolean(), true, 'wrong value'); + t.equal(reader.length, 0x01, 'wrong length'); + t.end(); +}); + + +test('read boolean false', function(t) { + var reader = new BerReader(new Buffer([0x01, 0x01, 0x00])); + t.ok(reader); + t.equal(reader.readBoolean(), false, 'wrong value'); + t.equal(reader.length, 0x01, 'wrong length'); + t.end(); +}); + + +test('read enumeration', function(t) { + var reader = new BerReader(new Buffer([0x0a, 0x01, 0x20])); + t.ok(reader); + t.equal(reader.readEnumeration(), 0x20, 'wrong value'); + t.equal(reader.length, 0x01, 'wrong length'); + t.end(); +}); + + +test('read string', function(t) { + var dn = 'cn=foo,ou=unit,o=test'; + var buf = new Buffer(dn.length + 2); + buf[0] = 0x04; + buf[1] = Buffer.byteLength(dn); + buf.write(dn, 2); + var reader = new BerReader(buf); + t.ok(reader); + t.equal(reader.readString(), dn, 'wrong value'); + t.equal(reader.length, dn.length, 'wrong length'); + t.end(); +}); + + +test('read sequence', function(t) { + var reader = new BerReader(new Buffer([0x30, 0x03, 0x01, 0x01, 0xff])); + t.ok(reader); + t.equal(reader.readSequence(), 0x30, 'wrong value'); + t.equal(reader.length, 0x03, 'wrong length'); + t.equal(reader.readBoolean(), true, 'wrong value'); + t.equal(reader.length, 0x01, 'wrong length'); + t.end(); +}); + + +test('anonymous LDAPv3 bind', function(t) { + var BIND = new Buffer(14); + BIND[0] = 0x30; // Sequence + BIND[1] = 12; // len + BIND[2] = 0x02; // ASN.1 Integer + BIND[3] = 1; // len + BIND[4] = 0x04; // msgid (make up 4) + BIND[5] = 0x60; // Bind Request + BIND[6] = 7; // len + BIND[7] = 0x02; // ASN.1 Integer + BIND[8] = 1; // len + BIND[9] = 0x03; // v3 + BIND[10] = 0x04; // String (bind dn) + BIND[11] = 0; // len + BIND[12] = 0x80; // ContextSpecific (choice) + BIND[13] = 0; // simple bind + + // Start testing ^^ + var ber = new BerReader(BIND); + t.equal(ber.readSequence(), 48, 'Not an ASN.1 Sequence'); + t.equal(ber.length, 12, 'Message length should be 12'); + t.equal(ber.readInt(), 4, 'Message id should have been 4'); + t.equal(ber.readSequence(), 96, 'Bind Request should have been 96'); + t.equal(ber.length, 7, 'Bind length should have been 7'); + t.equal(ber.readInt(), 3, 'LDAP version should have been 3'); + t.equal(ber.readString(), '', 'Bind DN should have been empty'); + t.equal(ber.length, 0, 'string length should have been 0'); + t.equal(ber.readByte(), 0x80, 'Should have been ContextSpecific (choice)'); + t.equal(ber.readByte(), 0, 'Should have been simple bind'); + t.equal(null, ber.readByte(), 'Should be out of data'); + t.end(); +}); + + +test('long string', function(t) { + var buf = new Buffer(256); + var o; + var s = + '2;649;CN=Red Hat CS 71GA Demo,O=Red Hat CS 71GA Demo,C=US;' + + 'CN=RHCS Agent - admin01,UID=admin01,O=redhat,C=US [1] This is ' + + 'Teena Vradmin\'s description.'; + buf[0] = 0x04; + buf[1] = 0x81; + buf[2] = 0x94; + buf.write(s, 3); + var ber = new BerReader(buf.slice(0, 3 + s.length)); + t.equal(ber.readString(), s); + t.end(); +}); diff --git a/node_modules/asn1/tst/ber/writer.test.js b/node_modules/asn1/tst/ber/writer.test.js new file mode 100644 index 0000000..d87cb7b --- /dev/null +++ b/node_modules/asn1/tst/ber/writer.test.js @@ -0,0 +1,370 @@ +// Copyright 2011 Mark Cavage All rights reserved. + +var test = require('tap').test; +var sys = require('sys'); + +///--- Globals + +var BerWriter; + +var BerReader; + + +///--- Tests + +test('load library', function(t) { + BerWriter = require('../../lib/index').BerWriter; + t.ok(BerWriter); + t.ok(new BerWriter()); + t.end(); +}); + + +test('write byte', function(t) { + var writer = new BerWriter(); + + writer.writeByte(0xC2); + var ber = writer.buffer; + + t.ok(ber); + t.equal(ber.length, 1, 'Wrong length'); + t.equal(ber[0], 0xC2, 'value wrong'); + + t.end(); +}); + + +test('write 1 byte int', function(t) { + var writer = new BerWriter(); + + writer.writeInt(0x7f); + var ber = writer.buffer; + + t.ok(ber); + t.equal(ber.length, 3, 'Wrong length for an int: ' + ber.length); + t.equal(ber[0], 0x02, 'ASN.1 tag wrong (2) -> ' + ber[0]); + t.equal(ber[1], 0x01, 'length wrong(1) -> ' + ber[1]); + t.equal(ber[2], 0x7f, 'value wrong(3) -> ' + ber[2]); + + t.end(); +}); + + +test('write 2 byte int', function(t) { + var writer = new BerWriter(); + + writer.writeInt(0x7ffe); + var ber = writer.buffer; + + t.ok(ber); + t.equal(ber.length, 4, 'Wrong length for an int'); + t.equal(ber[0], 0x02, 'ASN.1 tag wrong'); + t.equal(ber[1], 0x02, 'length wrong'); + t.equal(ber[2], 0x7f, 'value wrong (byte 1)'); + t.equal(ber[3], 0xfe, 'value wrong (byte 2)'); + + t.end(); +}); + + +test('write 3 byte int', function(t) { + var writer = new BerWriter(); + + writer.writeInt(0x7ffffe); + var ber = writer.buffer; + + t.ok(ber); + t.equal(ber.length, 5, 'Wrong length for an int'); + t.equal(ber[0], 0x02, 'ASN.1 tag wrong'); + t.equal(ber[1], 0x03, 'length wrong'); + t.equal(ber[2], 0x7f, 'value wrong (byte 1)'); + t.equal(ber[3], 0xff, 'value wrong (byte 2)'); + t.equal(ber[4], 0xfe, 'value wrong (byte 3)'); + + t.end(); +}); + + +test('write 4 byte int', function(t) { + var writer = new BerWriter(); + + writer.writeInt(0x7ffffffe); + var ber = writer.buffer; + + t.ok(ber); + + t.equal(ber.length, 6, 'Wrong length for an int'); + t.equal(ber[0], 0x02, 'ASN.1 tag wrong'); + t.equal(ber[1], 0x04, 'length wrong'); + t.equal(ber[2], 0x7f, 'value wrong (byte 1)'); + t.equal(ber[3], 0xff, 'value wrong (byte 2)'); + t.equal(ber[4], 0xff, 'value wrong (byte 3)'); + t.equal(ber[5], 0xfe, 'value wrong (byte 4)'); + + t.end(); +}); + + +test('write 1 byte negative int', function(t) { + var writer = new BerWriter(); + + writer.writeInt(-128); + var ber = writer.buffer; + + t.ok(ber); + + t.equal(ber.length, 3, 'Wrong length for an int'); + t.equal(ber[0], 0x02, 'ASN.1 tag wrong'); + t.equal(ber[1], 0x01, 'length wrong'); + t.equal(ber[2], 0x80, 'value wrong (byte 1)'); + + t.end(); +}); + + +test('write 2 byte negative int', function(t) { + var writer = new BerWriter(); + + writer.writeInt(-22400); + var ber = writer.buffer; + + t.ok(ber); + + t.equal(ber.length, 4, 'Wrong length for an int'); + t.equal(ber[0], 0x02, 'ASN.1 tag wrong'); + t.equal(ber[1], 0x02, 'length wrong'); + t.equal(ber[2], 0xa8, 'value wrong (byte 1)'); + t.equal(ber[3], 0x80, 'value wrong (byte 2)'); + + t.end(); +}); + + +test('write 3 byte negative int', function(t) { + var writer = new BerWriter(); + + writer.writeInt(-481653); + var ber = writer.buffer; + + t.ok(ber); + + t.equal(ber.length, 5, 'Wrong length for an int'); + t.equal(ber[0], 0x02, 'ASN.1 tag wrong'); + t.equal(ber[1], 0x03, 'length wrong'); + t.equal(ber[2], 0xf8, 'value wrong (byte 1)'); + t.equal(ber[3], 0xa6, 'value wrong (byte 2)'); + t.equal(ber[4], 0x8b, 'value wrong (byte 3)'); + + t.end(); +}); + + +test('write 4 byte negative int', function(t) { + var writer = new BerWriter(); + + writer.writeInt(-1522904131); + var ber = writer.buffer; + + t.ok(ber); + + t.equal(ber.length, 6, 'Wrong length for an int'); + t.equal(ber[0], 0x02, 'ASN.1 tag wrong'); + t.equal(ber[1], 0x04, 'length wrong'); + t.equal(ber[2], 0xa5, 'value wrong (byte 1)'); + t.equal(ber[3], 0x3a, 'value wrong (byte 2)'); + t.equal(ber[4], 0x53, 'value wrong (byte 3)'); + t.equal(ber[5], 0xbd, 'value wrong (byte 4)'); + + t.end(); +}); + + +test('write boolean', function(t) { + var writer = new BerWriter(); + + writer.writeBoolean(true); + writer.writeBoolean(false); + var ber = writer.buffer; + + t.ok(ber); + t.equal(ber.length, 6, 'Wrong length'); + t.equal(ber[0], 0x01, 'tag wrong'); + t.equal(ber[1], 0x01, 'length wrong'); + t.equal(ber[2], 0xff, 'value wrong'); + t.equal(ber[3], 0x01, 'tag wrong'); + t.equal(ber[4], 0x01, 'length wrong'); + t.equal(ber[5], 0x00, 'value wrong'); + + t.end(); +}); + + +test('write string', function(t) { + var writer = new BerWriter(); + writer.writeString('hello world'); + var ber = writer.buffer; + + t.ok(ber); + t.equal(ber.length, 13, 'wrong length'); + t.equal(ber[0], 0x04, 'wrong tag'); + t.equal(ber[1], 11, 'wrong length'); + t.equal(ber.slice(2).toString('utf8'), 'hello world', 'wrong value'); + + t.end(); +}); + +test('write buffer', function(t) { + var writer = new BerWriter(); + // write some stuff to start with + writer.writeString('hello world'); + var ber = writer.buffer; + var buf = new Buffer([0x04, 0x0b, 0x30, 0x09, 0x02, 0x01, 0x0f, 0x01, 0x01, + 0xff, 0x01, 0x01, 0xff]); + writer.writeBuffer(buf.slice(2, buf.length), 0x04); + ber = writer.buffer; + + t.ok(ber); + t.equal(ber.length, 26, 'wrong length'); + t.equal(ber[0], 0x04, 'wrong tag'); + t.equal(ber[1], 11, 'wrong length'); + t.equal(ber.slice(2, 13).toString('utf8'), 'hello world', 'wrong value'); + t.equal(ber[13], buf[0], 'wrong tag'); + t.equal(ber[14], buf[1], 'wrong length'); + for (var i = 13, j = 0; i < ber.length && j < buf.length; i++, j++) { + t.equal(ber[i], buf[j], 'buffer contents not identical'); + } + t.end(); +}); + +test('write string array', function(t) { + var writer = new BerWriter(); + writer.writeStringArray(['hello world', 'fubar!']); + var ber = writer.buffer; + + t.ok(ber); + + t.equal(ber.length, 21, 'wrong length'); + t.equal(ber[0], 0x04, 'wrong tag'); + t.equal(ber[1], 11, 'wrong length'); + t.equal(ber.slice(2, 13).toString('utf8'), 'hello world', 'wrong value'); + + t.equal(ber[13], 0x04, 'wrong tag'); + t.equal(ber[14], 6, 'wrong length'); + t.equal(ber.slice(15).toString('utf8'), 'fubar!', 'wrong value'); + + t.end(); +}); + + +test('resize internal buffer', function(t) { + var writer = new BerWriter({size: 2}); + writer.writeString('hello world'); + var ber = writer.buffer; + + t.ok(ber); + t.equal(ber.length, 13, 'wrong length'); + t.equal(ber[0], 0x04, 'wrong tag'); + t.equal(ber[1], 11, 'wrong length'); + t.equal(ber.slice(2).toString('utf8'), 'hello world', 'wrong value'); + + t.end(); +}); + + +test('sequence', function(t) { + var writer = new BerWriter({size: 25}); + writer.startSequence(); + writer.writeString('hello world'); + writer.endSequence(); + var ber = writer.buffer; + + t.ok(ber); + console.log(ber); + t.equal(ber.length, 15, 'wrong length'); + t.equal(ber[0], 0x30, 'wrong tag'); + t.equal(ber[1], 13, 'wrong length'); + t.equal(ber[2], 0x04, 'wrong tag'); + t.equal(ber[3], 11, 'wrong length'); + t.equal(ber.slice(4).toString('utf8'), 'hello world', 'wrong value'); + + t.end(); +}); + + +test('nested sequence', function(t) { + var writer = new BerWriter({size: 25}); + writer.startSequence(); + writer.writeString('hello world'); + writer.startSequence(); + writer.writeString('hello world'); + writer.endSequence(); + writer.endSequence(); + var ber = writer.buffer; + + t.ok(ber); + t.equal(ber.length, 30, 'wrong length'); + t.equal(ber[0], 0x30, 'wrong tag'); + t.equal(ber[1], 28, 'wrong length'); + t.equal(ber[2], 0x04, 'wrong tag'); + t.equal(ber[3], 11, 'wrong length'); + t.equal(ber.slice(4, 15).toString('utf8'), 'hello world', 'wrong value'); + t.equal(ber[15], 0x30, 'wrong tag'); + t.equal(ber[16], 13, 'wrong length'); + t.equal(ber[17], 0x04, 'wrong tag'); + t.equal(ber[18], 11, 'wrong length'); + t.equal(ber.slice(19, 30).toString('utf8'), 'hello world', 'wrong value'); + + t.end(); +}); + + +test('LDAP bind message', function(t) { + var dn = 'cn=foo,ou=unit,o=test'; + var writer = new BerWriter(); + writer.startSequence(); + writer.writeInt(3); // msgid = 3 + writer.startSequence(0x60); // ldap bind + writer.writeInt(3); // ldap v3 + writer.writeString(dn); + writer.writeByte(0x80); + writer.writeByte(0x00); + writer.endSequence(); + writer.endSequence(); + var ber = writer.buffer; + + t.ok(ber); + t.equal(ber.length, 35, 'wrong length (buffer)'); + t.equal(ber[0], 0x30, 'wrong tag'); + t.equal(ber[1], 33, 'wrong length'); + t.equal(ber[2], 0x02, 'wrong tag'); + t.equal(ber[3], 1, 'wrong length'); + t.equal(ber[4], 0x03, 'wrong value'); + t.equal(ber[5], 0x60, 'wrong tag'); + t.equal(ber[6], 28, 'wrong length'); + t.equal(ber[7], 0x02, 'wrong tag'); + t.equal(ber[8], 1, 'wrong length'); + t.equal(ber[9], 0x03, 'wrong value'); + t.equal(ber[10], 0x04, 'wrong tag'); + t.equal(ber[11], dn.length, 'wrong length'); + t.equal(ber.slice(12, 33).toString('utf8'), dn, 'wrong value'); + t.equal(ber[33], 0x80, 'wrong tag'); + t.equal(ber[34], 0x00, 'wrong len'); + + t.end(); +}); + + +test('Write OID', function(t) { + var oid = '1.2.840.113549.1.1.1'; + var writer = new BerWriter(); + writer.writeOID(oid); + + var ber = writer.buffer; + t.ok(ber); + console.log(require('util').inspect(ber)); + console.log(require('util').inspect(new Buffer([0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x01]))); + + t.end(); +}); diff --git a/node_modules/assert-plus/AUTHORS b/node_modules/assert-plus/AUTHORS new file mode 100644 index 0000000..1923524 --- /dev/null +++ b/node_modules/assert-plus/AUTHORS @@ -0,0 +1,6 @@ +Dave Eddy +Fred Kuo +Lars-Magnus Skog +Mark Cavage +Patrick Mooney +Rob Gulewich diff --git a/node_modules/assert-plus/CHANGES.md b/node_modules/assert-plus/CHANGES.md new file mode 100644 index 0000000..57d92bf --- /dev/null +++ b/node_modules/assert-plus/CHANGES.md @@ -0,0 +1,14 @@ +# assert-plus Changelog + +## 1.0.0 + +- *BREAKING* assert.number (and derivatives) now accept Infinity as valid input +- Add assert.finite check. Previous assert.number callers should use this if + they expect Infinity inputs to throw. + +## 0.2.0 + +- Fix `assert.object(null)` so it throws +- Fix optional/arrayOf exports for non-type-of asserts +- Add optiona/arrayOf exports for Stream/Date/Regex/uuid +- Add basic unit test coverage diff --git a/node_modules/assert-plus/README.md b/node_modules/assert-plus/README.md new file mode 100644 index 0000000..ec200d1 --- /dev/null +++ b/node_modules/assert-plus/README.md @@ -0,0 +1,162 @@ +# assert-plus + +This library is a super small wrapper over node's assert module that has two +things: (1) the ability to disable assertions with the environment variable +NODE\_NDEBUG, and (2) some API wrappers for argument testing. Like +`assert.string(myArg, 'myArg')`. As a simple example, most of my code looks +like this: + +```javascript + var assert = require('assert-plus'); + + function fooAccount(options, callback) { + assert.object(options, 'options'); + assert.number(options.id, 'options.id'); + assert.bool(options.isManager, 'options.isManager'); + assert.string(options.name, 'options.name'); + assert.arrayOfString(options.email, 'options.email'); + assert.func(callback, 'callback'); + + // Do stuff + callback(null, {}); + } +``` + +# API + +All methods that *aren't* part of node's core assert API are simply assumed to +take an argument, and then a string 'name' that's not a message; `AssertionError` +will be thrown if the assertion fails with a message like: + + AssertionError: foo (string) is required + at test (/home/mark/work/foo/foo.js:3:9) + at Object. (/home/mark/work/foo/foo.js:15:1) + at Module._compile (module.js:446:26) + at Object..js (module.js:464:10) + at Module.load (module.js:353:31) + at Function._load (module.js:311:12) + at Array.0 (module.js:484:10) + at EventEmitter._tickCallback (node.js:190:38) + +from: + +```javascript + function test(foo) { + assert.string(foo, 'foo'); + } +``` + +There you go. You can check that arrays are of a homogeneous type with `Arrayof$Type`: + +```javascript + function test(foo) { + assert.arrayOfString(foo, 'foo'); + } +``` + +You can assert IFF an argument is not `undefined` (i.e., an optional arg): + +```javascript + assert.optionalString(foo, 'foo'); +``` + +Lastly, you can opt-out of assertion checking altogether by setting the +environment variable `NODE_NDEBUG=1`. This is pseudo-useful if you have +lots of assertions, and don't want to pay `typeof ()` taxes to v8 in +production. Be advised: The standard functions re-exported from `assert` are +also disabled in assert-plus if NDEBUG is specified. Using them directly from +the `assert` module avoids this behavior. + +The complete list of APIs is: + +* assert.array +* assert.bool +* assert.buffer +* assert.func +* assert.number +* assert.finite +* assert.object +* assert.string +* assert.stream +* assert.date +* assert.regexp +* assert.uuid +* assert.arrayOfArray +* assert.arrayOfBool +* assert.arrayOfBuffer +* assert.arrayOfFunc +* assert.arrayOfNumber +* assert.arrayOfFinite +* assert.arrayOfObject +* assert.arrayOfString +* assert.arrayOfStream +* assert.arrayOfDate +* assert.arrayOfRegexp +* assert.arrayOfUuid +* assert.optionalArray +* assert.optionalBool +* assert.optionalBuffer +* assert.optionalFunc +* assert.optionalNumber +* assert.optionalFinite +* assert.optionalObject +* assert.optionalString +* assert.optionalStream +* assert.optionalDate +* assert.optionalRegexp +* assert.optionalUuid +* assert.optionalArrayOfArray +* assert.optionalArrayOfBool +* assert.optionalArrayOfBuffer +* assert.optionalArrayOfFunc +* assert.optionalArrayOfNumber +* assert.optionalArrayOfFinite +* assert.optionalArrayOfObject +* assert.optionalArrayOfString +* assert.optionalArrayOfStream +* assert.optionalArrayOfDate +* assert.optionalArrayOfRegexp +* assert.optionalArrayOfUuid +* assert.AssertionError +* assert.fail +* assert.ok +* assert.equal +* assert.notEqual +* assert.deepEqual +* assert.notDeepEqual +* assert.strictEqual +* assert.notStrictEqual +* assert.throws +* assert.doesNotThrow +* assert.ifError + +# Installation + + npm install assert-plus + +## License + +The MIT License (MIT) +Copyright (c) 2012 Mark Cavage + +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. + +## Bugs + +See . diff --git a/node_modules/assert-plus/assert.js b/node_modules/assert-plus/assert.js new file mode 100644 index 0000000..26f944e --- /dev/null +++ b/node_modules/assert-plus/assert.js @@ -0,0 +1,211 @@ +// Copyright (c) 2012, Mark Cavage. All rights reserved. +// Copyright 2015 Joyent, Inc. + +var assert = require('assert'); +var Stream = require('stream').Stream; +var util = require('util'); + + +///--- Globals + +/* JSSTYLED */ +var UUID_REGEXP = /^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$/; + + +///--- Internal + +function _capitalize(str) { + return (str.charAt(0).toUpperCase() + str.slice(1)); +} + +function _toss(name, expected, oper, arg, actual) { + throw new assert.AssertionError({ + message: util.format('%s (%s) is required', name, expected), + actual: (actual === undefined) ? typeof (arg) : actual(arg), + expected: expected, + operator: oper || '===', + stackStartFunction: _toss.caller + }); +} + +function _getClass(arg) { + return (Object.prototype.toString.call(arg).slice(8, -1)); +} + +function noop() { + // Why even bother with asserts? +} + + +///--- Exports + +var types = { + bool: { + check: function (arg) { return typeof (arg) === 'boolean'; } + }, + func: { + check: function (arg) { return typeof (arg) === 'function'; } + }, + string: { + check: function (arg) { return typeof (arg) === 'string'; } + }, + object: { + check: function (arg) { + return typeof (arg) === 'object' && arg !== null; + } + }, + number: { + check: function (arg) { + return typeof (arg) === 'number' && !isNaN(arg); + } + }, + finite: { + check: function (arg) { + return typeof (arg) === 'number' && !isNaN(arg) && isFinite(arg); + } + }, + buffer: { + check: function (arg) { return Buffer.isBuffer(arg); }, + operator: 'Buffer.isBuffer' + }, + array: { + check: function (arg) { return Array.isArray(arg); }, + operator: 'Array.isArray' + }, + stream: { + check: function (arg) { return arg instanceof Stream; }, + operator: 'instanceof', + actual: _getClass + }, + date: { + check: function (arg) { return arg instanceof Date; }, + operator: 'instanceof', + actual: _getClass + }, + regexp: { + check: function (arg) { return arg instanceof RegExp; }, + operator: 'instanceof', + actual: _getClass + }, + uuid: { + check: function (arg) { + return typeof (arg) === 'string' && UUID_REGEXP.test(arg); + }, + operator: 'isUUID' + } +}; + +function _setExports(ndebug) { + var keys = Object.keys(types); + var out; + + /* re-export standard assert */ + if (process.env.NODE_NDEBUG) { + out = noop; + } else { + out = function (arg, msg) { + if (!arg) { + _toss(msg, 'true', arg); + } + }; + } + + /* standard checks */ + keys.forEach(function (k) { + if (ndebug) { + out[k] = noop; + return; + } + var type = types[k]; + out[k] = function (arg, msg) { + if (!type.check(arg)) { + _toss(msg, k, type.operator, arg, type.actual); + } + }; + }); + + /* optional checks */ + keys.forEach(function (k) { + var name = 'optional' + _capitalize(k); + if (ndebug) { + out[name] = noop; + return; + } + var type = types[k]; + out[name] = function (arg, msg) { + if (arg === undefined || arg === null) { + return; + } + if (!type.check(arg)) { + _toss(msg, k, type.operator, arg, type.actual); + } + }; + }); + + /* arrayOf checks */ + keys.forEach(function (k) { + var name = 'arrayOf' + _capitalize(k); + if (ndebug) { + out[name] = noop; + return; + } + var type = types[k]; + var expected = '[' + k + ']'; + out[name] = function (arg, msg) { + if (!Array.isArray(arg)) { + _toss(msg, expected, type.operator, arg, type.actual); + } + var i; + for (i = 0; i < arg.length; i++) { + if (!type.check(arg[i])) { + _toss(msg, expected, type.operator, arg, type.actual); + } + } + }; + }); + + /* optionalArrayOf checks */ + keys.forEach(function (k) { + var name = 'optionalArrayOf' + _capitalize(k); + if (ndebug) { + out[name] = noop; + return; + } + var type = types[k]; + var expected = '[' + k + ']'; + out[name] = function (arg, msg) { + if (arg === undefined || arg === null) { + return; + } + if (!Array.isArray(arg)) { + _toss(msg, expected, type.operator, arg, type.actual); + } + var i; + for (i = 0; i < arg.length; i++) { + if (!type.check(arg[i])) { + _toss(msg, expected, type.operator, arg, type.actual); + } + } + }; + }); + + /* re-export built-in assertions */ + Object.keys(assert).forEach(function (k) { + if (k === 'AssertionError') { + out[k] = assert[k]; + return; + } + if (ndebug) { + out[k] = noop; + return; + } + out[k] = assert[k]; + }); + + /* export ourselves (for unit tests _only_) */ + out._setExports = _setExports; + + return out; +} + +module.exports = _setExports(process.env.NODE_NDEBUG); diff --git a/node_modules/assert-plus/package.json b/node_modules/assert-plus/package.json new file mode 100644 index 0000000..fed66ef --- /dev/null +++ b/node_modules/assert-plus/package.json @@ -0,0 +1,84 @@ +{ + "_from": "assert-plus@^1.0.0", + "_id": "assert-plus@1.0.0", + "_inBundle": false, + "_integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "_location": "/assert-plus", + "_phantomChildren": {}, + "_requested": { + "type": "range", + "registry": true, + "raw": "assert-plus@^1.0.0", + "name": "assert-plus", + "escapedName": "assert-plus", + "rawSpec": "^1.0.0", + "saveSpec": null, + "fetchSpec": "^1.0.0" + }, + "_requiredBy": [ + "/dashdash", + "/ldapjs", + "/verror" + ], + "_resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "_shasum": "f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525", + "_spec": "assert-plus@^1.0.0", + "_where": "/home/erik/Documents/workspace_brackets/a1_BME_Project_Ohm/om/node_modules/ldapjs", + "author": { + "name": "Mark Cavage", + "email": "mcavage@gmail.com" + }, + "bugs": { + "url": "https://github.com/mcavage/node-assert-plus/issues" + }, + "bundleDependencies": false, + "contributors": [ + { + "name": "Dave Eddy", + "email": "dave@daveeddy.com" + }, + { + "name": "Fred Kuo", + "email": "fred.kuo@joyent.com" + }, + { + "name": "Lars-Magnus Skog", + "email": "ralphtheninja@riseup.net" + }, + { + "name": "Mark Cavage", + "email": "mcavage@gmail.com" + }, + { + "name": "Patrick Mooney", + "email": "pmooney@pfmooney.com" + }, + { + "name": "Rob Gulewich", + "email": "robert.gulewich@joyent.com" + } + ], + "dependencies": {}, + "deprecated": false, + "description": "Extra assertions on top of node's assert module", + "devDependencies": { + "faucet": "0.0.1", + "tape": "4.2.2" + }, + "engines": { + "node": ">=0.8" + }, + "homepage": "https://github.com/mcavage/node-assert-plus#readme", + "license": "MIT", + "main": "./assert.js", + "name": "assert-plus", + "optionalDependencies": {}, + "repository": { + "type": "git", + "url": "git+https://github.com/mcavage/node-assert-plus.git" + }, + "scripts": { + "test": "tape tests/*.js | ./node_modules/.bin/faucet" + }, + "version": "1.0.0" +} diff --git a/node_modules/async/CHANGELOG.md b/node_modules/async/CHANGELOG.md index c226ba8..f1d226e 100644 --- a/node_modules/async/CHANGELOG.md +++ b/node_modules/async/CHANGELOG.md @@ -1,3 +1,6 @@ +#v2.6.2 +- Updated lodash to squelch a security warning (#1620) + # v2.6.1 - Updated lodash to prevent `npm audit` warnings. (#1532, #1533) - Made `async-es` more optimized for webpack users (#1517) diff --git a/node_modules/async/all.js b/node_modules/async/all.js index 26023c1..d0565b0 100644 --- a/node_modules/async/all.js +++ b/node_modules/async/all.js @@ -47,4 +47,4 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de * }); */ exports.default = (0, _doParallel2.default)((0, _createTester2.default)(_notId2.default, _notId2.default)); -module.exports = exports['default']; +module.exports = exports['default']; \ No newline at end of file diff --git a/node_modules/async/allLimit.js b/node_modules/async/allLimit.js index 03dc04b..a1a759a 100644 --- a/node_modules/async/allLimit.js +++ b/node_modules/async/allLimit.js @@ -39,4 +39,4 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de * depending on the values of the async tests. Invoked with (err, result). */ exports.default = (0, _doParallelLimit2.default)((0, _createTester2.default)(_notId2.default, _notId2.default)); -module.exports = exports['default']; +module.exports = exports['default']; \ No newline at end of file diff --git a/node_modules/async/allSeries.js b/node_modules/async/allSeries.js index 474b4db..23bfebb 100644 --- a/node_modules/async/allSeries.js +++ b/node_modules/async/allSeries.js @@ -34,4 +34,4 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de * depending on the values of the async tests. Invoked with (err, result). */ exports.default = (0, _doLimit2.default)(_everyLimit2.default, 1); -module.exports = exports['default']; +module.exports = exports['default']; \ No newline at end of file diff --git a/node_modules/async/any.js b/node_modules/async/any.js index 64c9286..a8e70f7 100644 --- a/node_modules/async/any.js +++ b/node_modules/async/any.js @@ -49,4 +49,4 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de * }); */ exports.default = (0, _doParallel2.default)((0, _createTester2.default)(Boolean, _identity2.default)); -module.exports = exports['default']; +module.exports = exports['default']; \ No newline at end of file diff --git a/node_modules/async/anyLimit.js b/node_modules/async/anyLimit.js index 5afcdfd..24ca3f4 100644 --- a/node_modules/async/anyLimit.js +++ b/node_modules/async/anyLimit.js @@ -40,4 +40,4 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de * tests. Invoked with (err, result). */ exports.default = (0, _doParallelLimit2.default)((0, _createTester2.default)(Boolean, _identity2.default)); -module.exports = exports['default']; +module.exports = exports['default']; \ No newline at end of file diff --git a/node_modules/async/anySeries.js b/node_modules/async/anySeries.js index 4f2afdb..dc24ed2 100644 --- a/node_modules/async/anySeries.js +++ b/node_modules/async/anySeries.js @@ -35,4 +35,4 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de * tests. Invoked with (err, result). */ exports.default = (0, _doLimit2.default)(_someLimit2.default, 1); -module.exports = exports['default']; +module.exports = exports['default']; \ No newline at end of file diff --git a/node_modules/async/apply.js b/node_modules/async/apply.js index 9098008..f590fa5 100644 --- a/node_modules/async/apply.js +++ b/node_modules/async/apply.js @@ -65,4 +65,4 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de * two * three */ -module.exports = exports['default']; +module.exports = exports['default']; \ No newline at end of file diff --git a/node_modules/async/applyEach.js b/node_modules/async/applyEach.js index a435b56..06c0845 100644 --- a/node_modules/async/applyEach.js +++ b/node_modules/async/applyEach.js @@ -48,4 +48,4 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de * ); */ exports.default = (0, _applyEach2.default)(_map2.default); -module.exports = exports['default']; +module.exports = exports['default']; \ No newline at end of file diff --git a/node_modules/async/applyEachSeries.js b/node_modules/async/applyEachSeries.js index ceabc79..ad80280 100644 --- a/node_modules/async/applyEachSeries.js +++ b/node_modules/async/applyEachSeries.js @@ -34,4 +34,4 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de * function call. */ exports.default = (0, _applyEach2.default)(_mapSeries2.default); -module.exports = exports['default']; +module.exports = exports['default']; \ No newline at end of file diff --git a/node_modules/async/asyncify.js b/node_modules/async/asyncify.js index 77272f5..5e3fc91 100644 --- a/node_modules/async/asyncify.js +++ b/node_modules/async/asyncify.js @@ -107,4 +107,4 @@ function invokeCallback(callback, error, value) { function rethrow(error) { throw error; } -module.exports = exports['default']; +module.exports = exports['default']; \ No newline at end of file diff --git a/node_modules/async/auto.js b/node_modules/async/auto.js index 6d9cb0d..26c1d56 100644 --- a/node_modules/async/auto.js +++ b/node_modules/async/auto.js @@ -286,4 +286,4 @@ module.exports = exports['default']; * console.log('err = ', err); * console.log('results = ', results); * }); - */ + */ \ No newline at end of file diff --git a/node_modules/async/autoInject.js b/node_modules/async/autoInject.js index a75f63b..bfbe7e8 100644 --- a/node_modules/async/autoInject.js +++ b/node_modules/async/autoInject.js @@ -167,4 +167,4 @@ function autoInject(tasks, callback) { (0, _auto2.default)(newTasks, callback); } -module.exports = exports['default']; +module.exports = exports['default']; \ No newline at end of file diff --git a/node_modules/async/cargo.js b/node_modules/async/cargo.js index e8d531f..c7e59c7 100644 --- a/node_modules/async/cargo.js +++ b/node_modules/async/cargo.js @@ -91,4 +91,4 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de function cargo(worker, payload) { return (0, _queue2.default)(worker, 1, payload); } -module.exports = exports['default']; +module.exports = exports['default']; \ No newline at end of file diff --git a/node_modules/async/compose.js b/node_modules/async/compose.js index 1f58f24..47c49f6 100644 --- a/node_modules/async/compose.js +++ b/node_modules/async/compose.js @@ -55,4 +55,4 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de * // result now equals 15 * }); */ -module.exports = exports['default']; +module.exports = exports['default']; \ No newline at end of file diff --git a/node_modules/async/concat.js b/node_modules/async/concat.js index 3c0623c..c39ea00 100644 --- a/node_modules/async/concat.js +++ b/node_modules/async/concat.js @@ -40,4 +40,4 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de * }); */ exports.default = (0, _doLimit2.default)(_concatLimit2.default, Infinity); -module.exports = exports['default']; +module.exports = exports['default']; \ No newline at end of file diff --git a/node_modules/async/concatLimit.js b/node_modules/async/concatLimit.js index 1bedd1f..f32cd4d 100644 --- a/node_modules/async/concatLimit.js +++ b/node_modules/async/concatLimit.js @@ -62,4 +62,4 @@ var _concat = Array.prototype.concat; * containing the concatenated results of the `iteratee` function. Invoked with * (err, results). */ -module.exports = exports['default']; +module.exports = exports['default']; \ No newline at end of file diff --git a/node_modules/async/concatSeries.js b/node_modules/async/concatSeries.js index 7ce8c72..541ab7d 100644 --- a/node_modules/async/concatSeries.js +++ b/node_modules/async/concatSeries.js @@ -33,4 +33,4 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de * (err, results). */ exports.default = (0, _doLimit2.default)(_concatLimit2.default, 1); -module.exports = exports['default']; +module.exports = exports['default']; \ No newline at end of file diff --git a/node_modules/async/constant.js b/node_modules/async/constant.js index 9f7bcc8..c825475 100644 --- a/node_modules/async/constant.js +++ b/node_modules/async/constant.js @@ -63,4 +63,4 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de * //... * }, callback); */ -module.exports = exports['default']; +module.exports = exports['default']; \ No newline at end of file diff --git a/node_modules/async/detect.js b/node_modules/async/detect.js index 05a4e3e..db46783 100644 --- a/node_modules/async/detect.js +++ b/node_modules/async/detect.js @@ -58,4 +58,4 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de * }); */ exports.default = (0, _doParallel2.default)((0, _createTester2.default)(_identity2.default, _findGetResult2.default)); -module.exports = exports['default']; +module.exports = exports['default']; \ No newline at end of file diff --git a/node_modules/async/detectLimit.js b/node_modules/async/detectLimit.js index 045877a..6bf6560 100644 --- a/node_modules/async/detectLimit.js +++ b/node_modules/async/detectLimit.js @@ -45,4 +45,4 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de * (err, result). */ exports.default = (0, _doParallelLimit2.default)((0, _createTester2.default)(_identity2.default, _findGetResult2.default)); -module.exports = exports['default']; +module.exports = exports['default']; \ No newline at end of file diff --git a/node_modules/async/detectSeries.js b/node_modules/async/detectSeries.js index 674afb5..6fe16c9 100644 --- a/node_modules/async/detectSeries.js +++ b/node_modules/async/detectSeries.js @@ -35,4 +35,4 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de * (err, result). */ exports.default = (0, _doLimit2.default)(_detectLimit2.default, 1); -module.exports = exports['default']; +module.exports = exports['default']; \ No newline at end of file diff --git a/node_modules/async/dir.js b/node_modules/async/dir.js index d38f67b..85fbcce 100644 --- a/node_modules/async/dir.js +++ b/node_modules/async/dir.js @@ -40,4 +40,4 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de * {hello: 'world'} */ exports.default = (0, _consoleFunc2.default)('dir'); -module.exports = exports['default']; +module.exports = exports['default']; \ No newline at end of file diff --git a/node_modules/async/dist/async.min.js b/node_modules/async/dist/async.min.js index 0922f6c..013f194 100644 --- a/node_modules/async/dist/async.min.js +++ b/node_modules/async/dist/async.min.js @@ -1,2 +1,2 @@ !function(n,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t(n.async=n.async||{})}(this,function(n){"use strict";function t(n,t){t|=0;for(var e=Math.max(n.length-t,0),r=Array(e),u=0;u-1&&n%1==0&&n<=Tt}function d(n){return null!=n&&v(n.length)&&!y(n)}function m(){}function g(n){return function(){if(null!==n){var t=n;n=null,t.apply(this,arguments)}}}function b(n,t){for(var e=-1,r=Array(n);++e-1&&n%1==0&&nu?0:u+t),e=e>u?u:e,e<0&&(e+=u),u=t>e?0:e-t>>>0,t>>>=0;for(var i=Array(u);++r=r?n:Z(n,t,e)}function tn(n,t){for(var e=n.length;e--&&J(t,n[e],0)>-1;);return e}function en(n,t){for(var e=-1,r=n.length;++e-1;);return e}function rn(n){return n.split("")}function un(n){return Xe.test(n)}function on(n){return n.match(mr)||[]}function cn(n){return un(n)?on(n):rn(n)}function fn(n){return null==n?"":Y(n)}function an(n,t,e){if(n=fn(n),n&&(e||void 0===t))return n.replace(gr,"");if(!n||!(t=Y(t)))return n;var r=cn(n),u=cn(t),i=en(r,u),o=tn(r,u)+1;return nn(r,i,o).join("")}function ln(n){return n=n.toString().replace(kr,""),n=n.match(br)[2].replace(" ",""),n=n?n.split(jr):[],n=n.map(function(n){return an(n.replace(Sr,""))})}function sn(n,t){var e={};N(n,function(n,t){function r(t,e){var r=K(u,function(n){return t[n]});r.push(e),a(n).apply(null,r)}var u,i=f(n),o=!i&&1===n.length||i&&0===n.length;if(Pt(n))u=n.slice(0,-1),n=n[n.length-1],e[t]=u.concat(u.length>0?r:n);else if(o)e[t]=n;else{if(u=ln(n),0===n.length&&!i&&0===u.length)throw new Error("autoInject task functions require explicit parameters.");i||u.pop(),e[t]=u.concat(r)}}),Ve(e,t)}function pn(){this.head=this.tail=null,this.length=0}function hn(n,t){n.length=1,n.head=n.tail=t}function yn(n,t,e){function r(n,t,e){if(null!=e&&"function"!=typeof e)throw new Error("task callback must be a function");if(s.started=!0,Pt(n)||(n=[n]),0===n.length&&s.idle())return lt(function(){s.drain()});for(var r=0,u=n.length;r0&&c.splice(i,1),u.callback.apply(u,arguments),null!=t&&s.error(t,u.data)}o<=s.concurrency-s.buffer&&s.unsaturated(),s.idle()&&s.drain(),s.process()}}if(null==t)t=1;else if(0===t)throw new Error("Concurrency must not be zero");var i=a(n),o=0,c=[],f=!1,l=!1,s={_tasks:new pn,concurrency:t,payload:e,saturated:m,unsaturated:m,buffer:t/4,empty:m,drain:m,error:m,started:!1,paused:!1,push:function(n,t){r(n,!1,t)},kill:function(){s.drain=m,s._tasks.empty()},unshift:function(n,t){r(n,!0,t)},remove:function(n){s._tasks.remove(n)},process:function(){if(!l){for(l=!0;!s.paused&&o2&&(i=t(arguments,1)),u[e]=i,r(n)})},function(n){r(n,u)})}function Dn(n,t){Vn(Ie,n,t)}function Rn(n,t,e){Vn(q(t),n,e)}function Cn(n,t){if(t=g(t||m),!Pt(n))return t(new TypeError("First argument to race must be an array of functions"));if(!n.length)return t();for(var e=0,r=n.length;er?1:0}var u=a(t);_e(n,function(n,t){u(n,function(e,r){return e?t(e):void t(null,{value:n,criteria:r})})},function(n,t){return n?e(n):void e(null,K(t.sort(r),Fn("value")))})}function Xn(n,t,e){var r=a(n);return ct(function(u,i){function o(){var t=n.name||"anonymous",r=new Error('Callback function "'+t+'" timed out.');r.code="ETIMEDOUT",e&&(r.info=e),f=!0,i(r)}var c,f=!1;u.push(function(){f||(i.apply(null,arguments),clearTimeout(c))}),c=setTimeout(o,t),r.apply(null,u)})}function Yn(n,t,e,r){for(var u=-1,i=iu(uu((t-n)/(e||1)),0),o=Array(i);i--;)o[r?i:++u]=n,n+=e;return o}function Zn(n,t,e,r){var u=a(e);Ue(Yn(0,n,1),t,u,r)}function nt(n,t,e,r){arguments.length<=3&&(r=e,e=t,t=Pt(n)?[]:{}),r=g(r||m);var u=a(e);Ie(n,function(n,e,r){u(t,n,e,r)},function(n){r(n,t)})}function tt(n,e){var r,u=null;e=e||m,Ur(n,function(n,e){a(n)(function(n,i){r=arguments.length>2?t(arguments,1):i,u=n,e(!n)})},function(){e(u,r)})}function et(n){return function(){return(n.unmemoized||n).apply(null,arguments)}}function rt(n,e,r){r=U(r||m);var u=a(e);if(!n())return r(null);var i=function(e){if(e)return r(e);if(n())return u(i);var o=t(arguments,1);r.apply(null,[null].concat(o))};u(i)}function ut(n,t,e){rt(function(){return!n.apply(this,arguments)},t,e)}var it,ot=function(n){var e=t(arguments,1);return function(){var r=t(arguments);return n.apply(null,e.concat(r))}},ct=function(n){return function(){var e=t(arguments),r=e.pop();n.call(this,e,r)}},ft="function"==typeof setImmediate&&setImmediate,at="object"==typeof process&&"function"==typeof process.nextTick;it=ft?setImmediate:at?process.nextTick:r;var lt=u(it),st="function"==typeof Symbol,pt="object"==typeof global&&global&&global.Object===Object&&global,ht="object"==typeof self&&self&&self.Object===Object&&self,yt=pt||ht||Function("return this")(),vt=yt.Symbol,dt=Object.prototype,mt=dt.hasOwnProperty,gt=dt.toString,bt=vt?vt.toStringTag:void 0,jt=Object.prototype,St=jt.toString,kt="[object Null]",Lt="[object Undefined]",Ot=vt?vt.toStringTag:void 0,wt="[object AsyncFunction]",xt="[object Function]",Et="[object GeneratorFunction]",At="[object Proxy]",Tt=9007199254740991,Bt={},Ft="function"==typeof Symbol&&Symbol.iterator,It=function(n){return Ft&&n[Ft]&&n[Ft]()},_t="[object Arguments]",Mt=Object.prototype,Ut=Mt.hasOwnProperty,qt=Mt.propertyIsEnumerable,zt=S(function(){return arguments}())?S:function(n){return j(n)&&Ut.call(n,"callee")&&!qt.call(n,"callee")},Pt=Array.isArray,Vt="object"==typeof n&&n&&!n.nodeType&&n,Dt=Vt&&"object"==typeof module&&module&&!module.nodeType&&module,Rt=Dt&&Dt.exports===Vt,Ct=Rt?yt.Buffer:void 0,$t=Ct?Ct.isBuffer:void 0,Wt=$t||k,Nt=9007199254740991,Qt=/^(?:0|[1-9]\d*)$/,Gt="[object Arguments]",Ht="[object Array]",Jt="[object Boolean]",Kt="[object Date]",Xt="[object Error]",Yt="[object Function]",Zt="[object Map]",ne="[object Number]",te="[object Object]",ee="[object RegExp]",re="[object Set]",ue="[object String]",ie="[object WeakMap]",oe="[object ArrayBuffer]",ce="[object DataView]",fe="[object Float32Array]",ae="[object Float64Array]",le="[object Int8Array]",se="[object Int16Array]",pe="[object Int32Array]",he="[object Uint8Array]",ye="[object Uint8ClampedArray]",ve="[object Uint16Array]",de="[object Uint32Array]",me={};me[fe]=me[ae]=me[le]=me[se]=me[pe]=me[he]=me[ye]=me[ve]=me[de]=!0,me[Gt]=me[Ht]=me[oe]=me[Jt]=me[ce]=me[Kt]=me[Xt]=me[Yt]=me[Zt]=me[ne]=me[te]=me[ee]=me[re]=me[ue]=me[ie]=!1;var ge="object"==typeof n&&n&&!n.nodeType&&n,be=ge&&"object"==typeof module&&module&&!module.nodeType&&module,je=be&&be.exports===ge,Se=je&&pt.process,ke=function(){try{var n=be&&be.require&&be.require("util").types;return n?n:Se&&Se.binding&&Se.binding("util")}catch(n){}}(),Le=ke&&ke.isTypedArray,Oe=Le?w(Le):O,we=Object.prototype,xe=we.hasOwnProperty,Ee=Object.prototype,Ae=A(Object.keys,Object),Te=Object.prototype,Be=Te.hasOwnProperty,Fe=P(z,1/0),Ie=function(n,t,e){var r=d(n)?V:Fe;r(n,a(t),e)},_e=D(R),Me=l(_e),Ue=C(R),qe=P(Ue,1),ze=l(qe),Pe=W(),Ve=function(n,e,r){function u(n,t){j.push(function(){f(n,t)})}function i(){if(0===j.length&&0===v)return r(null,y);for(;j.length&&v2&&(u=t(arguments,1)),e){var i={};N(y,function(n,t){i[t]=n}),i[n]=u,d=!0,b=Object.create(null),r(e,i)}else y[n]=u,c(n)});v++;var i=a(e[e.length-1]);e.length>1?i(y,u):i(u)}}function l(){for(var n,t=0;S.length;)n=S.pop(),t++,$(s(n),function(n){0===--k[n]&&S.push(n)});if(t!==h)throw new Error("async.auto cannot execute tasks due to a recursive dependency")}function s(t){var e=[];return N(n,function(n,r){Pt(n)&&J(n,t,0)>=0&&e.push(r)}),e}"function"==typeof e&&(r=e,e=null),r=g(r||m);var p=B(n),h=p.length;if(!h)return r(null);e||(e=h);var y={},v=0,d=!1,b=Object.create(null),j=[],S=[],k={};N(n,function(t,e){if(!Pt(t))return u(e,[t]),void S.push(e);var r=t.slice(0,t.length-1),i=r.length;return 0===i?(u(e,t),void S.push(e)):(k[e]=i,void $(r,function(c){if(!n[c])throw new Error("async.auto task `"+e+"` has a non-existent dependency `"+c+"` in "+r.join(", "));o(c,function(){i--,0===i&&u(e,t)})}))}),l(),i()},De="[object Symbol]",Re=1/0,Ce=vt?vt.prototype:void 0,$e=Ce?Ce.toString:void 0,We="\\ud800-\\udfff",Ne="\\u0300-\\u036f",Qe="\\ufe20-\\ufe2f",Ge="\\u20d0-\\u20ff",He=Ne+Qe+Ge,Je="\\ufe0e\\ufe0f",Ke="\\u200d",Xe=RegExp("["+Ke+We+He+Je+"]"),Ye="\\ud800-\\udfff",Ze="\\u0300-\\u036f",nr="\\ufe20-\\ufe2f",tr="\\u20d0-\\u20ff",er=Ze+nr+tr,rr="\\ufe0e\\ufe0f",ur="["+Ye+"]",ir="["+er+"]",or="\\ud83c[\\udffb-\\udfff]",cr="(?:"+ir+"|"+or+")",fr="[^"+Ye+"]",ar="(?:\\ud83c[\\udde6-\\uddff]){2}",lr="[\\ud800-\\udbff][\\udc00-\\udfff]",sr="\\u200d",pr=cr+"?",hr="["+rr+"]?",yr="(?:"+sr+"(?:"+[fr,ar,lr].join("|")+")"+hr+pr+")*",vr=hr+pr+yr,dr="(?:"+[fr+ir+"?",ir,ar,lr,ur].join("|")+")",mr=RegExp(or+"(?="+or+")|"+dr+vr,"g"),gr=/^\s+|\s+$/g,br=/^(?:async\s+)?(function)?\s*[^\(]*\(\s*([^\)]*)\)/m,jr=/,/,Sr=/(=.+)?(\s*)$/,kr=/((\/\/.*$)|(\/\*[\s\S]*?\*\/))/gm;pn.prototype.removeLink=function(n){return n.prev?n.prev.next=n.next:this.head=n.next,n.next?n.next.prev=n.prev:this.tail=n.prev,n.prev=n.next=null,this.length-=1,n},pn.prototype.empty=function(){for(;this.head;)this.shift();return this},pn.prototype.insertAfter=function(n,t){t.prev=n,t.next=n.next,n.next?n.next.prev=t:this.tail=t,n.next=t,this.length+=1},pn.prototype.insertBefore=function(n,t){t.prev=n.prev,t.next=n,n.prev?n.prev.next=t:this.head=t,n.prev=t,this.length+=1},pn.prototype.unshift=function(n){this.head?this.insertBefore(this.head,n):hn(this,n)},pn.prototype.push=function(n){this.tail?this.insertAfter(this.tail,n):hn(this,n)},pn.prototype.shift=function(){return this.head&&this.removeLink(this.head)},pn.prototype.pop=function(){return this.tail&&this.removeLink(this.tail)},pn.prototype.toArray=function(){for(var n=Array(this.length),t=this.head,e=0;e=u.priority;)u=u.next;for(var i=0,o=n.length;i b ? 1 : 0; } } -module.exports = exports['default']; +module.exports = exports['default']; \ No newline at end of file diff --git a/node_modules/async/timeout.js b/node_modules/async/timeout.js index cee632f..b5cb505 100644 --- a/node_modules/async/timeout.js +++ b/node_modules/async/timeout.js @@ -86,4 +86,4 @@ function timeout(asyncFn, milliseconds, info) { fn.apply(null, args); }); } -module.exports = exports['default']; +module.exports = exports['default']; \ No newline at end of file diff --git a/node_modules/async/times.js b/node_modules/async/times.js index 1765a0d..b5ca24d 100644 --- a/node_modules/async/times.js +++ b/node_modules/async/times.js @@ -47,4 +47,4 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de * }); */ exports.default = (0, _doLimit2.default)(_timesLimit2.default, Infinity); -module.exports = exports['default']; +module.exports = exports['default']; \ No newline at end of file diff --git a/node_modules/async/timesLimit.js b/node_modules/async/timesLimit.js index 39c227e..aad8495 100644 --- a/node_modules/async/timesLimit.js +++ b/node_modules/async/timesLimit.js @@ -39,4 +39,4 @@ function timeLimit(count, limit, iteratee, callback) { var _iteratee = (0, _wrapAsync2.default)(iteratee); (0, _mapLimit2.default)((0, _baseRange2.default)(0, count, 1), limit, _iteratee, callback); } -module.exports = exports['default']; +module.exports = exports['default']; \ No newline at end of file diff --git a/node_modules/async/timesSeries.js b/node_modules/async/timesSeries.js index 40ba9ab..f187a35 100644 --- a/node_modules/async/timesSeries.js +++ b/node_modules/async/timesSeries.js @@ -29,4 +29,4 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de * @param {Function} callback - see {@link module:Collections.map}. */ exports.default = (0, _doLimit2.default)(_timesLimit2.default, 1); -module.exports = exports['default']; +module.exports = exports['default']; \ No newline at end of file diff --git a/node_modules/async/transform.js b/node_modules/async/transform.js index 5636ad2..84ee217 100644 --- a/node_modules/async/transform.js +++ b/node_modules/async/transform.js @@ -84,4 +84,4 @@ function transform(coll, accumulator, iteratee, callback) { callback(err, accumulator); }); } -module.exports = exports['default']; +module.exports = exports['default']; \ No newline at end of file diff --git a/node_modules/async/tryEach.js b/node_modules/async/tryEach.js index 6fe6a5b..f4e4c97 100644 --- a/node_modules/async/tryEach.js +++ b/node_modules/async/tryEach.js @@ -78,4 +78,4 @@ function tryEach(tasks, callback) { callback(error, result); }); } -module.exports = exports['default']; +module.exports = exports['default']; \ No newline at end of file diff --git a/node_modules/async/unmemoize.js b/node_modules/async/unmemoize.js index 644d34c..08f9f9f 100644 --- a/node_modules/async/unmemoize.js +++ b/node_modules/async/unmemoize.js @@ -22,4 +22,4 @@ function unmemoize(fn) { return (fn.unmemoized || fn).apply(null, arguments); }; } -module.exports = exports["default"]; +module.exports = exports["default"]; \ No newline at end of file diff --git a/node_modules/async/until.js b/node_modules/async/until.js index 53703ea..29955ab 100644 --- a/node_modules/async/until.js +++ b/node_modules/async/until.js @@ -38,4 +38,4 @@ function until(test, iteratee, callback) { return !test.apply(this, arguments); }, iteratee, callback); } -module.exports = exports['default']; +module.exports = exports['default']; \ No newline at end of file diff --git a/node_modules/async/waterfall.js b/node_modules/async/waterfall.js index bbae78a..d547d6b 100644 --- a/node_modules/async/waterfall.js +++ b/node_modules/async/waterfall.js @@ -110,4 +110,4 @@ module.exports = exports['default']; * // arg1 now equals 'three' * callback(null, 'done'); * } - */ + */ \ No newline at end of file diff --git a/node_modules/async/whilst.js b/node_modules/async/whilst.js index ad9aff2..9c4d8f6 100644 --- a/node_modules/async/whilst.js +++ b/node_modules/async/whilst.js @@ -69,4 +69,4 @@ function whilst(test, iteratee, callback) { }; _iteratee(next); } -module.exports = exports['default']; +module.exports = exports['default']; \ No newline at end of file diff --git a/node_modules/async/wrapSync.js b/node_modules/async/wrapSync.js index 77272f5..5e3fc91 100644 --- a/node_modules/async/wrapSync.js +++ b/node_modules/async/wrapSync.js @@ -107,4 +107,4 @@ function invokeCallback(callback, error, value) { function rethrow(error) { throw error; } -module.exports = exports['default']; +module.exports = exports['default']; \ No newline at end of file diff --git a/node_modules/backoff/CHANGES.md b/node_modules/backoff/CHANGES.md new file mode 100644 index 0000000..c820200 --- /dev/null +++ b/node_modules/backoff/CHANGES.md @@ -0,0 +1,86 @@ +# Changelog + +## 2.5.0 + +Those changes are not released yet. + +- In the functional API, invoke the wrapped function callback on abort and emit + an `abort` event. This makes it possible to detect when abort is called. +- Add a method on the function API, `call.retryIf(predicate)`, which specifies + a predicate used to determine whether a given error is retriable or not. The + default behavior is unaffected, errors remain retriable by default. + +## 2.4.1 + +- Add support for specifying the factor to use in the `ExponentialStrategy`. + +## 2.4.0 + +- Replace `FunctionCall.getResults` by `FunctionCall.getLastResult` to avoid + storing intermediary results forever as this may lead to memory exhaustion + when used in conjunction with an infinite number of backoffs. +- Add `FunctionCall.getNumRetries` which returns the number of times the + wrapped function was retried. + +## 2.3.0 + +- Add four new methods to `FunctionCall` to query the state of the call. + - isPending + - isRunning + - isCompleted + - isAborted + +## 2.2.0 + +- To match `Backoff` default behavior, `FunctionCall` no longer sets a + default failAfter of 5, i.e. the maximum number of backoffs is now + unbounded by default. + +## 2.1.0 + +- `Backoff.backoff` now accepts an optional error argument that is re-emitted + as the last argument of the `backoff` and `fail` events. This provides some + context to the listeners as to why a given backoff operation was attempted. +- The `backoff` event emitted by the `FunctionCall` class now contains, as its + last argument, the error that caused the backoff operation to be attempted. + This provides some context to the listeners as to why a given backoff + operation was attempted. + +## 2.0.0 + +- `FunctionCall.call` renamed into `FunctionCall.start`. +- `backoff.call` no longer invokes the wrapped function on `nextTick`. That + way, the first attempt is not delayed until the end of the current event + loop. + +## 1.2.1 + +- Make `FunctionCall.backoffFactory` a private member. + +## 1.2.0 + +- Add `backoff.call` and the associated `FunctionCall` class. + +## 1.1.0 + +- Add a `Backoff.failAfter`. + +## 1.0.0 + +- Rename `start` and `done` events `backoff` and `ready`. +- Remove deprecated `backoff.fibonnaci`. + +## 0.2.1 + +- Create `backoff.fibonacci`. +- Deprecate `backoff.fibonnaci`. +- Expose fibonacci and exponential strategies. + +## 0.2.0 + +- Provide exponential and fibonacci backoffs. + +## 0.1.0 + +- Change `initialTimeout` and `maxTimeout` to `initialDelay` and `maxDelay`. +- Use fibonnaci backoff. diff --git a/node_modules/backoff/LICENSE b/node_modules/backoff/LICENSE new file mode 100644 index 0000000..8748698 --- /dev/null +++ b/node_modules/backoff/LICENSE @@ -0,0 +1,19 @@ +Copyright (C) 2012 Mathieu Turcotte + +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/backoff/README.md b/node_modules/backoff/README.md new file mode 100644 index 0000000..f64a6e8 --- /dev/null +++ b/node_modules/backoff/README.md @@ -0,0 +1,382 @@ +# Backoff for Node.js +[![Build Status](https://secure.travis-ci.org/MathieuTurcotte/node-backoff.png?branch=master)](http://travis-ci.org/MathieuTurcotte/node-backoff) +[![NPM version](https://badge.fury.io/js/backoff.png)](http://badge.fury.io/js/backoff) + +Fibonacci and exponential backoffs for Node.js. + +## Installation + +``` +npm install backoff +``` + +## Unit tests + +``` +npm test +``` + +## Usage + +### Object Oriented + +The usual way to instantiate a new `Backoff` object is to use one predefined +factory method: `backoff.fibonacci([options])`, `backoff.exponential([options])`. + +`Backoff` inherits from `EventEmitter`. When a backoff starts, a `backoff` +event is emitted and, when a backoff ends, a `ready` event is emitted. +Handlers for these two events are called with the current backoff number and +delay. + +``` js +var backoff = require('backoff'); + +var fibonacciBackoff = backoff.fibonacci({ + randomisationFactor: 0, + initialDelay: 10, + maxDelay: 300 +}); + +fibonacciBackoff.failAfter(10); + +fibonacciBackoff.on('backoff', function(number, delay) { + // Do something when backoff starts, e.g. show to the + // user the delay before next reconnection attempt. + console.log(number + ' ' + delay + 'ms'); +}); + +fibonacciBackoff.on('ready', function(number, delay) { + // Do something when backoff ends, e.g. retry a failed + // operation (DNS lookup, API call, etc.). If it fails + // again then backoff, otherwise reset the backoff + // instance. + fibonacciBackoff.backoff(); +}); + +fibonacciBackoff.on('fail', function() { + // Do something when the maximum number of backoffs is + // reached, e.g. ask the user to check its connection. + console.log('fail'); +}); + +fibonacciBackoff.backoff(); +``` + +The previous example would print the following. + +``` +0 10ms +1 10ms +2 20ms +3 30ms +4 50ms +5 80ms +6 130ms +7 210ms +8 300ms +9 300ms +fail +``` + +Note that `Backoff` objects are meant to be instantiated once and reused +several times by calling `reset` after a successful "retry". + +### Functional + +It's also possible to avoid some boilerplate code when invoking an asynchronous +function in a backoff loop by using `backoff.call(fn, [args, ...], callback)`. + +Typical usage looks like the following. + +``` js +var call = backoff.call(get, 'https://duplika.ca/', function(err, res) { + console.log('Num retries: ' + call.getNumRetries()); + + if (err) { + console.log('Error: ' + err.message); + } else { + console.log('Status: ' + res.statusCode); + } +}); + +call.retryIf(function(err) { return err.status == 503; }); +call.setStrategy(new backoff.ExponentialStrategy()); +call.failAfter(10); +call.start(); +``` + +## API + +### backoff.fibonacci([options]) + +Constructs a Fibonacci backoff (10, 10, 20, 30, 50, etc.). + +The options are the following. + +- randomisationFactor: defaults to 0, must be between 0 and 1 +- initialDelay: defaults to 100 ms +- maxDelay: defaults to 10000 ms + +With these values, the backoff delay will increase from 100 ms to 10000 ms. The +randomisation factor controls the range of randomness and must be between 0 +and 1. By default, no randomisation is applied on the backoff delay. + +### backoff.exponential([options]) + +Constructs an exponential backoff (10, 20, 40, 80, etc.). + +The options are the following. + +- randomisationFactor: defaults to 0, must be between 0 and 1 +- initialDelay: defaults to 100 ms +- maxDelay: defaults to 10000 ms +- factor: defaults to 2, must be greater than 1 + +With these values, the backoff delay will increase from 100 ms to 10000 ms. The +randomisation factor controls the range of randomness and must be between 0 +and 1. By default, no randomisation is applied on the backoff delay. + +### backoff.call(fn, [args, ...], callback) + +- fn: function to call in a backoff handler, i.e. the wrapped function +- args: function's arguments +- callback: function's callback accepting an error as its first argument + +Constructs a `FunctionCall` instance for the given function. The wrapped +function will get retried until it succeds or reaches the maximum number +of backoffs. In both cases, the callback function will be invoked with the +last result returned by the wrapped function. + +It is the caller's responsability to initiate the call by invoking the +`start` method on the returned `FunctionCall` instance. + +### Class Backoff + +#### new Backoff(strategy) + +- strategy: the backoff strategy to use + +Constructs a new backoff object from a specific backoff strategy. The backoff +strategy must implement the `BackoffStrategy`interface defined bellow. + +#### backoff.failAfter(numberOfBackoffs) + +- numberOfBackoffs: maximum number of backoffs before the fail event gets +emitted, must be greater than 0 + +Sets a limit on the maximum number of backoffs that can be performed before +a fail event gets emitted and the backoff instance is reset. By default, there +is no limit on the number of backoffs that can be performed. + +#### backoff.backoff([err]) + +Starts a backoff operation. If provided, the error parameter will be emitted +as the last argument of the `backoff` and `fail` events to let the listeners +know why the backoff operation was attempted. + +An error will be thrown if a backoff operation is already in progress. + +In practice, this method should be called after a failed attempt to perform a +sensitive operation (connecting to a database, downloading a resource over the +network, etc.). + +#### backoff.reset() + +Resets the backoff delay to the initial backoff delay and stop any backoff +operation in progress. After reset, a backoff instance can and should be +reused. + +In practice, this method should be called after having successfully completed +the sensitive operation guarded by the backoff instance or if the client code +request to stop any reconnection attempt. + +#### Event: 'backoff' + +- number: number of backoffs since last reset, starting at 0 +- delay: backoff delay in milliseconds +- err: optional error parameter passed to `backoff.backoff([err])` + +Emitted when a backoff operation is started. Signals to the client how long +the next backoff delay will be. + +#### Event: 'ready' + +- number: number of backoffs since last reset, starting at 0 +- delay: backoff delay in milliseconds + +Emitted when a backoff operation is done. Signals that the failing operation +should be retried. + +#### Event: 'fail' + +- err: optional error parameter passed to `backoff.backoff([err])` + +Emitted when the maximum number of backoffs is reached. This event will only +be emitted if the client has set a limit on the number of backoffs by calling +`backoff.failAfter(numberOfBackoffs)`. The backoff instance is automatically +reset after this event is emitted. + +### Interface BackoffStrategy + +A backoff strategy must provide the following methods. + +#### strategy.next() + +Computes and returns the next backoff delay. + +#### strategy.reset() + +Resets the backoff delay to its initial value. + +### Class ExponentialStrategy + +Exponential (10, 20, 40, 80, etc.) backoff strategy implementation. + +#### new ExponentialStrategy([options]) + +The options are the following. + +- randomisationFactor: defaults to 0, must be between 0 and 1 +- initialDelay: defaults to 100 ms +- maxDelay: defaults to 10000 ms +- factor: defaults to 2, must be greater than 1 + +### Class FibonacciStrategy + +Fibonnaci (10, 10, 20, 30, 50, etc.) backoff strategy implementation. + +#### new FibonacciStrategy([options]) + +The options are the following. + +- randomisationFactor: defaults to 0, must be between 0 and 1 +- initialDelay: defaults to 100 ms +- maxDelay: defaults to 10000 ms + +### Class FunctionCall + +This class manages the calling of an asynchronous function within a backoff +loop. + +This class should rarely be instantiated directly since the factory method +`backoff.call(fn, [args, ...], callback)` offers a more convenient and safer +way to create `FunctionCall` instances. + +#### new FunctionCall(fn, args, callback) + +- fn: asynchronous function to call +- args: an array containing fn's args +- callback: fn's callback + +Constructs a function handler for the given asynchronous function. + +#### call.isPending() + +Returns whether the call is pending, i.e. hasn't been started. + +#### call.isRunning() + +Returns whether the call is in progress. + +#### call.isCompleted() + +Returns whether the call is completed. + +#### call.isAborted() + +Returns whether the call is aborted. + +#### call.setStrategy(strategy) + +- strategy: strategy instance to use, defaults to `FibonacciStrategy`. + +Sets the backoff strategy to use. This method should be called before +`call.start()` otherwise an exception will be thrown. + +#### call.failAfter(maxNumberOfBackoffs) + +- maxNumberOfBackoffs: maximum number of backoffs before the call is aborted + +Sets the maximum number of backoffs before the call is aborted. By default, +there is no limit on the number of backoffs that can be performed. + +This method should be called before `call.start()` otherwise an exception will +be thrown.. + +#### call.retryIf(predicate) + +- predicate: a function which takes in as its argument the error returned +by the wrapped function and determines whether it is retriable. + +Sets the predicate which will be invoked to determine whether a given error +should be retried or not, e.g. a network error would be retriable while a type +error would stop the function call. By default, all errors are considered to be +retriable. + +This method should be called before `call.start()` otherwise an exception will +be thrown. + +#### call.getLastResult() + +Returns an array containing the last arguments passed to the completion callback +of the wrapped function. For example, to get the error code returned by the last +call, one would do the following. + +``` js +var results = call.getLastResult(); +// The error code is the first parameter of the callback. +var error = results[0]; +``` + +Note that if the call was aborted, it will contain the abort error and not the +last error returned by the wrapped function. + +#### call.getNumRetries() + +Returns the number of times the wrapped function call was retried. For a +wrapped function that succeeded immediately, this would return 0. This +method can be called at any point in time during the call life cycle, i.e. +before, during and after the wrapped function invocation. + +#### call.start() + +Initiates the call the wrapped function. This method should only be called +once otherwise an exception will be thrown. + +#### call.abort() + +Aborts the call and causes the completion callback to be invoked with an abort +error if the call was pending or running; does nothing otherwise. This method +can safely be called mutliple times. + +#### Event: 'call' + +- args: wrapped function's arguments + +Emitted each time the wrapped function is called. + +#### Event: 'callback' + +- results: wrapped function's return values + +Emitted each time the wrapped function invokes its callback. + +#### Event: 'backoff' + +- number: backoff number, starts at 0 +- delay: backoff delay in milliseconds +- err: the error that triggered the backoff operation + +Emitted each time a backoff operation is started. + +#### Event: 'abort' + +Emitted when a call is aborted. + +## Annotated source code + +The annotated source code can be found at [mathieuturcotte.github.io/node-backoff/docs](http://mathieuturcotte.github.io/node-backoff/docs/). + +## License + +This code is free to use under the terms of the [MIT license](http://mturcotte.mit-license.org/). diff --git a/node_modules/backoff/index.js b/node_modules/backoff/index.js new file mode 100644 index 0000000..6281fa6 --- /dev/null +++ b/node_modules/backoff/index.js @@ -0,0 +1,31 @@ +// Copyright (c) 2012 Mathieu Turcotte +// Licensed under the MIT license. + +var Backoff = require('./lib/backoff'); +var ExponentialBackoffStrategy = require('./lib/strategy/exponential'); +var FibonacciBackoffStrategy = require('./lib/strategy/fibonacci'); +var FunctionCall = require('./lib/function_call.js'); + +module.exports.Backoff = Backoff; +module.exports.FunctionCall = FunctionCall; +module.exports.FibonacciStrategy = FibonacciBackoffStrategy; +module.exports.ExponentialStrategy = ExponentialBackoffStrategy; + +// Constructs a Fibonacci backoff. +module.exports.fibonacci = function(options) { + return new Backoff(new FibonacciBackoffStrategy(options)); +}; + +// Constructs an exponential backoff. +module.exports.exponential = function(options) { + return new Backoff(new ExponentialBackoffStrategy(options)); +}; + +// Constructs a FunctionCall for the given function and arguments. +module.exports.call = function(fn, vargs, callback) { + var args = Array.prototype.slice.call(arguments); + fn = args[0]; + vargs = args.slice(1, args.length - 1); + callback = args[args.length - 1]; + return new FunctionCall(fn, vargs, callback); +}; diff --git a/node_modules/backoff/lib/backoff.js b/node_modules/backoff/lib/backoff.js new file mode 100644 index 0000000..202a280 --- /dev/null +++ b/node_modules/backoff/lib/backoff.js @@ -0,0 +1,65 @@ +// Copyright (c) 2012 Mathieu Turcotte +// Licensed under the MIT license. + +var events = require('events'); +var precond = require('precond'); +var util = require('util'); + +// A class to hold the state of a backoff operation. Accepts a backoff strategy +// to generate the backoff delays. +function Backoff(backoffStrategy) { + events.EventEmitter.call(this); + + this.backoffStrategy_ = backoffStrategy; + this.maxNumberOfRetry_ = -1; + this.backoffNumber_ = 0; + this.backoffDelay_ = 0; + this.timeoutID_ = -1; + + this.handlers = { + backoff: this.onBackoff_.bind(this) + }; +} +util.inherits(Backoff, events.EventEmitter); + +// Sets a limit, greater than 0, on the maximum number of backoffs. A 'fail' +// event will be emitted when the limit is reached. +Backoff.prototype.failAfter = function(maxNumberOfRetry) { + precond.checkArgument(maxNumberOfRetry > 0, + 'Expected a maximum number of retry greater than 0 but got %s.', + maxNumberOfRetry); + + this.maxNumberOfRetry_ = maxNumberOfRetry; +}; + +// Starts a backoff operation. Accepts an optional parameter to let the +// listeners know why the backoff operation was started. +Backoff.prototype.backoff = function(err) { + precond.checkState(this.timeoutID_ === -1, 'Backoff in progress.'); + + if (this.backoffNumber_ === this.maxNumberOfRetry_) { + this.emit('fail', err); + this.reset(); + } else { + this.backoffDelay_ = this.backoffStrategy_.next(); + this.timeoutID_ = setTimeout(this.handlers.backoff, this.backoffDelay_); + this.emit('backoff', this.backoffNumber_, this.backoffDelay_, err); + } +}; + +// Handles the backoff timeout completion. +Backoff.prototype.onBackoff_ = function() { + this.timeoutID_ = -1; + this.emit('ready', this.backoffNumber_, this.backoffDelay_); + this.backoffNumber_++; +}; + +// Stops any backoff operation and resets the backoff delay to its inital value. +Backoff.prototype.reset = function() { + this.backoffNumber_ = 0; + this.backoffStrategy_.reset(); + clearTimeout(this.timeoutID_); + this.timeoutID_ = -1; +}; + +module.exports = Backoff; diff --git a/node_modules/backoff/lib/function_call.js b/node_modules/backoff/lib/function_call.js new file mode 100644 index 0000000..37319d7 --- /dev/null +++ b/node_modules/backoff/lib/function_call.js @@ -0,0 +1,190 @@ +// Copyright (c) 2012 Mathieu Turcotte +// Licensed under the MIT license. + +var events = require('events'); +var precond = require('precond'); +var util = require('util'); + +var Backoff = require('./backoff'); +var FibonacciBackoffStrategy = require('./strategy/fibonacci'); + +// Wraps a function to be called in a backoff loop. +function FunctionCall(fn, args, callback) { + events.EventEmitter.call(this); + + precond.checkIsFunction(fn, 'Expected fn to be a function.'); + precond.checkIsArray(args, 'Expected args to be an array.'); + precond.checkIsFunction(callback, 'Expected callback to be a function.'); + + this.function_ = fn; + this.arguments_ = args; + this.callback_ = callback; + this.lastResult_ = []; + this.numRetries_ = 0; + + this.backoff_ = null; + this.strategy_ = null; + this.failAfter_ = -1; + this.retryPredicate_ = FunctionCall.DEFAULT_RETRY_PREDICATE_; + + this.state_ = FunctionCall.State_.PENDING; +} +util.inherits(FunctionCall, events.EventEmitter); + +// States in which the call can be. +FunctionCall.State_ = { + // Call isn't started yet. + PENDING: 0, + // Call is in progress. + RUNNING: 1, + // Call completed successfully which means that either the wrapped function + // returned successfully or the maximal number of backoffs was reached. + COMPLETED: 2, + // The call was aborted. + ABORTED: 3 +}; + +// The default retry predicate which considers any error as retriable. +FunctionCall.DEFAULT_RETRY_PREDICATE_ = function(err) { + return true; +}; + +// Checks whether the call is pending. +FunctionCall.prototype.isPending = function() { + return this.state_ == FunctionCall.State_.PENDING; +}; + +// Checks whether the call is in progress. +FunctionCall.prototype.isRunning = function() { + return this.state_ == FunctionCall.State_.RUNNING; +}; + +// Checks whether the call is completed. +FunctionCall.prototype.isCompleted = function() { + return this.state_ == FunctionCall.State_.COMPLETED; +}; + +// Checks whether the call is aborted. +FunctionCall.prototype.isAborted = function() { + return this.state_ == FunctionCall.State_.ABORTED; +}; + +// Sets the backoff strategy to use. Can only be called before the call is +// started otherwise an exception will be thrown. +FunctionCall.prototype.setStrategy = function(strategy) { + precond.checkState(this.isPending(), 'FunctionCall in progress.'); + this.strategy_ = strategy; + return this; // Return this for chaining. +}; + +// Sets the predicate which will be used to determine whether the errors +// returned from the wrapped function should be retried or not, e.g. a +// network error would be retriable while a type error would stop the +// function call. +FunctionCall.prototype.retryIf = function(retryPredicate) { + precond.checkState(this.isPending(), 'FunctionCall in progress.'); + this.retryPredicate_ = retryPredicate; + return this; +}; + +// Returns all intermediary results returned by the wrapped function since +// the initial call. +FunctionCall.prototype.getLastResult = function() { + return this.lastResult_.concat(); +}; + +// Returns the number of times the wrapped function call was retried. +FunctionCall.prototype.getNumRetries = function() { + return this.numRetries_; +}; + +// Sets the backoff limit. +FunctionCall.prototype.failAfter = function(maxNumberOfRetry) { + precond.checkState(this.isPending(), 'FunctionCall in progress.'); + this.failAfter_ = maxNumberOfRetry; + return this; // Return this for chaining. +}; + +// Aborts the call. +FunctionCall.prototype.abort = function() { + if (this.isCompleted() || this.isAborted()) { + return; + } + + if (this.isRunning()) { + this.backoff_.reset(); + } + + this.state_ = FunctionCall.State_.ABORTED; + this.lastResult_ = [new Error('Backoff aborted.')]; + this.emit('abort'); + this.doCallback_(); +}; + +// Initiates the call to the wrapped function. Accepts an optional factory +// function used to create the backoff instance; used when testing. +FunctionCall.prototype.start = function(backoffFactory) { + precond.checkState(!this.isAborted(), 'FunctionCall is aborted.'); + precond.checkState(this.isPending(), 'FunctionCall already started.'); + + var strategy = this.strategy_ || new FibonacciBackoffStrategy(); + + this.backoff_ = backoffFactory ? + backoffFactory(strategy) : + new Backoff(strategy); + + this.backoff_.on('ready', this.doCall_.bind(this, true /* isRetry */)); + this.backoff_.on('fail', this.doCallback_.bind(this)); + this.backoff_.on('backoff', this.handleBackoff_.bind(this)); + + if (this.failAfter_ > 0) { + this.backoff_.failAfter(this.failAfter_); + } + + this.state_ = FunctionCall.State_.RUNNING; + this.doCall_(false /* isRetry */); +}; + +// Calls the wrapped function. +FunctionCall.prototype.doCall_ = function(isRetry) { + if (isRetry) { + this.numRetries_++; + } + var eventArgs = ['call'].concat(this.arguments_); + events.EventEmitter.prototype.emit.apply(this, eventArgs); + var callback = this.handleFunctionCallback_.bind(this); + this.function_.apply(null, this.arguments_.concat(callback)); +}; + +// Calls the wrapped function's callback with the last result returned by the +// wrapped function. +FunctionCall.prototype.doCallback_ = function() { + this.callback_.apply(null, this.lastResult_); +}; + +// Handles wrapped function's completion. This method acts as a replacement +// for the original callback function. +FunctionCall.prototype.handleFunctionCallback_ = function() { + if (this.isAborted()) { + return; + } + + var args = Array.prototype.slice.call(arguments); + this.lastResult_ = args; // Save last callback arguments. + events.EventEmitter.prototype.emit.apply(this, ['callback'].concat(args)); + + var err = args[0]; + if (err && this.retryPredicate_(err)) { + this.backoff_.backoff(err); + } else { + this.state_ = FunctionCall.State_.COMPLETED; + this.doCallback_(); + } +}; + +// Handles the backoff event by reemitting it. +FunctionCall.prototype.handleBackoff_ = function(number, delay, err) { + this.emit('backoff', number, delay, err); +}; + +module.exports = FunctionCall; diff --git a/node_modules/backoff/lib/strategy/exponential.js b/node_modules/backoff/lib/strategy/exponential.js new file mode 100644 index 0000000..8074a40 --- /dev/null +++ b/node_modules/backoff/lib/strategy/exponential.js @@ -0,0 +1,41 @@ +// Copyright (c) 2012 Mathieu Turcotte +// Licensed under the MIT license. + +var util = require('util'); +var precond = require('precond'); + +var BackoffStrategy = require('./strategy'); + +// Exponential backoff strategy. +function ExponentialBackoffStrategy(options) { + BackoffStrategy.call(this, options); + this.backoffDelay_ = 0; + this.nextBackoffDelay_ = this.getInitialDelay(); + this.factor_ = ExponentialBackoffStrategy.DEFAULT_FACTOR; + + if (options && options.factor !== undefined) { + precond.checkArgument(options.factor > 1, + 'Exponential factor should be greater than 1 but got %s.', + options.factor); + this.factor_ = options.factor; + } +} +util.inherits(ExponentialBackoffStrategy, BackoffStrategy); + +// Default multiplication factor used to compute the next backoff delay from +// the current one. The value can be overridden by passing a custom factor as +// part of the options. +ExponentialBackoffStrategy.DEFAULT_FACTOR = 2; + +ExponentialBackoffStrategy.prototype.next_ = function() { + this.backoffDelay_ = Math.min(this.nextBackoffDelay_, this.getMaxDelay()); + this.nextBackoffDelay_ = this.backoffDelay_ * this.factor_; + return this.backoffDelay_; +}; + +ExponentialBackoffStrategy.prototype.reset_ = function() { + this.backoffDelay_ = 0; + this.nextBackoffDelay_ = this.getInitialDelay(); +}; + +module.exports = ExponentialBackoffStrategy; diff --git a/node_modules/backoff/lib/strategy/fibonacci.js b/node_modules/backoff/lib/strategy/fibonacci.js new file mode 100644 index 0000000..7c71c03 --- /dev/null +++ b/node_modules/backoff/lib/strategy/fibonacci.js @@ -0,0 +1,28 @@ +// Copyright (c) 2012 Mathieu Turcotte +// Licensed under the MIT license. + +var util = require('util'); + +var BackoffStrategy = require('./strategy'); + +// Fibonacci backoff strategy. +function FibonacciBackoffStrategy(options) { + BackoffStrategy.call(this, options); + this.backoffDelay_ = 0; + this.nextBackoffDelay_ = this.getInitialDelay(); +} +util.inherits(FibonacciBackoffStrategy, BackoffStrategy); + +FibonacciBackoffStrategy.prototype.next_ = function() { + var backoffDelay = Math.min(this.nextBackoffDelay_, this.getMaxDelay()); + this.nextBackoffDelay_ += this.backoffDelay_; + this.backoffDelay_ = backoffDelay; + return backoffDelay; +}; + +FibonacciBackoffStrategy.prototype.reset_ = function() { + this.nextBackoffDelay_ = this.getInitialDelay(); + this.backoffDelay_ = 0; +}; + +module.exports = FibonacciBackoffStrategy; diff --git a/node_modules/backoff/lib/strategy/strategy.js b/node_modules/backoff/lib/strategy/strategy.js new file mode 100644 index 0000000..7adfd75 --- /dev/null +++ b/node_modules/backoff/lib/strategy/strategy.js @@ -0,0 +1,80 @@ +// Copyright (c) 2012 Mathieu Turcotte +// Licensed under the MIT license. + +var events = require('events'); +var util = require('util'); + +function isDef(value) { + return value !== undefined && value !== null; +} + +// Abstract class defining the skeleton for the backoff strategies. Accepts an +// object holding the options for the backoff strategy: +// +// * `randomisationFactor`: The randomisation factor which must be between 0 +// and 1 where 1 equates to a randomization factor of 100% and 0 to no +// randomization. +// * `initialDelay`: The backoff initial delay in milliseconds. +// * `maxDelay`: The backoff maximal delay in milliseconds. +function BackoffStrategy(options) { + options = options || {}; + + if (isDef(options.initialDelay) && options.initialDelay < 1) { + throw new Error('The initial timeout must be greater than 0.'); + } else if (isDef(options.maxDelay) && options.maxDelay < 1) { + throw new Error('The maximal timeout must be greater than 0.'); + } + + this.initialDelay_ = options.initialDelay || 100; + this.maxDelay_ = options.maxDelay || 10000; + + if (this.maxDelay_ <= this.initialDelay_) { + throw new Error('The maximal backoff delay must be ' + + 'greater than the initial backoff delay.'); + } + + if (isDef(options.randomisationFactor) && + (options.randomisationFactor < 0 || options.randomisationFactor > 1)) { + throw new Error('The randomisation factor must be between 0 and 1.'); + } + + this.randomisationFactor_ = options.randomisationFactor || 0; +} + +// Gets the maximal backoff delay. +BackoffStrategy.prototype.getMaxDelay = function() { + return this.maxDelay_; +}; + +// Gets the initial backoff delay. +BackoffStrategy.prototype.getInitialDelay = function() { + return this.initialDelay_; +}; + +// Template method that computes and returns the next backoff delay in +// milliseconds. +BackoffStrategy.prototype.next = function() { + var backoffDelay = this.next_(); + var randomisationMultiple = 1 + Math.random() * this.randomisationFactor_; + var randomizedDelay = Math.round(backoffDelay * randomisationMultiple); + return randomizedDelay; +}; + +// Computes and returns the next backoff delay. Intended to be overridden by +// subclasses. +BackoffStrategy.prototype.next_ = function() { + throw new Error('BackoffStrategy.next_() unimplemented.'); +}; + +// Template method that resets the backoff delay to its initial value. +BackoffStrategy.prototype.reset = function() { + this.reset_(); +}; + +// Resets the backoff delay to its initial value. Intended to be overridden by +// subclasses. +BackoffStrategy.prototype.reset_ = function() { + throw new Error('BackoffStrategy.reset_() unimplemented.'); +}; + +module.exports = BackoffStrategy; diff --git a/node_modules/backoff/package.json b/node_modules/backoff/package.json new file mode 100644 index 0000000..b04e458 --- /dev/null +++ b/node_modules/backoff/package.json @@ -0,0 +1,69 @@ +{ + "_from": "backoff@^2.5.0", + "_id": "backoff@2.5.0", + "_inBundle": false, + "_integrity": "sha1-9hbtqdPktmuMp/ynn2lXIsX44m8=", + "_location": "/backoff", + "_phantomChildren": {}, + "_requested": { + "type": "range", + "registry": true, + "raw": "backoff@^2.5.0", + "name": "backoff", + "escapedName": "backoff", + "rawSpec": "^2.5.0", + "saveSpec": null, + "fetchSpec": "^2.5.0" + }, + "_requiredBy": [ + "/ldapjs" + ], + "_resolved": "https://registry.npmjs.org/backoff/-/backoff-2.5.0.tgz", + "_shasum": "f616eda9d3e4b66b8ca7fca79f695722c5f8e26f", + "_spec": "backoff@^2.5.0", + "_where": "/home/erik/Documents/workspace_brackets/a1_BME_Project_Ohm/om/node_modules/ldapjs", + "author": { + "name": "Mathieu Turcotte", + "email": "turcotte.mat@gmail.com" + }, + "bugs": { + "url": "https://github.com/MathieuTurcotte/node-backoff/issues" + }, + "bundleDependencies": false, + "dependencies": { + "precond": "0.2" + }, + "deprecated": false, + "description": "Fibonacci and exponential backoffs.", + "devDependencies": { + "nodeunit": "0.9", + "sinon": "1.10" + }, + "engines": { + "node": ">= 0.6" + }, + "files": [ + "index.js", + "lib", + "tests" + ], + "homepage": "https://github.com/MathieuTurcotte/node-backoff#readme", + "keywords": [ + "backoff", + "retry", + "fibonacci", + "exponential" + ], + "license": "MIT", + "name": "backoff", + "repository": { + "type": "git", + "url": "git+https://github.com/MathieuTurcotte/node-backoff.git" + }, + "scripts": { + "docco": "docco lib/*.js lib/strategy/* index.js", + "pretest": "jshint lib/ tests/ examples/ index.js", + "test": "node_modules/nodeunit/bin/nodeunit tests/" + }, + "version": "2.5.0" +} diff --git a/node_modules/backoff/tests/api.js b/node_modules/backoff/tests/api.js new file mode 100644 index 0000000..835c412 --- /dev/null +++ b/node_modules/backoff/tests/api.js @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2012 Mathieu Turcotte + * Licensed under the MIT license. + */ + +var sinon = require('sinon'); + +var backoff = require('../index'); + +exports["API"] = { + "backoff.fibonnaci should be a function that returns a backoff instance": function(test) { + test.ok(backoff.fibonacci, 'backoff.fibonacci should be defined.'); + test.equal(typeof backoff.fibonacci, 'function', + 'backoff.fibonacci should be a function.'); + test.equal(backoff.fibonacci().constructor.name, 'Backoff'); + test.done(); + }, + + "backoff.exponential should be a function that returns a backoff instance": function(test) { + test.ok(backoff.exponential, 'backoff.exponential should be defined.'); + test.equal(typeof backoff.exponential, 'function', + 'backoff.exponential should be a function.'); + test.equal(backoff.exponential().constructor.name, 'Backoff'); + test.done(); + }, + + "backoff.call should be a function that returns a FunctionCall instance": function(test) { + var fn = function() {}; + var callback = function() {}; + test.ok(backoff.Backoff, 'backoff.call should be defined.'); + test.equal(typeof backoff.call, 'function', + 'backoff.call should be a function.'); + test.equal(backoff.call(fn, 1, 2, 3, callback).constructor.name, + 'FunctionCall'); + test.done(); + }, + + "backoff.Backoff should be defined and a function": function(test) { + test.ok(backoff.Backoff, 'backoff.Backoff should be defined.'); + test.equal(typeof backoff.Backoff, 'function', + 'backoff.Backoff should be a function.'); + test.done(); + }, + + "backoff.FunctionCall should be defined and a function": function(test) { + test.ok(backoff.FunctionCall, + 'backoff.FunctionCall should be defined.'); + test.equal(typeof backoff.FunctionCall, 'function', + 'backoff.FunctionCall should be a function.'); + test.done(); + }, + + "backoff.FibonacciStrategy should be defined and a function": function(test) { + test.ok(backoff.FibonacciStrategy, + 'backoff.FibonacciStrategy should be defined.'); + test.equal(typeof backoff.FibonacciStrategy, 'function', + 'backoff.FibonacciStrategy should be a function.'); + test.done(); + }, + + "backoff.ExponentialStrategy should be defined and a function": function(test) { + test.ok(backoff.ExponentialStrategy, + 'backoff.ExponentialStrategy should be defined.'); + test.equal(typeof backoff.ExponentialStrategy, 'function', + 'backoff.ExponentialStrategy should be a function.'); + test.done(); + } +}; diff --git a/node_modules/backoff/tests/backoff.js b/node_modules/backoff/tests/backoff.js new file mode 100644 index 0000000..84bbd16 --- /dev/null +++ b/node_modules/backoff/tests/backoff.js @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2012 Mathieu Turcotte + * Licensed under the MIT license. + */ + +var sinon = require('sinon'); + +var Backoff = require('../lib/backoff'); +var BackoffStrategy = require('../lib/strategy/strategy'); + +exports["Backoff"] = { + setUp: function(callback) { + this.backoffStrategy = sinon.stub(new BackoffStrategy()); + this.backoff = new Backoff(this.backoffStrategy); + this.clock = sinon.useFakeTimers(); + this.spy = new sinon.spy(); + callback(); + }, + + tearDown: function(callback) { + this.clock.restore(); + callback(); + }, + + "the backoff event should be emitted when backoff starts": function(test) { + this.backoffStrategy.next.returns(10); + this.backoff.on('backoff', this.spy); + + this.backoff.backoff(); + + test.ok(this.spy.calledOnce, + 'Backoff event should be emitted when backoff starts.'); + test.done(); + }, + + "the ready event should be emitted on backoff completion": function(test) { + this.backoffStrategy.next.returns(10); + this.backoff.on('ready', this.spy); + + this.backoff.backoff(); + this.clock.tick(10); + + test.ok(this.spy.calledOnce, + 'Ready event should be emitted when backoff ends.'); + test.done(); + }, + + "the backoff event should be passed the backoff delay": function(test) { + this.backoffStrategy.next.returns(989); + this.backoff.on('backoff', this.spy); + + this.backoff.backoff(); + + test.equal(this.spy.getCall(0).args[1], 989, 'Backoff event should ' + + 'carry the backoff delay as its second argument.'); + test.done(); + }, + + "the ready event should be passed the backoff delay": function(test) { + this.backoffStrategy.next.returns(989); + this.backoff.on('ready', this.spy); + + this.backoff.backoff(); + this.clock.tick(989); + + test.equal(this.spy.getCall(0).args[1], 989, 'Ready event should ' + + 'carry the backoff delay as its second argument.'); + test.done(); + }, + + "the fail event should be emitted when backoff limit is reached": function(test) { + var err = new Error('Fail'); + + this.backoffStrategy.next.returns(10); + this.backoff.on('fail', this.spy); + + this.backoff.failAfter(2); + + // Consume first 2 backoffs. + for (var i = 0; i < 2; i++) { + this.backoff.backoff(); + this.clock.tick(10); + } + + // Failure should occur on the third call, and not before. + test.ok(!this.spy.calledOnce, 'Fail event shouldn\'t have been emitted.'); + this.backoff.backoff(err); + test.ok(this.spy.calledOnce, 'Fail event should have been emitted.'); + test.equal(this.spy.getCall(0).args[0], err, 'Error should be passed'); + + test.done(); + }, + + "calling backoff while a backoff is in progress should throw an error": function(test) { + this.backoffStrategy.next.returns(10); + var backoff = this.backoff; + + backoff.backoff(); + + test.throws(function() { + backoff.backoff(); + }, /in progress/); + + test.done(); + }, + + "backoff limit should be greater than 0": function(test) { + var backoff = this.backoff; + test.throws(function() { + backoff.failAfter(0); + }, /greater than 0 but got 0/); + test.done(); + }, + + "reset should cancel any backoff in progress": function(test) { + this.backoffStrategy.next.returns(10); + this.backoff.on('ready', this.spy); + + this.backoff.backoff(); + + this.backoff.reset(); + this.clock.tick(100); // 'ready' should not be emitted. + + test.equals(this.spy.callCount, 0, 'Reset should have aborted the backoff.'); + test.done(); + }, + + "reset should reset the backoff strategy": function(test) { + this.backoff.reset(); + test.ok(this.backoffStrategy.reset.calledOnce, + 'The backoff strategy should have been resetted.'); + test.done(); + }, + + "backoff should be reset after fail": function(test) { + this.backoffStrategy.next.returns(10); + + this.backoff.failAfter(1); + + this.backoff.backoff(); + this.clock.tick(10); + this.backoff.backoff(); + + test.ok(this.backoffStrategy.reset.calledOnce, + 'Backoff should have been resetted after failure.'); + test.done(); + }, + + "the backoff number should increase from 0 to N - 1": function(test) { + this.backoffStrategy.next.returns(10); + this.backoff.on('backoff', this.spy); + + var expectedNumbers = [0, 1, 2, 3, 4]; + var actualNumbers = []; + + for (var i = 0; i < expectedNumbers.length; i++) { + this.backoff.backoff(); + this.clock.tick(10); + actualNumbers.push(this.spy.getCall(i).args[0]); + } + + test.deepEqual(expectedNumbers, actualNumbers, + 'Backoff number should increase from 0 to N - 1.'); + test.done(); + } +}; diff --git a/node_modules/backoff/tests/backoff_strategy.js b/node_modules/backoff/tests/backoff_strategy.js new file mode 100644 index 0000000..507f2a0 --- /dev/null +++ b/node_modules/backoff/tests/backoff_strategy.js @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2012 Mathieu Turcotte + * Licensed under the MIT license. + */ + +var sinon = require('sinon'); +var util = require('util'); + +var BackoffStrategy = require('../lib/strategy/strategy'); + +function SampleBackoffStrategy(options) { + BackoffStrategy.call(this, options); +} +util.inherits(SampleBackoffStrategy, BackoffStrategy); + +SampleBackoffStrategy.prototype.next_ = function() { + return this.getInitialDelay(); +}; + +SampleBackoffStrategy.prototype.reset_ = function() {}; + +exports["BackoffStrategy"] = { + setUp: function(callback) { + this.random = sinon.stub(Math, 'random'); + callback(); + }, + + tearDown: function(callback) { + this.random.restore(); + callback(); + }, + + "the randomisation factor should be between 0 and 1": function(test) { + test.throws(function() { + new BackoffStrategy({ + randomisationFactor: -0.1 + }); + }); + + test.throws(function() { + new BackoffStrategy({ + randomisationFactor: 1.1 + }); + }); + + test.doesNotThrow(function() { + new BackoffStrategy({ + randomisationFactor: 0.5 + }); + }); + + test.done(); + }, + + "the raw delay should be randomized based on the randomisation factor": function(test) { + var strategy = new SampleBackoffStrategy({ + randomisationFactor: 0.5, + initialDelay: 1000 + }); + this.random.returns(0.5); + + var backoffDelay = strategy.next(); + + test.equals(backoffDelay, 1000 + (1000 * 0.5 * 0.5)); + test.done(); + }, + + "the initial backoff delay should be greater than 0": function(test) { + test.throws(function() { + new BackoffStrategy({ + initialDelay: -1 + }); + }); + + test.throws(function() { + new BackoffStrategy({ + initialDelay: 0 + }); + }); + + test.doesNotThrow(function() { + new BackoffStrategy({ + initialDelay: 1 + }); + }); + + test.done(); + }, + + "the maximal backoff delay should be greater than 0": function(test) { + test.throws(function() { + new BackoffStrategy({ + maxDelay: -1 + }); + }); + + test.throws(function() { + new BackoffStrategy({ + maxDelay: 0 + }); + }); + + test.done(); + }, + + "the maximal backoff delay should be greater than the initial backoff delay": function(test) { + test.throws(function() { + new BackoffStrategy({ + initialDelay: 10, + maxDelay: 10 + }); + }); + + test.doesNotThrow(function() { + new BackoffStrategy({ + initialDelay: 10, + maxDelay: 11 + }); + }); + + test.done(); + } +}; diff --git a/node_modules/backoff/tests/exponential_backoff_strategy.js b/node_modules/backoff/tests/exponential_backoff_strategy.js new file mode 100644 index 0000000..3c83f50 --- /dev/null +++ b/node_modules/backoff/tests/exponential_backoff_strategy.js @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2012 Mathieu Turcotte + * Licensed under the MIT license. + */ + +var sinon = require('sinon'); + +var ExponentialBackoffStrategy = require('../lib/strategy/exponential'); + +exports["ExponentialBackoffStrategy"] = { + + "backoff delays should follow an exponential sequence": function(test) { + var strategy = new ExponentialBackoffStrategy({ + initialDelay: 10, + maxDelay: 1000 + }); + + // Exponential sequence: x[i] = x[i-1] * 2. + var expectedDelays = [10, 20, 40, 80, 160, 320, 640, 1000, 1000]; + var actualDelays = expectedDelays.map(function () { + return strategy.next(); + }); + + test.deepEqual(expectedDelays, actualDelays, + 'Generated delays should follow an exponential sequence.'); + test.done(); + }, + + "backoff delay factor should be configurable": function (test) { + var strategy = new ExponentialBackoffStrategy({ + initialDelay: 10, + maxDelay: 270, + factor: 3 + }); + + // Exponential sequence: x[i] = x[i-1] * 3. + var expectedDelays = [10, 30, 90, 270, 270]; + var actualDelays = expectedDelays.map(function () { + return strategy.next(); + }); + + test.deepEqual(expectedDelays, actualDelays, + 'Generated delays should follow a configurable exponential sequence.'); + test.done(); + }, + + "backoff delays should restart from the initial delay after reset": function(test) { + var strategy = new ExponentialBackoffStrategy({ + initialDelay: 10, + maxDelay: 1000 + }); + + strategy.next(); + strategy.reset(); + + var backoffDelay = strategy.next(); + test.equals(backoffDelay, 10, + 'Strategy should return the initial delay after reset.'); + test.done(); + } +}; diff --git a/node_modules/backoff/tests/fibonacci_backoff_strategy.js b/node_modules/backoff/tests/fibonacci_backoff_strategy.js new file mode 100644 index 0000000..cb15197 --- /dev/null +++ b/node_modules/backoff/tests/fibonacci_backoff_strategy.js @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2012 Mathieu Turcotte + * Licensed under the MIT license. + */ + +var sinon = require('sinon'); + +var FibonacciBackoffStrategy = require('../lib/strategy/fibonacci'); + +exports["FibonacciBackoffStrategy"] = { + setUp: function(callback) { + this.strategy = new FibonacciBackoffStrategy({ + initialDelay: 10, + maxDelay: 1000 + }); + callback(); + }, + + "backoff delays should follow a Fibonacci sequence": function(test) { + // Fibonacci sequence: x[i] = x[i-1] + x[i-2]. + var expectedDelays = [10, 10, 20, 30, 50, 80, 130, 210, 340, 550, 890, 1000]; + var actualDelays = []; + + for (var i = 0; i < expectedDelays.length; i++) { + actualDelays.push(this.strategy.next()); + } + + test.deepEqual(expectedDelays, actualDelays, + 'Generated delays should follow a Fibonacci sequence.'); + test.done(); + }, + + "backoff delays should restart from the initial delay after reset": function(test) { + var strategy = new FibonacciBackoffStrategy({ + initialDelay: 10, + maxDelay: 1000 + }); + + strategy.next(); + strategy.reset(); + + var backoffDelay = strategy.next(); + test.equals(backoffDelay, 10, + 'Strategy should return the initial delay after reset.'); + test.done(); + } +}; diff --git a/node_modules/backoff/tests/function_call.js b/node_modules/backoff/tests/function_call.js new file mode 100644 index 0000000..d54f4b0 --- /dev/null +++ b/node_modules/backoff/tests/function_call.js @@ -0,0 +1,406 @@ +/* + * Copyright (c) 2012 Mathieu Turcotte + * Licensed under the MIT license. + */ + +var assert = require('assert'); +var events = require('events'); +var sinon = require('sinon'); +var util = require('util'); + +var FunctionCall = require('../lib/function_call'); + +function MockBackoff() { + events.EventEmitter.call(this); + + this.reset = sinon.spy(); + this.backoff = sinon.spy(); + this.failAfter = sinon.spy(); +} +util.inherits(MockBackoff, events.EventEmitter); + +exports["FunctionCall"] = { + setUp: function(callback) { + this.wrappedFn = sinon.stub(); + this.callback = sinon.stub(); + this.backoff = new MockBackoff(); + this.backoffFactory = sinon.stub(); + this.backoffFactory.returns(this.backoff); + callback(); + }, + + tearDown: function(callback) { + callback(); + }, + + "constructor's first argument should be a function": function(test) { + test.throws(function() { + new FunctionCall(1, [], function() {}); + }, /Expected fn to be a function./); + test.done(); + }, + + "constructor's last argument should be a function": function(test) { + test.throws(function() { + new FunctionCall(function() {}, [], 3); + }, /Expected callback to be a function./); + test.done(); + }, + + "isPending should return false once the call is started": function(test) { + this.wrappedFn. + onFirstCall().yields(new Error()). + onSecondCall().yields(null, 'Success!'); + var call = new FunctionCall(this.wrappedFn, [], this.callback); + + test.ok(call.isPending()); + + call.start(this.backoffFactory); + test.ok(!call.isPending()); + + this.backoff.emit('ready'); + test.ok(!call.isPending()); + + test.done(); + }, + + "isRunning should return true when call is in progress": function(test) { + this.wrappedFn. + onFirstCall().yields(new Error()). + onSecondCall().yields(null, 'Success!'); + var call = new FunctionCall(this.wrappedFn, [], this.callback); + + test.ok(!call.isRunning()); + + call.start(this.backoffFactory); + test.ok(call.isRunning()); + + this.backoff.emit('ready'); + test.ok(!call.isRunning()); + + test.done(); + }, + + "isCompleted should return true once the call completes": function(test) { + this.wrappedFn. + onFirstCall().yields(new Error()). + onSecondCall().yields(null, 'Success!'); + var call = new FunctionCall(this.wrappedFn, [], this.callback); + + test.ok(!call.isCompleted()); + + call.start(this.backoffFactory); + test.ok(!call.isCompleted()); + + this.backoff.emit('ready'); + test.ok(call.isCompleted()); + + test.done(); + }, + + "isAborted should return true once the call is aborted": function(test) { + this.wrappedFn. + onFirstCall().yields(new Error()). + onSecondCall().yields(null, 'Success!'); + var call = new FunctionCall(this.wrappedFn, [], this.callback); + + test.ok(!call.isAborted()); + call.abort(); + test.ok(call.isAborted()); + + test.done(); + }, + + "setStrategy should overwrite the default strategy": function(test) { + var replacementStrategy = {}; + var call = new FunctionCall(this.wrappedFn, [], this.callback); + call.setStrategy(replacementStrategy); + call.start(this.backoffFactory); + test.ok(this.backoffFactory.calledWith(replacementStrategy), + 'User defined strategy should be used to instantiate ' + + 'the backoff instance.'); + test.done(); + }, + + "setStrategy should throw if the call is in progress": function(test) { + var call = new FunctionCall(this.wrappedFn, [], this.callback); + call.start(this.backoffFactory); + test.throws(function() { + call.setStrategy({}); + }, /in progress/); + test.done(); + }, + + "failAfter should not be set by default": function(test) { + var call = new FunctionCall(this.wrappedFn, [], this.callback); + call.start(this.backoffFactory); + test.equal(0, this.backoff.failAfter.callCount); + test.done(); + }, + + "failAfter should be used as the maximum number of backoffs": function(test) { + var failAfterValue = 99; + var call = new FunctionCall(this.wrappedFn, [], this.callback); + call.failAfter(failAfterValue); + call.start(this.backoffFactory); + test.ok(this.backoff.failAfter.calledWith(failAfterValue), + 'User defined maximum number of backoffs shoud be ' + + 'used to configure the backoff instance.'); + test.done(); + }, + + "failAfter should throw if the call is in progress": function(test) { + var call = new FunctionCall(this.wrappedFn, [], this.callback); + call.start(this.backoffFactory); + test.throws(function() { + call.failAfter(1234); + }, /in progress/); + test.done(); + }, + + "start shouldn't allow overlapping invocation": function(test) { + var call = new FunctionCall(this.wrappedFn, [], this.callback); + var backoffFactory = this.backoffFactory; + + call.start(backoffFactory); + test.throws(function() { + call.start(backoffFactory); + }, /already started/); + test.done(); + }, + + "start shouldn't allow invocation of aborted call": function(test) { + var call = new FunctionCall(this.wrappedFn, [], this.callback); + var backoffFactory = this.backoffFactory; + + call.abort(); + test.throws(function() { + call.start(backoffFactory); + }, /aborted/); + test.done(); + }, + + "call should forward its arguments to the wrapped function": function(test) { + var call = new FunctionCall(this.wrappedFn, [1, 2, 3], this.callback); + call.start(this.backoffFactory); + test.ok(this.wrappedFn.calledWith(1, 2, 3)); + test.done(); + }, + + "call should complete when the wrapped function succeeds": function(test) { + var call = new FunctionCall(this.wrappedFn, [1, 2, 3], this.callback); + this.wrappedFn. + onCall(0).yields(new Error()). + onCall(1).yields(new Error()). + onCall(2).yields(new Error()). + onCall(3).yields(null, 'Success!'); + + call.start(this.backoffFactory); + + for (var i = 0; i < 2; i++) { + this.backoff.emit('ready'); + } + + test.equals(this.callback.callCount, 0); + this.backoff.emit('ready'); + + test.ok(this.callback.calledWith(null, 'Success!')); + test.ok(this.wrappedFn.alwaysCalledWith(1, 2, 3)); + test.done(); + }, + + "call should fail when the backoff limit is reached": function(test) { + var call = new FunctionCall(this.wrappedFn, [1, 2, 3], this.callback); + var error = new Error(); + this.wrappedFn.yields(error); + call.start(this.backoffFactory); + + for (var i = 0; i < 3; i++) { + this.backoff.emit('ready'); + } + + test.equals(this.callback.callCount, 0); + + this.backoff.emit('fail'); + + test.ok(this.callback.calledWith(error)); + test.ok(this.wrappedFn.alwaysCalledWith(1, 2, 3)); + test.done(); + }, + + "call should fail when the retry predicate returns false": function(test) { + var call = new FunctionCall(this.wrappedFn, [1, 2, 3], this.callback); + call.retryIf(function(err) { return err.retriable; }); + + var retriableError = new Error(); + retriableError.retriable = true; + + var fatalError = new Error(); + fatalError.retriable = false; + + this.wrappedFn. + onCall(0).yields(retriableError). + onCall(1).yields(retriableError). + onCall(2).yields(fatalError); + + call.start(this.backoffFactory); + + for (var i = 0; i < 2; i++) { + this.backoff.emit('ready'); + } + + test.equals(this.callback.callCount, 1); + test.ok(this.callback.calledWith(fatalError)); + test.ok(this.wrappedFn.alwaysCalledWith(1, 2, 3)); + test.done(); + }, + + "wrapped function's callback shouldn't be called after abort": function(test) { + var call = new FunctionCall(function(callback) { + call.abort(); // Abort in middle of wrapped function's execution. + callback(null, 'ok'); + }, [], this.callback); + + call.start(this.backoffFactory); + + test.equals(this.callback.callCount, 1, + 'Wrapped function\'s callback shouldn\'t be called after abort.'); + test.ok(this.callback.calledWithMatch(sinon.match(function (err) { + return !!err.message.match(/Backoff aborted/); + }, "abort error"))); + test.done(); + }, + + "abort event is emitted once when abort is called": function(test) { + var call = new FunctionCall(this.wrappedFn, [], this.callback); + this.wrappedFn.yields(new Error()); + var callEventSpy = sinon.spy(); + + call.on('abort', callEventSpy); + call.start(this.backoffFactory); + + call.abort(); + call.abort(); + call.abort(); + + test.equals(callEventSpy.callCount, 1); + test.done(); + }, + + "getLastResult should return the last intermediary result": function(test) { + var call = new FunctionCall(this.wrappedFn, [], this.callback); + this.wrappedFn.yields(1); + call.start(this.backoffFactory); + + for (var i = 2; i < 5; i++) { + this.wrappedFn.yields(i); + this.backoff.emit('ready'); + test.deepEqual([i], call.getLastResult()); + } + + this.wrappedFn.yields(null); + this.backoff.emit('ready'); + test.deepEqual([null], call.getLastResult()); + + test.done(); + }, + + "getNumRetries should return the number of retries": function(test) { + var call = new FunctionCall(this.wrappedFn, [], this.callback); + + this.wrappedFn.yields(1); + call.start(this.backoffFactory); + // The inital call doesn't count as a retry. + test.equals(0, call.getNumRetries()); + + for (var i = 2; i < 5; i++) { + this.wrappedFn.yields(i); + this.backoff.emit('ready'); + test.equals(i - 1, call.getNumRetries()); + } + + this.wrappedFn.yields(null); + this.backoff.emit('ready'); + test.equals(4, call.getNumRetries()); + + test.done(); + }, + + "wrapped function's errors should be propagated": function(test) { + var call = new FunctionCall(this.wrappedFn, [1, 2, 3], this.callback); + this.wrappedFn.throws(new Error()); + test.throws(function() { + call.start(this.backoffFactory); + }, Error); + test.done(); + }, + + "wrapped callback's errors should be propagated": function(test) { + var call = new FunctionCall(this.wrappedFn, [1, 2, 3], this.callback); + this.wrappedFn.yields(null, 'Success!'); + this.callback.throws(new Error()); + test.throws(function() { + call.start(this.backoffFactory); + }, Error); + test.done(); + }, + + "call event should be emitted when wrapped function gets called": function(test) { + this.wrappedFn.yields(1); + var callEventSpy = sinon.spy(); + + var call = new FunctionCall(this.wrappedFn, [1, 'two'], this.callback); + call.on('call', callEventSpy); + call.start(this.backoffFactory); + + for (var i = 1; i < 5; i++) { + this.backoff.emit('ready'); + } + + test.equal(5, callEventSpy.callCount, + 'The call event should have been emitted 5 times.'); + test.deepEqual([1, 'two'], callEventSpy.getCall(0).args, + 'The call event should carry function\'s args.'); + test.done(); + }, + + "callback event should be emitted when callback is called": function(test) { + var call = new FunctionCall(this.wrappedFn, [1, 'two'], this.callback); + var callbackSpy = sinon.spy(); + call.on('callback', callbackSpy); + + this.wrappedFn.yields('error'); + call.start(this.backoffFactory); + + this.wrappedFn.yields(null, 'done'); + this.backoff.emit('ready'); + + test.equal(2, callbackSpy.callCount, + 'Callback event should have been emitted 2 times.'); + test.deepEqual(['error'], callbackSpy.firstCall.args, + 'First callback event should carry first call\'s results.'); + test.deepEqual([null, 'done'], callbackSpy.secondCall.args, + 'Second callback event should carry second call\'s results.'); + test.done(); + }, + + "backoff event should be emitted on backoff start": function(test) { + var err = new Error('backoff event error'); + var call = new FunctionCall(this.wrappedFn, [1, 'two'], this.callback); + var backoffSpy = sinon.spy(); + + call.on('backoff', backoffSpy); + + this.wrappedFn.yields(err); + call.start(this.backoffFactory); + this.backoff.emit('backoff', 3, 1234, err); + + test.ok(this.backoff.backoff.calledWith(err), + 'The backoff instance should have been called with the error.'); + test.equal(1, backoffSpy.callCount, + 'Backoff event should have been emitted 1 time.'); + test.deepEqual([3, 1234, err], backoffSpy.firstCall.args, + 'Backoff event should carry the backoff number, delay and error.'); + test.done(); + } +}; diff --git a/node_modules/buefy/CHANGELOG.md b/node_modules/buefy/CHANGELOG.md new file mode 100644 index 0000000..aecb67d --- /dev/null +++ b/node_modules/buefy/CHANGELOG.md @@ -0,0 +1,707 @@ +# Buefy Changelog + +## 0.7.5 + +* **New component: Numberinput**, [see docs](https://buefy.org/documentation/numberinput) +* **Loading improved**: can show a custom content, [see docs](https://buefy.org/documentation/loading) +* Add ``destroy-on-hide`` prop to tabs +* Add ``custom-detail-row`` prop to table +* Add ``open-on-focus`` prop and improved accessibility for datepicker (thanks @imfaber) + +### Fixes + +* Fix #1320 space keydown on Firefox to checkbox and switch +* Fix #1325 input emit to upload +* Enable native timepicker to clockpicker when ``mobile-native`` (default ``true``) +* Fix clockpicker docs and input size +* Fix upload opening in IE 11 + +## 0.7.4 + +### New features + +* **New component: Button**, [see docs](https://buefy.org/documentation/button) +* **New component: Clockpicker**, [see docs](https://buefy.org/documentation/clockpicker) (thanks @SharpSeeEr) +* **Notification improved**: can show a notification programmatically, [see docs](https://buefy.org/documentation/notification) +* Add ``custom-formatter`` prop to autocomplete +* Add ``draggable`` prop to table (thanks @suneab) +* Improve accessibility for notification, message and pagination (thanks @mateuswetah) + +### Fixes + +* #956 Fix hidden overflow on tabs (thanks @Baggs) +* #1246 Fix Cleave.js example using Vue 2.6.x (thanks @yxngl) +* #1251 Fix Datepicker closing when page back to ``min-date`` month +* #1257 Fix Datepicker slow/freeze on big year input +* #1282 Fix Datepicker event display wich have a time set (thanks @DonNicoJs) +* #1290 Fix double click event for CheckBox(Button) and Radio(Button) (thanks @yxngl) +* Fix tabindex on switch (thanks @yxngl), radio (thanks @Sacmanxman2) and checkbox + +## 0.7.3 + +### New features + +* **Update Bulma to 0.7.4** +* Add ``required`` prop to radio-button and checkbox-button +* Add ``defaultModalCanCancel`` constructor options (thanks @quimarche) +* Add ``typing`` event to autocomplete (thanks @adrlen) +* Add ``native-autocomplete`` prop to taginput +* Add support to [Font Awesome SVG component](https://www.npmjs.com/package/@fortawesome/vue-fontawesome) (thanks @rhwilr) +* Add ``custom-key-row`` prop to table +* Add ``defaultToastPosition`` and ``defaultSnackbarPosition`` constructor options +* Improve accessibility for collapse and dropdown (thanks @mateuswetah) +* Revert tab as confirm key code to taginput +* #1233 Change left margin to right margin when spacing nested fields (thanks @yxngl) + +### Fixes + +* #1177 Fix IE/Edge datepicker content size +* #1216 Fix reset v-model when upload cancel +* #1219 Fix modal ``width`` prop (thanks @yxngl) + +## 0.7.2 + +### New features + +* Add ``header`` autocomplete slot to taginput +* Add ``required`` prop to switch +* Add ``mobile-sort-placeholder`` prop to table +* Add ``contextmenu`` event to table (thanks @gps-dev) +* Add ``show-detail-icon`` prop to table and toggle row detail programmatically (thanks @omer2500) +* Add ``use-html5-validation`` prop to form components and ``defaultUseHtml5Validation`` constructor options (thanks @lukio3) +* #1164 Disable selecting row on checkbox click when table is ``checkable`` + +### Fixes + +* Fix taginput when ``allow-new`` is enabled +* Fix pagination order when simple +* #1126 Fix init sort using columns table prop +* #898, #1154 Fix browser autocomplete using multiple fields + +## 0.7.1 + +### New features + +* **Update Bulma to 0.7.2** +* Add ``indeterminate`` prop to checkbox (thanks @guanzo) +* #1029 Upgrade vue-test-utils to latest version (thanks @lordfuoco) +* #1065 Add tab as confirm key code to taginput (thanks @williamabbott) +* #1083 Add ``date-creator`` prop to datepicker (thanks @jonagoldman) + +### Fixes + +* #1024 Fix upload SSR support +* #1027 Fix ``icon-pack`` prop when individual components +* #1040 Fix prevent radio with multi-line text from shrinking (thanks @rhwilr) +* #1067 Fix IE 11 UI switch (thanks @patrickabkarian) +* #1072 Fix sorting boolean fields + +## 0.7.0 + +### Breaking changes + +* Change path to import components to use outside main vue instance, like: +```javascript +// see Toast, Snackbar, Modal and Dialog doc pages for more examples +import { Toast } from 'buefy/dist/components/toast' +Toast.open('Toasty!') +``` +* Upload component accepts a single `File` and `Array` when multiple as ``v-model`` +* Rename ``readonly`` to ``editable`` on datepicker and timepicker (now just use the prop without false value) +* **Removed Panel component**, it was deprecated since 0.5.3 + +### New features + +* Add ``closable`` prop to taginput (thanks @adrlen) +* #970 Add Object type to ``type`` prop of field and icon + +### Fixes + +* Updated timepicker style (it's a little smaller now) +* #992 Fix table header disappear with pagination +* #999 Fix ``size`` prop to datepicker and timepicker + +## 0.6.7 + +### New features + +* **Table improved**: can change columns dynamically +* Add ``auto-close`` and ``duration`` props to message and notification +* Add ``allow-duplicates`` prop to taginput +* Add ``required`` prop to radio and checkbox +* Add ``defaultInputHasCounter`` constructor options + +### Fixes and changes + +* #839 Fix ``icon-pack`` from icon to be reactive +* #840 Fix loading position to tagInput (thanks @adrlen) +* #852 Fix label class to field when horizontal +* #872 Fix datepicker default formatter +* #895 Fix loading overlay when not in full page (thanks @adrlen) +* #927 Fix autocomplete when option text is too long (thanks @8bu) +* #948 Fix switch when multi line text (thanks @rhwilr) + +## 0.6.6 + +### New features + +* **Update Bulma to 0.7.1** +* Add ``header`` slot to autocomplete +* Add ``type`` prop to checkbox and radio +* Add ``on-paste-separators`` and ``before-adding`` props to tagInput +* #830 Add ``ellipsis`` prop to tagInput and tag components + +### Fixes and changes + +* #746 Fix default ``dateFormatter`` function to datepicker +* #755 Fix arrow centered when table detail (thanks @wanxe) +* #787 Fix type in horizontal field when message is empty +* #814 Reset scroll to modal before destroy +* #481 Fix tagInput height to match other inputs + +## 0.6.5 + +* Revert some changes on Checkbox, CheckboxButton, Radio, RadioButton, Select and Switch, working as before now +* #711 Fix click event to switch (thanks @adrlen) +* #712 Fix SSR support (thanks @anteriovieira) +* #719 Fix ``header`` slot to tabItem +* #718 Fix ``changeMonth`` and ``changeYear`` events to datepicker in ``change-month`` and ``change-year`` +* #727 Fix upload check file +* #730 Fix field with addons not updating on re-render (tanks @arlen) + +## 0.6.4 + +### New features + +* **Add nuxt-buefy on docs**, [see here](https://buefy.org/#/documentation/start) (thanks @anteriovieira) +* Add ``indefinite`` prop to snackbar +* Add ``header`` slot to datepicker +* Add ``header`` slot to tabItem +* #485 Add ``custom-class`` prop to field (thanks @docnoe) +* #509 Add autocomplete slot support to taginput (thanks @gkinsman) +* #581 Add ``is-row-checkable`` prop to table (thanks @jvmonjo) +* #602 Add ``changeMonth`` and ``changeYear`` events to datepicker +* #604 Add ``remove-on-keys`` prop to taginput, allowing to remove last tag (thanks @adrlen) +* #609 Add ``is-full-page`` prop to loading, to limit it to its container (thanks @adrlen) +* #610 Add ``visible`` prop to tabItem +* #644 Add ``clear-on-select`` prop to autocomplete (thanks @raniesantos) +* #645 Add ``selectable-dates`` prop to datepicker (thanks @pip63) +* #682 Add ``has-detailed-visible`` prop to table (thanks @wanxe) +* #687 Add ``focus-on`` prop to dialog + +### Fixes and changes + +* #576 Fix upload check file type +* #586 Fix dropdown change event +* #593 Fix timepicker update only time of Date object +* #599 Fix ``on-cancel`` prop to dialog, get called when clicking confirm +* #648 Fix dropdown emit change event (thanks @adrlen) +* #670 Fix tabs emit change event (thanks @adrlen) +* #686 Remove 'is-light' color to cancel button of dialog + +## 0.6.3 + +### New features + +* **New extension: Sortable.js**, [see here](https://buefy.org/#/extensions/sortablejs) +* **Update Bulma to 0.6.2** +* **Add Font Awesome 5 support** (http://fontawesome.com/) +* Add ``columns`` prop to table, you can now pass an array instead of adding scoped slots (for simple tables) +* Add ``rounded`` prop to Input, Select, Autocomplete, Datepicker and Timepicker, Pagination +* Add "is-toggle-rounded" type to Tabs +* Add ``open`` prop to collapse ``trigger`` slot +* Add ``native`` prop to upload +* #222 Add ``open-on-focus`` prop to autocomplete (good to simulate a select element) +* #482 Add ``allow-new`` prop to taginput +* #483 Add ``unselectable-days-of-week`` prop to datepicker +* #487 Add ``icon-size`` prop to message +* #492 Add isAsc parameter to ``custom-sort`` function of table (thanks @frantic1048) +* #494 Add ``unselectable-times`` prop to timepicker +* #525 Add ``pagination-size`` prop to table (thanks @nateleavitt) +* #531 Add ``confirm-key-codes`` prop to taginput + +### Fixes and changes + +* Remove ``max-results`` prop from autocomplete, it now has a scrollbar with all results +* #493 Fix ``keep-first`` autocomplete prop with async data +* #498 Fix horizontal field on mobile +* #500 Fix message position for horizontal field (thanks @electrolinux) +* #543 Fix dropdown toggle programmatic + +## 0.6.2 + +### New features + +* **New component: Tag Input**, [see docs](https://buefy.org/#/documentation/taginput) (thanks @jgerbes) +* #125 Add ``queue`` prop to toast/snackbar and ``defaultNoticeQueue`` constructor option + * Note that the animations aren't perfect right now +* #432 **Datepicker improved**: can add event indicators on it (thanks @chasegiunta) +* #439 Add support to horizontal field, with the ``horizontal`` prop (thanks @electrolinux) +* Add ``mobile-native`` prop to datepicker and timepicker +* Add ``defaultDatepickerMobileNative`` and ``defaultTimepickerMobileNative`` constructor options +* Add ``events`` prop to modal (to bind events programmatically) +* Add ``position`` prop to datepicker and timepicker +* Add ``size`` prop to dialog +* Add ``tabstop`` and ``disabled`` props to tag +* Add ``.sync`` option to table ``current-page`` + +### Fixes and changes + +* Maxlength counter for input only shows on focus +* Add padding to tab content +* Fix autocomplete with ``keep-first`` selecting on blur when nothing is shown +* Fix tabs buttons size sometimes flickering +* #416 Fix pagination color +* #419 Fix input icon size +* #428 Fix ``current-page`` from table to be reactive +* #440 Fix upload input file width (thanks @frantic1048) + +## 0.6.1 + +* #409 Fix notification delete button +* #410 Fix alert triggering on upload + +## 0.6.0 + +### Breaking changes + +* Vue 2.5+ is now the minimum required version +* Bulma breaking changes, [see changelog](https://github.com/jgthms/bulma/blob/master/CHANGELOG.md#breaking-changes) +* **Removed** the deprecated prompt dialog ``inputPlaceholder``, ``inputName`` and ``inputMaxlength`` props +* Buefy now uses [MDI icons from community](https://materialdesignicons.com/) instead, you'll have to change icon names and if you use a CDN you should change: + +```html + +``` + +### New features + +* **New component: Timepicker**, [see docs](https://buefy.org/#/documentation/timepicker) +* **New component: Checkbox Button**, [see docs](https://buefy.org/#/documentation/checkbox) +* **New docs section: Extensions**, [see here](https://buefy.org/#/extensions/cleavejs) +* Support for Bulma 0.6.1 +* Add ``disabled`` prop to tabItem +* Add ``focusable`` prop to table +* Add ``focus()`` method to table +* Add ``hoverable`` prop to table +* Add ``custom-size`` prop to icon +* Add ``custom-class`` prop to icon +* Add ``detail-key`` and ``opened-detailed`` props to table (thanks @wanxe) +* Add ``scroll`` prop to modal/dialog (changes what to do with ```` scrollbar) +* Add ``parent`` prop to modal, pass a Vue object to it to open component modal programmatically +* #359 Add ``mobile-modal`` prop to dropdown to enable/disable modal on mobile +* #365 Add ``src/scss/utils/_all.scss`` for easier modular importing (thanks @gwvt) +* #377 Add support to MDI icons from community +* #387 Add ``current-page`` prop to table (thanks @frantic1048) +* #388 Add ``size`` prop to radio and checkbox +* #398 Add ``unselectable-dates`` prop to datepicker to disable an array of dates +* #399 Add configurable closing options for dialog (like modal) + +### Fixes + +* Update tooltip font size and padding, it's a bit bigger now +* Update table keyboard navigation, now doesn't require pressing enter and only works when ``focusable`` +* #288 Fix input message from parent field (thanks @yarbshk) +* #358 Fix modal/dialog shifting content (``scroll`` prop) +* #380 Fix clearing autocomplete input +* #395 Fix ref dropdown availability (thanks @frantic1048) + +## 0.5.4 + +* **Deprecated** prompt dialog ``inputPlaceholder``, ``inputName`` and ``inputMaxlength`` props, use new ``inputAttrs`` prop, [see docs](https://buefy.org/#/documentation/dialog) +* Fix ``focus`` method on select +* Table with ``selected`` prop can now be natigated with keyboard +* #251, #345 Add ``bottom-left`` slot to table +* #334 Add ``defaultDialogConfirmText`` and ``defaultDialogCancelText`` constructor options +* #335 Add ``icon`` and ``iconPack`` prop to dialog +* #350 Add Function type to ``component`` prop of modal (thanks @ivalkenburg) +* #354 Add tab key press to autocomplete (thanks @tmepple) +* #356 Fix table header alignment + +## 0.5.3 + +* **New component: Collapse**, [see docs](https://buefy.org/#/documentation/collapse) +* **Panel deprecated**, use new Collapse component, [old docs here](https://buefy.org/#/documentation/panel) +* Update Bulma to v0.5.3 +* #223 Add ``footer`` slot to table +* #246 Remove ``key`` on detailed rows of table component (thanks @Tirke) +* #301 Fix Bulma style override for radio and checkbox +* #303 Fix dropdown close on custom item when is replaced or changed +* #305 Fix datepicker calendar display when disabled and inline +* #309 Add ``labelFor`` prop to field component, to set native ``for`` attribute to the label tag (thanks @tmepple) +* #314 Set pack prop to next/prev icon buttons for datepicker +* #315 Fix escape regexp characters to autocomplete +* #316 Fix checkbox shrinking when text is very long (thanks @Tirke) +* #317 Add default datepicker constructor options +* #324 Fix table broken sort state +* #330 Fix table empty and detail disposition +* #339 Fix upload warning when is required +* #340 Add ``size`` prop to radio button + +## 0.5.2 + +* #262 Add ``empty`` slot to autocomplete (empty message) +* #264 Add ``has-counter`` prop to input, add it when you want show or hide character counter when maxlength prop is passed +* #265 Fix disabled pagination (thanks @YassinOuider) +* #272 Add ``readonly`` prop to allow typing a date on datepicker +* #273 Fix autocomplete for SSR (thanks @LANSELOT) +* #276 Add ``first-day-of-week`` prop to datepicker +* #279 Fix table not default sorting async data +* #289 Fix dropdown-trigger container html tag +* #291 Add configurable closing options for Modal (thanks @jwahdatehagh) +* #298 Fix mobile detection datepicker for SSR +* #302 Fix datepicker calendar display when disabled + +## 0.5.1 + +* **New component: Datepicker**, [see docs](https://buefy.org/#/documentation/datepicker) (thanks @bartboy011) +* **New component: Tag**, [see docs](https://buefy.org/#/documentation/tag) +* #195 Add ``custom-key`` prop to table column, add it when you want a column without label +* #221 Add backend pagination support to table (thanks @cappuc) +* #214 Add ``active`` prop to tooltip +* #215 Add ``header`` slot to table (custom headers) +* #228 Fix table checked rows not working on mobile +* #235 Add ``custom-is-checked`` prop to table column, add it when you want a custom compare function when is checkable +* #237 Fix emit blur event for input +* #239 Fix table columns on v-for loop +* #241 Fix remove tabItem when it's bounded to array +* #242 Update required Vue.js version (2.4+) (thanks @iwan-wijaya) +* #243 Add ``default-sort-direction`` prop to table, add it when you want change default sort direction on the first click +* #260 Fix radio/radio button emitting ``input`` multiple times (thanks @frantic1048) +* Add ``meta`` prop to table column, useful for custom headers +* Add ``type`` prop to switch (thanks @Tirke) +* Add ``multiple`` support to select +* Add ``inline`` prop to dropdown, items are shown inline and trigger removed +* Remove ``has-custom-template`` prop from autocomplete, just use scoped slot to have the same feature + +## 0.5.0 + +### Breaking changes + +* **Update Bulma to v0.5.1**, changes on Sass variables naming, [see docs](https://github.com/jgthms/bulma/blob/master/CHANGELOG.md#050) + * Buefy Sass variables are also following the new convention +* **Removed Menu component**, it was experimental and wasn't good enough, needed too much to work and can easily be replaced with pure HTML +* Constructor option ``defaultContentElement`` renamed to ``defaultContainerElement`` +* ``b-dropdown-option`` renamed to ``b-dropdown-item`` + * ``subheader`` prop renamed to ``custom`` +* Any attributes on Input, Select and Autocomplete will be added directly to ```` or ``