text: /*
   Hashbounds: Collision detection optimized 2d datastructure for usage in games
  
   Author: Andrews54757
   License: MIT (https://github.com/ThreeLetters/HashBounds/blob/master/LICENSE)
   Source: https://github.com/ThreeLetters/HashBounds
   Build: v5.0.3
   Built on: 24/09/2021
  */
  
  var TreeBucket=function(a,b,c){this.PARENT=void 0;this.CHILDREN=[void 0,void 0,void 0,void 0];this.BUCKET_SIZE=c;this.COUNTER=0;this.BUCKET_X=a;this.BUCKET_Y=b;this.X=a*c;this.Y=b*c;this.MAX_X=this.X+c;this.MAX_Y=this.Y+c;this.HALFX=this.X+c/2;this.HALFY=this.Y+c/2;this.QUAD_CACHE=[[],[],[],[],[],[],[],[],[]];this.ITEM_LIST=[]};
  TreeBucket.prototype.updateQuadCache=function(){var a=this;TreeBucket.QUADS.forEach(function(b,c){var d=[];a.QUAD_CACHE[c]=d;b.forEach(function(e){e=a.CHILDREN[e];void 0!==e&&d.push(e)})})};TreeBucket.prototype.add=function(){0===this.COUNTER&&void 0!==this.PARENT&&this.PARENT.add();++this.COUNTER};TreeBucket.prototype.subtract=function(){--this.COUNTER;0===this.COUNTER&&void 0!==this.PARENT&&this.PARENT.subtract()};
  TreeBucket.prototype.getQuad=function(a){if(1>=this.QUAD_CACHE[0].length)return 0;var b=a.minX,c=a.minY,d=a.maxX,e=a.maxY,h=this.X,f=this.Y,k=this.MAX_X,g=this.MAX_Y,l=this.HALFX,m=this.HALFY;return e<=m?d<=l?1:b>=l?2:5:c>=m?d<=l?3:b>=l?4:6:d<=l?7:b>=l?8:a.width<this.BUCKET_SIZE||a.height<this.BUCKET_SIZE||b>h||d<k||c>f||e<g?0:-1};TreeBucket.prototype._every=function(a,b){return this.ITEM_LIST.every(function(c){return c._HashBoundsTempCheck!==b?(c._HashBoundsTempCheck=b,a(c)):!0})};
  TreeBucket.prototype.every=function(a,b,c){if(0===this.COUNTER)return!0;var d=this.getQuad(a);return-1===d?this.everyAll(b,c):this._every(b,c)?this.QUAD_CACHE[d].every(function(e){return e.every(a,b,c)}):!1};TreeBucket.prototype.everyAll=function(a,b){return 0===this.COUNTER?!0:this._every(a,b)?this.QUAD_CACHE[0].every(function(c){return c.everyAll(a,b)}):!1};
  TreeBucket.prototype.remove=function(a,b){b=a.indexes[b];var c=this.ITEM_LIST.length-1;b!==c&&(a=(this.ITEM_LIST[b]=this.ITEM_LIST[c])._HashBounds[a.hashID],a.indexes[(this.BUCKET_X-a.k1x)*(a.k2y-a.k1y+1)+this.BUCKET_Y-a.k1y]=b);this.ITEM_LIST.pop();0===c&&this.subtract()};TreeBucket.prototype.set=function(a,b,c){var d=this.ITEM_LIST.length;b.indexes[c]=d;this.ITEM_LIST.push(a);0===d&&this.add()};TreeBucket.QUADS=[[0,1,2,3],[0],[1],[2],[3],[0,1],[2,3],[0,2],[1,3]];
  var HashGrid=function(a,b){this.BUCKETSIZE=a;this.BUCKETSIZE_INV=1/this.BUCKETSIZE;this.LEVEL=b;this.NEXT_GRID=this.PREV_GRID=void 0;this.BUCKET_GRID={}};HashGrid.prototype.initializeArea=function(a){var b=Math.ceil(a.maxX*this.BUCKETSIZE_INV),c=Math.ceil(a.maxY*this.BUCKETSIZE_INV),d=Math.floor(a.minY*this.BUCKETSIZE_INV);for(a=Math.floor(a.minX*this.BUCKETSIZE_INV);a<=b;++a)for(var e=d;e<=c;++e)this.createBucket(a,e)};
  HashGrid.prototype.deleteBucket=function(a,b){var c=this.BUCKET_GRID[a];delete c[b];0===Object.keys(c).length&&delete this.BUCKET_GRID[a]};HashGrid.prototype.setBucket=function(a,b,c){var d=this.BUCKET_GRID[a];void 0===d&&(d={},this.BUCKET_GRID[a]=d);d[b]=c};HashGrid.prototype.getBucket=function(a,b){a=this.BUCKET_GRID[a];return void 0===a?void 0:a[b]};
  HashGrid.prototype.createBucket=function(a,b){var c=new TreeBucket(a,b,this.BUCKETSIZE);this.setBucket(a,b,c);if(void 0!==this.NEXT_GRID){var d=Math.floor(a/2),e=Math.floor(b/2);a=2*(b-2*e)+a-2*d;b=this.NEXT_GRID.getBucket(d,e);void 0===b&&(b=this.NEXT_GRID.createBucket(d,e));c.PARENT=b;b.CHILDREN[a]=c;b.updateQuadCache()}return c};HashGrid.prototype.prune=function(){for(var a in this.BUCKET_GRID){var b=this.BUCKET_GRID[a],c;for(c in b){var d=b[c];0===d.COUNTER&&this.pruneBucket(d)}}};
  HashGrid.prototype.pruneBucket=function(a){void 0!==a.PARENT&&(0===a.PARENT.COUNTER?this.NEXT_GRID.pruneBucket(a.PARENT):(a.PARENT.CHILDREN[a.BUCKET_X%2*2+a.BUCKET_Y%2]=void 0,a.PARENT.updateQuadCache()));a.COUNTER=-1;this.deleteBucket(a.BUCKET_X,a.BUCKET_Y)};
  HashGrid.prototype.update=function(a,b,c){var d=Math.floor(b.minX*this.BUCKETSIZE_INV),e=Math.floor(b.minY*this.BUCKETSIZE_INV),h=Math.floor(b.maxX*this.BUCKETSIZE_INV),f=Math.floor(b.maxY*this.BUCKETSIZE_INV);return c.k1x!==d||c.k1y!==e||c.k2x!==h||c.k2y!==f?(this.remove(c),this.insert(a,b,c,d,e,h,f),!0):!1};
  HashGrid.prototype.insert=function(a,b,c,d,e,h,f){var k=b.minX,g=b.minY,l=b.maxX;b=b.maxY;void 0===d&&(d=Math.floor(k*this.BUCKETSIZE_INV),e=Math.floor(g*this.BUCKETSIZE_INV),h=Math.floor(l*this.BUCKETSIZE_INV),f=Math.floor(b*this.BUCKETSIZE_INV));c.k1x=d;c.k1y=e;c.k2x=h;c.k2y=f;k=f-e+1;for(g=d;g<=h;++g)for(l=(g-d)*k-e,b=e;b<=f;++b){var m=this.getBucket(g,b);void 0===m&&(m=this.createBucket(g,b));m.set(a,c,l+b)}};
  HashGrid.prototype.remove=function(a){for(var b=a.k1x,c=a.k1y,d=a.k2x,e=a.k2y,h=e-c+1,f=b;f<=d;++f)for(var k=(f-b)*h-c,g=c;g<=e;++g)this.getBucket(f,g).remove(a,k+g)};
  HashGrid.prototype.every=function(a,b,c){if(void 0===a){for(var d in this.BUCKET_GRID){a=this.BUCKET_GRID[d];for(var e in a)if(!a[e].everyAll(b,c))return!1}return!0}d=Math.floor(a.minY*this.BUCKETSIZE_INV);e=Math.floor(a.maxX*this.BUCKETSIZE_INV);for(var h=Math.floor(a.maxY*this.BUCKETSIZE_INV),f=Math.floor(a.minX*this.BUCKETSIZE_INV);f<=e;++f)for(var k=d;k<=h;++k){var g=this.getBucket(f,k);if(void 0!==g&&!g.every(a,b,c))return!1}return!0};
  var HashBounds=function(a,b,c,d){if(1>b)throw Error("Level count must be at least 1!");this.ID=void 0===d?HashBounds.LAST_ID++:d;this.MIN_SIZE=a;this.MIN_SIZE_INV=1/this.MIN_SIZE;this.LEVEL_COUNT=b;this.INITIAL_BOUNDS=c||{};HashBounds.convertBounds(this.INITIAL_BOUNDS);this.LEVELS=[];this.LOG2CACHE=this.BASE=void 0;this.QUERYID=0;this.setupLog2();this.init()};HashBounds.prototype.getQueryID=function(){4294967295<=this.QUERYID&&(this.QUERYID=-1,this.forEach(function(a){}));return this.QUERYID++};
  HashBounds.prototype.setupLog2=function(){var a=Math.pow(2,this.LEVEL_COUNT-2)+1;this.LOG2CACHE=new Uint8Array(a);for(var b=0;b<a;++b)this.LOG2CACHE[b]=Math.ceil(Math.log2(b))};
  HashBounds.prototype.createLevels=function(){for(var a=0;a<this.LEVEL_COUNT;a++)this.LEVELS[a]=new HashGrid(this.MIN_SIZE*Math.pow(2,a),a,this.INITIAL_BOUNDS);for(a=0;a<this.LEVEL_COUNT;a++)this.LEVELS[a].PREV_GRID=0<a?this.LEVELS[a-1]:void 0,this.LEVELS[a].NEXT_GRID=a<this.LEVEL_COUNT-1?this.LEVELS[a+1]:void 0;this.BASE=this.LEVELS[this.LEVEL_COUNT-1]};HashBounds.prototype.initializeArea=function(a){this.LEVELS[0].initializeArea(a)};HashBounds.prototype.init=function(){this.createLevels();this.initializeArea(this.INITIAL_BOUNDS)};
  HashBounds.prototype.clear=function(){this.LEVELS=[];this.ID=HashBounds.LAST_ID++;this.init()};HashBounds.prototype.prune=function(){this.LEVELS[0].prune()};HashBounds.prototype.update=function(a,b){if(!this.contains(a))throw Error("ERR: Entry is not in this hash!");HashBounds.convertBounds(b);var c=this.getHashCache(a),d=c.cachedIndex,e=this.getLevel(b,c);return d!==e?(this.LEVELS[d].remove(c),this.LEVELS[e].insert(a,b,c),!0):this.LEVELS[e].update(a,b,c)};
  HashBounds.prototype.getLevel=function(a,b){if(b.cacheWidth===a.width&&b.cacheHeight===a.height)return b.cachedIndex;var c=Math.ceil(Math.max(a.width,a.height)*this.MIN_SIZE_INV);c=c>=this.LOG2CACHE.length?this.LEVEL_COUNT-1:this.LOG2CACHE[c];b.cachedIndex=c;b.cacheWidth=a.width;b.cacheHeight=a.height;return c};
  HashBounds.prototype.insert=function(a,b){if(this.contains(a))throw Error("ERR: An entry cannot be already in this hash!");void 0===a._HashBounds&&(a._HashBounds={});void 0===a._HashBounds[this.ID]&&(a._HashBounds[this.ID]={k1x:0,k1y:0,k2x:0,k2y:0,indexes:[0,0,0,0],cachedIndex:0,cacheWidth:0,cacheHeight:0,hashID:this.ID,isInHash:!1},a._HashBoundsTempCheck=-1);HashBounds.convertBounds(b);var c=this.getHashCache(a);c.isInHash=!0;this.LEVELS[this.getLevel(b,c)].insert(a,b,c)};
  HashBounds.prototype.remove=function(a){if(!this.contains(a))throw Error("ERR: Entry is not in this hash!");a=this.getHashCache(a);this.LEVELS[a.cachedIndex].remove(a);a.isInHash=!1};HashBounds.prototype.contains=function(a){return void 0!==a._HashBounds&&void 0!==a._HashBounds[this.ID]&&a._HashBounds[this.ID].isInHash};HashBounds.prototype.getHashCache=function(a){return a._HashBounds[this.ID]};
  HashBounds.prototype.toArray=function(a){void 0!==a&&HashBounds.convertBounds(a);var b=[];this.BASE.every(a,function(c){b.push(c);return!0},this.getQueryID());return b};HashBounds.prototype.every=function(a,b){void 0===b?(b=a,a=void 0):void 0!==a&&HashBounds.convertBounds(a);return this.BASE.every(a,b,this.getQueryID())};HashBounds.prototype.forEach=function(a,b){void 0===b?(b=a,a=void 0):void 0!==a&&HashBounds.convertBounds(a);this.BASE.every(a,function(c){b(c);return!0},this.getQueryID())};
  HashBounds.prototype.boundsFitsInHash=function(a){HashBounds.convertBounds(a);return HashBounds.boundsContains(a,this.INITIAL_BOUNDS)};HashBounds.LAST_ID=0;HashBounds.mmToPS=function(a){a.x=a.minX;a.y=a.minY;a.width=a.maxX-a.minX;a.height=a.maxY-a.minY};HashBounds.psToMM=function(a){a.minX=a.x;a.minY=a.y;a.maxX=a.x+a.width;a.maxY=a.y+a.height};HashBounds.boundsOverlap=function(a,b){return!(a.minX>b.maxX||a.minY>b.maxY||a.maxX<b.minX||a.maxY<b.minY)};
  HashBounds.boundsContains=function(a,b){return a.minX>=b.minX&&a.maxX<=b.maxX&&a.minY>=b.minY&&a.maxY<=b.maxY};
  HashBounds.truncateBounds=function(a,b,c,d,e){if(1===a.TYPE)a.x=Math.max(a.x,b),a.y=Math.max(a.y,c),a.x+a.width>d&&(a.width=d-a.x),a.y+a.height>e&&(a.height=e-a.y);else if(2===a.TYPE)a.minX=Math.max(a.minX,b),a.minY=Math.max(a.minY,c),a.maxX=Math.min(a.maxX,d),a.maxY=Math.min(a.maxY,e);else throw Error("ERR: Bound not formatted! Please make sure bounds were put through the convertBounds function");};
  HashBounds.convertBounds=function(a){if(void 0===a.TYPE)void 0!==a.x?(HashBounds.psToMM(a),a.TYPE=1):(HashBounds.mmToPS(a),a.TYPE=2);else if(1===a.TYPE)HashBounds.psToMM(a);else if(2===a.TYPE)HashBounds.mmToPS(a);else throw Error("Invalid bounds!");};
  