Latest Threat Research:SANDWORM_MODE: Shai-Hulud-Style npm Worm Hijacks CI Workflows and Poisons AI Toolchains.Details
Socket
Book a DemoInstallSign in
Socket

chain-lightning

Package Overview
Dependencies
Maintainers
1
Versions
12
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

chain-lightning - npm Package Compare versions

Comparing version
0.3.0
to
0.4.0
+368
-165
lib/BinaryTree.js

@@ -31,2 +31,6 @@ /*

const arrayKit = require( 'array-kit' ) ;
/*

@@ -44,3 +48,3 @@ For balancing, it uses the AVL algorithm.

this.keyFn = options && options.keyFn ;
this.uniqueKeys = !! ( options && options.uniqueKeys ) ;
this.stack = !! ( options && options.stack ) ;

@@ -73,4 +77,3 @@ if ( ! this.keyFn ) {

function Node( tree , key , element , parent = null ) {
this.tree = tree ;
function Node( key , element , parent = null ) {
this.key = key ;

@@ -88,6 +91,11 @@ this.element = element ;

class Stack extends Array {}
BinaryTree.Stack = Stack ;
// /!\ DEPRECATED? .truncate*() does not call it /!\
// Used when a node is deleted
// Does it help garbage collection?
BinaryTree.prototype.destroyNode = function( node ) {
node.tree = null ;
node.key = null ;

@@ -112,6 +120,15 @@ node.element = null ;

BinaryTree.prototype.values = function *() {
var current = this.getHeadNode() ;
var element ,
current = this.getHeadNode() ;
while ( current ) {
yield current.element ;
if ( current.element instanceof Stack ) {
for ( element of current.element ) {
yield element ;
}
}
else {
yield current.element ;
}
current = this.nextNode( current ) ;

@@ -237,5 +254,6 @@ }

// Set: replace existing element
BinaryTree.prototype.set = function( key , element , noOverwrite ) {
if ( ! this.trunc ) {
this.trunc = new Node( this , key , element ) ;
this.trunc = new Node( key , element ) ;
this.length ++ ;

@@ -254,10 +272,9 @@ return ;

if ( this.uniqueKeys ) {
node.element = element ;
return ;
}
node.element = element ;
return ;
}
// No uniqueKey? So insert it after
if ( this.isOrdered( node.key , key ) ) {
if ( ! node.right ) {
node.right = new Node( this , key , element , node ) ;
node.right = new Node( key , element , node ) ;
this.length ++ ;

@@ -270,6 +287,45 @@ this.rebalance( node , true ) ;

}
else {
if ( ! node.left ) {
node.left = new Node( key , element , node ) ;
this.length ++ ;
this.rebalance( node , true ) ;
return ;
}
node = node.left ;
}
}
} ;
// Add: stack element if there is one already existing.
// If .stack is false, fallback to .set()
BinaryTree.prototype.add = function( key , element ) {
if ( ! this.stack ) { return this.set( key , element ) ; }
if ( ! this.trunc ) {
this.trunc = new Node( key , element ) ;
this.length ++ ;
return ;
}
var node = this.trunc ;
for ( ;; ) {
if ( key === node.key ) {
if ( node.element instanceof Stack ) {
node.element.push( element ) ;
}
else {
node.element = new Stack( node.element , element ) ;
}
return ;
}
if ( this.isOrdered( node.key , key ) ) {
if ( ! node.right ) {
node.right = new Node( this , key , element , node ) ;
node.right = new Node( key , element , node ) ;
this.length ++ ;

@@ -284,3 +340,3 @@ this.rebalance( node , true ) ;

if ( ! node.left ) {
node.left = new Node( this , key , element , node ) ;
node.left = new Node( key , element , node ) ;
this.length ++ ;

@@ -298,3 +354,3 @@ this.rebalance( node , true ) ;

BinaryTree.prototype.insert = function( ... elements ) {
BinaryTree.prototype.insertUnique = function( ... elements ) {
elements.forEach( element => this.set( this.keyFn( element ) , element , true ) ) ;

@@ -305,3 +361,10 @@ } ;

// Divide and conquer algo, to avoid rotation when all elements are in the correct order
BinaryTree.prototype.insert = function( ... elements ) {
elements.forEach( element => this.add( this.keyFn( element ) , element ) ) ;
} ;
// Divide and conquer algo, to avoid rotation when all elements are in the correct order.
// Each one should be unique.
BinaryTree.prototype.insertOrdered = function( ... elements ) {

@@ -359,2 +422,58 @@ var start , end , middle , diff , listIndex ,

if ( node.left && node.right ) {
// Ok, both node exist... it's the complicated case,
// Find a replacerNode.
// Note that the replacer has only one child, since it's either the min or the max of the subtree.
/* OLD
// Swap node's element, it's easier and faster, but it's also bad because the node could be referenced somewhere else,
// so breaking the node-element relationship may cause really nasty bugs.
// .inPlaceFilter() have had a bug because of this (it stored the .nextNode() before calling .deleteNode()).
// Choose the heavier child
if ( node.left.depth >= node.right.depth ) {
// We will use the left subtree, the replacer is the maximum of this sub-tree
replacerNode = this.getMaxNode( node.left ) ;
}
else {
// We will use the right subtree, the replacer is the minimum of this sub-tree
replacerNode = this.getMinNode( node.right ) ;
}
// Copy key/value...
node.key = replacerNode.key ;
node.element = replacerNode.element ;
// ... and just delete the replacer using .deleteNode()
this.deleteNode( replacerNode ) ;
//*/
//* NEW
// Swap node's place in the tree. It's way more complicated and a bit slower, but it's safer because
// it doesn't break the node-element relationship.
// Choose the heavier child
if ( node.left.depth >= node.right.depth ) {
// We will use the left subtree, the replacer is the maximum of this sub-tree
replacerNode = this.getMaxNode( node.left ) ;
}
else {
// We will use the right subtree, the replacer is the minimum of this sub-tree
replacerNode = this.getMinNode( node.right ) ;
}
this.swapNodes( node , replacerNode ) ;
// Copy key/value...
node.key = replacerNode.key ;
// We would like to try to delete it again using .deleteNode().
// But since it would branch in the "simple" case (because of .getMaxNode()/.getMinNode()),
// we can continue to the rest of this function.
//return this.deleteNode( replacerNode ) ;
//*/
}
parent = node.parent ;

