bl 3.0.1 → 4.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.travis.yml CHANGED
@@ -4,6 +4,9 @@ node_js:
4
4
  - '6'
5
5
  - '8'
6
6
  - '10'
7
+ - '12'
8
+ - '14'
9
+ - lts/*
7
10
  branches:
8
11
  only:
9
12
  - master
package/BufferList.js ADDED
@@ -0,0 +1,396 @@
1
+ 'use strict'
2
+
3
+ const { Buffer } = require('buffer')
4
+ const symbol = Symbol.for('BufferList')
5
+
6
+ function BufferList (buf) {
7
+ if (!(this instanceof BufferList)) {
8
+ return new BufferList(buf)
9
+ }
10
+
11
+ BufferList._init.call(this, buf)
12
+ }
13
+
14
+ BufferList._init = function _init (buf) {
15
+ Object.defineProperty(this, symbol, { value: true })
16
+
17
+ this._bufs = []
18
+ this.length = 0
19
+
20
+ if (buf) {
21
+ this.append(buf)
22
+ }
23
+ }
24
+
25
+ BufferList.prototype._new = function _new (buf) {
26
+ return new BufferList(buf)
27
+ }
28
+
29
+ BufferList.prototype._offset = function _offset (offset) {
30
+ if (offset === 0) {
31
+ return [0, 0]
32
+ }
33
+
34
+ let tot = 0
35
+
36
+ for (let i = 0; i < this._bufs.length; i++) {
37
+ const _t = tot + this._bufs[i].length
38
+ if (offset < _t || i === this._bufs.length - 1) {
39
+ return [i, offset - tot]
40
+ }
41
+ tot = _t
42
+ }
43
+ }
44
+
45
+ BufferList.prototype._reverseOffset = function (blOffset) {
46
+ const bufferId = blOffset[0]
47
+ let offset = blOffset[1]
48
+
49
+ for (let i = 0; i < bufferId; i++) {
50
+ offset += this._bufs[i].length
51
+ }
52
+
53
+ return offset
54
+ }
55
+
56
+ BufferList.prototype.get = function get (index) {
57
+ if (index > this.length || index < 0) {
58
+ return undefined
59
+ }
60
+
61
+ const offset = this._offset(index)
62
+
63
+ return this._bufs[offset[0]][offset[1]]
64
+ }
65
+
66
+ BufferList.prototype.slice = function slice (start, end) {
67
+ if (typeof start === 'number' && start < 0) {
68
+ start += this.length
69
+ }
70
+
71
+ if (typeof end === 'number' && end < 0) {
72
+ end += this.length
73
+ }
74
+
75
+ return this.copy(null, 0, start, end)
76
+ }
77
+
78
+ BufferList.prototype.copy = function copy (dst, dstStart, srcStart, srcEnd) {
79
+ if (typeof srcStart !== 'number' || srcStart < 0) {
80
+ srcStart = 0
81
+ }
82
+
83
+ if (typeof srcEnd !== 'number' || srcEnd > this.length) {
84
+ srcEnd = this.length
85
+ }
86
+
87
+ if (srcStart >= this.length) {
88
+ return dst || Buffer.alloc(0)
89
+ }
90
+
91
+ if (srcEnd <= 0) {
92
+ return dst || Buffer.alloc(0)
93
+ }
94
+
95
+ const copy = !!dst
96
+ const off = this._offset(srcStart)
97
+ const len = srcEnd - srcStart
98
+ let bytes = len
99
+ let bufoff = (copy && dstStart) || 0
100
+ let start = off[1]
101
+
102
+ // copy/slice everything
103
+ if (srcStart === 0 && srcEnd === this.length) {
104
+ if (!copy) {
105
+ // slice, but full concat if multiple buffers
106
+ return this._bufs.length === 1
107
+ ? this._bufs[0]
108
+ : Buffer.concat(this._bufs, this.length)
109
+ }
110
+
111
+ // copy, need to copy individual buffers
112
+ for (let i = 0; i < this._bufs.length; i++) {
113
+ this._bufs[i].copy(dst, bufoff)
114
+ bufoff += this._bufs[i].length
115
+ }
116
+
117
+ return dst
118
+ }
119
+
120
+ // easy, cheap case where it's a subset of one of the buffers
121
+ if (bytes <= this._bufs[off[0]].length - start) {
122
+ return copy
123
+ ? this._bufs[off[0]].copy(dst, dstStart, start, start + bytes)
124
+ : this._bufs[off[0]].slice(start, start + bytes)
125
+ }
126
+
127
+ if (!copy) {
128
+ // a slice, we need something to copy in to
129
+ dst = Buffer.allocUnsafe(len)
130
+ }
131
+
132
+ for (let i = off[0]; i < this._bufs.length; i++) {
133
+ const l = this._bufs[i].length - start
134
+
135
+ if (bytes > l) {
136
+ this._bufs[i].copy(dst, bufoff, start)
137
+ bufoff += l
138
+ } else {
139
+ this._bufs[i].copy(dst, bufoff, start, start + bytes)
140
+ bufoff += l
141
+ break
142
+ }
143
+
144
+ bytes -= l
145
+
146
+ if (start) {
147
+ start = 0
148
+ }
149
+ }
150
+
151
+ // safeguard so that we don't return uninitialized memory
152
+ if (dst.length > bufoff) return dst.slice(0, bufoff)
153
+
154
+ return dst
155
+ }
156
+
157
+ BufferList.prototype.shallowSlice = function shallowSlice (start, end) {
158
+ start = start || 0
159
+ end = typeof end !== 'number' ? this.length : end
160
+
161
+ if (start < 0) {
162
+ start += this.length
163
+ }
164
+
165
+ if (end < 0) {
166
+ end += this.length
167
+ }
168
+
169
+ if (start === end) {
170
+ return this._new()
171
+ }
172
+
173
+ const startOffset = this._offset(start)
174
+ const endOffset = this._offset(end)
175
+ const buffers = this._bufs.slice(startOffset[0], endOffset[0] + 1)
176
+
177
+ if (endOffset[1] === 0) {
178
+ buffers.pop()
179
+ } else {
180
+ buffers[buffers.length - 1] = buffers[buffers.length - 1].slice(0, endOffset[1])
181
+ }
182
+
183
+ if (startOffset[1] !== 0) {
184
+ buffers[0] = buffers[0].slice(startOffset[1])
185
+ }
186
+
187
+ return this._new(buffers)
188
+ }
189
+
190
+ BufferList.prototype.toString = function toString (encoding, start, end) {
191
+ return this.slice(start, end).toString(encoding)
192
+ }
193
+
194
+ BufferList.prototype.consume = function consume (bytes) {
195
+ // first, normalize the argument, in accordance with how Buffer does it
196
+ bytes = Math.trunc(bytes)
197
+ // do nothing if not a positive number
198
+ if (Number.isNaN(bytes) || bytes <= 0) return this
199
+
200
+ while (this._bufs.length) {
201
+ if (bytes >= this._bufs[0].length) {
202
+ bytes -= this._bufs[0].length
203
+ this.length -= this._bufs[0].length
204
+ this._bufs.shift()
205
+ } else {
206
+ this._bufs[0] = this._bufs[0].slice(bytes)
207
+ this.length -= bytes
208
+ break
209
+ }
210
+ }
211
+
212
+ return this
213
+ }
214
+
215
+ BufferList.prototype.duplicate = function duplicate () {
216
+ const copy = this._new()
217
+
218
+ for (let i = 0; i < this._bufs.length; i++) {
219
+ copy.append(this._bufs[i])
220
+ }
221
+
222
+ return copy
223
+ }
224
+
225
+ BufferList.prototype.append = function append (buf) {
226
+ if (buf == null) {
227
+ return this
228
+ }
229
+
230
+ if (buf.buffer) {
231
+ // append a view of the underlying ArrayBuffer
232
+ this._appendBuffer(Buffer.from(buf.buffer, buf.byteOffset, buf.byteLength))
233
+ } else if (Array.isArray(buf)) {
234
+ for (let i = 0; i < buf.length; i++) {
235
+ this.append(buf[i])
236
+ }
237
+ } else if (this._isBufferList(buf)) {
238
+ // unwrap argument into individual BufferLists
239
+ for (let i = 0; i < buf._bufs.length; i++) {
240
+ this.append(buf._bufs[i])
241
+ }
242
+ } else {
243
+ // coerce number arguments to strings, since Buffer(number) does
244
+ // uninitialized memory allocation
245
+ if (typeof buf === 'number') {
246
+ buf = buf.toString()
247
+ }
248
+
249
+ this._appendBuffer(Buffer.from(buf))
250
+ }
251
+
252
+ return this
253
+ }
254
+
255
+ BufferList.prototype._appendBuffer = function appendBuffer (buf) {
256
+ this._bufs.push(buf)
257
+ this.length += buf.length
258
+ }
259
+
260
+ BufferList.prototype.indexOf = function (search, offset, encoding) {
261
+ if (encoding === undefined && typeof offset === 'string') {
262
+ encoding = offset
263
+ offset = undefined
264
+ }
265
+
266
+ if (typeof search === 'function' || Array.isArray(search)) {
267
+ throw new TypeError('The "value" argument must be one of type string, Buffer, BufferList, or Uint8Array.')
268
+ } else if (typeof search === 'number') {
269
+ search = Buffer.from([search])
270
+ } else if (typeof search === 'string') {
271
+ search = Buffer.from(search, encoding)
272
+ } else if (this._isBufferList(search)) {
273
+ search = search.slice()
274
+ } else if (Array.isArray(search.buffer)) {
275
+ search = Buffer.from(search.buffer, search.byteOffset, search.byteLength)
276
+ } else if (!Buffer.isBuffer(search)) {
277
+ search = Buffer.from(search)
278
+ }
279
+
280
+ offset = Number(offset || 0)
281
+
282
+ if (isNaN(offset)) {
283
+ offset = 0
284
+ }
285
+
286
+ if (offset < 0) {
287
+ offset = this.length + offset
288
+ }
289
+
290
+ if (offset < 0) {
291
+ offset = 0
292
+ }
293
+
294
+ if (search.length === 0) {
295
+ return offset > this.length ? this.length : offset
296
+ }
297
+
298
+ const blOffset = this._offset(offset)
299
+ let blIndex = blOffset[0] // index of which internal buffer we're working on
300
+ let buffOffset = blOffset[1] // offset of the internal buffer we're working on
301
+
302
+ // scan over each buffer
303
+ for (; blIndex < this._bufs.length; blIndex++) {
304
+ const buff = this._bufs[blIndex]
305
+
306
+ while (buffOffset < buff.length) {
307
+ const availableWindow = buff.length - buffOffset
308
+
309
+ if (availableWindow >= search.length) {
310
+ const nativeSearchResult = buff.indexOf(search, buffOffset)
311
+
312
+ if (nativeSearchResult !== -1) {
313
+ return this._reverseOffset([blIndex, nativeSearchResult])
314
+ }
315
+
316
+ buffOffset = buff.length - search.length + 1 // end of native search window
317
+ } else {
318
+ const revOffset = this._reverseOffset([blIndex, buffOffset])
319
+
320
+ if (this._match(revOffset, search)) {
321
+ return revOffset
322
+ }
323
+
324
+ buffOffset++
325
+ }
326
+ }
327
+
328
+ buffOffset = 0
329
+ }
330
+
331
+ return -1
332
+ }
333
+
334
+ BufferList.prototype._match = function (offset, search) {
335
+ if (this.length - offset < search.length) {
336
+ return false
337
+ }
338
+
339
+ for (let searchOffset = 0; searchOffset < search.length; searchOffset++) {
340
+ if (this.get(offset + searchOffset) !== search[searchOffset]) {
341
+ return false
342
+ }
343
+ }
344
+ return true
345
+ }
346
+
347
+ ;(function () {
348
+ const methods = {
349
+ readDoubleBE: 8,
350
+ readDoubleLE: 8,
351
+ readFloatBE: 4,
352
+ readFloatLE: 4,
353
+ readInt32BE: 4,
354
+ readInt32LE: 4,
355
+ readUInt32BE: 4,
356
+ readUInt32LE: 4,
357
+ readInt16BE: 2,
358
+ readInt16LE: 2,
359
+ readUInt16BE: 2,
360
+ readUInt16LE: 2,
361
+ readInt8: 1,
362
+ readUInt8: 1,
363
+ readIntBE: null,
364
+ readIntLE: null,
365
+ readUIntBE: null,
366
+ readUIntLE: null
367
+ }
368
+
369
+ for (const m in methods) {
370
+ (function (m) {
371
+ if (methods[m] === null) {
372
+ BufferList.prototype[m] = function (offset, byteLength) {
373
+ return this.slice(offset, offset + byteLength)[m](0, byteLength)
374
+ }
375
+ } else {
376
+ BufferList.prototype[m] = function (offset) {
377
+ return this.slice(offset, offset + methods[m])[m](0)
378
+ }
379
+ }
380
+ }(m))
381
+ }
382
+ }())
383
+
384
+ // Used internally by the class and also as an indicator of this object being
385
+ // a `BufferList`. It's not possible to use `instanceof BufferList` in a browser
386
+ // environment because there could be multiple different copies of the
387
+ // BufferList class and some `BufferList`s might be `BufferList`s.
388
+ BufferList.prototype._isBufferList = function _isBufferList (b) {
389
+ return b instanceof BufferList || BufferList.isBufferList(b)
390
+ }
391
+
392
+ BufferList.isBufferList = function isBufferList (b) {
393
+ return b != null && b[symbol]
394
+ }
395
+
396
+ module.exports = BufferList
package/LICENSE.md CHANGED
@@ -1,7 +1,7 @@
1
1
  The MIT License (MIT)
2
2
  =====================
3
3
 
4
- Copyright (c) 2013-2018 bl contributors
4
+ Copyright (c) 2013-2019 bl contributors
5
5
  ----------------------------------
6
6
 
7
7
  *bl contributors listed at <https://github.com/rvagg/bl#contributors>*
package/README.md CHANGED
@@ -1,20 +1,19 @@
1
1
  # bl *(BufferList)*
2
2
 
3
- [![Build Status](https://travis-ci.org/rvagg/bl.svg?branch=master)](https://travis-ci.org/rvagg/bl)
3
+ [![Build Status](https://api.travis-ci.com/rvagg/bl.svg?branch=master)](https://travis-ci.com/rvagg/bl/)
4
4
 
5
5
  **A Node.js Buffer list collector, reader and streamer thingy.**
6
6
 
7
- [![NPM](https://nodei.co/npm/bl.png?downloads=true&downloadRank=true)](https://nodei.co/npm/bl/)
8
- [![NPM](https://nodei.co/npm-dl/bl.png?months=6&height=3)](https://nodei.co/npm/bl/)
7
+ [![NPM](https://nodei.co/npm/bl.svg)](https://nodei.co/npm/bl/)
9
8
 
10
9
  **bl** is a storage object for collections of Node Buffers, exposing them with the main Buffer readable API. Also works as a duplex stream so you can collect buffers from a stream that emits them and emit buffers to a stream that consumes them!
11
10
 
12
11
  The original buffers are kept intact and copies are only done as necessary. Any reads that require the use of a single original buffer will return a slice of that buffer only (which references the same memory as the original buffer). Reads that span buffers perform concatenation as required and return the results transparently.
13
12
 
14
13
  ```js
15
- const BufferList = require('bl')
14
+ const { BufferList } = require('bl')
16
15
 
17
- var bl = new BufferList()
16
+ const bl = new BufferList()
18
17
  bl.append(Buffer.from('abcd'))
19
18
  bl.append(Buffer.from('efg'))
20
19
  bl.append('hi') // bl will also accept & convert Strings
@@ -45,11 +44,11 @@ console.log(bl.readUInt16LE(10)) // 0x0403
45
44
  Give it a callback in the constructor and use it just like **[concat-stream](https://github.com/maxogden/node-concat-stream)**:
46
45
 
47
46
  ```js
48
- const bl = require('bl')
49
- , fs = require('fs')
47
+ const { BufferListStream } = require('bl')
48
+ const fs = require('fs')
50
49
 
51
50
  fs.createReadStream('README.md')
52
- .pipe(bl(function (err, data) { // note 'new' isn't strictly required
51
+ .pipe(BufferListStream((err, data) => { // note 'new' isn't strictly required
53
52
  // `data` is a complete Buffer object containing the full data
54
53
  console.log(data.toString())
55
54
  }))
@@ -58,12 +57,14 @@ fs.createReadStream('README.md')
58
57
  Note that when you use the *callback* method like this, the resulting `data` parameter is a concatenation of all `Buffer` objects in the list. If you want to avoid the overhead of this concatenation (in cases of extreme performance consciousness), then avoid the *callback* method and just listen to `'end'` instead, like a standard Stream.
59
58
 
60
59
  Or to fetch a URL using [hyperquest](https://github.com/substack/hyperquest) (should work with [request](http://github.com/mikeal/request) and even plain Node http too!):
60
+
61
61
  ```js
62
62
  const hyperquest = require('hyperquest')
63
- , bl = require('bl')
64
- , url = 'https://raw.github.com/rvagg/bl/master/README.md'
63
+ const { BufferListStream } = require('bl')
64
+
65
+ const url = 'https://raw.github.com/rvagg/bl/master/README.md'
65
66
 
66
- hyperquest(url).pipe(bl(function (err, data) {
67
+ hyperquest(url).pipe(BufferListStream((err, data) => {
67
68
  console.log(data.toString())
68
69
  }))
69
70
  ```
@@ -71,10 +72,10 @@ hyperquest(url).pipe(bl(function (err, data) {
71
72
  Or, use it as a readable stream to recompose a list of Buffers to an output source:
72
73
 
73
74
  ```js
74
- const BufferList = require('bl')
75
- , fs = require('fs')
75
+ const { BufferListStream } = require('bl')
76
+ const fs = require('fs')
76
77
 
77
- var bl = new BufferList()
78
+ var bl = new BufferListStream()
78
79
  bl.append(Buffer.from('abcd'))
79
80
  bl.append(Buffer.from('efg'))
80
81
  bl.append(Buffer.from('hi'))
@@ -85,7 +86,8 @@ bl.pipe(fs.createWriteStream('gibberish.txt'))
85
86
 
86
87
  ## API
87
88
 
88
- * <a href="#ctor"><code><b>new BufferList([ callback ])</b></code></a>
89
+ * <a href="#ctor"><code><b>new BufferList([ buf ])</b></code></a>
90
+ * <a href="#isBufferList"><code><b>BufferList.isBufferList(obj)</b></code></a>
89
91
  * <a href="#length"><code>bl.<b>length</b></code></a>
90
92
  * <a href="#append"><code>bl.<b>append(buffer)</b></code></a>
91
93
  * <a href="#get"><code>bl.<b>get(index)</b></code></a>
@@ -97,27 +99,32 @@ bl.pipe(fs.createWriteStream('gibberish.txt'))
97
99
  * <a href="#consume"><code>bl.<b>consume(bytes)</b></code></a>
98
100
  * <a href="#toString"><code>bl.<b>toString([encoding, [ start, [ end ]]])</b></code></a>
99
101
  * <a href="#readXX"><code>bl.<b>readDoubleBE()</b></code>, <code>bl.<b>readDoubleLE()</b></code>, <code>bl.<b>readFloatBE()</b></code>, <code>bl.<b>readFloatLE()</b></code>, <code>bl.<b>readInt32BE()</b></code>, <code>bl.<b>readInt32LE()</b></code>, <code>bl.<b>readUInt32BE()</b></code>, <code>bl.<b>readUInt32LE()</b></code>, <code>bl.<b>readInt16BE()</b></code>, <code>bl.<b>readInt16LE()</b></code>, <code>bl.<b>readUInt16BE()</b></code>, <code>bl.<b>readUInt16LE()</b></code>, <code>bl.<b>readInt8()</b></code>, <code>bl.<b>readUInt8()</b></code></a>
100
- * <a href="#streams">Streams</a>
102
+ * <a href="#ctorStream"><code><b>new BufferListStream([ callback ])</b></code></a>
101
103
 
102
104
  --------------------------------------------------------
103
105
  <a name="ctor"></a>
104
- ### new BufferList([ callback | Buffer | Buffer array | BufferList | BufferList array | String ])
105
- The constructor takes an optional callback, if supplied, the callback will be called with an error argument followed by a reference to the **bl** instance, when `bl.end()` is called (i.e. from a piped stream). This is a convenient method of collecting the entire contents of a stream, particularly when the stream is *chunky*, such as a network stream.
106
-
107
- Normally, no arguments are required for the constructor, but you can initialise the list by passing in a single `Buffer` object or an array of `Buffer` object.
106
+ ### new BufferList([ Buffer | Buffer array | BufferList | BufferList array | String ])
107
+ No arguments are _required_ for the constructor, but you can initialise the list by passing in a single `Buffer` object or an array of `Buffer` objects.
108
108
 
109
109
  `new` is not strictly required, if you don't instantiate a new object, it will be done automatically for you so you can create a new instance simply with:
110
110
 
111
111
  ```js
112
- var bl = require('bl')
113
- var myinstance = bl()
112
+ const { BufferList } = require('bl')
113
+ const bl = BufferList()
114
114
 
115
115
  // equivalent to:
116
116
 
117
- var BufferList = require('bl')
118
- var myinstance = new BufferList()
117
+ const { BufferList } = require('bl')
118
+ const bl = new BufferList()
119
119
  ```
120
120
 
121
+ --------------------------------------------------------
122
+ <a name="isBufferList"></a>
123
+ ### BufferList.isBufferList(obj)
124
+ Determines if the passed object is a `BufferList`. It will return `true` if the passed object is an instance of `BufferList` **or** `BufferListStream` and `false` otherwise.
125
+
126
+ N.B. this won't return `true` for `BufferList` or `BufferListStream` instances created by versions of this library before this static method was added.
127
+
121
128
  --------------------------------------------------------
122
129
  <a name="length"></a>
123
130
  ### bl.length
@@ -164,7 +171,7 @@ No copies will be performed. All buffers in the result share memory with the ori
164
171
  `duplicate()` performs a **shallow-copy** of the list. The internal Buffers remains the same, so if you change the underlying Buffers, the change will be reflected in both the original and the duplicate. This method is needed if you want to call `consume()` or `pipe()` and still keep the original list.Example:
165
172
 
166
173
  ```js
167
- var bl = new BufferList()
174
+ var bl = new BufferListStream()
168
175
 
169
176
  bl.append('hello')
170
177
  bl.append(' world')
@@ -194,9 +201,33 @@ All of the standard byte-reading methods of the `Buffer` interface are implement
194
201
  See the <b><code>[Buffer](http://nodejs.org/docs/latest/api/buffer.html)</code></b> documentation for how these work.
195
202
 
196
203
  --------------------------------------------------------
197
- <a name="streams"></a>
198
- ### Streams
199
- **bl** is a Node **[Duplex Stream](http://nodejs.org/docs/latest/api/stream.html#stream_class_stream_duplex)**, so it can be read from and written to like a standard Node stream. You can also `pipe()` to and from a **bl** instance.
204
+ <a name="ctorStream"></a>
205
+ ### new BufferListStream([ callback | Buffer | Buffer array | BufferList | BufferList array | String ])
206
+ **BufferListStream** is a Node **[Duplex Stream](http://nodejs.org/docs/latest/api/stream.html#stream_class_stream_duplex)**, so it can be read from and written to like a standard Node stream. You can also `pipe()` to and from a **BufferListStream** instance.
207
+
208
+ The constructor takes an optional callback, if supplied, the callback will be called with an error argument followed by a reference to the **bl** instance, when `bl.end()` is called (i.e. from a piped stream). This is a convenient method of collecting the entire contents of a stream, particularly when the stream is *chunky*, such as a network stream.
209
+
210
+ Normally, no arguments are required for the constructor, but you can initialise the list by passing in a single `Buffer` object or an array of `Buffer` object.
211
+
212
+ `new` is not strictly required, if you don't instantiate a new object, it will be done automatically for you so you can create a new instance simply with:
213
+
214
+ ```js
215
+ const { BufferListStream } = require('bl')
216
+ const bl = BufferListStream()
217
+
218
+ // equivalent to:
219
+
220
+ const { BufferListStream } = require('bl')
221
+ const bl = new BufferListStream()
222
+ ```
223
+
224
+ N.B. For backwards compatibility reasons, `BufferListStream` is the **default** export when you `require('bl')`:
225
+
226
+ ```js
227
+ const { BufferListStream } = require('bl')
228
+ // equivalent to:
229
+ const BufferListStream = require('bl')
230
+ ```
200
231
 
201
232
  --------------------------------------------------------
202
233
 
@@ -208,11 +239,9 @@ See the <b><code>[Buffer](http://nodejs.org/docs/latest/api/buffer.html)</code><
208
239
  * [Matteo Collina](https://github.com/mcollina)
209
240
  * [Jarett Cruger](https://github.com/jcrugzz)
210
241
 
211
- =======
212
-
213
242
  <a name="license"></a>
214
243
  ## License &amp; copyright
215
244
 
216
- Copyright (c) 2013-2018 bl contributors (listed above).
245
+ Copyright (c) 2013-2019 bl contributors (listed above).
217
246
 
218
247
  bl is licensed under the MIT license. All rights not explicitly granted in the MIT license are reserved. See the included LICENSE.md file for more details.