text: 'use strict';
  
  var Long = require('../long').Long,
    Double = require('../double').Double,
    Timestamp = require('../timestamp').Timestamp,
    ObjectID = require('../objectid').ObjectID,
    Symbol = require('../symbol').Symbol,
    Code = require('../code').Code,
    MinKey = require('../min_key').MinKey,
    MaxKey = require('../max_key').MaxKey,
    Decimal128 = require('../decimal128'),
    Int32 = require('../int_32'),
    DBRef = require('../db_ref').DBRef,
    BSONRegExp = require('../regexp').BSONRegExp,
    Binary = require('../binary').Binary;
  
  var utils = require('./utils');
  
  var deserialize = function(buffer, options, isArray) {
    options = options == null ? {} : options;
    var index = options && options.index ? options.index : 0;
    // Read the document size
    var size =
      buffer[index] |
      (buffer[index + 1] << 8) |
      (buffer[index + 2] << 16) |
      (buffer[index + 3] << 24);
  
    // Ensure buffer is valid size
    if (size < 5 || buffer.length < size || size + index > buffer.length) {
      throw new Error('corrupt bson message');
    }
  
    // Illegal end value
    if (buffer[index + size - 1] !== 0) {
      throw new Error("One object, sized correctly, with a spot for an EOO, but the EOO isn't 0x00");
    }
  
    // Start deserializtion
    return deserializeObject(buffer, index, options, isArray);
  };
  
  var deserializeObject = function(buffer, index, options, isArray) {
    var evalFunctions = options['evalFunctions'] == null ? false : options['evalFunctions'];
    var cacheFunctions = options['cacheFunctions'] == null ? false : options['cacheFunctions'];
    var cacheFunctionsCrc32 =
      options['cacheFunctionsCrc32'] == null ? false : options['cacheFunctionsCrc32'];
  
    if (!cacheFunctionsCrc32) var crc32 = null;
  
    var fieldsAsRaw = options['fieldsAsRaw'] == null ? null : options['fieldsAsRaw'];
  
    // Return raw bson buffer instead of parsing it
    var raw = options['raw'] == null ? false : options['raw'];
  
    // Return BSONRegExp objects instead of native regular expressions
    var bsonRegExp = typeof options['bsonRegExp'] === 'boolean' ? options['bsonRegExp'] : false;
  
    // Controls the promotion of values vs wrapper classes
    var promoteBuffers = options['promoteBuffers'] == null ? false : options['promoteBuffers'];
    var promoteLongs = options['promoteLongs'] == null ? true : options['promoteLongs'];
    var promoteValues = options['promoteValues'] == null ? true : options['promoteValues'];
  
    // Set the start index
    var startIndex = index;
  
    // Validate that we have at least 4 bytes of buffer
    if (buffer.length < 5) throw new Error('corrupt bson message < 5 bytes long');
  
    // Read the document size
    var size =
      buffer[index++] | (buffer[index++] << 8) | (buffer[index++] << 16) | (buffer[index++] << 24);
  
    // Ensure buffer is valid size
    if (size < 5 || size > buffer.length) throw new Error('corrupt bson message');
  
    // Create holding object
    var object = isArray ? [] : {};
    // Used for arrays to skip having to perform utf8 decoding
    var arrayIndex = 0;
  
    var done = false;
  
    // While we have more left data left keep parsing
    // while (buffer[index + 1] !== 0) {
    while (!done) {
      // Read the type
      var elementType = buffer[index++];
      // If we get a zero it's the last byte, exit
      if (elementType === 0) break;
  
      // Get the start search index
      var i = index;
      // Locate the end of the c string
      while (buffer[i] !== 0x00 && i < buffer.length) {
        i++;
      }
  
      // If are at the end of the buffer there is a problem with the document
      if (i >= buffer.length) throw new Error('Bad BSON Document: illegal CString');
      var name = isArray ? arrayIndex++ : buffer.toString('utf8', index, i);
  
      index = i + 1;
  
      if (elementType === BSON.BSON_DATA_STRING) {
        var stringSize =
          buffer[index++] |
          (buffer[index++] << 8) |
          (buffer[index++] << 16) |
          (buffer[index++] << 24);
        if (
          stringSize <= 0 ||
          stringSize > buffer.length - index ||
          buffer[index + stringSize - 1] !== 0
        )
          throw new Error('bad string length in bson');
        object[name] = buffer.toString('utf8', index, index + stringSize - 1);
        index = index + stringSize;
      } else if (elementType === BSON.BSON_DATA_OID) {
        var oid = utils.allocBuffer(12);
        buffer.copy(oid, 0, index, index + 12);
        object[name] = new ObjectID(oid);
        index = index + 12;
      } else if (elementType === BSON.BSON_DATA_INT && promoteValues === false) {
        object[name] = new Int32(
          buffer[index++] | (buffer[index++] << 8) | (buffer[index++] << 16) | (buffer[index++] << 24)
        );
      } else if (elementType === BSON.BSON_DATA_INT) {
        object[name] =
          buffer[index++] |
          (buffer[index++] << 8) |
          (buffer[index++] << 16) |
          (buffer[index++] << 24);
      } else if (elementType === BSON.BSON_DATA_NUMBER && promoteValues === false) {
        object[name] = new Double(buffer.readDoubleLE(index));
        index = index + 8;
      } else if (elementType === BSON.BSON_DATA_NUMBER) {
        object[name] = buffer.readDoubleLE(index);
        index = index + 8;
      } else if (elementType === BSON.BSON_DATA_DATE) {
        var lowBits =
          buffer[index++] |
          (buffer[index++] << 8) |
          (buffer[index++] << 16) |
          (buffer[index++] << 24);
        var highBits =
          buffer[index++] |
          (buffer[index++] << 8) |
          (buffer[index++] << 16) |
          (buffer[index++] << 24);
        object[name] = new Date(new Long(lowBits, highBits).toNumber());
      } else if (elementType === BSON.BSON_DATA_BOOLEAN) {
        if (buffer[index] !== 0 && buffer[index] !== 1) throw new Error('illegal boolean type value');
        object[name] = buffer[index++] === 1;
      } else if (elementType === BSON.BSON_DATA_OBJECT) {
        var _index = index;
        var objectSize =
          buffer[index] |
          (buffer[index + 1] << 8) |
          (buffer[index + 2] << 16) |
          (buffer[index + 3] << 24);
        if (objectSize <= 0 || objectSize > buffer.length - index)
          throw new Error('bad embedded document length in bson');
  
        // We have a raw value
        if (raw) {
          object[name] = buffer.slice(index, index + objectSize);
        } else {
          object[name] = deserializeObject(buffer, _index, options, false);
        }
  
        index = index + objectSize;
      } else if (elementType === BSON.BSON_DATA_ARRAY) {
        _index = index;
        objectSize =
          buffer[index] |
          (buffer[index + 1] << 8) |
          (buffer[index + 2] << 16) |
          (buffer[index + 3] << 24);
        var arrayOptions = options;
  
        // Stop index
        var stopIndex = index + objectSize;
  
        // All elements of array to be returned as raw bson
        if (fieldsAsRaw && fieldsAsRaw[name]) {
          arrayOptions = {};
          for (var n in options) arrayOptions[n] = options[n];
          arrayOptions['raw'] = true;
        }
  
        object[name] = deserializeObject(buffer, _index, arrayOptions, true);
        index = index + objectSize;
  
        if (buffer[index - 1] !== 0) throw new Error('invalid array terminator byte');
        if (index !== stopIndex) throw new Error('corrupted array bson');
      } else if (elementType === BSON.BSON_DATA_UNDEFINED) {
        object[name] = undefined;
      } else if (elementType === BSON.BSON_DATA_NULL) {
        object[name] = null;
      } else if (elementType === BSON.BSON_DATA_LONG) {
        // Unpack the low and high bits
        lowBits =
          buffer[index++] |
          (buffer[index++] << 8) |
          (buffer[index++] << 16) |
          (buffer[index++] << 24);
        highBits =
          buffer[index++] |
          (buffer[index++] << 8) |
          (buffer[index++] << 16) |
          (buffer[index++] << 24);
        var long = new Long(lowBits, highBits);
        // Promote the long if possible
        if (promoteLongs && promoteValues === true) {
          object[name] =
            long.lessThanOrEqual(JS_INT_MAX_LONG) && long.greaterThanOrEqual(JS_INT_MIN_LONG)
              ? long.toNumber()
              : long;
        } else {
          object[name] = long;
        }
      } else if (elementType === BSON.BSON_DATA_DECIMAL128) {
        // Buffer to contain the decimal bytes
        var bytes = utils.allocBuffer(16);
        // Copy the next 16 bytes into the bytes buffer
        buffer.copy(bytes, 0, index, index + 16);
        // Update index
        index = index + 16;
        // Assign the new Decimal128 value
        var decimal128 = new Decimal128(bytes);
        // If we have an alternative mapper use that
        object[name] = decimal128.toObject ? decimal128.toObject() : decimal128;
      } else if (elementType === BSON.BSON_DATA_BINARY) {
        var binarySize =
          buffer[index++] |
          (buffer[index++] << 8) |
          (buffer[index++] << 16) |
          (buffer[index++] << 24);
        var totalBinarySize = binarySize;
        var subType = buffer[index++];
  
        // Did we have a negative binary size, throw
        if (binarySize < 0) throw new Error('Negative binary type element size found');
  
        // Is the length longer than the document
        if (binarySize > buffer.length) throw new Error('Binary type size larger than document size');
  
        // Decode as raw Buffer object if options specifies it
        if (buffer['slice'] != null) {
          // If we have subtype 2 skip the 4 bytes for the size
          if (subType === Binary.SUBTYPE_BYTE_ARRAY) {
            binarySize =
              buffer[index++] |
              (buffer[index++] << 8) |
              (buffer[index++] << 16) |
              (buffer[index++] << 24);
            if (binarySize < 0)
              throw new Error('Negative binary type element size found for subtype 0x02');
            if (binarySize > totalBinarySize - 4)
              throw new Error('Binary type with subtype 0x02 contains to long binary size');
            if (binarySize < totalBinarySize - 4)
              throw new Error('Binary type with subtype 0x02 contains to short binary size');
          }
  
          if (promoteBuffers && promoteValues) {
            object[name] = buffer.slice(index, index + binarySize);
          } else {
            object[name] = new Binary(buffer.slice(index, index + binarySize), subType);
          }
        } else {
          var _buffer =
            typeof Uint8Array !== 'undefined'
              ? new Uint8Array(new ArrayBuffer(binarySize))
              : new Array(binarySize);
          // If we have subtype 2 skip the 4 bytes for the size
          if (subType === Binary.SUBTYPE_BYTE_ARRAY) {
            binarySize =
              buffer[index++] |
              (buffer[index++] << 8) |
              (buffer[index++] << 16) |
              (buffer[index++] << 24);
            if (binarySize < 0)
              throw new Error('Negative binary type element size found for subtype 0x02');
            if (binarySize > totalBinarySize - 4)
              throw new Error('Binary type with subtype 0x02 contains to long binary size');
            if (binarySize < totalBinarySize - 4)
              throw new Error('Binary type with subtype 0x02 contains to short binary size');
          }
  
          // Copy the data
          for (i = 0; i < binarySize; i++) {
            _buffer[i] = buffer[index + i];
          }
  
          if (promoteBuffers && promoteValues) {
            object[name] = _buffer;
          } else {
            object[name] = new Binary(_buffer, subType);
          }
        }
  
        // Update the index
        index = index + binarySize;
      } else if (elementType === BSON.BSON_DATA_REGEXP && bsonRegExp === false) {
        // Get the start search index
        i = index;
        // Locate the end of the c string
        while (buffer[i] !== 0x00 && i < buffer.length) {
          i++;
        }
        // If are at the end of the buffer there is a problem with the document
        if (i >= buffer.length) throw new Error('Bad BSON Document: illegal CString');
        // Return the C string
        var source = buffer.toString('utf8', index, i);
        // Create the regexp
        index = i + 1;
  
        // Get the start search index
        i = index;
        // Locate the end of the c string
        while (buffer[i] !== 0x00 && i < buffer.length) {
          i++;
        }
        // If are at the end of the buffer there is a problem with the document
        if (i >= buffer.length) throw new Error('Bad BSON Document: illegal CString');
        // Return the C string
        var regExpOptions = buffer.toString('utf8', index, i);
        index = i + 1;
  
        // For each option add the corresponding one for javascript
        var optionsArray = new Array(regExpOptions.length);
  
        // Parse options
        for (i = 0; i < regExpOptions.length; i++) {
          switch (regExpOptions[i]) {
            case 'm':
              optionsArray[i] = 'm';
              break;
            case 's':
              optionsArray[i] = 'g';
              break;
            case 'i':
              optionsArray[i] = 'i';
              break;
          }
        }
  
        object[name] = new RegExp(source, optionsArray.join(''));
      } else if (elementType === BSON.BSON_DATA_REGEXP && bsonRegExp === true) {
        // Get the start search index
        i = index;
        // Locate the end of the c string
        while (buffer[i] !== 0x00 && i < buffer.length) {
          i++;
        }
        // If are at the end of the buffer there is a problem with the document
        if (i >= buffer.length) throw new Error('Bad BSON Document: illegal CString');
        // Return the C string
        source = buffer.toString('utf8', index, i);
        index = i + 1;
  
        // Get the start search index
        i = index;
        // Locate the end of the c string
        while (buffer[i] !== 0x00 && i < buffer.length) {
          i++;
        }
        // If are at the end of the buffer there is a problem with the document
        if (i >= buffer.length) throw new Error('Bad BSON Document: illegal CString');
        // Return the C string
        regExpOptions = buffer.toString('utf8', index, i);
        index = i + 1;
  
        // Set the object
        object[name] = new BSONRegExp(source, regExpOptions);
      } else if (elementType === BSON.BSON_DATA_SYMBOL) {
        stringSize =
          buffer[index++] |
          (buffer[index++] << 8) |
          (buffer[index++] << 16) |
          (buffer[index++] << 24);
        if (
          stringSize <= 0 ||
          stringSize > buffer.length - index ||
          buffer[index + stringSize - 1] !== 0
        )
          throw new Error('bad string length in bson');
        object[name] = new Symbol(buffer.toString('utf8', index, index + stringSize - 1));
        index = index + stringSize;
      } else if (elementType === BSON.BSON_DATA_TIMESTAMP) {
        lowBits =
          buffer[index++] |
          (buffer[index++] << 8) |
          (buffer[index++] << 16) |
          (buffer[index++] << 24);
        highBits =
          buffer[index++] |
          (buffer[index++] << 8) |
          (buffer[index++] << 16) |
          (buffer[index++] << 24);
        object[name] = new Timestamp(lowBits, highBits);
      } else if (elementType === BSON.BSON_DATA_MIN_KEY) {
        object[name] = new MinKey();
      } else if (elementType === BSON.BSON_DATA_MAX_KEY) {
        object[name] = new MaxKey();
      } else if (elementType === BSON.BSON_DATA_CODE) {
        stringSize =
          buffer[index++] |
          (buffer[index++] << 8) |
          (buffer[index++] << 16) |
          (buffer[index++] << 24);
        if (
          stringSize <= 0 ||
          stringSize > buffer.length - index ||
          buffer[index + stringSize - 1] !== 0
        )
          throw new Error('bad string length in bson');
        var functionString = buffer.toString('utf8', index, index + stringSize - 1);
  
        // If we are evaluating the functions
        if (evalFunctions) {
          // If we have cache enabled let's look for the md5 of the function in the cache
          if (cacheFunctions) {
            var hash = cacheFunctionsCrc32 ? crc32(functionString) : functionString;
            // Got to do this to avoid V8 deoptimizing the call due to finding eval
            object[name] = isolateEvalWithHash(functionCache, hash, functionString, object);
          } else {
            object[name] = isolateEval(functionString);
          }
        } else {
          object[name] = new Code(functionString);
        }
  
        // Update parse index position
        index = index + stringSize;
      } else if (elementType === BSON.BSON_DATA_CODE_W_SCOPE) {
        var totalSize =
          buffer[index++] |
          (buffer[index++] << 8) |
          (buffer[index++] << 16) |
          (buffer[index++] << 24);
  
        // Element cannot be shorter than totalSize + stringSize + documentSize + terminator
        if (totalSize < 4 + 4 + 4 + 1) {
          throw new Error('code_w_scope total size shorter minimum expected length');
        }
  
        // Get the code string size
        stringSize =
          buffer[index++] |
          (buffer[index++] << 8) |
          (buffer[index++] << 16) |
          (buffer[index++] << 24);
        // Check if we have a valid string
        if (
          stringSize <= 0 ||
          stringSize > buffer.length - index ||
          buffer[index + stringSize - 1] !== 0
        )
          throw new Error('bad string length in bson');
  
        // Javascript function
        functionString = buffer.toString('utf8', index, index + stringSize - 1);
        // Update parse index position
        index = index + stringSize;
        // Parse the element
        _index = index;
        // Decode the size of the object document
        objectSize =
          buffer[index] |
          (buffer[index + 1] << 8) |
          (buffer[index + 2] << 16) |
          (buffer[index + 3] << 24);
        // Decode the scope object
        var scopeObject = deserializeObject(buffer, _index, options, false);
        // Adjust the index
        index = index + objectSize;
  
        // Check if field length is to short
        if (totalSize < 4 + 4 + objectSize + stringSize) {
          throw new Error('code_w_scope total size is to short, truncating scope');
        }
  
        // Check if totalSize field is to long
        if (totalSize > 4 + 4 + objectSize + stringSize) {
          throw new Error('code_w_scope total size is to long, clips outer document');
        }
  
        // If we are evaluating the functions
        if (evalFunctions) {
          // If we have cache enabled let's look for the md5 of the function in the cache
          if (cacheFunctions) {
            hash = cacheFunctionsCrc32 ? crc32(functionString) : functionString;
            // Got to do this to avoid V8 deoptimizing the call due to finding eval
            object[name] = isolateEvalWithHash(functionCache, hash, functionString, object);
          } else {
            object[name] = isolateEval(functionString);
          }
  
          object[name].scope = scopeObject;
        } else {
          object[name] = new Code(functionString, scopeObject);
        }
      } else if (elementType === BSON.BSON_DATA_DBPOINTER) {
        // Get the code string size
        stringSize =
          buffer[index++] |
          (buffer[index++] << 8) |
          (buffer[index++] << 16) |
          (buffer[index++] << 24);
        // Check if we have a valid string
        if (
          stringSize <= 0 ||
          stringSize > buffer.length - index ||
          buffer[index + stringSize - 1] !== 0
        )
          throw new Error('bad string length in bson');
        // Namespace
        var namespace = buffer.toString('utf8', index, index + stringSize - 1);
        // Update parse index position
        index = index + stringSize;
  
        // Read the oid
        var oidBuffer = utils.allocBuffer(12);
        buffer.copy(oidBuffer, 0, index, index + 12);
        oid = new ObjectID(oidBuffer);
  
        // Update the index
        index = index + 12;
  
        // Split the namespace
        var parts = namespace.split('.');
        var db = parts.shift();
        var collection = parts.join('.');
        // Upgrade to DBRef type
        object[name] = new DBRef(collection, oid, db);
      } else {
        throw new Error(
          'Detected unknown BSON type ' +
            elementType.toString(16) +
            ' for fieldname "' +
            name +
            '", are you using the latest BSON parser'
        );
      }
    }
  
    // Check if the deserialization was against a valid array/object
    if (size !== index - startIndex) {
      if (isArray) throw new Error('corrupt array bson');
      throw new Error('corrupt object bson');
    }
  
    // Check if we have a db ref object
    if (object['$id'] != null) object = new DBRef(object['$ref'], object['$id'], object['$db']);
    return object;
  };
  
  /**
   * Ensure eval is isolated.
   *
   * @ignore
   * @api private
   */
  var isolateEvalWithHash = function(functionCache, hash, functionString, object) {
    // Contains the value we are going to set
    var value = null;
  
    // Check for cache hit, eval if missing and return cached function
    if (functionCache[hash] == null) {
      eval('value = ' + functionString);
      functionCache[hash] = value;
    }
    // Set the object
    return functionCache[hash].bind(object);
  };
  
  /**
   * Ensure eval is isolated.
   *
   * @ignore
   * @api private
   */
  var isolateEval = function(functionString) {
    // Contains the value we are going to set
    var value = null;
    // Eval the function
    eval('value = ' + functionString);
    return value;
  };
  
  var BSON = {};
  
  /**
   * Contains the function cache if we have that enable to allow for avoiding the eval step on each deserialization, comparison is by md5
   *
   * @ignore
   * @api private
   */
  var functionCache = (BSON.functionCache = {});
  
  /**
   * Number BSON Type
   *
   * @classconstant BSON_DATA_NUMBER
   **/
  BSON.BSON_DATA_NUMBER = 1;
  /**
   * String BSON Type
   *
   * @classconstant BSON_DATA_STRING
   **/
  BSON.BSON_DATA_STRING = 2;
  /**
   * Object BSON Type
   *
   * @classconstant BSON_DATA_OBJECT
   **/
  BSON.BSON_DATA_OBJECT = 3;
  /**
   * Array BSON Type
   *
   * @classconstant BSON_DATA_ARRAY
   **/
  BSON.BSON_DATA_ARRAY = 4;
  /**
   * Binary BSON Type
   *
   * @classconstant BSON_DATA_BINARY
   **/
  BSON.BSON_DATA_BINARY = 5;
  /**
   * Binary BSON Type
   *
   * @classconstant BSON_DATA_UNDEFINED
   **/
  BSON.BSON_DATA_UNDEFINED = 6;
  /**
   * ObjectID BSON Type
   *
   * @classconstant BSON_DATA_OID
   **/
  BSON.BSON_DATA_OID = 7;
  /**
   * Boolean BSON Type
   *
   * @classconstant BSON_DATA_BOOLEAN
   **/
  BSON.BSON_DATA_BOOLEAN = 8;
  /**
   * Date BSON Type
   *
   * @classconstant BSON_DATA_DATE
   **/
  BSON.BSON_DATA_DATE = 9;
  /**
   * null BSON Type
   *
   * @classconstant BSON_DATA_NULL
   **/
  BSON.BSON_DATA_NULL = 10;
  /**
   * RegExp BSON Type
   *
   * @classconstant BSON_DATA_REGEXP
   **/
  BSON.BSON_DATA_REGEXP = 11;
  /**
   * Code BSON Type
   *
   * @classconstant BSON_DATA_DBPOINTER
   **/
  BSON.BSON_DATA_DBPOINTER = 12;
  /**
   * Code BSON Type
   *
   * @classconstant BSON_DATA_CODE
   **/
  BSON.BSON_DATA_CODE = 13;
  /**
   * Symbol BSON Type
   *
   * @classconstant BSON_DATA_SYMBOL
   **/
  BSON.BSON_DATA_SYMBOL = 14;
  /**
   * Code with Scope BSON Type
   *
   * @classconstant BSON_DATA_CODE_W_SCOPE
   **/
  BSON.BSON_DATA_CODE_W_SCOPE = 15;
  /**
   * 32 bit Integer BSON Type
   *
   * @classconstant BSON_DATA_INT
   **/
  BSON.BSON_DATA_INT = 16;
  /**
   * Timestamp BSON Type
   *
   * @classconstant BSON_DATA_TIMESTAMP
   **/
  BSON.BSON_DATA_TIMESTAMP = 17;
  /**
   * Long BSON Type
   *
   * @classconstant BSON_DATA_LONG
   **/
  BSON.BSON_DATA_LONG = 18;
  /**
   * Long BSON Type
   *
   * @classconstant BSON_DATA_DECIMAL128
   **/
  BSON.BSON_DATA_DECIMAL128 = 19;
  /**
   * MinKey BSON Type
   *
   * @classconstant BSON_DATA_MIN_KEY
   **/
  BSON.BSON_DATA_MIN_KEY = 0xff;
  /**
   * MaxKey BSON Type
   *
   * @classconstant BSON_DATA_MAX_KEY
   **/
  BSON.BSON_DATA_MAX_KEY = 0x7f;
  
  /**
   * Binary Default Type
   *
   * @classconstant BSON_BINARY_SUBTYPE_DEFAULT
   **/
  BSON.BSON_BINARY_SUBTYPE_DEFAULT = 0;
  /**
   * Binary Function Type
   *
   * @classconstant BSON_BINARY_SUBTYPE_FUNCTION
   **/
  BSON.BSON_BINARY_SUBTYPE_FUNCTION = 1;
  /**
   * Binary Byte Array Type
   *
   * @classconstant BSON_BINARY_SUBTYPE_BYTE_ARRAY
   **/
  BSON.BSON_BINARY_SUBTYPE_BYTE_ARRAY = 2;
  /**
   * Binary UUID Type
   *
   * @classconstant BSON_BINARY_SUBTYPE_UUID
   **/
  BSON.BSON_BINARY_SUBTYPE_UUID = 3;
  /**
   * Binary MD5 Type
   *
   * @classconstant BSON_BINARY_SUBTYPE_MD5
   **/
  BSON.BSON_BINARY_SUBTYPE_MD5 = 4;
  /**
   * Binary User Defined Type
   *
   * @classconstant BSON_BINARY_SUBTYPE_USER_DEFINED
   **/
  BSON.BSON_BINARY_SUBTYPE_USER_DEFINED = 128;
  
  // BSON MAX VALUES
  BSON.BSON_INT32_MAX = 0x7fffffff;
  BSON.BSON_INT32_MIN = -0x80000000;
  
  BSON.BSON_INT64_MAX = Math.pow(2, 63) - 1;
  BSON.BSON_INT64_MIN = -Math.pow(2, 63);
  
  // JS MAX PRECISE VALUES
  BSON.JS_INT_MAX = 0x20000000000000; // Any integer up to 2^53 can be precisely represented by a double.
  BSON.JS_INT_MIN = -0x20000000000000; // Any integer down to -2^53 can be precisely represented by a double.
  
  // Internal long versions
  var JS_INT_MAX_LONG = Long.fromNumber(0x20000000000000); // Any integer up to 2^53 can be precisely represented by a double.
  var JS_INT_MIN_LONG = Long.fromNumber(-0x20000000000000); // Any integer down to -2^53 can be precisely represented by a double.
  
  module.exports = deserialize;
  