@@ -372,34 +491,8 @@

if ( node.left ) {
if ( node.right ) {
// Ok, both node exist... it's the complicated case,
// Find a replacerNode, copy its key and value in the current node,
// and delete the replacer instead of this one.
// Note that the replacer has only one child, since it's either the min or the max of the subtree.
// Choose the heavier child
if ( node.left.depth >= node.right.depth ) {
// We will use the left subtree, the replacer is the maximum of this sub-tree
replacerNode = this.getMaxNode( node.left ) ;
}
else {
// We will use the right subtree, the replacer is the minimum of this sub-tree
replacerNode = this.getMinNode( node.right ) ;
}
// Copy key/value...
node.key = replacerNode.key ;
node.element = replacerNode.element ;
// ... and just delete the replacer using .deleteNode()
this.deleteNode( replacerNode ) ;
}
else {
// Only a left child, attach its subtree to the parent
referer[ refererProp ] = node.left ;
node.left.parent = parent ;
this.length -- ;
this.rebalance( node , true ) ;
this.destroyNode( node ) ;
}
// Only a left child, attach its subtree to the parent
referer[ refererProp ] = node.left ;
node.left.parent = parent ;
this.length -- ;
this.rebalance( node , true ) ;
this.destroyNode( node ) ;
}

@@ -426,3 +519,3 @@ else if ( node.right ) {

BinaryTree.prototype.truncateBefore = function( key , including ) {
var lastTruncatedNode = this.getClosestNode( key , ! including , -1 ) ;
var lastTruncatedNode = this.getClosestNode( key , including , -1 ) ;
//var firstKeptNode = this.nextNode( lastTruncatedNode ) ;

@@ -509,3 +602,3 @@

BinaryTree.prototype.truncateAfter = function( key , including ) {
var firstTruncatedNode = this.getClosestNode( key , ! including , 1 ) ;
var firstTruncatedNode = this.getClosestNode( key , including , 1 ) ;
//var firstKeptNode = this.nextNode( firstTruncatedNode ) ;

@@ -592,2 +685,48 @@

/*
Advanced custom features
*/
// Delete all occurences of a value
BinaryTree.prototype.deleteValue =
BinaryTree.prototype.removeValue = function( value ) {
this.inPlaceFilter( e => ! isIdenticalTo( e , value ) ) ;
} ;
BinaryTree.prototype.inPlaceFilter = function( fn , thisArg ) {
var current = this.getHeadNode() ,
next ;
while ( current ) {
if ( current.element instanceof Stack ) {
arrayKit.inPlaceFilter( current.element , fn , thisArg , current.key ) ;
if ( current.element.length ) {
current = this.nextNode( current ) ;
}
else {
next = this.nextNode( current ) ;
this.deleteNode( current ) ;
current = next ;
}
}
else if ( fn.call( thisArg , current.element , current.key , this ) ) {
current = this.nextNode( current ) ;
}
else {
next = this.nextNode( current ) ;
this.deleteNode( current ) ;
current = next ;
}
}
return this ;
} ;
/*
Advanced Array-like features

@@ -606,7 +745,11 @@ */

BinaryTree.prototype.keyOf = function( element , fromKey ) {
BinaryTree.prototype.keyOf = function( searchElement , fromKey ) {
var current = fromKey ? this.getNode( fromKey ) : this.getHeadNode() ;
while ( current ) {
if ( isIdenticalTo( current.element , element ) ) { return current.key ; }
if ( current.element instanceof Stack ) {
if ( current.element.includes( searchElement ) ) { return current.key ; }
}
else if ( isIdenticalTo( current.element , searchElement ) ) { return current.key ; }
current = this.nextNode( current ) ;

@@ -620,7 +763,11 @@ }

BinaryTree.prototype.lastKeyOf = function( element , fromKey ) {
BinaryTree.prototype.lastKeyOf = function( searchElement , fromKey ) {
var current = fromKey ? this.getNode( fromKey ) : this.getTailNode() ;
while ( current ) {
if ( isIdenticalTo( current.element , element ) ) { return current.key ; }
if ( current.element instanceof Stack ) {
if ( current.element.includes( searchElement ) ) { return current.key ; }
}
else if ( isIdenticalTo( current.element , searchElement ) ) { return current.key ; }
current = this.previousNode( current ) ;

@@ -634,14 +781,13 @@ }

BinaryTree.prototype.includes = function( element ) {
if ( ! this.trunc ) { return false ; }
return this._recursiveIncludes( element , this.trunc ) ;
} ;
BinaryTree.prototype.includes = function( searchElement , current = this.trunc ) {
if ( ! current ) { return false ; }
if ( current.element instanceof Stack ) {
if ( current.element.includes( searchElement ) ) { return true ; }
}
else if ( isIdenticalTo( current.element , searchElement ) ) {
return true ;
}
BinaryTree.prototype._recursiveIncludes = function( element , current ) {
if ( isIdenticalTo( current.element , element ) ) { return true ; }
if ( current.left && this._recursiveIncludes( element , current.left ) ) { return true ; }
if ( current.right && this._recursiveIncludes( element , current.right ) ) { return true ; }
return false ;
return this.includes( searchElement , current.left ) || this.includes( searchElement , current.right ) ;
} ;

@@ -652,6 +798,15 @@

BinaryTree.prototype.forEach = function( fn , thisArg ) {
var current = this.getHeadNode() ;
var element ,
current = this.getHeadNode() ;
while ( current ) {
fn.call( thisArg , current.element , current.key , this ) ;
if ( current.element instanceof Stack ) {
for ( element of current.element ) {
fn.call( thisArg , element , current.key , this ) ;
}
}
else {
fn.call( thisArg , current.element , current.key , this ) ;
}
current = this.nextNode( current ) ;

@@ -664,6 +819,15 @@ }

BinaryTree.prototype.some = function( fn , thisArg ) {
var current = this.getHeadNode() ;
var element ,
current = this.getHeadNode() ;
while ( current ) {
if ( fn.call( thisArg , current.element , current.key , this ) ) { return true ; }
if ( current.element instanceof Stack ) {
for ( element of current.element ) {
if ( fn.call( thisArg , element , current.key , this ) ) { return true ; }
}
}
else if ( fn.call( thisArg , current.element , current.key , this ) ) {
return true ;
}
current = this.nextNode( current ) ;

@@ -678,6 +842,15 @@ }

BinaryTree.prototype.every = function( fn , thisArg ) {
var current = this.getHeadNode() ;
var element ,
current = this.getHeadNode() ;
while ( current ) {
if ( ! fn.call( thisArg , current.element , current.key , this ) ) { return false ; }
if ( current.element instanceof Stack ) {
for ( element of current.element ) {
if ( ! fn.call( thisArg , element , current.key , this ) ) { return false ; }
}
}
else if ( ! fn.call( thisArg , current.element , current.key , this ) ) {
return false ;
}
current = this.nextNode( current ) ;

@@ -692,6 +865,12 @@ }

BinaryTree.prototype.find = function( fn , thisArg ) {
var current = this.getHeadNode() ;
var element ,
current = this.getHeadNode() ;
while ( current ) {
if ( fn.call( thisArg , current.element , current.key , this ) ) {
if ( current.element instanceof Stack ) {
for ( element of current.element ) {
if ( fn.call( thisArg , element , current.key , this ) ) { return element ; }
}
}
else if ( fn.call( thisArg , current.element , current.key , this ) ) {
return current.element ;

@@ -709,6 +888,12 @@ }

BinaryTree.prototype.findKey = function( fn , thisArg ) {
var current = this.getHeadNode() ;
var element ,
current = this.getHeadNode() ;
while ( current ) {
if ( fn.call( thisArg , current.element , current.key , this ) ) {
if ( current.element instanceof Stack ) {
for ( element of current.element ) {
if ( fn.call( thisArg , element , current.key , this ) ) { return current.key ; }
}
}
else if ( fn.call( thisArg , current.element , current.key , this ) ) {
return current.key ;

@@ -728,8 +913,16 @@ }

BinaryTree.prototype.map = function( fn , thisArg ) {
var array = new Array( this.length ) ,
index = 0 ,
var element , index = 0 ,
array = new Array( this.length ) ,
current = this.getHeadNode() ;
while ( current ) {
array[ index ++ ] = fn.call( thisArg , current.element , current.key , this ) ;
if ( current.element instanceof Stack ) {
for ( element of current.element ) {
array[ index ++ ] = fn.call( thisArg , element , current.key , this ) ;
}
}
else {
array[ index ++ ] = fn.call( thisArg , current.element , current.key , this ) ;
}
current = this.nextNode( current ) ;

@@ -744,6 +937,15 @@ }

BinaryTree.prototype.reduce = function( fn , accumulator ) {
var current = this.getHeadNode() ;
var element ,
current = this.getHeadNode() ;
while ( current ) {
accumulator = fn( accumulator , current.element , current.key , this ) ;
if ( current.element instanceof Stack ) {
for ( element of current.element ) {
accumulator = fn( accumulator , element , current.key , this ) ;
}
}
else {
accumulator = fn( accumulator , current.element , current.key , this ) ;
}
current = this.nextNode( current ) ;

@@ -758,6 +960,18 @@ }

BinaryTree.prototype.reduceRight = function( fn , accumulator ) {
var current = this.getTailNode() ;
var index , element ,
current = this.getTailNode() ;
while ( current ) {
accumulator = fn( accumulator , current.element , current.key , this ) ;
if ( current.element instanceof Stack ) {
// Not sure if it makes sense to call it backward, since it's not backward at all...
index = current.element.length ;
while ( index -- ) {
element = current.element[ index ] ;
accumulator = fn( accumulator , element , current.key , this ) ;
}
}
else {
accumulator = fn( accumulator , current.element , current.key , this ) ;
}
current = this.previousNode( current ) ;

@@ -774,8 +988,12 @@ }

BinaryTree.prototype.filter = function( fn , thisArg ) {
var array = [] ,
index = 0 ,
var element , index = 0 , array = [] ,
current = this.getHeadNode() ;
while ( current ) {
if ( fn.call( thisArg , current.element , current.key , this ) ) {
if ( current.element instanceof Stack ) {
for ( element of current.element ) {
if ( fn.call( thisArg , element , current.key , this ) ) { array[ index ++ ] = element ; }
}
}
else if ( fn.call( thisArg , current.element , current.key , this ) ) {
array[ index ++ ] = current.element ;

@@ -793,36 +1011,2 @@ }

/*
Advanced custom features
*/
// Delete all occurences of a value
BinaryTree.prototype.deleteValue =
BinaryTree.prototype.removeValue = function( value ) {
this.inPlaceFilter( e => ! isIdenticalTo( e , value ) ) ;
} ;
BinaryTree.prototype.inPlaceFilter = function( fn , thisArg ) {
var current = this.getHeadNode() ,
next ;
while ( current ) {
if ( fn.call( thisArg , current.element , current.key , this ) ) {
current = this.nextNode( current ) ;
}
else {
next = this.nextNode( current ) ;
this.deleteNode( current ) ;
current = next ;
}
}
return this ;
} ;
/*
Internal, low-level

@@ -1033,4 +1217,4 @@ */

/*
excluding: exclude the current key
direction: how to choose a node for a non uniqueKeys tree or when excluding the key:
including: include the current key if it exists
direction: how to choose a node when excluding the key:
* unset: don't care

@@ -1040,3 +1224,3 @@ * 1: forward direction, choose the left-most node

*/
BinaryTree.prototype.getClosestNode = function( key , excluding , direction ) {
BinaryTree.prototype.getClosestNode = function( key , including , direction ) {
if ( ! this.trunc ) { return null ; }

@@ -1052,41 +1236,5 @@

if ( node.key === key ) {
if ( excluding ) {
if ( this.uniqueKeys ) {
if ( direction > 0 ) { return this.nextNode( node ) ; }
return this.previousNode( node ) ;
}
if ( direction > 0 ) {
do {
node = this.nextNode( node ) ;
} while ( node && node.key === key ) ;
return node ;
}
do {
node = this.previousNode( node ) ;
} while ( node && node.key === key ) ;
return node ;
}
else if ( this.uniqueKeys ) {
return node ;
}
else if ( direction > 0 ) {
if ( ! node.left || node.left.key !== key ) { return node ; }
lastRightAncestor = lastNode = node ;
lastDirection = -1 ;
node = node.left ;
}
else { // if ( direction < 0 ) {
if ( ! node.right || node.right.key !== key ) { return node ; }
lastLeftAncestor = lastNode = node ;
lastDirection = 1 ;
node = node.right ;
}
if ( including ) { return node ; }
if ( direction > 0 ) { return this.nextNode( node ) ; }
return this.previousNode( node ) ;
}

@@ -1120,2 +1268,51 @@ else if ( this.isOrdered( node.key , key ) ) {

// .deleteNode() uses it
BinaryTree.prototype.swapNodes = function( a , b ) {
var aParent = a.parent ,
bParent = b.parent ,
aLeft = a.left ,
bLeft = b.left ,
aRight = a.right ,
bRight = b.right ,
aDepth = a.depth ,
bDepth = b.depth ;
// Swap nodes' refs
a.parent = bParent !== a ? bParent : b ;
b.parent = aParent !== b ? aParent : a ;
a.left = bLeft !== a ? bLeft : b ;
b.left = aLeft !== b ? aLeft : a ;
a.right = bRight !== a ? bRight : b ;
b.right = aRight !== b ? aRight : a ;
a.depth = bDepth ;
b.depth = aDepth ;
// Swap parents' refs
if ( bParent ) {
if ( bParent !== a ) { bParent[ b === bParent.left ? 'left' : 'right' ] = a ; }
}
else {
this.trunc = a ;
}
if ( aParent ) {
if ( aParent !== b ) { aParent[ a === aParent.left ? 'left' : 'right' ] = b ; }
}
else {
this.trunc = b ;
}
// Fix children's refs
if ( a.left ) { a.left.parent = a ; }
if ( a.right ) { a.right.parent = a ; }
if ( b.left ) { b.left.parent = b ; }
if ( b.right ) { b.right.parent = b ; }
} ;
// DEPRECATED?

@@ -1153,3 +1350,5 @@ // Delete subtree without re-balancing

BinaryTree.prototype.debug = function( node = this.trunc , spaces = 0 , prefix = '━' ) {
const util = require( 'util' ) ;
BinaryTree.prototype.debug = function( node = this.trunc , spaces = 0 , prefix = '━' , showValue = false ) {
if ( ! node ) {

@@ -1167,4 +1366,8 @@ console.log( '(empty)' ) ;

if ( showValue ) {
str += ' => ' + util.inspect( node.element ) ;
}
if ( node.right ) {
this.debug( node.right , nextSpaces , '┏' ) ;
this.debug( node.right , nextSpaces , '┏' , showValue ) ;
}

@@ -1175,6 +1378,7 @@

if ( node.left ) {
this.debug( node.left , nextSpaces , '┗' ) ;
this.debug( node.left , nextSpaces , '┗' , showValue ) ;
}
} ;
BinaryTree.prototype.debugValues = function() { return this.debug( this.trunc , 0 , '━' , true ) ; } ;

@@ -1209,3 +1413,2 @@

assert.strictEqual( node.tree , this , "Current node doesn't belong to the current tree, key: " + node.key ) ;
assert.strictEqual( node.parent , parentNode , "Parent mismatch, key: " + node.key ) ;

@@ -1212,0 +1415,0 @@

{
"name": "chain-lightning",
"version": "0.3.0",
"version": "0.4.0",
"description": "Linked list",

@@ -12,3 +12,5 @@ "main": "lib/chainlightning.js",

},
"dependencies": {},
"dependencies": {
"array-kit": "^0.2.2"
},
"scripts": {

@@ -44,2 +46,2 @@ "test": "tea-time -R dot -O"

}
}
}

@@ -87,3 +87,3 @@ /*

tree = new BinaryTree() ;
tree = new BinaryTree( { stack: true } ) ;

@@ -102,5 +102,6 @@ tree.set( 3 , 'jack' ) ;

tree.set( 2.77 , 'vlad' ) ;
expect( [ ... tree ] ).to.equal( [ 'jean' , 'john' , 'robert' , 'tom' , 'boris' , 'roger' , 'vlad' , 'johnson' , 'carl' , 'jack' , 'steve' , 'bobby' ] ) ;
tree.add( 6 , 'bob' ) ;
expect( [ ... tree ] ).to.equal( [ 'jean' , 'john' , 'robert' , 'tom' , 'boris' , 'roger' , 'vlad' , 'johnson' , 'carl' , 'jack' , 'steve' , 'bobby' , 'bob' ] ) ;
expect( tree.keys() ).to.equal( [ 2 , 2.5 , 2.7 , 2.72 , 2.75 , 2.76 , 2.77 , 2.8 , 2.85 , 3 , 5 , 6 ] ) ;
expect( [ ... tree.values() ] ).to.equal( [ 'jean' , 'john' , 'robert' , 'tom' , 'boris' , 'roger' , 'vlad' , 'johnson' , 'carl' , 'jack' , 'steve' , 'bobby' ] ) ;
expect( [ ... tree.values() ] ).to.equal( [ 'jean' , 'john' , 'robert' , 'tom' , 'boris' , 'roger' , 'vlad' , 'johnson' , 'carl' , 'jack' , 'steve' , 'bobby' , 'bob' ] ) ;
} ) ;

@@ -177,28 +178,56 @@

it( "duplicated keys and the 'uniqueKeys' option" , () => {
it( "add and get elements in conjunction with the 'stack' option" , () => {
var tree ;
tree = new BinaryTree() ;
tree = new BinaryTree( { stack: true } ) ;
// Without uniqueKeys
tree.set( 2 , 'jean' ) ;
tree.set( 3 , 'jack' ) ;
// Try getting unexisting keys
expect( tree.get( 0 ) ).to.be( undefined ) ;
expect( tree.get( 9 ) ).to.be( undefined ) ;
tree.add( 3 , 'jack' ) ;
expect( [ ... tree ] ).to.equal( [ 'jack' ] ) ;
tree.sanityCheck() ;
tree.add( 2 , 'jean' ) ;
expect( [ ... tree ] ).to.equal( [ 'jean' , 'jack' ] ) ;
expect( [ ... tree.keys() ] ).to.equal( [ 2 , 3 ] ) ;
tree.sanityCheck() ;
tree.set( 2 , 'bob' ) ;
expect( [ ... tree ] ).to.equal( [ 'jean' , 'bob' , 'jack' ] ) ;
expect( [ ... tree.keys() ] ).to.equal( [ 2 , 2 , 3 ] ) ;
tree.add( 5 , 'steve' ) ;
expect( [ ... tree ] ).to.equal( [ 'jean' , 'jack' , 'steve' ] ) ;
tree.sanityCheck() ;
// With uniqueKeys
tree = new BinaryTree( { uniqueKeys: true } ) ;
tree.set( 2 , 'jean' ) ;
tree.set( 3 , 'jack' ) ;
tree.set( 2 , 'bob' ) ;
expect( [ ... tree ] ).to.equal( [ 'bob' , 'jack' ] ) ;
expect( [ ... tree.keys() ] ).to.equal( [ 2 , 3 ] ) ;
tree.add( 2.5 , 'john' ) ;
expect( [ ... tree ] ).to.equal( [ 'jean' , 'john' , 'jack' , 'steve' ] ) ;
tree.sanityCheck() ;
tree.add( 2.7 , 'robert' ) ;
expect( [ ... tree ] ).to.equal( [ 'jean' , 'john' , 'robert' , 'jack' , 'steve' ] ) ;
tree.sanityCheck() ;
tree.add( 3 , 'bobby' ) ;
expect( [ ... tree ] ).to.be.like( [ 'jean' , 'john' , 'robert' , 'jack' , 'bobby' , 'steve' ] ) ;
tree.sanityCheck() ;
tree.add( 2 , 'jeanjean' ) ;
expect( [ ... tree ] ).to.be.like( [ 'jean' , 'jeanjean' , 'john' , 'robert' , 'jack' , 'bobby' , 'steve' ] ) ;
tree.sanityCheck() ;
tree.add( 2 , 'jeanjeanjean' ) ;
expect( [ ... tree ] ).to.be.like( [ 'jean' , 'jeanjean' , 'jeanjeanjean' , 'john' , 'robert' , 'jack' , 'bobby' , 'steve' ] ) ;
tree.sanityCheck() ;
//tree.debug() ;
expect( tree.get( 3 ) ).to.be.a( BinaryTree.Stack ) ;
expect( tree.get( 3 ) ).to.be.like( [ 'jack' , 'bobby' ] ) ;
expect( tree.get( 2 ) ).to.be.a( BinaryTree.Stack ) ;
expect( tree.get( 2 ) ).to.be.like( [ 'jean' , 'jeanjean' , 'jeanjeanjean' ] ) ;
expect( tree.get( 5 ) ).to.be( 'steve' ) ;
expect( tree.get( 2.5 ) ).to.be( 'john' ) ;
expect( tree.get( 2.7 ) ).to.be( 'robert' ) ;
// Try getting unexisting keys
expect( tree.get( 0 ) ).to.be( undefined ) ;
expect( tree.get( 9 ) ).to.be( undefined ) ;
} ) ;

@@ -223,3 +252,5 @@

} ) ;
it( ".insertUnique()" ) ;
it( "delete by key" , () => {

@@ -301,3 +332,3 @@ var tree ;

tree = new BinaryTree( { uniqueKeys: true } , e1 , e2 , e3 ) ;
tree = new BinaryTree( null , e1 , e2 , e3 ) ;
expect( tree.keyOf( e2 ) ).to.be( 1 ) ;

@@ -311,2 +342,20 @@ expect( tree.keyOf( e4 ) ).to.be( undefined ) ;

expect( [ ... tree ] ).to.equal( [ { v: 'jack' } , { v: 'bobby' } , { v: 'steve' } , { v: 'bob' } , { v: 'bob' } , { v: 'bobby' } ] ) ;
// Stack
tree = new BinaryTree( { stack: true } ) ;
tree.add( 2 , e1 ) ;
tree.add( 2 , e2 ) ;
tree.add( 2.5 , e3 ) ;
tree.add( 4 , e1 ) ;
tree.add( 4 , e2 ) ;
tree.add( 4.5 , e3 ) ;
expect( tree.keyOf( e1 ) ).to.be( 2 ) ;
expect( tree.keyOf( e2 ) ).to.be( 2 ) ;
expect( tree.keyOf( e3 ) ).to.be( 2.5 ) ;
expect( tree.keyOf( e4 ) ).to.be( undefined ) ;
expect( tree.lastKeyOf( e1 ) ).to.be( 4 ) ;
expect( tree.lastKeyOf( e2 ) ).to.be( 4 ) ;
expect( tree.lastKeyOf( e3 ) ).to.be( 4.5 ) ;
expect( tree.lastKeyOf( e4 ) ).to.be( undefined ) ;
} ) ;

@@ -318,3 +367,4 @@

e2 = { v: 'bob' } ,
e3 = { v: 'steve' } ;
e3 = { v: 'steve' } ,
e4 = { v: 'bobby' } ;

@@ -344,7 +394,17 @@ tree = new BinaryTree() ;

expect( tree.includes( e2 ) ).to.be.true() ;
// Stack
tree = new BinaryTree( { stack: true } ) ;
tree.add( 2 , e1 ) ;
tree.add( 2 , e2 ) ;
tree.add( 2.5 , e3 ) ;
expect( tree.includes( e1 ) ).to.be.true() ;
expect( tree.includes( e2 ) ).to.be.true() ;
expect( tree.includes( e3 ) ).to.be.true() ;
expect( tree.includes( e4 ) ).to.be.false() ;
} ) ;
it( ".forEach()" , () => {
var tree ,
accumulator = [] ,
var tree , values , keys ,
e1 = { v: 'jack' } ,

@@ -354,9 +414,26 @@ e2 = { v: 'bob' } ,

keys = [] ;
values = [] ;
tree = new BinaryTree() ;
tree.forEach( element => accumulator.push( element.v ) ) ;
expect( accumulator ).to.equal( [] ) ;
tree.forEach( element => values.push( element.v ) ) ;
expect( values ).to.equal( [] ) ;
keys = [] ;
values = [] ;
tree = new BinaryTree( null , e1 , e2 , e3 ) ;
tree.forEach( element => accumulator.push( element.v ) ) ;
expect( accumulator ).to.equal( [ 'jack' , 'bob' , 'steve' ] ) ;
tree.forEach( element => values.push( element.v ) ) ;
expect( values ).to.equal( [ 'jack' , 'bob' , 'steve' ] ) ;
keys = [] ;
values = [] ;
tree = new BinaryTree( { stack: true } ) ;
tree.add( 2 , e1 ) ;
tree.add( 2 , e2 ) ;
tree.add( 2.5 , e3 ) ;
tree.add( 2.5 , e3 ) ;
tree.add( 2.5 , e1 ) ;
tree.add( 2.2 , e2 ) ;
tree.forEach( ( element , key ) => { keys.push( key ) ; values.push( element.v ) ; } ) ;
expect( keys ).to.equal( [ 2 , 2 , 2.2 , 2.5 , 2.5 , 2.5 ] ) ;
expect( values ).to.equal( [ 'jack' , 'bob' , 'bob' , 'steve' , 'steve' , 'jack' ] ) ;
} ) ;

@@ -401,2 +478,22 @@

expect( tree.every( element => element.v === 'bob' ) ).to.be.true() ;
// Stack
tree = new BinaryTree( { stack: true } ) ;
tree.add( 2 , e2 ) ;
tree.add( 2.5 , e2 ) ;
tree.add( 2.5 , e2 ) ;
expect( tree.some( element => element.v === 'jack' ) ).to.be.false() ;
expect( tree.every( element => element.v === 'jack' ) ).to.be.false() ;
expect( tree.some( element => element.v === 'bob' ) ).to.be.true() ;
expect( tree.every( element => element.v === 'bob' ) ).to.be.true() ;
expect( tree.some( element => element.v === 'steve' ) ).to.be.false() ;
expect( tree.every( element => element.v === 'steve' ) ).to.be.false() ;
tree.add( 2 , e1 ) ;
expect( tree.some( element => element.v === 'jack' ) ).to.be.true() ;
expect( tree.every( element => element.v === 'jack' ) ).to.be.false() ;
expect( tree.some( element => element.v === 'bob' ) ).to.be.true() ;
expect( tree.every( element => element.v === 'bob' ) ).to.be.false() ;
expect( tree.some( element => element.v === 'steve' ) ).to.be.false() ;
expect( tree.every( element => element.v === 'steve' ) ).to.be.false() ;
} ) ;

@@ -420,2 +517,13 @@

expect( tree.find( element => element.v === 'bob' ) ).to.be( e4 ) ;
// Stack
tree = new BinaryTree( { stack: true } ) ;
tree.add( 2 , e2 ) ;
tree.add( 2.5 , e2 ) ;
tree.add( 2.5 , e2 ) ;
tree.add( 1 , e1 ) ;
expect( tree.find( element => element.v === 'jack' ) ).to.be( e1 ) ;
expect( tree.find( element => element.v === 'bob' ) ).to.be( e2 ) ;
expect( tree.find( element => element.v === 'steve' ) ).to.be( undefined ) ;
} ) ;

@@ -440,6 +548,17 @@

expect( tree.findKey( element => element.v === 'bob' ) ).to.be( 3 ) ;
// Stack
tree = new BinaryTree( { stack: true } ) ;
tree.add( 2 , e2 ) ;
tree.add( 2.5 , e2 ) ;
tree.add( 2.5 , e2 ) ;
tree.add( 1 , e1 ) ;
expect( tree.findKey( element => element.v === 'jack' ) ).to.be( 1 ) ;
expect( tree.findKey( element => element.v === 'bob' ) ).to.be( 2 ) ;
expect( tree.findKey( element => element.v === 'steve' ) ).to.be( undefined ) ;
} ) ;
it( ".arrayMap()" , () => {
var array ,
it( ".map() (or alias .arrayMap())" , () => {
var tree , array ,
e1 = { v: 'jack' } ,

@@ -449,3 +568,3 @@ e2 = { v: 'bob' } ,

array = new BinaryTree( null ).arrayMap( element => element.v + element.v ) ;
array = new BinaryTree( null ).map( element => element.v + element.v ) ;
expect( array ).to.equal( [] ) ;

@@ -458,2 +577,12 @@

expect( array ).to.equal( [ 'jackjack' , 'bobbob' , 'stevesteve' ] ) ;
// Stack
tree = new BinaryTree( { stack: true } ) ;
tree.add( 2 , e2 ) ;
tree.add( 2.5 , e3 ) ;
tree.add( 2.5 , e2 ) ;
tree.add( 1 , e1 ) ;
array = tree.map( element => element.v + element.v ) ;
expect( array ).to.equal( [ 'jackjack' , 'bobbob' , 'stevesteve' , 'bobbob' ] ) ;
} ) ;

@@ -478,6 +607,16 @@

expect( tree.reduceRight( ( accumulator , element ) => accumulator + element.v , '' ) ).to.equal( 'stevebobjack' ) ;
// Stack
tree = new BinaryTree( { stack: true } ) ;
tree.add( 2 , e2 ) ;
tree.add( 2.5 , e3 ) ;
tree.add( 2.5 , e2 ) ;
tree.add( 1 , e1 ) ;
expect( tree.reduce( ( accumulator , element ) => accumulator + element.v , '' ) ).to.equal( 'jackbobstevebob' ) ;
expect( tree.reduceRight( ( accumulator , element ) => accumulator + element.v , '' ) ).to.equal( 'bobstevebobjack' ) ;
} ) ;
it( ".arrayFilter()" , () => {
var array ,
it( ".filter() (or alias .arrayFilter())" , () => {
var tree , array ,
e1 = { v: 'jack' } ,

@@ -507,2 +646,14 @@ e2 = { v: 'bob' } ,

expect( array ).to.equal( [ e2 ] ) ;
// Stack
tree = new BinaryTree( { stack: true } ) ;
tree.add( 2 , e2 ) ;
tree.add( 2.5 , e3 ) ;
tree.add( 2.5 , e2 ) ;
tree.add( 1 , e1 ) ;
expect( tree.filter( element => element.v.length < 4 ) ).to.equal( [ e2 , e2 ] ) ;
expect( tree.filter( element => element.v.length > 4 ) ).to.equal( [ e3 ] ) ;
expect( tree.filter( element => element.v.length <= 4 ) ).to.equal( [ e1 , e2 , e2 ] ) ;
expect( tree.filter( element => element.v.length >= 4 ) ).to.equal( [ e1 , e3 ] ) ;
} ) ;

@@ -513,3 +664,3 @@ } ) ;

it( ".deleteValue()" , () => {
it( ".deleteValue() (and alias .removeValue())" , () => {
var tree ,

@@ -557,2 +708,19 @@ e1 = { v: 'jack' } ,

tree.sanityCheck() ;
// Stacked values
tree = new BinaryTree( { stack: true } ) ;
tree.add( 1 , e1 ) ;
tree.add( 1 , e4 ) ;
tree.add( 2 , e1 ) ;
tree.add( 3 , e2 ) ;
tree.add( 3 , e1 ) ;
tree.add( 3 , e3 ) ;
tree.add( 4 , e4 ) ;
//tree.debugValues() ;
expect( [ ... tree ] ).to.equal( [ e1 , e4 , e1 , e2 , e1 , e3 , e4 ] ) ;
tree.deleteValue( e1 ) ;
//tree.debugValues() ;
expect( [ ... tree ] ).to.equal( [ e4 , e2 , e3 , e4 ] ) ;
tree.sanityCheck() ;
} ) ;

@@ -996,38 +1164,64 @@

// Including existing
expect( tree.getClosestNode( 2 , false , -1 ).key ).to.be( 2 ) ;
expect( tree.getClosestNode( 2 , false , 1 ).key ).to.be( 2 ) ;
expect( tree.getClosestNode( 2.72 , false , -1 ).key ).to.be( 2.72 ) ;
expect( tree.getClosestNode( 2.72 , false , 1 ).key ).to.be( 2.72 ) ;
expect( tree.getClosestNode( 2.8 , false , -1 ).key ).to.be( 2.8 ) ;
expect( tree.getClosestNode( 2.8 , false , 1 ).key ).to.be( 2.8 ) ;
expect( tree.getClosestNode( 2.85 , false , -1 ).key ).to.be( 2.85 ) ;
expect( tree.getClosestNode( 2.85 , false , 1 ).key ).to.be( 2.85 ) ;
expect( tree.getClosestNode( 6 , false , -1 ).key ).to.be( 6 ) ;
expect( tree.getClosestNode( 6 , false , 1 ).key ).to.be( 6 ) ;
expect( tree.getClosestNode( 2 , true , -1 ).key ).to.be( 2 ) ;
expect( tree.getClosestNode( 2 , true , 1 ).key ).to.be( 2 ) ;
expect( tree.getClosestNode( 2.72 , true , -1 ).key ).to.be( 2.72 ) ;
expect( tree.getClosestNode( 2.72 , true , 1 ).key ).to.be( 2.72 ) ;
expect( tree.getClosestNode( 2.8 , true , -1 ).key ).to.be( 2.8 ) ;
expect( tree.getClosestNode( 2.8 , true , 1 ).key ).to.be( 2.8 ) ;
expect( tree.getClosestNode( 2.85 , true , -1 ).key ).to.be( 2.85 ) ;
expect( tree.getClosestNode( 2.85 , true , 1 ).key ).to.be( 2.85 ) ;
expect( tree.getClosestNode( 6 , true , -1 ).key ).to.be( 6 ) ;
expect( tree.getClosestNode( 6 , true , 1 ).key ).to.be( 6 ) ;
// Excluding existing
expect( tree.getClosestNode( 2 , true , -1 ) ).to.be( null ) ;
expect( tree.getClosestNode( 2 , true , 1 ).key ).to.be( 2.5 ) ;
expect( tree.getClosestNode( 2.5 , true , -1 ).key ).to.be( 2 ) ;
expect( tree.getClosestNode( 2.5 , true , 1 ).key ).to.be( 2.7 ) ;
expect( tree.getClosestNode( 2.7 , true , -1 ).key ).to.be( 2.5 ) ;
expect( tree.getClosestNode( 2.7 , true , 1 ).key ).to.be( 2.72 ) ;
expect( tree.getClosestNode( 2.72 , true , -1 ).key ).to.be( 2.7 ) ;
expect( tree.getClosestNode( 2.72 , true , 1 ).key ).to.be( 2.75 ) ;
expect( tree.getClosestNode( 2.75 , true , -1 ).key ).to.be( 2.72 ) ;
expect( tree.getClosestNode( 2.75 , true , 1 ).key ).to.be( 2.76 ) ;
expect( tree.getClosestNode( 2.76 , true , -1 ).key ).to.be( 2.75 ) ;
expect( tree.getClosestNode( 2.76 , true , 1 ).key ).to.be( 2.77 ) ;
expect( tree.getClosestNode( 2.77 , true , -1 ).key ).to.be( 2.76 ) ;
expect( tree.getClosestNode( 2.77 , true , 1 ).key ).to.be( 2.8 ) ;
expect( tree.getClosestNode( 2.8 , true , -1 ).key ).to.be( 2.77 ) ;
expect( tree.getClosestNode( 2.8 , true , 1 ).key ).to.be( 2.85 ) ;
expect( tree.getClosestNode( 2.85 , true , -1 ).key ).to.be( 2.8 ) ;
expect( tree.getClosestNode( 2.85 , true , 1 ).key ).to.be( 3 ) ;
expect( tree.getClosestNode( 3 , true , -1 ).key ).to.be( 2.85 ) ;
expect( tree.getClosestNode( 3 , true , 1 ).key ).to.be( 5 ) ;
expect( tree.getClosestNode( 6 , true , -1 ).key ).to.be( 5 ) ;
expect( tree.getClosestNode( 6 , true , 1 ) ).to.be( null ) ;
expect( tree.getClosestNode( 2 , false , -1 ) ).to.be( null ) ;
expect( tree.getClosestNode( 2 , false , 1 ).key ).to.be( 2.5 ) ;
expect( tree.getClosestNode( 2.5 , false , -1 ).key ).to.be( 2 ) ;
expect( tree.getClosestNode( 2.5 , false , 1 ).key ).to.be( 2.7 ) ;
expect( tree.getClosestNode( 2.7 , false , -1 ).key ).to.be( 2.5 ) ;
expect( tree.getClosestNode( 2.7 , false , 1 ).key ).to.be( 2.72 ) ;
expect( tree.getClosestNode( 2.72 , false , -1 ).key ).to.be( 2.7 ) ;
expect( tree.getClosestNode( 2.72 , false , 1 ).key ).to.be( 2.75 ) ;
expect( tree.getClosestNode( 2.75 , false , -1 ).key ).to.be( 2.72 ) ;
expect( tree.getClosestNode( 2.75 , false , 1 ).key ).to.be( 2.76 ) ;
expect( tree.getClosestNode( 2.76 , false , -1 ).key ).to.be( 2.75 ) ;
expect( tree.getClosestNode( 2.76 , false , 1 ).key ).to.be( 2.77 ) ;
expect( tree.getClosestNode( 2.77 , false , -1 ).key ).to.be( 2.76 ) ;
expect( tree.getClosestNode( 2.77 , false , 1 ).key ).to.be( 2.8 ) ;
expect( tree.getClosestNode( 2.8 , false , -1 ).key ).to.be( 2.77 ) ;
expect( tree.getClosestNode( 2.8 , false , 1 ).key ).to.be( 2.85 ) ;
expect( tree.getClosestNode( 2.85 , false , -1 ).key ).to.be( 2.8 ) ;
expect( tree.getClosestNode( 2.85 , false , 1 ).key ).to.be( 3 ) ;
expect( tree.getClosestNode( 3 , false , -1 ).key ).to.be( 2.85 ) ;
expect( tree.getClosestNode( 3 , false , 1 ).key ).to.be( 5 ) ;
expect( tree.getClosestNode( 6 , false , -1 ).key ).to.be( 5 ) ;
expect( tree.getClosestNode( 6 , false , 1 ) ).to.be( null ) ;
// Including unexisting
expect( tree.getClosestNode( 1 , true , -1 ) ).to.be( null ) ;
expect( tree.getClosestNode( 1 , true , 1 ).key ).to.be( 2 ) ;
expect( tree.getClosestNode( 2.1 , true , -1 ).key ).to.be( 2 ) ;
expect( tree.getClosestNode( 2.1 , true , 1 ).key ).to.be( 2.5 ) ;
expect( tree.getClosestNode( 2.6 , true , -1 ).key ).to.be( 2.5 ) ;
expect( tree.getClosestNode( 2.6 , true , 1 ).key ).to.be( 2.7 ) ;
expect( tree.getClosestNode( 2.71 , true , -1 ).key ).to.be( 2.7 ) ;
expect( tree.getClosestNode( 2.71 , true , 1 ).key ).to.be( 2.72 ) ;
expect( tree.getClosestNode( 2.73 , true , -1 ).key ).to.be( 2.72 ) ;
expect( tree.getClosestNode( 2.73 , true , 1 ).key ).to.be( 2.75 ) ;
expect( tree.getClosestNode( 2.755 , true , -1 ).key ).to.be( 2.75 ) ;
expect( tree.getClosestNode( 2.755 , true , 1 ).key ).to.be( 2.76 ) ;
expect( tree.getClosestNode( 2.765 , true , -1 ).key ).to.be( 2.76 ) ;
expect( tree.getClosestNode( 2.765 , true , 1 ).key ).to.be( 2.77 ) ;
expect( tree.getClosestNode( 2.78 , true , -1 ).key ).to.be( 2.77 ) ;
expect( tree.getClosestNode( 2.78 , true , 1 ).key ).to.be( 2.8 ) ;
expect( tree.getClosestNode( 2.84 , true , -1 ).key ).to.be( 2.8 ) ;
expect( tree.getClosestNode( 2.84 , true , 1 ).key ).to.be( 2.85 ) ;
expect( tree.getClosestNode( 2.9 , true , -1 ).key ).to.be( 2.85 ) ;
expect( tree.getClosestNode( 2.9 , true , 1 ).key ).to.be( 3 ) ;
expect( tree.getClosestNode( 4 , true , -1 ).key ).to.be( 3 ) ;
expect( tree.getClosestNode( 4 , true , 1 ).key ).to.be( 5 ) ;
expect( tree.getClosestNode( 7 , true , -1 ).key ).to.be( 6 ) ;
expect( tree.getClosestNode( 7 , true , 1 ) ).to.be( null ) ;
// Excluding unexisting -- should be identical to 'including unexisting'
expect( tree.getClosestNode( 1 , false , -1 ) ).to.be( null ) ;

@@ -1057,28 +1251,2 @@ expect( tree.getClosestNode( 1 , false , 1 ).key ).to.be( 2 ) ;

expect( tree.getClosestNode( 7 , false , 1 ) ).to.be( null ) ;
// Excluding unexisting -- should be identical to 'including unexisting'
expect( tree.getClosestNode( 1 , true , -1 ) ).to.be( null ) ;
expect( tree.getClosestNode( 1 , true , 1 ).key ).to.be( 2 ) ;
expect( tree.getClosestNode( 2.1 , true , -1 ).key ).to.be( 2 ) ;
expect( tree.getClosestNode( 2.1 , true , 1 ).key ).to.be( 2.5 ) ;
expect( tree.getClosestNode( 2.6 , true , -1 ).key ).to.be( 2.5 ) ;
expect( tree.getClosestNode( 2.6 , true , 1 ).key ).to.be( 2.7 ) ;
expect( tree.getClosestNode( 2.71 , true , -1 ).key ).to.be( 2.7 ) ;
expect( tree.getClosestNode( 2.71 , true , 1 ).key ).to.be( 2.72 ) ;
expect( tree.getClosestNode( 2.73 , true , -1 ).key ).to.be( 2.72 ) ;
expect( tree.getClosestNode( 2.73 , true , 1 ).key ).to.be( 2.75 ) ;
expect( tree.getClosestNode( 2.755 , true , -1 ).key ).to.be( 2.75 ) ;
expect( tree.getClosestNode( 2.755 , true , 1 ).key ).to.be( 2.76 ) ;
expect( tree.getClosestNode( 2.765 , true , -1 ).key ).to.be( 2.76 ) ;
expect( tree.getClosestNode( 2.765 , true , 1 ).key ).to.be( 2.77 ) ;
expect( tree.getClosestNode( 2.78 , true , -1 ).key ).to.be( 2.77 ) ;
expect( tree.getClosestNode( 2.78 , true , 1 ).key ).to.be( 2.8 ) ;
expect( tree.getClosestNode( 2.84 , true , -1 ).key ).to.be( 2.8 ) ;
expect( tree.getClosestNode( 2.84 , true , 1 ).key ).to.be( 2.85 ) ;
expect( tree.getClosestNode( 2.9 , true , -1 ).key ).to.be( 2.85 ) ;
expect( tree.getClosestNode( 2.9 , true , 1 ).key ).to.be( 3 ) ;
expect( tree.getClosestNode( 4 , true , -1 ).key ).to.be( 3 ) ;
expect( tree.getClosestNode( 4 , true , 1 ).key ).to.be( 5 ) ;
expect( tree.getClosestNode( 7 , true , -1 ).key ).to.be( 6 ) ;
expect( tree.getClosestNode( 7 , true , 1 ) ).to.be( null ) ;
} ) ;

@@ -1085,0 +1253,0 @@ } ) ;