hypercore 11.16.1 → 11.17.0

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/lib/audit.js CHANGED
@@ -3,9 +3,20 @@ const flat = require('flat-tree')
3
3
  const b4a = require('b4a')
4
4
  const { MerkleTree } = require('./merkle-tree')
5
5
 
6
- module.exports = async function auditCore (core, { tree = true, blocks = true, bitfield = true, dryRun = false } = {}) {
6
+ module.exports = async function auditCore(
7
+ core,
8
+ { tree = true, blocks = true, bitfield = true, dryRun = false } = {}
9
+ ) {
7
10
  const length = core.state.length
8
- const stats = { treeNodes: 0, blocks: 0, bits: 0, droppedTreeNodes: 0, droppedBlocks: 0, droppedBits: 0, corrupt: false }
11
+ const stats = {
12
+ treeNodes: 0,
13
+ blocks: 0,
14
+ bits: 0,
15
+ droppedTreeNodes: 0,
16
+ droppedBlocks: 0,
17
+ droppedBits: 0,
18
+ corrupt: false
19
+ }
9
20
 
10
21
  // audit the tree
11
22
  if (tree) {
@@ -113,7 +124,7 @@ module.exports = async function auditCore (core, { tree = true, blocks = true, b
113
124
 
114
125
  const page = core.bitfield.getBitfield(index)
115
126
  if (page.bitfield) tx.putBitfieldPage(page.index, page.bitfield)
116
- else tx.deleteBitfieldPage(page.idnex)
127
+ else tx.deleteBitfieldPage(page.index)
117
128
  continue
118
129
  }
119
130
 
@@ -126,20 +137,20 @@ module.exports = async function auditCore (core, { tree = true, blocks = true, b
126
137
  return stats
127
138
  }
128
139
 
129
- function isBadBlock (node, block) {
140
+ function isBadBlock(node, block) {
130
141
  if (!node) return true
131
142
  const hash = crypto.data(block)
132
143
  return !b4a.equals(hash, node.hash) || node.size !== block.byteLength
133
144
  }
134
145
 
135
- function isBadTree (parent, left, right) {
146
+ function isBadTree(parent, left, right) {
136
147
  if (!left && !right) return false
137
148
  if (!left || !right) return true
138
149
  const hash = crypto.parent(left, right)
139
- return !b4a.equals(hash, parent.hash) || parent.size !== (left.size + right.size)
150
+ return !b4a.equals(hash, parent.hash) || parent.size !== left.size + right.size
140
151
  }
141
152
 
142
- function * allBits (bitfield) {
153
+ function* allBits(bitfield) {
143
154
  let i = 0
144
155
  if (bitfield.get(0)) yield 0
145
156
  while (true) {
@@ -2,11 +2,11 @@ const b4a = require('b4a')
2
2
  const quickbit = require('./compat').quickbit
3
3
 
4
4
  module.exports = class BitInterlude {
5
- constructor () {
5
+ constructor() {
6
6
  this.ranges = []
7
7
  }
8
8
 
9
- contiguousLength (from) {
9
+ contiguousLength(from) {
10
10
  for (const r of this.ranges) {
11
11
  if (r.start > from) break
12
12
  if (!r.value && r.start <= from) return r.start
@@ -17,7 +17,7 @@ module.exports = class BitInterlude {
17
17
  return from
18
18
  }
19
19
 
20
- get (index) {
20
+ get(index) {
21
21
  let start = 0
22
22
  let end = this.ranges.length
23
23
 
@@ -42,7 +42,7 @@ module.exports = class BitInterlude {
42
42
  return false
43
43
  }
44
44
 
45
- setRange (start, end, value) {
45
+ setRange(start, end, value) {
46
46
  if (start === end) return
47
47
 
48
48
  let r = null
@@ -75,8 +75,18 @@ module.exports = class BitInterlude {
75
75
  // we overran but our start is contained in this interval, move start back
76
76
  if (start >= r.start && start <= r.end) {
77
77
  if (r.value !== value) {
78
+ r.end = start // Crop current comparison
79
+
80
+ // If there's a next range
81
+ if (this.ranges.length - 1 > i) {
82
+ const next = this.ranges[i + 1]
83
+ // If the same, go next
84
+ if (next.value === value) continue
85
+ // Else we overlap so update next range
86
+ if (next.start < end) next.start = end
87
+ }
88
+
78
89
  this.ranges.splice(++i, 0, { start, end, value })
79
- r.end = start
80
90
  return
81
91
  }
82
92
 
@@ -109,7 +119,7 @@ module.exports = class BitInterlude {
109
119
  this.ranges.push({ start, end, value })
110
120
  }
111
121
 
112
- flush (tx, bitfield) {
122
+ flush(tx, bitfield) {
113
123
  if (!this.ranges.length) return []
114
124
 
115
125
  let index = this.ranges[0].start
@@ -159,7 +169,7 @@ module.exports = class BitInterlude {
159
169
  }
160
170
  }
161
171
 
162
- function mergeRanges (a, b) {
172
+ function mergeRanges(a, b) {
163
173
  const ranges = []
164
174
  if (a.start < b.start) ranges.push({ start: a.start, end: b.start, value: a.value })
165
175
  ranges.push({ start: b.start, end: b.end, value: b.value })
package/lib/bitfield.js CHANGED
@@ -13,7 +13,7 @@ const PAGES_PER_SEGMENT = BITS_PER_SEGMENT / BITS_PER_PAGE
13
13
  const SEGMENT_GROWTH_FACTOR = 4
14
14
 
15
15
  class BitfieldPage {
16
- constructor (index, segment) {
16
+ constructor(index, segment) {
17
17
  this.index = index
18
18
  this.offset = index * BYTES_PER_PAGE - segment.offset
19
19
  this.bitfield = null
@@ -22,21 +22,21 @@ class BitfieldPage {
22
22
  segment.add(this)
23
23
  }
24
24
 
25
- get tree () {
25
+ get tree() {
26
26
  return this.segment.tree
27
27
  }
28
28
 
29
- get (index, dirty) {
29
+ get(index, dirty) {
30
30
  return quickbit.get(this.bitfield, index)
31
31
  }
32
32
 
33
- set (index, val) {
33
+ set(index, val) {
34
34
  if (quickbit.set(this.bitfield, index, val)) {
35
35
  this.tree.update(this.offset * 8 + index)
36
36
  }
37
37
  }
38
38
 
39
- setRange (start, end, val) {
39
+ setRange(start, end, val) {
40
40
  quickbit.fill(this.bitfield, val, start, end)
41
41
 
42
42
  let i = Math.floor(start / 128)
@@ -45,15 +45,15 @@ class BitfieldPage {
45
45
  while (i <= n) this.tree.update(this.offset * 8 + i++ * 128)
46
46
  }
47
47
 
48
- findFirst (val, position) {
48
+ findFirst(val, position) {
49
49
  return quickbit.findFirst(this.bitfield, val, position)
50
50
  }
51
51
 
52
- findLast (val, position) {
52
+ findLast(val, position) {
53
53
  return quickbit.findLast(this.bitfield, val, position)
54
54
  }
55
55
 
56
- count (start, length, val) {
56
+ count(start, length, val) {
57
57
  const end = start + length
58
58
 
59
59
  let i = start
@@ -76,18 +76,18 @@ class BitfieldPage {
76
76
  }
77
77
 
78
78
  class BitfieldSegment {
79
- constructor (index, bitfield) {
79
+ constructor(index, bitfield) {
80
80
  this.index = index
81
81
  this.offset = index * BYTES_PER_SEGMENT
82
82
  this.tree = quickbit.Index.from(bitfield, BYTES_PER_SEGMENT)
83
83
  this.pages = new Array(PAGES_PER_SEGMENT)
84
84
  }
85
85
 
86
- get bitfield () {
86
+ get bitfield() {
87
87
  return this.tree.field
88
88
  }
89
89
 
90
- add (page) {
90
+ add(page) {
91
91
  const i = page.index - this.index * PAGES_PER_SEGMENT
92
92
  this.pages[i] = page
93
93
 
@@ -99,7 +99,7 @@ class BitfieldSegment {
99
99
  page.bitfield = this.bitfield.subarray(start, end)
100
100
  }
101
101
 
102
- reallocate (length) {
102
+ reallocate(length) {
103
103
  let target = this.bitfield.length
104
104
  while (target < length) target *= SEGMENT_GROWTH_FACTOR
105
105
 
@@ -119,7 +119,7 @@ class BitfieldSegment {
119
119
  }
120
120
  }
121
121
 
122
- findFirst (val, position) {
122
+ findFirst(val, position) {
123
123
  position = this.tree.skipFirst(!val, position)
124
124
 
125
125
  let j = position & (BITS_PER_PAGE - 1)
@@ -144,7 +144,7 @@ class BitfieldSegment {
144
144
  return -1
145
145
  }
146
146
 
147
- findLast (val, position) {
147
+ findLast(val, position) {
148
148
  position = this.tree.skipLast(!val, position)
149
149
 
150
150
  let j = position & (BITS_PER_PAGE - 1)
@@ -174,22 +174,18 @@ module.exports = class Bitfield {
174
174
  static BITS_PER_PAGE = BITS_PER_PAGE
175
175
  static BYTES_PER_PAGE = BYTES_PER_PAGE
176
176
 
177
- constructor (buffer) {
177
+ constructor(buffer) {
178
178
  this.resumed = !!(buffer && buffer.byteLength >= 0)
179
179
 
180
180
  this._pages = new BigSparseArray()
181
181
  this._segments = new BigSparseArray()
182
182
 
183
183
  const view = this.resumed
184
- ? new Uint32Array(
185
- buffer.buffer,
186
- buffer.byteOffset,
187
- Math.floor(buffer.byteLength / 4)
188
- )
184
+ ? new Uint32Array(buffer.buffer, buffer.byteOffset, Math.floor(buffer.byteLength / 4))
189
185
  : new Uint32Array(INITIAL_WORDS_PER_SEGMENT)
190
186
 
191
187
  for (let i = 0; i < view.length; i += WORDS_PER_SEGMENT) {
192
- let bitfield = view.subarray(i, i + (WORDS_PER_SEGMENT))
188
+ let bitfield = view.subarray(i, i + WORDS_PER_SEGMENT)
193
189
  let length = WORDS_PER_SEGMENT
194
190
 
195
191
  if (i === 0) {
@@ -203,7 +199,7 @@ module.exports = class Bitfield {
203
199
  bitfield = copy
204
200
  }
205
201
 
206
- const segment = new BitfieldSegment(i / (WORDS_PER_SEGMENT), bitfield)
202
+ const segment = new BitfieldSegment(i / WORDS_PER_SEGMENT, bitfield)
207
203
  this._segments.set(segment.index, segment)
208
204
 
209
205
  for (let j = 0; j < bitfield.length; j += WORDS_PER_PAGE) {
@@ -213,11 +209,11 @@ module.exports = class Bitfield {
213
209
  }
214
210
  }
215
211
 
216
- static from (bitfield) {
212
+ static from(bitfield) {
217
213
  return new Bitfield(bitfield.toBuffer(bitfield._pages.maxLength * BITS_PER_PAGE))
218
214
  }
219
215
 
220
- toBuffer (length) {
216
+ toBuffer(length) {
221
217
  const pages = Math.ceil(length / BITS_PER_PAGE)
222
218
  const buffer = b4a.allocUnsafe(pages * BYTES_PER_PAGE)
223
219
 
@@ -241,14 +237,14 @@ module.exports = class Bitfield {
241
237
  return buffer
242
238
  }
243
239
 
244
- getBitfield (index) {
240
+ getBitfield(index) {
245
241
  const i = this.getPageIndex(index)
246
242
 
247
243
  const p = this._pages.get(i)
248
244
  return p || null
249
245
  }
250
246
 
251
- merge (bitfield, length) {
247
+ merge(bitfield, length) {
252
248
  let i = 0
253
249
 
254
250
  while (i < length) {
@@ -265,7 +261,7 @@ module.exports = class Bitfield {
265
261
  }
266
262
  }
267
263
 
268
- get (index) {
264
+ get(index) {
269
265
  const j = index & (BITS_PER_PAGE - 1)
270
266
  const i = (index - j) / BITS_PER_PAGE
271
267
 
@@ -274,16 +270,16 @@ module.exports = class Bitfield {
274
270
  return p ? p.get(j) : false
275
271
  }
276
272
 
277
- getPageByteLength () {
273
+ getPageByteLength() {
278
274
  return BYTES_PER_PAGE
279
275
  }
280
276
 
281
- getPageIndex (index) {
277
+ getPageIndex(index) {
282
278
  const j = index & (BITS_PER_PAGE - 1)
283
279
  return (index - j) / BITS_PER_PAGE
284
280
  }
285
281
 
286
- getPage (index, create) {
282
+ getPage(index, create) {
287
283
  const i = this.getPageIndex(index)
288
284
 
289
285
  let p = this._pages.get(i)
@@ -293,14 +289,22 @@ module.exports = class Bitfield {
293
289
  if (!create) return null
294
290
 
295
291
  const k = Math.floor(i / PAGES_PER_SEGMENT)
296
- const s = this._segments.get(k) || this._segments.set(k, new BitfieldSegment(k, new Uint32Array(k === 0 ? INITIAL_WORDS_PER_SEGMENT : WORDS_PER_SEGMENT)))
292
+ const s =
293
+ this._segments.get(k) ||
294
+ this._segments.set(
295
+ k,
296
+ new BitfieldSegment(
297
+ k,
298
+ new Uint32Array(k === 0 ? INITIAL_WORDS_PER_SEGMENT : WORDS_PER_SEGMENT)
299
+ )
300
+ )
297
301
 
298
302
  p = this._pages.set(i, new BitfieldPage(i, s))
299
303
 
300
304
  return p
301
305
  }
302
306
 
303
- set (index, val) {
307
+ set(index, val) {
304
308
  const j = index & (BITS_PER_PAGE - 1)
305
309
  const i = (index - j) / BITS_PER_PAGE
306
310
 
@@ -308,7 +312,15 @@ module.exports = class Bitfield {
308
312
 
309
313
  if (!p && val) {
310
314
  const k = Math.floor(i / PAGES_PER_SEGMENT)
311
- const s = this._segments.get(k) || this._segments.set(k, new BitfieldSegment(k, new Uint32Array(k === 0 ? INITIAL_WORDS_PER_SEGMENT : WORDS_PER_SEGMENT)))
315
+ const s =
316
+ this._segments.get(k) ||
317
+ this._segments.set(
318
+ k,
319
+ new BitfieldSegment(
320
+ k,
321
+ new Uint32Array(k === 0 ? INITIAL_WORDS_PER_SEGMENT : WORDS_PER_SEGMENT)
322
+ )
323
+ )
312
324
 
313
325
  p = this._pages.set(i, new BitfieldPage(i, s))
314
326
  }
@@ -316,7 +328,7 @@ module.exports = class Bitfield {
316
328
  if (p) p.set(j, val)
317
329
  }
318
330
 
319
- setRange (start, end, val) {
331
+ setRange(start, end, val) {
320
332
  let j = start & (BITS_PER_PAGE - 1)
321
333
  let i = (start - j) / BITS_PER_PAGE
322
334
 
@@ -325,7 +337,15 @@ module.exports = class Bitfield {
325
337
 
326
338
  if (!p && val) {
327
339
  const k = Math.floor(i / PAGES_PER_SEGMENT)
328
- const s = this._segments.get(k) || this._segments.set(k, new BitfieldSegment(k, new Uint32Array(k === 0 ? INITIAL_WORDS_PER_SEGMENT : WORDS_PER_SEGMENT)))
340
+ const s =
341
+ this._segments.get(k) ||
342
+ this._segments.set(
343
+ k,
344
+ new BitfieldSegment(
345
+ k,
346
+ new Uint32Array(k === 0 ? INITIAL_WORDS_PER_SEGMENT : WORDS_PER_SEGMENT)
347
+ )
348
+ )
329
349
 
330
350
  p = this._pages.set(i, new BitfieldPage(i, s))
331
351
  }
@@ -342,7 +362,7 @@ module.exports = class Bitfield {
342
362
  }
343
363
  }
344
364
 
345
- findFirst (val, position) {
365
+ findFirst(val, position) {
346
366
  let j = position & (BITS_PER_SEGMENT - 1)
347
367
  let i = (position - j) / BITS_PER_SEGMENT
348
368
 
@@ -363,15 +383,15 @@ module.exports = class Bitfield {
363
383
  return val ? -1 : this._segments.maxLength * BITS_PER_SEGMENT
364
384
  }
365
385
 
366
- firstSet (position) {
386
+ firstSet(position) {
367
387
  return this.findFirst(true, position)
368
388
  }
369
389
 
370
- firstUnset (position) {
390
+ firstUnset(position) {
371
391
  return this.findFirst(false, position)
372
392
  }
373
393
 
374
- findLast (val, position) {
394
+ findLast(val, position) {
375
395
  let j = position & (BITS_PER_SEGMENT - 1)
376
396
  let i = (position - j) / BITS_PER_SEGMENT
377
397
 
@@ -392,15 +412,15 @@ module.exports = class Bitfield {
392
412
  return -1
393
413
  }
394
414
 
395
- lastSet (position) {
415
+ lastSet(position) {
396
416
  return this.findLast(true, position)
397
417
  }
398
418
 
399
- lastUnset (position) {
419
+ lastUnset(position) {
400
420
  return this.findLast(false, position)
401
421
  }
402
422
 
403
- hasSet (start, length) {
423
+ hasSet(start, length) {
404
424
  const end = start + length
405
425
 
406
426
  let j = start & (BITS_PER_SEGMENT - 1)
@@ -413,7 +433,7 @@ module.exports = class Bitfield {
413
433
 
414
434
  if (s) index = s.findFirst(true, j)
415
435
 
416
- if (index !== -1) return (i * BITS_PER_SEGMENT + index) < end
436
+ if (index !== -1) return i * BITS_PER_SEGMENT + index < end
417
437
 
418
438
  j = 0
419
439
  i++
@@ -424,7 +444,7 @@ module.exports = class Bitfield {
424
444
  return false
425
445
  }
426
446
 
427
- count (start, length, val) {
447
+ count(start, length, val) {
428
448
  let j = start & (BITS_PER_PAGE - 1)
429
449
  let i = (start - j) / BITS_PER_PAGE
430
450
  let c = 0
@@ -446,15 +466,15 @@ module.exports = class Bitfield {
446
466
  return c
447
467
  }
448
468
 
449
- countSet (start, length) {
469
+ countSet(start, length) {
450
470
  return this.count(start, length, true)
451
471
  }
452
472
 
453
- countUnset (start, length) {
473
+ countUnset(start, length) {
454
474
  return this.count(start, length, false)
455
475
  }
456
476
 
457
- * want (start, length) {
477
+ *want(start, length) {
458
478
  const j = start & (BITS_PER_SEGMENT - 1)
459
479
  let i = (start - j) / BITS_PER_SEGMENT
460
480
 
@@ -477,22 +497,22 @@ module.exports = class Bitfield {
477
497
  }
478
498
  }
479
499
 
480
- clear (tx) {
500
+ clear(tx) {
481
501
  return tx.deleteBitfieldPageRange(0, -1)
482
502
  }
483
503
 
484
- onupdate (ranges) {
504
+ onupdate(ranges) {
485
505
  for (const { start, end, value } of ranges) {
486
506
  this.setRange(start, end, value)
487
507
  }
488
508
  }
489
509
 
490
- static async open (storage, length) {
510
+ static async open(storage, length) {
491
511
  if (length === 0) return new Bitfield(storage, null)
492
512
 
493
513
  const pages = Math.ceil(length / BITS_PER_PAGE)
494
514
  const buffer = b4a.alloc(pages * BYTES_PER_PAGE)
495
- const stream = storage.createBitfieldStream()
515
+ const stream = storage.createBitfieldStream({ lt: pages })
496
516
 
497
517
  for await (const { index, page } of stream) {
498
518
  buffer.set(page, index * BYTES_PER_PAGE)
@@ -502,11 +522,11 @@ module.exports = class Bitfield {
502
522
  }
503
523
  }
504
524
 
505
- function clamp (n, min, max) {
525
+ function clamp(n, min, max) {
506
526
  return Math.min(Math.max(n, min), max)
507
527
  }
508
528
 
509
- function ceilTo (n, multiple = 1) {
529
+ function ceilTo(n, multiple = 1) {
510
530
  const remainder = n % multiple
511
531
  if (remainder === 0) return n
512
532
  return n + multiple - remainder
package/lib/caps.js CHANGED
@@ -21,7 +21,11 @@ exports.DEFAULT_ENCRYPTION = DEFAULT_ENCRYPTION
21
21
 
22
22
  exports.replicate = function (isInitiator, key, handshakeHash) {
23
23
  const out = b4a.allocUnsafe(32)
24
- sodium.crypto_generichash_batch(out, [isInitiator ? REPLICATE_INITIATOR : REPLICATE_RESPONDER, key], handshakeHash)
24
+ sodium.crypto_generichash_batch(
25
+ out,
26
+ [isInitiator ? REPLICATE_INITIATOR : REPLICATE_RESPONDER, key],
27
+ handshakeHash
28
+ )
25
29
  return out
26
30
  }
27
31
 
@@ -11,7 +11,7 @@ const MIN_BATCH_USED = 512 * 1024
11
11
 
12
12
  module.exports = copyPrologue
13
13
 
14
- async function copyPrologue (src, dst) {
14
+ async function copyPrologue(src, dst) {
15
15
  const prologue = dst.header.manifest.prologue
16
16
 
17
17
  if (src.length < prologue.length || prologue.length === 0) return
@@ -29,7 +29,11 @@ async function copyPrologue (src, dst) {
29
29
  let lastPage = -1
30
30
  let lastBlock = -1
31
31
 
32
- for await (const data of src.storage.createBlockStream({ gte: 0, lt: prologue.length, reverse: true })) {
32
+ for await (const data of src.storage.createBlockStream({
33
+ gte: 0,
34
+ lt: prologue.length,
35
+ reverse: true
36
+ })) {
33
37
  if (walkTree(stack, data.index * 2, batch) === false) {
34
38
  throw new Error('Missing block or tree node for ' + data.index)
35
39
  }
@@ -44,7 +48,7 @@ async function copyPrologue (src, dst) {
44
48
  batch.used += Math.max(data.value.byteLength, 128) // 128 is just a sanity number to avoid mega batches
45
49
 
46
50
  // always safe to partially flush so we do that ondemand to reduce memory usage...
47
- if ((batch.used >= MIN_BATCH_USED && page !== lastPage) || (batch.used >= MAX_BATCH_USED)) {
51
+ if ((batch.used >= MIN_BATCH_USED && page !== lastPage) || batch.used >= MAX_BATCH_USED) {
48
52
  await flushBatch(prologue, src, dst, batch)
49
53
  }
50
54
 
@@ -57,7 +61,7 @@ async function copyPrologue (src, dst) {
57
61
  await flushBatch(prologue, src, dst, batch)
58
62
  }
59
63
 
60
- async function flushBatch (prologue, src, dst, batch) {
64
+ async function flushBatch(prologue, src, dst, batch) {
61
65
  const nodePromises = []
62
66
 
63
67
  const srcReader = src.storage.read()
@@ -183,7 +187,7 @@ async function flushBatch (prologue, src, dst, batch) {
183
187
  batch.used = 0
184
188
  }
185
189
 
186
- function signalReplicator (core, upgraded, start, length) {
190
+ function signalReplicator(core, upgraded, start, length) {
187
191
  if (upgraded) {
188
192
  core.replicator.cork()
189
193
  core.replicator.onhave(start, length, false)
@@ -194,7 +198,7 @@ function signalReplicator (core, upgraded, start, length) {
194
198
  }
195
199
  }
196
200
 
197
- function prologueToTree (prologue) {
201
+ function prologueToTree(prologue) {
198
202
  return {
199
203
  fork: 0,
200
204
  length: prologue.length,
@@ -203,15 +207,15 @@ function prologueToTree (prologue) {
203
207
  }
204
208
  }
205
209
 
206
- function getBitfieldPage (index) {
210
+ function getBitfieldPage(index) {
207
211
  return Math.floor(index / Bitfield.BITS_PER_PAGE)
208
212
  }
209
213
 
210
- function getBitfieldOffset (index) {
214
+ function getBitfieldOffset(index) {
211
215
  return index & (Bitfield.BITS_PER_PAGE - 1)
212
216
  }
213
217
 
214
- function walkTree (stack, target, batch) {
218
+ function walkTree(stack, target, batch) {
215
219
  while (stack.length > 0) {
216
220
  const node = stack.pop()
217
221
 
@@ -239,4 +243,4 @@ function walkTree (stack, target, batch) {
239
243
  return false
240
244
  }
241
245
 
242
- function noop () {}
246
+ function noop() {}