var client;
(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
    'use strict';
    
    const asn1 = exports;
    
    asn1.bignum = require('bn.js');
    
    asn1.define = require('./asn1/api').define;
    asn1.base = require('./asn1/base');
    asn1.constants = require('./asn1/constants');
    asn1.decoders = require('./asn1/decoders');
    asn1.encoders = require('./asn1/encoders');
    
    },{"./asn1/api":2,"./asn1/base":4,"./asn1/constants":8,"./asn1/decoders":10,"./asn1/encoders":13,"bn.js":15}],2:[function(require,module,exports){
    'use strict';
    
    const encoders = require('./encoders');
    const decoders = require('./decoders');
    const inherits = require('inherits');
    
    const api = exports;
    
    api.define = function define(name, body) {
      return new Entity(name, body);
    };
    
    function Entity(name, body) {
      this.name = name;
      this.body = body;
    
      this.decoders = {};
      this.encoders = {};
    }
    
    Entity.prototype._createNamed = function createNamed(Base) {
      const name = this.name;
    
      function Generated(entity) {
        this._initNamed(entity, name);
      }
      inherits(Generated, Base);
      Generated.prototype._initNamed = function _initNamed(entity, name) {
        Base.call(this, entity, name);
      };
    
      return new Generated(this);
    };
    
    Entity.prototype._getDecoder = function _getDecoder(enc) {
      enc = enc || 'der';
      // Lazily create decoder
      if (!this.decoders.hasOwnProperty(enc))
        this.decoders[enc] = this._createNamed(decoders[enc]);
      return this.decoders[enc];
    };
    
    Entity.prototype.decode = function decode(data, enc, options) {
      return this._getDecoder(enc).decode(data, options);
    };
    
    Entity.prototype._getEncoder = function _getEncoder(enc) {
      enc = enc || 'der';
      // Lazily create encoder
      if (!this.encoders.hasOwnProperty(enc))
        this.encoders[enc] = this._createNamed(encoders[enc]);
      return this.encoders[enc];
    };
    
    Entity.prototype.encode = function encode(data, enc, /* internal */ reporter) {
      return this._getEncoder(enc).encode(data, reporter);
    };
    
    },{"./decoders":10,"./encoders":13,"inherits":149}],3:[function(require,module,exports){
    'use strict';
    
    const inherits = require('inherits');
    const Reporter = require('../base/reporter').Reporter;
    const Buffer = require('safer-buffer').Buffer;
    
    function DecoderBuffer(base, options) {
      Reporter.call(this, options);
      if (!Buffer.isBuffer(base)) {
        this.error('Input not Buffer');
        return;
      }
    
      this.base = base;
      this.offset = 0;
      this.length = base.length;
    }
    inherits(DecoderBuffer, Reporter);
    exports.DecoderBuffer = DecoderBuffer;
    
    DecoderBuffer.isDecoderBuffer = function isDecoderBuffer(data) {
      if (data instanceof DecoderBuffer) {
        return true;
      }
    
      // Or accept compatible API
      const isCompatible = typeof data === 'object' &&
        Buffer.isBuffer(data.base) &&
        data.constructor.name === 'DecoderBuffer' &&
        typeof data.offset === 'number' &&
        typeof data.length === 'number' &&
        typeof data.save === 'function' &&
        typeof data.restore === 'function' &&
        typeof data.isEmpty === 'function' &&
        typeof data.readUInt8 === 'function' &&
        typeof data.skip === 'function' &&
        typeof data.raw === 'function';
    
      return isCompatible;
    };
    
    DecoderBuffer.prototype.save = function save() {
      return { offset: this.offset, reporter: Reporter.prototype.save.call(this) };
    };
    
    DecoderBuffer.prototype.restore = function restore(save) {
      // Return skipped data
      const res = new DecoderBuffer(this.base);
      res.offset = save.offset;
      res.length = this.offset;
    
      this.offset = save.offset;
      Reporter.prototype.restore.call(this, save.reporter);
    
      return res;
    };
    
    DecoderBuffer.prototype.isEmpty = function isEmpty() {
      return this.offset === this.length;
    };
    
    DecoderBuffer.prototype.readUInt8 = function readUInt8(fail) {
      if (this.offset + 1 <= this.length)
        return this.base.readUInt8(this.offset++, true);
      else
        return this.error(fail || 'DecoderBuffer overrun');
    };
    
    DecoderBuffer.prototype.skip = function skip(bytes, fail) {
      if (!(this.offset + bytes <= this.length))
        return this.error(fail || 'DecoderBuffer overrun');
    
      const res = new DecoderBuffer(this.base);
    
      // Share reporter state
      res._reporterState = this._reporterState;
    
      res.offset = this.offset;
      res.length = this.offset + bytes;
      this.offset += bytes;
      return res;
    };
    
    DecoderBuffer.prototype.raw = function raw(save) {
      return this.base.slice(save ? save.offset : this.offset, this.length);
    };
    
    function EncoderBuffer(value, reporter) {
      if (Array.isArray(value)) {
        this.length = 0;
        this.value = value.map(function(item) {
          if (!EncoderBuffer.isEncoderBuffer(item))
            item = new EncoderBuffer(item, reporter);
          this.length += item.length;
          return item;
        }, this);
      } else if (typeof value === 'number') {
        if (!(0 <= value && value <= 0xff))
          return reporter.error('non-byte EncoderBuffer value');
        this.value = value;
        this.length = 1;
      } else if (typeof value === 'string') {
        this.value = value;
        this.length = Buffer.byteLength(value);
      } else if (Buffer.isBuffer(value)) {
        this.value = value;
        this.length = value.length;
      } else {
        return reporter.error('Unsupported type: ' + typeof value);
      }
    }
    exports.EncoderBuffer = EncoderBuffer;
    
    EncoderBuffer.isEncoderBuffer = function isEncoderBuffer(data) {
      if (data instanceof EncoderBuffer) {
        return true;
      }
    
      // Or accept compatible API
      const isCompatible = typeof data === 'object' &&
        data.constructor.name === 'EncoderBuffer' &&
        typeof data.length === 'number' &&
        typeof data.join === 'function';
    
      return isCompatible;
    };
    
    EncoderBuffer.prototype.join = function join(out, offset) {
      if (!out)
        out = Buffer.alloc(this.length);
      if (!offset)
        offset = 0;
    
      if (this.length === 0)
        return out;
    
      if (Array.isArray(this.value)) {
        this.value.forEach(function(item) {
          item.join(out, offset);
          offset += item.length;
        });
      } else {
        if (typeof this.value === 'number')
          out[offset] = this.value;
        else if (typeof this.value === 'string')
          out.write(this.value, offset);
        else if (Buffer.isBuffer(this.value))
          this.value.copy(out, offset);
        offset += this.length;
      }
    
      return out;
    };
    
    },{"../base/reporter":6,"inherits":149,"safer-buffer":188}],4:[function(require,module,exports){
    'use strict';
    
    const base = exports;
    
    base.Reporter = require('./reporter').Reporter;
    base.DecoderBuffer = require('./buffer').DecoderBuffer;
    base.EncoderBuffer = require('./buffer').EncoderBuffer;
    base.Node = require('./node');
    
    },{"./buffer":3,"./node":5,"./reporter":6}],5:[function(require,module,exports){
    'use strict';
    
    const Reporter = require('../base/reporter').Reporter;
    const EncoderBuffer = require('../base/buffer').EncoderBuffer;
    const DecoderBuffer = require('../base/buffer').DecoderBuffer;
    const assert = require('minimalistic-assert');
    
    // Supported tags
    const tags = [
      'seq', 'seqof', 'set', 'setof', 'objid', 'bool',
      'gentime', 'utctime', 'null_', 'enum', 'int', 'objDesc',
      'bitstr', 'bmpstr', 'charstr', 'genstr', 'graphstr', 'ia5str', 'iso646str',
      'numstr', 'octstr', 'printstr', 't61str', 'unistr', 'utf8str', 'videostr'
    ];
    
    // Public methods list
    const methods = [
      'key', 'obj', 'use', 'optional', 'explicit', 'implicit', 'def', 'choice',
      'any', 'contains'
    ].concat(tags);
    
    // Overrided methods list
    const overrided = [
      '_peekTag', '_decodeTag', '_use',
      '_decodeStr', '_decodeObjid', '_decodeTime',
      '_decodeNull', '_decodeInt', '_decodeBool', '_decodeList',
    
      '_encodeComposite', '_encodeStr', '_encodeObjid', '_encodeTime',
      '_encodeNull', '_encodeInt', '_encodeBool'
    ];
    
    function Node(enc, parent, name) {
      const state = {};
      this._baseState = state;
    
      state.name = name;
      state.enc = enc;
    
      state.parent = parent || null;
      state.children = null;
    
      // State
      state.tag = null;
      state.args = null;
      state.reverseArgs = null;
      state.choice = null;
      state.optional = false;
      state.any = false;
      state.obj = false;
      state.use = null;
      state.useDecoder = null;
      state.key = null;
      state['default'] = null;
      state.explicit = null;
      state.implicit = null;
      state.contains = null;
    
      // Should create new instance on each method
      if (!state.parent) {
        state.children = [];
        this._wrap();
      }
    }
    module.exports = Node;
    
    const stateProps = [
      'enc', 'parent', 'children', 'tag', 'args', 'reverseArgs', 'choice',
      'optional', 'any', 'obj', 'use', 'alteredUse', 'key', 'default', 'explicit',
      'implicit', 'contains'
    ];
    
    Node.prototype.clone = function clone() {
      const state = this._baseState;
      const cstate = {};
      stateProps.forEach(function(prop) {
        cstate[prop] = state[prop];
      });
      const res = new this.constructor(cstate.parent);
      res._baseState = cstate;
      return res;
    };
    
    Node.prototype._wrap = function wrap() {
      const state = this._baseState;
      methods.forEach(function(method) {
        this[method] = function _wrappedMethod() {
          const clone = new this.constructor(this);
          state.children.push(clone);
          return clone[method].apply(clone, arguments);
        };
      }, this);
    };
    
    Node.prototype._init = function init(body) {
      const state = this._baseState;
    
      assert(state.parent === null);
      body.call(this);
    
      // Filter children
      state.children = state.children.filter(function(child) {
        return child._baseState.parent === this;
      }, this);
      assert.equal(state.children.length, 1, 'Root node can have only one child');
    };
    
    Node.prototype._useArgs = function useArgs(args) {
      const state = this._baseState;
    
      // Filter children and args
      const children = args.filter(function(arg) {
        return arg instanceof this.constructor;
      }, this);
      args = args.filter(function(arg) {
        return !(arg instanceof this.constructor);
      }, this);
    
      if (children.length !== 0) {
        assert(state.children === null);
        state.children = children;
    
        // Replace parent to maintain backward link
        children.forEach(function(child) {
          child._baseState.parent = this;
        }, this);
      }
      if (args.length !== 0) {
        assert(state.args === null);
        state.args = args;
        state.reverseArgs = args.map(function(arg) {
          if (typeof arg !== 'object' || arg.constructor !== Object)
            return arg;
    
          const res = {};
          Object.keys(arg).forEach(function(key) {
            if (key == (key | 0))
              key |= 0;
            const value = arg[key];
            res[value] = key;
          });
          return res;
        });
      }
    };
    
    //
    // Overrided methods
    //
    
    overrided.forEach(function(method) {
      Node.prototype[method] = function _overrided() {
        const state = this._baseState;
        throw new Error(method + ' not implemented for encoding: ' + state.enc);
      };
    });
    
    //
    // Public methods
    //
    
    tags.forEach(function(tag) {
      Node.prototype[tag] = function _tagMethod() {
        const state = this._baseState;
        const args = Array.prototype.slice.call(arguments);
    
        assert(state.tag === null);
        state.tag = tag;
    
        this._useArgs(args);
    
        return this;
      };
    });
    
    Node.prototype.use = function use(item) {
      assert(item);
      const state = this._baseState;
    
      assert(state.use === null);
      state.use = item;
    
      return this;
    };
    
    Node.prototype.optional = function optional() {
      const state = this._baseState;
    
      state.optional = true;
    
      return this;
    };
    
    Node.prototype.def = function def(val) {
      const state = this._baseState;
    
      assert(state['default'] === null);
      state['default'] = val;
      state.optional = true;
    
      return this;
    };
    
    Node.prototype.explicit = function explicit(num) {
      const state = this._baseState;
    
      assert(state.explicit === null && state.implicit === null);
      state.explicit = num;
    
      return this;
    };
    
    Node.prototype.implicit = function implicit(num) {
      const state = this._baseState;
    
      assert(state.explicit === null && state.implicit === null);
      state.implicit = num;
    
      return this;
    };
    
    Node.prototype.obj = function obj() {
      const state = this._baseState;
      const args = Array.prototype.slice.call(arguments);
    
      state.obj = true;
    
      if (args.length !== 0)
        this._useArgs(args);
    
      return this;
    };
    
    Node.prototype.key = function key(newKey) {
      const state = this._baseState;
    
      assert(state.key === null);
      state.key = newKey;
    
      return this;
    };
    
    Node.prototype.any = function any() {
      const state = this._baseState;
    
      state.any = true;
    
      return this;
    };
    
    Node.prototype.choice = function choice(obj) {
      const state = this._baseState;
    
      assert(state.choice === null);
      state.choice = obj;
      this._useArgs(Object.keys(obj).map(function(key) {
        return obj[key];
      }));
    
      return this;
    };
    
    Node.prototype.contains = function contains(item) {
      const state = this._baseState;
    
      assert(state.use === null);
      state.contains = item;
    
      return this;
    };
    
    //
    // Decoding
    //
    
    Node.prototype._decode = function decode(input, options) {
      const state = this._baseState;
    
      // Decode root node
      if (state.parent === null)
        return input.wrapResult(state.children[0]._decode(input, options));
    
      let result = state['default'];
      let present = true;
    
      let prevKey = null;
      if (state.key !== null)
        prevKey = input.enterKey(state.key);
    
      // Check if tag is there
      if (state.optional) {
        let tag = null;
        if (state.explicit !== null)
          tag = state.explicit;
        else if (state.implicit !== null)
          tag = state.implicit;
        else if (state.tag !== null)
          tag = state.tag;
    
        if (tag === null && !state.any) {
          // Trial and Error
          const save = input.save();
          try {
            if (state.choice === null)
              this._decodeGeneric(state.tag, input, options);
            else
              this._decodeChoice(input, options);
            present = true;
          } catch (e) {
            present = false;
          }
          input.restore(save);
        } else {
          present = this._peekTag(input, tag, state.any);
    
          if (input.isError(present))
            return present;
        }
      }
    
      // Push object on stack
      let prevObj;
      if (state.obj && present)
        prevObj = input.enterObject();
    
      if (present) {
        // Unwrap explicit values
        if (state.explicit !== null) {
          const explicit = this._decodeTag(input, state.explicit);
          if (input.isError(explicit))
            return explicit;
          input = explicit;
        }
    
        const start = input.offset;
    
        // Unwrap implicit and normal values
        if (state.use === null && state.choice === null) {
          let save;
          if (state.any)
            save = input.save();
          const body = this._decodeTag(
            input,
            state.implicit !== null ? state.implicit : state.tag,
            state.any
          );
          if (input.isError(body))
            return body;
    
          if (state.any)
            result = input.raw(save);
          else
            input = body;
        }
    
        if (options && options.track && state.tag !== null)
          options.track(input.path(), start, input.length, 'tagged');
    
        if (options && options.track && state.tag !== null)
          options.track(input.path(), input.offset, input.length, 'content');
    
        // Select proper method for tag
        if (state.any) {
          // no-op
        } else if (state.choice === null) {
          result = this._decodeGeneric(state.tag, input, options);
        } else {
          result = this._decodeChoice(input, options);
        }
    
        if (input.isError(result))
          return result;
    
        // Decode children
        if (!state.any && state.choice === null && state.children !== null) {
          state.children.forEach(function decodeChildren(child) {
            // NOTE: We are ignoring errors here, to let parser continue with other
            // parts of encoded data
            child._decode(input, options);
          });
        }
    
        // Decode contained/encoded by schema, only in bit or octet strings
        if (state.contains && (state.tag === 'octstr' || state.tag === 'bitstr')) {
          const data = new DecoderBuffer(result);
          result = this._getUse(state.contains, input._reporterState.obj)
            ._decode(data, options);
        }
      }
    
      // Pop object
      if (state.obj && present)
        result = input.leaveObject(prevObj);
    
      // Set key
      if (state.key !== null && (result !== null || present === true))
        input.leaveKey(prevKey, state.key, result);
      else if (prevKey !== null)
        input.exitKey(prevKey);
    
      return result;
    };
    
    Node.prototype._decodeGeneric = function decodeGeneric(tag, input, options) {
      const state = this._baseState;
    
      if (tag === 'seq' || tag === 'set')
        return null;
      if (tag === 'seqof' || tag === 'setof')
        return this._decodeList(input, tag, state.args[0], options);
      else if (/str$/.test(tag))
        return this._decodeStr(input, tag, options);
      else if (tag === 'objid' && state.args)
        return this._decodeObjid(input, state.args[0], state.args[1], options);
      else if (tag === 'objid')
        return this._decodeObjid(input, null, null, options);
      else if (tag === 'gentime' || tag === 'utctime')
        return this._decodeTime(input, tag, options);
      else if (tag === 'null_')
        return this._decodeNull(input, options);
      else if (tag === 'bool')
        return this._decodeBool(input, options);
      else if (tag === 'objDesc')
        return this._decodeStr(input, tag, options);
      else if (tag === 'int' || tag === 'enum')
        return this._decodeInt(input, state.args && state.args[0], options);
    
      if (state.use !== null) {
        return this._getUse(state.use, input._reporterState.obj)
          ._decode(input, options);
      } else {
        return input.error('unknown tag: ' + tag);
      }
    };
    
    Node.prototype._getUse = function _getUse(entity, obj) {
    
      const state = this._baseState;
      // Create altered use decoder if implicit is set
      state.useDecoder = this._use(entity, obj);
      assert(state.useDecoder._baseState.parent === null);
      state.useDecoder = state.useDecoder._baseState.children[0];
      if (state.implicit !== state.useDecoder._baseState.implicit) {
        state.useDecoder = state.useDecoder.clone();
        state.useDecoder._baseState.implicit = state.implicit;
      }
      return state.useDecoder;
    };
    
    Node.prototype._decodeChoice = function decodeChoice(input, options) {
      const state = this._baseState;
      let result = null;
      let match = false;
    
      Object.keys(state.choice).some(function(key) {
        const save = input.save();
        const node = state.choice[key];
        try {
          const value = node._decode(input, options);
          if (input.isError(value))
            return false;
    
          result = { type: key, value: value };
          match = true;
        } catch (e) {
          input.restore(save);
          return false;
        }
        return true;
      }, this);
    
      if (!match)
        return input.error('Choice not matched');
    
      return result;
    };
    
    //
    // Encoding
    //
    
    Node.prototype._createEncoderBuffer = function createEncoderBuffer(data) {
      return new EncoderBuffer(data, this.reporter);
    };
    
    Node.prototype._encode = function encode(data, reporter, parent) {
      const state = this._baseState;
      if (state['default'] !== null && state['default'] === data)
        return;
    
      const result = this._encodeValue(data, reporter, parent);
      if (result === undefined)
        return;
    
      if (this._skipDefault(result, reporter, parent))
        return;
    
      return result;
    };
    
    Node.prototype._encodeValue = function encode(data, reporter, parent) {
      const state = this._baseState;
    
      // Decode root node
      if (state.parent === null)
        return state.children[0]._encode(data, reporter || new Reporter());
    
      let result = null;
    
      // Set reporter to share it with a child class
      this.reporter = reporter;
    
      // Check if data is there
      if (state.optional && data === undefined) {
        if (state['default'] !== null)
          data = state['default'];
        else
          return;
      }
    
      // Encode children first
      let content = null;
      let primitive = false;
      if (state.any) {
        // Anything that was given is translated to buffer
        result = this._createEncoderBuffer(data);
      } else if (state.choice) {
        result = this._encodeChoice(data, reporter);
      } else if (state.contains) {
        content = this._getUse(state.contains, parent)._encode(data, reporter);
        primitive = true;
      } else if (state.children) {
        content = state.children.map(function(child) {
          if (child._baseState.tag === 'null_')
            return child._encode(null, reporter, data);
    
          if (child._baseState.key === null)
            return reporter.error('Child should have a key');
          const prevKey = reporter.enterKey(child._baseState.key);
    
          if (typeof data !== 'object')
            return reporter.error('Child expected, but input is not object');
    
          const res = child._encode(data[child._baseState.key], reporter, data);
          reporter.leaveKey(prevKey);
    
          return res;
        }, this).filter(function(child) {
          return child;
        });
        content = this._createEncoderBuffer(content);
      } else {
        if (state.tag === 'seqof' || state.tag === 'setof') {
          // TODO(indutny): this should be thrown on DSL level
          if (!(state.args && state.args.length === 1))
            return reporter.error('Too many args for : ' + state.tag);
    
          if (!Array.isArray(data))
            return reporter.error('seqof/setof, but data is not Array');
    
          const child = this.clone();
          child._baseState.implicit = null;
          content = this._createEncoderBuffer(data.map(function(item) {
            const state = this._baseState;
    
            return this._getUse(state.args[0], data)._encode(item, reporter);
          }, child));
        } else if (state.use !== null) {
          result = this._getUse(state.use, parent)._encode(data, reporter);
        } else {
          content = this._encodePrimitive(state.tag, data);
          primitive = true;
        }
      }
    
      // Encode data itself
      if (!state.any && state.choice === null) {
        const tag = state.implicit !== null ? state.implicit : state.tag;
        const cls = state.implicit === null ? 'universal' : 'context';
    
        if (tag === null) {
          if (state.use === null)
            reporter.error('Tag could be omitted only for .use()');
        } else {
          if (state.use === null)
            result = this._encodeComposite(tag, primitive, cls, content);
        }
      }
    
      // Wrap in explicit
      if (state.explicit !== null)
        result = this._encodeComposite(state.explicit, false, 'context', result);
    
      return result;
    };
    
    Node.prototype._encodeChoice = function encodeChoice(data, reporter) {
      const state = this._baseState;
    
      const node = state.choice[data.type];
      if (!node) {
        assert(
          false,
          data.type + ' not found in ' +
                JSON.stringify(Object.keys(state.choice)));
      }
      return node._encode(data.value, reporter);
    };
    
    Node.prototype._encodePrimitive = function encodePrimitive(tag, data) {
      const state = this._baseState;
    
      if (/str$/.test(tag))
        return this._encodeStr(data, tag);
      else if (tag === 'objid' && state.args)
        return this._encodeObjid(data, state.reverseArgs[0], state.args[1]);
      else if (tag === 'objid')
        return this._encodeObjid(data, null, null);
      else if (tag === 'gentime' || tag === 'utctime')
        return this._encodeTime(data, tag);
      else if (tag === 'null_')
        return this._encodeNull();
      else if (tag === 'int' || tag === 'enum')
        return this._encodeInt(data, state.args && state.reverseArgs[0]);
      else if (tag === 'bool')
        return this._encodeBool(data);
      else if (tag === 'objDesc')
        return this._encodeStr(data, tag);
      else
        throw new Error('Unsupported tag: ' + tag);
    };
    
    Node.prototype._isNumstr = function isNumstr(str) {
      return /^[0-9 ]*$/.test(str);
    };
    
    Node.prototype._isPrintstr = function isPrintstr(str) {
      return /^[A-Za-z0-9 '()+,-./:=?]*$/.test(str);
    };
    
    },{"../base/buffer":3,"../base/reporter":6,"minimalistic-assert":158}],6:[function(require,module,exports){
    'use strict';
    
    const inherits = require('inherits');
    
    function Reporter(options) {
      this._reporterState = {
        obj: null,
        path: [],
        options: options || {},
        errors: []
      };
    }
    exports.Reporter = Reporter;
    
    Reporter.prototype.isError = function isError(obj) {
      return obj instanceof ReporterError;
    };
    
    Reporter.prototype.save = function save() {
      const state = this._reporterState;
    
      return { obj: state.obj, pathLen: state.path.length };
    };
    
    Reporter.prototype.restore = function restore(data) {
      const state = this._reporterState;
    
      state.obj = data.obj;
      state.path = state.path.slice(0, data.pathLen);
    };
    
    Reporter.prototype.enterKey = function enterKey(key) {
      return this._reporterState.path.push(key);
    };
    
    Reporter.prototype.exitKey = function exitKey(index) {
      const state = this._reporterState;
    
      state.path = state.path.slice(0, index - 1);
    };
    
    Reporter.prototype.leaveKey = function leaveKey(index, key, value) {
      const state = this._reporterState;
    
      this.exitKey(index);
      if (state.obj !== null)
        state.obj[key] = value;
    };
    
    Reporter.prototype.path = function path() {
      return this._reporterState.path.join('/');
    };
    
    Reporter.prototype.enterObject = function enterObject() {
      const state = this._reporterState;
    
      const prev = state.obj;
      state.obj = {};
      return prev;
    };
    
    Reporter.prototype.leaveObject = function leaveObject(prev) {
      const state = this._reporterState;
    
      const now = state.obj;
      state.obj = prev;
      return now;
    };
    
    Reporter.prototype.error = function error(msg) {
      let err;
      const state = this._reporterState;
    
      const inherited = msg instanceof ReporterError;
      if (inherited) {
        err = msg;
      } else {
        err = new ReporterError(state.path.map(function(elem) {
          return '[' + JSON.stringify(elem) + ']';
        }).join(''), msg.message || msg, msg.stack);
      }
    
      if (!state.options.partial)
        throw err;
    
      if (!inherited)
        state.errors.push(err);
    
      return err;
    };
    
    Reporter.prototype.wrapResult = function wrapResult(result) {
      const state = this._reporterState;
      if (!state.options.partial)
        return result;
    
      return {
        result: this.isError(result) ? null : result,
        errors: state.errors
      };
    };
    
    function ReporterError(path, msg) {
      this.path = path;
      this.rethrow(msg);
    }
    inherits(ReporterError, Error);
    
    ReporterError.prototype.rethrow = function rethrow(msg) {
      this.message = msg + ' at: ' + (this.path || '(shallow)');
      if (Error.captureStackTrace)
        Error.captureStackTrace(this, ReporterError);
    
      if (!this.stack) {
        try {
          // IE only adds stack when thrown
          throw new Error(this.message);
        } catch (e) {
          this.stack = e.stack;
        }
      }
      return this;
    };
    
    },{"inherits":149}],7:[function(require,module,exports){
    'use strict';
    
    // Helper
    function reverse(map) {
      const res = {};
    
      Object.keys(map).forEach(function(key) {
        // Convert key to integer if it is stringified
        if ((key | 0) == key)
          key = key | 0;
    
        const value = map[key];
        res[value] = key;
      });
    
      return res;
    }
    
    exports.tagClass = {
      0: 'universal',
      1: 'application',
      2: 'context',
      3: 'private'
    };
    exports.tagClassByName = reverse(exports.tagClass);
    
    exports.tag = {
      0x00: 'end',
      0x01: 'bool',
      0x02: 'int',
      0x03: 'bitstr',
      0x04: 'octstr',
      0x05: 'null_',
      0x06: 'objid',
      0x07: 'objDesc',
      0x08: 'external',
      0x09: 'real',
      0x0a: 'enum',
      0x0b: 'embed',
      0x0c: 'utf8str',
      0x0d: 'relativeOid',
      0x10: 'seq',
      0x11: 'set',
      0x12: 'numstr',
      0x13: 'printstr',
      0x14: 't61str',
      0x15: 'videostr',
      0x16: 'ia5str',
      0x17: 'utctime',
      0x18: 'gentime',
      0x19: 'graphstr',
      0x1a: 'iso646str',
      0x1b: 'genstr',
      0x1c: 'unistr',
      0x1d: 'charstr',
      0x1e: 'bmpstr'
    };
    exports.tagByName = reverse(exports.tag);
    
    },{}],8:[function(require,module,exports){
    'use strict';
    
    const constants = exports;
    
    // Helper
    constants._reverse = function reverse(map) {
      const res = {};
    
      Object.keys(map).forEach(function(key) {
        // Convert key to integer if it is stringified
        if ((key | 0) == key)
          key = key | 0;
    
        const value = map[key];
        res[value] = key;
      });
    
      return res;
    };
    
    constants.der = require('./der');
    
    },{"./der":7}],9:[function(require,module,exports){
    'use strict';
    
    const inherits = require('inherits');
    
    const bignum = require('bn.js');
    const DecoderBuffer = require('../base/buffer').DecoderBuffer;
    const Node = require('../base/node');
    
    // Import DER constants
    const der = require('../constants/der');
    
    function DERDecoder(entity) {
      this.enc = 'der';
      this.name = entity.name;
      this.entity = entity;
    
      // Construct base tree
      this.tree = new DERNode();
      this.tree._init(entity.body);
    }
    module.exports = DERDecoder;
    
    DERDecoder.prototype.decode = function decode(data, options) {
      if (!DecoderBuffer.isDecoderBuffer(data)) {
        data = new DecoderBuffer(data, options);
      }
    
      return this.tree._decode(data, options);
    };
    
    // Tree methods
    
    function DERNode(parent) {
      Node.call(this, 'der', parent);
    }
    inherits(DERNode, Node);
    
    DERNode.prototype._peekTag = function peekTag(buffer, tag, any) {
      if (buffer.isEmpty())
        return false;
    
      const state = buffer.save();
      const decodedTag = derDecodeTag(buffer, 'Failed to peek tag: "' + tag + '"');
      if (buffer.isError(decodedTag))
        return decodedTag;
    
      buffer.restore(state);
    
      return decodedTag.tag === tag || decodedTag.tagStr === tag ||
        (decodedTag.tagStr + 'of') === tag || any;
    };
    
    DERNode.prototype._decodeTag = function decodeTag(buffer, tag, any) {
      const decodedTag = derDecodeTag(buffer,
        'Failed to decode tag of "' + tag + '"');
      if (buffer.isError(decodedTag))
        return decodedTag;
    
      let len = derDecodeLen(buffer,
        decodedTag.primitive,
        'Failed to get length of "' + tag + '"');
    
      // Failure
      if (buffer.isError(len))
        return len;
    
      if (!any &&
          decodedTag.tag !== tag &&
          decodedTag.tagStr !== tag &&
          decodedTag.tagStr + 'of' !== tag) {
        return buffer.error('Failed to match tag: "' + tag + '"');
      }
    
      if (decodedTag.primitive || len !== null)
        return buffer.skip(len, 'Failed to match body of: "' + tag + '"');
    
      // Indefinite length... find END tag
      const state = buffer.save();
      const res = this._skipUntilEnd(
        buffer,
        'Failed to skip indefinite length body: "' + this.tag + '"');
      if (buffer.isError(res))
        return res;
    
      len = buffer.offset - state.offset;
      buffer.restore(state);
      return buffer.skip(len, 'Failed to match body of: "' + tag + '"');
    };
    
    DERNode.prototype._skipUntilEnd = function skipUntilEnd(buffer, fail) {
      for (;;) {
        const tag = derDecodeTag(buffer, fail);
        if (buffer.isError(tag))
          return tag;
        const len = derDecodeLen(buffer, tag.primitive, fail);
        if (buffer.isError(len))
          return len;
    
        let res;
        if (tag.primitive || len !== null)
          res = buffer.skip(len);
        else
          res = this._skipUntilEnd(buffer, fail);
    
        // Failure
        if (buffer.isError(res))
          return res;
    
        if (tag.tagStr === 'end')
          break;
      }
    };
    
    DERNode.prototype._decodeList = function decodeList(buffer, tag, decoder,
      options) {
      const result = [];
      while (!buffer.isEmpty()) {
        const possibleEnd = this._peekTag(buffer, 'end');
        if (buffer.isError(possibleEnd))
          return possibleEnd;
    
        const res = decoder.decode(buffer, 'der', options);
        if (buffer.isError(res) && possibleEnd)
          break;
        result.push(res);
      }
      return result;
    };
    
    DERNode.prototype._decodeStr = function decodeStr(buffer, tag) {
      if (tag === 'bitstr') {
        const unused = buffer.readUInt8();
        if (buffer.isError(unused))
          return unused;
        return { unused: unused, data: buffer.raw() };
      } else if (tag === 'bmpstr') {
        const raw = buffer.raw();
        if (raw.length % 2 === 1)
          return buffer.error('Decoding of string type: bmpstr length mismatch');
    
        let str = '';
        for (let i = 0; i < raw.length / 2; i++) {
          str += String.fromCharCode(raw.readUInt16BE(i * 2));
        }
        return str;
      } else if (tag === 'numstr') {
        const numstr = buffer.raw().toString('ascii');
        if (!this._isNumstr(numstr)) {
          return buffer.error('Decoding of string type: ' +
                              'numstr unsupported characters');
        }
        return numstr;
      } else if (tag === 'octstr') {
        return buffer.raw();
      } else if (tag === 'objDesc') {
        return buffer.raw();
      } else if (tag === 'printstr') {
        const printstr = buffer.raw().toString('ascii');
        if (!this._isPrintstr(printstr)) {
          return buffer.error('Decoding of string type: ' +
                              'printstr unsupported characters');
        }
        return printstr;
      } else if (/str$/.test(tag)) {
        return buffer.raw().toString();
      } else {
        return buffer.error('Decoding of string type: ' + tag + ' unsupported');
      }
    };
    
    DERNode.prototype._decodeObjid = function decodeObjid(buffer, values, relative) {
      let result;
      const identifiers = [];
      let ident = 0;
      let subident = 0;
      while (!buffer.isEmpty()) {
        subident = buffer.readUInt8();
        ident <<= 7;
        ident |= subident & 0x7f;
        if ((subident & 0x80) === 0) {
          identifiers.push(ident);
          ident = 0;
        }
      }
      if (subident & 0x80)
        identifiers.push(ident);
    
      const first = (identifiers[0] / 40) | 0;
      const second = identifiers[0] % 40;
    
      if (relative)
        result = identifiers;
      else
        result = [first, second].concat(identifiers.slice(1));
    
      if (values) {
        let tmp = values[result.join(' ')];
        if (tmp === undefined)
          tmp = values[result.join('.')];
        if (tmp !== undefined)
          result = tmp;
      }
    
      return result;
    };
    
    DERNode.prototype._decodeTime = function decodeTime(buffer, tag) {
      const str = buffer.raw().toString();
    
      let year;
      let mon;
      let day;
      let hour;
      let min;
      let sec;
      if (tag === 'gentime') {
        year = str.slice(0, 4) | 0;
        mon = str.slice(4, 6) | 0;
        day = str.slice(6, 8) | 0;
        hour = str.slice(8, 10) | 0;
        min = str.slice(10, 12) | 0;
        sec = str.slice(12, 14) | 0;
      } else if (tag === 'utctime') {
        year = str.slice(0, 2) | 0;
        mon = str.slice(2, 4) | 0;
        day = str.slice(4, 6) | 0;
        hour = str.slice(6, 8) | 0;
        min = str.slice(8, 10) | 0;
        sec = str.slice(10, 12) | 0;
        if (year < 70)
          year = 2000 + year;
        else
          year = 1900 + year;
      } else {
        return buffer.error('Decoding ' + tag + ' time is not supported yet');
      }
    
      return Date.UTC(year, mon - 1, day, hour, min, sec, 0);
    };
    
    DERNode.prototype._decodeNull = function decodeNull() {
      return null;
    };
    
    DERNode.prototype._decodeBool = function decodeBool(buffer) {
      const res = buffer.readUInt8();
      if (buffer.isError(res))
        return res;
      else
        return res !== 0;
    };
    
    DERNode.prototype._decodeInt = function decodeInt(buffer, values) {
      // Bigint, return as it is (assume big endian)
      const raw = buffer.raw();
      let res = new bignum(raw);
    
      if (values)
        res = values[res.toString(10)] || res;
    
      return res;
    };
    
    DERNode.prototype._use = function use(entity, obj) {
      if (typeof entity === 'function')
        entity = entity(obj);
      return entity._getDecoder('der').tree;
    };
    
    // Utility methods
    
    function derDecodeTag(buf, fail) {
      let tag = buf.readUInt8(fail);
      if (buf.isError(tag))
        return tag;
    
      const cls = der.tagClass[tag >> 6];
      const primitive = (tag & 0x20) === 0;
    
      // Multi-octet tag - load
      if ((tag & 0x1f) === 0x1f) {
        let oct = tag;
        tag = 0;
        while ((oct & 0x80) === 0x80) {
          oct = buf.readUInt8(fail);
          if (buf.isError(oct))
            return oct;
    
          tag <<= 7;
          tag |= oct & 0x7f;
        }
      } else {
        tag &= 0x1f;
      }
      const tagStr = der.tag[tag];
    
      return {
        cls: cls,
        primitive: primitive,
        tag: tag,
        tagStr: tagStr
      };
    }
    
    function derDecodeLen(buf, primitive, fail) {
      let len = buf.readUInt8(fail);
      if (buf.isError(len))
        return len;
    
      // Indefinite form
      if (!primitive && len === 0x80)
        return null;
    
      // Definite form
      if ((len & 0x80) === 0) {
        // Short form
        return len;
      }
    
      // Long form
      const num = len & 0x7f;
      if (num > 4)
        return buf.error('length octect is too long');
    
      len = 0;
      for (let i = 0; i < num; i++) {
        len <<= 8;
        const j = buf.readUInt8(fail);
        if (buf.isError(j))
          return j;
        len |= j;
      }
    
      return len;
    }
    
    },{"../base/buffer":3,"../base/node":5,"../constants/der":7,"bn.js":15,"inherits":149}],10:[function(require,module,exports){
    'use strict';
    
    const decoders = exports;
    
    decoders.der = require('./der');
    decoders.pem = require('./pem');
    
    },{"./der":9,"./pem":11}],11:[function(require,module,exports){
    'use strict';
    
    const inherits = require('inherits');
    const Buffer = require('safer-buffer').Buffer;
    
    const DERDecoder = require('./der');
    
    function PEMDecoder(entity) {
      DERDecoder.call(this, entity);
      this.enc = 'pem';
    }
    inherits(PEMDecoder, DERDecoder);
    module.exports = PEMDecoder;
    
    PEMDecoder.prototype.decode = function decode(data, options) {
      const lines = data.toString().split(/[\r\n]+/g);
    
      const label = options.label.toUpperCase();
    
      const re = /^-----(BEGIN|END) ([^-]+)-----$/;
      let start = -1;
      let end = -1;
      for (let i = 0; i < lines.length; i++) {
        const match = lines[i].match(re);
        if (match === null)
          continue;
    
        if (match[2] !== label)
          continue;
    
        if (start === -1) {
          if (match[1] !== 'BEGIN')
            break;
          start = i;
        } else {
          if (match[1] !== 'END')
            break;
          end = i;
          break;
        }
      }
      if (start === -1 || end === -1)
        throw new Error('PEM section not found for: ' + label);
    
      const base64 = lines.slice(start + 1, end).join('');
      // Remove excessive symbols
      base64.replace(/[^a-z0-9+/=]+/gi, '');
    
      const input = Buffer.from(base64, 'base64');
      return DERDecoder.prototype.decode.call(this, input, options);
    };
    
    },{"./der":9,"inherits":149,"safer-buffer":188}],12:[function(require,module,exports){
    'use strict';
    
    const inherits = require('inherits');
    const Buffer = require('safer-buffer').Buffer;
    const Node = require('../base/node');
    
    // Import DER constants
    const der = require('../constants/der');
    
    function DEREncoder(entity) {
      this.enc = 'der';
      this.name = entity.name;
      this.entity = entity;
    
      // Construct base tree
      this.tree = new DERNode();
      this.tree._init(entity.body);
    }
    module.exports = DEREncoder;
    
    DEREncoder.prototype.encode = function encode(data, reporter) {
      return this.tree._encode(data, reporter).join();
    };
    
    // Tree methods
    
    function DERNode(parent) {
      Node.call(this, 'der', parent);
    }
    inherits(DERNode, Node);
    
    DERNode.prototype._encodeComposite = function encodeComposite(tag,
      primitive,
      cls,
      content) {
      const encodedTag = encodeTag(tag, primitive, cls, this.reporter);
    
      // Short form
      if (content.length < 0x80) {
        const header = Buffer.alloc(2);
        header[0] = encodedTag;
        header[1] = content.length;
        return this._createEncoderBuffer([ header, content ]);
      }
    
      // Long form
      // Count octets required to store length
      let lenOctets = 1;
      for (let i = content.length; i >= 0x100; i >>= 8)
        lenOctets++;
    
      const header = Buffer.alloc(1 + 1 + lenOctets);
      header[0] = encodedTag;
      header[1] = 0x80 | lenOctets;
    
      for (let i = 1 + lenOctets, j = content.length; j > 0; i--, j >>= 8)
        header[i] = j & 0xff;
    
      return this._createEncoderBuffer([ header, content ]);
    };
    
    DERNode.prototype._encodeStr = function encodeStr(str, tag) {
      if (tag === 'bitstr') {
        return this._createEncoderBuffer([ str.unused | 0, str.data ]);
      } else if (tag === 'bmpstr') {
        const buf = Buffer.alloc(str.length * 2);
        for (let i = 0; i < str.length; i++) {
          buf.writeUInt16BE(str.charCodeAt(i), i * 2);
        }
        return this._createEncoderBuffer(buf);
      } else if (tag === 'numstr') {
        if (!this._isNumstr(str)) {
          return this.reporter.error('Encoding of string type: numstr supports ' +
                                     'only digits and space');
        }
        return this._createEncoderBuffer(str);
      } else if (tag === 'printstr') {
        if (!this._isPrintstr(str)) {
          return this.reporter.error('Encoding of string type: printstr supports ' +
                                     'only latin upper and lower case letters, ' +
                                     'digits, space, apostrophe, left and rigth ' +
                                     'parenthesis, plus sign, comma, hyphen, ' +
                                     'dot, slash, colon, equal sign, ' +
                                     'question mark');
        }
        return this._createEncoderBuffer(str);
      } else if (/str$/.test(tag)) {
        return this._createEncoderBuffer(str);
      } else if (tag === 'objDesc') {
        return this._createEncoderBuffer(str);
      } else {
        return this.reporter.error('Encoding of string type: ' + tag +
                                   ' unsupported');
      }
    };
    
    DERNode.prototype._encodeObjid = function encodeObjid(id, values, relative) {
      if (typeof id === 'string') {
        if (!values)
          return this.reporter.error('string objid given, but no values map found');
        if (!values.hasOwnProperty(id))
          return this.reporter.error('objid not found in values map');
        id = values[id].split(/[\s.]+/g);
        for (let i = 0; i < id.length; i++)
          id[i] |= 0;
      } else if (Array.isArray(id)) {
        id = id.slice();
        for (let i = 0; i < id.length; i++)
          id[i] |= 0;
      }
    
      if (!Array.isArray(id)) {
        return this.reporter.error('objid() should be either array or string, ' +
                                   'got: ' + JSON.stringify(id));
      }
    
      if (!relative) {
        if (id[1] >= 40)
          return this.reporter.error('Second objid identifier OOB');
        id.splice(0, 2, id[0] * 40 + id[1]);
      }
    
      // Count number of octets
      let size = 0;
      for (let i = 0; i < id.length; i++) {
        let ident = id[i];
        for (size++; ident >= 0x80; ident >>= 7)
          size++;
      }
    
      const objid = Buffer.alloc(size);
      let offset = objid.length - 1;
      for (let i = id.length - 1; i >= 0; i--) {
        let ident = id[i];
        objid[offset--] = ident & 0x7f;
        while ((ident >>= 7) > 0)
          objid[offset--] = 0x80 | (ident & 0x7f);
      }
    
      return this._createEncoderBuffer(objid);
    };
    
    function two(num) {
      if (num < 10)
        return '0' + num;
      else
        return num;
    }
    
    DERNode.prototype._encodeTime = function encodeTime(time, tag) {
      let str;
      const date = new Date(time);
    
      if (tag === 'gentime') {
        str = [
          two(date.getUTCFullYear()),
          two(date.getUTCMonth() + 1),
          two(date.getUTCDate()),
          two(date.getUTCHours()),
          two(date.getUTCMinutes()),
          two(date.getUTCSeconds()),
          'Z'
        ].join('');
      } else if (tag === 'utctime') {
        str = [
          two(date.getUTCFullYear() % 100),
          two(date.getUTCMonth() + 1),
          two(date.getUTCDate()),
          two(date.getUTCHours()),
          two(date.getUTCMinutes()),
          two(date.getUTCSeconds()),
          'Z'
        ].join('');
      } else {
        this.reporter.error('Encoding ' + tag + ' time is not supported yet');
      }
    
      return this._encodeStr(str, 'octstr');
    };
    
    DERNode.prototype._encodeNull = function encodeNull() {
      return this._createEncoderBuffer('');
    };
    
    DERNode.prototype._encodeInt = function encodeInt(num, values) {
      if (typeof num === 'string') {
        if (!values)
          return this.reporter.error('String int or enum given, but no values map');
        if (!values.hasOwnProperty(num)) {
          return this.reporter.error('Values map doesn\'t contain: ' +
                                     JSON.stringify(num));
        }
        num = values[num];
      }
    
      // Bignum, assume big endian
      if (typeof num !== 'number' && !Buffer.isBuffer(num)) {
        const numArray = num.toArray();
        if (!num.sign && numArray[0] & 0x80) {
          numArray.unshift(0);
        }
        num = Buffer.from(numArray);
      }
    
      if (Buffer.isBuffer(num)) {
        let size = num.length;
        if (num.length === 0)
          size++;
    
        const out = Buffer.alloc(size);
        num.copy(out);
        if (num.length === 0)
          out[0] = 0;
        return this._createEncoderBuffer(out);
      }
    
      if (num < 0x80)
        return this._createEncoderBuffer(num);
    
      if (num < 0x100)
        return this._createEncoderBuffer([0, num]);
    
      let size = 1;
      for (let i = num; i >= 0x100; i >>= 8)
        size++;
    
      const out = new Array(size);
      for (let i = out.length - 1; i >= 0; i--) {
        out[i] = num & 0xff;
        num >>= 8;
      }
      if(out[0] & 0x80) {
        out.unshift(0);
      }
    
      return this._createEncoderBuffer(Buffer.from(out));
    };
    
    DERNode.prototype._encodeBool = function encodeBool(value) {
      return this._createEncoderBuffer(value ? 0xff : 0);
    };
    
    DERNode.prototype._use = function use(entity, obj) {
      if (typeof entity === 'function')
        entity = entity(obj);
      return entity._getEncoder('der').tree;
    };
    
    DERNode.prototype._skipDefault = function skipDefault(dataBuffer, reporter, parent) {
      const state = this._baseState;
      let i;
      if (state['default'] === null)
        return false;
    
      const data = dataBuffer.join();
      if (state.defaultBuffer === undefined)
        state.defaultBuffer = this._encodeValue(state['default'], reporter, parent).join();
    
      if (data.length !== state.defaultBuffer.length)
        return false;
    
      for (i=0; i < data.length; i++)
        if (data[i] !== state.defaultBuffer[i])
          return false;
    
      return true;
    };
    
    // Utility methods
    
    function encodeTag(tag, primitive, cls, reporter) {
      let res;
    
      if (tag === 'seqof')
        tag = 'seq';
      else if (tag === 'setof')
        tag = 'set';
    
      if (der.tagByName.hasOwnProperty(tag))
        res = der.tagByName[tag];
      else if (typeof tag === 'number' && (tag | 0) === tag)
        res = tag;
      else
        return reporter.error('Unknown tag: ' + tag);
    
      if (res >= 0x1f)
        return reporter.error('Multi-octet tag encoding unsupported');
    
      if (!primitive)
        res |= 0x20;
    
      res |= (der.tagClassByName[cls || 'universal'] << 6);
    
      return res;
    }
    
    },{"../base/node":5,"../constants/der":7,"inherits":149,"safer-buffer":188}],13:[function(require,module,exports){
    'use strict';
    
    const encoders = exports;
    
    encoders.der = require('./der');
    encoders.pem = require('./pem');
    
    },{"./der":12,"./pem":14}],14:[function(require,module,exports){
    'use strict';
    
    const inherits = require('inherits');
    
    const DEREncoder = require('./der');
    
    function PEMEncoder(entity) {
      DEREncoder.call(this, entity);
      this.enc = 'pem';
    }
    inherits(PEMEncoder, DEREncoder);
    module.exports = PEMEncoder;
    
    PEMEncoder.prototype.encode = function encode(data, options) {
      const buf = DEREncoder.prototype.encode.call(this, data);
    
      const p = buf.toString('base64');
      const out = [ '-----BEGIN ' + options.label + '-----' ];
      for (let i = 0; i < p.length; i += 64)
        out.push(p.slice(i, i + 64));
      out.push('-----END ' + options.label + '-----');
      return out.join('\n');
    };
    
    },{"./der":12,"inherits":149}],15:[function(require,module,exports){
    (function (module, exports) {
      'use strict';
    
      // Utils
      function assert (val, msg) {
        if (!val) throw new Error(msg || 'Assertion failed');
      }
    
      // Could use `inherits` module, but don't want to move from single file
      // architecture yet.
      function inherits (ctor, superCtor) {
        ctor.super_ = superCtor;
        var TempCtor = function () {};
        TempCtor.prototype = superCtor.prototype;
        ctor.prototype = new TempCtor();
        ctor.prototype.constructor = ctor;
      }
    
      // BN
    
      function BN (number, base, endian) {
        if (BN.isBN(number)) {
          return number;
        }
    
        this.negative = 0;
        this.words = null;
        this.length = 0;
    
        // Reduction context
        this.red = null;
    
        if (number !== null) {
          if (base === 'le' || base === 'be') {
            endian = base;
            base = 10;
          }
    
          this._init(number || 0, base || 10, endian || 'be');
        }
      }
      if (typeof module === 'object') {
        module.exports = BN;
      } else {
        exports.BN = BN;
      }
    
      BN.BN = BN;
      BN.wordSize = 26;
    
      var Buffer;
      try {
        if (typeof window !== 'undefined' && typeof window.Buffer !== 'undefined') {
          Buffer = window.Buffer;
        } else {
          Buffer = require('buffer').Buffer;
        }
      } catch (e) {
      }
    
      BN.isBN = function isBN (num) {
        if (num instanceof BN) {
          return true;
        }
    
        return num !== null && typeof num === 'object' &&
          num.constructor.wordSize === BN.wordSize && Array.isArray(num.words);
      };
    
      BN.max = function max (left, right) {
        if (left.cmp(right) > 0) return left;
        return right;
      };
    
      BN.min = function min (left, right) {
        if (left.cmp(right) < 0) return left;
        return right;
      };
    
      BN.prototype._init = function init (number, base, endian) {
        if (typeof number === 'number') {
          return this._initNumber(number, base, endian);
        }
    
        if (typeof number === 'object') {
          return this._initArray(number, base, endian);
        }
    
        if (base === 'hex') {
          base = 16;
        }
        assert(base === (base | 0) && base >= 2 && base <= 36);
    
        number = number.toString().replace(/\s+/g, '');
        var start = 0;
        if (number[0] === '-') {
          start++;
          this.negative = 1;
        }
    
        if (start < number.length) {
          if (base === 16) {
            this._parseHex(number, start, endian);
          } else {
            this._parseBase(number, base, start);
            if (endian === 'le') {
              this._initArray(this.toArray(), base, endian);
            }
          }
        }
      };
    
      BN.prototype._initNumber = function _initNumber (number, base, endian) {
        if (number < 0) {
          this.negative = 1;
          number = -number;
        }
        if (number < 0x4000000) {
          this.words = [ number & 0x3ffffff ];
          this.length = 1;
        } else if (number < 0x10000000000000) {
          this.words = [
            number & 0x3ffffff,
            (number / 0x4000000) & 0x3ffffff
          ];
          this.length = 2;
        } else {
          assert(number < 0x20000000000000); // 2 ^ 53 (unsafe)
          this.words = [
            number & 0x3ffffff,
            (number / 0x4000000) & 0x3ffffff,
            1
          ];
          this.length = 3;
        }
    
        if (endian !== 'le') return;
    
        // Reverse the bytes
        this._initArray(this.toArray(), base, endian);
      };
    
      BN.prototype._initArray = function _initArray (number, base, endian) {
        // Perhaps a Uint8Array
        assert(typeof number.length === 'number');
        if (number.length <= 0) {
          this.words = [ 0 ];
          this.length = 1;
          return this;
        }
    
        this.length = Math.ceil(number.length / 3);
        this.words = new Array(this.length);
        for (var i = 0; i < this.length; i++) {
          this.words[i] = 0;
        }
    
        var j, w;
        var off = 0;
        if (endian === 'be') {
          for (i = number.length - 1, j = 0; i >= 0; i -= 3) {
            w = number[i] | (number[i - 1] << 8) | (number[i - 2] << 16);
            this.words[j] |= (w << off) & 0x3ffffff;
            this.words[j + 1] = (w >>> (26 - off)) & 0x3ffffff;
            off += 24;
            if (off >= 26) {
              off -= 26;
              j++;
            }
          }
        } else if (endian === 'le') {
          for (i = 0, j = 0; i < number.length; i += 3) {
            w = number[i] | (number[i + 1] << 8) | (number[i + 2] << 16);
            this.words[j] |= (w << off) & 0x3ffffff;
            this.words[j + 1] = (w >>> (26 - off)) & 0x3ffffff;
            off += 24;
            if (off >= 26) {
              off -= 26;
              j++;
            }
          }
        }
        return this.strip();
      };
    
      function parseHex4Bits (string, index) {
        var c = string.charCodeAt(index);
        // 'A' - 'F'
        if (c >= 65 && c <= 70) {
          return c - 55;
        // 'a' - 'f'
        } else if (c >= 97 && c <= 102) {
          return c - 87;
        // '0' - '9'
        } else {
          return (c - 48) & 0xf;
        }
      }
    
      function parseHexByte (string, lowerBound, index) {
        var r = parseHex4Bits(string, index);
        if (index - 1 >= lowerBound) {
          r |= parseHex4Bits(string, index - 1) << 4;
        }
        return r;
      }
    
      BN.prototype._parseHex = function _parseHex (number, start, endian) {
        // Create possibly bigger array to ensure that it fits the number
        this.length = Math.ceil((number.length - start) / 6);
        this.words = new Array(this.length);
        for (var i = 0; i < this.length; i++) {
          this.words[i] = 0;
        }
    
        // 24-bits chunks
        var off = 0;
        var j = 0;
    
        var w;
        if (endian === 'be') {
          for (i = number.length - 1; i >= start; i -= 2) {
            w = parseHexByte(number, start, i) << off;
            this.words[j] |= w & 0x3ffffff;
            if (off >= 18) {
              off -= 18;
              j += 1;
              this.words[j] |= w >>> 26;
            } else {
              off += 8;
            }
          }
        } else {
          var parseLength = number.length - start;
          for (i = parseLength % 2 === 0 ? start + 1 : start; i < number.length; i += 2) {
            w = parseHexByte(number, start, i) << off;
            this.words[j] |= w & 0x3ffffff;
            if (off >= 18) {
              off -= 18;
              j += 1;
              this.words[j] |= w >>> 26;
            } else {
              off += 8;
            }
          }
        }
    
        this.strip();
      };
    
      function parseBase (str, start, end, mul) {
        var r = 0;
        var len = Math.min(str.length, end);
        for (var i = start; i < len; i++) {
          var c = str.charCodeAt(i) - 48;
    
          r *= mul;
    
          // 'a'
          if (c >= 49) {
            r += c - 49 + 0xa;
    
          // 'A'
          } else if (c >= 17) {
            r += c - 17 + 0xa;
    
          // '0' - '9'
          } else {
            r += c;
          }
        }
        return r;
      }
    
      BN.prototype._parseBase = function _parseBase (number, base, start) {
        // Initialize as zero
        this.words = [ 0 ];
        this.length = 1;
    
        // Find length of limb in base
        for (var limbLen = 0, limbPow = 1; limbPow <= 0x3ffffff; limbPow *= base) {
          limbLen++;
        }
        limbLen--;
        limbPow = (limbPow / base) | 0;
    
        var total = number.length - start;
        var mod = total % limbLen;
        var end = Math.min(total, total - mod) + start;
    
        var word = 0;
        for (var i = start; i < end; i += limbLen) {
          word = parseBase(number, i, i + limbLen, base);
    
          this.imuln(limbPow);
          if (this.words[0] + word < 0x4000000) {
            this.words[0] += word;
          } else {
            this._iaddn(word);
          }
        }
    
        if (mod !== 0) {
          var pow = 1;
          word = parseBase(number, i, number.length, base);
    
          for (i = 0; i < mod; i++) {
            pow *= base;
          }
    
          this.imuln(pow);
          if (this.words[0] + word < 0x4000000) {
            this.words[0] += word;
          } else {
            this._iaddn(word);
          }
        }
    
        this.strip();
      };
    
      BN.prototype.copy = function copy (dest) {
        dest.words = new Array(this.length);
        for (var i = 0; i < this.length; i++) {
          dest.words[i] = this.words[i];
        }
        dest.length = this.length;
        dest.negative = this.negative;
        dest.red = this.red;
      };
    
      BN.prototype.clone = function clone () {
        var r = new BN(null);
        this.copy(r);
        return r;
      };
    
      BN.prototype._expand = function _expand (size) {
        while (this.length < size) {
          this.words[this.length++] = 0;
        }
        return this;
      };
    
      // Remove leading `0` from `this`
      BN.prototype.strip = function strip () {
        while (this.length > 1 && this.words[this.length - 1] === 0) {
          this.length--;
        }
        return this._normSign();
      };
    
      BN.prototype._normSign = function _normSign () {
        // -0 = 0
        if (this.length === 1 && this.words[0] === 0) {
          this.negative = 0;
        }
        return this;
      };
    
      BN.prototype.inspect = function inspect () {
        return (this.red ? '<BN-R: ' : '<BN: ') + this.toString(16) + '>';
      };
    
      /*
    
      var zeros = [];
      var groupSizes = [];
      var groupBases = [];
    
      var s = '';
      var i = -1;
      while (++i < BN.wordSize) {
        zeros[i] = s;
        s += '0';
      }
      groupSizes[0] = 0;
      groupSizes[1] = 0;
      groupBases[0] = 0;
      groupBases[1] = 0;
      var base = 2 - 1;
      while (++base < 36 + 1) {
        var groupSize = 0;
        var groupBase = 1;
        while (groupBase < (1 << BN.wordSize) / base) {
          groupBase *= base;
          groupSize += 1;
        }
        groupSizes[base] = groupSize;
        groupBases[base] = groupBase;
      }
    
      */
    
      var zeros = [
        '',
        '0',
        '00',
        '000',
        '0000',
        '00000',
        '000000',
        '0000000',
        '00000000',
        '000000000',
        '0000000000',
        '00000000000',
        '000000000000',
        '0000000000000',
        '00000000000000',
        '000000000000000',
        '0000000000000000',
        '00000000000000000',
        '000000000000000000',
        '0000000000000000000',
        '00000000000000000000',
        '000000000000000000000',
        '0000000000000000000000',
        '00000000000000000000000',
        '000000000000000000000000',
        '0000000000000000000000000'
      ];
    
      var groupSizes = [
        0, 0,
        25, 16, 12, 11, 10, 9, 8,
        8, 7, 7, 7, 7, 6, 6,
        6, 6, 6, 6, 6, 5, 5,
        5, 5, 5, 5, 5, 5, 5,
        5, 5, 5, 5, 5, 5, 5
      ];
    
      var groupBases = [
        0, 0,
        33554432, 43046721, 16777216, 48828125, 60466176, 40353607, 16777216,
        43046721, 10000000, 19487171, 35831808, 62748517, 7529536, 11390625,
        16777216, 24137569, 34012224, 47045881, 64000000, 4084101, 5153632,
        6436343, 7962624, 9765625, 11881376, 14348907, 17210368, 20511149,
        24300000, 28629151, 33554432, 39135393, 45435424, 52521875, 60466176
      ];
    
      BN.prototype.toString = function toString (base, padding) {
        base = base || 10;
        padding = padding | 0 || 1;
    
        var out;
        if (base === 16 || base === 'hex') {
          out = '';
          var off = 0;
          var carry = 0;
          for (var i = 0; i < this.length; i++) {
            var w = this.words[i];
            var word = (((w << off) | carry) & 0xffffff).toString(16);
            carry = (w >>> (24 - off)) & 0xffffff;
            if (carry !== 0 || i !== this.length - 1) {
              out = zeros[6 - word.length] + word + out;
            } else {
              out = word + out;
            }
            off += 2;
            if (off >= 26) {
              off -= 26;
              i--;
            }
          }
          if (carry !== 0) {
            out = carry.toString(16) + out;
          }
          while (out.length % padding !== 0) {
            out = '0' + out;
          }
          if (this.negative !== 0) {
            out = '-' + out;
          }
          return out;
        }
    
        if (base === (base | 0) && base >= 2 && base <= 36) {
          // var groupSize = Math.floor(BN.wordSize * Math.LN2 / Math.log(base));
          var groupSize = groupSizes[base];
          // var groupBase = Math.pow(base, groupSize);
          var groupBase = groupBases[base];
          out = '';
          var c = this.clone();
          c.negative = 0;
          while (!c.isZero()) {
            var r = c.modn(groupBase).toString(base);
            c = c.idivn(groupBase);
    
            if (!c.isZero()) {
              out = zeros[groupSize - r.length] + r + out;
            } else {
              out = r + out;
            }
          }
          if (this.isZero()) {
            out = '0' + out;
          }
          while (out.length % padding !== 0) {
            out = '0' + out;
          }
          if (this.negative !== 0) {
            out = '-' + out;
          }
          return out;
        }
    
        assert(false, 'Base should be between 2 and 36');
      };
    
      BN.prototype.toNumber = function toNumber () {
        var ret = this.words[0];
        if (this.length === 2) {
          ret += this.words[1] * 0x4000000;
        } else if (this.length === 3 && this.words[2] === 0x01) {
          // NOTE: at this stage it is known that the top bit is set
          ret += 0x10000000000000 + (this.words[1] * 0x4000000);
        } else if (this.length > 2) {
          assert(false, 'Number can only safely store up to 53 bits');
        }
        return (this.negative !== 0) ? -ret : ret;
      };
    
      BN.prototype.toJSON = function toJSON () {
        return this.toString(16);
      };
    
      BN.prototype.toBuffer = function toBuffer (endian, length) {
        assert(typeof Buffer !== 'undefined');
        return this.toArrayLike(Buffer, endian, length);
      };
    
      BN.prototype.toArray = function toArray (endian, length) {
        return this.toArrayLike(Array, endian, length);
      };
    
      BN.prototype.toArrayLike = function toArrayLike (ArrayType, endian, length) {
        var byteLength = this.byteLength();
        var reqLength = length || Math.max(1, byteLength);
        assert(byteLength <= reqLength, 'byte array longer than desired length');
        assert(reqLength > 0, 'Requested array length <= 0');
    
        this.strip();
        var littleEndian = endian === 'le';
        var res = new ArrayType(reqLength);
    
        var b, i;
        var q = this.clone();
        if (!littleEndian) {
          // Assume big-endian
          for (i = 0; i < reqLength - byteLength; i++) {
            res[i] = 0;
          }
    
          for (i = 0; !q.isZero(); i++) {
            b = q.andln(0xff);
            q.iushrn(8);
    
            res[reqLength - i - 1] = b;
          }
        } else {
          for (i = 0; !q.isZero(); i++) {
            b = q.andln(0xff);
            q.iushrn(8);
    
            res[i] = b;
          }
    
          for (; i < reqLength; i++) {
            res[i] = 0;
          }
        }
    
        return res;
      };
    
      if (Math.clz32) {
        BN.prototype._countBits = function _countBits (w) {
          return 32 - Math.clz32(w);
        };
      } else {
        BN.prototype._countBits = function _countBits (w) {
          var t = w;
          var r = 0;
          if (t >= 0x1000) {
            r += 13;
            t >>>= 13;
          }
          if (t >= 0x40) {
            r += 7;
            t >>>= 7;
          }
          if (t >= 0x8) {
            r += 4;
            t >>>= 4;
          }
          if (t >= 0x02) {
            r += 2;
            t >>>= 2;
          }
          return r + t;
        };
      }
    
      BN.prototype._zeroBits = function _zeroBits (w) {
        // Short-cut
        if (w === 0) return 26;
    
        var t = w;
        var r = 0;
        if ((t & 0x1fff) === 0) {
          r += 13;
          t >>>= 13;
        }
        if ((t & 0x7f) === 0) {
          r += 7;
          t >>>= 7;
        }
        if ((t & 0xf) === 0) {
          r += 4;
          t >>>= 4;
        }
        if ((t & 0x3) === 0) {
          r += 2;
          t >>>= 2;
        }
        if ((t & 0x1) === 0) {
          r++;
        }
        return r;
      };
    
      // Return number of used bits in a BN
      BN.prototype.bitLength = function bitLength () {
        var w = this.words[this.length - 1];
        var hi = this._countBits(w);
        return (this.length - 1) * 26 + hi;
      };
    
      function toBitArray (num) {
        var w = new Array(num.bitLength());
    
        for (var bit = 0; bit < w.length; bit++) {
          var off = (bit / 26) | 0;
          var wbit = bit % 26;
    
          w[bit] = (num.words[off] & (1 << wbit)) >>> wbit;
        }
    
        return w;
      }
    
      // Number of trailing zero bits
      BN.prototype.zeroBits = function zeroBits () {
        if (this.isZero()) return 0;
    
        var r = 0;
        for (var i = 0; i < this.length; i++) {
          var b = this._zeroBits(this.words[i]);
          r += b;
          if (b !== 26) break;
        }
        return r;
      };
    
      BN.prototype.byteLength = function byteLength () {
        return Math.ceil(this.bitLength() / 8);
      };
    
      BN.prototype.toTwos = function toTwos (width) {
        if (this.negative !== 0) {
          return this.abs().inotn(width).iaddn(1);
        }
        return this.clone();
      };
    
      BN.prototype.fromTwos = function fromTwos (width) {
        if (this.testn(width - 1)) {
          return this.notn(width).iaddn(1).ineg();
        }
        return this.clone();
      };
    
      BN.prototype.isNeg = function isNeg () {
        return this.negative !== 0;
      };
    
      // Return negative clone of `this`
      BN.prototype.neg = function neg () {
        return this.clone().ineg();
      };
    
      BN.prototype.ineg = function ineg () {
        if (!this.isZero()) {
          this.negative ^= 1;
        }
    
        return this;
      };
    
      // Or `num` with `this` in-place
      BN.prototype.iuor = function iuor (num) {
        while (this.length < num.length) {
          this.words[this.length++] = 0;
        }
    
        for (var i = 0; i < num.length; i++) {
          this.words[i] = this.words[i] | num.words[i];
        }
    
        return this.strip();
      };
    
      BN.prototype.ior = function ior (num) {
        assert((this.negative | num.negative) === 0);
        return this.iuor(num);
      };
    
      // Or `num` with `this`
      BN.prototype.or = function or (num) {
        if (this.length > num.length) return this.clone().ior(num);
        return num.clone().ior(this);
      };
    
      BN.prototype.uor = function uor (num) {
        if (this.length > num.length) return this.clone().iuor(num);
        return num.clone().iuor(this);
      };
    
      // And `num` with `this` in-place
      BN.prototype.iuand = function iuand (num) {
        // b = min-length(num, this)
        var b;
        if (this.length > num.length) {
          b = num;
        } else {
          b = this;
        }
    
        for (var i = 0; i < b.length; i++) {
          this.words[i] = this.words[i] & num.words[i];
        }
    
        this.length = b.length;
    
        return this.strip();
      };
    
      BN.prototype.iand = function iand (num) {
        assert((this.negative | num.negative) === 0);
        return this.iuand(num);
      };
    
      // And `num` with `this`
      BN.prototype.and = function and (num) {
        if (this.length > num.length) return this.clone().iand(num);
        return num.clone().iand(this);
      };
    
      BN.prototype.uand = function uand (num) {
        if (this.length > num.length) return this.clone().iuand(num);
        return num.clone().iuand(this);
      };
    
      // Xor `num` with `this` in-place
      BN.prototype.iuxor = function iuxor (num) {
        // a.length > b.length
        var a;
        var b;
        if (this.length > num.length) {
          a = this;
          b = num;
        } else {
          a = num;
          b = this;
        }
    
        for (var i = 0; i < b.length; i++) {
          this.words[i] = a.words[i] ^ b.words[i];
        }
    
        if (this !== a) {
          for (; i < a.length; i++) {
            this.words[i] = a.words[i];
          }
        }
    
        this.length = a.length;
    
        return this.strip();
      };
    
      BN.prototype.ixor = function ixor (num) {
        assert((this.negative | num.negative) === 0);
        return this.iuxor(num);
      };
    
      // Xor `num` with `this`
      BN.prototype.xor = function xor (num) {
        if (this.length > num.length) return this.clone().ixor(num);
        return num.clone().ixor(this);
      };
    
      BN.prototype.uxor = function uxor (num) {
        if (this.length > num.length) return this.clone().iuxor(num);
        return num.clone().iuxor(this);
      };
    
      // Not ``this`` with ``width`` bitwidth
      BN.prototype.inotn = function inotn (width) {
        assert(typeof width === 'number' && width >= 0);
    
        var bytesNeeded = Math.ceil(width / 26) | 0;
        var bitsLeft = width % 26;
    
        // Extend the buffer with leading zeroes
        this._expand(bytesNeeded);
    
        if (bitsLeft > 0) {
          bytesNeeded--;
        }
    
        // Handle complete words
        for (var i = 0; i < bytesNeeded; i++) {
          this.words[i] = ~this.words[i] & 0x3ffffff;
        }
    
        // Handle the residue
        if (bitsLeft > 0) {
          this.words[i] = ~this.words[i] & (0x3ffffff >> (26 - bitsLeft));
        }
    
        // And remove leading zeroes
        return this.strip();
      };
    
      BN.prototype.notn = function notn (width) {
        return this.clone().inotn(width);
      };
    
      // Set `bit` of `this`
      BN.prototype.setn = function setn (bit, val) {
        assert(typeof bit === 'number' && bit >= 0);
    
        var off = (bit / 26) | 0;
        var wbit = bit % 26;
    
        this._expand(off + 1);
    
        if (val) {
          this.words[off] = this.words[off] | (1 << wbit);
        } else {
          this.words[off] = this.words[off] & ~(1 << wbit);
        }
    
        return this.strip();
      };
    
      // Add `num` to `this` in-place
      BN.prototype.iadd = function iadd (num) {
        var r;
    
        // negative + positive
        if (this.negative !== 0 && num.negative === 0) {
          this.negative = 0;
          r = this.isub(num);
          this.negative ^= 1;
          return this._normSign();
    
        // positive + negative
        } else if (this.negative === 0 && num.negative !== 0) {
          num.negative = 0;
          r = this.isub(num);
          num.negative = 1;
          return r._normSign();
        }
    
        // a.length > b.length
        var a, b;
        if (this.length > num.length) {
          a = this;
          b = num;
        } else {
          a = num;
          b = this;
        }
    
        var carry = 0;
        for (var i = 0; i < b.length; i++) {
          r = (a.words[i] | 0) + (b.words[i] | 0) + carry;
          this.words[i] = r & 0x3ffffff;
          carry = r >>> 26;
        }
        for (; carry !== 0 && i < a.length; i++) {
          r = (a.words[i] | 0) + carry;
          this.words[i] = r & 0x3ffffff;
          carry = r >>> 26;
        }
    
        this.length = a.length;
        if (carry !== 0) {
          this.words[this.length] = carry;
          this.length++;
        // Copy the rest of the words
        } else if (a !== this) {
          for (; i < a.length; i++) {
            this.words[i] = a.words[i];
          }
        }
    
        return this;
      };
    
      // Add `num` to `this`
      BN.prototype.add = function add (num) {
        var res;
        if (num.negative !== 0 && this.negative === 0) {
          num.negative = 0;
          res = this.sub(num);
          num.negative ^= 1;
          return res;
        } else if (num.negative === 0 && this.negative !== 0) {
          this.negative = 0;
          res = num.sub(this);
          this.negative = 1;
          return res;
        }
    
        if (this.length > num.length) return this.clone().iadd(num);
    
        return num.clone().iadd(this);
      };
    
      // Subtract `num` from `this` in-place
      BN.prototype.isub = function isub (num) {
        // this - (-num) = this + num
        if (num.negative !== 0) {
          num.negative = 0;
          var r = this.iadd(num);
          num.negative = 1;
          return r._normSign();
    
        // -this - num = -(this + num)
        } else if (this.negative !== 0) {
          this.negative = 0;
          this.iadd(num);
          this.negative = 1;
          return this._normSign();
        }
    
        // At this point both numbers are positive
        var cmp = this.cmp(num);
    
        // Optimization - zeroify
        if (cmp === 0) {
          this.negative = 0;
          this.length = 1;
          this.words[0] = 0;
          return this;
        }
    
        // a > b
        var a, b;
        if (cmp > 0) {
          a = this;
          b = num;
        } else {
          a = num;
          b = this;
        }
    
        var carry = 0;
        for (var i = 0; i < b.length; i++) {
          r = (a.words[i] | 0) - (b.words[i] | 0) + carry;
          carry = r >> 26;
          this.words[i] = r & 0x3ffffff;
        }
        for (; carry !== 0 && i < a.length; i++) {
          r = (a.words[i] | 0) + carry;
          carry = r >> 26;
          this.words[i] = r & 0x3ffffff;
        }
    
        // Copy rest of the words
        if (carry === 0 && i < a.length && a !== this) {
          for (; i < a.length; i++) {
            this.words[i] = a.words[i];
          }
        }
    
        this.length = Math.max(this.length, i);
    
        if (a !== this) {
          this.negative = 1;
        }
    
        return this.strip();
      };
    
      // Subtract `num` from `this`
      BN.prototype.sub = function sub (num) {
        return this.clone().isub(num);
      };
    
      function smallMulTo (self, num, out) {
        out.negative = num.negative ^ self.negative;
        var len = (self.length + num.length) | 0;
        out.length = len;
        len = (len - 1) | 0;
    
        // Peel one iteration (compiler can't do it, because of code complexity)
        var a = self.words[0] | 0;
        var b = num.words[0] | 0;
        var r = a * b;
    
        var lo = r & 0x3ffffff;
        var carry = (r / 0x4000000) | 0;
        out.words[0] = lo;
    
        for (var k = 1; k < len; k++) {
          // Sum all words with the same `i + j = k` and accumulate `ncarry`,
          // note that ncarry could be >= 0x3ffffff
          var ncarry = carry >>> 26;
          var rword = carry & 0x3ffffff;
          var maxJ = Math.min(k, num.length - 1);
          for (var j = Math.max(0, k - self.length + 1); j <= maxJ; j++) {
            var i = (k - j) | 0;
            a = self.words[i] | 0;
            b = num.words[j] | 0;
            r = a * b + rword;
            ncarry += (r / 0x4000000) | 0;
            rword = r & 0x3ffffff;
          }
          out.words[k] = rword | 0;
          carry = ncarry | 0;
        }
        if (carry !== 0) {
          out.words[k] = carry | 0;
        } else {
          out.length--;
        }
    
        return out.strip();
      }
    
      // TODO(indutny): it may be reasonable to omit it for users who don't need
      // to work with 256-bit numbers, otherwise it gives 20% improvement for 256-bit
      // multiplication (like elliptic secp256k1).
      var comb10MulTo = function comb10MulTo (self, num, out) {
        var a = self.words;
        var b = num.words;
        var o = out.words;
        var c = 0;
        var lo;
        var mid;
        var hi;
        var a0 = a[0] | 0;
        var al0 = a0 & 0x1fff;
        var ah0 = a0 >>> 13;
        var a1 = a[1] | 0;
        var al1 = a1 & 0x1fff;
        var ah1 = a1 >>> 13;
        var a2 = a[2] | 0;
        var al2 = a2 & 0x1fff;
        var ah2 = a2 >>> 13;
        var a3 = a[3] | 0;
        var al3 = a3 & 0x1fff;
        var ah3 = a3 >>> 13;
        var a4 = a[4] | 0;
        var al4 = a4 & 0x1fff;
        var ah4 = a4 >>> 13;
        var a5 = a[5] | 0;
        var al5 = a5 & 0x1fff;
        var ah5 = a5 >>> 13;
        var a6 = a[6] | 0;
        var al6 = a6 & 0x1fff;
        var ah6 = a6 >>> 13;
        var a7 = a[7] | 0;
        var al7 = a7 & 0x1fff;
        var ah7 = a7 >>> 13;
        var a8 = a[8] | 0;
        var al8 = a8 & 0x1fff;
        var ah8 = a8 >>> 13;
        var a9 = a[9] | 0;
        var al9 = a9 & 0x1fff;
        var ah9 = a9 >>> 13;
        var b0 = b[0] | 0;
        var bl0 = b0 & 0x1fff;
        var bh0 = b0 >>> 13;
        var b1 = b[1] | 0;
        var bl1 = b1 & 0x1fff;
        var bh1 = b1 >>> 13;
        var b2 = b[2] | 0;
        var bl2 = b2 & 0x1fff;
        var bh2 = b2 >>> 13;
        var b3 = b[3] | 0;
        var bl3 = b3 & 0x1fff;
        var bh3 = b3 >>> 13;
        var b4 = b[4] | 0;
        var bl4 = b4 & 0x1fff;
        var bh4 = b4 >>> 13;
        var b5 = b[5] | 0;
        var bl5 = b5 & 0x1fff;
        var bh5 = b5 >>> 13;
        var b6 = b[6] | 0;
        var bl6 = b6 & 0x1fff;
        var bh6 = b6 >>> 13;
        var b7 = b[7] | 0;
        var bl7 = b7 & 0x1fff;
        var bh7 = b7 >>> 13;
        var b8 = b[8] | 0;
        var bl8 = b8 & 0x1fff;
        var bh8 = b8 >>> 13;
        var b9 = b[9] | 0;
        var bl9 = b9 & 0x1fff;
        var bh9 = b9 >>> 13;
    
        out.negative = self.negative ^ num.negative;
        out.length = 19;
        /* k = 0 */
        lo = Math.imul(al0, bl0);
        mid = Math.imul(al0, bh0);
        mid = (mid + Math.imul(ah0, bl0)) | 0;
        hi = Math.imul(ah0, bh0);
        var w0 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
        c = (((hi + (mid >>> 13)) | 0) + (w0 >>> 26)) | 0;
        w0 &= 0x3ffffff;
        /* k = 1 */
        lo = Math.imul(al1, bl0);
        mid = Math.imul(al1, bh0);
        mid = (mid + Math.imul(ah1, bl0)) | 0;
        hi = Math.imul(ah1, bh0);
        lo = (lo + Math.imul(al0, bl1)) | 0;
        mid = (mid + Math.imul(al0, bh1)) | 0;
        mid = (mid + Math.imul(ah0, bl1)) | 0;
        hi = (hi + Math.imul(ah0, bh1)) | 0;
        var w1 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
        c = (((hi + (mid >>> 13)) | 0) + (w1 >>> 26)) | 0;
        w1 &= 0x3ffffff;
        /* k = 2 */
        lo = Math.imul(al2, bl0);
        mid = Math.imul(al2, bh0);
        mid = (mid + Math.imul(ah2, bl0)) | 0;
        hi = Math.imul(ah2, bh0);
        lo = (lo + Math.imul(al1, bl1)) | 0;
        mid = (mid + Math.imul(al1, bh1)) | 0;
        mid = (mid + Math.imul(ah1, bl1)) | 0;
        hi = (hi + Math.imul(ah1, bh1)) | 0;
        lo = (lo + Math.imul(al0, bl2)) | 0;
        mid = (mid + Math.imul(al0, bh2)) | 0;
        mid = (mid + Math.imul(ah0, bl2)) | 0;
        hi = (hi + Math.imul(ah0, bh2)) | 0;
        var w2 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
        c = (((hi + (mid >>> 13)) | 0) + (w2 >>> 26)) | 0;
        w2 &= 0x3ffffff;
        /* k = 3 */
        lo = Math.imul(al3, bl0);
        mid = Math.imul(al3, bh0);
        mid = (mid + Math.imul(ah3, bl0)) | 0;
        hi = Math.imul(ah3, bh0);
        lo = (lo + Math.imul(al2, bl1)) | 0;
        mid = (mid + Math.imul(al2, bh1)) | 0;
        mid = (mid + Math.imul(ah2, bl1)) | 0;
        hi = (hi + Math.imul(ah2, bh1)) | 0;
        lo = (lo + Math.imul(al1, bl2)) | 0;
        mid = (mid + Math.imul(al1, bh2)) | 0;
        mid = (mid + Math.imul(ah1, bl2)) | 0;
        hi = (hi + Math.imul(ah1, bh2)) | 0;
        lo = (lo + Math.imul(al0, bl3)) | 0;
        mid = (mid + Math.imul(al0, bh3)) | 0;
        mid = (mid + Math.imul(ah0, bl3)) | 0;
        hi = (hi + Math.imul(ah0, bh3)) | 0;
        var w3 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
        c = (((hi + (mid >>> 13)) | 0) + (w3 >>> 26)) | 0;
        w3 &= 0x3ffffff;
        /* k = 4 */
        lo = Math.imul(al4, bl0);
        mid = Math.imul(al4, bh0);
        mid = (mid + Math.imul(ah4, bl0)) | 0;
        hi = Math.imul(ah4, bh0);
        lo = (lo + Math.imul(al3, bl1)) | 0;
        mid = (mid + Math.imul(al3, bh1)) | 0;
        mid = (mid + Math.imul(ah3, bl1)) | 0;
        hi = (hi + Math.imul(ah3, bh1)) | 0;
        lo = (lo + Math.imul(al2, bl2)) | 0;
        mid = (mid + Math.imul(al2, bh2)) | 0;
        mid = (mid + Math.imul(ah2, bl2)) | 0;
        hi = (hi + Math.imul(ah2, bh2)) | 0;
        lo = (lo + Math.imul(al1, bl3)) | 0;
        mid = (mid + Math.imul(al1, bh3)) | 0;
        mid = (mid + Math.imul(ah1, bl3)) | 0;
        hi = (hi + Math.imul(ah1, bh3)) | 0;
        lo = (lo + Math.imul(al0, bl4)) | 0;
        mid = (mid + Math.imul(al0, bh4)) | 0;
        mid = (mid + Math.imul(ah0, bl4)) | 0;
        hi = (hi + Math.imul(ah0, bh4)) | 0;
        var w4 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
        c = (((hi + (mid >>> 13)) | 0) + (w4 >>> 26)) | 0;
        w4 &= 0x3ffffff;
        /* k = 5 */
        lo = Math.imul(al5, bl0);
        mid = Math.imul(al5, bh0);
        mid = (mid + Math.imul(ah5, bl0)) | 0;
        hi = Math.imul(ah5, bh0);
        lo = (lo + Math.imul(al4, bl1)) | 0;
        mid = (mid + Math.imul(al4, bh1)) | 0;
        mid = (mid + Math.imul(ah4, bl1)) | 0;
        hi = (hi + Math.imul(ah4, bh1)) | 0;
        lo = (lo + Math.imul(al3, bl2)) | 0;
        mid = (mid + Math.imul(al3, bh2)) | 0;
        mid = (mid + Math.imul(ah3, bl2)) | 0;
        hi = (hi + Math.imul(ah3, bh2)) | 0;
        lo = (lo + Math.imul(al2, bl3)) | 0;
        mid = (mid + Math.imul(al2, bh3)) | 0;
        mid = (mid + Math.imul(ah2, bl3)) | 0;
        hi = (hi + Math.imul(ah2, bh3)) | 0;
        lo = (lo + Math.imul(al1, bl4)) | 0;
        mid = (mid + Math.imul(al1, bh4)) | 0;
        mid = (mid + Math.imul(ah1, bl4)) | 0;
        hi = (hi + Math.imul(ah1, bh4)) | 0;
        lo = (lo + Math.imul(al0, bl5)) | 0;
        mid = (mid + Math.imul(al0, bh5)) | 0;
        mid = (mid + Math.imul(ah0, bl5)) | 0;
        hi = (hi + Math.imul(ah0, bh5)) | 0;
        var w5 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
        c = (((hi + (mid >>> 13)) | 0) + (w5 >>> 26)) | 0;
        w5 &= 0x3ffffff;
        /* k = 6 */
        lo = Math.imul(al6, bl0);
        mid = Math.imul(al6, bh0);
        mid = (mid + Math.imul(ah6, bl0)) | 0;
        hi = Math.imul(ah6, bh0);
        lo = (lo + Math.imul(al5, bl1)) | 0;
        mid = (mid + Math.imul(al5, bh1)) | 0;
        mid = (mid + Math.imul(ah5, bl1)) | 0;
        hi = (hi + Math.imul(ah5, bh1)) | 0;
        lo = (lo + Math.imul(al4, bl2)) | 0;
        mid = (mid + Math.imul(al4, bh2)) | 0;
        mid = (mid + Math.imul(ah4, bl2)) | 0;
        hi = (hi + Math.imul(ah4, bh2)) | 0;
        lo = (lo + Math.imul(al3, bl3)) | 0;
        mid = (mid + Math.imul(al3, bh3)) | 0;
        mid = (mid + Math.imul(ah3, bl3)) | 0;
        hi = (hi + Math.imul(ah3, bh3)) | 0;
        lo = (lo + Math.imul(al2, bl4)) | 0;
        mid = (mid + Math.imul(al2, bh4)) | 0;
        mid = (mid + Math.imul(ah2, bl4)) | 0;
        hi = (hi + Math.imul(ah2, bh4)) | 0;
        lo = (lo + Math.imul(al1, bl5)) | 0;
        mid = (mid + Math.imul(al1, bh5)) | 0;
        mid = (mid + Math.imul(ah1, bl5)) | 0;
        hi = (hi + Math.imul(ah1, bh5)) | 0;
        lo = (lo + Math.imul(al0, bl6)) | 0;
        mid = (mid + Math.imul(al0, bh6)) | 0;
        mid = (mid + Math.imul(ah0, bl6)) | 0;
        hi = (hi + Math.imul(ah0, bh6)) | 0;
        var w6 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
        c = (((hi + (mid >>> 13)) | 0) + (w6 >>> 26)) | 0;
        w6 &= 0x3ffffff;
        /* k = 7 */
        lo = Math.imul(al7, bl0);
        mid = Math.imul(al7, bh0);
        mid = (mid + Math.imul(ah7, bl0)) | 0;
        hi = Math.imul(ah7, bh0);
        lo = (lo + Math.imul(al6, bl1)) | 0;
        mid = (mid + Math.imul(al6, bh1)) | 0;
        mid = (mid + Math.imul(ah6, bl1)) | 0;
        hi = (hi + Math.imul(ah6, bh1)) | 0;
        lo = (lo + Math.imul(al5, bl2)) | 0;
        mid = (mid + Math.imul(al5, bh2)) | 0;
        mid = (mid + Math.imul(ah5, bl2)) | 0;
        hi = (hi + Math.imul(ah5, bh2)) | 0;
        lo = (lo + Math.imul(al4, bl3)) | 0;
        mid = (mid + Math.imul(al4, bh3)) | 0;
        mid = (mid + Math.imul(ah4, bl3)) | 0;
        hi = (hi + Math.imul(ah4, bh3)) | 0;
        lo = (lo + Math.imul(al3, bl4)) | 0;
        mid = (mid + Math.imul(al3, bh4)) | 0;
        mid = (mid + Math.imul(ah3, bl4)) | 0;
        hi = (hi + Math.imul(ah3, bh4)) | 0;
        lo = (lo + Math.imul(al2, bl5)) | 0;
        mid = (mid + Math.imul(al2, bh5)) | 0;
        mid = (mid + Math.imul(ah2, bl5)) | 0;
        hi = (hi + Math.imul(ah2, bh5)) | 0;
        lo = (lo + Math.imul(al1, bl6)) | 0;
        mid = (mid + Math.imul(al1, bh6)) | 0;
        mid = (mid + Math.imul(ah1, bl6)) | 0;
        hi = (hi + Math.imul(ah1, bh6)) | 0;
        lo = (lo + Math.imul(al0, bl7)) | 0;
        mid = (mid + Math.imul(al0, bh7)) | 0;
        mid = (mid + Math.imul(ah0, bl7)) | 0;
        hi = (hi + Math.imul(ah0, bh7)) | 0;
        var w7 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
        c = (((hi + (mid >>> 13)) | 0) + (w7 >>> 26)) | 0;
        w7 &= 0x3ffffff;
        /* k = 8 */
        lo = Math.imul(al8, bl0);
        mid = Math.imul(al8, bh0);
        mid = (mid + Math.imul(ah8, bl0)) | 0;
        hi = Math.imul(ah8, bh0);
        lo = (lo + Math.imul(al7, bl1)) | 0;
        mid = (mid + Math.imul(al7, bh1)) | 0;
        mid = (mid + Math.imul(ah7, bl1)) | 0;
        hi = (hi + Math.imul(ah7, bh1)) | 0;
        lo = (lo + Math.imul(al6, bl2)) | 0;
        mid = (mid + Math.imul(al6, bh2)) | 0;
        mid = (mid + Math.imul(ah6, bl2)) | 0;
        hi = (hi + Math.imul(ah6, bh2)) | 0;
        lo = (lo + Math.imul(al5, bl3)) | 0;
        mid = (mid + Math.imul(al5, bh3)) | 0;
        mid = (mid + Math.imul(ah5, bl3)) | 0;
        hi = (hi + Math.imul(ah5, bh3)) | 0;
        lo = (lo + Math.imul(al4, bl4)) | 0;
        mid = (mid + Math.imul(al4, bh4)) | 0;
        mid = (mid + Math.imul(ah4, bl4)) | 0;
        hi = (hi + Math.imul(ah4, bh4)) | 0;
        lo = (lo + Math.imul(al3, bl5)) | 0;
        mid = (mid + Math.imul(al3, bh5)) | 0;
        mid = (mid + Math.imul(ah3, bl5)) | 0;
        hi = (hi + Math.imul(ah3, bh5)) | 0;
        lo = (lo + Math.imul(al2, bl6)) | 0;
        mid = (mid + Math.imul(al2, bh6)) | 0;
        mid = (mid + Math.imul(ah2, bl6)) | 0;
        hi = (hi + Math.imul(ah2, bh6)) | 0;
        lo = (lo + Math.imul(al1, bl7)) | 0;
        mid = (mid + Math.imul(al1, bh7)) | 0;
        mid = (mid + Math.imul(ah1, bl7)) | 0;
        hi = (hi + Math.imul(ah1, bh7)) | 0;
        lo = (lo + Math.imul(al0, bl8)) | 0;
        mid = (mid + Math.imul(al0, bh8)) | 0;
        mid = (mid + Math.imul(ah0, bl8)) | 0;
        hi = (hi + Math.imul(ah0, bh8)) | 0;
        var w8 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
        c = (((hi + (mid >>> 13)) | 0) + (w8 >>> 26)) | 0;
        w8 &= 0x3ffffff;
        /* k = 9 */
        lo = Math.imul(al9, bl0);
        mid = Math.imul(al9, bh0);
        mid = (mid + Math.imul(ah9, bl0)) | 0;
        hi = Math.imul(ah9, bh0);
        lo = (lo + Math.imul(al8, bl1)) | 0;
        mid = (mid + Math.imul(al8, bh1)) | 0;
        mid = (mid + Math.imul(ah8, bl1)) | 0;
        hi = (hi + Math.imul(ah8, bh1)) | 0;
        lo = (lo + Math.imul(al7, bl2)) | 0;
        mid = (mid + Math.imul(al7, bh2)) | 0;
        mid = (mid + Math.imul(ah7, bl2)) | 0;
        hi = (hi + Math.imul(ah7, bh2)) | 0;
        lo = (lo + Math.imul(al6, bl3)) | 0;
        mid = (mid + Math.imul(al6, bh3)) | 0;
        mid = (mid + Math.imul(ah6, bl3)) | 0;
        hi = (hi + Math.imul(ah6, bh3)) | 0;
        lo = (lo + Math.imul(al5, bl4)) | 0;
        mid = (mid + Math.imul(al5, bh4)) | 0;
        mid = (mid + Math.imul(ah5, bl4)) | 0;
        hi = (hi + Math.imul(ah5, bh4)) | 0;
        lo = (lo + Math.imul(al4, bl5)) | 0;
        mid = (mid + Math.imul(al4, bh5)) | 0;
        mid = (mid + Math.imul(ah4, bl5)) | 0;
        hi = (hi + Math.imul(ah4, bh5)) | 0;
        lo = (lo + Math.imul(al3, bl6)) | 0;
        mid = (mid + Math.imul(al3, bh6)) | 0;
        mid = (mid + Math.imul(ah3, bl6)) | 0;
        hi = (hi + Math.imul(ah3, bh6)) | 0;
        lo = (lo + Math.imul(al2, bl7)) | 0;
        mid = (mid + Math.imul(al2, bh7)) | 0;
        mid = (mid + Math.imul(ah2, bl7)) | 0;
        hi = (hi + Math.imul(ah2, bh7)) | 0;
        lo = (lo + Math.imul(al1, bl8)) | 0;
        mid = (mid + Math.imul(al1, bh8)) | 0;
        mid = (mid + Math.imul(ah1, bl8)) | 0;
        hi = (hi + Math.imul(ah1, bh8)) | 0;
        lo = (lo + Math.imul(al0, bl9)) | 0;
        mid = (mid + Math.imul(al0, bh9)) | 0;
        mid = (mid + Math.imul(ah0, bl9)) | 0;
        hi = (hi + Math.imul(ah0, bh9)) | 0;
        var w9 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
        c = (((hi + (mid >>> 13)) | 0) + (w9 >>> 26)) | 0;
        w9 &= 0x3ffffff;
        /* k = 10 */
        lo = Math.imul(al9, bl1);
        mid = Math.imul(al9, bh1);
        mid = (mid + Math.imul(ah9, bl1)) | 0;
        hi = Math.imul(ah9, bh1);
        lo = (lo + Math.imul(al8, bl2)) | 0;
        mid = (mid + Math.imul(al8, bh2)) | 0;
        mid = (mid + Math.imul(ah8, bl2)) | 0;
        hi = (hi + Math.imul(ah8, bh2)) | 0;
        lo = (lo + Math.imul(al7, bl3)) | 0;
        mid = (mid + Math.imul(al7, bh3)) | 0;
        mid = (mid + Math.imul(ah7, bl3)) | 0;
        hi = (hi + Math.imul(ah7, bh3)) | 0;
        lo = (lo + Math.imul(al6, bl4)) | 0;
        mid = (mid + Math.imul(al6, bh4)) | 0;
        mid = (mid + Math.imul(ah6, bl4)) | 0;
        hi = (hi + Math.imul(ah6, bh4)) | 0;
        lo = (lo + Math.imul(al5, bl5)) | 0;
        mid = (mid + Math.imul(al5, bh5)) | 0;
        mid = (mid + Math.imul(ah5, bl5)) | 0;
        hi = (hi + Math.imul(ah5, bh5)) | 0;
        lo = (lo + Math.imul(al4, bl6)) | 0;
        mid = (mid + Math.imul(al4, bh6)) | 0;
        mid = (mid + Math.imul(ah4, bl6)) | 0;
        hi = (hi + Math.imul(ah4, bh6)) | 0;
        lo = (lo + Math.imul(al3, bl7)) | 0;
        mid = (mid + Math.imul(al3, bh7)) | 0;
        mid = (mid + Math.imul(ah3, bl7)) | 0;
        hi = (hi + Math.imul(ah3, bh7)) | 0;
        lo = (lo + Math.imul(al2, bl8)) | 0;
        mid = (mid + Math.imul(al2, bh8)) | 0;
        mid = (mid + Math.imul(ah2, bl8)) | 0;
        hi = (hi + Math.imul(ah2, bh8)) | 0;
        lo = (lo + Math.imul(al1, bl9)) | 0;
        mid = (mid + Math.imul(al1, bh9)) | 0;
        mid = (mid + Math.imul(ah1, bl9)) | 0;
        hi = (hi + Math.imul(ah1, bh9)) | 0;
        var w10 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
        c = (((hi + (mid >>> 13)) | 0) + (w10 >>> 26)) | 0;
        w10 &= 0x3ffffff;
        /* k = 11 */
        lo = Math.imul(al9, bl2);
        mid = Math.imul(al9, bh2);
        mid = (mid + Math.imul(ah9, bl2)) | 0;
        hi = Math.imul(ah9, bh2);
        lo = (lo + Math.imul(al8, bl3)) | 0;
        mid = (mid + Math.imul(al8, bh3)) | 0;
        mid = (mid + Math.imul(ah8, bl3)) | 0;
        hi = (hi + Math.imul(ah8, bh3)) | 0;
        lo = (lo + Math.imul(al7, bl4)) | 0;
        mid = (mid + Math.imul(al7, bh4)) | 0;
        mid = (mid + Math.imul(ah7, bl4)) | 0;
        hi = (hi + Math.imul(ah7, bh4)) | 0;
        lo = (lo + Math.imul(al6, bl5)) | 0;
        mid = (mid + Math.imul(al6, bh5)) | 0;
        mid = (mid + Math.imul(ah6, bl5)) | 0;
        hi = (hi + Math.imul(ah6, bh5)) | 0;
        lo = (lo + Math.imul(al5, bl6)) | 0;
        mid = (mid + Math.imul(al5, bh6)) | 0;
        mid = (mid + Math.imul(ah5, bl6)) | 0;
        hi = (hi + Math.imul(ah5, bh6)) | 0;
        lo = (lo + Math.imul(al4, bl7)) | 0;
        mid = (mid + Math.imul(al4, bh7)) | 0;
        mid = (mid + Math.imul(ah4, bl7)) | 0;
        hi = (hi + Math.imul(ah4, bh7)) | 0;
        lo = (lo + Math.imul(al3, bl8)) | 0;
        mid = (mid + Math.imul(al3, bh8)) | 0;
        mid = (mid + Math.imul(ah3, bl8)) | 0;
        hi = (hi + Math.imul(ah3, bh8)) | 0;
        lo = (lo + Math.imul(al2, bl9)) | 0;
        mid = (mid + Math.imul(al2, bh9)) | 0;
        mid = (mid + Math.imul(ah2, bl9)) | 0;
        hi = (hi + Math.imul(ah2, bh9)) | 0;
        var w11 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
        c = (((hi + (mid >>> 13)) | 0) + (w11 >>> 26)) | 0;
        w11 &= 0x3ffffff;
        /* k = 12 */
        lo = Math.imul(al9, bl3);
        mid = Math.imul(al9, bh3);
        mid = (mid + Math.imul(ah9, bl3)) | 0;
        hi = Math.imul(ah9, bh3);
        lo = (lo + Math.imul(al8, bl4)) | 0;
        mid = (mid + Math.imul(al8, bh4)) | 0;
        mid = (mid + Math.imul(ah8, bl4)) | 0;
        hi = (hi + Math.imul(ah8, bh4)) | 0;
        lo = (lo + Math.imul(al7, bl5)) | 0;
        mid = (mid + Math.imul(al7, bh5)) | 0;
        mid = (mid + Math.imul(ah7, bl5)) | 0;
        hi = (hi + Math.imul(ah7, bh5)) | 0;
        lo = (lo + Math.imul(al6, bl6)) | 0;
        mid = (mid + Math.imul(al6, bh6)) | 0;
        mid = (mid + Math.imul(ah6, bl6)) | 0;
        hi = (hi + Math.imul(ah6, bh6)) | 0;
        lo = (lo + Math.imul(al5, bl7)) | 0;
        mid = (mid + Math.imul(al5, bh7)) | 0;
        mid = (mid + Math.imul(ah5, bl7)) | 0;
        hi = (hi + Math.imul(ah5, bh7)) | 0;
        lo = (lo + Math.imul(al4, bl8)) | 0;
        mid = (mid + Math.imul(al4, bh8)) | 0;
        mid = (mid + Math.imul(ah4, bl8)) | 0;
        hi = (hi + Math.imul(ah4, bh8)) | 0;
        lo = (lo + Math.imul(al3, bl9)) | 0;
        mid = (mid + Math.imul(al3, bh9)) | 0;
        mid = (mid + Math.imul(ah3, bl9)) | 0;
        hi = (hi + Math.imul(ah3, bh9)) | 0;
        var w12 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
        c = (((hi + (mid >>> 13)) | 0) + (w12 >>> 26)) | 0;
        w12 &= 0x3ffffff;
        /* k = 13 */
        lo = Math.imul(al9, bl4);
        mid = Math.imul(al9, bh4);
        mid = (mid + Math.imul(ah9, bl4)) | 0;
        hi = Math.imul(ah9, bh4);
        lo = (lo + Math.imul(al8, bl5)) | 0;
        mid = (mid + Math.imul(al8, bh5)) | 0;
        mid = (mid + Math.imul(ah8, bl5)) | 0;
        hi = (hi + Math.imul(ah8, bh5)) | 0;
        lo = (lo + Math.imul(al7, bl6)) | 0;
        mid = (mid + Math.imul(al7, bh6)) | 0;
        mid = (mid + Math.imul(ah7, bl6)) | 0;
        hi = (hi + Math.imul(ah7, bh6)) | 0;
        lo = (lo + Math.imul(al6, bl7)) | 0;
        mid = (mid + Math.imul(al6, bh7)) | 0;
        mid = (mid + Math.imul(ah6, bl7)) | 0;
        hi = (hi + Math.imul(ah6, bh7)) | 0;
        lo = (lo + Math.imul(al5, bl8)) | 0;
        mid = (mid + Math.imul(al5, bh8)) | 0;
        mid = (mid + Math.imul(ah5, bl8)) | 0;
        hi = (hi + Math.imul(ah5, bh8)) | 0;
        lo = (lo + Math.imul(al4, bl9)) | 0;
        mid = (mid + Math.imul(al4, bh9)) | 0;
        mid = (mid + Math.imul(ah4, bl9)) | 0;
        hi = (hi + Math.imul(ah4, bh9)) | 0;
        var w13 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
        c = (((hi + (mid >>> 13)) | 0) + (w13 >>> 26)) | 0;
        w13 &= 0x3ffffff;
        /* k = 14 */
        lo = Math.imul(al9, bl5);
        mid = Math.imul(al9, bh5);
        mid = (mid + Math.imul(ah9, bl5)) | 0;
        hi = Math.imul(ah9, bh5);
        lo = (lo + Math.imul(al8, bl6)) | 0;
        mid = (mid + Math.imul(al8, bh6)) | 0;
        mid = (mid + Math.imul(ah8, bl6)) | 0;
        hi = (hi + Math.imul(ah8, bh6)) | 0;
        lo = (lo + Math.imul(al7, bl7)) | 0;
        mid = (mid + Math.imul(al7, bh7)) | 0;
        mid = (mid + Math.imul(ah7, bl7)) | 0;
        hi = (hi + Math.imul(ah7, bh7)) | 0;
        lo = (lo + Math.imul(al6, bl8)) | 0;
        mid = (mid + Math.imul(al6, bh8)) | 0;
        mid = (mid + Math.imul(ah6, bl8)) | 0;
        hi = (hi + Math.imul(ah6, bh8)) | 0;
        lo = (lo + Math.imul(al5, bl9)) | 0;
        mid = (mid + Math.imul(al5, bh9)) | 0;
        mid = (mid + Math.imul(ah5, bl9)) | 0;
        hi = (hi + Math.imul(ah5, bh9)) | 0;
        var w14 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
        c = (((hi + (mid >>> 13)) | 0) + (w14 >>> 26)) | 0;
        w14 &= 0x3ffffff;
        /* k = 15 */
        lo = Math.imul(al9, bl6);
        mid = Math.imul(al9, bh6);
        mid = (mid + Math.imul(ah9, bl6)) | 0;
        hi = Math.imul(ah9, bh6);
        lo = (lo + Math.imul(al8, bl7)) | 0;
        mid = (mid + Math.imul(al8, bh7)) | 0;
        mid = (mid + Math.imul(ah8, bl7)) | 0;
        hi = (hi + Math.imul(ah8, bh7)) | 0;
        lo = (lo + Math.imul(al7, bl8)) | 0;
        mid = (mid + Math.imul(al7, bh8)) | 0;
        mid = (mid + Math.imul(ah7, bl8)) | 0;
        hi = (hi + Math.imul(ah7, bh8)) | 0;
        lo = (lo + Math.imul(al6, bl9)) | 0;
        mid = (mid + Math.imul(al6, bh9)) | 0;
        mid = (mid + Math.imul(ah6, bl9)) | 0;
        hi = (hi + Math.imul(ah6, bh9)) | 0;
        var w15 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
        c = (((hi + (mid >>> 13)) | 0) + (w15 >>> 26)) | 0;
        w15 &= 0x3ffffff;
        /* k = 16 */
        lo = Math.imul(al9, bl7);
        mid = Math.imul(al9, bh7);
        mid = (mid + Math.imul(ah9, bl7)) | 0;
        hi = Math.imul(ah9, bh7);
        lo = (lo + Math.imul(al8, bl8)) | 0;
        mid = (mid + Math.imul(al8, bh8)) | 0;
        mid = (mid + Math.imul(ah8, bl8)) | 0;
        hi = (hi + Math.imul(ah8, bh8)) | 0;
        lo = (lo + Math.imul(al7, bl9)) | 0;
        mid = (mid + Math.imul(al7, bh9)) | 0;
        mid = (mid + Math.imul(ah7, bl9)) | 0;
        hi = (hi + Math.imul(ah7, bh9)) | 0;
        var w16 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
        c = (((hi + (mid >>> 13)) | 0) + (w16 >>> 26)) | 0;
        w16 &= 0x3ffffff;
        /* k = 17 */
        lo = Math.imul(al9, bl8);
        mid = Math.imul(al9, bh8);
        mid = (mid + Math.imul(ah9, bl8)) | 0;
        hi = Math.imul(ah9, bh8);
        lo = (lo + Math.imul(al8, bl9)) | 0;
        mid = (mid + Math.imul(al8, bh9)) | 0;
        mid = (mid + Math.imul(ah8, bl9)) | 0;
        hi = (hi + Math.imul(ah8, bh9)) | 0;
        var w17 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
        c = (((hi + (mid >>> 13)) | 0) + (w17 >>> 26)) | 0;
        w17 &= 0x3ffffff;
        /* k = 18 */
        lo = Math.imul(al9, bl9);
        mid = Math.imul(al9, bh9);
        mid = (mid + Math.imul(ah9, bl9)) | 0;
        hi = Math.imul(ah9, bh9);
        var w18 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
        c = (((hi + (mid >>> 13)) | 0) + (w18 >>> 26)) | 0;
        w18 &= 0x3ffffff;
        o[0] = w0;
        o[1] = w1;
        o[2] = w2;
        o[3] = w3;
        o[4] = w4;
        o[5] = w5;
        o[6] = w6;
        o[7] = w7;
        o[8] = w8;
        o[9] = w9;
        o[10] = w10;
        o[11] = w11;
        o[12] = w12;
        o[13] = w13;
        o[14] = w14;
        o[15] = w15;
        o[16] = w16;
        o[17] = w17;
        o[18] = w18;
        if (c !== 0) {
          o[19] = c;
          out.length++;
        }
        return out;
      };
    
      // Polyfill comb
      if (!Math.imul) {
        comb10MulTo = smallMulTo;
      }
    
      function bigMulTo (self, num, out) {
        out.negative = num.negative ^ self.negative;
        out.length = self.length + num.length;
    
        var carry = 0;
        var hncarry = 0;
        for (var k = 0; k < out.length - 1; k++) {
          // Sum all words with the same `i + j = k` and accumulate `ncarry`,
          // note that ncarry could be >= 0x3ffffff
          var ncarry = hncarry;
          hncarry = 0;
          var rword = carry & 0x3ffffff;
          var maxJ = Math.min(k, num.length - 1);
          for (var j = Math.max(0, k - self.length + 1); j <= maxJ; j++) {
            var i = k - j;
            var a = self.words[i] | 0;
            var b = num.words[j] | 0;
            var r = a * b;
    
            var lo = r & 0x3ffffff;
            ncarry = (ncarry + ((r / 0x4000000) | 0)) | 0;
            lo = (lo + rword) | 0;
            rword = lo & 0x3ffffff;
            ncarry = (ncarry + (lo >>> 26)) | 0;
    
            hncarry += ncarry >>> 26;
            ncarry &= 0x3ffffff;
          }
          out.words[k] = rword;
          carry = ncarry;
          ncarry = hncarry;
        }
        if (carry !== 0) {
          out.words[k] = carry;
        } else {
          out.length--;
        }
    
        return out.strip();
      }
    
      function jumboMulTo (self, num, out) {
        var fftm = new FFTM();
        return fftm.mulp(self, num, out);
      }
    
      BN.prototype.mulTo = function mulTo (num, out) {
        var res;
        var len = this.length + num.length;
        if (this.length === 10 && num.length === 10) {
          res = comb10MulTo(this, num, out);
        } else if (len < 63) {
          res = smallMulTo(this, num, out);
        } else if (len < 1024) {
          res = bigMulTo(this, num, out);
        } else {
          res = jumboMulTo(this, num, out);
        }
    
        return res;
      };
    
      // Cooley-Tukey algorithm for FFT
      // slightly revisited to rely on looping instead of recursion
    
      function FFTM (x, y) {
        this.x = x;
        this.y = y;
      }
    
      FFTM.prototype.makeRBT = function makeRBT (N) {
        var t = new Array(N);
        var l = BN.prototype._countBits(N) - 1;
        for (var i = 0; i < N; i++) {
          t[i] = this.revBin(i, l, N);
        }
    
        return t;
      };
    
      // Returns binary-reversed representation of `x`
      FFTM.prototype.revBin = function revBin (x, l, N) {
        if (x === 0 || x === N - 1) return x;
    
        var rb = 0;
        for (var i = 0; i < l; i++) {
          rb |= (x & 1) << (l - i - 1);
          x >>= 1;
        }
    
        return rb;
      };
    
      // Performs "tweedling" phase, therefore 'emulating'
      // behaviour of the recursive algorithm
      FFTM.prototype.permute = function permute (rbt, rws, iws, rtws, itws, N) {
        for (var i = 0; i < N; i++) {
          rtws[i] = rws[rbt[i]];
          itws[i] = iws[rbt[i]];
        }
      };
    
      FFTM.prototype.transform = function transform (rws, iws, rtws, itws, N, rbt) {
        this.permute(rbt, rws, iws, rtws, itws, N);
    
        for (var s = 1; s < N; s <<= 1) {
          var l = s << 1;
    
          var rtwdf = Math.cos(2 * Math.PI / l);
          var itwdf = Math.sin(2 * Math.PI / l);
    
          for (var p = 0; p < N; p += l) {
            var rtwdf_ = rtwdf;
            var itwdf_ = itwdf;
    
            for (var j = 0; j < s; j++) {
              var re = rtws[p + j];
              var ie = itws[p + j];
    
              var ro = rtws[p + j + s];
              var io = itws[p + j + s];
    
              var rx = rtwdf_ * ro - itwdf_ * io;
    
              io = rtwdf_ * io + itwdf_ * ro;
              ro = rx;
    
              rtws[p + j] = re + ro;
              itws[p + j] = ie + io;
    
              rtws[p + j + s] = re - ro;
              itws[p + j + s] = ie - io;
    
              /* jshint maxdepth : false */
              if (j !== l) {
                rx = rtwdf * rtwdf_ - itwdf * itwdf_;
    
                itwdf_ = rtwdf * itwdf_ + itwdf * rtwdf_;
                rtwdf_ = rx;
              }
            }
          }
        }
      };
    
      FFTM.prototype.guessLen13b = function guessLen13b (n, m) {
        var N = Math.max(m, n) | 1;
        var odd = N & 1;
        var i = 0;
        for (N = N / 2 | 0; N; N = N >>> 1) {
          i++;
        }
    
        return 1 << i + 1 + odd;
      };
    
      FFTM.prototype.conjugate = function conjugate (rws, iws, N) {
        if (N <= 1) return;
    
        for (var i = 0; i < N / 2; i++) {
          var t = rws[i];
    
          rws[i] = rws[N - i - 1];
          rws[N - i - 1] = t;
    
          t = iws[i];
    
          iws[i] = -iws[N - i - 1];
          iws[N - i - 1] = -t;
        }
      };
    
      FFTM.prototype.normalize13b = function normalize13b (ws, N) {
        var carry = 0;
        for (var i = 0; i < N / 2; i++) {
          var w = Math.round(ws[2 * i + 1] / N) * 0x2000 +
            Math.round(ws[2 * i] / N) +
            carry;
    
          ws[i] = w & 0x3ffffff;
    
          if (w < 0x4000000) {
            carry = 0;
          } else {
            carry = w / 0x4000000 | 0;
          }
        }
    
        return ws;
      };
    
      FFTM.prototype.convert13b = function convert13b (ws, len, rws, N) {
        var carry = 0;
        for (var i = 0; i < len; i++) {
          carry = carry + (ws[i] | 0);
    
          rws[2 * i] = carry & 0x1fff; carry = carry >>> 13;
          rws[2 * i + 1] = carry & 0x1fff; carry = carry >>> 13;
        }
    
        // Pad with zeroes
        for (i = 2 * len; i < N; ++i) {
          rws[i] = 0;
        }
    
        assert(carry === 0);
        assert((carry & ~0x1fff) === 0);
      };
    
      FFTM.prototype.stub = function stub (N) {
        var ph = new Array(N);
        for (var i = 0; i < N; i++) {
          ph[i] = 0;
        }
    
        return ph;
      };
    
      FFTM.prototype.mulp = function mulp (x, y, out) {
        var N = 2 * this.guessLen13b(x.length, y.length);
    
        var rbt = this.makeRBT(N);
    
        var _ = this.stub(N);
    
        var rws = new Array(N);
        var rwst = new Array(N);
        var iwst = new Array(N);
    
        var nrws = new Array(N);
        var nrwst = new Array(N);
        var niwst = new Array(N);
    
        var rmws = out.words;
        rmws.length = N;
    
        this.convert13b(x.words, x.length, rws, N);
        this.convert13b(y.words, y.length, nrws, N);
    
        this.transform(rws, _, rwst, iwst, N, rbt);
        this.transform(nrws, _, nrwst, niwst, N, rbt);
    
        for (var i = 0; i < N; i++) {
          var rx = rwst[i] * nrwst[i] - iwst[i] * niwst[i];
          iwst[i] = rwst[i] * niwst[i] + iwst[i] * nrwst[i];
          rwst[i] = rx;
        }
    
        this.conjugate(rwst, iwst, N);
        this.transform(rwst, iwst, rmws, _, N, rbt);
        this.conjugate(rmws, _, N);
        this.normalize13b(rmws, N);
    
        out.negative = x.negative ^ y.negative;
        out.length = x.length + y.length;
        return out.strip();
      };
    
      // Multiply `this` by `num`
      BN.prototype.mul = function mul (num) {
        var out = new BN(null);
        out.words = new Array(this.length + num.length);
        return this.mulTo(num, out);
      };
    
      // Multiply employing FFT
      BN.prototype.mulf = function mulf (num) {
        var out = new BN(null);
        out.words = new Array(this.length + num.length);
        return jumboMulTo(this, num, out);
      };
    
      // In-place Multiplication
      BN.prototype.imul = function imul (num) {
        return this.clone().mulTo(num, this);
      };
    
      BN.prototype.imuln = function imuln (num) {
        assert(typeof num === 'number');
        assert(num < 0x4000000);
    
        // Carry
        var carry = 0;
        for (var i = 0; i < this.length; i++) {
          var w = (this.words[i] | 0) * num;
          var lo = (w & 0x3ffffff) + (carry & 0x3ffffff);
          carry >>= 26;
          carry += (w / 0x4000000) | 0;
          // NOTE: lo is 27bit maximum
          carry += lo >>> 26;
          this.words[i] = lo & 0x3ffffff;
        }
    
        if (carry !== 0) {
          this.words[i] = carry;
          this.length++;
        }
    
        return this;
      };
    
      BN.prototype.muln = function muln (num) {
        return this.clone().imuln(num);
      };
    
      // `this` * `this`
      BN.prototype.sqr = function sqr () {
        return this.mul(this);
      };
    
      // `this` * `this` in-place
      BN.prototype.isqr = function isqr () {
        return this.imul(this.clone());
      };
    
      // Math.pow(`this`, `num`)
      BN.prototype.pow = function pow (num) {
        var w = toBitArray(num);
        if (w.length === 0) return new BN(1);
    
        // Skip leading zeroes
        var res = this;
        for (var i = 0; i < w.length; i++, res = res.sqr()) {
          if (w[i] !== 0) break;
        }
    
        if (++i < w.length) {
          for (var q = res.sqr(); i < w.length; i++, q = q.sqr()) {
            if (w[i] === 0) continue;
    
            res = res.mul(q);
          }
        }
    
        return res;
      };
    
      // Shift-left in-place
      BN.prototype.iushln = function iushln (bits) {
        assert(typeof bits === 'number' && bits >= 0);
        var r = bits % 26;
        var s = (bits - r) / 26;
        var carryMask = (0x3ffffff >>> (26 - r)) << (26 - r);
        var i;
    
        if (r !== 0) {
          var carry = 0;
    
          for (i = 0; i < this.length; i++) {
            var newCarry = this.words[i] & carryMask;
            var c = ((this.words[i] | 0) - newCarry) << r;
            this.words[i] = c | carry;
            carry = newCarry >>> (26 - r);
          }
    
          if (carry) {
            this.words[i] = carry;
            this.length++;
          }
        }
    
        if (s !== 0) {
          for (i = this.length - 1; i >= 0; i--) {
            this.words[i + s] = this.words[i];
          }
    
          for (i = 0; i < s; i++) {
            this.words[i] = 0;
          }
    
          this.length += s;
        }
    
        return this.strip();
      };
    
      BN.prototype.ishln = function ishln (bits) {
        // TODO(indutny): implement me
        assert(this.negative === 0);
        return this.iushln(bits);
      };
    
      // Shift-right in-place
      // NOTE: `hint` is a lowest bit before trailing zeroes
      // NOTE: if `extended` is present - it will be filled with destroyed bits
      BN.prototype.iushrn = function iushrn (bits, hint, extended) {
        assert(typeof bits === 'number' && bits >= 0);
        var h;
        if (hint) {
          h = (hint - (hint % 26)) / 26;
        } else {
          h = 0;
        }
    
        var r = bits % 26;
        var s = Math.min((bits - r) / 26, this.length);
        var mask = 0x3ffffff ^ ((0x3ffffff >>> r) << r);
        var maskedWords = extended;
    
        h -= s;
        h = Math.max(0, h);
    
        // Extended mode, copy masked part
        if (maskedWords) {
          for (var i = 0; i < s; i++) {
            maskedWords.words[i] = this.words[i];
          }
          maskedWords.length = s;
        }
    
        if (s === 0) {
          // No-op, we should not move anything at all
        } else if (this.length > s) {
          this.length -= s;
          for (i = 0; i < this.length; i++) {
            this.words[i] = this.words[i + s];
          }
        } else {
          this.words[0] = 0;
          this.length = 1;
        }
    
        var carry = 0;
        for (i = this.length - 1; i >= 0 && (carry !== 0 || i >= h); i--) {
          var word = this.words[i] | 0;
          this.words[i] = (carry << (26 - r)) | (word >>> r);
          carry = word & mask;
        }
    
        // Push carried bits as a mask
        if (maskedWords && carry !== 0) {
          maskedWords.words[maskedWords.length++] = carry;
        }
    
        if (this.length === 0) {
          this.words[0] = 0;
          this.length = 1;
        }
    
        return this.strip();
      };
    
      BN.prototype.ishrn = function ishrn (bits, hint, extended) {
        // TODO(indutny): implement me
        assert(this.negative === 0);
        return this.iushrn(bits, hint, extended);
      };
    
      // Shift-left
      BN.prototype.shln = function shln (bits) {
        return this.clone().ishln(bits);
      };
    
      BN.prototype.ushln = function ushln (bits) {
        return this.clone().iushln(bits);
      };
    
      // Shift-right
      BN.prototype.shrn = function shrn (bits) {
        return this.clone().ishrn(bits);
      };
    
      BN.prototype.ushrn = function ushrn (bits) {
        return this.clone().iushrn(bits);
      };
    
      // Test if n bit is set
      BN.prototype.testn = function testn (bit) {
        assert(typeof bit === 'number' && bit >= 0);
        var r = bit % 26;
        var s = (bit - r) / 26;
        var q = 1 << r;
    
        // Fast case: bit is much higher than all existing words
        if (this.length <= s) return false;
    
        // Check bit and return
        var w = this.words[s];
    
        return !!(w & q);
      };
    
      // Return only lowers bits of number (in-place)
      BN.prototype.imaskn = function imaskn (bits) {
        assert(typeof bits === 'number' && bits >= 0);
        var r = bits % 26;
        var s = (bits - r) / 26;
    
        assert(this.negative === 0, 'imaskn works only with positive numbers');
    
        if (this.length <= s) {
          return this;
        }
    
        if (r !== 0) {
          s++;
        }
        this.length = Math.min(s, this.length);
    
        if (r !== 0) {
          var mask = 0x3ffffff ^ ((0x3ffffff >>> r) << r);
          this.words[this.length - 1] &= mask;
        }
    
        return this.strip();
      };
    
      // Return only lowers bits of number
      BN.prototype.maskn = function maskn (bits) {
        return this.clone().imaskn(bits);
      };
    
      // Add plain number `num` to `this`
      BN.prototype.iaddn = function iaddn (num) {
        assert(typeof num === 'number');
        assert(num < 0x4000000);
        if (num < 0) return this.isubn(-num);
    
        // Possible sign change
        if (this.negative !== 0) {
          if (this.length === 1 && (this.words[0] | 0) < num) {
            this.words[0] = num - (this.words[0] | 0);
            this.negative = 0;
            return this;
          }
    
          this.negative = 0;
          this.isubn(num);
          this.negative = 1;
          return this;
        }
    
        // Add without checks
        return this._iaddn(num);
      };
    
      BN.prototype._iaddn = function _iaddn (num) {
        this.words[0] += num;
    
        // Carry
        for (var i = 0; i < this.length && this.words[i] >= 0x4000000; i++) {
          this.words[i] -= 0x4000000;
          if (i === this.length - 1) {
            this.words[i + 1] = 1;
          } else {
            this.words[i + 1]++;
          }
        }
        this.length = Math.max(this.length, i + 1);
    
        return this;
      };
    
      // Subtract plain number `num` from `this`
      BN.prototype.isubn = function isubn (num) {
        assert(typeof num === 'number');
        assert(num < 0x4000000);
        if (num < 0) return this.iaddn(-num);
    
        if (this.negative !== 0) {
          this.negative = 0;
          this.iaddn(num);
          this.negative = 1;
          return this;
        }
    
        this.words[0] -= num;
    
        if (this.length === 1 && this.words[0] < 0) {
          this.words[0] = -this.words[0];
          this.negative = 1;
        } else {
          // Carry
          for (var i = 0; i < this.length && this.words[i] < 0; i++) {
            this.words[i] += 0x4000000;
            this.words[i + 1] -= 1;
          }
        }
    
        return this.strip();
      };
    
      BN.prototype.addn = function addn (num) {
        return this.clone().iaddn(num);
      };
    
      BN.prototype.subn = function subn (num) {
        return this.clone().isubn(num);
      };
    
      BN.prototype.iabs = function iabs () {
        this.negative = 0;
    
        return this;
      };
    
      BN.prototype.abs = function abs () {
        return this.clone().iabs();
      };
    
      BN.prototype._ishlnsubmul = function _ishlnsubmul (num, mul, shift) {
        var len = num.length + shift;
        var i;
    
        this._expand(len);
    
        var w;
        var carry = 0;
        for (i = 0; i < num.length; i++) {
          w = (this.words[i + shift] | 0) + carry;
          var right = (num.words[i] | 0) * mul;
          w -= right & 0x3ffffff;
          carry = (w >> 26) - ((right / 0x4000000) | 0);
          this.words[i + shift] = w & 0x3ffffff;
        }
        for (; i < this.length - shift; i++) {
          w = (this.words[i + shift] | 0) + carry;
          carry = w >> 26;
          this.words[i + shift] = w & 0x3ffffff;
        }
    
        if (carry === 0) return this.strip();
    
        // Subtraction overflow
        assert(carry === -1);
        carry = 0;
        for (i = 0; i < this.length; i++) {
          w = -(this.words[i] | 0) + carry;
          carry = w >> 26;
          this.words[i] = w & 0x3ffffff;
        }
        this.negative = 1;
    
        return this.strip();
      };
    
      BN.prototype._wordDiv = function _wordDiv (num, mode) {
        var shift = this.length - num.length;
    
        var a = this.clone();
        var b = num;
    
        // Normalize
        var bhi = b.words[b.length - 1] | 0;
        var bhiBits = this._countBits(bhi);
        shift = 26 - bhiBits;
        if (shift !== 0) {
          b = b.ushln(shift);
          a.iushln(shift);
          bhi = b.words[b.length - 1] | 0;
        }
    
        // Initialize quotient
        var m = a.length - b.length;
        var q;
    
        if (mode !== 'mod') {
          q = new BN(null);
          q.length = m + 1;
          q.words = new Array(q.length);
          for (var i = 0; i < q.length; i++) {
            q.words[i] = 0;
          }
        }
    
        var diff = a.clone()._ishlnsubmul(b, 1, m);
        if (diff.negative === 0) {
          a = diff;
          if (q) {
            q.words[m] = 1;
          }
        }
    
        for (var j = m - 1; j >= 0; j--) {
          var qj = (a.words[b.length + j] | 0) * 0x4000000 +
            (a.words[b.length + j - 1] | 0);
    
          // NOTE: (qj / bhi) is (0x3ffffff * 0x4000000 + 0x3ffffff) / 0x2000000 max
          // (0x7ffffff)
          qj = Math.min((qj / bhi) | 0, 0x3ffffff);
    
          a._ishlnsubmul(b, qj, j);
          while (a.negative !== 0) {
            qj--;
            a.negative = 0;
            a._ishlnsubmul(b, 1, j);
            if (!a.isZero()) {
              a.negative ^= 1;
            }
          }
          if (q) {
            q.words[j] = qj;
          }
        }
        if (q) {
          q.strip();
        }
        a.strip();
    
        // Denormalize
        if (mode !== 'div' && shift !== 0) {
          a.iushrn(shift);
        }
    
        return {
          div: q || null,
          mod: a
        };
      };
    
      // NOTE: 1) `mode` can be set to `mod` to request mod only,
      //       to `div` to request div only, or be absent to
      //       request both div & mod
      //       2) `positive` is true if unsigned mod is requested
      BN.prototype.divmod = function divmod (num, mode, positive) {
        assert(!num.isZero());
    
        if (this.isZero()) {
          return {
            div: new BN(0),
            mod: new BN(0)
          };
        }
    
        var div, mod, res;
        if (this.negative !== 0 && num.negative === 0) {
          res = this.neg().divmod(num, mode);
    
          if (mode !== 'mod') {
            div = res.div.neg();
          }
    
          if (mode !== 'div') {
            mod = res.mod.neg();
            if (positive && mod.negative !== 0) {
              mod.iadd(num);
            }
          }
    
          return {
            div: div,
            mod: mod
          };
        }
    
        if (this.negative === 0 && num.negative !== 0) {
          res = this.divmod(num.neg(), mode);
    
          if (mode !== 'mod') {
            div = res.div.neg();
          }
    
          return {
            div: div,
            mod: res.mod
          };
        }
    
        if ((this.negative & num.negative) !== 0) {
          res = this.neg().divmod(num.neg(), mode);
    
          if (mode !== 'div') {
            mod = res.mod.neg();
            if (positive && mod.negative !== 0) {
              mod.isub(num);
            }
          }
    
          return {
            div: res.div,
            mod: mod
          };
        }
    
        // Both numbers are positive at this point
    
        // Strip both numbers to approximate shift value
        if (num.length > this.length || this.cmp(num) < 0) {
          return {
            div: new BN(0),
            mod: this
          };
        }
    
        // Very short reduction
        if (num.length === 1) {
          if (mode === 'div') {
            return {
              div: this.divn(num.words[0]),
              mod: null
            };
          }
    
          if (mode === 'mod') {
            return {
              div: null,
              mod: new BN(this.modn(num.words[0]))
            };
          }
    
          return {
            div: this.divn(num.words[0]),
            mod: new BN(this.modn(num.words[0]))
          };
        }
    
        return this._wordDiv(num, mode);
      };
    
      // Find `this` / `num`
      BN.prototype.div = function div (num) {
        return this.divmod(num, 'div', false).div;
      };
    
      // Find `this` % `num`
      BN.prototype.mod = function mod (num) {
        return this.divmod(num, 'mod', false).mod;
      };
    
      BN.prototype.umod = function umod (num) {
        return this.divmod(num, 'mod', true).mod;
      };
    
      // Find Round(`this` / `num`)
      BN.prototype.divRound = function divRound (num) {
        var dm = this.divmod(num);
    
        // Fast case - exact division
        if (dm.mod.isZero()) return dm.div;
    
        var mod = dm.div.negative !== 0 ? dm.mod.isub(num) : dm.mod;
    
        var half = num.ushrn(1);
        var r2 = num.andln(1);
        var cmp = mod.cmp(half);
    
        // Round down
        if (cmp < 0 || r2 === 1 && cmp === 0) return dm.div;
    
        // Round up
        return dm.div.negative !== 0 ? dm.div.isubn(1) : dm.div.iaddn(1);
      };
    
      BN.prototype.modn = function modn (num) {
        assert(num <= 0x3ffffff);
        var p = (1 << 26) % num;
    
        var acc = 0;
        for (var i = this.length - 1; i >= 0; i--) {
          acc = (p * acc + (this.words[i] | 0)) % num;
        }
    
        return acc;
      };
    
      // In-place division by number
      BN.prototype.idivn = function idivn (num) {
        assert(num <= 0x3ffffff);
    
        var carry = 0;
        for (var i = this.length - 1; i >= 0; i--) {
          var w = (this.words[i] | 0) + carry * 0x4000000;
          this.words[i] = (w / num) | 0;
          carry = w % num;
        }
    
        return this.strip();
      };
    
      BN.prototype.divn = function divn (num) {
        return this.clone().idivn(num);
      };
    
      BN.prototype.egcd = function egcd (p) {
        assert(p.negative === 0);
        assert(!p.isZero());
    
        var x = this;
        var y = p.clone();
    
        if (x.negative !== 0) {
          x = x.umod(p);
        } else {
          x = x.clone();
        }
    
        // A * x + B * y = x
        var A = new BN(1);
        var B = new BN(0);
    
        // C * x + D * y = y
        var C = new BN(0);
        var D = new BN(1);
    
        var g = 0;
    
        while (x.isEven() && y.isEven()) {
          x.iushrn(1);
          y.iushrn(1);
          ++g;
        }
    
        var yp = y.clone();
        var xp = x.clone();
    
        while (!x.isZero()) {
          for (var i = 0, im = 1; (x.words[0] & im) === 0 && i < 26; ++i, im <<= 1);
          if (i > 0) {
            x.iushrn(i);
            while (i-- > 0) {
              if (A.isOdd() || B.isOdd()) {
                A.iadd(yp);
                B.isub(xp);
              }
    
              A.iushrn(1);
              B.iushrn(1);
            }
          }
    
          for (var j = 0, jm = 1; (y.words[0] & jm) === 0 && j < 26; ++j, jm <<= 1);
          if (j > 0) {
            y.iushrn(j);
            while (j-- > 0) {
              if (C.isOdd() || D.isOdd()) {
                C.iadd(yp);
                D.isub(xp);
              }
    
              C.iushrn(1);
              D.iushrn(1);
            }
          }
    
          if (x.cmp(y) >= 0) {
            x.isub(y);
            A.isub(C);
            B.isub(D);
          } else {
            y.isub(x);
            C.isub(A);
            D.isub(B);
          }
        }
    
        return {
          a: C,
          b: D,
          gcd: y.iushln(g)
        };
      };
    
      // This is reduced incarnation of the binary EEA
      // above, designated to invert members of the
      // _prime_ fields F(p) at a maximal speed
      BN.prototype._invmp = function _invmp (p) {
        assert(p.negative === 0);
        assert(!p.isZero());
    
        var a = this;
        var b = p.clone();
    
        if (a.negative !== 0) {
          a = a.umod(p);
        } else {
          a = a.clone();
        }
    
        var x1 = new BN(1);
        var x2 = new BN(0);
    
        var delta = b.clone();
    
        while (a.cmpn(1) > 0 && b.cmpn(1) > 0) {
          for (var i = 0, im = 1; (a.words[0] & im) === 0 && i < 26; ++i, im <<= 1);
          if (i > 0) {
            a.iushrn(i);
            while (i-- > 0) {
              if (x1.isOdd()) {
                x1.iadd(delta);
              }
    
              x1.iushrn(1);
            }
          }
    
          for (var j = 0, jm = 1; (b.words[0] & jm) === 0 && j < 26; ++j, jm <<= 1);
          if (j > 0) {
            b.iushrn(j);
            while (j-- > 0) {
              if (x2.isOdd()) {
                x2.iadd(delta);
              }
    
              x2.iushrn(1);
            }
          }
    
          if (a.cmp(b) >= 0) {
            a.isub(b);
            x1.isub(x2);
          } else {
            b.isub(a);
            x2.isub(x1);
          }
        }
    
        var res;
        if (a.cmpn(1) === 0) {
          res = x1;
        } else {
          res = x2;
        }
    
        if (res.cmpn(0) < 0) {
          res.iadd(p);
        }
    
        return res;
      };
    
      BN.prototype.gcd = function gcd (num) {
        if (this.isZero()) return num.abs();
        if (num.isZero()) return this.abs();
    
        var a = this.clone();
        var b = num.clone();
        a.negative = 0;
        b.negative = 0;
    
        // Remove common factor of two
        for (var shift = 0; a.isEven() && b.isEven(); shift++) {
          a.iushrn(1);
          b.iushrn(1);
        }
    
        do {
          while (a.isEven()) {
            a.iushrn(1);
          }
          while (b.isEven()) {
            b.iushrn(1);
          }
    
          var r = a.cmp(b);
          if (r < 0) {
            // Swap `a` and `b` to make `a` always bigger than `b`
            var t = a;
            a = b;
            b = t;
          } else if (r === 0 || b.cmpn(1) === 0) {
            break;
          }
    
          a.isub(b);
        } while (true);
    
        return b.iushln(shift);
      };
    
      // Invert number in the field F(num)
      BN.prototype.invm = function invm (num) {
        return this.egcd(num).a.umod(num);
      };
    
      BN.prototype.isEven = function isEven () {
        return (this.words[0] & 1) === 0;
      };
    
      BN.prototype.isOdd = function isOdd () {
        return (this.words[0] & 1) === 1;
      };
    
      // And first word and num
      BN.prototype.andln = function andln (num) {
        return this.words[0] & num;
      };
    
      // Increment at the bit position in-line
      BN.prototype.bincn = function bincn (bit) {
        assert(typeof bit === 'number');
        var r = bit % 26;
        var s = (bit - r) / 26;
        var q = 1 << r;
    
        // Fast case: bit is much higher than all existing words
        if (this.length <= s) {
          this._expand(s + 1);
          this.words[s] |= q;
          return this;
        }
    
        // Add bit and propagate, if needed
        var carry = q;
        for (var i = s; carry !== 0 && i < this.length; i++) {
          var w = this.words[i] | 0;
          w += carry;
          carry = w >>> 26;
          w &= 0x3ffffff;
          this.words[i] = w;
        }
        if (carry !== 0) {
          this.words[i] = carry;
          this.length++;
        }
        return this;
      };
    
      BN.prototype.isZero = function isZero () {
        return this.length === 1 && this.words[0] === 0;
      };
    
      BN.prototype.cmpn = function cmpn (num) {
        var negative = num < 0;
    
        if (this.negative !== 0 && !negative) return -1;
        if (this.negative === 0 && negative) return 1;
    
        this.strip();
    
        var res;
        if (this.length > 1) {
          res = 1;
        } else {
          if (negative) {
            num = -num;
          }
    
          assert(num <= 0x3ffffff, 'Number is too big');
    
          var w = this.words[0] | 0;
          res = w === num ? 0 : w < num ? -1 : 1;
        }
        if (this.negative !== 0) return -res | 0;
        return res;
      };
    
      // Compare two numbers and return:
      // 1 - if `this` > `num`
      // 0 - if `this` == `num`
      // -1 - if `this` < `num`
      BN.prototype.cmp = function cmp (num) {
        if (this.negative !== 0 && num.negative === 0) return -1;
        if (this.negative === 0 && num.negative !== 0) return 1;
    
        var res = this.ucmp(num);
        if (this.negative !== 0) return -res | 0;
        return res;
      };
    
      // Unsigned comparison
      BN.prototype.ucmp = function ucmp (num) {
        // At this point both numbers have the same sign
        if (this.length > num.length) return 1;
        if (this.length < num.length) return -1;
    
        var res = 0;
        for (var i = this.length - 1; i >= 0; i--) {
          var a = this.words[i] | 0;
          var b = num.words[i] | 0;
    
          if (a === b) continue;
          if (a < b) {
            res = -1;
          } else if (a > b) {
            res = 1;
          }
          break;
        }
        return res;
      };
    
      BN.prototype.gtn = function gtn (num) {
        return this.cmpn(num) === 1;
      };
    
      BN.prototype.gt = function gt (num) {
        return this.cmp(num) === 1;
      };
    
      BN.prototype.gten = function gten (num) {
        return this.cmpn(num) >= 0;
      };
    
      BN.prototype.gte = function gte (num) {
        return this.cmp(num) >= 0;
      };
    
      BN.prototype.ltn = function ltn (num) {
        return this.cmpn(num) === -1;
      };
    
      BN.prototype.lt = function lt (num) {
        return this.cmp(num) === -1;
      };
    
      BN.prototype.lten = function lten (num) {
        return this.cmpn(num) <= 0;
      };
    
      BN.prototype.lte = function lte (num) {
        return this.cmp(num) <= 0;
      };
    
      BN.prototype.eqn = function eqn (num) {
        return this.cmpn(num) === 0;
      };
    
      BN.prototype.eq = function eq (num) {
        return this.cmp(num) === 0;
      };
    
      //
      // A reduce context, could be using montgomery or something better, depending
      // on the `m` itself.
      //
      BN.red = function red (num) {
        return new Red(num);
      };
    
      BN.prototype.toRed = function toRed (ctx) {
        assert(!this.red, 'Already a number in reduction context');
        assert(this.negative === 0, 'red works only with positives');
        return ctx.convertTo(this)._forceRed(ctx);
      };
    
      BN.prototype.fromRed = function fromRed () {
        assert(this.red, 'fromRed works only with numbers in reduction context');
        return this.red.convertFrom(this);
      };
    
      BN.prototype._forceRed = function _forceRed (ctx) {
        this.red = ctx;
        return this;
      };
    
      BN.prototype.forceRed = function forceRed (ctx) {
        assert(!this.red, 'Already a number in reduction context');
        return this._forceRed(ctx);
      };
    
      BN.prototype.redAdd = function redAdd (num) {
        assert(this.red, 'redAdd works only with red numbers');
        return this.red.add(this, num);
      };
    
      BN.prototype.redIAdd = function redIAdd (num) {
        assert(this.red, 'redIAdd works only with red numbers');
        return this.red.iadd(this, num);
      };
    
      BN.prototype.redSub = function redSub (num) {
        assert(this.red, 'redSub works only with red numbers');
        return this.red.sub(this, num);
      };
    
      BN.prototype.redISub = function redISub (num) {
        assert(this.red, 'redISub works only with red numbers');
        return this.red.isub(this, num);
      };
    
      BN.prototype.redShl = function redShl (num) {
        assert(this.red, 'redShl works only with red numbers');
        return this.red.shl(this, num);
      };
    
      BN.prototype.redMul = function redMul (num) {
        assert(this.red, 'redMul works only with red numbers');
        this.red._verify2(this, num);
        return this.red.mul(this, num);
      };
    
      BN.prototype.redIMul = function redIMul (num) {
        assert(this.red, 'redMul works only with red numbers');
        this.red._verify2(this, num);
        return this.red.imul(this, num);
      };
    
      BN.prototype.redSqr = function redSqr () {
        assert(this.red, 'redSqr works only with red numbers');
        this.red._verify1(this);
        return this.red.sqr(this);
      };
    
      BN.prototype.redISqr = function redISqr () {
        assert(this.red, 'redISqr works only with red numbers');
        this.red._verify1(this);
        return this.red.isqr(this);
      };
    
      // Square root over p
      BN.prototype.redSqrt = function redSqrt () {
        assert(this.red, 'redSqrt works only with red numbers');
        this.red._verify1(this);
        return this.red.sqrt(this);
      };
    
      BN.prototype.redInvm = function redInvm () {
        assert(this.red, 'redInvm works only with red numbers');
        this.red._verify1(this);
        return this.red.invm(this);
      };
    
      // Return negative clone of `this` % `red modulo`
      BN.prototype.redNeg = function redNeg () {
        assert(this.red, 'redNeg works only with red numbers');
        this.red._verify1(this);
        return this.red.neg(this);
      };
    
      BN.prototype.redPow = function redPow (num) {
        assert(this.red && !num.red, 'redPow(normalNum)');
        this.red._verify1(this);
        return this.red.pow(this, num);
      };
    
      // Prime numbers with efficient reduction
      var primes = {
        k256: null,
        p224: null,
        p192: null,
        p25519: null
      };
    
      // Pseudo-Mersenne prime
      function MPrime (name, p) {
        // P = 2 ^ N - K
        this.name = name;
        this.p = new BN(p, 16);
        this.n = this.p.bitLength();
        this.k = new BN(1).iushln(this.n).isub(this.p);
    
        this.tmp = this._tmp();
      }
    
      MPrime.prototype._tmp = function _tmp () {
        var tmp = new BN(null);
        tmp.words = new Array(Math.ceil(this.n / 13));
        return tmp;
      };
    
      MPrime.prototype.ireduce = function ireduce (num) {
        // Assumes that `num` is less than `P^2`
        // num = HI * (2 ^ N - K) + HI * K + LO = HI * K + LO (mod P)
        var r = num;
        var rlen;
    
        do {
          this.split(r, this.tmp);
          r = this.imulK(r);
          r = r.iadd(this.tmp);
          rlen = r.bitLength();
        } while (rlen > this.n);
    
        var cmp = rlen < this.n ? -1 : r.ucmp(this.p);
        if (cmp === 0) {
          r.words[0] = 0;
          r.length = 1;
        } else if (cmp > 0) {
          r.isub(this.p);
        } else {
          if (r.strip !== undefined) {
            // r is BN v4 instance
            r.strip();
          } else {
            // r is BN v5 instance
            r._strip();
          }
        }
    
        return r;
      };
    
      MPrime.prototype.split = function split (input, out) {
        input.iushrn(this.n, 0, out);
      };
    
      MPrime.prototype.imulK = function imulK (num) {
        return num.imul(this.k);
      };
    
      function K256 () {
        MPrime.call(
          this,
          'k256',
          'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc2f');
      }
      inherits(K256, MPrime);
    
      K256.prototype.split = function split (input, output) {
        // 256 = 9 * 26 + 22
        var mask = 0x3fffff;
    
        var outLen = Math.min(input.length, 9);
        for (var i = 0; i < outLen; i++) {
          output.words[i] = input.words[i];
        }
        output.length = outLen;
    
        if (input.length <= 9) {
          input.words[0] = 0;
          input.length = 1;
          return;
        }
    
        // Shift by 9 limbs
        var prev = input.words[9];
        output.words[output.length++] = prev & mask;
    
        for (i = 10; i < input.length; i++) {
          var next = input.words[i] | 0;
          input.words[i - 10] = ((next & mask) << 4) | (prev >>> 22);
          prev = next;
        }
        prev >>>= 22;
        input.words[i - 10] = prev;
        if (prev === 0 && input.length > 10) {
          input.length -= 10;
        } else {
          input.length -= 9;
        }
      };
    
      K256.prototype.imulK = function imulK (num) {
        // K = 0x1000003d1 = [ 0x40, 0x3d1 ]
        num.words[num.length] = 0;
        num.words[num.length + 1] = 0;
        num.length += 2;
    
        // bounded at: 0x40 * 0x3ffffff + 0x3d0 = 0x100000390
        var lo = 0;
        for (var i = 0; i < num.length; i++) {
          var w = num.words[i] | 0;
          lo += w * 0x3d1;
          num.words[i] = lo & 0x3ffffff;
          lo = w * 0x40 + ((lo / 0x4000000) | 0);
        }
    
        // Fast length reduction
        if (num.words[num.length - 1] === 0) {
          num.length--;
          if (num.words[num.length - 1] === 0) {
            num.length--;
          }
        }
        return num;
      };
    
      function P224 () {
        MPrime.call(
          this,
          'p224',
          'ffffffff ffffffff ffffffff ffffffff 00000000 00000000 00000001');
      }
      inherits(P224, MPrime);
    
      function P192 () {
        MPrime.call(
          this,
          'p192',
          'ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff');
      }
      inherits(P192, MPrime);
    
      function P25519 () {
        // 2 ^ 255 - 19
        MPrime.call(
          this,
          '25519',
          '7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed');
      }
      inherits(P25519, MPrime);
    
      P25519.prototype.imulK = function imulK (num) {
        // K = 0x13
        var carry = 0;
        for (var i = 0; i < num.length; i++) {
          var hi = (num.words[i] | 0) * 0x13 + carry;
          var lo = hi & 0x3ffffff;
          hi >>>= 26;
    
          num.words[i] = lo;
          carry = hi;
        }
        if (carry !== 0) {
          num.words[num.length++] = carry;
        }
        return num;
      };
    
      // Exported mostly for testing purposes, use plain name instead
      BN._prime = function prime (name) {
        // Cached version of prime
        if (primes[name]) return primes[name];
    
        var prime;
        if (name === 'k256') {
          prime = new K256();
        } else if (name === 'p224') {
          prime = new P224();
        } else if (name === 'p192') {
          prime = new P192();
        } else if (name === 'p25519') {
          prime = new P25519();
        } else {
          throw new Error('Unknown prime ' + name);
        }
        primes[name] = prime;
    
        return prime;
      };
    
      //
      // Base reduction engine
      //
      function Red (m) {
        if (typeof m === 'string') {
          var prime = BN._prime(m);
          this.m = prime.p;
          this.prime = prime;
        } else {
          assert(m.gtn(1), 'modulus must be greater than 1');
          this.m = m;
          this.prime = null;
        }
      }
    
      Red.prototype._verify1 = function _verify1 (a) {
        assert(a.negative === 0, 'red works only with positives');
        assert(a.red, 'red works only with red numbers');
      };
    
      Red.prototype._verify2 = function _verify2 (a, b) {
        assert((a.negative | b.negative) === 0, 'red works only with positives');
        assert(a.red && a.red === b.red,
          'red works only with red numbers');
      };
    
      Red.prototype.imod = function imod (a) {
        if (this.prime) return this.prime.ireduce(a)._forceRed(this);
        return a.umod(this.m)._forceRed(this);
      };
    
      Red.prototype.neg = function neg (a) {
        if (a.isZero()) {
          return a.clone();
        }
    
        return this.m.sub(a)._forceRed(this);
      };
    
      Red.prototype.add = function add (a, b) {
        this._verify2(a, b);
    
        var res = a.add(b);
        if (res.cmp(this.m) >= 0) {
          res.isub(this.m);
        }
        return res._forceRed(this);
      };
    
      Red.prototype.iadd = function iadd (a, b) {
        this._verify2(a, b);
    
        var res = a.iadd(b);
        if (res.cmp(this.m) >= 0) {
          res.isub(this.m);
        }
        return res;
      };
    
      Red.prototype.sub = function sub (a, b) {
        this._verify2(a, b);
    
        var res = a.sub(b);
        if (res.cmpn(0) < 0) {
          res.iadd(this.m);
        }
        return res._forceRed(this);
      };
    
      Red.prototype.isub = function isub (a, b) {
        this._verify2(a, b);
    
        var res = a.isub(b);
        if (res.cmpn(0) < 0) {
          res.iadd(this.m);
        }
        return res;
      };
    
      Red.prototype.shl = function shl (a, num) {
        this._verify1(a);
        return this.imod(a.ushln(num));
      };
    
      Red.prototype.imul = function imul (a, b) {
        this._verify2(a, b);
        return this.imod(a.imul(b));
      };
    
      Red.prototype.mul = function mul (a, b) {
        this._verify2(a, b);
        return this.imod(a.mul(b));
      };
    
      Red.prototype.isqr = function isqr (a) {
        return this.imul(a, a.clone());
      };
    
      Red.prototype.sqr = function sqr (a) {
        return this.mul(a, a);
      };
    
      Red.prototype.sqrt = function sqrt (a) {
        if (a.isZero()) return a.clone();
    
        var mod3 = this.m.andln(3);
        assert(mod3 % 2 === 1);
    
        // Fast case
        if (mod3 === 3) {
          var pow = this.m.add(new BN(1)).iushrn(2);
          return this.pow(a, pow);
        }
    
        // Tonelli-Shanks algorithm (Totally unoptimized and slow)
        //
        // Find Q and S, that Q * 2 ^ S = (P - 1)
        var q = this.m.subn(1);
        var s = 0;
        while (!q.isZero() && q.andln(1) === 0) {
          s++;
          q.iushrn(1);
        }
        assert(!q.isZero());
    
        var one = new BN(1).toRed(this);
        var nOne = one.redNeg();
    
        // Find quadratic non-residue
        // NOTE: Max is such because of generalized Riemann hypothesis.
        var lpow = this.m.subn(1).iushrn(1);
        var z = this.m.bitLength();
        z = new BN(2 * z * z).toRed(this);
    
        while (this.pow(z, lpow).cmp(nOne) !== 0) {
          z.redIAdd(nOne);
        }
    
        var c = this.pow(z, q);
        var r = this.pow(a, q.addn(1).iushrn(1));
        var t = this.pow(a, q);
        var m = s;
        while (t.cmp(one) !== 0) {
          var tmp = t;
          for (var i = 0; tmp.cmp(one) !== 0; i++) {
            tmp = tmp.redSqr();
          }
          assert(i < m);
          var b = this.pow(c, new BN(1).iushln(m - i - 1));
    
          r = r.redMul(b);
          c = b.redSqr();
          t = t.redMul(c);
          m = i;
        }
    
        return r;
      };
    
      Red.prototype.invm = function invm (a) {
        var inv = a._invmp(this.m);
        if (inv.negative !== 0) {
          inv.negative = 0;
          return this.imod(inv).redNeg();
        } else {
          return this.imod(inv);
        }
      };
    
      Red.prototype.pow = function pow (a, num) {
        if (num.isZero()) return new BN(1).toRed(this);
        if (num.cmpn(1) === 0) return a.clone();
    
        var windowSize = 4;
        var wnd = new Array(1 << windowSize);
        wnd[0] = new BN(1).toRed(this);
        wnd[1] = a;
        for (var i = 2; i < wnd.length; i++) {
          wnd[i] = this.mul(wnd[i - 1], a);
        }
    
        var res = wnd[0];
        var current = 0;
        var currentLen = 0;
        var start = num.bitLength() % 26;
        if (start === 0) {
          start = 26;
        }
    
        for (i = num.length - 1; i >= 0; i--) {
          var word = num.words[i];
          for (var j = start - 1; j >= 0; j--) {
            var bit = (word >> j) & 1;
            if (res !== wnd[0]) {
              res = this.sqr(res);
            }
    
            if (bit === 0 && current === 0) {
              currentLen = 0;
              continue;
            }
    
            current <<= 1;
            current |= bit;
            currentLen++;
            if (currentLen !== windowSize && (i !== 0 || j !== 0)) continue;
    
            res = this.mul(res, wnd[current]);
            currentLen = 0;
            current = 0;
          }
          start = 26;
        }
    
        return res;
      };
    
      Red.prototype.convertTo = function convertTo (num) {
        var r = num.umod(this.m);
    
        return r === num ? r.clone() : r;
      };
    
      Red.prototype.convertFrom = function convertFrom (num) {
        var res = num.clone();
        res.red = null;
        return res;
      };
    
      //
      // Montgomery method engine
      //
    
      BN.mont = function mont (num) {
        return new Mont(num);
      };
    
      function Mont (m) {
        Red.call(this, m);
    
        this.shift = this.m.bitLength();
        if (this.shift % 26 !== 0) {
          this.shift += 26 - (this.shift % 26);
        }
    
        this.r = new BN(1).iushln(this.shift);
        this.r2 = this.imod(this.r.sqr());
        this.rinv = this.r._invmp(this.m);
    
        this.minv = this.rinv.mul(this.r).isubn(1).div(this.m);
        this.minv = this.minv.umod(this.r);
        this.minv = this.r.sub(this.minv);
      }
      inherits(Mont, Red);
    
      Mont.prototype.convertTo = function convertTo (num) {
        return this.imod(num.ushln(this.shift));
      };
    
      Mont.prototype.convertFrom = function convertFrom (num) {
        var r = this.imod(num.mul(this.rinv));
        r.red = null;
        return r;
      };
    
      Mont.prototype.imul = function imul (a, b) {
        if (a.isZero() || b.isZero()) {
          a.words[0] = 0;
          a.length = 1;
          return a;
        }
    
        var t = a.imul(b);
        var c = t.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m);
        var u = t.isub(c).iushrn(this.shift);
        var res = u;
    
        if (u.cmp(this.m) >= 0) {
          res = u.isub(this.m);
        } else if (u.cmpn(0) < 0) {
          res = u.iadd(this.m);
        }
    
        return res._forceRed(this);
      };
    
      Mont.prototype.mul = function mul (a, b) {
        if (a.isZero() || b.isZero()) return new BN(0)._forceRed(this);
    
        var t = a.mul(b);
        var c = t.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m);
        var u = t.isub(c).iushrn(this.shift);
        var res = u;
        if (u.cmp(this.m) >= 0) {
          res = u.isub(this.m);
        } else if (u.cmpn(0) < 0) {
          res = u.iadd(this.m);
        }
    
        return res._forceRed(this);
      };
    
      Mont.prototype.invm = function invm (a) {
        // (AR)^-1 * R^2 = (A^-1 * R^-1) * R^2 = A^-1 * R
        var res = this.imod(a._invmp(this.m).mul(this.r2));
        return res._forceRed(this);
      };
    })(typeof module === 'undefined' || module, this);
    
    },{"buffer":24}],16:[function(require,module,exports){
    (function (global){(function (){
    'use strict';
    
    var objectAssign = require('object.assign/polyfill')();
    
    // compare and isBuffer taken from https://github.com/feross/buffer/blob/680e9e5e488f22aac27599a57dc844a6315928dd/index.js
    // original notice:
    
    /*!
     * The buffer module from node.js, for the browser.
     *
     * @author   Feross Aboukhadijeh <feross@feross.org> <http://feross.org>
     * @license  MIT
     */
    function compare(a, b) {
      if (a === b) {
        return 0;
      }
    
      var x = a.length;
      var y = b.length;
    
      for (var i = 0, len = Math.min(x, y); i < len; ++i) {
        if (a[i] !== b[i]) {
          x = a[i];
          y = b[i];
          break;
        }
      }
    
      if (x < y) {
        return -1;
      }
      if (y < x) {
        return 1;
      }
      return 0;
    }
    function isBuffer(b) {
      if (global.Buffer && typeof global.Buffer.isBuffer === 'function') {
        return global.Buffer.isBuffer(b);
      }
      return !!(b != null && b._isBuffer);
    }
    
    // based on node assert, original notice:
    // NB: The URL to the CommonJS spec is kept just for tradition.
    //     node-assert has evolved a lot since then, both in API and behavior.
    
    // http://wiki.commonjs.org/wiki/Unit_Testing/1.0
    //
    // THIS IS NOT TESTED NOR LIKELY TO WORK OUTSIDE V8!
    //
    // Originally from narwhal.js (http://narwhaljs.org)
    // Copyright (c) 2009 Thomas Robinson <280north.com>
    //
    // Permission is hereby granted, free of charge, to any person obtaining a copy
    // of this software and associated documentation files (the 'Software'), to
    // deal in the Software without restriction, including without limitation the
    // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
    // sell copies of the Software, and to permit persons to whom the Software is
    // furnished to do so, subject to the following conditions:
    //
    // The above copyright notice and this permission notice shall be included in
    // all copies or substantial portions of the Software.
    //
    // THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    // AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
    // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
    // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    
    var util = require('util/');
    var hasOwn = Object.prototype.hasOwnProperty;
    var pSlice = Array.prototype.slice;
    var functionsHaveNames = (function () {
      return function foo() {}.name === 'foo';
    }());
    function pToString (obj) {
      return Object.prototype.toString.call(obj);
    }
    function isView(arrbuf) {
      if (isBuffer(arrbuf)) {
        return false;
      }
      if (typeof global.ArrayBuffer !== 'function') {
        return false;
      }
      if (typeof ArrayBuffer.isView === 'function') {
        return ArrayBuffer.isView(arrbuf);
      }
      if (!arrbuf) {
        return false;
      }
      if (arrbuf instanceof DataView) {
        return true;
      }
      if (arrbuf.buffer && arrbuf.buffer instanceof ArrayBuffer) {
        return true;
      }
      return false;
    }
    // 1. The assert module provides functions that throw
    // AssertionError's when particular conditions are not met. The
    // assert module must conform to the following interface.
    
    var assert = module.exports = ok;
    
    // 2. The AssertionError is defined in assert.
    // new assert.AssertionError({ message: message,
    //                             actual: actual,
    //                             expected: expected })
    
    var regex = /\s*function\s+([^\(\s]*)\s*/;
    // based on https://github.com/ljharb/function.prototype.name/blob/adeeeec8bfcc6068b187d7d9fb3d5bb1d3a30899/implementation.js
    function getName(func) {
      if (!util.isFunction(func)) {
        return;
      }
      if (functionsHaveNames) {
        return func.name;
      }
      var str = func.toString();
      var match = str.match(regex);
      return match && match[1];
    }
    assert.AssertionError = function AssertionError(options) {
      this.name = 'AssertionError';
      this.actual = options.actual;
      this.expected = options.expected;
      this.operator = options.operator;
      if (options.message) {
        this.message = options.message;
        this.generatedMessage = false;
      } else {
        this.message = getMessage(this);
        this.generatedMessage = true;
      }
      var stackStartFunction = options.stackStartFunction || fail;
      if (Error.captureStackTrace) {
        Error.captureStackTrace(this, stackStartFunction);
      } else {
        // non v8 browsers so we can have a stacktrace
        var err = new Error();
        if (err.stack) {
          var out = err.stack;
    
          // try to strip useless frames
          var fn_name = getName(stackStartFunction);
          var idx = out.indexOf('\n' + fn_name);
          if (idx >= 0) {
            // once we have located the function frame
            // we need to strip out everything before it (and its line)
            var next_line = out.indexOf('\n', idx + 1);
            out = out.substring(next_line + 1);
          }
    
          this.stack = out;
        }
      }
    };
    
    // assert.AssertionError instanceof Error
    util.inherits(assert.AssertionError, Error);
    
    function truncate(s, n) {
      if (typeof s === 'string') {
        return s.length < n ? s : s.slice(0, n);
      } else {
        return s;
      }
    }
    function inspect(something) {
      if (functionsHaveNames || !util.isFunction(something)) {
        return util.inspect(something);
      }
      var rawname = getName(something);
      var name = rawname ? ': ' + rawname : '';
      return '[Function' +  name + ']';
    }
    function getMessage(self) {
      return truncate(inspect(self.actual), 128) + ' ' +
             self.operator + ' ' +
             truncate(inspect(self.expected), 128);
    }
    
    // At present only the three keys mentioned above are used and
    // understood by the spec. Implementations or sub modules can pass
    // other keys to the AssertionError's constructor - they will be
    // ignored.
    
    // 3. All of the following functions must throw an AssertionError
    // when a corresponding condition is not met, with a message that
    // may be undefined if not provided.  All assertion methods provide
    // both the actual and expected values to the assertion error for
    // display purposes.
    
    function fail(actual, expected, message, operator, stackStartFunction) {
      throw new assert.AssertionError({
        message: message,
        actual: actual,
        expected: expected,
        operator: operator,
        stackStartFunction: stackStartFunction
      });
    }
    
    // EXTENSION! allows for well behaved errors defined elsewhere.
    assert.fail = fail;
    
    // 4. Pure assertion tests whether a value is truthy, as determined
    // by !!guard.
    // assert.ok(guard, message_opt);
    // This statement is equivalent to assert.equal(true, !!guard,
    // message_opt);. To test strictly for the value true, use
    // assert.strictEqual(true, guard, message_opt);.
    
    function ok(value, message) {
      if (!value) fail(value, true, message, '==', assert.ok);
    }
    assert.ok = ok;
    
    // 5. The equality assertion tests shallow, coercive equality with
    // ==.
    // assert.equal(actual, expected, message_opt);
    
    assert.equal = function equal(actual, expected, message) {
      if (actual != expected) fail(actual, expected, message, '==', assert.equal);
    };
    
    // 6. The non-equality assertion tests for whether two objects are not equal
    // with != assert.notEqual(actual, expected, message_opt);
    
    assert.notEqual = function notEqual(actual, expected, message) {
      if (actual == expected) {
        fail(actual, expected, message, '!=', assert.notEqual);
      }
    };
    
    // 7. The equivalence assertion tests a deep equality relation.
    // assert.deepEqual(actual, expected, message_opt);
    
    assert.deepEqual = function deepEqual(actual, expected, message) {
      if (!_deepEqual(actual, expected, false)) {
        fail(actual, expected, message, 'deepEqual', assert.deepEqual);
      }
    };
    
    assert.deepStrictEqual = function deepStrictEqual(actual, expected, message) {
      if (!_deepEqual(actual, expected, true)) {
        fail(actual, expected, message, 'deepStrictEqual', assert.deepStrictEqual);
      }
    };
    
    function _deepEqual(actual, expected, strict, memos) {
      // 7.1. All identical values are equivalent, as determined by ===.
      if (actual === expected) {
        return true;
      } else if (isBuffer(actual) && isBuffer(expected)) {
        return compare(actual, expected) === 0;
    
      // 7.2. If the expected value is a Date object, the actual value is
      // equivalent if it is also a Date object that refers to the same time.
      } else if (util.isDate(actual) && util.isDate(expected)) {
        return actual.getTime() === expected.getTime();
    
      // 7.3 If the expected value is a RegExp object, the actual value is
      // equivalent if it is also a RegExp object with the same source and
      // properties (`global`, `multiline`, `lastIndex`, `ignoreCase`).
      } else if (util.isRegExp(actual) && util.isRegExp(expected)) {
        return actual.source === expected.source &&
               actual.global === expected.global &&
               actual.multiline === expected.multiline &&
               actual.lastIndex === expected.lastIndex &&
               actual.ignoreCase === expected.ignoreCase;
    
      // 7.4. Other pairs that do not both pass typeof value == 'object',
      // equivalence is determined by ==.
      } else if ((actual === null || typeof actual !== 'object') &&
                 (expected === null || typeof expected !== 'object')) {
        return strict ? actual === expected : actual == expected;
    
      // If both values are instances of typed arrays, wrap their underlying
      // ArrayBuffers in a Buffer each to increase performance
      // This optimization requires the arrays to have the same type as checked by
      // Object.prototype.toString (aka pToString). Never perform binary
      // comparisons for Float*Arrays, though, since e.g. +0 === -0 but their
      // bit patterns are not identical.
      } else if (isView(actual) && isView(expected) &&
                 pToString(actual) === pToString(expected) &&
                 !(actual instanceof Float32Array ||
                   actual instanceof Float64Array)) {
        return compare(new Uint8Array(actual.buffer),
                       new Uint8Array(expected.buffer)) === 0;
    
      // 7.5 For all other Object pairs, including Array objects, equivalence is
      // determined by having the same number of owned properties (as verified
      // with Object.prototype.hasOwnProperty.call), the same set of keys
      // (although not necessarily the same order), equivalent values for every
      // corresponding key, and an identical 'prototype' property. Note: this
      // accounts for both named and indexed properties on Arrays.
      } else if (isBuffer(actual) !== isBuffer(expected)) {
        return false;
      } else {
        memos = memos || {actual: [], expected: []};
    
        var actualIndex = memos.actual.indexOf(actual);
        if (actualIndex !== -1) {
          if (actualIndex === memos.expected.indexOf(expected)) {
            return true;
          }
        }
    
        memos.actual.push(actual);
        memos.expected.push(expected);
    
        return objEquiv(actual, expected, strict, memos);
      }
    }
    
    function isArguments(object) {
      return Object.prototype.toString.call(object) == '[object Arguments]';
    }
    
    function objEquiv(a, b, strict, actualVisitedObjects) {
      if (a === null || a === undefined || b === null || b === undefined)
        return false;
      // if one is a primitive, the other must be same
      if (util.isPrimitive(a) || util.isPrimitive(b))
        return a === b;
      if (strict && Object.getPrototypeOf(a) !== Object.getPrototypeOf(b))
        return false;
      var aIsArgs = isArguments(a);
      var bIsArgs = isArguments(b);
      if ((aIsArgs && !bIsArgs) || (!aIsArgs && bIsArgs))
        return false;
      if (aIsArgs) {
        a = pSlice.call(a);
        b = pSlice.call(b);
        return _deepEqual(a, b, strict);
      }
      var ka = objectKeys(a);
      var kb = objectKeys(b);
      var key, i;
      // having the same number of owned properties (keys incorporates
      // hasOwnProperty)
      if (ka.length !== kb.length)
        return false;
      //the same set of keys (although not necessarily the same order),
      ka.sort();
      kb.sort();
      //~~~cheap key test
      for (i = ka.length - 1; i >= 0; i--) {
        if (ka[i] !== kb[i])
          return false;
      }
      //equivalent values for every corresponding key, and
      //~~~possibly expensive deep test
      for (i = ka.length - 1; i >= 0; i--) {
        key = ka[i];
        if (!_deepEqual(a[key], b[key], strict, actualVisitedObjects))
          return false;
      }
      return true;
    }
    
    // 8. The non-equivalence assertion tests for any deep inequality.
    // assert.notDeepEqual(actual, expected, message_opt);
    
    assert.notDeepEqual = function notDeepEqual(actual, expected, message) {
      if (_deepEqual(actual, expected, false)) {
        fail(actual, expected, message, 'notDeepEqual', assert.notDeepEqual);
      }
    };
    
    assert.notDeepStrictEqual = notDeepStrictEqual;
    function notDeepStrictEqual(actual, expected, message) {
      if (_deepEqual(actual, expected, true)) {
        fail(actual, expected, message, 'notDeepStrictEqual', notDeepStrictEqual);
      }
    }
    
    
    // 9. The strict equality assertion tests strict equality, as determined by ===.
    // assert.strictEqual(actual, expected, message_opt);
    
    assert.strictEqual = function strictEqual(actual, expected, message) {
      if (actual !== expected) {
        fail(actual, expected, message, '===', assert.strictEqual);
      }
    };
    
    // 10. The strict non-equality assertion tests for strict inequality, as
    // determined by !==.  assert.notStrictEqual(actual, expected, message_opt);
    
    assert.notStrictEqual = function notStrictEqual(actual, expected, message) {
      if (actual === expected) {
        fail(actual, expected, message, '!==', assert.notStrictEqual);
      }
    };
    
    function expectedException(actual, expected) {
      if (!actual || !expected) {
        return false;
      }
    
      if (Object.prototype.toString.call(expected) == '[object RegExp]') {
        return expected.test(actual);
      }
    
      try {
        if (actual instanceof expected) {
          return true;
        }
      } catch (e) {
        // Ignore.  The instanceof check doesn't work for arrow functions.
      }
    
      if (Error.isPrototypeOf(expected)) {
        return false;
      }
    
      return expected.call({}, actual) === true;
    }
    
    function _tryBlock(block) {
      var error;
      try {
        block();
      } catch (e) {
        error = e;
      }
      return error;
    }
    
    function _throws(shouldThrow, block, expected, message) {
      var actual;
    
      if (typeof block !== 'function') {
        throw new TypeError('"block" argument must be a function');
      }
    
      if (typeof expected === 'string') {
        message = expected;
        expected = null;
      }
    
      actual = _tryBlock(block);
    
      message = (expected && expected.name ? ' (' + expected.name + ').' : '.') +
                (message ? ' ' + message : '.');
    
      if (shouldThrow && !actual) {
        fail(actual, expected, 'Missing expected exception' + message);
      }
    
      var userProvidedMessage = typeof message === 'string';
      var isUnwantedException = !shouldThrow && util.isError(actual);
      var isUnexpectedException = !shouldThrow && actual && !expected;
    
      if ((isUnwantedException &&
          userProvidedMessage &&
          expectedException(actual, expected)) ||
          isUnexpectedException) {
        fail(actual, expected, 'Got unwanted exception' + message);
      }
    
      if ((shouldThrow && actual && expected &&
          !expectedException(actual, expected)) || (!shouldThrow && actual)) {
        throw actual;
      }
    }
    
    // 11. Expected to throw an error:
    // assert.throws(block, Error_opt, message_opt);
    
    assert.throws = function(block, /*optional*/error, /*optional*/message) {
      _throws(true, block, error, message);
    };
    
    // EXTENSION! This is annoying to write outside this module.
    assert.doesNotThrow = function(block, /*optional*/error, /*optional*/message) {
      _throws(false, block, error, message);
    };
    
    assert.ifError = function(err) { if (err) throw err; };
    
    // Expose a strict only variant of assert
    function strict(value, message) {
      if (!value) fail(value, true, message, '==', strict);
    }
    assert.strict = objectAssign(strict, assert, {
      equal: assert.strictEqual,
      deepEqual: assert.deepStrictEqual,
      notEqual: assert.notStrictEqual,
      notDeepEqual: assert.notDeepStrictEqual
    });
    assert.strict.strict = assert.strict;
    
    var objectKeys = Object.keys || function (obj) {
      var keys = [];
      for (var key in obj) {
        if (hasOwn.call(obj, key)) keys.push(key);
      }
      return keys;
    };
    
    }).call(this)}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
    },{"object.assign/polyfill":164,"util/":19}],17:[function(require,module,exports){
    if (typeof Object.create === 'function') {
      // implementation from standard node.js 'util' module
      module.exports = function inherits(ctor, superCtor) {
        ctor.super_ = superCtor
        ctor.prototype = Object.create(superCtor.prototype, {
          constructor: {
            value: ctor,
            enumerable: false,
            writable: true,
            configurable: true
          }
        });
      };
    } else {
      // old school shim for old browsers
      module.exports = function inherits(ctor, superCtor) {
        ctor.super_ = superCtor
        var TempCtor = function () {}
        TempCtor.prototype = superCtor.prototype
        ctor.prototype = new TempCtor()
        ctor.prototype.constructor = ctor
      }
    }
    
    },{}],18:[function(require,module,exports){
    module.exports = function isBuffer(arg) {
      return arg && typeof arg === 'object'
        && typeof arg.copy === 'function'
        && typeof arg.fill === 'function'
        && typeof arg.readUInt8 === 'function';
    }
    },{}],19:[function(require,module,exports){
    (function (process,global){(function (){
    // Copyright Joyent, Inc. and other Node contributors.
    //
    // Permission is hereby granted, free of charge, to any person obtaining a
    // copy of this software and associated documentation files (the
    // "Software"), to deal in the Software without restriction, including
    // without limitation the rights to use, copy, modify, merge, publish,
    // distribute, sublicense, and/or sell copies of the Software, and to permit
    // persons to whom the Software is furnished to do so, subject to the
    // following conditions:
    //
    // The above copyright notice and this permission notice shall be included
    // in all copies or substantial portions of the Software.
    //
    // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
    // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
    // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
    // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
    // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
    // USE OR OTHER DEALINGS IN THE SOFTWARE.
    
    var formatRegExp = /%[sdj%]/g;
    exports.format = function(f) {
      if (!isString(f)) {
        var objects = [];
        for (var i = 0; i < arguments.length; i++) {
          objects.push(inspect(arguments[i]));
        }
        return objects.join(' ');
      }
    
      var i = 1;
      var args = arguments;
      var len = args.length;
      var str = String(f).replace(formatRegExp, function(x) {
        if (x === '%%') return '%';
        if (i >= len) return x;
        switch (x) {
          case '%s': return String(args[i++]);
          case '%d': return Number(args[i++]);
          case '%j':
            try {
              return JSON.stringify(args[i++]);
            } catch (_) {
              return '[Circular]';
            }
          default:
            return x;
        }
      });
      for (var x = args[i]; i < len; x = args[++i]) {
        if (isNull(x) || !isObject(x)) {
          str += ' ' + x;
        } else {
          str += ' ' + inspect(x);
        }
      }
      return str;
    };
    
    
    // Mark that a method should not be used.
    // Returns a modified function which warns once by default.
    // If --no-deprecation is set, then it is a no-op.
    exports.deprecate = function(fn, msg) {
      // Allow for deprecating things in the process of starting up.
      if (isUndefined(global.process)) {
        return function() {
          return exports.deprecate(fn, msg).apply(this, arguments);
        };
      }
    
      if (process.noDeprecation === true) {
        return fn;
      }
    
      var warned = false;
      function deprecated() {
        if (!warned) {
          if (process.throwDeprecation) {
            throw new Error(msg);
          } else if (process.traceDeprecation) {
            console.trace(msg);
          } else {
            console.error(msg);
          }
          warned = true;
        }
        return fn.apply(this, arguments);
      }
    
      return deprecated;
    };
    
    
    var debugs = {};
    var debugEnviron;
    exports.debuglog = function(set) {
      if (isUndefined(debugEnviron))
        debugEnviron = process.env.NODE_DEBUG || '';
      set = set.toUpperCase();
      if (!debugs[set]) {
        if (new RegExp('\\b' + set + '\\b', 'i').test(debugEnviron)) {
          var pid = process.pid;
          debugs[set] = function() {
            var msg = exports.format.apply(exports, arguments);
            console.error('%s %d: %s', set, pid, msg);
          };
        } else {
          debugs[set] = function() {};
        }
      }
      return debugs[set];
    };
    
    
    /**
     * Echos the value of a value. Trys to print the value out
     * in the best way possible given the different types.
     *
     * @param {Object} obj The object to print out.
     * @param {Object} opts Optional options object that alters the output.
     */
    /* legacy: obj, showHidden, depth, colors*/
    function inspect(obj, opts) {
      // default options
      var ctx = {
        seen: [],
        stylize: stylizeNoColor
      };
      // legacy...
      if (arguments.length >= 3) ctx.depth = arguments[2];
      if (arguments.length >= 4) ctx.colors = arguments[3];
      if (isBoolean(opts)) {
        // legacy...
        ctx.showHidden = opts;
      } else if (opts) {
        // got an "options" object
        exports._extend(ctx, opts);
      }
      // set default options
      if (isUndefined(ctx.showHidden)) ctx.showHidden = false;
      if (isUndefined(ctx.depth)) ctx.depth = 2;
      if (isUndefined(ctx.colors)) ctx.colors = false;
      if (isUndefined(ctx.customInspect)) ctx.customInspect = true;
      if (ctx.colors) ctx.stylize = stylizeWithColor;
      return formatValue(ctx, obj, ctx.depth);
    }
    exports.inspect = inspect;
    
    
    // http://en.wikipedia.org/wiki/ANSI_escape_code#graphics
    inspect.colors = {
      'bold' : [1, 22],
      'italic' : [3, 23],
      'underline' : [4, 24],
      'inverse' : [7, 27],
      'white' : [37, 39],
      'grey' : [90, 39],
      'black' : [30, 39],
      'blue' : [34, 39],
      'cyan' : [36, 39],
      'green' : [32, 39],
      'magenta' : [35, 39],
      'red' : [31, 39],
      'yellow' : [33, 39]
    };
    
    // Don't use 'blue' not visible on cmd.exe
    inspect.styles = {
      'special': 'cyan',
      'number': 'yellow',
      'boolean': 'yellow',
      'undefined': 'grey',
      'null': 'bold',
      'string': 'green',
      'date': 'magenta',
      // "name": intentionally not styling
      'regexp': 'red'
    };
    
    
    function stylizeWithColor(str, styleType) {
      var style = inspect.styles[styleType];
    
      if (style) {
        return '\u001b[' + inspect.colors[style][0] + 'm' + str +
               '\u001b[' + inspect.colors[style][1] + 'm';
      } else {
        return str;
      }
    }
    
    
    function stylizeNoColor(str, styleType) {
      return str;
    }
    
    
    function arrayToHash(array) {
      var hash = {};
    
      array.forEach(function(val, idx) {
        hash[val] = true;
      });
    
      return hash;
    }
    
    
    function formatValue(ctx, value, recurseTimes) {
      // Provide a hook for user-specified inspect functions.
      // Check that value is an object with an inspect function on it
      if (ctx.customInspect &&
          value &&
          isFunction(value.inspect) &&
          // Filter out the util module, it's inspect function is special
          value.inspect !== exports.inspect &&
          // Also filter out any prototype objects using the circular check.
          !(value.constructor && value.constructor.prototype === value)) {
        var ret = value.inspect(recurseTimes, ctx);
        if (!isString(ret)) {
          ret = formatValue(ctx, ret, recurseTimes);
        }
        return ret;
      }
    
      // Primitive types cannot have properties
      var primitive = formatPrimitive(ctx, value);
      if (primitive) {
        return primitive;
      }
    
      // Look up the keys of the object.
      var keys = Object.keys(value);
      var visibleKeys = arrayToHash(keys);
    
      if (ctx.showHidden) {
        keys = Object.getOwnPropertyNames(value);
      }
    
      // IE doesn't make error fields non-enumerable
      // http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx
      if (isError(value)
          && (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)) {
        return formatError(value);
      }
    
      // Some type of object without properties can be shortcutted.
      if (keys.length === 0) {
        if (isFunction(value)) {
          var name = value.name ? ': ' + value.name : '';
          return ctx.stylize('[Function' + name + ']', 'special');
        }
        if (isRegExp(value)) {
          return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
        }
        if (isDate(value)) {
          return ctx.stylize(Date.prototype.toString.call(value), 'date');
        }
        if (isError(value)) {
          return formatError(value);
        }
      }
    
      var base = '', array = false, braces = ['{', '}'];
    
      // Make Array say that they are Array
      if (isArray(value)) {
        array = true;
        braces = ['[', ']'];
      }
    
      // Make functions say that they are functions
      if (isFunction(value)) {
        var n = value.name ? ': ' + value.name : '';
        base = ' [Function' + n + ']';
      }
    
      // Make RegExps say that they are RegExps
      if (isRegExp(value)) {
        base = ' ' + RegExp.prototype.toString.call(value);
      }
    
      // Make dates with properties first say the date
      if (isDate(value)) {
        base = ' ' + Date.prototype.toUTCString.call(value);
      }
    
      // Make error with message first say the error
      if (isError(value)) {
        base = ' ' + formatError(value);
      }
    
      if (keys.length === 0 && (!array || value.length == 0)) {
        return braces[0] + base + braces[1];
      }
    
      if (recurseTimes < 0) {
        if (isRegExp(value)) {
          return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
        } else {
          return ctx.stylize('[Object]', 'special');
        }
      }
    
      ctx.seen.push(value);
    
      var output;
      if (array) {
        output = formatArray(ctx, value, recurseTimes, visibleKeys, keys);
      } else {
        output = keys.map(function(key) {
          return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array);
        });
      }
    
      ctx.seen.pop();
    
      return reduceToSingleString(output, base, braces);
    }
    
    
    function formatPrimitive(ctx, value) {
      if (isUndefined(value))
        return ctx.stylize('undefined', 'undefined');
      if (isString(value)) {
        var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '')
                                                 .replace(/'/g, "\\'")
                                                 .replace(/\\"/g, '"') + '\'';
        return ctx.stylize(simple, 'string');
      }
      if (isNumber(value))
        return ctx.stylize('' + value, 'number');
      if (isBoolean(value))
        return ctx.stylize('' + value, 'boolean');
      // For some reason typeof null is "object", so special case here.
      if (isNull(value))
        return ctx.stylize('null', 'null');
    }
    
    
    function formatError(value) {
      return '[' + Error.prototype.toString.call(value) + ']';
    }
    
    
    function formatArray(ctx, value, recurseTimes, visibleKeys, keys) {
      var output = [];
      for (var i = 0, l = value.length; i < l; ++i) {
        if (hasOwnProperty(value, String(i))) {
          output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
              String(i), true));
        } else {
          output.push('');
        }
      }
      keys.forEach(function(key) {
        if (!key.match(/^\d+$/)) {
          output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
              key, true));
        }
      });
      return output;
    }
    
    
    function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) {
      var name, str, desc;
      desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] };
      if (desc.get) {
        if (desc.set) {
          str = ctx.stylize('[Getter/Setter]', 'special');
        } else {
          str = ctx.stylize('[Getter]', 'special');
        }
      } else {
        if (desc.set) {
          str = ctx.stylize('[Setter]', 'special');
        }
      }
      if (!hasOwnProperty(visibleKeys, key)) {
        name = '[' + key + ']';
      }
      if (!str) {
        if (ctx.seen.indexOf(desc.value) < 0) {
          if (isNull(recurseTimes)) {
            str = formatValue(ctx, desc.value, null);
          } else {
            str = formatValue(ctx, desc.value, recurseTimes - 1);
          }
          if (str.indexOf('\n') > -1) {
            if (array) {
              str = str.split('\n').map(function(line) {
                return '  ' + line;
              }).join('\n').substr(2);
            } else {
              str = '\n' + str.split('\n').map(function(line) {
                return '   ' + line;
              }).join('\n');
            }
          }
        } else {
          str = ctx.stylize('[Circular]', 'special');
        }
      }
      if (isUndefined(name)) {
        if (array && key.match(/^\d+$/)) {
          return str;
        }
        name = JSON.stringify('' + key);
        if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) {
          name = name.substr(1, name.length - 2);
          name = ctx.stylize(name, 'name');
        } else {
          name = name.replace(/'/g, "\\'")
                     .replace(/\\"/g, '"')
                     .replace(/(^"|"$)/g, "'");
          name = ctx.stylize(name, 'string');
        }
      }
    
      return name + ': ' + str;
    }
    
    
    function reduceToSingleString(output, base, braces) {
      var numLinesEst = 0;
      var length = output.reduce(function(prev, cur) {
        numLinesEst++;
        if (cur.indexOf('\n') >= 0) numLinesEst++;
        return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1;
      }, 0);
    
      if (length > 60) {
        return braces[0] +
               (base === '' ? '' : base + '\n ') +
               ' ' +
               output.join(',\n  ') +
               ' ' +
               braces[1];
      }
    
      return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1];
    }
    
    
    // NOTE: These type checking functions intentionally don't use `instanceof`
    // because it is fragile and can be easily faked with `Object.create()`.
    function isArray(ar) {
      return Array.isArray(ar);
    }
    exports.isArray = isArray;
    
    function isBoolean(arg) {
      return typeof arg === 'boolean';
    }
    exports.isBoolean = isBoolean;
    
    function isNull(arg) {
      return arg === null;
    }
    exports.isNull = isNull;
    
    function isNullOrUndefined(arg) {
      return arg == null;
    }
    exports.isNullOrUndefined = isNullOrUndefined;
    
    function isNumber(arg) {
      return typeof arg === 'number';
    }
    exports.isNumber = isNumber;
    
    function isString(arg) {
      return typeof arg === 'string';
    }
    exports.isString = isString;
    
    function isSymbol(arg) {
      return typeof arg === 'symbol';
    }
    exports.isSymbol = isSymbol;
    
    function isUndefined(arg) {
      return arg === void 0;
    }
    exports.isUndefined = isUndefined;
    
    function isRegExp(re) {
      return isObject(re) && objectToString(re) === '[object RegExp]';
    }
    exports.isRegExp = isRegExp;
    
    function isObject(arg) {
      return typeof arg === 'object' && arg !== null;
    }
    exports.isObject = isObject;
    
    function isDate(d) {
      return isObject(d) && objectToString(d) === '[object Date]';
    }
    exports.isDate = isDate;
    
    function isError(e) {
      return isObject(e) &&
          (objectToString(e) === '[object Error]' || e instanceof Error);
    }
    exports.isError = isError;
    
    function isFunction(arg) {
      return typeof arg === 'function';
    }
    exports.isFunction = isFunction;
    
    function isPrimitive(arg) {
      return arg === null ||
             typeof arg === 'boolean' ||
             typeof arg === 'number' ||
             typeof arg === 'string' ||
             typeof arg === 'symbol' ||  // ES6 symbol
             typeof arg === 'undefined';
    }
    exports.isPrimitive = isPrimitive;
    
    exports.isBuffer = require('./support/isBuffer');
    
    function objectToString(o) {
      return Object.prototype.toString.call(o);
    }
    
    
    function pad(n) {
      return n < 10 ? '0' + n.toString(10) : n.toString(10);
    }
    
    
    var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep',
                  'Oct', 'Nov', 'Dec'];
    
    // 26 Feb 16:19:34
    function timestamp() {
      var d = new Date();
      var time = [pad(d.getHours()),
                  pad(d.getMinutes()),
                  pad(d.getSeconds())].join(':');
      return [d.getDate(), months[d.getMonth()], time].join(' ');
    }
    
    
    // log is just a thin wrapper to console.log that prepends a timestamp
    exports.log = function() {
      console.log('%s - %s', timestamp(), exports.format.apply(exports, arguments));
    };
    
    
    /**
     * Inherit the prototype methods from one constructor into another.
     *
     * The Function.prototype.inherits from lang.js rewritten as a standalone
     * function (not on Function.prototype). NOTE: If this file is to be loaded
     * during bootstrapping this function needs to be rewritten using some native
     * functions as prototype setup using normal JavaScript does not work as
     * expected during bootstrapping (see mirror.js in r114903).
     *
     * @param {function} ctor Constructor function which needs to inherit the
     *     prototype.
     * @param {function} superCtor Constructor function to inherit prototype from.
     */
    exports.inherits = require('inherits');
    
    exports._extend = function(origin, add) {
      // Don't do anything if add isn't an object
      if (!add || !isObject(add)) return origin;
    
      var keys = Object.keys(add);
      var i = keys.length;
      while (i--) {
        origin[keys[i]] = add[keys[i]];
      }
      return origin;
    };
    
    function hasOwnProperty(obj, prop) {
      return Object.prototype.hasOwnProperty.call(obj, prop);
    }
    
    }).call(this)}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
    },{"./support/isBuffer":18,"_process":176,"inherits":17}],20:[function(require,module,exports){
    (function (global){(function (){
    'use strict';
    
    var possibleNames = [
        'BigInt64Array',
        'BigUint64Array',
        'Float32Array',
        'Float64Array',
        'Int16Array',
        'Int32Array',
        'Int8Array',
        'Uint16Array',
        'Uint32Array',
        'Uint8Array',
        'Uint8ClampedArray'
    ];
    
    var g = typeof globalThis === 'undefined' ? global : globalThis;
    
    module.exports = function availableTypedArrays() {
        var out = [];
        for (var i = 0; i < possibleNames.length; i++) {
            if (typeof g[possibleNames[i]] === 'function') {
                out[out.length] = possibleNames[i];
            }
        }
        return out;
    };
    
    }).call(this)}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
    },{}],21:[function(require,module,exports){
    'use strict'
    
    exports.byteLength = byteLength
    exports.toByteArray = toByteArray
    exports.fromByteArray = fromByteArray
    
    var lookup = []
    var revLookup = []
    var Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array
    
    var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
    for (var i = 0, len = code.length; i < len; ++i) {
      lookup[i] = code[i]
      revLookup[code.charCodeAt(i)] = i
    }
    
    // Support decoding URL-safe base64 strings, as Node.js does.
    // See: https://en.wikipedia.org/wiki/Base64#URL_applications
    revLookup['-'.charCodeAt(0)] = 62
    revLookup['_'.charCodeAt(0)] = 63
    
    function getLens (b64) {
      var len = b64.length
    
      if (len % 4 > 0) {
        throw new Error('Invalid string. Length must be a multiple of 4')
      }
    
      // Trim off extra bytes after placeholder bytes are found
      // See: https://github.com/beatgammit/base64-js/issues/42
      var validLen = b64.indexOf('=')
      if (validLen === -1) validLen = len
    
      var placeHoldersLen = validLen === len
        ? 0
        : 4 - (validLen % 4)
    
      return [validLen, placeHoldersLen]
    }
    
    // base64 is 4/3 + up to two characters of the original data
    function byteLength (b64) {
      var lens = getLens(b64)
      var validLen = lens[0]
      var placeHoldersLen = lens[1]
      return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen
    }
    
    function _byteLength (b64, validLen, placeHoldersLen) {
      return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen
    }
    
    function toByteArray (b64) {
      var tmp
      var lens = getLens(b64)
      var validLen = lens[0]
      var placeHoldersLen = lens[1]
    
      var arr = new Arr(_byteLength(b64, validLen, placeHoldersLen))
    
      var curByte = 0
    
      // if there are placeholders, only get up to the last complete 4 chars
      var len = placeHoldersLen > 0
        ? validLen - 4
        : validLen
    
      var i
      for (i = 0; i < len; i += 4) {
        tmp =
          (revLookup[b64.charCodeAt(i)] << 18) |
          (revLookup[b64.charCodeAt(i + 1)] << 12) |
          (revLookup[b64.charCodeAt(i + 2)] << 6) |
          revLookup[b64.charCodeAt(i + 3)]
        arr[curByte++] = (tmp >> 16) & 0xFF
        arr[curByte++] = (tmp >> 8) & 0xFF
        arr[curByte++] = tmp & 0xFF
      }
    
      if (placeHoldersLen === 2) {
        tmp =
          (revLookup[b64.charCodeAt(i)] << 2) |
          (revLookup[b64.charCodeAt(i + 1)] >> 4)
        arr[curByte++] = tmp & 0xFF
      }
    
      if (placeHoldersLen === 1) {
        tmp =
          (revLookup[b64.charCodeAt(i)] << 10) |
          (revLookup[b64.charCodeAt(i + 1)] << 4) |
          (revLookup[b64.charCodeAt(i + 2)] >> 2)
        arr[curByte++] = (tmp >> 8) & 0xFF
        arr[curByte++] = tmp & 0xFF
      }
    
      return arr
    }
    
    function tripletToBase64 (num) {
      return lookup[num >> 18 & 0x3F] +
        lookup[num >> 12 & 0x3F] +
        lookup[num >> 6 & 0x3F] +
        lookup[num & 0x3F]
    }
    
    function encodeChunk (uint8, start, end) {
      var tmp
      var output = []
      for (var i = start; i < end; i += 3) {
        tmp =
          ((uint8[i] << 16) & 0xFF0000) +
          ((uint8[i + 1] << 8) & 0xFF00) +
          (uint8[i + 2] & 0xFF)
        output.push(tripletToBase64(tmp))
      }
      return output.join('')
    }
    
    function fromByteArray (uint8) {
      var tmp
      var len = uint8.length
      var extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes
      var parts = []
      var maxChunkLength = 16383 // must be multiple of 3
    
      // go through the array every three bytes, we'll deal with trailing stuff later
      for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) {
        parts.push(encodeChunk(uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength)))
      }
    
      // pad the end with zeros, but make sure to not forget the extra bytes
      if (extraBytes === 1) {
        tmp = uint8[len - 1]
        parts.push(
          lookup[tmp >> 2] +
          lookup[(tmp << 4) & 0x3F] +
          '=='
        )
      } else if (extraBytes === 2) {
        tmp = (uint8[len - 2] << 8) + uint8[len - 1]
        parts.push(
          lookup[tmp >> 10] +
          lookup[(tmp >> 4) & 0x3F] +
          lookup[(tmp << 2) & 0x3F] +
          '='
        )
      }
    
      return parts.join('')
    }
    
    },{}],22:[function(require,module,exports){
    (function (module, exports) {
      'use strict';
    
      // Utils
      function assert (val, msg) {
        if (!val) throw new Error(msg || 'Assertion failed');
      }
    
      // Could use `inherits` module, but don't want to move from single file
      // architecture yet.
      function inherits (ctor, superCtor) {
        ctor.super_ = superCtor;
        var TempCtor = function () {};
        TempCtor.prototype = superCtor.prototype;
        ctor.prototype = new TempCtor();
        ctor.prototype.constructor = ctor;
      }
    
      // BN
    
      function BN (number, base, endian) {
        if (BN.isBN(number)) {
          return number;
        }
    
        this.negative = 0;
        this.words = null;
        this.length = 0;
    
        // Reduction context
        this.red = null;
    
        if (number !== null) {
          if (base === 'le' || base === 'be') {
            endian = base;
            base = 10;
          }
    
          this._init(number || 0, base || 10, endian || 'be');
        }
      }
      if (typeof module === 'object') {
        module.exports = BN;
      } else {
        exports.BN = BN;
      }
    
      BN.BN = BN;
      BN.wordSize = 26;
    
      var Buffer;
      try {
        if (typeof window !== 'undefined' && typeof window.Buffer !== 'undefined') {
          Buffer = window.Buffer;
        } else {
          Buffer = require('buffer').Buffer;
        }
      } catch (e) {
      }
    
      BN.isBN = function isBN (num) {
        if (num instanceof BN) {
          return true;
        }
    
        return num !== null && typeof num === 'object' &&
          num.constructor.wordSize === BN.wordSize && Array.isArray(num.words);
      };
    
      BN.max = function max (left, right) {
        if (left.cmp(right) > 0) return left;
        return right;
      };
    
      BN.min = function min (left, right) {
        if (left.cmp(right) < 0) return left;
        return right;
      };
    
      BN.prototype._init = function init (number, base, endian) {
        if (typeof number === 'number') {
          return this._initNumber(number, base, endian);
        }
    
        if (typeof number === 'object') {
          return this._initArray(number, base, endian);
        }
    
        if (base === 'hex') {
          base = 16;
        }
        assert(base === (base | 0) && base >= 2 && base <= 36);
    
        number = number.toString().replace(/\s+/g, '');
        var start = 0;
        if (number[0] === '-') {
          start++;
          this.negative = 1;
        }
    
        if (start < number.length) {
          if (base === 16) {
            this._parseHex(number, start, endian);
          } else {
            this._parseBase(number, base, start);
            if (endian === 'le') {
              this._initArray(this.toArray(), base, endian);
            }
          }
        }
      };
    
      BN.prototype._initNumber = function _initNumber (number, base, endian) {
        if (number < 0) {
          this.negative = 1;
          number = -number;
        }
        if (number < 0x4000000) {
          this.words = [number & 0x3ffffff];
          this.length = 1;
        } else if (number < 0x10000000000000) {
          this.words = [
            number & 0x3ffffff,
            (number / 0x4000000) & 0x3ffffff
          ];
          this.length = 2;
        } else {
          assert(number < 0x20000000000000); // 2 ^ 53 (unsafe)
          this.words = [
            number & 0x3ffffff,
            (number / 0x4000000) & 0x3ffffff,
            1
          ];
          this.length = 3;
        }
    
        if (endian !== 'le') return;
    
        // Reverse the bytes
        this._initArray(this.toArray(), base, endian);
      };
    
      BN.prototype._initArray = function _initArray (number, base, endian) {
        // Perhaps a Uint8Array
        assert(typeof number.length === 'number');
        if (number.length <= 0) {
          this.words = [0];
          this.length = 1;
          return this;
        }
    
        this.length = Math.ceil(number.length / 3);
        this.words = new Array(this.length);
        for (var i = 0; i < this.length; i++) {
          this.words[i] = 0;
        }
    
        var j, w;
        var off = 0;
        if (endian === 'be') {
          for (i = number.length - 1, j = 0; i >= 0; i -= 3) {
            w = number[i] | (number[i - 1] << 8) | (number[i - 2] << 16);
            this.words[j] |= (w << off) & 0x3ffffff;
            this.words[j + 1] = (w >>> (26 - off)) & 0x3ffffff;
            off += 24;
            if (off >= 26) {
              off -= 26;
              j++;
            }
          }
        } else if (endian === 'le') {
          for (i = 0, j = 0; i < number.length; i += 3) {
            w = number[i] | (number[i + 1] << 8) | (number[i + 2] << 16);
            this.words[j] |= (w << off) & 0x3ffffff;
            this.words[j + 1] = (w >>> (26 - off)) & 0x3ffffff;
            off += 24;
            if (off >= 26) {
              off -= 26;
              j++;
            }
          }
        }
        return this._strip();
      };
    
      function parseHex4Bits (string, index) {
        var c = string.charCodeAt(index);
        // '0' - '9'
        if (c >= 48 && c <= 57) {
          return c - 48;
        // 'A' - 'F'
        } else if (c >= 65 && c <= 70) {
          return c - 55;
        // 'a' - 'f'
        } else if (c >= 97 && c <= 102) {
          return c - 87;
        } else {
          assert(false, 'Invalid character in ' + string);
        }
      }
    
      function parseHexByte (string, lowerBound, index) {
        var r = parseHex4Bits(string, index);
        if (index - 1 >= lowerBound) {
          r |= parseHex4Bits(string, index - 1) << 4;
        }
        return r;
      }
    
      BN.prototype._parseHex = function _parseHex (number, start, endian) {
        // Create possibly bigger array to ensure that it fits the number
        this.length = Math.ceil((number.length - start) / 6);
        this.words = new Array(this.length);
        for (var i = 0; i < this.length; i++) {
          this.words[i] = 0;
        }
    
        // 24-bits chunks
        var off = 0;
        var j = 0;
    
        var w;
        if (endian === 'be') {
          for (i = number.length - 1; i >= start; i -= 2) {
            w = parseHexByte(number, start, i) << off;
            this.words[j] |= w & 0x3ffffff;
            if (off >= 18) {
              off -= 18;
              j += 1;
              this.words[j] |= w >>> 26;
            } else {
              off += 8;
            }
          }
        } else {
          var parseLength = number.length - start;
          for (i = parseLength % 2 === 0 ? start + 1 : start; i < number.length; i += 2) {
            w = parseHexByte(number, start, i) << off;
            this.words[j] |= w & 0x3ffffff;
            if (off >= 18) {
              off -= 18;
              j += 1;
              this.words[j] |= w >>> 26;
            } else {
              off += 8;
            }
          }
        }
    
        this._strip();
      };
    
      function parseBase (str, start, end, mul) {
        var r = 0;
        var b = 0;
        var len = Math.min(str.length, end);
        for (var i = start; i < len; i++) {
          var c = str.charCodeAt(i) - 48;
    
          r *= mul;
    
          // 'a'
          if (c >= 49) {
            b = c - 49 + 0xa;
    
          // 'A'
          } else if (c >= 17) {
            b = c - 17 + 0xa;
    
          // '0' - '9'
          } else {
            b = c;
          }
          assert(c >= 0 && b < mul, 'Invalid character');
          r += b;
        }
        return r;
      }
    
      BN.prototype._parseBase = function _parseBase (number, base, start) {
        // Initialize as zero
        this.words = [0];
        this.length = 1;
    
        // Find length of limb in base
        for (var limbLen = 0, limbPow = 1; limbPow <= 0x3ffffff; limbPow *= base) {
          limbLen++;
        }
        limbLen--;
        limbPow = (limbPow / base) | 0;
    
        var total = number.length - start;
        var mod = total % limbLen;
        var end = Math.min(total, total - mod) + start;
    
        var word = 0;
        for (var i = start; i < end; i += limbLen) {
          word = parseBase(number, i, i + limbLen, base);
    
          this.imuln(limbPow);
          if (this.words[0] + word < 0x4000000) {
            this.words[0] += word;
          } else {
            this._iaddn(word);
          }
        }
    
        if (mod !== 0) {
          var pow = 1;
          word = parseBase(number, i, number.length, base);
    
          for (i = 0; i < mod; i++) {
            pow *= base;
          }
    
          this.imuln(pow);
          if (this.words[0] + word < 0x4000000) {
            this.words[0] += word;
          } else {
            this._iaddn(word);
          }
        }
    
        this._strip();
      };
    
      BN.prototype.copy = function copy (dest) {
        dest.words = new Array(this.length);
        for (var i = 0; i < this.length; i++) {
          dest.words[i] = this.words[i];
        }
        dest.length = this.length;
        dest.negative = this.negative;
        dest.red = this.red;
      };
    
      function move (dest, src) {
        dest.words = src.words;
        dest.length = src.length;
        dest.negative = src.negative;
        dest.red = src.red;
      }
    
      BN.prototype._move = function _move (dest) {
        move(dest, this);
      };
    
      BN.prototype.clone = function clone () {
        var r = new BN(null);
        this.copy(r);
        return r;
      };
    
      BN.prototype._expand = function _expand (size) {
        while (this.length < size) {
          this.words[this.length++] = 0;
        }
        return this;
      };
    
      // Remove leading `0` from `this`
      BN.prototype._strip = function strip () {
        while (this.length > 1 && this.words[this.length - 1] === 0) {
          this.length--;
        }
        return this._normSign();
      };
    
      BN.prototype._normSign = function _normSign () {
        // -0 = 0
        if (this.length === 1 && this.words[0] === 0) {
          this.negative = 0;
        }
        return this;
      };
    
      // Check Symbol.for because not everywhere where Symbol defined
      // See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol#Browser_compatibility
      if (typeof Symbol !== 'undefined' && typeof Symbol.for === 'function') {
        try {
          BN.prototype[Symbol.for('nodejs.util.inspect.custom')] = inspect;
        } catch (e) {
          BN.prototype.inspect = inspect;
        }
      } else {
        BN.prototype.inspect = inspect;
      }
    
      function inspect () {
        return (this.red ? '<BN-R: ' : '<BN: ') + this.toString(16) + '>';
      }
    
      /*
    
      var zeros = [];
      var groupSizes = [];
      var groupBases = [];
    
      var s = '';
      var i = -1;
      while (++i < BN.wordSize) {
        zeros[i] = s;
        s += '0';
      }
      groupSizes[0] = 0;
      groupSizes[1] = 0;
      groupBases[0] = 0;
      groupBases[1] = 0;
      var base = 2 - 1;
      while (++base < 36 + 1) {
        var groupSize = 0;
        var groupBase = 1;
        while (groupBase < (1 << BN.wordSize) / base) {
          groupBase *= base;
          groupSize += 1;
        }
        groupSizes[base] = groupSize;
        groupBases[base] = groupBase;
      }
    
      */
    
      var zeros = [
        '',
        '0',
        '00',
        '000',
        '0000',
        '00000',
        '000000',
        '0000000',
        '00000000',
        '000000000',
        '0000000000',
        '00000000000',
        '000000000000',
        '0000000000000',
        '00000000000000',
        '000000000000000',
        '0000000000000000',
        '00000000000000000',
        '000000000000000000',
        '0000000000000000000',
        '00000000000000000000',
        '000000000000000000000',
        '0000000000000000000000',
        '00000000000000000000000',
        '000000000000000000000000',
        '0000000000000000000000000'
      ];
    
      var groupSizes = [
        0, 0,
        25, 16, 12, 11, 10, 9, 8,
        8, 7, 7, 7, 7, 6, 6,
        6, 6, 6, 6, 6, 5, 5,
        5, 5, 5, 5, 5, 5, 5,
        5, 5, 5, 5, 5, 5, 5
      ];
    
      var groupBases = [
        0, 0,
        33554432, 43046721, 16777216, 48828125, 60466176, 40353607, 16777216,
        43046721, 10000000, 19487171, 35831808, 62748517, 7529536, 11390625,
        16777216, 24137569, 34012224, 47045881, 64000000, 4084101, 5153632,
        6436343, 7962624, 9765625, 11881376, 14348907, 17210368, 20511149,
        24300000, 28629151, 33554432, 39135393, 45435424, 52521875, 60466176
      ];
    
      BN.prototype.toString = function toString (base, padding) {
        base = base || 10;
        padding = padding | 0 || 1;
    
        var out;
        if (base === 16 || base === 'hex') {
          out = '';
          var off = 0;
          var carry = 0;
          for (var i = 0; i < this.length; i++) {
            var w = this.words[i];
            var word = (((w << off) | carry) & 0xffffff).toString(16);
            carry = (w >>> (24 - off)) & 0xffffff;
            off += 2;
            if (off >= 26) {
              off -= 26;
              i--;
            }
            if (carry !== 0 || i !== this.length - 1) {
              out = zeros[6 - word.length] + word + out;
            } else {
              out = word + out;
            }
          }
          if (carry !== 0) {
            out = carry.toString(16) + out;
          }
          while (out.length % padding !== 0) {
            out = '0' + out;
          }
          if (this.negative !== 0) {
            out = '-' + out;
          }
          return out;
        }
    
        if (base === (base | 0) && base >= 2 && base <= 36) {
          // var groupSize = Math.floor(BN.wordSize * Math.LN2 / Math.log(base));
          var groupSize = groupSizes[base];
          // var groupBase = Math.pow(base, groupSize);
          var groupBase = groupBases[base];
          out = '';
          var c = this.clone();
          c.negative = 0;
          while (!c.isZero()) {
            var r = c.modrn(groupBase).toString(base);
            c = c.idivn(groupBase);
    
            if (!c.isZero()) {
              out = zeros[groupSize - r.length] + r + out;
            } else {
              out = r + out;
            }
          }
          if (this.isZero()) {
            out = '0' + out;
          }
          while (out.length % padding !== 0) {
            out = '0' + out;
          }
          if (this.negative !== 0) {
            out = '-' + out;
          }
          return out;
        }
    
        assert(false, 'Base should be between 2 and 36');
      };
    
      BN.prototype.toNumber = function toNumber () {
        var ret = this.words[0];
        if (this.length === 2) {
          ret += this.words[1] * 0x4000000;
        } else if (this.length === 3 && this.words[2] === 0x01) {
          // NOTE: at this stage it is known that the top bit is set
          ret += 0x10000000000000 + (this.words[1] * 0x4000000);
        } else if (this.length > 2) {
          assert(false, 'Number can only safely store up to 53 bits');
        }
        return (this.negative !== 0) ? -ret : ret;
      };
    
      BN.prototype.toJSON = function toJSON () {
        return this.toString(16, 2);
      };
    
      if (Buffer) {
        BN.prototype.toBuffer = function toBuffer (endian, length) {
          return this.toArrayLike(Buffer, endian, length);
        };
      }
    
      BN.prototype.toArray = function toArray (endian, length) {
        return this.toArrayLike(Array, endian, length);
      };
    
      var allocate = function allocate (ArrayType, size) {
        if (ArrayType.allocUnsafe) {
          return ArrayType.allocUnsafe(size);
        }
        return new ArrayType(size);
      };
    
      BN.prototype.toArrayLike = function toArrayLike (ArrayType, endian, length) {
        this._strip();
    
        var byteLength = this.byteLength();
        var reqLength = length || Math.max(1, byteLength);
        assert(byteLength <= reqLength, 'byte array longer than desired length');
        assert(reqLength > 0, 'Requested array length <= 0');
    
        var res = allocate(ArrayType, reqLength);
        var postfix = endian === 'le' ? 'LE' : 'BE';
        this['_toArrayLike' + postfix](res, byteLength);
        return res;
      };
    
      BN.prototype._toArrayLikeLE = function _toArrayLikeLE (res, byteLength) {
        var position = 0;
        var carry = 0;
    
        for (var i = 0, shift = 0; i < this.length; i++) {
          var word = (this.words[i] << shift) | carry;
    
          res[position++] = word & 0xff;
          if (position < res.length) {
            res[position++] = (word >> 8) & 0xff;
          }
          if (position < res.length) {
            res[position++] = (word >> 16) & 0xff;
          }
    
          if (shift === 6) {
            if (position < res.length) {
              res[position++] = (word >> 24) & 0xff;
            }
            carry = 0;
            shift = 0;
          } else {
            carry = word >>> 24;
            shift += 2;
          }
        }
    
        if (position < res.length) {
          res[position++] = carry;
    
          while (position < res.length) {
            res[position++] = 0;
          }
        }
      };
    
      BN.prototype._toArrayLikeBE = function _toArrayLikeBE (res, byteLength) {
        var position = res.length - 1;
        var carry = 0;
    
        for (var i = 0, shift = 0; i < this.length; i++) {
          var word = (this.words[i] << shift) | carry;
    
          res[position--] = word & 0xff;
          if (position >= 0) {
            res[position--] = (word >> 8) & 0xff;
          }
          if (position >= 0) {
            res[position--] = (word >> 16) & 0xff;
          }
    
          if (shift === 6) {
            if (position >= 0) {
              res[position--] = (word >> 24) & 0xff;
            }
            carry = 0;
            shift = 0;
          } else {
            carry = word >>> 24;
            shift += 2;
          }
        }
    
        if (position >= 0) {
          res[position--] = carry;
    
          while (position >= 0) {
            res[position--] = 0;
          }
        }
      };
    
      if (Math.clz32) {
        BN.prototype._countBits = function _countBits (w) {
          return 32 - Math.clz32(w);
        };
      } else {
        BN.prototype._countBits = function _countBits (w) {
          var t = w;
          var r = 0;
          if (t >= 0x1000) {
            r += 13;
            t >>>= 13;
          }
          if (t >= 0x40) {
            r += 7;
            t >>>= 7;
          }
          if (t >= 0x8) {
            r += 4;
            t >>>= 4;
          }
          if (t >= 0x02) {
            r += 2;
            t >>>= 2;
          }
          return r + t;
        };
      }
    
      BN.prototype._zeroBits = function _zeroBits (w) {
        // Short-cut
        if (w === 0) return 26;
    
        var t = w;
        var r = 0;
        if ((t & 0x1fff) === 0) {
          r += 13;
          t >>>= 13;
        }
        if ((t & 0x7f) === 0) {
          r += 7;
          t >>>= 7;
        }
        if ((t & 0xf) === 0) {
          r += 4;
          t >>>= 4;
        }
        if ((t & 0x3) === 0) {
          r += 2;
          t >>>= 2;
        }
        if ((t & 0x1) === 0) {
          r++;
        }
        return r;
      };
    
      // Return number of used bits in a BN
      BN.prototype.bitLength = function bitLength () {
        var w = this.words[this.length - 1];
        var hi = this._countBits(w);
        return (this.length - 1) * 26 + hi;
      };
    
      function toBitArray (num) {
        var w = new Array(num.bitLength());
    
        for (var bit = 0; bit < w.length; bit++) {
          var off = (bit / 26) | 0;
          var wbit = bit % 26;
    
          w[bit] = (num.words[off] >>> wbit) & 0x01;
        }
    
        return w;
      }
    
      // Number of trailing zero bits
      BN.prototype.zeroBits = function zeroBits () {
        if (this.isZero()) return 0;
    
        var r = 0;
        for (var i = 0; i < this.length; i++) {
          var b = this._zeroBits(this.words[i]);
          r += b;
          if (b !== 26) break;
        }
        return r;
      };
    
      BN.prototype.byteLength = function byteLength () {
        return Math.ceil(this.bitLength() / 8);
      };
    
      BN.prototype.toTwos = function toTwos (width) {
        if (this.negative !== 0) {
          return this.abs().inotn(width).iaddn(1);
        }
        return this.clone();
      };
    
      BN.prototype.fromTwos = function fromTwos (width) {
        if (this.testn(width - 1)) {
          return this.notn(width).iaddn(1).ineg();
        }
        return this.clone();
      };
    
      BN.prototype.isNeg = function isNeg () {
        return this.negative !== 0;
      };
    
      // Return negative clone of `this`
      BN.prototype.neg = function neg () {
        return this.clone().ineg();
      };
    
      BN.prototype.ineg = function ineg () {
        if (!this.isZero()) {
          this.negative ^= 1;
        }
    
        return this;
      };
    
      // Or `num` with `this` in-place
      BN.prototype.iuor = function iuor (num) {
        while (this.length < num.length) {
          this.words[this.length++] = 0;
        }
    
        for (var i = 0; i < num.length; i++) {
          this.words[i] = this.words[i] | num.words[i];
        }
    
        return this._strip();
      };
    
      BN.prototype.ior = function ior (num) {
        assert((this.negative | num.negative) === 0);
        return this.iuor(num);
      };
    
      // Or `num` with `this`
      BN.prototype.or = function or (num) {
        if (this.length > num.length) return this.clone().ior(num);
        return num.clone().ior(this);
      };
    
      BN.prototype.uor = function uor (num) {
        if (this.length > num.length) return this.clone().iuor(num);
        return num.clone().iuor(this);
      };
    
      // And `num` with `this` in-place
      BN.prototype.iuand = function iuand (num) {
        // b = min-length(num, this)
        var b;
        if (this.length > num.length) {
          b = num;
        } else {
          b = this;
        }
    
        for (var i = 0; i < b.length; i++) {
          this.words[i] = this.words[i] & num.words[i];
        }
    
        this.length = b.length;
    
        return this._strip();
      };
    
      BN.prototype.iand = function iand (num) {
        assert((this.negative | num.negative) === 0);
        return this.iuand(num);
      };
    
      // And `num` with `this`
      BN.prototype.and = function and (num) {
        if (this.length > num.length) return this.clone().iand(num);
        return num.clone().iand(this);
      };
    
      BN.prototype.uand = function uand (num) {
        if (this.length > num.length) return this.clone().iuand(num);
        return num.clone().iuand(this);
      };
    
      // Xor `num` with `this` in-place
      BN.prototype.iuxor = function iuxor (num) {
        // a.length > b.length
        var a;
        var b;
        if (this.length > num.length) {
          a = this;
          b = num;
        } else {
          a = num;
          b = this;
        }
    
        for (var i = 0; i < b.length; i++) {
          this.words[i] = a.words[i] ^ b.words[i];
        }
    
        if (this !== a) {
          for (; i < a.length; i++) {
            this.words[i] = a.words[i];
          }
        }
    
        this.length = a.length;
    
        return this._strip();
      };
    
      BN.prototype.ixor = function ixor (num) {
        assert((this.negative | num.negative) === 0);
        return this.iuxor(num);
      };
    
      // Xor `num` with `this`
      BN.prototype.xor = function xor (num) {
        if (this.length > num.length) return this.clone().ixor(num);
        return num.clone().ixor(this);
      };
    
      BN.prototype.uxor = function uxor (num) {
        if (this.length > num.length) return this.clone().iuxor(num);
        return num.clone().iuxor(this);
      };
    
      // Not ``this`` with ``width`` bitwidth
      BN.prototype.inotn = function inotn (width) {
        assert(typeof width === 'number' && width >= 0);
    
        var bytesNeeded = Math.ceil(width / 26) | 0;
        var bitsLeft = width % 26;
    
        // Extend the buffer with leading zeroes
        this._expand(bytesNeeded);
    
        if (bitsLeft > 0) {
          bytesNeeded--;
        }
    
        // Handle complete words
        for (var i = 0; i < bytesNeeded; i++) {
          this.words[i] = ~this.words[i] & 0x3ffffff;
        }
    
        // Handle the residue
        if (bitsLeft > 0) {
          this.words[i] = ~this.words[i] & (0x3ffffff >> (26 - bitsLeft));
        }
    
        // And remove leading zeroes
        return this._strip();
      };
    
      BN.prototype.notn = function notn (width) {
        return this.clone().inotn(width);
      };
    
      // Set `bit` of `this`
      BN.prototype.setn = function setn (bit, val) {
        assert(typeof bit === 'number' && bit >= 0);
    
        var off = (bit / 26) | 0;
        var wbit = bit % 26;
    
        this._expand(off + 1);
    
        if (val) {
          this.words[off] = this.words[off] | (1 << wbit);
        } else {
          this.words[off] = this.words[off] & ~(1 << wbit);
        }
    
        return this._strip();
      };
    
      // Add `num` to `this` in-place
      BN.prototype.iadd = function iadd (num) {
        var r;
    
        // negative + positive
        if (this.negative !== 0 && num.negative === 0) {
          this.negative = 0;
          r = this.isub(num);
          this.negative ^= 1;
          return this._normSign();
    
        // positive + negative
        } else if (this.negative === 0 && num.negative !== 0) {
          num.negative = 0;
          r = this.isub(num);
          num.negative = 1;
          return r._normSign();
        }
    
        // a.length > b.length
        var a, b;
        if (this.length > num.length) {
          a = this;
          b = num;
        } else {
          a = num;
          b = this;
        }
    
        var carry = 0;
        for (var i = 0; i < b.length; i++) {
          r = (a.words[i] | 0) + (b.words[i] | 0) + carry;
          this.words[i] = r & 0x3ffffff;
          carry = r >>> 26;
        }
        for (; carry !== 0 && i < a.length; i++) {
          r = (a.words[i] | 0) + carry;
          this.words[i] = r & 0x3ffffff;
          carry = r >>> 26;
        }
    
        this.length = a.length;
        if (carry !== 0) {
          this.words[this.length] = carry;
          this.length++;
        // Copy the rest of the words
        } else if (a !== this) {
          for (; i < a.length; i++) {
            this.words[i] = a.words[i];
          }
        }
    
        return this;
      };
    
      // Add `num` to `this`
      BN.prototype.add = function add (num) {
        var res;
        if (num.negative !== 0 && this.negative === 0) {
          num.negative = 0;
          res = this.sub(num);
          num.negative ^= 1;
          return res;
        } else if (num.negative === 0 && this.negative !== 0) {
          this.negative = 0;
          res = num.sub(this);
          this.negative = 1;
          return res;
        }
    
        if (this.length > num.length) return this.clone().iadd(num);
    
        return num.clone().iadd(this);
      };
    
      // Subtract `num` from `this` in-place
      BN.prototype.isub = function isub (num) {
        // this - (-num) = this + num
        if (num.negative !== 0) {
          num.negative = 0;
          var r = this.iadd(num);
          num.negative = 1;
          return r._normSign();
    
        // -this - num = -(this + num)
        } else if (this.negative !== 0) {
          this.negative = 0;
          this.iadd(num);
          this.negative = 1;
          return this._normSign();
        }
    
        // At this point both numbers are positive
        var cmp = this.cmp(num);
    
        // Optimization - zeroify
        if (cmp === 0) {
          this.negative = 0;
          this.length = 1;
          this.words[0] = 0;
          return this;
        }
    
        // a > b
        var a, b;
        if (cmp > 0) {
          a = this;
          b = num;
        } else {
          a = num;
          b = this;
        }
    
        var carry = 0;
        for (var i = 0; i < b.length; i++) {
          r = (a.words[i] | 0) - (b.words[i] | 0) + carry;
          carry = r >> 26;
          this.words[i] = r & 0x3ffffff;
        }
        for (; carry !== 0 && i < a.length; i++) {
          r = (a.words[i] | 0) + carry;
          carry = r >> 26;
          this.words[i] = r & 0x3ffffff;
        }
    
        // Copy rest of the words
        if (carry === 0 && i < a.length && a !== this) {
          for (; i < a.length; i++) {
            this.words[i] = a.words[i];
          }
        }
    
        this.length = Math.max(this.length, i);
    
        if (a !== this) {
          this.negative = 1;
        }
    
        return this._strip();
      };
    
      // Subtract `num` from `this`
      BN.prototype.sub = function sub (num) {
        return this.clone().isub(num);
      };
    
      function smallMulTo (self, num, out) {
        out.negative = num.negative ^ self.negative;
        var len = (self.length + num.length) | 0;
        out.length = len;
        len = (len - 1) | 0;
    
        // Peel one iteration (compiler can't do it, because of code complexity)
        var a = self.words[0] | 0;
        var b = num.words[0] | 0;
        var r = a * b;
    
        var lo = r & 0x3ffffff;
        var carry = (r / 0x4000000) | 0;
        out.words[0] = lo;
    
        for (var k = 1; k < len; k++) {
          // Sum all words with the same `i + j = k` and accumulate `ncarry`,
          // note that ncarry could be >= 0x3ffffff
          var ncarry = carry >>> 26;
          var rword = carry & 0x3ffffff;
          var maxJ = Math.min(k, num.length - 1);
          for (var j = Math.max(0, k - self.length + 1); j <= maxJ; j++) {
            var i = (k - j) | 0;
            a = self.words[i] | 0;
            b = num.words[j] | 0;
            r = a * b + rword;
            ncarry += (r / 0x4000000) | 0;
            rword = r & 0x3ffffff;
          }
          out.words[k] = rword | 0;
          carry = ncarry | 0;
        }
        if (carry !== 0) {
          out.words[k] = carry | 0;
        } else {
          out.length--;
        }
    
        return out._strip();
      }
    
      // TODO(indutny): it may be reasonable to omit it for users who don't need
      // to work with 256-bit numbers, otherwise it gives 20% improvement for 256-bit
      // multiplication (like elliptic secp256k1).
      var comb10MulTo = function comb10MulTo (self, num, out) {
        var a = self.words;
        var b = num.words;
        var o = out.words;
        var c = 0;
        var lo;
        var mid;
        var hi;
        var a0 = a[0] | 0;
        var al0 = a0 & 0x1fff;
        var ah0 = a0 >>> 13;
        var a1 = a[1] | 0;
        var al1 = a1 & 0x1fff;
        var ah1 = a1 >>> 13;
        var a2 = a[2] | 0;
        var al2 = a2 & 0x1fff;
        var ah2 = a2 >>> 13;
        var a3 = a[3] | 0;
        var al3 = a3 & 0x1fff;
        var ah3 = a3 >>> 13;
        var a4 = a[4] | 0;
        var al4 = a4 & 0x1fff;
        var ah4 = a4 >>> 13;
        var a5 = a[5] | 0;
        var al5 = a5 & 0x1fff;
        var ah5 = a5 >>> 13;
        var a6 = a[6] | 0;
        var al6 = a6 & 0x1fff;
        var ah6 = a6 >>> 13;
        var a7 = a[7] | 0;
        var al7 = a7 & 0x1fff;
        var ah7 = a7 >>> 13;
        var a8 = a[8] | 0;
        var al8 = a8 & 0x1fff;
        var ah8 = a8 >>> 13;
        var a9 = a[9] | 0;
        var al9 = a9 & 0x1fff;
        var ah9 = a9 >>> 13;
        var b0 = b[0] | 0;
        var bl0 = b0 & 0x1fff;
        var bh0 = b0 >>> 13;
        var b1 = b[1] | 0;
        var bl1 = b1 & 0x1fff;
        var bh1 = b1 >>> 13;
        var b2 = b[2] | 0;
        var bl2 = b2 & 0x1fff;
        var bh2 = b2 >>> 13;
        var b3 = b[3] | 0;
        var bl3 = b3 & 0x1fff;
        var bh3 = b3 >>> 13;
        var b4 = b[4] | 0;
        var bl4 = b4 & 0x1fff;
        var bh4 = b4 >>> 13;
        var b5 = b[5] | 0;
        var bl5 = b5 & 0x1fff;
        var bh5 = b5 >>> 13;
        var b6 = b[6] | 0;
        var bl6 = b6 & 0x1fff;
        var bh6 = b6 >>> 13;
        var b7 = b[7] | 0;
        var bl7 = b7 & 0x1fff;
        var bh7 = b7 >>> 13;
        var b8 = b[8] | 0;
        var bl8 = b8 & 0x1fff;
        var bh8 = b8 >>> 13;
        var b9 = b[9] | 0;
        var bl9 = b9 & 0x1fff;
        var bh9 = b9 >>> 13;
    
        out.negative = self.negative ^ num.negative;
        out.length = 19;
        /* k = 0 */
        lo = Math.imul(al0, bl0);
        mid = Math.imul(al0, bh0);
        mid = (mid + Math.imul(ah0, bl0)) | 0;
        hi = Math.imul(ah0, bh0);
        var w0 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
        c = (((hi + (mid >>> 13)) | 0) + (w0 >>> 26)) | 0;
        w0 &= 0x3ffffff;
        /* k = 1 */
        lo = Math.imul(al1, bl0);
        mid = Math.imul(al1, bh0);
        mid = (mid + Math.imul(ah1, bl0)) | 0;
        hi = Math.imul(ah1, bh0);
        lo = (lo + Math.imul(al0, bl1)) | 0;
        mid = (mid + Math.imul(al0, bh1)) | 0;
        mid = (mid + Math.imul(ah0, bl1)) | 0;
        hi = (hi + Math.imul(ah0, bh1)) | 0;
        var w1 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
        c = (((hi + (mid >>> 13)) | 0) + (w1 >>> 26)) | 0;
        w1 &= 0x3ffffff;
        /* k = 2 */
        lo = Math.imul(al2, bl0);
        mid = Math.imul(al2, bh0);
        mid = (mid + Math.imul(ah2, bl0)) | 0;
        hi = Math.imul(ah2, bh0);
        lo = (lo + Math.imul(al1, bl1)) | 0;
        mid = (mid + Math.imul(al1, bh1)) | 0;
        mid = (mid + Math.imul(ah1, bl1)) | 0;
        hi = (hi + Math.imul(ah1, bh1)) | 0;
        lo = (lo + Math.imul(al0, bl2)) | 0;
        mid = (mid + Math.imul(al0, bh2)) | 0;
        mid = (mid + Math.imul(ah0, bl2)) | 0;
        hi = (hi + Math.imul(ah0, bh2)) | 0;
        var w2 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
        c = (((hi + (mid >>> 13)) | 0) + (w2 >>> 26)) | 0;
        w2 &= 0x3ffffff;
        /* k = 3 */
        lo = Math.imul(al3, bl0);
        mid = Math.imul(al3, bh0);
        mid = (mid + Math.imul(ah3, bl0)) | 0;
        hi = Math.imul(ah3, bh0);
        lo = (lo + Math.imul(al2, bl1)) | 0;
        mid = (mid + Math.imul(al2, bh1)) | 0;
        mid = (mid + Math.imul(ah2, bl1)) | 0;
        hi = (hi + Math.imul(ah2, bh1)) | 0;
        lo = (lo + Math.imul(al1, bl2)) | 0;
        mid = (mid + Math.imul(al1, bh2)) | 0;
        mid = (mid + Math.imul(ah1, bl2)) | 0;
        hi = (hi + Math.imul(ah1, bh2)) | 0;
        lo = (lo + Math.imul(al0, bl3)) | 0;
        mid = (mid + Math.imul(al0, bh3)) | 0;
        mid = (mid + Math.imul(ah0, bl3)) | 0;
        hi = (hi + Math.imul(ah0, bh3)) | 0;
        var w3 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
        c = (((hi + (mid >>> 13)) | 0) + (w3 >>> 26)) | 0;
        w3 &= 0x3ffffff;
        /* k = 4 */
        lo = Math.imul(al4, bl0);
        mid = Math.imul(al4, bh0);
        mid = (mid + Math.imul(ah4, bl0)) | 0;
        hi = Math.imul(ah4, bh0);
        lo = (lo + Math.imul(al3, bl1)) | 0;
        mid = (mid + Math.imul(al3, bh1)) | 0;
        mid = (mid + Math.imul(ah3, bl1)) | 0;
        hi = (hi + Math.imul(ah3, bh1)) | 0;
        lo = (lo + Math.imul(al2, bl2)) | 0;
        mid = (mid + Math.imul(al2, bh2)) | 0;
        mid = (mid + Math.imul(ah2, bl2)) | 0;
        hi = (hi + Math.imul(ah2, bh2)) | 0;
        lo = (lo + Math.imul(al1, bl3)) | 0;
        mid = (mid + Math.imul(al1, bh3)) | 0;
        mid = (mid + Math.imul(ah1, bl3)) | 0;
        hi = (hi + Math.imul(ah1, bh3)) | 0;
        lo = (lo + Math.imul(al0, bl4)) | 0;
        mid = (mid + Math.imul(al0, bh4)) | 0;
        mid = (mid + Math.imul(ah0, bl4)) | 0;
        hi = (hi + Math.imul(ah0, bh4)) | 0;
        var w4 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
        c = (((hi + (mid >>> 13)) | 0) + (w4 >>> 26)) | 0;
        w4 &= 0x3ffffff;
        /* k = 5 */
        lo = Math.imul(al5, bl0);
        mid = Math.imul(al5, bh0);
        mid = (mid + Math.imul(ah5, bl0)) | 0;
        hi = Math.imul(ah5, bh0);
        lo = (lo + Math.imul(al4, bl1)) | 0;
        mid = (mid + Math.imul(al4, bh1)) | 0;
        mid = (mid + Math.imul(ah4, bl1)) | 0;
        hi = (hi + Math.imul(ah4, bh1)) | 0;
        lo = (lo + Math.imul(al3, bl2)) | 0;
        mid = (mid + Math.imul(al3, bh2)) | 0;
        mid = (mid + Math.imul(ah3, bl2)) | 0;
        hi = (hi + Math.imul(ah3, bh2)) | 0;
        lo = (lo + Math.imul(al2, bl3)) | 0;
        mid = (mid + Math.imul(al2, bh3)) | 0;
        mid = (mid + Math.imul(ah2, bl3)) | 0;
        hi = (hi + Math.imul(ah2, bh3)) | 0;
        lo = (lo + Math.imul(al1, bl4)) | 0;
        mid = (mid + Math.imul(al1, bh4)) | 0;
        mid = (mid + Math.imul(ah1, bl4)) | 0;
        hi = (hi + Math.imul(ah1, bh4)) | 0;
        lo = (lo + Math.imul(al0, bl5)) | 0;
        mid = (mid + Math.imul(al0, bh5)) | 0;
        mid = (mid + Math.imul(ah0, bl5)) | 0;
        hi = (hi + Math.imul(ah0, bh5)) | 0;
        var w5 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
        c = (((hi + (mid >>> 13)) | 0) + (w5 >>> 26)) | 0;
        w5 &= 0x3ffffff;
        /* k = 6 */
        lo = Math.imul(al6, bl0);
        mid = Math.imul(al6, bh0);
        mid = (mid + Math.imul(ah6, bl0)) | 0;
        hi = Math.imul(ah6, bh0);
        lo = (lo + Math.imul(al5, bl1)) | 0;
        mid = (mid + Math.imul(al5, bh1)) | 0;
        mid = (mid + Math.imul(ah5, bl1)) | 0;
        hi = (hi + Math.imul(ah5, bh1)) | 0;
        lo = (lo + Math.imul(al4, bl2)) | 0;
        mid = (mid + Math.imul(al4, bh2)) | 0;
        mid = (mid + Math.imul(ah4, bl2)) | 0;
        hi = (hi + Math.imul(ah4, bh2)) | 0;
        lo = (lo + Math.imul(al3, bl3)) | 0;
        mid = (mid + Math.imul(al3, bh3)) | 0;
        mid = (mid + Math.imul(ah3, bl3)) | 0;
        hi = (hi + Math.imul(ah3, bh3)) | 0;
        lo = (lo + Math.imul(al2, bl4)) | 0;
        mid = (mid + Math.imul(al2, bh4)) | 0;
        mid = (mid + Math.imul(ah2, bl4)) | 0;
        hi = (hi + Math.imul(ah2, bh4)) | 0;
        lo = (lo + Math.imul(al1, bl5)) | 0;
        mid = (mid + Math.imul(al1, bh5)) | 0;
        mid = (mid + Math.imul(ah1, bl5)) | 0;
        hi = (hi + Math.imul(ah1, bh5)) | 0;
        lo = (lo + Math.imul(al0, bl6)) | 0;
        mid = (mid + Math.imul(al0, bh6)) | 0;
        mid = (mid + Math.imul(ah0, bl6)) | 0;
        hi = (hi + Math.imul(ah0, bh6)) | 0;
        var w6 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
        c = (((hi + (mid >>> 13)) | 0) + (w6 >>> 26)) | 0;
        w6 &= 0x3ffffff;
        /* k = 7 */
        lo = Math.imul(al7, bl0);
        mid = Math.imul(al7, bh0);
        mid = (mid + Math.imul(ah7, bl0)) | 0;
        hi = Math.imul(ah7, bh0);
        lo = (lo + Math.imul(al6, bl1)) | 0;
        mid = (mid + Math.imul(al6, bh1)) | 0;
        mid = (mid + Math.imul(ah6, bl1)) | 0;
        hi = (hi + Math.imul(ah6, bh1)) | 0;
        lo = (lo + Math.imul(al5, bl2)) | 0;
        mid = (mid + Math.imul(al5, bh2)) | 0;
        mid = (mid + Math.imul(ah5, bl2)) | 0;
        hi = (hi + Math.imul(ah5, bh2)) | 0;
        lo = (lo + Math.imul(al4, bl3)) | 0;
        mid = (mid + Math.imul(al4, bh3)) | 0;
        mid = (mid + Math.imul(ah4, bl3)) | 0;
        hi = (hi + Math.imul(ah4, bh3)) | 0;
        lo = (lo + Math.imul(al3, bl4)) | 0;
        mid = (mid + Math.imul(al3, bh4)) | 0;
        mid = (mid + Math.imul(ah3, bl4)) | 0;
        hi = (hi + Math.imul(ah3, bh4)) | 0;
        lo = (lo + Math.imul(al2, bl5)) | 0;
        mid = (mid + Math.imul(al2, bh5)) | 0;
        mid = (mid + Math.imul(ah2, bl5)) | 0;
        hi = (hi + Math.imul(ah2, bh5)) | 0;
        lo = (lo + Math.imul(al1, bl6)) | 0;
        mid = (mid + Math.imul(al1, bh6)) | 0;
        mid = (mid + Math.imul(ah1, bl6)) | 0;
        hi = (hi + Math.imul(ah1, bh6)) | 0;
        lo = (lo + Math.imul(al0, bl7)) | 0;
        mid = (mid + Math.imul(al0, bh7)) | 0;
        mid = (mid + Math.imul(ah0, bl7)) | 0;
        hi = (hi + Math.imul(ah0, bh7)) | 0;
        var w7 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
        c = (((hi + (mid >>> 13)) | 0) + (w7 >>> 26)) | 0;
        w7 &= 0x3ffffff;
        /* k = 8 */
        lo = Math.imul(al8, bl0);
        mid = Math.imul(al8, bh0);
        mid = (mid + Math.imul(ah8, bl0)) | 0;
        hi = Math.imul(ah8, bh0);
        lo = (lo + Math.imul(al7, bl1)) | 0;
        mid = (mid + Math.imul(al7, bh1)) | 0;
        mid = (mid + Math.imul(ah7, bl1)) | 0;
        hi = (hi + Math.imul(ah7, bh1)) | 0;
        lo = (lo + Math.imul(al6, bl2)) | 0;
        mid = (mid + Math.imul(al6, bh2)) | 0;
        mid = (mid + Math.imul(ah6, bl2)) | 0;
        hi = (hi + Math.imul(ah6, bh2)) | 0;
        lo = (lo + Math.imul(al5, bl3)) | 0;
        mid = (mid + Math.imul(al5, bh3)) | 0;
        mid = (mid + Math.imul(ah5, bl3)) | 0;
        hi = (hi + Math.imul(ah5, bh3)) | 0;
        lo = (lo + Math.imul(al4, bl4)) | 0;
        mid = (mid + Math.imul(al4, bh4)) | 0;
        mid = (mid + Math.imul(ah4, bl4)) | 0;
        hi = (hi + Math.imul(ah4, bh4)) | 0;
        lo = (lo + Math.imul(al3, bl5)) | 0;
        mid = (mid + Math.imul(al3, bh5)) | 0;
        mid = (mid + Math.imul(ah3, bl5)) | 0;
        hi = (hi + Math.imul(ah3, bh5)) | 0;
        lo = (lo + Math.imul(al2, bl6)) | 0;
        mid = (mid + Math.imul(al2, bh6)) | 0;
        mid = (mid + Math.imul(ah2, bl6)) | 0;
        hi = (hi + Math.imul(ah2, bh6)) | 0;
        lo = (lo + Math.imul(al1, bl7)) | 0;
        mid = (mid + Math.imul(al1, bh7)) | 0;
        mid = (mid + Math.imul(ah1, bl7)) | 0;
        hi = (hi + Math.imul(ah1, bh7)) | 0;
        lo = (lo + Math.imul(al0, bl8)) | 0;
        mid = (mid + Math.imul(al0, bh8)) | 0;
        mid = (mid + Math.imul(ah0, bl8)) | 0;
        hi = (hi + Math.imul(ah0, bh8)) | 0;
        var w8 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
        c = (((hi + (mid >>> 13)) | 0) + (w8 >>> 26)) | 0;
        w8 &= 0x3ffffff;
        /* k = 9 */
        lo = Math.imul(al9, bl0);
        mid = Math.imul(al9, bh0);
        mid = (mid + Math.imul(ah9, bl0)) | 0;
        hi = Math.imul(ah9, bh0);
        lo = (lo + Math.imul(al8, bl1)) | 0;
        mid = (mid + Math.imul(al8, bh1)) | 0;
        mid = (mid + Math.imul(ah8, bl1)) | 0;
        hi = (hi + Math.imul(ah8, bh1)) | 0;
        lo = (lo + Math.imul(al7, bl2)) | 0;
        mid = (mid + Math.imul(al7, bh2)) | 0;
        mid = (mid + Math.imul(ah7, bl2)) | 0;
        hi = (hi + Math.imul(ah7, bh2)) | 0;
        lo = (lo + Math.imul(al6, bl3)) | 0;
        mid = (mid + Math.imul(al6, bh3)) | 0;
        mid = (mid + Math.imul(ah6, bl3)) | 0;
        hi = (hi + Math.imul(ah6, bh3)) | 0;
        lo = (lo + Math.imul(al5, bl4)) | 0;
        mid = (mid + Math.imul(al5, bh4)) | 0;
        mid = (mid + Math.imul(ah5, bl4)) | 0;
        hi = (hi + Math.imul(ah5, bh4)) | 0;
        lo = (lo + Math.imul(al4, bl5)) | 0;
        mid = (mid + Math.imul(al4, bh5)) | 0;
        mid = (mid + Math.imul(ah4, bl5)) | 0;
        hi = (hi + Math.imul(ah4, bh5)) | 0;
        lo = (lo + Math.imul(al3, bl6)) | 0;
        mid = (mid + Math.imul(al3, bh6)) | 0;
        mid = (mid + Math.imul(ah3, bl6)) | 0;
        hi = (hi + Math.imul(ah3, bh6)) | 0;
        lo = (lo + Math.imul(al2, bl7)) | 0;
        mid = (mid + Math.imul(al2, bh7)) | 0;
        mid = (mid + Math.imul(ah2, bl7)) | 0;
        hi = (hi + Math.imul(ah2, bh7)) | 0;
        lo = (lo + Math.imul(al1, bl8)) | 0;
        mid = (mid + Math.imul(al1, bh8)) | 0;
        mid = (mid + Math.imul(ah1, bl8)) | 0;
        hi = (hi + Math.imul(ah1, bh8)) | 0;
        lo = (lo + Math.imul(al0, bl9)) | 0;
        mid = (mid + Math.imul(al0, bh9)) | 0;
        mid = (mid + Math.imul(ah0, bl9)) | 0;
        hi = (hi + Math.imul(ah0, bh9)) | 0;
        var w9 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
        c = (((hi + (mid >>> 13)) | 0) + (w9 >>> 26)) | 0;
        w9 &= 0x3ffffff;
        /* k = 10 */
        lo = Math.imul(al9, bl1);
        mid = Math.imul(al9, bh1);
        mid = (mid + Math.imul(ah9, bl1)) | 0;
        hi = Math.imul(ah9, bh1);
        lo = (lo + Math.imul(al8, bl2)) | 0;
        mid = (mid + Math.imul(al8, bh2)) | 0;
        mid = (mid + Math.imul(ah8, bl2)) | 0;
        hi = (hi + Math.imul(ah8, bh2)) | 0;
        lo = (lo + Math.imul(al7, bl3)) | 0;
        mid = (mid + Math.imul(al7, bh3)) | 0;
        mid = (mid + Math.imul(ah7, bl3)) | 0;
        hi = (hi + Math.imul(ah7, bh3)) | 0;
        lo = (lo + Math.imul(al6, bl4)) | 0;
        mid = (mid + Math.imul(al6, bh4)) | 0;
        mid = (mid + Math.imul(ah6, bl4)) | 0;
        hi = (hi + Math.imul(ah6, bh4)) | 0;
        lo = (lo + Math.imul(al5, bl5)) | 0;
        mid = (mid + Math.imul(al5, bh5)) | 0;
        mid = (mid + Math.imul(ah5, bl5)) | 0;
        hi = (hi + Math.imul(ah5, bh5)) | 0;
        lo = (lo + Math.imul(al4, bl6)) | 0;
        mid = (mid + Math.imul(al4, bh6)) | 0;
        mid = (mid + Math.imul(ah4, bl6)) | 0;
        hi = (hi + Math.imul(ah4, bh6)) | 0;
        lo = (lo + Math.imul(al3, bl7)) | 0;
        mid = (mid + Math.imul(al3, bh7)) | 0;
        mid = (mid + Math.imul(ah3, bl7)) | 0;
        hi = (hi + Math.imul(ah3, bh7)) | 0;
        lo = (lo + Math.imul(al2, bl8)) | 0;
        mid = (mid + Math.imul(al2, bh8)) | 0;
        mid = (mid + Math.imul(ah2, bl8)) | 0;
        hi = (hi + Math.imul(ah2, bh8)) | 0;
        lo = (lo + Math.imul(al1, bl9)) | 0;
        mid = (mid + Math.imul(al1, bh9)) | 0;
        mid = (mid + Math.imul(ah1, bl9)) | 0;
        hi = (hi + Math.imul(ah1, bh9)) | 0;
        var w10 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
        c = (((hi + (mid >>> 13)) | 0) + (w10 >>> 26)) | 0;
        w10 &= 0x3ffffff;
        /* k = 11 */
        lo = Math.imul(al9, bl2);
        mid = Math.imul(al9, bh2);
        mid = (mid + Math.imul(ah9, bl2)) | 0;
        hi = Math.imul(ah9, bh2);
        lo = (lo + Math.imul(al8, bl3)) | 0;
        mid = (mid + Math.imul(al8, bh3)) | 0;
        mid = (mid + Math.imul(ah8, bl3)) | 0;
        hi = (hi + Math.imul(ah8, bh3)) | 0;
        lo = (lo + Math.imul(al7, bl4)) | 0;
        mid = (mid + Math.imul(al7, bh4)) | 0;
        mid = (mid + Math.imul(ah7, bl4)) | 0;
        hi = (hi + Math.imul(ah7, bh4)) | 0;
        lo = (lo + Math.imul(al6, bl5)) | 0;
        mid = (mid + Math.imul(al6, bh5)) | 0;
        mid = (mid + Math.imul(ah6, bl5)) | 0;
        hi = (hi + Math.imul(ah6, bh5)) | 0;
        lo = (lo + Math.imul(al5, bl6)) | 0;
        mid = (mid + Math.imul(al5, bh6)) | 0;
        mid = (mid + Math.imul(ah5, bl6)) | 0;
        hi = (hi + Math.imul(ah5, bh6)) | 0;
        lo = (lo + Math.imul(al4, bl7)) | 0;
        mid = (mid + Math.imul(al4, bh7)) | 0;
        mid = (mid + Math.imul(ah4, bl7)) | 0;
        hi = (hi + Math.imul(ah4, bh7)) | 0;
        lo = (lo + Math.imul(al3, bl8)) | 0;
        mid = (mid + Math.imul(al3, bh8)) | 0;
        mid = (mid + Math.imul(ah3, bl8)) | 0;
        hi = (hi + Math.imul(ah3, bh8)) | 0;
        lo = (lo + Math.imul(al2, bl9)) | 0;
        mid = (mid + Math.imul(al2, bh9)) | 0;
        mid = (mid + Math.imul(ah2, bl9)) | 0;
        hi = (hi + Math.imul(ah2, bh9)) | 0;
        var w11 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
        c = (((hi + (mid >>> 13)) | 0) + (w11 >>> 26)) | 0;
        w11 &= 0x3ffffff;
        /* k = 12 */
        lo = Math.imul(al9, bl3);
        mid = Math.imul(al9, bh3);
        mid = (mid + Math.imul(ah9, bl3)) | 0;
        hi = Math.imul(ah9, bh3);
        lo = (lo + Math.imul(al8, bl4)) | 0;
        mid = (mid + Math.imul(al8, bh4)) | 0;
        mid = (mid + Math.imul(ah8, bl4)) | 0;
        hi = (hi + Math.imul(ah8, bh4)) | 0;
        lo = (lo + Math.imul(al7, bl5)) | 0;
        mid = (mid + Math.imul(al7, bh5)) | 0;
        mid = (mid + Math.imul(ah7, bl5)) | 0;
        hi = (hi + Math.imul(ah7, bh5)) | 0;
        lo = (lo + Math.imul(al6, bl6)) | 0;
        mid = (mid + Math.imul(al6, bh6)) | 0;
        mid = (mid + Math.imul(ah6, bl6)) | 0;
        hi = (hi + Math.imul(ah6, bh6)) | 0;
        lo = (lo + Math.imul(al5, bl7)) | 0;
        mid = (mid + Math.imul(al5, bh7)) | 0;
        mid = (mid + Math.imul(ah5, bl7)) | 0;
        hi = (hi + Math.imul(ah5, bh7)) | 0;
        lo = (lo + Math.imul(al4, bl8)) | 0;
        mid = (mid + Math.imul(al4, bh8)) | 0;
        mid = (mid + Math.imul(ah4, bl8)) | 0;
        hi = (hi + Math.imul(ah4, bh8)) | 0;
        lo = (lo + Math.imul(al3, bl9)) | 0;
        mid = (mid + Math.imul(al3, bh9)) | 0;
        mid = (mid + Math.imul(ah3, bl9)) | 0;
        hi = (hi + Math.imul(ah3, bh9)) | 0;
        var w12 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
        c = (((hi + (mid >>> 13)) | 0) + (w12 >>> 26)) | 0;
        w12 &= 0x3ffffff;
        /* k = 13 */
        lo = Math.imul(al9, bl4);
        mid = Math.imul(al9, bh4);
        mid = (mid + Math.imul(ah9, bl4)) | 0;
        hi = Math.imul(ah9, bh4);
        lo = (lo + Math.imul(al8, bl5)) | 0;
        mid = (mid + Math.imul(al8, bh5)) | 0;
        mid = (mid + Math.imul(ah8, bl5)) | 0;
        hi = (hi + Math.imul(ah8, bh5)) | 0;
        lo = (lo + Math.imul(al7, bl6)) | 0;
        mid = (mid + Math.imul(al7, bh6)) | 0;
        mid = (mid + Math.imul(ah7, bl6)) | 0;
        hi = (hi + Math.imul(ah7, bh6)) | 0;
        lo = (lo + Math.imul(al6, bl7)) | 0;
        mid = (mid + Math.imul(al6, bh7)) | 0;
        mid = (mid + Math.imul(ah6, bl7)) | 0;
        hi = (hi + Math.imul(ah6, bh7)) | 0;
        lo = (lo + Math.imul(al5, bl8)) | 0;
        mid = (mid + Math.imul(al5, bh8)) | 0;
        mid = (mid + Math.imul(ah5, bl8)) | 0;
        hi = (hi + Math.imul(ah5, bh8)) | 0;
        lo = (lo + Math.imul(al4, bl9)) | 0;
        mid = (mid + Math.imul(al4, bh9)) | 0;
        mid = (mid + Math.imul(ah4, bl9)) | 0;
        hi = (hi + Math.imul(ah4, bh9)) | 0;
        var w13 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
        c = (((hi + (mid >>> 13)) | 0) + (w13 >>> 26)) | 0;
        w13 &= 0x3ffffff;
        /* k = 14 */
        lo = Math.imul(al9, bl5);
        mid = Math.imul(al9, bh5);
        mid = (mid + Math.imul(ah9, bl5)) | 0;
        hi = Math.imul(ah9, bh5);
        lo = (lo + Math.imul(al8, bl6)) | 0;
        mid = (mid + Math.imul(al8, bh6)) | 0;
        mid = (mid + Math.imul(ah8, bl6)) | 0;
        hi = (hi + Math.imul(ah8, bh6)) | 0;
        lo = (lo + Math.imul(al7, bl7)) | 0;
        mid = (mid + Math.imul(al7, bh7)) | 0;
        mid = (mid + Math.imul(ah7, bl7)) | 0;
        hi = (hi + Math.imul(ah7, bh7)) | 0;
        lo = (lo + Math.imul(al6, bl8)) | 0;
        mid = (mid + Math.imul(al6, bh8)) | 0;
        mid = (mid + Math.imul(ah6, bl8)) | 0;
        hi = (hi + Math.imul(ah6, bh8)) | 0;
        lo = (lo + Math.imul(al5, bl9)) | 0;
        mid = (mid + Math.imul(al5, bh9)) | 0;
        mid = (mid + Math.imul(ah5, bl9)) | 0;
        hi = (hi + Math.imul(ah5, bh9)) | 0;
        var w14 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
        c = (((hi + (mid >>> 13)) | 0) + (w14 >>> 26)) | 0;
        w14 &= 0x3ffffff;
        /* k = 15 */
        lo = Math.imul(al9, bl6);
        mid = Math.imul(al9, bh6);
        mid = (mid + Math.imul(ah9, bl6)) | 0;
        hi = Math.imul(ah9, bh6);
        lo = (lo + Math.imul(al8, bl7)) | 0;
        mid = (mid + Math.imul(al8, bh7)) | 0;
        mid = (mid + Math.imul(ah8, bl7)) | 0;
        hi = (hi + Math.imul(ah8, bh7)) | 0;
        lo = (lo + Math.imul(al7, bl8)) | 0;
        mid = (mid + Math.imul(al7, bh8)) | 0;
        mid = (mid + Math.imul(ah7, bl8)) | 0;
        hi = (hi + Math.imul(ah7, bh8)) | 0;
        lo = (lo + Math.imul(al6, bl9)) | 0;
        mid = (mid + Math.imul(al6, bh9)) | 0;
        mid = (mid + Math.imul(ah6, bl9)) | 0;
        hi = (hi + Math.imul(ah6, bh9)) | 0;
        var w15 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
        c = (((hi + (mid >>> 13)) | 0) + (w15 >>> 26)) | 0;
        w15 &= 0x3ffffff;
        /* k = 16 */
        lo = Math.imul(al9, bl7);
        mid = Math.imul(al9, bh7);
        mid = (mid + Math.imul(ah9, bl7)) | 0;
        hi = Math.imul(ah9, bh7);
        lo = (lo + Math.imul(al8, bl8)) | 0;
        mid = (mid + Math.imul(al8, bh8)) | 0;
        mid = (mid + Math.imul(ah8, bl8)) | 0;
        hi = (hi + Math.imul(ah8, bh8)) | 0;
        lo = (lo + Math.imul(al7, bl9)) | 0;
        mid = (mid + Math.imul(al7, bh9)) | 0;
        mid = (mid + Math.imul(ah7, bl9)) | 0;
        hi = (hi + Math.imul(ah7, bh9)) | 0;
        var w16 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
        c = (((hi + (mid >>> 13)) | 0) + (w16 >>> 26)) | 0;
        w16 &= 0x3ffffff;
        /* k = 17 */
        lo = Math.imul(al9, bl8);
        mid = Math.imul(al9, bh8);
        mid = (mid + Math.imul(ah9, bl8)) | 0;
        hi = Math.imul(ah9, bh8);
        lo = (lo + Math.imul(al8, bl9)) | 0;
        mid = (mid + Math.imul(al8, bh9)) | 0;
        mid = (mid + Math.imul(ah8, bl9)) | 0;
        hi = (hi + Math.imul(ah8, bh9)) | 0;
        var w17 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
        c = (((hi + (mid >>> 13)) | 0) + (w17 >>> 26)) | 0;
        w17 &= 0x3ffffff;
        /* k = 18 */
        lo = Math.imul(al9, bl9);
        mid = Math.imul(al9, bh9);
        mid = (mid + Math.imul(ah9, bl9)) | 0;
        hi = Math.imul(ah9, bh9);
        var w18 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
        c = (((hi + (mid >>> 13)) | 0) + (w18 >>> 26)) | 0;
        w18 &= 0x3ffffff;
        o[0] = w0;
        o[1] = w1;
        o[2] = w2;
        o[3] = w3;
        o[4] = w4;
        o[5] = w5;
        o[6] = w6;
        o[7] = w7;
        o[8] = w8;
        o[9] = w9;
        o[10] = w10;
        o[11] = w11;
        o[12] = w12;
        o[13] = w13;
        o[14] = w14;
        o[15] = w15;
        o[16] = w16;
        o[17] = w17;
        o[18] = w18;
        if (c !== 0) {
          o[19] = c;
          out.length++;
        }
        return out;
      };
    
      // Polyfill comb
      if (!Math.imul) {
        comb10MulTo = smallMulTo;
      }
    
      function bigMulTo (self, num, out) {
        out.negative = num.negative ^ self.negative;
        out.length = self.length + num.length;
    
        var carry = 0;
        var hncarry = 0;
        for (var k = 0; k < out.length - 1; k++) {
          // Sum all words with the same `i + j = k` and accumulate `ncarry`,
          // note that ncarry could be >= 0x3ffffff
          var ncarry = hncarry;
          hncarry = 0;
          var rword = carry & 0x3ffffff;
          var maxJ = Math.min(k, num.length - 1);
          for (var j = Math.max(0, k - self.length + 1); j <= maxJ; j++) {
            var i = k - j;
            var a = self.words[i] | 0;
            var b = num.words[j] | 0;
            var r = a * b;
    
            var lo = r & 0x3ffffff;
            ncarry = (ncarry + ((r / 0x4000000) | 0)) | 0;
            lo = (lo + rword) | 0;
            rword = lo & 0x3ffffff;
            ncarry = (ncarry + (lo >>> 26)) | 0;
    
            hncarry += ncarry >>> 26;
            ncarry &= 0x3ffffff;
          }
          out.words[k] = rword;
          carry = ncarry;
          ncarry = hncarry;
        }
        if (carry !== 0) {
          out.words[k] = carry;
        } else {
          out.length--;
        }
    
        return out._strip();
      }
    
      function jumboMulTo (self, num, out) {
        // Temporary disable, see https://github.com/indutny/bn.js/issues/211
        // var fftm = new FFTM();
        // return fftm.mulp(self, num, out);
        return bigMulTo(self, num, out);
      }
    
      BN.prototype.mulTo = function mulTo (num, out) {
        var res;
        var len = this.length + num.length;
        if (this.length === 10 && num.length === 10) {
          res = comb10MulTo(this, num, out);
        } else if (len < 63) {
          res = smallMulTo(this, num, out);
        } else if (len < 1024) {
          res = bigMulTo(this, num, out);
        } else {
          res = jumboMulTo(this, num, out);
        }
    
        return res;
      };
    
      // Cooley-Tukey algorithm for FFT
      // slightly revisited to rely on looping instead of recursion
    
      function FFTM (x, y) {
        this.x = x;
        this.y = y;
      }
    
      FFTM.prototype.makeRBT = function makeRBT (N) {
        var t = new Array(N);
        var l = BN.prototype._countBits(N) - 1;
        for (var i = 0; i < N; i++) {
          t[i] = this.revBin(i, l, N);
        }
    
        return t;
      };
    
      // Returns binary-reversed representation of `x`
      FFTM.prototype.revBin = function revBin (x, l, N) {
        if (x === 0 || x === N - 1) return x;
    
        var rb = 0;
        for (var i = 0; i < l; i++) {
          rb |= (x & 1) << (l - i - 1);
          x >>= 1;
        }
    
        return rb;
      };
    
      // Performs "tweedling" phase, therefore 'emulating'
      // behaviour of the recursive algorithm
      FFTM.prototype.permute = function permute (rbt, rws, iws, rtws, itws, N) {
        for (var i = 0; i < N; i++) {
          rtws[i] = rws[rbt[i]];
          itws[i] = iws[rbt[i]];
        }
      };
    
      FFTM.prototype.transform = function transform (rws, iws, rtws, itws, N, rbt) {
        this.permute(rbt, rws, iws, rtws, itws, N);
    
        for (var s = 1; s < N; s <<= 1) {
          var l = s << 1;
    
          var rtwdf = Math.cos(2 * Math.PI / l);
          var itwdf = Math.sin(2 * Math.PI / l);
    
          for (var p = 0; p < N; p += l) {
            var rtwdf_ = rtwdf;
            var itwdf_ = itwdf;
    
            for (var j = 0; j < s; j++) {
              var re = rtws[p + j];
              var ie = itws[p + j];
    
              var ro = rtws[p + j + s];
              var io = itws[p + j + s];
    
              var rx = rtwdf_ * ro - itwdf_ * io;
    
              io = rtwdf_ * io + itwdf_ * ro;
              ro = rx;
    
              rtws[p + j] = re + ro;
              itws[p + j] = ie + io;
    
              rtws[p + j + s] = re - ro;
              itws[p + j + s] = ie - io;
    
              /* jshint maxdepth : false */
              if (j !== l) {
                rx = rtwdf * rtwdf_ - itwdf * itwdf_;
    
                itwdf_ = rtwdf * itwdf_ + itwdf * rtwdf_;
                rtwdf_ = rx;
              }
            }
          }
        }
      };
    
      FFTM.prototype.guessLen13b = function guessLen13b (n, m) {
        var N = Math.max(m, n) | 1;
        var odd = N & 1;
        var i = 0;
        for (N = N / 2 | 0; N; N = N >>> 1) {
          i++;
        }
    
        return 1 << i + 1 + odd;
      };
    
      FFTM.prototype.conjugate = function conjugate (rws, iws, N) {
        if (N <= 1) return;
    
        for (var i = 0; i < N / 2; i++) {
          var t = rws[i];
    
          rws[i] = rws[N - i - 1];
          rws[N - i - 1] = t;
    
          t = iws[i];
    
          iws[i] = -iws[N - i - 1];
          iws[N - i - 1] = -t;
        }
      };
    
      FFTM.prototype.normalize13b = function normalize13b (ws, N) {
        var carry = 0;
        for (var i = 0; i < N / 2; i++) {
          var w = Math.round(ws[2 * i + 1] / N) * 0x2000 +
            Math.round(ws[2 * i] / N) +
            carry;
    
          ws[i] = w & 0x3ffffff;
    
          if (w < 0x4000000) {
            carry = 0;
          } else {
            carry = w / 0x4000000 | 0;
          }
        }
    
        return ws;
      };
    
      FFTM.prototype.convert13b = function convert13b (ws, len, rws, N) {
        var carry = 0;
        for (var i = 0; i < len; i++) {
          carry = carry + (ws[i] | 0);
    
          rws[2 * i] = carry & 0x1fff; carry = carry >>> 13;
          rws[2 * i + 1] = carry & 0x1fff; carry = carry >>> 13;
        }
    
        // Pad with zeroes
        for (i = 2 * len; i < N; ++i) {
          rws[i] = 0;
        }
    
        assert(carry === 0);
        assert((carry & ~0x1fff) === 0);
      };
    
      FFTM.prototype.stub = function stub (N) {
        var ph = new Array(N);
        for (var i = 0; i < N; i++) {
          ph[i] = 0;
        }
    
        return ph;
      };
    
      FFTM.prototype.mulp = function mulp (x, y, out) {
        var N = 2 * this.guessLen13b(x.length, y.length);
    
        var rbt = this.makeRBT(N);
    
        var _ = this.stub(N);
    
        var rws = new Array(N);
        var rwst = new Array(N);
        var iwst = new Array(N);
    
        var nrws = new Array(N);
        var nrwst = new Array(N);
        var niwst = new Array(N);
    
        var rmws = out.words;
        rmws.length = N;
    
        this.convert13b(x.words, x.length, rws, N);
        this.convert13b(y.words, y.length, nrws, N);
    
        this.transform(rws, _, rwst, iwst, N, rbt);
        this.transform(nrws, _, nrwst, niwst, N, rbt);
    
        for (var i = 0; i < N; i++) {
          var rx = rwst[i] * nrwst[i] - iwst[i] * niwst[i];
          iwst[i] = rwst[i] * niwst[i] + iwst[i] * nrwst[i];
          rwst[i] = rx;
        }
    
        this.conjugate(rwst, iwst, N);
        this.transform(rwst, iwst, rmws, _, N, rbt);
        this.conjugate(rmws, _, N);
        this.normalize13b(rmws, N);
    
        out.negative = x.negative ^ y.negative;
        out.length = x.length + y.length;
        return out._strip();
      };
    
      // Multiply `this` by `num`
      BN.prototype.mul = function mul (num) {
        var out = new BN(null);
        out.words = new Array(this.length + num.length);
        return this.mulTo(num, out);
      };
    
      // Multiply employing FFT
      BN.prototype.mulf = function mulf (num) {
        var out = new BN(null);
        out.words = new Array(this.length + num.length);
        return jumboMulTo(this, num, out);
      };
    
      // In-place Multiplication
      BN.prototype.imul = function imul (num) {
        return this.clone().mulTo(num, this);
      };
    
      BN.prototype.imuln = function imuln (num) {
        var isNegNum = num < 0;
        if (isNegNum) num = -num;
    
        assert(typeof num === 'number');
        assert(num < 0x4000000);
    
        // Carry
        var carry = 0;
        for (var i = 0; i < this.length; i++) {
          var w = (this.words[i] | 0) * num;
          var lo = (w & 0x3ffffff) + (carry & 0x3ffffff);
          carry >>= 26;
          carry += (w / 0x4000000) | 0;
          // NOTE: lo is 27bit maximum
          carry += lo >>> 26;
          this.words[i] = lo & 0x3ffffff;
        }
    
        if (carry !== 0) {
          this.words[i] = carry;
          this.length++;
        }
    
        return isNegNum ? this.ineg() : this;
      };
    
      BN.prototype.muln = function muln (num) {
        return this.clone().imuln(num);
      };
    
      // `this` * `this`
      BN.prototype.sqr = function sqr () {
        return this.mul(this);
      };
    
      // `this` * `this` in-place
      BN.prototype.isqr = function isqr () {
        return this.imul(this.clone());
      };
    
      // Math.pow(`this`, `num`)
      BN.prototype.pow = function pow (num) {
        var w = toBitArray(num);
        if (w.length === 0) return new BN(1);
    
        // Skip leading zeroes
        var res = this;
        for (var i = 0; i < w.length; i++, res = res.sqr()) {
          if (w[i] !== 0) break;
        }
    
        if (++i < w.length) {
          for (var q = res.sqr(); i < w.length; i++, q = q.sqr()) {
            if (w[i] === 0) continue;
    
            res = res.mul(q);
          }
        }
    
        return res;
      };
    
      // Shift-left in-place
      BN.prototype.iushln = function iushln (bits) {
        assert(typeof bits === 'number' && bits >= 0);
        var r = bits % 26;
        var s = (bits - r) / 26;
        var carryMask = (0x3ffffff >>> (26 - r)) << (26 - r);
        var i;
    
        if (r !== 0) {
          var carry = 0;
    
          for (i = 0; i < this.length; i++) {
            var newCarry = this.words[i] & carryMask;
            var c = ((this.words[i] | 0) - newCarry) << r;
            this.words[i] = c | carry;
            carry = newCarry >>> (26 - r);
          }
    
          if (carry) {
            this.words[i] = carry;
            this.length++;
          }
        }
    
        if (s !== 0) {
          for (i = this.length - 1; i >= 0; i--) {
            this.words[i + s] = this.words[i];
          }
    
          for (i = 0; i < s; i++) {
            this.words[i] = 0;
          }
    
          this.length += s;
        }
    
        return this._strip();
      };
    
      BN.prototype.ishln = function ishln (bits) {
        // TODO(indutny): implement me
        assert(this.negative === 0);
        return this.iushln(bits);
      };
    
      // Shift-right in-place
      // NOTE: `hint` is a lowest bit before trailing zeroes
      // NOTE: if `extended` is present - it will be filled with destroyed bits
      BN.prototype.iushrn = function iushrn (bits, hint, extended) {
        assert(typeof bits === 'number' && bits >= 0);
        var h;
        if (hint) {
          h = (hint - (hint % 26)) / 26;
        } else {
          h = 0;
        }
    
        var r = bits % 26;
        var s = Math.min((bits - r) / 26, this.length);
        var mask = 0x3ffffff ^ ((0x3ffffff >>> r) << r);
        var maskedWords = extended;
    
        h -= s;
        h = Math.max(0, h);
    
        // Extended mode, copy masked part
        if (maskedWords) {
          for (var i = 0; i < s; i++) {
            maskedWords.words[i] = this.words[i];
          }
          maskedWords.length = s;
        }
    
        if (s === 0) {
          // No-op, we should not move anything at all
        } else if (this.length > s) {
          this.length -= s;
          for (i = 0; i < this.length; i++) {
            this.words[i] = this.words[i + s];
          }
        } else {
          this.words[0] = 0;
          this.length = 1;
        }
    
        var carry = 0;
        for (i = this.length - 1; i >= 0 && (carry !== 0 || i >= h); i--) {
          var word = this.words[i] | 0;
          this.words[i] = (carry << (26 - r)) | (word >>> r);
          carry = word & mask;
        }
    
        // Push carried bits as a mask
        if (maskedWords && carry !== 0) {
          maskedWords.words[maskedWords.length++] = carry;
        }
    
        if (this.length === 0) {
          this.words[0] = 0;
          this.length = 1;
        }
    
        return this._strip();
      };
    
      BN.prototype.ishrn = function ishrn (bits, hint, extended) {
        // TODO(indutny): implement me
        assert(this.negative === 0);
        return this.iushrn(bits, hint, extended);
      };
    
      // Shift-left
      BN.prototype.shln = function shln (bits) {
        return this.clone().ishln(bits);
      };
    
      BN.prototype.ushln = function ushln (bits) {
        return this.clone().iushln(bits);
      };
    
      // Shift-right
      BN.prototype.shrn = function shrn (bits) {
        return this.clone().ishrn(bits);
      };
    
      BN.prototype.ushrn = function ushrn (bits) {
        return this.clone().iushrn(bits);
      };
    
      // Test if n bit is set
      BN.prototype.testn = function testn (bit) {
        assert(typeof bit === 'number' && bit >= 0);
        var r = bit % 26;
        var s = (bit - r) / 26;
        var q = 1 << r;
    
        // Fast case: bit is much higher than all existing words
        if (this.length <= s) return false;
    
        // Check bit and return
        var w = this.words[s];
    
        return !!(w & q);
      };
    
      // Return only lowers bits of number (in-place)
      BN.prototype.imaskn = function imaskn (bits) {
        assert(typeof bits === 'number' && bits >= 0);
        var r = bits % 26;
        var s = (bits - r) / 26;
    
        assert(this.negative === 0, 'imaskn works only with positive numbers');
    
        if (this.length <= s) {
          return this;
        }
    
        if (r !== 0) {
          s++;
        }
        this.length = Math.min(s, this.length);
    
        if (r !== 0) {
          var mask = 0x3ffffff ^ ((0x3ffffff >>> r) << r);
          this.words[this.length - 1] &= mask;
        }
    
        return this._strip();
      };
    
      // Return only lowers bits of number
      BN.prototype.maskn = function maskn (bits) {
        return this.clone().imaskn(bits);
      };
    
      // Add plain number `num` to `this`
      BN.prototype.iaddn = function iaddn (num) {
        assert(typeof num === 'number');
        assert(num < 0x4000000);
        if (num < 0) return this.isubn(-num);
    
        // Possible sign change
        if (this.negative !== 0) {
          if (this.length === 1 && (this.words[0] | 0) <= num) {
            this.words[0] = num - (this.words[0] | 0);
            this.negative = 0;
            return this;
          }
    
          this.negative = 0;
          this.isubn(num);
          this.negative = 1;
          return this;
        }
    
        // Add without checks
        return this._iaddn(num);
      };
    
      BN.prototype._iaddn = function _iaddn (num) {
        this.words[0] += num;
    
        // Carry
        for (var i = 0; i < this.length && this.words[i] >= 0x4000000; i++) {
          this.words[i] -= 0x4000000;
          if (i === this.length - 1) {
            this.words[i + 1] = 1;
          } else {
            this.words[i + 1]++;
          }
        }
        this.length = Math.max(this.length, i + 1);
    
        return this;
      };
    
      // Subtract plain number `num` from `this`
      BN.prototype.isubn = function isubn (num) {
        assert(typeof num === 'number');
        assert(num < 0x4000000);
        if (num < 0) return this.iaddn(-num);
    
        if (this.negative !== 0) {
          this.negative = 0;
          this.iaddn(num);
          this.negative = 1;
          return this;
        }
    
        this.words[0] -= num;
    
        if (this.length === 1 && this.words[0] < 0) {
          this.words[0] = -this.words[0];
          this.negative = 1;
        } else {
          // Carry
          for (var i = 0; i < this.length && this.words[i] < 0; i++) {
            this.words[i] += 0x4000000;
            this.words[i + 1] -= 1;
          }
        }
    
        return this._strip();
      };
    
      BN.prototype.addn = function addn (num) {
        return this.clone().iaddn(num);
      };
    
      BN.prototype.subn = function subn (num) {
        return this.clone().isubn(num);
      };
    
      BN.prototype.iabs = function iabs () {
        this.negative = 0;
    
        return this;
      };
    
      BN.prototype.abs = function abs () {
        return this.clone().iabs();
      };
    
      BN.prototype._ishlnsubmul = function _ishlnsubmul (num, mul, shift) {
        var len = num.length + shift;
        var i;
    
        this._expand(len);
    
        var w;
        var carry = 0;
        for (i = 0; i < num.length; i++) {
          w = (this.words[i + shift] | 0) + carry;
          var right = (num.words[i] | 0) * mul;
          w -= right & 0x3ffffff;
          carry = (w >> 26) - ((right / 0x4000000) | 0);
          this.words[i + shift] = w & 0x3ffffff;
        }
        for (; i < this.length - shift; i++) {
          w = (this.words[i + shift] | 0) + carry;
          carry = w >> 26;
          this.words[i + shift] = w & 0x3ffffff;
        }
    
        if (carry === 0) return this._strip();
    
        // Subtraction overflow
        assert(carry === -1);
        carry = 0;
        for (i = 0; i < this.length; i++) {
          w = -(this.words[i] | 0) + carry;
          carry = w >> 26;
          this.words[i] = w & 0x3ffffff;
        }
        this.negative = 1;
    
        return this._strip();
      };
    
      BN.prototype._wordDiv = function _wordDiv (num, mode) {
        var shift = this.length - num.length;
    
        var a = this.clone();
        var b = num;
    
        // Normalize
        var bhi = b.words[b.length - 1] | 0;
        var bhiBits = this._countBits(bhi);
        shift = 26 - bhiBits;
        if (shift !== 0) {
          b = b.ushln(shift);
          a.iushln(shift);
          bhi = b.words[b.length - 1] | 0;
        }
    
        // Initialize quotient
        var m = a.length - b.length;
        var q;
    
        if (mode !== 'mod') {
          q = new BN(null);
          q.length = m + 1;
          q.words = new Array(q.length);
          for (var i = 0; i < q.length; i++) {
            q.words[i] = 0;
          }
        }
    
        var diff = a.clone()._ishlnsubmul(b, 1, m);
        if (diff.negative === 0) {
          a = diff;
          if (q) {
            q.words[m] = 1;
          }
        }
    
        for (var j = m - 1; j >= 0; j--) {
          var qj = (a.words[b.length + j] | 0) * 0x4000000 +
            (a.words[b.length + j - 1] | 0);
    
          // NOTE: (qj / bhi) is (0x3ffffff * 0x4000000 + 0x3ffffff) / 0x2000000 max
          // (0x7ffffff)
          qj = Math.min((qj / bhi) | 0, 0x3ffffff);
    
          a._ishlnsubmul(b, qj, j);
          while (a.negative !== 0) {
            qj--;
            a.negative = 0;
            a._ishlnsubmul(b, 1, j);
            if (!a.isZero()) {
              a.negative ^= 1;
            }
          }
          if (q) {
            q.words[j] = qj;
          }
        }
        if (q) {
          q._strip();
        }
        a._strip();
    
        // Denormalize
        if (mode !== 'div' && shift !== 0) {
          a.iushrn(shift);
        }
    
        return {
          div: q || null,
          mod: a
        };
      };
    
      // NOTE: 1) `mode` can be set to `mod` to request mod only,
      //       to `div` to request div only, or be absent to
      //       request both div & mod
      //       2) `positive` is true if unsigned mod is requested
      BN.prototype.divmod = function divmod (num, mode, positive) {
        assert(!num.isZero());
    
        if (this.isZero()) {
          return {
            div: new BN(0),
            mod: new BN(0)
          };
        }
    
        var div, mod, res;
        if (this.negative !== 0 && num.negative === 0) {
          res = this.neg().divmod(num, mode);
    
          if (mode !== 'mod') {
            div = res.div.neg();
          }
    
          if (mode !== 'div') {
            mod = res.mod.neg();
            if (positive && mod.negative !== 0) {
              mod.iadd(num);
            }
          }
    
          return {
            div: div,
            mod: mod
          };
        }
    
        if (this.negative === 0 && num.negative !== 0) {
          res = this.divmod(num.neg(), mode);
    
          if (mode !== 'mod') {
            div = res.div.neg();
          }
    
          return {
            div: div,
            mod: res.mod
          };
        }
    
        if ((this.negative & num.negative) !== 0) {
          res = this.neg().divmod(num.neg(), mode);
    
          if (mode !== 'div') {
            mod = res.mod.neg();
            if (positive && mod.negative !== 0) {
              mod.isub(num);
            }
          }
    
          return {
            div: res.div,
            mod: mod
          };
        }
    
        // Both numbers are positive at this point
    
        // Strip both numbers to approximate shift value
        if (num.length > this.length || this.cmp(num) < 0) {
          return {
            div: new BN(0),
            mod: this
          };
        }
    
        // Very short reduction
        if (num.length === 1) {
          if (mode === 'div') {
            return {
              div: this.divn(num.words[0]),
              mod: null
            };
          }
    
          if (mode === 'mod') {
            return {
              div: null,
              mod: new BN(this.modrn(num.words[0]))
            };
          }
    
          return {
            div: this.divn(num.words[0]),
            mod: new BN(this.modrn(num.words[0]))
          };
        }
    
        return this._wordDiv(num, mode);
      };
    
      // Find `this` / `num`
      BN.prototype.div = function div (num) {
        return this.divmod(num, 'div', false).div;
      };
    
      // Find `this` % `num`
      BN.prototype.mod = function mod (num) {
        return this.divmod(num, 'mod', false).mod;
      };
    
      BN.prototype.umod = function umod (num) {
        return this.divmod(num, 'mod', true).mod;
      };
    
      // Find Round(`this` / `num`)
      BN.prototype.divRound = function divRound (num) {
        var dm = this.divmod(num);
    
        // Fast case - exact division
        if (dm.mod.isZero()) return dm.div;
    
        var mod = dm.div.negative !== 0 ? dm.mod.isub(num) : dm.mod;
    
        var half = num.ushrn(1);
        var r2 = num.andln(1);
        var cmp = mod.cmp(half);
    
        // Round down
        if (cmp < 0 || (r2 === 1 && cmp === 0)) return dm.div;
    
        // Round up
        return dm.div.negative !== 0 ? dm.div.isubn(1) : dm.div.iaddn(1);
      };
    
      BN.prototype.modrn = function modrn (num) {
        var isNegNum = num < 0;
        if (isNegNum) num = -num;
    
        assert(num <= 0x3ffffff);
        var p = (1 << 26) % num;
    
        var acc = 0;
        for (var i = this.length - 1; i >= 0; i--) {
          acc = (p * acc + (this.words[i] | 0)) % num;
        }
    
        return isNegNum ? -acc : acc;
      };
    
      // WARNING: DEPRECATED
      BN.prototype.modn = function modn (num) {
        return this.modrn(num);
      };
    
      // In-place division by number
      BN.prototype.idivn = function idivn (num) {
        var isNegNum = num < 0;
        if (isNegNum) num = -num;
    
        assert(num <= 0x3ffffff);
    
        var carry = 0;
        for (var i = this.length - 1; i >= 0; i--) {
          var w = (this.words[i] | 0) + carry * 0x4000000;
          this.words[i] = (w / num) | 0;
          carry = w % num;
        }
    
        this._strip();
        return isNegNum ? this.ineg() : this;
      };
    
      BN.prototype.divn = function divn (num) {
        return this.clone().idivn(num);
      };
    
      BN.prototype.egcd = function egcd (p) {
        assert(p.negative === 0);
        assert(!p.isZero());
    
        var x = this;
        var y = p.clone();
    
        if (x.negative !== 0) {
          x = x.umod(p);
        } else {
          x = x.clone();
        }
    
        // A * x + B * y = x
        var A = new BN(1);
        var B = new BN(0);
    
        // C * x + D * y = y
        var C = new BN(0);
        var D = new BN(1);
    
        var g = 0;
    
        while (x.isEven() && y.isEven()) {
          x.iushrn(1);
          y.iushrn(1);
          ++g;
        }
    
        var yp = y.clone();
        var xp = x.clone();
    
        while (!x.isZero()) {
          for (var i = 0, im = 1; (x.words[0] & im) === 0 && i < 26; ++i, im <<= 1);
          if (i > 0) {
            x.iushrn(i);
            while (i-- > 0) {
              if (A.isOdd() || B.isOdd()) {
                A.iadd(yp);
                B.isub(xp);
              }
    
              A.iushrn(1);
              B.iushrn(1);
            }
          }
    
          for (var j = 0, jm = 1; (y.words[0] & jm) === 0 && j < 26; ++j, jm <<= 1);
          if (j > 0) {
            y.iushrn(j);
            while (j-- > 0) {
              if (C.isOdd() || D.isOdd()) {
                C.iadd(yp);
                D.isub(xp);
              }
    
              C.iushrn(1);
              D.iushrn(1);
            }
          }
    
          if (x.cmp(y) >= 0) {
            x.isub(y);
            A.isub(C);
            B.isub(D);
          } else {
            y.isub(x);
            C.isub(A);
            D.isub(B);
          }
        }
    
        return {
          a: C,
          b: D,
          gcd: y.iushln(g)
        };
      };
    
      // This is reduced incarnation of the binary EEA
      // above, designated to invert members of the
      // _prime_ fields F(p) at a maximal speed
      BN.prototype._invmp = function _invmp (p) {
        assert(p.negative === 0);
        assert(!p.isZero());
    
        var a = this;
        var b = p.clone();
    
        if (a.negative !== 0) {
          a = a.umod(p);
        } else {
          a = a.clone();
        }
    
        var x1 = new BN(1);
        var x2 = new BN(0);
    
        var delta = b.clone();
    
        while (a.cmpn(1) > 0 && b.cmpn(1) > 0) {
          for (var i = 0, im = 1; (a.words[0] & im) === 0 && i < 26; ++i, im <<= 1);
          if (i > 0) {
            a.iushrn(i);
            while (i-- > 0) {
              if (x1.isOdd()) {
                x1.iadd(delta);
              }
    
              x1.iushrn(1);
            }
          }
    
          for (var j = 0, jm = 1; (b.words[0] & jm) === 0 && j < 26; ++j, jm <<= 1);
          if (j > 0) {
            b.iushrn(j);
            while (j-- > 0) {
              if (x2.isOdd()) {
                x2.iadd(delta);
              }
    
              x2.iushrn(1);
            }
          }
    
          if (a.cmp(b) >= 0) {
            a.isub(b);
            x1.isub(x2);
          } else {
            b.isub(a);
            x2.isub(x1);
          }
        }
    
        var res;
        if (a.cmpn(1) === 0) {
          res = x1;
        } else {
          res = x2;
        }
    
        if (res.cmpn(0) < 0) {
          res.iadd(p);
        }
    
        return res;
      };
    
      BN.prototype.gcd = function gcd (num) {
        if (this.isZero()) return num.abs();
        if (num.isZero()) return this.abs();
    
        var a = this.clone();
        var b = num.clone();
        a.negative = 0;
        b.negative = 0;
    
        // Remove common factor of two
        for (var shift = 0; a.isEven() && b.isEven(); shift++) {
          a.iushrn(1);
          b.iushrn(1);
        }
    
        do {
          while (a.isEven()) {
            a.iushrn(1);
          }
          while (b.isEven()) {
            b.iushrn(1);
          }
    
          var r = a.cmp(b);
          if (r < 0) {
            // Swap `a` and `b` to make `a` always bigger than `b`
            var t = a;
            a = b;
            b = t;
          } else if (r === 0 || b.cmpn(1) === 0) {
            break;
          }
    
          a.isub(b);
        } while (true);
    
        return b.iushln(shift);
      };
    
      // Invert number in the field F(num)
      BN.prototype.invm = function invm (num) {
        return this.egcd(num).a.umod(num);
      };
    
      BN.prototype.isEven = function isEven () {
        return (this.words[0] & 1) === 0;
      };
    
      BN.prototype.isOdd = function isOdd () {
        return (this.words[0] & 1) === 1;
      };
    
      // And first word and num
      BN.prototype.andln = function andln (num) {
        return this.words[0] & num;
      };
    
      // Increment at the bit position in-line
      BN.prototype.bincn = function bincn (bit) {
        assert(typeof bit === 'number');
        var r = bit % 26;
        var s = (bit - r) / 26;
        var q = 1 << r;
    
        // Fast case: bit is much higher than all existing words
        if (this.length <= s) {
          this._expand(s + 1);
          this.words[s] |= q;
          return this;
        }
    
        // Add bit and propagate, if needed
        var carry = q;
        for (var i = s; carry !== 0 && i < this.length; i++) {
          var w = this.words[i] | 0;
          w += carry;
          carry = w >>> 26;
          w &= 0x3ffffff;
          this.words[i] = w;
        }
        if (carry !== 0) {
          this.words[i] = carry;
          this.length++;
        }
        return this;
      };
    
      BN.prototype.isZero = function isZero () {
        return this.length === 1 && this.words[0] === 0;
      };
    
      BN.prototype.cmpn = function cmpn (num) {
        var negative = num < 0;
    
        if (this.negative !== 0 && !negative) return -1;
        if (this.negative === 0 && negative) return 1;
    
        this._strip();
    
        var res;
        if (this.length > 1) {
          res = 1;
        } else {
          if (negative) {
            num = -num;
          }
    
          assert(num <= 0x3ffffff, 'Number is too big');
    
          var w = this.words[0] | 0;
          res = w === num ? 0 : w < num ? -1 : 1;
        }
        if (this.negative !== 0) return -res | 0;
        return res;
      };
    
      // Compare two numbers and return:
      // 1 - if `this` > `num`
      // 0 - if `this` == `num`
      // -1 - if `this` < `num`
      BN.prototype.cmp = function cmp (num) {
        if (this.negative !== 0 && num.negative === 0) return -1;
        if (this.negative === 0 && num.negative !== 0) return 1;
    
        var res = this.ucmp(num);
        if (this.negative !== 0) return -res | 0;
        return res;
      };
    
      // Unsigned comparison
      BN.prototype.ucmp = function ucmp (num) {
        // At this point both numbers have the same sign
        if (this.length > num.length) return 1;
        if (this.length < num.length) return -1;
    
        var res = 0;
        for (var i = this.length - 1; i >= 0; i--) {
          var a = this.words[i] | 0;
          var b = num.words[i] | 0;
    
          if (a === b) continue;
          if (a < b) {
            res = -1;
          } else if (a > b) {
            res = 1;
          }
          break;
        }
        return res;
      };
    
      BN.prototype.gtn = function gtn (num) {
        return this.cmpn(num) === 1;
      };
    
      BN.prototype.gt = function gt (num) {
        return this.cmp(num) === 1;
      };
    
      BN.prototype.gten = function gten (num) {
        return this.cmpn(num) >= 0;
      };
    
      BN.prototype.gte = function gte (num) {
        return this.cmp(num) >= 0;
      };
    
      BN.prototype.ltn = function ltn (num) {
        return this.cmpn(num) === -1;
      };
    
      BN.prototype.lt = function lt (num) {
        return this.cmp(num) === -1;
      };
    
      BN.prototype.lten = function lten (num) {
        return this.cmpn(num) <= 0;
      };
    
      BN.prototype.lte = function lte (num) {
        return this.cmp(num) <= 0;
      };
    
      BN.prototype.eqn = function eqn (num) {
        return this.cmpn(num) === 0;
      };
    
      BN.prototype.eq = function eq (num) {
        return this.cmp(num) === 0;
      };
    
      //
      // A reduce context, could be using montgomery or something better, depending
      // on the `m` itself.
      //
      BN.red = function red (num) {
        return new Red(num);
      };
    
      BN.prototype.toRed = function toRed (ctx) {
        assert(!this.red, 'Already a number in reduction context');
        assert(this.negative === 0, 'red works only with positives');
        return ctx.convertTo(this)._forceRed(ctx);
      };
    
      BN.prototype.fromRed = function fromRed () {
        assert(this.red, 'fromRed works only with numbers in reduction context');
        return this.red.convertFrom(this);
      };
    
      BN.prototype._forceRed = function _forceRed (ctx) {
        this.red = ctx;
        return this;
      };
    
      BN.prototype.forceRed = function forceRed (ctx) {
        assert(!this.red, 'Already a number in reduction context');
        return this._forceRed(ctx);
      };
    
      BN.prototype.redAdd = function redAdd (num) {
        assert(this.red, 'redAdd works only with red numbers');
        return this.red.add(this, num);
      };
    
      BN.prototype.redIAdd = function redIAdd (num) {
        assert(this.red, 'redIAdd works only with red numbers');
        return this.red.iadd(this, num);
      };
    
      BN.prototype.redSub = function redSub (num) {
        assert(this.red, 'redSub works only with red numbers');
        return this.red.sub(this, num);
      };
    
      BN.prototype.redISub = function redISub (num) {
        assert(this.red, 'redISub works only with red numbers');
        return this.red.isub(this, num);
      };
    
      BN.prototype.redShl = function redShl (num) {
        assert(this.red, 'redShl works only with red numbers');
        return this.red.shl(this, num);
      };
    
      BN.prototype.redMul = function redMul (num) {
        assert(this.red, 'redMul works only with red numbers');
        this.red._verify2(this, num);
        return this.red.mul(this, num);
      };
    
      BN.prototype.redIMul = function redIMul (num) {
        assert(this.red, 'redMul works only with red numbers');
        this.red._verify2(this, num);
        return this.red.imul(this, num);
      };
    
      BN.prototype.redSqr = function redSqr () {
        assert(this.red, 'redSqr works only with red numbers');
        this.red._verify1(this);
        return this.red.sqr(this);
      };
    
      BN.prototype.redISqr = function redISqr () {
        assert(this.red, 'redISqr works only with red numbers');
        this.red._verify1(this);
        return this.red.isqr(this);
      };
    
      // Square root over p
      BN.prototype.redSqrt = function redSqrt () {
        assert(this.red, 'redSqrt works only with red numbers');
        this.red._verify1(this);
        return this.red.sqrt(this);
      };
    
      BN.prototype.redInvm = function redInvm () {
        assert(this.red, 'redInvm works only with red numbers');
        this.red._verify1(this);
        return this.red.invm(this);
      };
    
      // Return negative clone of `this` % `red modulo`
      BN.prototype.redNeg = function redNeg () {
        assert(this.red, 'redNeg works only with red numbers');
        this.red._verify1(this);
        return this.red.neg(this);
      };
    
      BN.prototype.redPow = function redPow (num) {
        assert(this.red && !num.red, 'redPow(normalNum)');
        this.red._verify1(this);
        return this.red.pow(this, num);
      };
    
      // Prime numbers with efficient reduction
      var primes = {
        k256: null,
        p224: null,
        p192: null,
        p25519: null
      };
    
      // Pseudo-Mersenne prime
      function MPrime (name, p) {
        // P = 2 ^ N - K
        this.name = name;
        this.p = new BN(p, 16);
        this.n = this.p.bitLength();
        this.k = new BN(1).iushln(this.n).isub(this.p);
    
        this.tmp = this._tmp();
      }
    
      MPrime.prototype._tmp = function _tmp () {
        var tmp = new BN(null);
        tmp.words = new Array(Math.ceil(this.n / 13));
        return tmp;
      };
    
      MPrime.prototype.ireduce = function ireduce (num) {
        // Assumes that `num` is less than `P^2`
        // num = HI * (2 ^ N - K) + HI * K + LO = HI * K + LO (mod P)
        var r = num;
        var rlen;
    
        do {
          this.split(r, this.tmp);
          r = this.imulK(r);
          r = r.iadd(this.tmp);
          rlen = r.bitLength();
        } while (rlen > this.n);
    
        var cmp = rlen < this.n ? -1 : r.ucmp(this.p);
        if (cmp === 0) {
          r.words[0] = 0;
          r.length = 1;
        } else if (cmp > 0) {
          r.isub(this.p);
        } else {
          if (r.strip !== undefined) {
            // r is a BN v4 instance
            r.strip();
          } else {
            // r is a BN v5 instance
            r._strip();
          }
        }
    
        return r;
      };
    
      MPrime.prototype.split = function split (input, out) {
        input.iushrn(this.n, 0, out);
      };
    
      MPrime.prototype.imulK = function imulK (num) {
        return num.imul(this.k);
      };
    
      function K256 () {
        MPrime.call(
          this,
          'k256',
          'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc2f');
      }
      inherits(K256, MPrime);
    
      K256.prototype.split = function split (input, output) {
        // 256 = 9 * 26 + 22
        var mask = 0x3fffff;
    
        var outLen = Math.min(input.length, 9);
        for (var i = 0; i < outLen; i++) {
          output.words[i] = input.words[i];
        }
        output.length = outLen;
    
        if (input.length <= 9) {
          input.words[0] = 0;
          input.length = 1;
          return;
        }
    
        // Shift by 9 limbs
        var prev = input.words[9];
        output.words[output.length++] = prev & mask;
    
        for (i = 10; i < input.length; i++) {
          var next = input.words[i] | 0;
          input.words[i - 10] = ((next & mask) << 4) | (prev >>> 22);
          prev = next;
        }
        prev >>>= 22;
        input.words[i - 10] = prev;
        if (prev === 0 && input.length > 10) {
          input.length -= 10;
        } else {
          input.length -= 9;
        }
      };
    
      K256.prototype.imulK = function imulK (num) {
        // K = 0x1000003d1 = [ 0x40, 0x3d1 ]
        num.words[num.length] = 0;
        num.words[num.length + 1] = 0;
        num.length += 2;
    
        // bounded at: 0x40 * 0x3ffffff + 0x3d0 = 0x100000390
        var lo = 0;
        for (var i = 0; i < num.length; i++) {
          var w = num.words[i] | 0;
          lo += w * 0x3d1;
          num.words[i] = lo & 0x3ffffff;
          lo = w * 0x40 + ((lo / 0x4000000) | 0);
        }
    
        // Fast length reduction
        if (num.words[num.length - 1] === 0) {
          num.length--;
          if (num.words[num.length - 1] === 0) {
            num.length--;
          }
        }
        return num;
      };
    
      function P224 () {
        MPrime.call(
          this,
          'p224',
          'ffffffff ffffffff ffffffff ffffffff 00000000 00000000 00000001');
      }
      inherits(P224, MPrime);
    
      function P192 () {
        MPrime.call(
          this,
          'p192',
          'ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff');
      }
      inherits(P192, MPrime);
    
      function P25519 () {
        // 2 ^ 255 - 19
        MPrime.call(
          this,
          '25519',
          '7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed');
      }
      inherits(P25519, MPrime);
    
      P25519.prototype.imulK = function imulK (num) {
        // K = 0x13
        var carry = 0;
        for (var i = 0; i < num.length; i++) {
          var hi = (num.words[i] | 0) * 0x13 + carry;
          var lo = hi & 0x3ffffff;
          hi >>>= 26;
    
          num.words[i] = lo;
          carry = hi;
        }
        if (carry !== 0) {
          num.words[num.length++] = carry;
        }
        return num;
      };
    
      // Exported mostly for testing purposes, use plain name instead
      BN._prime = function prime (name) {
        // Cached version of prime
        if (primes[name]) return primes[name];
    
        var prime;
        if (name === 'k256') {
          prime = new K256();
        } else if (name === 'p224') {
          prime = new P224();
        } else if (name === 'p192') {
          prime = new P192();
        } else if (name === 'p25519') {
          prime = new P25519();
        } else {
          throw new Error('Unknown prime ' + name);
        }
        primes[name] = prime;
    
        return prime;
      };
    
      //
      // Base reduction engine
      //
      function Red (m) {
        if (typeof m === 'string') {
          var prime = BN._prime(m);
          this.m = prime.p;
          this.prime = prime;
        } else {
          assert(m.gtn(1), 'modulus must be greater than 1');
          this.m = m;
          this.prime = null;
        }
      }
    
      Red.prototype._verify1 = function _verify1 (a) {
        assert(a.negative === 0, 'red works only with positives');
        assert(a.red, 'red works only with red numbers');
      };
    
      Red.prototype._verify2 = function _verify2 (a, b) {
        assert((a.negative | b.negative) === 0, 'red works only with positives');
        assert(a.red && a.red === b.red,
          'red works only with red numbers');
      };
    
      Red.prototype.imod = function imod (a) {
        if (this.prime) return this.prime.ireduce(a)._forceRed(this);
    
        move(a, a.umod(this.m)._forceRed(this));
        return a;
      };
    
      Red.prototype.neg = function neg (a) {
        if (a.isZero()) {
          return a.clone();
        }
    
        return this.m.sub(a)._forceRed(this);
      };
    
      Red.prototype.add = function add (a, b) {
        this._verify2(a, b);
    
        var res = a.add(b);
        if (res.cmp(this.m) >= 0) {
          res.isub(this.m);
        }
        return res._forceRed(this);
      };
    
      Red.prototype.iadd = function iadd (a, b) {
        this._verify2(a, b);
    
        var res = a.iadd(b);
        if (res.cmp(this.m) >= 0) {
          res.isub(this.m);
        }
        return res;
      };
    
      Red.prototype.sub = function sub (a, b) {
        this._verify2(a, b);
    
        var res = a.sub(b);
        if (res.cmpn(0) < 0) {
          res.iadd(this.m);
        }
        return res._forceRed(this);
      };
    
      Red.prototype.isub = function isub (a, b) {
        this._verify2(a, b);
    
        var res = a.isub(b);
        if (res.cmpn(0) < 0) {
          res.iadd(this.m);
        }
        return res;
      };
    
      Red.prototype.shl = function shl (a, num) {
        this._verify1(a);
        return this.imod(a.ushln(num));
      };
    
      Red.prototype.imul = function imul (a, b) {
        this._verify2(a, b);
        return this.imod(a.imul(b));
      };
    
      Red.prototype.mul = function mul (a, b) {
        this._verify2(a, b);
        return this.imod(a.mul(b));
      };
    
      Red.prototype.isqr = function isqr (a) {
        return this.imul(a, a.clone());
      };
    
      Red.prototype.sqr = function sqr (a) {
        return this.mul(a, a);
      };
    
      Red.prototype.sqrt = function sqrt (a) {
        if (a.isZero()) return a.clone();
    
        var mod3 = this.m.andln(3);
        assert(mod3 % 2 === 1);
    
        // Fast case
        if (mod3 === 3) {
          var pow = this.m.add(new BN(1)).iushrn(2);
          return this.pow(a, pow);
        }
    
        // Tonelli-Shanks algorithm (Totally unoptimized and slow)
        //
        // Find Q and S, that Q * 2 ^ S = (P - 1)
        var q = this.m.subn(1);
        var s = 0;
        while (!q.isZero() && q.andln(1) === 0) {
          s++;
          q.iushrn(1);
        }
        assert(!q.isZero());
    
        var one = new BN(1).toRed(this);
        var nOne = one.redNeg();
    
        // Find quadratic non-residue
        // NOTE: Max is such because of generalized Riemann hypothesis.
        var lpow = this.m.subn(1).iushrn(1);
        var z = this.m.bitLength();
        z = new BN(2 * z * z).toRed(this);
    
        while (this.pow(z, lpow).cmp(nOne) !== 0) {
          z.redIAdd(nOne);
        }
    
        var c = this.pow(z, q);
        var r = this.pow(a, q.addn(1).iushrn(1));
        var t = this.pow(a, q);
        var m = s;
        while (t.cmp(one) !== 0) {
          var tmp = t;
          for (var i = 0; tmp.cmp(one) !== 0; i++) {
            tmp = tmp.redSqr();
          }
          assert(i < m);
          var b = this.pow(c, new BN(1).iushln(m - i - 1));
    
          r = r.redMul(b);
          c = b.redSqr();
          t = t.redMul(c);
          m = i;
        }
    
        return r;
      };
    
      Red.prototype.invm = function invm (a) {
        var inv = a._invmp(this.m);
        if (inv.negative !== 0) {
          inv.negative = 0;
          return this.imod(inv).redNeg();
        } else {
          return this.imod(inv);
        }
      };
    
      Red.prototype.pow = function pow (a, num) {
        if (num.isZero()) return new BN(1).toRed(this);
        if (num.cmpn(1) === 0) return a.clone();
    
        var windowSize = 4;
        var wnd = new Array(1 << windowSize);
        wnd[0] = new BN(1).toRed(this);
        wnd[1] = a;
        for (var i = 2; i < wnd.length; i++) {
          wnd[i] = this.mul(wnd[i - 1], a);
        }
    
        var res = wnd[0];
        var current = 0;
        var currentLen = 0;
        var start = num.bitLength() % 26;
        if (start === 0) {
          start = 26;
        }
    
        for (i = num.length - 1; i >= 0; i--) {
          var word = num.words[i];
          for (var j = start - 1; j >= 0; j--) {
            var bit = (word >> j) & 1;
            if (res !== wnd[0]) {
              res = this.sqr(res);
            }
    
            if (bit === 0 && current === 0) {
              currentLen = 0;
              continue;
            }
    
            current <<= 1;
            current |= bit;
            currentLen++;
            if (currentLen !== windowSize && (i !== 0 || j !== 0)) continue;
    
            res = this.mul(res, wnd[current]);
            currentLen = 0;
            current = 0;
          }
          start = 26;
        }
    
        return res;
      };
    
      Red.prototype.convertTo = function convertTo (num) {
        var r = num.umod(this.m);
    
        return r === num ? r.clone() : r;
      };
    
      Red.prototype.convertFrom = function convertFrom (num) {
        var res = num.clone();
        res.red = null;
        return res;
      };
    
      //
      // Montgomery method engine
      //
    
      BN.mont = function mont (num) {
        return new Mont(num);
      };
    
      function Mont (m) {
        Red.call(this, m);
    
        this.shift = this.m.bitLength();
        if (this.shift % 26 !== 0) {
          this.shift += 26 - (this.shift % 26);
        }
    
        this.r = new BN(1).iushln(this.shift);
        this.r2 = this.imod(this.r.sqr());
        this.rinv = this.r._invmp(this.m);
    
        this.minv = this.rinv.mul(this.r).isubn(1).div(this.m);
        this.minv = this.minv.umod(this.r);
        this.minv = this.r.sub(this.minv);
      }
      inherits(Mont, Red);
    
      Mont.prototype.convertTo = function convertTo (num) {
        return this.imod(num.ushln(this.shift));
      };
    
      Mont.prototype.convertFrom = function convertFrom (num) {
        var r = this.imod(num.mul(this.rinv));
        r.red = null;
        return r;
      };
    
      Mont.prototype.imul = function imul (a, b) {
        if (a.isZero() || b.isZero()) {
          a.words[0] = 0;
          a.length = 1;
          return a;
        }
    
        var t = a.imul(b);
        var c = t.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m);
        var u = t.isub(c).iushrn(this.shift);
        var res = u;
    
        if (u.cmp(this.m) >= 0) {
          res = u.isub(this.m);
        } else if (u.cmpn(0) < 0) {
          res = u.iadd(this.m);
        }
    
        return res._forceRed(this);
      };
    
      Mont.prototype.mul = function mul (a, b) {
        if (a.isZero() || b.isZero()) return new BN(0)._forceRed(this);
    
        var t = a.mul(b);
        var c = t.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m);
        var u = t.isub(c).iushrn(this.shift);
        var res = u;
        if (u.cmp(this.m) >= 0) {
          res = u.isub(this.m);
        } else if (u.cmpn(0) < 0) {
          res = u.iadd(this.m);
        }
    
        return res._forceRed(this);
      };
    
      Mont.prototype.invm = function invm (a) {
        // (AR)^-1 * R^2 = (A^-1 * R^-1) * R^2 = A^-1 * R
        var res = this.imod(a._invmp(this.m).mul(this.r2));
        return res._forceRed(this);
      };
    })(typeof module === 'undefined' || module, this);
    
    },{"buffer":24}],23:[function(require,module,exports){
    var r;
    
    module.exports = function rand(len) {
      if (!r)
        r = new Rand(null);
    
      return r.generate(len);
    };
    
    function Rand(rand) {
      this.rand = rand;
    }
    module.exports.Rand = Rand;
    
    Rand.prototype.generate = function generate(len) {
      return this._rand(len);
    };
    
    // Emulate crypto API using randy
    Rand.prototype._rand = function _rand(n) {
      if (this.rand.getBytes)
        return this.rand.getBytes(n);
    
      var res = new Uint8Array(n);
      for (var i = 0; i < res.length; i++)
        res[i] = this.rand.getByte();
      return res;
    };
    
    if (typeof self === 'object') {
      if (self.crypto && self.crypto.getRandomValues) {
        // Modern browsers
        Rand.prototype._rand = function _rand(n) {
          var arr = new Uint8Array(n);
          self.crypto.getRandomValues(arr);
          return arr;
        };
      } else if (self.msCrypto && self.msCrypto.getRandomValues) {
        // IE
        Rand.prototype._rand = function _rand(n) {
          var arr = new Uint8Array(n);
          self.msCrypto.getRandomValues(arr);
          return arr;
        };
    
      // Safari's WebWorkers do not have `crypto`
      } else if (typeof window === 'object') {
        // Old junk
        Rand.prototype._rand = function() {
          throw new Error('Not implemented yet');
        };
      }
    } else {
      // Node.js or Web worker with no crypto support
      try {
        var crypto = require('crypto');
        if (typeof crypto.randomBytes !== 'function')
          throw new Error('Not supported');
    
        Rand.prototype._rand = function _rand(n) {
          return crypto.randomBytes(n);
        };
      } catch (e) {
      }
    }
    
    },{"crypto":24}],24:[function(require,module,exports){
    
    },{}],25:[function(require,module,exports){
    // based on the aes implimentation in triple sec
    // https://github.com/keybase/triplesec
    // which is in turn based on the one from crypto-js
    // https://code.google.com/p/crypto-js/
    
    var Buffer = require('safe-buffer').Buffer
    
    function asUInt32Array (buf) {
      if (!Buffer.isBuffer(buf)) buf = Buffer.from(buf)
    
      var len = (buf.length / 4) | 0
      var out = new Array(len)
    
      for (var i = 0; i < len; i++) {
        out[i] = buf.readUInt32BE(i * 4)
      }
    
      return out
    }
    
    function scrubVec (v) {
      for (var i = 0; i < v.length; v++) {
        v[i] = 0
      }
    }
    
    function cryptBlock (M, keySchedule, SUB_MIX, SBOX, nRounds) {
      var SUB_MIX0 = SUB_MIX[0]
      var SUB_MIX1 = SUB_MIX[1]
      var SUB_MIX2 = SUB_MIX[2]
      var SUB_MIX3 = SUB_MIX[3]
    
      var s0 = M[0] ^ keySchedule[0]
      var s1 = M[1] ^ keySchedule[1]
      var s2 = M[2] ^ keySchedule[2]
      var s3 = M[3] ^ keySchedule[3]
      var t0, t1, t2, t3
      var ksRow = 4
    
      for (var round = 1; round < nRounds; round++) {
        t0 = SUB_MIX0[s0 >>> 24] ^ SUB_MIX1[(s1 >>> 16) & 0xff] ^ SUB_MIX2[(s2 >>> 8) & 0xff] ^ SUB_MIX3[s3 & 0xff] ^ keySchedule[ksRow++]
        t1 = SUB_MIX0[s1 >>> 24] ^ SUB_MIX1[(s2 >>> 16) & 0xff] ^ SUB_MIX2[(s3 >>> 8) & 0xff] ^ SUB_MIX3[s0 & 0xff] ^ keySchedule[ksRow++]
        t2 = SUB_MIX0[s2 >>> 24] ^ SUB_MIX1[(s3 >>> 16) & 0xff] ^ SUB_MIX2[(s0 >>> 8) & 0xff] ^ SUB_MIX3[s1 & 0xff] ^ keySchedule[ksRow++]
        t3 = SUB_MIX0[s3 >>> 24] ^ SUB_MIX1[(s0 >>> 16) & 0xff] ^ SUB_MIX2[(s1 >>> 8) & 0xff] ^ SUB_MIX3[s2 & 0xff] ^ keySchedule[ksRow++]
        s0 = t0
        s1 = t1
        s2 = t2
        s3 = t3
      }
    
      t0 = ((SBOX[s0 >>> 24] << 24) | (SBOX[(s1 >>> 16) & 0xff] << 16) | (SBOX[(s2 >>> 8) & 0xff] << 8) | SBOX[s3 & 0xff]) ^ keySchedule[ksRow++]
      t1 = ((SBOX[s1 >>> 24] << 24) | (SBOX[(s2 >>> 16) & 0xff] << 16) | (SBOX[(s3 >>> 8) & 0xff] << 8) | SBOX[s0 & 0xff]) ^ keySchedule[ksRow++]
      t2 = ((SBOX[s2 >>> 24] << 24) | (SBOX[(s3 >>> 16) & 0xff] << 16) | (SBOX[(s0 >>> 8) & 0xff] << 8) | SBOX[s1 & 0xff]) ^ keySchedule[ksRow++]
      t3 = ((SBOX[s3 >>> 24] << 24) | (SBOX[(s0 >>> 16) & 0xff] << 16) | (SBOX[(s1 >>> 8) & 0xff] << 8) | SBOX[s2 & 0xff]) ^ keySchedule[ksRow++]
      t0 = t0 >>> 0
      t1 = t1 >>> 0
      t2 = t2 >>> 0
      t3 = t3 >>> 0
    
      return [t0, t1, t2, t3]
    }
    
    // AES constants
    var RCON = [0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36]
    var G = (function () {
      // Compute double table
      var d = new Array(256)
      for (var j = 0; j < 256; j++) {
        if (j < 128) {
          d[j] = j << 1
        } else {
          d[j] = (j << 1) ^ 0x11b
        }
      }
    
      var SBOX = []
      var INV_SBOX = []
      var SUB_MIX = [[], [], [], []]
      var INV_SUB_MIX = [[], [], [], []]
    
      // Walk GF(2^8)
      var x = 0
      var xi = 0
      for (var i = 0; i < 256; ++i) {
        // Compute sbox
        var sx = xi ^ (xi << 1) ^ (xi << 2) ^ (xi << 3) ^ (xi << 4)
        sx = (sx >>> 8) ^ (sx & 0xff) ^ 0x63
        SBOX[x] = sx
        INV_SBOX[sx] = x
    
        // Compute multiplication
        var x2 = d[x]
        var x4 = d[x2]
        var x8 = d[x4]
    
        // Compute sub bytes, mix columns tables
        var t = (d[sx] * 0x101) ^ (sx * 0x1010100)
        SUB_MIX[0][x] = (t << 24) | (t >>> 8)
        SUB_MIX[1][x] = (t << 16) | (t >>> 16)
        SUB_MIX[2][x] = (t << 8) | (t >>> 24)
        SUB_MIX[3][x] = t
    
        // Compute inv sub bytes, inv mix columns tables
        t = (x8 * 0x1010101) ^ (x4 * 0x10001) ^ (x2 * 0x101) ^ (x * 0x1010100)
        INV_SUB_MIX[0][sx] = (t << 24) | (t >>> 8)
        INV_SUB_MIX[1][sx] = (t << 16) | (t >>> 16)
        INV_SUB_MIX[2][sx] = (t << 8) | (t >>> 24)
        INV_SUB_MIX[3][sx] = t
    
        if (x === 0) {
          x = xi = 1
        } else {
          x = x2 ^ d[d[d[x8 ^ x2]]]
          xi ^= d[d[xi]]
        }
      }
    
      return {
        SBOX: SBOX,
        INV_SBOX: INV_SBOX,
        SUB_MIX: SUB_MIX,
        INV_SUB_MIX: INV_SUB_MIX
      }
    })()
    
    function AES (key) {
      this._key = asUInt32Array(key)
      this._reset()
    }
    
    AES.blockSize = 4 * 4
    AES.keySize = 256 / 8
    AES.prototype.blockSize = AES.blockSize
    AES.prototype.keySize = AES.keySize
    AES.prototype._reset = function () {
      var keyWords = this._key
      var keySize = keyWords.length
      var nRounds = keySize + 6
      var ksRows = (nRounds + 1) * 4
    
      var keySchedule = []
      for (var k = 0; k < keySize; k++) {
        keySchedule[k] = keyWords[k]
      }
    
      for (k = keySize; k < ksRows; k++) {
        var t = keySchedule[k - 1]
    
        if (k % keySize === 0) {
          t = (t << 8) | (t >>> 24)
          t =
            (G.SBOX[t >>> 24] << 24) |
            (G.SBOX[(t >>> 16) & 0xff] << 16) |
            (G.SBOX[(t >>> 8) & 0xff] << 8) |
            (G.SBOX[t & 0xff])
    
          t ^= RCON[(k / keySize) | 0] << 24
        } else if (keySize > 6 && k % keySize === 4) {
          t =
            (G.SBOX[t >>> 24] << 24) |
            (G.SBOX[(t >>> 16) & 0xff] << 16) |
            (G.SBOX[(t >>> 8) & 0xff] << 8) |
            (G.SBOX[t & 0xff])
        }
    
        keySchedule[k] = keySchedule[k - keySize] ^ t
      }
    
      var invKeySchedule = []
      for (var ik = 0; ik < ksRows; ik++) {
        var ksR = ksRows - ik
        var tt = keySchedule[ksR - (ik % 4 ? 0 : 4)]
    
        if (ik < 4 || ksR <= 4) {
          invKeySchedule[ik] = tt
        } else {
          invKeySchedule[ik] =
            G.INV_SUB_MIX[0][G.SBOX[tt >>> 24]] ^
            G.INV_SUB_MIX[1][G.SBOX[(tt >>> 16) & 0xff]] ^
            G.INV_SUB_MIX[2][G.SBOX[(tt >>> 8) & 0xff]] ^
            G.INV_SUB_MIX[3][G.SBOX[tt & 0xff]]
        }
      }
    
      this._nRounds = nRounds
      this._keySchedule = keySchedule
      this._invKeySchedule = invKeySchedule
    }
    
    AES.prototype.encryptBlockRaw = function (M) {
      M = asUInt32Array(M)
      return cryptBlock(M, this._keySchedule, G.SUB_MIX, G.SBOX, this._nRounds)
    }
    
    AES.prototype.encryptBlock = function (M) {
      var out = this.encryptBlockRaw(M)
      var buf = Buffer.allocUnsafe(16)
      buf.writeUInt32BE(out[0], 0)
      buf.writeUInt32BE(out[1], 4)
      buf.writeUInt32BE(out[2], 8)
      buf.writeUInt32BE(out[3], 12)
      return buf
    }
    
    AES.prototype.decryptBlock = function (M) {
      M = asUInt32Array(M)
    
      // swap
      var m1 = M[1]
      M[1] = M[3]
      M[3] = m1
    
      var out = cryptBlock(M, this._invKeySchedule, G.INV_SUB_MIX, G.INV_SBOX, this._nRounds)
      var buf = Buffer.allocUnsafe(16)
      buf.writeUInt32BE(out[0], 0)
      buf.writeUInt32BE(out[3], 4)
      buf.writeUInt32BE(out[2], 8)
      buf.writeUInt32BE(out[1], 12)
      return buf
    }
    
    AES.prototype.scrub = function () {
      scrubVec(this._keySchedule)
      scrubVec(this._invKeySchedule)
      scrubVec(this._key)
    }
    
    module.exports.AES = AES
    
    },{"safe-buffer":187}],26:[function(require,module,exports){
    var aes = require('./aes')
    var Buffer = require('safe-buffer').Buffer
    var Transform = require('cipher-base')
    var inherits = require('inherits')
    var GHASH = require('./ghash')
    var xor = require('buffer-xor')
    var incr32 = require('./incr32')
    
    function xorTest (a, b) {
      var out = 0
      if (a.length !== b.length) out++
    
      var len = Math.min(a.length, b.length)
      for (var i = 0; i < len; ++i) {
        out += (a[i] ^ b[i])
      }
    
      return out
    }
    
    function calcIv (self, iv, ck) {
      if (iv.length === 12) {
        self._finID = Buffer.concat([iv, Buffer.from([0, 0, 0, 1])])
        return Buffer.concat([iv, Buffer.from([0, 0, 0, 2])])
      }
      var ghash = new GHASH(ck)
      var len = iv.length
      var toPad = len % 16
      ghash.update(iv)
      if (toPad) {
        toPad = 16 - toPad
        ghash.update(Buffer.alloc(toPad, 0))
      }
      ghash.update(Buffer.alloc(8, 0))
      var ivBits = len * 8
      var tail = Buffer.alloc(8)
      tail.writeUIntBE(ivBits, 0, 8)
      ghash.update(tail)
      self._finID = ghash.state
      var out = Buffer.from(self._finID)
      incr32(out)
      return out
    }
    function StreamCipher (mode, key, iv, decrypt) {
      Transform.call(this)
    
      var h = Buffer.alloc(4, 0)
    
      this._cipher = new aes.AES(key)
      var ck = this._cipher.encryptBlock(h)
      this._ghash = new GHASH(ck)
      iv = calcIv(this, iv, ck)
    
      this._prev = Buffer.from(iv)
      this._cache = Buffer.allocUnsafe(0)
      this._secCache = Buffer.allocUnsafe(0)
      this._decrypt = decrypt
      this._alen = 0
      this._len = 0
      this._mode = mode
    
      this._authTag = null
      this._called = false
    }
    
    inherits(StreamCipher, Transform)
    
    StreamCipher.prototype._update = function (chunk) {
      if (!this._called && this._alen) {
        var rump = 16 - (this._alen % 16)
        if (rump < 16) {
          rump = Buffer.alloc(rump, 0)
          this._ghash.update(rump)
        }
      }
    
      this._called = true
      var out = this._mode.encrypt(this, chunk)
      if (this._decrypt) {
        this._ghash.update(chunk)
      } else {
        this._ghash.update(out)
      }
      this._len += chunk.length
      return out
    }
    
    StreamCipher.prototype._final = function () {
      if (this._decrypt && !this._authTag) throw new Error('Unsupported state or unable to authenticate data')
    
      var tag = xor(this._ghash.final(this._alen * 8, this._len * 8), this._cipher.encryptBlock(this._finID))
      if (this._decrypt && xorTest(tag, this._authTag)) throw new Error('Unsupported state or unable to authenticate data')
    
      this._authTag = tag
      this._cipher.scrub()
    }
    
    StreamCipher.prototype.getAuthTag = function getAuthTag () {
      if (this._decrypt || !Buffer.isBuffer(this._authTag)) throw new Error('Attempting to get auth tag in unsupported state')
    
      return this._authTag
    }
    
    StreamCipher.prototype.setAuthTag = function setAuthTag (tag) {
      if (!this._decrypt) throw new Error('Attempting to set auth tag in unsupported state')
    
      this._authTag = tag
    }
    
    StreamCipher.prototype.setAAD = function setAAD (buf) {
      if (this._called) throw new Error('Attempting to set AAD in unsupported state')
    
      this._ghash.update(buf)
      this._alen += buf.length
    }
    
    module.exports = StreamCipher
    
    },{"./aes":25,"./ghash":30,"./incr32":31,"buffer-xor":67,"cipher-base":71,"inherits":149,"safe-buffer":187}],27:[function(require,module,exports){
    var ciphers = require('./encrypter')
    var deciphers = require('./decrypter')
    var modes = require('./modes/list.json')
    
    function getCiphers () {
      return Object.keys(modes)
    }
    
    exports.createCipher = exports.Cipher = ciphers.createCipher
    exports.createCipheriv = exports.Cipheriv = ciphers.createCipheriv
    exports.createDecipher = exports.Decipher = deciphers.createDecipher
    exports.createDecipheriv = exports.Decipheriv = deciphers.createDecipheriv
    exports.listCiphers = exports.getCiphers = getCiphers
    
    },{"./decrypter":28,"./encrypter":29,"./modes/list.json":39}],28:[function(require,module,exports){
    var AuthCipher = require('./authCipher')
    var Buffer = require('safe-buffer').Buffer
    var MODES = require('./modes')
    var StreamCipher = require('./streamCipher')
    var Transform = require('cipher-base')
    var aes = require('./aes')
    var ebtk = require('evp_bytestokey')
    var inherits = require('inherits')
    
    function Decipher (mode, key, iv) {
      Transform.call(this)
    
      this._cache = new Splitter()
      this._last = void 0
      this._cipher = new aes.AES(key)
      this._prev = Buffer.from(iv)
      this._mode = mode
      this._autopadding = true
    }
    
    inherits(Decipher, Transform)
    
    Decipher.prototype._update = function (data) {
      this._cache.add(data)
      var chunk
      var thing
      var out = []
      while ((chunk = this._cache.get(this._autopadding))) {
        thing = this._mode.decrypt(this, chunk)
        out.push(thing)
      }
      return Buffer.concat(out)
    }
    
    Decipher.prototype._final = function () {
      var chunk = this._cache.flush()
      if (this._autopadding) {
        return unpad(this._mode.decrypt(this, chunk))
      } else if (chunk) {
        throw new Error('data not multiple of block length')
      }
    }
    
    Decipher.prototype.setAutoPadding = function (setTo) {
      this._autopadding = !!setTo
      return this
    }
    
    function Splitter () {
      this.cache = Buffer.allocUnsafe(0)
    }
    
    Splitter.prototype.add = function (data) {
      this.cache = Buffer.concat([this.cache, data])
    }
    
    Splitter.prototype.get = function (autoPadding) {
      var out
      if (autoPadding) {
        if (this.cache.length > 16) {
          out = this.cache.slice(0, 16)
          this.cache = this.cache.slice(16)
          return out
        }
      } else {
        if (this.cache.length >= 16) {
          out = this.cache.slice(0, 16)
          this.cache = this.cache.slice(16)
          return out
        }
      }
    
      return null
    }
    
    Splitter.prototype.flush = function () {
      if (this.cache.length) return this.cache
    }
    
    function unpad (last) {
      var padded = last[15]
      if (padded < 1 || padded > 16) {
        throw new Error('unable to decrypt data')
      }
      var i = -1
      while (++i < padded) {
        if (last[(i + (16 - padded))] !== padded) {
          throw new Error('unable to decrypt data')
        }
      }
      if (padded === 16) return
    
      return last.slice(0, 16 - padded)
    }
    
    function createDecipheriv (suite, password, iv) {
      var config = MODES[suite.toLowerCase()]
      if (!config) throw new TypeError('invalid suite type')
    
      if (typeof iv === 'string') iv = Buffer.from(iv)
      if (config.mode !== 'GCM' && iv.length !== config.iv) throw new TypeError('invalid iv length ' + iv.length)
    
      if (typeof password === 'string') password = Buffer.from(password)
      if (password.length !== config.key / 8) throw new TypeError('invalid key length ' + password.length)
    
      if (config.type === 'stream') {
        return new StreamCipher(config.module, password, iv, true)
      } else if (config.type === 'auth') {
        return new AuthCipher(config.module, password, iv, true)
      }
    
      return new Decipher(config.module, password, iv)
    }
    
    function createDecipher (suite, password) {
      var config = MODES[suite.toLowerCase()]
      if (!config) throw new TypeError('invalid suite type')
    
      var keys = ebtk(password, false, config.key, config.iv)
      return createDecipheriv(suite, keys.key, keys.iv)
    }
    
    exports.createDecipher = createDecipher
    exports.createDecipheriv = createDecipheriv
    
    },{"./aes":25,"./authCipher":26,"./modes":38,"./streamCipher":41,"cipher-base":71,"evp_bytestokey":108,"inherits":149,"safe-buffer":187}],29:[function(require,module,exports){
    var MODES = require('./modes')
    var AuthCipher = require('./authCipher')
    var Buffer = require('safe-buffer').Buffer
    var StreamCipher = require('./streamCipher')
    var Transform = require('cipher-base')
    var aes = require('./aes')
    var ebtk = require('evp_bytestokey')
    var inherits = require('inherits')
    
    function Cipher (mode, key, iv) {
      Transform.call(this)
    
      this._cache = new Splitter()
      this._cipher = new aes.AES(key)
      this._prev = Buffer.from(iv)
      this._mode = mode
      this._autopadding = true
    }
    
    inherits(Cipher, Transform)
    
    Cipher.prototype._update = function (data) {
      this._cache.add(data)
      var chunk
      var thing
      var out = []
    
      while ((chunk = this._cache.get())) {
        thing = this._mode.encrypt(this, chunk)
        out.push(thing)
      }
    
      return Buffer.concat(out)
    }
    
    var PADDING = Buffer.alloc(16, 0x10)
    
    Cipher.prototype._final = function () {
      var chunk = this._cache.flush()
      if (this._autopadding) {
        chunk = this._mode.encrypt(this, chunk)
        this._cipher.scrub()
        return chunk
      }
    
      if (!chunk.equals(PADDING)) {
        this._cipher.scrub()
        throw new Error('data not multiple of block length')
      }
    }
    
    Cipher.prototype.setAutoPadding = function (setTo) {
      this._autopadding = !!setTo
      return this
    }
    
    function Splitter () {
      this.cache = Buffer.allocUnsafe(0)
    }
    
    Splitter.prototype.add = function (data) {
      this.cache = Buffer.concat([this.cache, data])
    }
    
    Splitter.prototype.get = function () {
      if (this.cache.length > 15) {
        var out = this.cache.slice(0, 16)
        this.cache = this.cache.slice(16)
        return out
      }
      return null
    }
    
    Splitter.prototype.flush = function () {
      var len = 16 - this.cache.length
      var padBuff = Buffer.allocUnsafe(len)
    
      var i = -1
      while (++i < len) {
        padBuff.writeUInt8(len, i)
      }
    
      return Buffer.concat([this.cache, padBuff])
    }
    
    function createCipheriv (suite, password, iv) {
      var config = MODES[suite.toLowerCase()]
      if (!config) throw new TypeError('invalid suite type')
    
      if (typeof password === 'string') password = Buffer.from(password)
      if (password.length !== config.key / 8) throw new TypeError('invalid key length ' + password.length)
    
      if (typeof iv === 'string') iv = Buffer.from(iv)
      if (config.mode !== 'GCM' && iv.length !== config.iv) throw new TypeError('invalid iv length ' + iv.length)
    
      if (config.type === 'stream') {
        return new StreamCipher(config.module, password, iv)
      } else if (config.type === 'auth') {
        return new AuthCipher(config.module, password, iv)
      }
    
      return new Cipher(config.module, password, iv)
    }
    
    function createCipher (suite, password) {
      var config = MODES[suite.toLowerCase()]
      if (!config) throw new TypeError('invalid suite type')
    
      var keys = ebtk(password, false, config.key, config.iv)
      return createCipheriv(suite, keys.key, keys.iv)
    }
    
    exports.createCipheriv = createCipheriv
    exports.createCipher = createCipher
    
    },{"./aes":25,"./authCipher":26,"./modes":38,"./streamCipher":41,"cipher-base":71,"evp_bytestokey":108,"inherits":149,"safe-buffer":187}],30:[function(require,module,exports){
    var Buffer = require('safe-buffer').Buffer
    var ZEROES = Buffer.alloc(16, 0)
    
    function toArray (buf) {
      return [
        buf.readUInt32BE(0),
        buf.readUInt32BE(4),
        buf.readUInt32BE(8),
        buf.readUInt32BE(12)
      ]
    }
    
    function fromArray (out) {
      var buf = Buffer.allocUnsafe(16)
      buf.writeUInt32BE(out[0] >>> 0, 0)
      buf.writeUInt32BE(out[1] >>> 0, 4)
      buf.writeUInt32BE(out[2] >>> 0, 8)
      buf.writeUInt32BE(out[3] >>> 0, 12)
      return buf
    }
    
    function GHASH (key) {
      this.h = key
      this.state = Buffer.alloc(16, 0)
      this.cache = Buffer.allocUnsafe(0)
    }
    
    // from http://bitwiseshiftleft.github.io/sjcl/doc/symbols/src/core_gcm.js.html
    // by Juho Vähä-Herttua
    GHASH.prototype.ghash = function (block) {
      var i = -1
      while (++i < block.length) {
        this.state[i] ^= block[i]
      }
      this._multiply()
    }
    
    GHASH.prototype._multiply = function () {
      var Vi = toArray(this.h)
      var Zi = [0, 0, 0, 0]
      var j, xi, lsbVi
      var i = -1
      while (++i < 128) {
        xi = (this.state[~~(i / 8)] & (1 << (7 - (i % 8)))) !== 0
        if (xi) {
          // Z_i+1 = Z_i ^ V_i
          Zi[0] ^= Vi[0]
          Zi[1] ^= Vi[1]
          Zi[2] ^= Vi[2]
          Zi[3] ^= Vi[3]
        }
    
        // Store the value of LSB(V_i)
        lsbVi = (Vi[3] & 1) !== 0
    
        // V_i+1 = V_i >> 1
        for (j = 3; j > 0; j--) {
          Vi[j] = (Vi[j] >>> 1) | ((Vi[j - 1] & 1) << 31)
        }
        Vi[0] = Vi[0] >>> 1
    
        // If LSB(V_i) is 1, V_i+1 = (V_i >> 1) ^ R
        if (lsbVi) {
          Vi[0] = Vi[0] ^ (0xe1 << 24)
        }
      }
      this.state = fromArray(Zi)
    }
    
    GHASH.prototype.update = function (buf) {
      this.cache = Buffer.concat([this.cache, buf])
      var chunk
      while (this.cache.length >= 16) {
        chunk = this.cache.slice(0, 16)
        this.cache = this.cache.slice(16)
        this.ghash(chunk)
      }
    }
    
    GHASH.prototype.final = function (abl, bl) {
      if (this.cache.length) {
        this.ghash(Buffer.concat([this.cache, ZEROES], 16))
      }
    
      this.ghash(fromArray([0, abl, 0, bl]))
      return this.state
    }
    
    module.exports = GHASH
    
    },{"safe-buffer":187}],31:[function(require,module,exports){
    function incr32 (iv) {
      var len = iv.length
      var item
      while (len--) {
        item = iv.readUInt8(len)
        if (item === 255) {
          iv.writeUInt8(0, len)
        } else {
          item++
          iv.writeUInt8(item, len)
          break
        }
      }
    }
    module.exports = incr32
    
    },{}],32:[function(require,module,exports){
    var xor = require('buffer-xor')
    
    exports.encrypt = function (self, block) {
      var data = xor(block, self._prev)
    
      self._prev = self._cipher.encryptBlock(data)
      return self._prev
    }
    
    exports.decrypt = function (self, block) {
      var pad = self._prev
    
      self._prev = block
      var out = self._cipher.decryptBlock(block)
    
      return xor(out, pad)
    }
    
    },{"buffer-xor":67}],33:[function(require,module,exports){
    var Buffer = require('safe-buffer').Buffer
    var xor = require('buffer-xor')
    
    function encryptStart (self, data, decrypt) {
      var len = data.length
      var out = xor(data, self._cache)
      self._cache = self._cache.slice(len)
      self._prev = Buffer.concat([self._prev, decrypt ? data : out])
      return out
    }
    
    exports.encrypt = function (self, data, decrypt) {
      var out = Buffer.allocUnsafe(0)
      var len
    
      while (data.length) {
        if (self._cache.length === 0) {
          self._cache = self._cipher.encryptBlock(self._prev)
          self._prev = Buffer.allocUnsafe(0)
        }
    
        if (self._cache.length <= data.length) {
          len = self._cache.length
          out = Buffer.concat([out, encryptStart(self, data.slice(0, len), decrypt)])
          data = data.slice(len)
        } else {
          out = Buffer.concat([out, encryptStart(self, data, decrypt)])
          break
        }
      }
    
      return out
    }
    
    },{"buffer-xor":67,"safe-buffer":187}],34:[function(require,module,exports){
    var Buffer = require('safe-buffer').Buffer
    
    function encryptByte (self, byteParam, decrypt) {
      var pad
      var i = -1
      var len = 8
      var out = 0
      var bit, value
      while (++i < len) {
        pad = self._cipher.encryptBlock(self._prev)
        bit = (byteParam & (1 << (7 - i))) ? 0x80 : 0
        value = pad[0] ^ bit
        out += ((value & 0x80) >> (i % 8))
        self._prev = shiftIn(self._prev, decrypt ? bit : value)
      }
      return out
    }
    
    function shiftIn (buffer, value) {
      var len = buffer.length
      var i = -1
      var out = Buffer.allocUnsafe(buffer.length)
      buffer = Buffer.concat([buffer, Buffer.from([value])])
    
      while (++i < len) {
        out[i] = buffer[i] << 1 | buffer[i + 1] >> (7)
      }
    
      return out
    }
    
    exports.encrypt = function (self, chunk, decrypt) {
      var len = chunk.length
      var out = Buffer.allocUnsafe(len)
      var i = -1
    
      while (++i < len) {
        out[i] = encryptByte(self, chunk[i], decrypt)
      }
    
      return out
    }
    
    },{"safe-buffer":187}],35:[function(require,module,exports){
    var Buffer = require('safe-buffer').Buffer
    
    function encryptByte (self, byteParam, decrypt) {
      var pad = self._cipher.encryptBlock(self._prev)
      var out = pad[0] ^ byteParam
    
      self._prev = Buffer.concat([
        self._prev.slice(1),
        Buffer.from([decrypt ? byteParam : out])
      ])
    
      return out
    }
    
    exports.encrypt = function (self, chunk, decrypt) {
      var len = chunk.length
      var out = Buffer.allocUnsafe(len)
      var i = -1
    
      while (++i < len) {
        out[i] = encryptByte(self, chunk[i], decrypt)
      }
    
      return out
    }
    
    },{"safe-buffer":187}],36:[function(require,module,exports){
    var xor = require('buffer-xor')
    var Buffer = require('safe-buffer').Buffer
    var incr32 = require('../incr32')
    
    function getBlock (self) {
      var out = self._cipher.encryptBlockRaw(self._prev)
      incr32(self._prev)
      return out
    }
    
    var blockSize = 16
    exports.encrypt = function (self, chunk) {
      var chunkNum = Math.ceil(chunk.length / blockSize)
      var start = self._cache.length
      self._cache = Buffer.concat([
        self._cache,
        Buffer.allocUnsafe(chunkNum * blockSize)
      ])
      for (var i = 0; i < chunkNum; i++) {
        var out = getBlock(self)
        var offset = start + i * blockSize
        self._cache.writeUInt32BE(out[0], offset + 0)
        self._cache.writeUInt32BE(out[1], offset + 4)
        self._cache.writeUInt32BE(out[2], offset + 8)
        self._cache.writeUInt32BE(out[3], offset + 12)
      }
      var pad = self._cache.slice(0, chunk.length)
      self._cache = self._cache.slice(chunk.length)
      return xor(chunk, pad)
    }
    
    },{"../incr32":31,"buffer-xor":67,"safe-buffer":187}],37:[function(require,module,exports){
    exports.encrypt = function (self, block) {
      return self._cipher.encryptBlock(block)
    }
    
    exports.decrypt = function (self, block) {
      return self._cipher.decryptBlock(block)
    }
    
    },{}],38:[function(require,module,exports){
    var modeModules = {
      ECB: require('./ecb'),
      CBC: require('./cbc'),
      CFB: require('./cfb'),
      CFB8: require('./cfb8'),
      CFB1: require('./cfb1'),
      OFB: require('./ofb'),
      CTR: require('./ctr'),
      GCM: require('./ctr')
    }
    
    var modes = require('./list.json')
    
    for (var key in modes) {
      modes[key].module = modeModules[modes[key].mode]
    }
    
    module.exports = modes
    
    },{"./cbc":32,"./cfb":33,"./cfb1":34,"./cfb8":35,"./ctr":36,"./ecb":37,"./list.json":39,"./ofb":40}],39:[function(require,module,exports){
    module.exports={
      "aes-128-ecb": {
        "cipher": "AES",
        "key": 128,
        "iv": 0,
        "mode": "ECB",
        "type": "block"
      },
      "aes-192-ecb": {
        "cipher": "AES",
        "key": 192,
        "iv": 0,
        "mode": "ECB",
        "type": "block"
      },
      "aes-256-ecb": {
        "cipher": "AES",
        "key": 256,
        "iv": 0,
        "mode": "ECB",
        "type": "block"
      },
      "aes-128-cbc": {
        "cipher": "AES",
        "key": 128,
        "iv": 16,
        "mode": "CBC",
        "type": "block"
      },
      "aes-192-cbc": {
        "cipher": "AES",
        "key": 192,
        "iv": 16,
        "mode": "CBC",
        "type": "block"
      },
      "aes-256-cbc": {
        "cipher": "AES",
        "key": 256,
        "iv": 16,
        "mode": "CBC",
        "type": "block"
      },
      "aes128": {
        "cipher": "AES",
        "key": 128,
        "iv": 16,
        "mode": "CBC",
        "type": "block"
      },
      "aes192": {
        "cipher": "AES",
        "key": 192,
        "iv": 16,
        "mode": "CBC",
        "type": "block"
      },
      "aes256": {
        "cipher": "AES",
        "key": 256,
        "iv": 16,
        "mode": "CBC",
        "type": "block"
      },
      "aes-128-cfb": {
        "cipher": "AES",
        "key": 128,
        "iv": 16,
        "mode": "CFB",
        "type": "stream"
      },
      "aes-192-cfb": {
        "cipher": "AES",
        "key": 192,
        "iv": 16,
        "mode": "CFB",
        "type": "stream"
      },
      "aes-256-cfb": {
        "cipher": "AES",
        "key": 256,
        "iv": 16,
        "mode": "CFB",
        "type": "stream"
      },
      "aes-128-cfb8": {
        "cipher": "AES",
        "key": 128,
        "iv": 16,
        "mode": "CFB8",
        "type": "stream"
      },
      "aes-192-cfb8": {
        "cipher": "AES",
        "key": 192,
        "iv": 16,
        "mode": "CFB8",
        "type": "stream"
      },
      "aes-256-cfb8": {
        "cipher": "AES",
        "key": 256,
        "iv": 16,
        "mode": "CFB8",
        "type": "stream"
      },
      "aes-128-cfb1": {
        "cipher": "AES",
        "key": 128,
        "iv": 16,
        "mode": "CFB1",
        "type": "stream"
      },
      "aes-192-cfb1": {
        "cipher": "AES",
        "key": 192,
        "iv": 16,
        "mode": "CFB1",
        "type": "stream"
      },
      "aes-256-cfb1": {
        "cipher": "AES",
        "key": 256,
        "iv": 16,
        "mode": "CFB1",
        "type": "stream"
      },
      "aes-128-ofb": {
        "cipher": "AES",
        "key": 128,
        "iv": 16,
        "mode": "OFB",
        "type": "stream"
      },
      "aes-192-ofb": {
        "cipher": "AES",
        "key": 192,
        "iv": 16,
        "mode": "OFB",
        "type": "stream"
      },
      "aes-256-ofb": {
        "cipher": "AES",
        "key": 256,
        "iv": 16,
        "mode": "OFB",
        "type": "stream"
      },
      "aes-128-ctr": {
        "cipher": "AES",
        "key": 128,
        "iv": 16,
        "mode": "CTR",
        "type": "stream"
      },
      "aes-192-ctr": {
        "cipher": "AES",
        "key": 192,
        "iv": 16,
        "mode": "CTR",
        "type": "stream"
      },
      "aes-256-ctr": {
        "cipher": "AES",
        "key": 256,
        "iv": 16,
        "mode": "CTR",
        "type": "stream"
      },
      "aes-128-gcm": {
        "cipher": "AES",
        "key": 128,
        "iv": 12,
        "mode": "GCM",
        "type": "auth"
      },
      "aes-192-gcm": {
        "cipher": "AES",
        "key": 192,
        "iv": 12,
        "mode": "GCM",
        "type": "auth"
      },
      "aes-256-gcm": {
        "cipher": "AES",
        "key": 256,
        "iv": 12,
        "mode": "GCM",
        "type": "auth"
      }
    }
    
    },{}],40:[function(require,module,exports){
    (function (Buffer){(function (){
    var xor = require('buffer-xor')
    
    function getBlock (self) {
      self._prev = self._cipher.encryptBlock(self._prev)
      return self._prev
    }
    
    exports.encrypt = function (self, chunk) {
      while (self._cache.length < chunk.length) {
        self._cache = Buffer.concat([self._cache, getBlock(self)])
      }
    
      var pad = self._cache.slice(0, chunk.length)
      self._cache = self._cache.slice(chunk.length)
      return xor(chunk, pad)
    }
    
    }).call(this)}).call(this,require("buffer").Buffer)
    },{"buffer":68,"buffer-xor":67}],41:[function(require,module,exports){
    var aes = require('./aes')
    var Buffer = require('safe-buffer').Buffer
    var Transform = require('cipher-base')
    var inherits = require('inherits')
    
    function StreamCipher (mode, key, iv, decrypt) {
      Transform.call(this)
    
      this._cipher = new aes.AES(key)
      this._prev = Buffer.from(iv)
      this._cache = Buffer.allocUnsafe(0)
      this._secCache = Buffer.allocUnsafe(0)
      this._decrypt = decrypt
      this._mode = mode
    }
    
    inherits(StreamCipher, Transform)
    
    StreamCipher.prototype._update = function (chunk) {
      return this._mode.encrypt(this, chunk, this._decrypt)
    }
    
    StreamCipher.prototype._final = function () {
      this._cipher.scrub()
    }
    
    module.exports = StreamCipher
    
    },{"./aes":25,"cipher-base":71,"inherits":149,"safe-buffer":187}],42:[function(require,module,exports){
    var DES = require('browserify-des')
    var aes = require('browserify-aes/browser')
    var aesModes = require('browserify-aes/modes')
    var desModes = require('browserify-des/modes')
    var ebtk = require('evp_bytestokey')
    
    function createCipher (suite, password) {
      suite = suite.toLowerCase()
    
      var keyLen, ivLen
      if (aesModes[suite]) {
        keyLen = aesModes[suite].key
        ivLen = aesModes[suite].iv
      } else if (desModes[suite]) {
        keyLen = desModes[suite].key * 8
        ivLen = desModes[suite].iv
      } else {
        throw new TypeError('invalid suite type')
      }
    
      var keys = ebtk(password, false, keyLen, ivLen)
      return createCipheriv(suite, keys.key, keys.iv)
    }
    
    function createDecipher (suite, password) {
      suite = suite.toLowerCase()
    
      var keyLen, ivLen
      if (aesModes[suite]) {
        keyLen = aesModes[suite].key
        ivLen = aesModes[suite].iv
      } else if (desModes[suite]) {
        keyLen = desModes[suite].key * 8
        ivLen = desModes[suite].iv
      } else {
        throw new TypeError('invalid suite type')
      }
    
      var keys = ebtk(password, false, keyLen, ivLen)
      return createDecipheriv(suite, keys.key, keys.iv)
    }
    
    function createCipheriv (suite, key, iv) {
      suite = suite.toLowerCase()
      if (aesModes[suite]) return aes.createCipheriv(suite, key, iv)
      if (desModes[suite]) return new DES({ key: key, iv: iv, mode: suite })
    
      throw new TypeError('invalid suite type')
    }
    
    function createDecipheriv (suite, key, iv) {
      suite = suite.toLowerCase()
      if (aesModes[suite]) return aes.createDecipheriv(suite, key, iv)
      if (desModes[suite]) return new DES({ key: key, iv: iv, mode: suite, decrypt: true })
    
      throw new TypeError('invalid suite type')
    }
    
    function getCiphers () {
      return Object.keys(desModes).concat(aes.getCiphers())
    }
    
    exports.createCipher = exports.Cipher = createCipher
    exports.createCipheriv = exports.Cipheriv = createCipheriv
    exports.createDecipher = exports.Decipher = createDecipher
    exports.createDecipheriv = exports.Decipheriv = createDecipheriv
    exports.listCiphers = exports.getCiphers = getCiphers
    
    },{"browserify-aes/browser":27,"browserify-aes/modes":38,"browserify-des":43,"browserify-des/modes":44,"evp_bytestokey":108}],43:[function(require,module,exports){
    var CipherBase = require('cipher-base')
    var des = require('des.js')
    var inherits = require('inherits')
    var Buffer = require('safe-buffer').Buffer
    
    var modes = {
      'des-ede3-cbc': des.CBC.instantiate(des.EDE),
      'des-ede3': des.EDE,
      'des-ede-cbc': des.CBC.instantiate(des.EDE),
      'des-ede': des.EDE,
      'des-cbc': des.CBC.instantiate(des.DES),
      'des-ecb': des.DES
    }
    modes.des = modes['des-cbc']
    modes.des3 = modes['des-ede3-cbc']
    module.exports = DES
    inherits(DES, CipherBase)
    function DES (opts) {
      CipherBase.call(this)
      var modeName = opts.mode.toLowerCase()
      var mode = modes[modeName]
      var type
      if (opts.decrypt) {
        type = 'decrypt'
      } else {
        type = 'encrypt'
      }
      var key = opts.key
      if (!Buffer.isBuffer(key)) {
        key = Buffer.from(key)
      }
      if (modeName === 'des-ede' || modeName === 'des-ede-cbc') {
        key = Buffer.concat([key, key.slice(0, 8)])
      }
      var iv = opts.iv
      if (!Buffer.isBuffer(iv)) {
        iv = Buffer.from(iv)
      }
      this._des = mode.create({
        key: key,
        iv: iv,
        type: type
      })
    }
    DES.prototype._update = function (data) {
      return Buffer.from(this._des.update(data))
    }
    DES.prototype._final = function () {
      return Buffer.from(this._des.final())
    }
    
    },{"cipher-base":71,"des.js":79,"inherits":149,"safe-buffer":187}],44:[function(require,module,exports){
    exports['des-ecb'] = {
      key: 8,
      iv: 0
    }
    exports['des-cbc'] = exports.des = {
      key: 8,
      iv: 8
    }
    exports['des-ede3-cbc'] = exports.des3 = {
      key: 24,
      iv: 8
    }
    exports['des-ede3'] = {
      key: 24,
      iv: 0
    }
    exports['des-ede-cbc'] = {
      key: 16,
      iv: 8
    }
    exports['des-ede'] = {
      key: 16,
      iv: 0
    }
    
    },{}],45:[function(require,module,exports){
    (function (Buffer){(function (){
    var BN = require('bn.js')
    var randomBytes = require('randombytes')
    
    function blind (priv) {
      var r = getr(priv)
      var blinder = r.toRed(BN.mont(priv.modulus)).redPow(new BN(priv.publicExponent)).fromRed()
      return { blinder: blinder, unblinder: r.invm(priv.modulus) }
    }
    
    function getr (priv) {
      var len = priv.modulus.byteLength()
      var r
      do {
        r = new BN(randomBytes(len))
      } while (r.cmp(priv.modulus) >= 0 || !r.umod(priv.prime1) || !r.umod(priv.prime2))
      return r
    }
    
    function crt (msg, priv) {
      var blinds = blind(priv)
      var len = priv.modulus.byteLength()
      var blinded = new BN(msg).mul(blinds.blinder).umod(priv.modulus)
      var c1 = blinded.toRed(BN.mont(priv.prime1))
      var c2 = blinded.toRed(BN.mont(priv.prime2))
      var qinv = priv.coefficient
      var p = priv.prime1
      var q = priv.prime2
      var m1 = c1.redPow(priv.exponent1).fromRed()
      var m2 = c2.redPow(priv.exponent2).fromRed()
      var h = m1.isub(m2).imul(qinv).umod(p).imul(q)
      return m2.iadd(h).imul(blinds.unblinder).umod(priv.modulus).toArrayLike(Buffer, 'be', len)
    }
    crt.getr = getr
    
    module.exports = crt
    
    }).call(this)}).call(this,require("buffer").Buffer)
    },{"bn.js":22,"buffer":68,"randombytes":184}],46:[function(require,module,exports){
    module.exports = require('./browser/algorithms.json')
    
    },{"./browser/algorithms.json":47}],47:[function(require,module,exports){
    module.exports={
      "sha224WithRSAEncryption": {
        "sign": "rsa",
        "hash": "sha224",
        "id": "302d300d06096086480165030402040500041c"
      },
      "RSA-SHA224": {
        "sign": "ecdsa/rsa",
        "hash": "sha224",
        "id": "302d300d06096086480165030402040500041c"
      },
      "sha256WithRSAEncryption": {
        "sign": "rsa",
        "hash": "sha256",
        "id": "3031300d060960864801650304020105000420"
      },
      "RSA-SHA256": {
        "sign": "ecdsa/rsa",
        "hash": "sha256",
        "id": "3031300d060960864801650304020105000420"
      },
      "sha384WithRSAEncryption": {
        "sign": "rsa",
        "hash": "sha384",
        "id": "3041300d060960864801650304020205000430"
      },
      "RSA-SHA384": {
        "sign": "ecdsa/rsa",
        "hash": "sha384",
        "id": "3041300d060960864801650304020205000430"
      },
      "sha512WithRSAEncryption": {
        "sign": "rsa",
        "hash": "sha512",
        "id": "3051300d060960864801650304020305000440"
      },
      "RSA-SHA512": {
        "sign": "ecdsa/rsa",
        "hash": "sha512",
        "id": "3051300d060960864801650304020305000440"
      },
      "RSA-SHA1": {
        "sign": "rsa",
        "hash": "sha1",
        "id": "3021300906052b0e03021a05000414"
      },
      "ecdsa-with-SHA1": {
        "sign": "ecdsa",
        "hash": "sha1",
        "id": ""
      },
      "sha256": {
        "sign": "ecdsa",
        "hash": "sha256",
        "id": ""
      },
      "sha224": {
        "sign": "ecdsa",
        "hash": "sha224",
        "id": ""
      },
      "sha384": {
        "sign": "ecdsa",
        "hash": "sha384",
        "id": ""
      },
      "sha512": {
        "sign": "ecdsa",
        "hash": "sha512",
        "id": ""
      },
      "DSA-SHA": {
        "sign": "dsa",
        "hash": "sha1",
        "id": ""
      },
      "DSA-SHA1": {
        "sign": "dsa",
        "hash": "sha1",
        "id": ""
      },
      "DSA": {
        "sign": "dsa",
        "hash": "sha1",
        "id": ""
      },
      "DSA-WITH-SHA224": {
        "sign": "dsa",
        "hash": "sha224",
        "id": ""
      },
      "DSA-SHA224": {
        "sign": "dsa",
        "hash": "sha224",
        "id": ""
      },
      "DSA-WITH-SHA256": {
        "sign": "dsa",
        "hash": "sha256",
        "id": ""
      },
      "DSA-SHA256": {
        "sign": "dsa",
        "hash": "sha256",
        "id": ""
      },
      "DSA-WITH-SHA384": {
        "sign": "dsa",
        "hash": "sha384",
        "id": ""
      },
      "DSA-SHA384": {
        "sign": "dsa",
        "hash": "sha384",
        "id": ""
      },
      "DSA-WITH-SHA512": {
        "sign": "dsa",
        "hash": "sha512",
        "id": ""
      },
      "DSA-SHA512": {
        "sign": "dsa",
        "hash": "sha512",
        "id": ""
      },
      "DSA-RIPEMD160": {
        "sign": "dsa",
        "hash": "rmd160",
        "id": ""
      },
      "ripemd160WithRSA": {
        "sign": "rsa",
        "hash": "rmd160",
        "id": "3021300906052b2403020105000414"
      },
      "RSA-RIPEMD160": {
        "sign": "rsa",
        "hash": "rmd160",
        "id": "3021300906052b2403020105000414"
      },
      "md5WithRSAEncryption": {
        "sign": "rsa",
        "hash": "md5",
        "id": "3020300c06082a864886f70d020505000410"
      },
      "RSA-MD5": {
        "sign": "rsa",
        "hash": "md5",
        "id": "3020300c06082a864886f70d020505000410"
      }
    }
    
    },{}],48:[function(require,module,exports){
    module.exports={
      "1.3.132.0.10": "secp256k1",
      "1.3.132.0.33": "p224",
      "1.2.840.10045.3.1.1": "p192",
      "1.2.840.10045.3.1.7": "p256",
      "1.3.132.0.34": "p384",
      "1.3.132.0.35": "p521"
    }
    
    },{}],49:[function(require,module,exports){
    var Buffer = require('safe-buffer').Buffer
    var createHash = require('create-hash')
    var stream = require('readable-stream')
    var inherits = require('inherits')
    var sign = require('./sign')
    var verify = require('./verify')
    
    var algorithms = require('./algorithms.json')
    Object.keys(algorithms).forEach(function (key) {
      algorithms[key].id = Buffer.from(algorithms[key].id, 'hex')
      algorithms[key.toLowerCase()] = algorithms[key]
    })
    
    function Sign (algorithm) {
      stream.Writable.call(this)
    
      var data = algorithms[algorithm]
      if (!data) throw new Error('Unknown message digest')
    
      this._hashType = data.hash
      this._hash = createHash(data.hash)
      this._tag = data.id
      this._signType = data.sign
    }
    inherits(Sign, stream.Writable)
    
    Sign.prototype._write = function _write (data, _, done) {
      this._hash.update(data)
      done()
    }
    
    Sign.prototype.update = function update (data, enc) {
      if (typeof data === 'string') data = Buffer.from(data, enc)
    
      this._hash.update(data)
      return this
    }
    
    Sign.prototype.sign = function signMethod (key, enc) {
      this.end()
      var hash = this._hash.digest()
      var sig = sign(hash, key, this._hashType, this._signType, this._tag)
    
      return enc ? sig.toString(enc) : sig
    }
    
    function Verify (algorithm) {
      stream.Writable.call(this)
    
      var data = algorithms[algorithm]
      if (!data) throw new Error('Unknown message digest')
    
      this._hash = createHash(data.hash)
      this._tag = data.id
      this._signType = data.sign
    }
    inherits(Verify, stream.Writable)
    
    Verify.prototype._write = function _write (data, _, done) {
      this._hash.update(data)
      done()
    }
    
    Verify.prototype.update = function update (data, enc) {
      if (typeof data === 'string') data = Buffer.from(data, enc)
    
      this._hash.update(data)
      return this
    }
    
    Verify.prototype.verify = function verifyMethod (key, sig, enc) {
      if (typeof sig === 'string') sig = Buffer.from(sig, enc)
    
      this.end()
      var hash = this._hash.digest()
      return verify(sig, hash, key, this._signType, this._tag)
    }
    
    function createSign (algorithm) {
      return new Sign(algorithm)
    }
    
    function createVerify (algorithm) {
      return new Verify(algorithm)
    }
    
    module.exports = {
      Sign: createSign,
      Verify: createVerify,
      createSign: createSign,
      createVerify: createVerify
    }
    
    },{"./algorithms.json":47,"./sign":50,"./verify":51,"create-hash":74,"inherits":149,"readable-stream":66,"safe-buffer":187}],50:[function(require,module,exports){
    // much of this based on https://github.com/indutny/self-signed/blob/gh-pages/lib/rsa.js
    var Buffer = require('safe-buffer').Buffer
    var createHmac = require('create-hmac')
    var crt = require('browserify-rsa')
    var EC = require('elliptic').ec
    var BN = require('bn.js')
    var parseKeys = require('parse-asn1')
    var curves = require('./curves.json')
    
    function sign (hash, key, hashType, signType, tag) {
      var priv = parseKeys(key)
      if (priv.curve) {
        // rsa keys can be interpreted as ecdsa ones in openssl
        if (signType !== 'ecdsa' && signType !== 'ecdsa/rsa') throw new Error('wrong private key type')
        return ecSign(hash, priv)
      } else if (priv.type === 'dsa') {
        if (signType !== 'dsa') throw new Error('wrong private key type')
        return dsaSign(hash, priv, hashType)
      } else {
        if (signType !== 'rsa' && signType !== 'ecdsa/rsa') throw new Error('wrong private key type')
      }
      hash = Buffer.concat([tag, hash])
      var len = priv.modulus.byteLength()
      var pad = [0, 1]
      while (hash.length + pad.length + 1 < len) pad.push(0xff)
      pad.push(0x00)
      var i = -1
      while (++i < hash.length) pad.push(hash[i])
    
      var out = crt(pad, priv)
      return out
    }
    
    function ecSign (hash, priv) {
      var curveId = curves[priv.curve.join('.')]
      if (!curveId) throw new Error('unknown curve ' + priv.curve.join('.'))
    
      var curve = new EC(curveId)
      var key = curve.keyFromPrivate(priv.privateKey)
      var out = key.sign(hash)
    
      return Buffer.from(out.toDER())
    }
    
    function dsaSign (hash, priv, algo) {
      var x = priv.params.priv_key
      var p = priv.params.p
      var q = priv.params.q
      var g = priv.params.g
      var r = new BN(0)
      var k
      var H = bits2int(hash, q).mod(q)
      var s = false
      var kv = getKey(x, q, hash, algo)
      while (s === false) {
        k = makeKey(q, kv, algo)
        r = makeR(g, k, p, q)
        s = k.invm(q).imul(H.add(x.mul(r))).mod(q)
        if (s.cmpn(0) === 0) {
          s = false
          r = new BN(0)
        }
      }
      return toDER(r, s)
    }
    
    function toDER (r, s) {
      r = r.toArray()
      s = s.toArray()
    
      // Pad values
      if (r[0] & 0x80) r = [0].concat(r)
      if (s[0] & 0x80) s = [0].concat(s)
    
      var total = r.length + s.length + 4
      var res = [0x30, total, 0x02, r.length]
      res = res.concat(r, [0x02, s.length], s)
      return Buffer.from(res)
    }
    
    function getKey (x, q, hash, algo) {
      x = Buffer.from(x.toArray())
      if (x.length < q.byteLength()) {
        var zeros = Buffer.alloc(q.byteLength() - x.length)
        x = Buffer.concat([zeros, x])
      }
      var hlen = hash.length
      var hbits = bits2octets(hash, q)
      var v = Buffer.alloc(hlen)
      v.fill(1)
      var k = Buffer.alloc(hlen)
      k = createHmac(algo, k).update(v).update(Buffer.from([0])).update(x).update(hbits).digest()
      v = createHmac(algo, k).update(v).digest()
      k = createHmac(algo, k).update(v).update(Buffer.from([1])).update(x).update(hbits).digest()
      v = createHmac(algo, k).update(v).digest()
      return { k: k, v: v }
    }
    
    function bits2int (obits, q) {
      var bits = new BN(obits)
      var shift = (obits.length << 3) - q.bitLength()
      if (shift > 0) bits.ishrn(shift)
      return bits
    }
    
    function bits2octets (bits, q) {
      bits = bits2int(bits, q)
      bits = bits.mod(q)
      var out = Buffer.from(bits.toArray())
      if (out.length < q.byteLength()) {
        var zeros = Buffer.alloc(q.byteLength() - out.length)
        out = Buffer.concat([zeros, out])
      }
      return out
    }
    
    function makeKey (q, kv, algo) {
      var t
      var k
    
      do {
        t = Buffer.alloc(0)
    
        while (t.length * 8 < q.bitLength()) {
          kv.v = createHmac(algo, kv.k).update(kv.v).digest()
          t = Buffer.concat([t, kv.v])
        }
    
        k = bits2int(t, q)
        kv.k = createHmac(algo, kv.k).update(kv.v).update(Buffer.from([0])).digest()
        kv.v = createHmac(algo, kv.k).update(kv.v).digest()
      } while (k.cmp(q) !== -1)
    
      return k
    }
    
    function makeR (g, k, p, q) {
      return g.toRed(BN.mont(p)).redPow(k).fromRed().mod(q)
    }
    
    module.exports = sign
    module.exports.getKey = getKey
    module.exports.makeKey = makeKey
    
    },{"./curves.json":48,"bn.js":22,"browserify-rsa":45,"create-hmac":76,"elliptic":90,"parse-asn1":169,"safe-buffer":187}],51:[function(require,module,exports){
    // much of this based on https://github.com/indutny/self-signed/blob/gh-pages/lib/rsa.js
    var Buffer = require('safe-buffer').Buffer
    var BN = require('bn.js')
    var EC = require('elliptic').ec
    var parseKeys = require('parse-asn1')
    var curves = require('./curves.json')
    
    function verify (sig, hash, key, signType, tag) {
      var pub = parseKeys(key)
      if (pub.type === 'ec') {
        // rsa keys can be interpreted as ecdsa ones in openssl
        if (signType !== 'ecdsa' && signType !== 'ecdsa/rsa') throw new Error('wrong public key type')
        return ecVerify(sig, hash, pub)
      } else if (pub.type === 'dsa') {
        if (signType !== 'dsa') throw new Error('wrong public key type')
        return dsaVerify(sig, hash, pub)
      } else {
        if (signType !== 'rsa' && signType !== 'ecdsa/rsa') throw new Error('wrong public key type')
      }
      hash = Buffer.concat([tag, hash])
      var len = pub.modulus.byteLength()
      var pad = [1]
      var padNum = 0
      while (hash.length + pad.length + 2 < len) {
        pad.push(0xff)
        padNum++
      }
      pad.push(0x00)
      var i = -1
      while (++i < hash.length) {
        pad.push(hash[i])
      }
      pad = Buffer.from(pad)
      var red = BN.mont(pub.modulus)
      sig = new BN(sig).toRed(red)
    
      sig = sig.redPow(new BN(pub.publicExponent))
      sig = Buffer.from(sig.fromRed().toArray())
      var out = padNum < 8 ? 1 : 0
      len = Math.min(sig.length, pad.length)
      if (sig.length !== pad.length) out = 1
    
      i = -1
      while (++i < len) out |= sig[i] ^ pad[i]
      return out === 0
    }
    
    function ecVerify (sig, hash, pub) {
      var curveId = curves[pub.data.algorithm.curve.join('.')]
      if (!curveId) throw new Error('unknown curve ' + pub.data.algorithm.curve.join('.'))
    
      var curve = new EC(curveId)
      var pubkey = pub.data.subjectPrivateKey.data
    
      return curve.verify(hash, sig, pubkey)
    }
    
    function dsaVerify (sig, hash, pub) {
      var p = pub.data.p
      var q = pub.data.q
      var g = pub.data.g
      var y = pub.data.pub_key
      var unpacked = parseKeys.signature.decode(sig, 'der')
      var s = unpacked.s
      var r = unpacked.r
      checkValue(s, q)
      checkValue(r, q)
      var montp = BN.mont(p)
      var w = s.invm(q)
      var v = g.toRed(montp)
        .redPow(new BN(hash).mul(w).mod(q))
        .fromRed()
        .mul(y.toRed(montp).redPow(r.mul(w).mod(q)).fromRed())
        .mod(p)
        .mod(q)
      return v.cmp(r) === 0
    }
    
    function checkValue (b, q) {
      if (b.cmpn(0) <= 0) throw new Error('invalid sig')
      if (b.cmp(q) >= q) throw new Error('invalid sig')
    }
    
    module.exports = verify
    
    },{"./curves.json":48,"bn.js":22,"elliptic":90,"parse-asn1":169,"safe-buffer":187}],52:[function(require,module,exports){
    'use strict';
    
    function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; }
    
    var codes = {};
    
    function createErrorType(code, message, Base) {
      if (!Base) {
        Base = Error;
      }
    
      function getMessage(arg1, arg2, arg3) {
        if (typeof message === 'string') {
          return message;
        } else {
          return message(arg1, arg2, arg3);
        }
      }
    
      var NodeError =
      /*#__PURE__*/
      function (_Base) {
        _inheritsLoose(NodeError, _Base);
    
        function NodeError(arg1, arg2, arg3) {
          return _Base.call(this, getMessage(arg1, arg2, arg3)) || this;
        }
    
        return NodeError;
      }(Base);
    
      NodeError.prototype.name = Base.name;
      NodeError.prototype.code = code;
      codes[code] = NodeError;
    } // https://github.com/nodejs/node/blob/v10.8.0/lib/internal/errors.js
    
    
    function oneOf(expected, thing) {
      if (Array.isArray(expected)) {
        var len = expected.length;
        expected = expected.map(function (i) {
          return String(i);
        });
    
        if (len > 2) {
          return "one of ".concat(thing, " ").concat(expected.slice(0, len - 1).join(', '), ", or ") + expected[len - 1];
        } else if (len === 2) {
          return "one of ".concat(thing, " ").concat(expected[0], " or ").concat(expected[1]);
        } else {
          return "of ".concat(thing, " ").concat(expected[0]);
        }
      } else {
        return "of ".concat(thing, " ").concat(String(expected));
      }
    } // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/startsWith
    
    
    function startsWith(str, search, pos) {
      return str.substr(!pos || pos < 0 ? 0 : +pos, search.length) === search;
    } // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/endsWith
    
    
    function endsWith(str, search, this_len) {
      if (this_len === undefined || this_len > str.length) {
        this_len = str.length;
      }
    
      return str.substring(this_len - search.length, this_len) === search;
    } // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/includes
    
    
    function includes(str, search, start) {
      if (typeof start !== 'number') {
        start = 0;
      }
    
      if (start + search.length > str.length) {
        return false;
      } else {
        return str.indexOf(search, start) !== -1;
      }
    }
    
    createErrorType('ERR_INVALID_OPT_VALUE', function (name, value) {
      return 'The value "' + value + '" is invalid for option "' + name + '"';
    }, TypeError);
    createErrorType('ERR_INVALID_ARG_TYPE', function (name, expected, actual) {
      // determiner: 'must be' or 'must not be'
      var determiner;
    
      if (typeof expected === 'string' && startsWith(expected, 'not ')) {
        determiner = 'must not be';
        expected = expected.replace(/^not /, '');
      } else {
        determiner = 'must be';
      }
    
      var msg;
    
      if (endsWith(name, ' argument')) {
        // For cases like 'first argument'
        msg = "The ".concat(name, " ").concat(determiner, " ").concat(oneOf(expected, 'type'));
      } else {
        var type = includes(name, '.') ? 'property' : 'argument';
        msg = "The \"".concat(name, "\" ").concat(type, " ").concat(determiner, " ").concat(oneOf(expected, 'type'));
      }
    
      msg += ". Received type ".concat(typeof actual);
      return msg;
    }, TypeError);
    createErrorType('ERR_STREAM_PUSH_AFTER_EOF', 'stream.push() after EOF');
    createErrorType('ERR_METHOD_NOT_IMPLEMENTED', function (name) {
      return 'The ' + name + ' method is not implemented';
    });
    createErrorType('ERR_STREAM_PREMATURE_CLOSE', 'Premature close');
    createErrorType('ERR_STREAM_DESTROYED', function (name) {
      return 'Cannot call ' + name + ' after a stream was destroyed';
    });
    createErrorType('ERR_MULTIPLE_CALLBACK', 'Callback called multiple times');
    createErrorType('ERR_STREAM_CANNOT_PIPE', 'Cannot pipe, not readable');
    createErrorType('ERR_STREAM_WRITE_AFTER_END', 'write after end');
    createErrorType('ERR_STREAM_NULL_VALUES', 'May not write null values to stream', TypeError);
    createErrorType('ERR_UNKNOWN_ENCODING', function (arg) {
      return 'Unknown encoding: ' + arg;
    }, TypeError);
    createErrorType('ERR_STREAM_UNSHIFT_AFTER_END_EVENT', 'stream.unshift() after end event');
    module.exports.codes = codes;
    
    },{}],53:[function(require,module,exports){
    (function (process){(function (){
    // Copyright Joyent, Inc. and other Node contributors.
    //
    // Permission is hereby granted, free of charge, to any person obtaining a
    // copy of this software and associated documentation files (the
    // "Software"), to deal in the Software without restriction, including
    // without limitation the rights to use, copy, modify, merge, publish,
    // distribute, sublicense, and/or sell copies of the Software, and to permit
    // persons to whom the Software is furnished to do so, subject to the
    // following conditions:
    //
    // The above copyright notice and this permission notice shall be included
    // in all copies or substantial portions of the Software.
    //
    // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
    // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
    // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
    // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
    // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
    // USE OR OTHER DEALINGS IN THE SOFTWARE.
    
    // a duplex stream is just a stream that is both readable and writable.
    // Since JS doesn't have multiple prototypal inheritance, this class
    // prototypally inherits from Readable, and then parasitically from
    // Writable.
    
    'use strict';
    
    /*<replacement>*/
    var objectKeys = Object.keys || function (obj) {
      var keys = [];
      for (var key in obj) keys.push(key);
      return keys;
    };
    /*</replacement>*/
    
    module.exports = Duplex;
    var Readable = require('./_stream_readable');
    var Writable = require('./_stream_writable');
    require('inherits')(Duplex, Readable);
    {
      // Allow the keys array to be GC'ed.
      var keys = objectKeys(Writable.prototype);
      for (var v = 0; v < keys.length; v++) {
        var method = keys[v];
        if (!Duplex.prototype[method]) Duplex.prototype[method] = Writable.prototype[method];
      }
    }
    function Duplex(options) {
      if (!(this instanceof Duplex)) return new Duplex(options);
      Readable.call(this, options);
      Writable.call(this, options);
      this.allowHalfOpen = true;
      if (options) {
        if (options.readable === false) this.readable = false;
        if (options.writable === false) this.writable = false;
        if (options.allowHalfOpen === false) {
          this.allowHalfOpen = false;
          this.once('end', onend);
        }
      }
    }
    Object.defineProperty(Duplex.prototype, 'writableHighWaterMark', {
      // making it explicit this property is not enumerable
      // because otherwise some prototype manipulation in
      // userland will fail
      enumerable: false,
      get: function get() {
        return this._writableState.highWaterMark;
      }
    });
    Object.defineProperty(Duplex.prototype, 'writableBuffer', {
      // making it explicit this property is not enumerable
      // because otherwise some prototype manipulation in
      // userland will fail
      enumerable: false,
      get: function get() {
        return this._writableState && this._writableState.getBuffer();
      }
    });
    Object.defineProperty(Duplex.prototype, 'writableLength', {
      // making it explicit this property is not enumerable
      // because otherwise some prototype manipulation in
      // userland will fail
      enumerable: false,
      get: function get() {
        return this._writableState.length;
      }
    });
    
    // the no-half-open enforcer
    function onend() {
      // If the writable side ended, then we're ok.
      if (this._writableState.ended) return;
    
      // no more data can be written.
      // But allow more writes to happen in this tick.
      process.nextTick(onEndNT, this);
    }
    function onEndNT(self) {
      self.end();
    }
    Object.defineProperty(Duplex.prototype, 'destroyed', {
      // making it explicit this property is not enumerable
      // because otherwise some prototype manipulation in
      // userland will fail
      enumerable: false,
      get: function get() {
        if (this._readableState === undefined || this._writableState === undefined) {
          return false;
        }
        return this._readableState.destroyed && this._writableState.destroyed;
      },
      set: function set(value) {
        // we ignore the value if the stream
        // has not been initialized yet
        if (this._readableState === undefined || this._writableState === undefined) {
          return;
        }
    
        // backward compatibility, the user is explicitly
        // managing destroyed
        this._readableState.destroyed = value;
        this._writableState.destroyed = value;
      }
    });
    }).call(this)}).call(this,require('_process'))
    },{"./_stream_readable":55,"./_stream_writable":57,"_process":176,"inherits":149}],54:[function(require,module,exports){
    // Copyright Joyent, Inc. and other Node contributors.
    //
    // Permission is hereby granted, free of charge, to any person obtaining a
    // copy of this software and associated documentation files (the
    // "Software"), to deal in the Software without restriction, including
    // without limitation the rights to use, copy, modify, merge, publish,
    // distribute, sublicense, and/or sell copies of the Software, and to permit
    // persons to whom the Software is furnished to do so, subject to the
    // following conditions:
    //
    // The above copyright notice and this permission notice shall be included
    // in all copies or substantial portions of the Software.
    //
    // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
    // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
    // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
    // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
    // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
    // USE OR OTHER DEALINGS IN THE SOFTWARE.
    
    // a passthrough stream.
    // basically just the most minimal sort of Transform stream.
    // Every written chunk gets output as-is.
    
    'use strict';
    
    module.exports = PassThrough;
    var Transform = require('./_stream_transform');
    require('inherits')(PassThrough, Transform);
    function PassThrough(options) {
      if (!(this instanceof PassThrough)) return new PassThrough(options);
      Transform.call(this, options);
    }
    PassThrough.prototype._transform = function (chunk, encoding, cb) {
      cb(null, chunk);
    };
    },{"./_stream_transform":56,"inherits":149}],55:[function(require,module,exports){
    (function (process,global){(function (){
    // Copyright Joyent, Inc. and other Node contributors.
    //
    // Permission is hereby granted, free of charge, to any person obtaining a
    // copy of this software and associated documentation files (the
    // "Software"), to deal in the Software without restriction, including
    // without limitation the rights to use, copy, modify, merge, publish,
    // distribute, sublicense, and/or sell copies of the Software, and to permit
    // persons to whom the Software is furnished to do so, subject to the
    // following conditions:
    //
    // The above copyright notice and this permission notice shall be included
    // in all copies or substantial portions of the Software.
    //
    // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
    // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
    // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
    // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
    // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
    // USE OR OTHER DEALINGS IN THE SOFTWARE.
    
    'use strict';
    
    module.exports = Readable;
    
    /*<replacement>*/
    var Duplex;
    /*</replacement>*/
    
    Readable.ReadableState = ReadableState;
    
    /*<replacement>*/
    var EE = require('events').EventEmitter;
    var EElistenerCount = function EElistenerCount(emitter, type) {
      return emitter.listeners(type).length;
    };
    /*</replacement>*/
    
    /*<replacement>*/
    var Stream = require('./internal/streams/stream');
    /*</replacement>*/
    
    var Buffer = require('buffer').Buffer;
    var OurUint8Array = (typeof global !== 'undefined' ? global : typeof window !== 'undefined' ? window : typeof self !== 'undefined' ? self : {}).Uint8Array || function () {};
    function _uint8ArrayToBuffer(chunk) {
      return Buffer.from(chunk);
    }
    function _isUint8Array(obj) {
      return Buffer.isBuffer(obj) || obj instanceof OurUint8Array;
    }
    
    /*<replacement>*/
    var debugUtil = require('util');
    var debug;
    if (debugUtil && debugUtil.debuglog) {
      debug = debugUtil.debuglog('stream');
    } else {
      debug = function debug() {};
    }
    /*</replacement>*/
    
    var BufferList = require('./internal/streams/buffer_list');
    var destroyImpl = require('./internal/streams/destroy');
    var _require = require('./internal/streams/state'),
      getHighWaterMark = _require.getHighWaterMark;
    var _require$codes = require('../errors').codes,
      ERR_INVALID_ARG_TYPE = _require$codes.ERR_INVALID_ARG_TYPE,
      ERR_STREAM_PUSH_AFTER_EOF = _require$codes.ERR_STREAM_PUSH_AFTER_EOF,
      ERR_METHOD_NOT_IMPLEMENTED = _require$codes.ERR_METHOD_NOT_IMPLEMENTED,
      ERR_STREAM_UNSHIFT_AFTER_END_EVENT = _require$codes.ERR_STREAM_UNSHIFT_AFTER_END_EVENT;
    
    // Lazy loaded to improve the startup performance.
    var StringDecoder;
    var createReadableStreamAsyncIterator;
    var from;
    require('inherits')(Readable, Stream);
    var errorOrDestroy = destroyImpl.errorOrDestroy;
    var kProxyEvents = ['error', 'close', 'destroy', 'pause', 'resume'];
    function prependListener(emitter, event, fn) {
      // Sadly this is not cacheable as some libraries bundle their own
      // event emitter implementation with them.
      if (typeof emitter.prependListener === 'function') return emitter.prependListener(event, fn);
    
      // This is a hack to make sure that our error handler is attached before any
      // userland ones.  NEVER DO THIS. This is here only because this code needs
      // to continue to work with older versions of Node.js that do not include
      // the prependListener() method. The goal is to eventually remove this hack.
      if (!emitter._events || !emitter._events[event]) emitter.on(event, fn);else if (Array.isArray(emitter._events[event])) emitter._events[event].unshift(fn);else emitter._events[event] = [fn, emitter._events[event]];
    }
    function ReadableState(options, stream, isDuplex) {
      Duplex = Duplex || require('./_stream_duplex');
      options = options || {};
    
      // Duplex streams are both readable and writable, but share
      // the same options object.
      // However, some cases require setting options to different
      // values for the readable and the writable sides of the duplex stream.
      // These options can be provided separately as readableXXX and writableXXX.
      if (typeof isDuplex !== 'boolean') isDuplex = stream instanceof Duplex;
    
      // object stream flag. Used to make read(n) ignore n and to
      // make all the buffer merging and length checks go away
      this.objectMode = !!options.objectMode;
      if (isDuplex) this.objectMode = this.objectMode || !!options.readableObjectMode;
    
      // the point at which it stops calling _read() to fill the buffer
      // Note: 0 is a valid value, means "don't call _read preemptively ever"
      this.highWaterMark = getHighWaterMark(this, options, 'readableHighWaterMark', isDuplex);
    
      // A linked list is used to store data chunks instead of an array because the
      // linked list can remove elements from the beginning faster than
      // array.shift()
      this.buffer = new BufferList();
      this.length = 0;
      this.pipes = null;
      this.pipesCount = 0;
      this.flowing = null;
      this.ended = false;
      this.endEmitted = false;
      this.reading = false;
    
      // a flag to be able to tell if the event 'readable'/'data' is emitted
      // immediately, or on a later tick.  We set this to true at first, because
      // any actions that shouldn't happen until "later" should generally also
      // not happen before the first read call.
      this.sync = true;
    
      // whenever we return null, then we set a flag to say
      // that we're awaiting a 'readable' event emission.
      this.needReadable = false;
      this.emittedReadable = false;
      this.readableListening = false;
      this.resumeScheduled = false;
      this.paused = true;
    
      // Should close be emitted on destroy. Defaults to true.
      this.emitClose = options.emitClose !== false;
    
      // Should .destroy() be called after 'end' (and potentially 'finish')
      this.autoDestroy = !!options.autoDestroy;
    
      // has it been destroyed
      this.destroyed = false;
    
      // Crypto is kind of old and crusty.  Historically, its default string
      // encoding is 'binary' so we have to make this configurable.
      // Everything else in the universe uses 'utf8', though.
      this.defaultEncoding = options.defaultEncoding || 'utf8';
    
      // the number of writers that are awaiting a drain event in .pipe()s
      this.awaitDrain = 0;
    
      // if true, a maybeReadMore has been scheduled
      this.readingMore = false;
      this.decoder = null;
      this.encoding = null;
      if (options.encoding) {
        if (!StringDecoder) StringDecoder = require('string_decoder/').StringDecoder;
        this.decoder = new StringDecoder(options.encoding);
        this.encoding = options.encoding;
      }
    }
    function Readable(options) {
      Duplex = Duplex || require('./_stream_duplex');
      if (!(this instanceof Readable)) return new Readable(options);
    
      // Checking for a Stream.Duplex instance is faster here instead of inside
      // the ReadableState constructor, at least with V8 6.5
      var isDuplex = this instanceof Duplex;
      this._readableState = new ReadableState(options, this, isDuplex);
    
      // legacy
      this.readable = true;
      if (options) {
        if (typeof options.read === 'function') this._read = options.read;
        if (typeof options.destroy === 'function') this._destroy = options.destroy;
      }
      Stream.call(this);
    }
    Object.defineProperty(Readable.prototype, 'destroyed', {
      // making it explicit this property is not enumerable
      // because otherwise some prototype manipulation in
      // userland will fail
      enumerable: false,
      get: function get() {
        if (this._readableState === undefined) {
          return false;
        }
        return this._readableState.destroyed;
      },
      set: function set(value) {
        // we ignore the value if the stream
        // has not been initialized yet
        if (!this._readableState) {
          return;
        }
    
        // backward compatibility, the user is explicitly
        // managing destroyed
        this._readableState.destroyed = value;
      }
    });
    Readable.prototype.destroy = destroyImpl.destroy;
    Readable.prototype._undestroy = destroyImpl.undestroy;
    Readable.prototype._destroy = function (err, cb) {
      cb(err);
    };
    
    // Manually shove something into the read() buffer.
    // This returns true if the highWaterMark has not been hit yet,
    // similar to how Writable.write() returns true if you should
    // write() some more.
    Readable.prototype.push = function (chunk, encoding) {
      var state = this._readableState;
      var skipChunkCheck;
      if (!state.objectMode) {
        if (typeof chunk === 'string') {
          encoding = encoding || state.defaultEncoding;
          if (encoding !== state.encoding) {
            chunk = Buffer.from(chunk, encoding);
            encoding = '';
          }
          skipChunkCheck = true;
        }
      } else {
        skipChunkCheck = true;
      }
      return readableAddChunk(this, chunk, encoding, false, skipChunkCheck);
    };
    
    // Unshift should *always* be something directly out of read()
    Readable.prototype.unshift = function (chunk) {
      return readableAddChunk(this, chunk, null, true, false);
    };
    function readableAddChunk(stream, chunk, encoding, addToFront, skipChunkCheck) {
      debug('readableAddChunk', chunk);
      var state = stream._readableState;
      if (chunk === null) {
        state.reading = false;
        onEofChunk(stream, state);
      } else {
        var er;
        if (!skipChunkCheck) er = chunkInvalid(state, chunk);
        if (er) {
          errorOrDestroy(stream, er);
        } else if (state.objectMode || chunk && chunk.length > 0) {
          if (typeof chunk !== 'string' && !state.objectMode && Object.getPrototypeOf(chunk) !== Buffer.prototype) {
            chunk = _uint8ArrayToBuffer(chunk);
          }
          if (addToFront) {
            if (state.endEmitted) errorOrDestroy(stream, new ERR_STREAM_UNSHIFT_AFTER_END_EVENT());else addChunk(stream, state, chunk, true);
          } else if (state.ended) {
            errorOrDestroy(stream, new ERR_STREAM_PUSH_AFTER_EOF());
          } else if (state.destroyed) {
            return false;
          } else {
            state.reading = false;
            if (state.decoder && !encoding) {
              chunk = state.decoder.write(chunk);
              if (state.objectMode || chunk.length !== 0) addChunk(stream, state, chunk, false);else maybeReadMore(stream, state);
            } else {
              addChunk(stream, state, chunk, false);
            }
          }
        } else if (!addToFront) {
          state.reading = false;
          maybeReadMore(stream, state);
        }
      }
    
      // We can push more data if we are below the highWaterMark.
      // Also, if we have no data yet, we can stand some more bytes.
      // This is to work around cases where hwm=0, such as the repl.
      return !state.ended && (state.length < state.highWaterMark || state.length === 0);
    }
    function addChunk(stream, state, chunk, addToFront) {
      if (state.flowing && state.length === 0 && !state.sync) {
        state.awaitDrain = 0;
        stream.emit('data', chunk);
      } else {
        // update the buffer info.
        state.length += state.objectMode ? 1 : chunk.length;
        if (addToFront) state.buffer.unshift(chunk);else state.buffer.push(chunk);
        if (state.needReadable) emitReadable(stream);
      }
      maybeReadMore(stream, state);
    }
    function chunkInvalid(state, chunk) {
      var er;
      if (!_isUint8Array(chunk) && typeof chunk !== 'string' && chunk !== undefined && !state.objectMode) {
        er = new ERR_INVALID_ARG_TYPE('chunk', ['string', 'Buffer', 'Uint8Array'], chunk);
      }
      return er;
    }
    Readable.prototype.isPaused = function () {
      return this._readableState.flowing === false;
    };
    
    // backwards compatibility.
    Readable.prototype.setEncoding = function (enc) {
      if (!StringDecoder) StringDecoder = require('string_decoder/').StringDecoder;
      var decoder = new StringDecoder(enc);
      this._readableState.decoder = decoder;
      // If setEncoding(null), decoder.encoding equals utf8
      this._readableState.encoding = this._readableState.decoder.encoding;
    
      // Iterate over current buffer to convert already stored Buffers:
      var p = this._readableState.buffer.head;
      var content = '';
      while (p !== null) {
        content += decoder.write(p.data);
        p = p.next;
      }
      this._readableState.buffer.clear();
      if (content !== '') this._readableState.buffer.push(content);
      this._readableState.length = content.length;
      return this;
    };
    
    // Don't raise the hwm > 1GB
    var MAX_HWM = 0x40000000;
    function computeNewHighWaterMark(n) {
      if (n >= MAX_HWM) {
        // TODO(ronag): Throw ERR_VALUE_OUT_OF_RANGE.
        n = MAX_HWM;
      } else {
        // Get the next highest power of 2 to prevent increasing hwm excessively in
        // tiny amounts
        n--;
        n |= n >>> 1;
        n |= n >>> 2;
        n |= n >>> 4;
        n |= n >>> 8;
        n |= n >>> 16;
        n++;
      }
      return n;
    }
    
    // This function is designed to be inlinable, so please take care when making
    // changes to the function body.
    function howMuchToRead(n, state) {
      if (n <= 0 || state.length === 0 && state.ended) return 0;
      if (state.objectMode) return 1;
      if (n !== n) {
        // Only flow one buffer at a time
        if (state.flowing && state.length) return state.buffer.head.data.length;else return state.length;
      }
      // If we're asking for more than the current hwm, then raise the hwm.
      if (n > state.highWaterMark) state.highWaterMark = computeNewHighWaterMark(n);
      if (n <= state.length) return n;
      // Don't have enough
      if (!state.ended) {
        state.needReadable = true;
        return 0;
      }
      return state.length;
    }
    
    // you can override either this method, or the async _read(n) below.
    Readable.prototype.read = function (n) {
      debug('read', n);
      n = parseInt(n, 10);
      var state = this._readableState;
      var nOrig = n;
      if (n !== 0) state.emittedReadable = false;
    
      // if we're doing read(0) to trigger a readable event, but we
      // already have a bunch of data in the buffer, then just trigger
      // the 'readable' event and move on.
      if (n === 0 && state.needReadable && ((state.highWaterMark !== 0 ? state.length >= state.highWaterMark : state.length > 0) || state.ended)) {
        debug('read: emitReadable', state.length, state.ended);
        if (state.length === 0 && state.ended) endReadable(this);else emitReadable(this);
        return null;
      }
      n = howMuchToRead(n, state);
    
      // if we've ended, and we're now clear, then finish it up.
      if (n === 0 && state.ended) {
        if (state.length === 0) endReadable(this);
        return null;
      }
    
      // All the actual chunk generation logic needs to be
      // *below* the call to _read.  The reason is that in certain
      // synthetic stream cases, such as passthrough streams, _read
      // may be a completely synchronous operation which may change
      // the state of the read buffer, providing enough data when
      // before there was *not* enough.
      //
      // So, the steps are:
      // 1. Figure out what the state of things will be after we do
      // a read from the buffer.
      //
      // 2. If that resulting state will trigger a _read, then call _read.
      // Note that this may be asynchronous, or synchronous.  Yes, it is
      // deeply ugly to write APIs this way, but that still doesn't mean
      // that the Readable class should behave improperly, as streams are
      // designed to be sync/async agnostic.
      // Take note if the _read call is sync or async (ie, if the read call
      // has returned yet), so that we know whether or not it's safe to emit
      // 'readable' etc.
      //
      // 3. Actually pull the requested chunks out of the buffer and return.
    
      // if we need a readable event, then we need to do some reading.
      var doRead = state.needReadable;
      debug('need readable', doRead);
    
      // if we currently have less than the highWaterMark, then also read some
      if (state.length === 0 || state.length - n < state.highWaterMark) {
        doRead = true;
        debug('length less than watermark', doRead);
      }
    
      // however, if we've ended, then there's no point, and if we're already
      // reading, then it's unnecessary.
      if (state.ended || state.reading) {
        doRead = false;
        debug('reading or ended', doRead);
      } else if (doRead) {
        debug('do read');
        state.reading = true;
        state.sync = true;
        // if the length is currently zero, then we *need* a readable event.
        if (state.length === 0) state.needReadable = true;
        // call internal read method
        this._read(state.highWaterMark);
        state.sync = false;
        // If _read pushed data synchronously, then `reading` will be false,
        // and we need to re-evaluate how much data we can return to the user.
        if (!state.reading) n = howMuchToRead(nOrig, state);
      }
      var ret;
      if (n > 0) ret = fromList(n, state);else ret = null;
      if (ret === null) {
        state.needReadable = state.length <= state.highWaterMark;
        n = 0;
      } else {
        state.length -= n;
        state.awaitDrain = 0;
      }
      if (state.length === 0) {
        // If we have nothing in the buffer, then we want to know
        // as soon as we *do* get something into the buffer.
        if (!state.ended) state.needReadable = true;
    
        // If we tried to read() past the EOF, then emit end on the next tick.
        if (nOrig !== n && state.ended) endReadable(this);
      }
      if (ret !== null) this.emit('data', ret);
      return ret;
    };
    function onEofChunk(stream, state) {
      debug('onEofChunk');
      if (state.ended) return;
      if (state.decoder) {
        var chunk = state.decoder.end();
        if (chunk && chunk.length) {
          state.buffer.push(chunk);
          state.length += state.objectMode ? 1 : chunk.length;
        }
      }
      state.ended = true;
      if (state.sync) {
        // if we are sync, wait until next tick to emit the data.
        // Otherwise we risk emitting data in the flow()
        // the readable code triggers during a read() call
        emitReadable(stream);
      } else {
        // emit 'readable' now to make sure it gets picked up.
        state.needReadable = false;
        if (!state.emittedReadable) {
          state.emittedReadable = true;
          emitReadable_(stream);
        }
      }
    }
    
    // Don't emit readable right away in sync mode, because this can trigger
    // another read() call => stack overflow.  This way, it might trigger
    // a nextTick recursion warning, but that's not so bad.
    function emitReadable(stream) {
      var state = stream._readableState;
      debug('emitReadable', state.needReadable, state.emittedReadable);
      state.needReadable = false;
      if (!state.emittedReadable) {
        debug('emitReadable', state.flowing);
        state.emittedReadable = true;
        process.nextTick(emitReadable_, stream);
      }
    }
    function emitReadable_(stream) {
      var state = stream._readableState;
      debug('emitReadable_', state.destroyed, state.length, state.ended);
      if (!state.destroyed && (state.length || state.ended)) {
        stream.emit('readable');
        state.emittedReadable = false;
      }
    
      // The stream needs another readable event if
      // 1. It is not flowing, as the flow mechanism will take
      //    care of it.
      // 2. It is not ended.
      // 3. It is below the highWaterMark, so we can schedule
      //    another readable later.
      state.needReadable = !state.flowing && !state.ended && state.length <= state.highWaterMark;
      flow(stream);
    }
    
    // at this point, the user has presumably seen the 'readable' event,
    // and called read() to consume some data.  that may have triggered
    // in turn another _read(n) call, in which case reading = true if
    // it's in progress.
    // However, if we're not ended, or reading, and the length < hwm,
    // then go ahead and try to read some more preemptively.
    function maybeReadMore(stream, state) {
      if (!state.readingMore) {
        state.readingMore = true;
        process.nextTick(maybeReadMore_, stream, state);
      }
    }
    function maybeReadMore_(stream, state) {
      // Attempt to read more data if we should.
      //
      // The conditions for reading more data are (one of):
      // - Not enough data buffered (state.length < state.highWaterMark). The loop
      //   is responsible for filling the buffer with enough data if such data
      //   is available. If highWaterMark is 0 and we are not in the flowing mode
      //   we should _not_ attempt to buffer any extra data. We'll get more data
      //   when the stream consumer calls read() instead.
      // - No data in the buffer, and the stream is in flowing mode. In this mode
      //   the loop below is responsible for ensuring read() is called. Failing to
      //   call read here would abort the flow and there's no other mechanism for
      //   continuing the flow if the stream consumer has just subscribed to the
      //   'data' event.
      //
      // In addition to the above conditions to keep reading data, the following
      // conditions prevent the data from being read:
      // - The stream has ended (state.ended).
      // - There is already a pending 'read' operation (state.reading). This is a
      //   case where the the stream has called the implementation defined _read()
      //   method, but they are processing the call asynchronously and have _not_
      //   called push() with new data. In this case we skip performing more
      //   read()s. The execution ends in this method again after the _read() ends
      //   up calling push() with more data.
      while (!state.reading && !state.ended && (state.length < state.highWaterMark || state.flowing && state.length === 0)) {
        var len = state.length;
        debug('maybeReadMore read 0');
        stream.read(0);
        if (len === state.length)
          // didn't get any data, stop spinning.
          break;
      }
      state.readingMore = false;
    }
    
    // abstract method.  to be overridden in specific implementation classes.
    // call cb(er, data) where data is <= n in length.
    // for virtual (non-string, non-buffer) streams, "length" is somewhat
    // arbitrary, and perhaps not very meaningful.
    Readable.prototype._read = function (n) {
      errorOrDestroy(this, new ERR_METHOD_NOT_IMPLEMENTED('_read()'));
    };
    Readable.prototype.pipe = function (dest, pipeOpts) {
      var src = this;
      var state = this._readableState;
      switch (state.pipesCount) {
        case 0:
          state.pipes = dest;
          break;
        case 1:
          state.pipes = [state.pipes, dest];
          break;
        default:
          state.pipes.push(dest);
          break;
      }
      state.pipesCount += 1;
      debug('pipe count=%d opts=%j', state.pipesCount, pipeOpts);
      var doEnd = (!pipeOpts || pipeOpts.end !== false) && dest !== process.stdout && dest !== process.stderr;
      var endFn = doEnd ? onend : unpipe;
      if (state.endEmitted) process.nextTick(endFn);else src.once('end', endFn);
      dest.on('unpipe', onunpipe);
      function onunpipe(readable, unpipeInfo) {
        debug('onunpipe');
        if (readable === src) {
          if (unpipeInfo && unpipeInfo.hasUnpiped === false) {
            unpipeInfo.hasUnpiped = true;
            cleanup();
          }
        }
      }
      function onend() {
        debug('onend');
        dest.end();
      }
    
      // when the dest drains, it reduces the awaitDrain counter
      // on the source.  This would be more elegant with a .once()
      // handler in flow(), but adding and removing repeatedly is
      // too slow.
      var ondrain = pipeOnDrain(src);
      dest.on('drain', ondrain);
      var cleanedUp = false;
      function cleanup() {
        debug('cleanup');
        // cleanup event handlers once the pipe is broken
        dest.removeListener('close', onclose);
        dest.removeListener('finish', onfinish);
        dest.removeListener('drain', ondrain);
        dest.removeListener('error', onerror);
        dest.removeListener('unpipe', onunpipe);
        src.removeListener('end', onend);
        src.removeListener('end', unpipe);
        src.removeListener('data', ondata);
        cleanedUp = true;
    
        // if the reader is waiting for a drain event from this
        // specific writer, then it would cause it to never start
        // flowing again.
        // So, if this is awaiting a drain, then we just call it now.
        // If we don't know, then assume that we are waiting for one.
        if (state.awaitDrain && (!dest._writableState || dest._writableState.needDrain)) ondrain();
      }
      src.on('data', ondata);
      function ondata(chunk) {
        debug('ondata');
        var ret = dest.write(chunk);
        debug('dest.write', ret);
        if (ret === false) {
          // If the user unpiped during `dest.write()`, it is possible
          // to get stuck in a permanently paused state if that write
          // also returned false.
          // => Check whether `dest` is still a piping destination.
          if ((state.pipesCount === 1 && state.pipes === dest || state.pipesCount > 1 && indexOf(state.pipes, dest) !== -1) && !cleanedUp) {
            debug('false write response, pause', state.awaitDrain);
            state.awaitDrain++;
          }
          src.pause();
        }
      }
    
      // if the dest has an error, then stop piping into it.
      // however, don't suppress the throwing behavior for this.
      function onerror(er) {
        debug('onerror', er);
        unpipe();
        dest.removeListener('error', onerror);
        if (EElistenerCount(dest, 'error') === 0) errorOrDestroy(dest, er);
      }
    
      // Make sure our error handler is attached before userland ones.
      prependListener(dest, 'error', onerror);
    
      // Both close and finish should trigger unpipe, but only once.
      function onclose() {
        dest.removeListener('finish', onfinish);
        unpipe();
      }
      dest.once('close', onclose);
      function onfinish() {
        debug('onfinish');
        dest.removeListener('close', onclose);
        unpipe();
      }
      dest.once('finish', onfinish);
      function unpipe() {
        debug('unpipe');
        src.unpipe(dest);
      }
    
      // tell the dest that it's being piped to
      dest.emit('pipe', src);
    
      // start the flow if it hasn't been started already.
      if (!state.flowing) {
        debug('pipe resume');
        src.resume();
      }
      return dest;
    };
    function pipeOnDrain(src) {
      return function pipeOnDrainFunctionResult() {
        var state = src._readableState;
        debug('pipeOnDrain', state.awaitDrain);
        if (state.awaitDrain) state.awaitDrain--;
        if (state.awaitDrain === 0 && EElistenerCount(src, 'data')) {
          state.flowing = true;
          flow(src);
        }
      };
    }
    Readable.prototype.unpipe = function (dest) {
      var state = this._readableState;
      var unpipeInfo = {
        hasUnpiped: false
      };
    
      // if we're not piping anywhere, then do nothing.
      if (state.pipesCount === 0) return this;
    
      // just one destination.  most common case.
      if (state.pipesCount === 1) {
        // passed in one, but it's not the right one.
        if (dest && dest !== state.pipes) return this;
        if (!dest) dest = state.pipes;
    
        // got a match.
        state.pipes = null;
        state.pipesCount = 0;
        state.flowing = false;
        if (dest) dest.emit('unpipe', this, unpipeInfo);
        return this;
      }
    
      // slow case. multiple pipe destinations.
    
      if (!dest) {
        // remove all.
        var dests = state.pipes;
        var len = state.pipesCount;
        state.pipes = null;
        state.pipesCount = 0;
        state.flowing = false;
        for (var i = 0; i < len; i++) dests[i].emit('unpipe', this, {
          hasUnpiped: false
        });
        return this;
      }
    
      // try to find the right one.
      var index = indexOf(state.pipes, dest);
      if (index === -1) return this;
      state.pipes.splice(index, 1);
      state.pipesCount -= 1;
      if (state.pipesCount === 1) state.pipes = state.pipes[0];
      dest.emit('unpipe', this, unpipeInfo);
      return this;
    };
    
    // set up data events if they are asked for
    // Ensure readable listeners eventually get something
    Readable.prototype.on = function (ev, fn) {
      var res = Stream.prototype.on.call(this, ev, fn);
      var state = this._readableState;
      if (ev === 'data') {
        // update readableListening so that resume() may be a no-op
        // a few lines down. This is needed to support once('readable').
        state.readableListening = this.listenerCount('readable') > 0;
    
        // Try start flowing on next tick if stream isn't explicitly paused
        if (state.flowing !== false) this.resume();
      } else if (ev === 'readable') {
        if (!state.endEmitted && !state.readableListening) {
          state.readableListening = state.needReadable = true;
          state.flowing = false;
          state.emittedReadable = false;
          debug('on readable', state.length, state.reading);
          if (state.length) {
            emitReadable(this);
          } else if (!state.reading) {
            process.nextTick(nReadingNextTick, this);
          }
        }
      }
      return res;
    };
    Readable.prototype.addListener = Readable.prototype.on;
    Readable.prototype.removeListener = function (ev, fn) {
      var res = Stream.prototype.removeListener.call(this, ev, fn);
      if (ev === 'readable') {
        // We need to check if there is someone still listening to
        // readable and reset the state. However this needs to happen
        // after readable has been emitted but before I/O (nextTick) to
        // support once('readable', fn) cycles. This means that calling
        // resume within the same tick will have no
        // effect.
        process.nextTick(updateReadableListening, this);
      }
      return res;
    };
    Readable.prototype.removeAllListeners = function (ev) {
      var res = Stream.prototype.removeAllListeners.apply(this, arguments);
      if (ev === 'readable' || ev === undefined) {
        // We need to check if there is someone still listening to
        // readable and reset the state. However this needs to happen
        // after readable has been emitted but before I/O (nextTick) to
        // support once('readable', fn) cycles. This means that calling
        // resume within the same tick will have no
        // effect.
        process.nextTick(updateReadableListening, this);
      }
      return res;
    };
    function updateReadableListening(self) {
      var state = self._readableState;
      state.readableListening = self.listenerCount('readable') > 0;
      if (state.resumeScheduled && !state.paused) {
        // flowing needs to be set to true now, otherwise
        // the upcoming resume will not flow.
        state.flowing = true;
    
        // crude way to check if we should resume
      } else if (self.listenerCount('data') > 0) {
        self.resume();
      }
    }
    function nReadingNextTick(self) {
      debug('readable nexttick read 0');
      self.read(0);
    }
    
    // pause() and resume() are remnants of the legacy readable stream API
    // If the user uses them, then switch into old mode.
    Readable.prototype.resume = function () {
      var state = this._readableState;
      if (!state.flowing) {
        debug('resume');
        // we flow only if there is no one listening
        // for readable, but we still have to call
        // resume()
        state.flowing = !state.readableListening;
        resume(this, state);
      }
      state.paused = false;
      return this;
    };
    function resume(stream, state) {
      if (!state.resumeScheduled) {
        state.resumeScheduled = true;
        process.nextTick(resume_, stream, state);
      }
    }
    function resume_(stream, state) {
      debug('resume', state.reading);
      if (!state.reading) {
        stream.read(0);
      }
      state.resumeScheduled = false;
      stream.emit('resume');
      flow(stream);
      if (state.flowing && !state.reading) stream.read(0);
    }
    Readable.prototype.pause = function () {
      debug('call pause flowing=%j', this._readableState.flowing);
      if (this._readableState.flowing !== false) {
        debug('pause');
        this._readableState.flowing = false;
        this.emit('pause');
      }
      this._readableState.paused = true;
      return this;
    };
    function flow(stream) {
      var state = stream._readableState;
      debug('flow', state.flowing);
      while (state.flowing && stream.read() !== null);
    }
    
    // wrap an old-style stream as the async data source.
    // This is *not* part of the readable stream interface.
    // It is an ugly unfortunate mess of history.
    Readable.prototype.wrap = function (stream) {
      var _this = this;
      var state = this._readableState;
      var paused = false;
      stream.on('end', function () {
        debug('wrapped end');
        if (state.decoder && !state.ended) {
          var chunk = state.decoder.end();
          if (chunk && chunk.length) _this.push(chunk);
        }
        _this.push(null);
      });
      stream.on('data', function (chunk) {
        debug('wrapped data');
        if (state.decoder) chunk = state.decoder.write(chunk);
    
        // don't skip over falsy values in objectMode
        if (state.objectMode && (chunk === null || chunk === undefined)) return;else if (!state.objectMode && (!chunk || !chunk.length)) return;
        var ret = _this.push(chunk);
        if (!ret) {
          paused = true;
          stream.pause();
        }
      });
    
      // proxy all the other methods.
      // important when wrapping filters and duplexes.
      for (var i in stream) {
        if (this[i] === undefined && typeof stream[i] === 'function') {
          this[i] = function methodWrap(method) {
            return function methodWrapReturnFunction() {
              return stream[method].apply(stream, arguments);
            };
          }(i);
        }
      }
    
      // proxy certain important events.
      for (var n = 0; n < kProxyEvents.length; n++) {
        stream.on(kProxyEvents[n], this.emit.bind(this, kProxyEvents[n]));
      }
    
      // when we try to consume some more bytes, simply unpause the
      // underlying stream.
      this._read = function (n) {
        debug('wrapped _read', n);
        if (paused) {
          paused = false;
          stream.resume();
        }
      };
      return this;
    };
    if (typeof Symbol === 'function') {
      Readable.prototype[Symbol.asyncIterator] = function () {
        if (createReadableStreamAsyncIterator === undefined) {
          createReadableStreamAsyncIterator = require('./internal/streams/async_iterator');
        }
        return createReadableStreamAsyncIterator(this);
      };
    }
    Object.defineProperty(Readable.prototype, 'readableHighWaterMark', {
      // making it explicit this property is not enumerable
      // because otherwise some prototype manipulation in
      // userland will fail
      enumerable: false,
      get: function get() {
        return this._readableState.highWaterMark;
      }
    });
    Object.defineProperty(Readable.prototype, 'readableBuffer', {
      // making it explicit this property is not enumerable
      // because otherwise some prototype manipulation in
      // userland will fail
      enumerable: false,
      get: function get() {
        return this._readableState && this._readableState.buffer;
      }
    });
    Object.defineProperty(Readable.prototype, 'readableFlowing', {
      // making it explicit this property is not enumerable
      // because otherwise some prototype manipulation in
      // userland will fail
      enumerable: false,
      get: function get() {
        return this._readableState.flowing;
      },
      set: function set(state) {
        if (this._readableState) {
          this._readableState.flowing = state;
        }
      }
    });
    
    // exposed for testing purposes only.
    Readable._fromList = fromList;
    Object.defineProperty(Readable.prototype, 'readableLength', {
      // making it explicit this property is not enumerable
      // because otherwise some prototype manipulation in
      // userland will fail
      enumerable: false,
      get: function get() {
        return this._readableState.length;
      }
    });
    
    // Pluck off n bytes from an array of buffers.
    // Length is the combined lengths of all the buffers in the list.
    // This function is designed to be inlinable, so please take care when making
    // changes to the function body.
    function fromList(n, state) {
      // nothing buffered
      if (state.length === 0) return null;
      var ret;
      if (state.objectMode) ret = state.buffer.shift();else if (!n || n >= state.length) {
        // read it all, truncate the list
        if (state.decoder) ret = state.buffer.join('');else if (state.buffer.length === 1) ret = state.buffer.first();else ret = state.buffer.concat(state.length);
        state.buffer.clear();
      } else {
        // read part of list
        ret = state.buffer.consume(n, state.decoder);
      }
      return ret;
    }
    function endReadable(stream) {
      var state = stream._readableState;
      debug('endReadable', state.endEmitted);
      if (!state.endEmitted) {
        state.ended = true;
        process.nextTick(endReadableNT, state, stream);
      }
    }
    function endReadableNT(state, stream) {
      debug('endReadableNT', state.endEmitted, state.length);
    
      // Check that we didn't get one last unshift.
      if (!state.endEmitted && state.length === 0) {
        state.endEmitted = true;
        stream.readable = false;
        stream.emit('end');
        if (state.autoDestroy) {
          // In case of duplex streams we need a way to detect
          // if the writable side is ready for autoDestroy as well
          var wState = stream._writableState;
          if (!wState || wState.autoDestroy && wState.finished) {
            stream.destroy();
          }
        }
      }
    }
    if (typeof Symbol === 'function') {
      Readable.from = function (iterable, opts) {
        if (from === undefined) {
          from = require('./internal/streams/from');
        }
        return from(Readable, iterable, opts);
      };
    }
    function indexOf(xs, x) {
      for (var i = 0, l = xs.length; i < l; i++) {
        if (xs[i] === x) return i;
      }
      return -1;
    }
    }).call(this)}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
    },{"../errors":52,"./_stream_duplex":53,"./internal/streams/async_iterator":58,"./internal/streams/buffer_list":59,"./internal/streams/destroy":60,"./internal/streams/from":62,"./internal/streams/state":64,"./internal/streams/stream":65,"_process":176,"buffer":68,"events":107,"inherits":149,"string_decoder/":212,"util":24}],56:[function(require,module,exports){
    // Copyright Joyent, Inc. and other Node contributors.
    //
    // Permission is hereby granted, free of charge, to any person obtaining a
    // copy of this software and associated documentation files (the
    // "Software"), to deal in the Software without restriction, including
    // without limitation the rights to use, copy, modify, merge, publish,
    // distribute, sublicense, and/or sell copies of the Software, and to permit
    // persons to whom the Software is furnished to do so, subject to the
    // following conditions:
    //
    // The above copyright notice and this permission notice shall be included
    // in all copies or substantial portions of the Software.
    //
    // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
    // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
    // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
    // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
    // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
    // USE OR OTHER DEALINGS IN THE SOFTWARE.
    
    // a transform stream is a readable/writable stream where you do
    // something with the data.  Sometimes it's called a "filter",
    // but that's not a great name for it, since that implies a thing where
    // some bits pass through, and others are simply ignored.  (That would
    // be a valid example of a transform, of course.)
    //
    // While the output is causally related to the input, it's not a
    // necessarily symmetric or synchronous transformation.  For example,
    // a zlib stream might take multiple plain-text writes(), and then
    // emit a single compressed chunk some time in the future.
    //
    // Here's how this works:
    //
    // The Transform stream has all the aspects of the readable and writable
    // stream classes.  When you write(chunk), that calls _write(chunk,cb)
    // internally, and returns false if there's a lot of pending writes
    // buffered up.  When you call read(), that calls _read(n) until
    // there's enough pending readable data buffered up.
    //
    // In a transform stream, the written data is placed in a buffer.  When
    // _read(n) is called, it transforms the queued up data, calling the
    // buffered _write cb's as it consumes chunks.  If consuming a single
    // written chunk would result in multiple output chunks, then the first
    // outputted bit calls the readcb, and subsequent chunks just go into
    // the read buffer, and will cause it to emit 'readable' if necessary.
    //
    // This way, back-pressure is actually determined by the reading side,
    // since _read has to be called to start processing a new chunk.  However,
    // a pathological inflate type of transform can cause excessive buffering
    // here.  For example, imagine a stream where every byte of input is
    // interpreted as an integer from 0-255, and then results in that many
    // bytes of output.  Writing the 4 bytes {ff,ff,ff,ff} would result in
    // 1kb of data being output.  In this case, you could write a very small
    // amount of input, and end up with a very large amount of output.  In
    // such a pathological inflating mechanism, there'd be no way to tell
    // the system to stop doing the transform.  A single 4MB write could
    // cause the system to run out of memory.
    //
    // However, even in such a pathological case, only a single written chunk
    // would be consumed, and then the rest would wait (un-transformed) until
    // the results of the previous transformed chunk were consumed.
    
    'use strict';
    
    module.exports = Transform;
    var _require$codes = require('../errors').codes,
      ERR_METHOD_NOT_IMPLEMENTED = _require$codes.ERR_METHOD_NOT_IMPLEMENTED,
      ERR_MULTIPLE_CALLBACK = _require$codes.ERR_MULTIPLE_CALLBACK,
      ERR_TRANSFORM_ALREADY_TRANSFORMING = _require$codes.ERR_TRANSFORM_ALREADY_TRANSFORMING,
      ERR_TRANSFORM_WITH_LENGTH_0 = _require$codes.ERR_TRANSFORM_WITH_LENGTH_0;
    var Duplex = require('./_stream_duplex');
    require('inherits')(Transform, Duplex);
    function afterTransform(er, data) {
      var ts = this._transformState;
      ts.transforming = false;
      var cb = ts.writecb;
      if (cb === null) {
        return this.emit('error', new ERR_MULTIPLE_CALLBACK());
      }
      ts.writechunk = null;
      ts.writecb = null;
      if (data != null)
        // single equals check for both `null` and `undefined`
        this.push(data);
      cb(er);
      var rs = this._readableState;
      rs.reading = false;
      if (rs.needReadable || rs.length < rs.highWaterMark) {
        this._read(rs.highWaterMark);
      }
    }
    function Transform(options) {
      if (!(this instanceof Transform)) return new Transform(options);
      Duplex.call(this, options);
      this._transformState = {
        afterTransform: afterTransform.bind(this),
        needTransform: false,
        transforming: false,
        writecb: null,
        writechunk: null,
        writeencoding: null
      };
    
      // start out asking for a readable event once data is transformed.
      this._readableState.needReadable = true;
    
      // we have implemented the _read method, and done the other things
      // that Readable wants before the first _read call, so unset the
      // sync guard flag.
      this._readableState.sync = false;
      if (options) {
        if (typeof options.transform === 'function') this._transform = options.transform;
        if (typeof options.flush === 'function') this._flush = options.flush;
      }
    
      // When the writable side finishes, then flush out anything remaining.
      this.on('prefinish', prefinish);
    }
    function prefinish() {
      var _this = this;
      if (typeof this._flush === 'function' && !this._readableState.destroyed) {
        this._flush(function (er, data) {
          done(_this, er, data);
        });
      } else {
        done(this, null, null);
      }
    }
    Transform.prototype.push = function (chunk, encoding) {
      this._transformState.needTransform = false;
      return Duplex.prototype.push.call(this, chunk, encoding);
    };
    
    // This is the part where you do stuff!
    // override this function in implementation classes.
    // 'chunk' is an input chunk.
    //
    // Call `push(newChunk)` to pass along transformed output
    // to the readable side.  You may call 'push' zero or more times.
    //
    // Call `cb(err)` when you are done with this chunk.  If you pass
    // an error, then that'll put the hurt on the whole operation.  If you
    // never call cb(), then you'll never get another chunk.
    Transform.prototype._transform = function (chunk, encoding, cb) {
      cb(new ERR_METHOD_NOT_IMPLEMENTED('_transform()'));
    };
    Transform.prototype._write = function (chunk, encoding, cb) {
      var ts = this._transformState;
      ts.writecb = cb;
      ts.writechunk = chunk;
      ts.writeencoding = encoding;
      if (!ts.transforming) {
        var rs = this._readableState;
        if (ts.needTransform || rs.needReadable || rs.length < rs.highWaterMark) this._read(rs.highWaterMark);
      }
    };
    
    // Doesn't matter what the args are here.
    // _transform does all the work.
    // That we got here means that the readable side wants more data.
    Transform.prototype._read = function (n) {
      var ts = this._transformState;
      if (ts.writechunk !== null && !ts.transforming) {
        ts.transforming = true;
        this._transform(ts.writechunk, ts.writeencoding, ts.afterTransform);
      } else {
        // mark that we need a transform, so that any data that comes in
        // will get processed, now that we've asked for it.
        ts.needTransform = true;
      }
    };
    Transform.prototype._destroy = function (err, cb) {
      Duplex.prototype._destroy.call(this, err, function (err2) {
        cb(err2);
      });
    };
    function done(stream, er, data) {
      if (er) return stream.emit('error', er);
      if (data != null)
        // single equals check for both `null` and `undefined`
        stream.push(data);
    
      // TODO(BridgeAR): Write a test for these two error cases
      // if there's nothing in the write buffer, then that means
      // that nothing more will ever be provided
      if (stream._writableState.length) throw new ERR_TRANSFORM_WITH_LENGTH_0();
      if (stream._transformState.transforming) throw new ERR_TRANSFORM_ALREADY_TRANSFORMING();
      return stream.push(null);
    }
    },{"../errors":52,"./_stream_duplex":53,"inherits":149}],57:[function(require,module,exports){
    (function (process,global){(function (){
    // Copyright Joyent, Inc. and other Node contributors.
    //
    // Permission is hereby granted, free of charge, to any person obtaining a
    // copy of this software and associated documentation files (the
    // "Software"), to deal in the Software without restriction, including
    // without limitation the rights to use, copy, modify, merge, publish,
    // distribute, sublicense, and/or sell copies of the Software, and to permit
    // persons to whom the Software is furnished to do so, subject to the
    // following conditions:
    //
    // The above copyright notice and this permission notice shall be included
    // in all copies or substantial portions of the Software.
    //
    // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
    // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
    // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
    // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
    // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
    // USE OR OTHER DEALINGS IN THE SOFTWARE.
    
    // A bit simpler than readable streams.
    // Implement an async ._write(chunk, encoding, cb), and it'll handle all
    // the drain event emission and buffering.
    
    'use strict';
    
    module.exports = Writable;
    
    /* <replacement> */
    function WriteReq(chunk, encoding, cb) {
      this.chunk = chunk;
      this.encoding = encoding;
      this.callback = cb;
      this.next = null;
    }
    
    // It seems a linked list but it is not
    // there will be only 2 of these for each stream
    function CorkedRequest(state) {
      var _this = this;
      this.next = null;
      this.entry = null;
      this.finish = function () {
        onCorkedFinish(_this, state);
      };
    }
    /* </replacement> */
    
    /*<replacement>*/
    var Duplex;
    /*</replacement>*/
    
    Writable.WritableState = WritableState;
    
    /*<replacement>*/
    var internalUtil = {
      deprecate: require('util-deprecate')
    };
    /*</replacement>*/
    
    /*<replacement>*/
    var Stream = require('./internal/streams/stream');
    /*</replacement>*/
    
    var Buffer = require('buffer').Buffer;
    var OurUint8Array = (typeof global !== 'undefined' ? global : typeof window !== 'undefined' ? window : typeof self !== 'undefined' ? self : {}).Uint8Array || function () {};
    function _uint8ArrayToBuffer(chunk) {
      return Buffer.from(chunk);
    }
    function _isUint8Array(obj) {
      return Buffer.isBuffer(obj) || obj instanceof OurUint8Array;
    }
    var destroyImpl = require('./internal/streams/destroy');
    var _require = require('./internal/streams/state'),
      getHighWaterMark = _require.getHighWaterMark;
    var _require$codes = require('../errors').codes,
      ERR_INVALID_ARG_TYPE = _require$codes.ERR_INVALID_ARG_TYPE,
      ERR_METHOD_NOT_IMPLEMENTED = _require$codes.ERR_METHOD_NOT_IMPLEMENTED,
      ERR_MULTIPLE_CALLBACK = _require$codes.ERR_MULTIPLE_CALLBACK,
      ERR_STREAM_CANNOT_PIPE = _require$codes.ERR_STREAM_CANNOT_PIPE,
      ERR_STREAM_DESTROYED = _require$codes.ERR_STREAM_DESTROYED,
      ERR_STREAM_NULL_VALUES = _require$codes.ERR_STREAM_NULL_VALUES,
      ERR_STREAM_WRITE_AFTER_END = _require$codes.ERR_STREAM_WRITE_AFTER_END,
      ERR_UNKNOWN_ENCODING = _require$codes.ERR_UNKNOWN_ENCODING;
    var errorOrDestroy = destroyImpl.errorOrDestroy;
    require('inherits')(Writable, Stream);
    function nop() {}
    function WritableState(options, stream, isDuplex) {
      Duplex = Duplex || require('./_stream_duplex');
      options = options || {};
    
      // Duplex streams are both readable and writable, but share
      // the same options object.
      // However, some cases require setting options to different
      // values for the readable and the writable sides of the duplex stream,
      // e.g. options.readableObjectMode vs. options.writableObjectMode, etc.
      if (typeof isDuplex !== 'boolean') isDuplex = stream instanceof Duplex;
    
      // object stream flag to indicate whether or not this stream
      // contains buffers or objects.
      this.objectMode = !!options.objectMode;
      if (isDuplex) this.objectMode = this.objectMode || !!options.writableObjectMode;
    
      // the point at which write() starts returning false
      // Note: 0 is a valid value, means that we always return false if
      // the entire buffer is not flushed immediately on write()
      this.highWaterMark = getHighWaterMark(this, options, 'writableHighWaterMark', isDuplex);
    
      // if _final has been called
      this.finalCalled = false;
    
      // drain event flag.
      this.needDrain = false;
      // at the start of calling end()
      this.ending = false;
      // when end() has been called, and returned
      this.ended = false;
      // when 'finish' is emitted
      this.finished = false;
    
      // has it been destroyed
      this.destroyed = false;
    
      // should we decode strings into buffers before passing to _write?
      // this is here so that some node-core streams can optimize string
      // handling at a lower level.
      var noDecode = options.decodeStrings === false;
      this.decodeStrings = !noDecode;
    
      // Crypto is kind of old and crusty.  Historically, its default string
      // encoding is 'binary' so we have to make this configurable.
      // Everything else in the universe uses 'utf8', though.
      this.defaultEncoding = options.defaultEncoding || 'utf8';
    
      // not an actual buffer we keep track of, but a measurement
      // of how much we're waiting to get pushed to some underlying
      // socket or file.
      this.length = 0;
    
      // a flag to see when we're in the middle of a write.
      this.writing = false;
    
      // when true all writes will be buffered until .uncork() call
      this.corked = 0;
    
      // a flag to be able to tell if the onwrite cb is called immediately,
      // or on a later tick.  We set this to true at first, because any
      // actions that shouldn't happen until "later" should generally also
      // not happen before the first write call.
      this.sync = true;
    
      // a flag to know if we're processing previously buffered items, which
      // may call the _write() callback in the same tick, so that we don't
      // end up in an overlapped onwrite situation.
      this.bufferProcessing = false;
    
      // the callback that's passed to _write(chunk,cb)
      this.onwrite = function (er) {
        onwrite(stream, er);
      };
    
      // the callback that the user supplies to write(chunk,encoding,cb)
      this.writecb = null;
    
      // the amount that is being written when _write is called.
      this.writelen = 0;
      this.bufferedRequest = null;
      this.lastBufferedRequest = null;
    
      // number of pending user-supplied write callbacks
      // this must be 0 before 'finish' can be emitted
      this.pendingcb = 0;
    
      // emit prefinish if the only thing we're waiting for is _write cbs
      // This is relevant for synchronous Transform streams
      this.prefinished = false;
    
      // True if the error was already emitted and should not be thrown again
      this.errorEmitted = false;
    
      // Should close be emitted on destroy. Defaults to true.
      this.emitClose = options.emitClose !== false;
    
      // Should .destroy() be called after 'finish' (and potentially 'end')
      this.autoDestroy = !!options.autoDestroy;
    
      // count buffered requests
      this.bufferedRequestCount = 0;
    
      // allocate the first CorkedRequest, there is always
      // one allocated and free to use, and we maintain at most two
      this.corkedRequestsFree = new CorkedRequest(this);
    }
    WritableState.prototype.getBuffer = function getBuffer() {
      var current = this.bufferedRequest;
      var out = [];
      while (current) {
        out.push(current);
        current = current.next;
      }
      return out;
    };
    (function () {
      try {
        Object.defineProperty(WritableState.prototype, 'buffer', {
          get: internalUtil.deprecate(function writableStateBufferGetter() {
            return this.getBuffer();
          }, '_writableState.buffer is deprecated. Use _writableState.getBuffer ' + 'instead.', 'DEP0003')
        });
      } catch (_) {}
    })();
    
    // Test _writableState for inheritance to account for Duplex streams,
    // whose prototype chain only points to Readable.
    var realHasInstance;
    if (typeof Symbol === 'function' && Symbol.hasInstance && typeof Function.prototype[Symbol.hasInstance] === 'function') {
      realHasInstance = Function.prototype[Symbol.hasInstance];
      Object.defineProperty(Writable, Symbol.hasInstance, {
        value: function value(object) {
          if (realHasInstance.call(this, object)) return true;
          if (this !== Writable) return false;
          return object && object._writableState instanceof WritableState;
        }
      });
    } else {
      realHasInstance = function realHasInstance(object) {
        return object instanceof this;
      };
    }
    function Writable(options) {
      Duplex = Duplex || require('./_stream_duplex');
    
      // Writable ctor is applied to Duplexes, too.
      // `realHasInstance` is necessary because using plain `instanceof`
      // would return false, as no `_writableState` property is attached.
    
      // Trying to use the custom `instanceof` for Writable here will also break the
      // Node.js LazyTransform implementation, which has a non-trivial getter for
      // `_writableState` that would lead to infinite recursion.
    
      // Checking for a Stream.Duplex instance is faster here instead of inside
      // the WritableState constructor, at least with V8 6.5
      var isDuplex = this instanceof Duplex;
      if (!isDuplex && !realHasInstance.call(Writable, this)) return new Writable(options);
      this._writableState = new WritableState(options, this, isDuplex);
    
      // legacy.
      this.writable = true;
      if (options) {
        if (typeof options.write === 'function') this._write = options.write;
        if (typeof options.writev === 'function') this._writev = options.writev;
        if (typeof options.destroy === 'function') this._destroy = options.destroy;
        if (typeof options.final === 'function') this._final = options.final;
      }
      Stream.call(this);
    }
    
    // Otherwise people can pipe Writable streams, which is just wrong.
    Writable.prototype.pipe = function () {
      errorOrDestroy(this, new ERR_STREAM_CANNOT_PIPE());
    };
    function writeAfterEnd(stream, cb) {
      var er = new ERR_STREAM_WRITE_AFTER_END();
      // TODO: defer error events consistently everywhere, not just the cb
      errorOrDestroy(stream, er);
      process.nextTick(cb, er);
    }
    
    // Checks that a user-supplied chunk is valid, especially for the particular
    // mode the stream is in. Currently this means that `null` is never accepted
    // and undefined/non-string values are only allowed in object mode.
    function validChunk(stream, state, chunk, cb) {
      var er;
      if (chunk === null) {
        er = new ERR_STREAM_NULL_VALUES();
      } else if (typeof chunk !== 'string' && !state.objectMode) {
        er = new ERR_INVALID_ARG_TYPE('chunk', ['string', 'Buffer'], chunk);
      }
      if (er) {
        errorOrDestroy(stream, er);
        process.nextTick(cb, er);
        return false;
      }
      return true;
    }
    Writable.prototype.write = function (chunk, encoding, cb) {
      var state = this._writableState;
      var ret = false;
      var isBuf = !state.objectMode && _isUint8Array(chunk);
      if (isBuf && !Buffer.isBuffer(chunk)) {
        chunk = _uint8ArrayToBuffer(chunk);
      }
      if (typeof encoding === 'function') {
        cb = encoding;
        encoding = null;
      }
      if (isBuf) encoding = 'buffer';else if (!encoding) encoding = state.defaultEncoding;
      if (typeof cb !== 'function') cb = nop;
      if (state.ending) writeAfterEnd(this, cb);else if (isBuf || validChunk(this, state, chunk, cb)) {
        state.pendingcb++;
        ret = writeOrBuffer(this, state, isBuf, chunk, encoding, cb);
      }
      return ret;
    };
    Writable.prototype.cork = function () {
      this._writableState.corked++;
    };
    Writable.prototype.uncork = function () {
      var state = this._writableState;
      if (state.corked) {
        state.corked--;
        if (!state.writing && !state.corked && !state.bufferProcessing && state.bufferedRequest) clearBuffer(this, state);
      }
    };
    Writable.prototype.setDefaultEncoding = function setDefaultEncoding(encoding) {
      // node::ParseEncoding() requires lower case.
      if (typeof encoding === 'string') encoding = encoding.toLowerCase();
      if (!(['hex', 'utf8', 'utf-8', 'ascii', 'binary', 'base64', 'ucs2', 'ucs-2', 'utf16le', 'utf-16le', 'raw'].indexOf((encoding + '').toLowerCase()) > -1)) throw new ERR_UNKNOWN_ENCODING(encoding);
      this._writableState.defaultEncoding = encoding;
      return this;
    };
    Object.defineProperty(Writable.prototype, 'writableBuffer', {
      // making it explicit this property is not enumerable
      // because otherwise some prototype manipulation in
      // userland will fail
      enumerable: false,
      get: function get() {
        return this._writableState && this._writableState.getBuffer();
      }
    });
    function decodeChunk(state, chunk, encoding) {
      if (!state.objectMode && state.decodeStrings !== false && typeof chunk === 'string') {
        chunk = Buffer.from(chunk, encoding);
      }
      return chunk;
    }
    Object.defineProperty(Writable.prototype, 'writableHighWaterMark', {
      // making it explicit this property is not enumerable
      // because otherwise some prototype manipulation in
      // userland will fail
      enumerable: false,
      get: function get() {
        return this._writableState.highWaterMark;
      }
    });
    
    // if we're already writing something, then just put this
    // in the queue, and wait our turn.  Otherwise, call _write
    // If we return false, then we need a drain event, so set that flag.
    function writeOrBuffer(stream, state, isBuf, chunk, encoding, cb) {
      if (!isBuf) {
        var newChunk = decodeChunk(state, chunk, encoding);
        if (chunk !== newChunk) {
          isBuf = true;
          encoding = 'buffer';
          chunk = newChunk;
        }
      }
      var len = state.objectMode ? 1 : chunk.length;
      state.length += len;
      var ret = state.length < state.highWaterMark;
      // we must ensure that previous needDrain will not be reset to false.
      if (!ret) state.needDrain = true;
      if (state.writing || state.corked) {
        var last = state.lastBufferedRequest;
        state.lastBufferedRequest = {
          chunk: chunk,
          encoding: encoding,
          isBuf: isBuf,
          callback: cb,
          next: null
        };
        if (last) {
          last.next = state.lastBufferedRequest;
        } else {
          state.bufferedRequest = state.lastBufferedRequest;
        }
        state.bufferedRequestCount += 1;
      } else {
        doWrite(stream, state, false, len, chunk, encoding, cb);
      }
      return ret;
    }
    function doWrite(stream, state, writev, len, chunk, encoding, cb) {
      state.writelen = len;
      state.writecb = cb;
      state.writing = true;
      state.sync = true;
      if (state.destroyed) state.onwrite(new ERR_STREAM_DESTROYED('write'));else if (writev) stream._writev(chunk, state.onwrite);else stream._write(chunk, encoding, state.onwrite);
      state.sync = false;
    }
    function onwriteError(stream, state, sync, er, cb) {
      --state.pendingcb;
      if (sync) {
        // defer the callback if we are being called synchronously
        // to avoid piling up things on the stack
        process.nextTick(cb, er);
        // this can emit finish, and it will always happen
        // after error
        process.nextTick(finishMaybe, stream, state);
        stream._writableState.errorEmitted = true;
        errorOrDestroy(stream, er);
      } else {
        // the caller expect this to happen before if
        // it is async
        cb(er);
        stream._writableState.errorEmitted = true;
        errorOrDestroy(stream, er);
        // this can emit finish, but finish must
        // always follow error
        finishMaybe(stream, state);
      }
    }
    function onwriteStateUpdate(state) {
      state.writing = false;
      state.writecb = null;
      state.length -= state.writelen;
      state.writelen = 0;
    }
    function onwrite(stream, er) {
      var state = stream._writableState;
      var sync = state.sync;
      var cb = state.writecb;
      if (typeof cb !== 'function') throw new ERR_MULTIPLE_CALLBACK();
      onwriteStateUpdate(state);
      if (er) onwriteError(stream, state, sync, er, cb);else {
        // Check if we're actually ready to finish, but don't emit yet
        var finished = needFinish(state) || stream.destroyed;
        if (!finished && !state.corked && !state.bufferProcessing && state.bufferedRequest) {
          clearBuffer(stream, state);
        }
        if (sync) {
          process.nextTick(afterWrite, stream, state, finished, cb);
        } else {
          afterWrite(stream, state, finished, cb);
        }
      }
    }
    function afterWrite(stream, state, finished, cb) {
      if (!finished) onwriteDrain(stream, state);
      state.pendingcb--;
      cb();
      finishMaybe(stream, state);
    }
    
    // Must force callback to be called on nextTick, so that we don't
    // emit 'drain' before the write() consumer gets the 'false' return
    // value, and has a chance to attach a 'drain' listener.
    function onwriteDrain(stream, state) {
      if (state.length === 0 && state.needDrain) {
        state.needDrain = false;
        stream.emit('drain');
      }
    }
    
    // if there's something in the buffer waiting, then process it
    function clearBuffer(stream, state) {
      state.bufferProcessing = true;
      var entry = state.bufferedRequest;
      if (stream._writev && entry && entry.next) {
        // Fast case, write everything using _writev()
        var l = state.bufferedRequestCount;
        var buffer = new Array(l);
        var holder = state.corkedRequestsFree;
        holder.entry = entry;
        var count = 0;
        var allBuffers = true;
        while (entry) {
          buffer[count] = entry;
          if (!entry.isBuf) allBuffers = false;
          entry = entry.next;
          count += 1;
        }
        buffer.allBuffers = allBuffers;
        doWrite(stream, state, true, state.length, buffer, '', holder.finish);
    
        // doWrite is almost always async, defer these to save a bit of time
        // as the hot path ends with doWrite
        state.pendingcb++;
        state.lastBufferedRequest = null;
        if (holder.next) {
          state.corkedRequestsFree = holder.next;
          holder.next = null;
        } else {
          state.corkedRequestsFree = new CorkedRequest(state);
        }
        state.bufferedRequestCount = 0;
      } else {
        // Slow case, write chunks one-by-one
        while (entry) {
          var chunk = entry.chunk;
          var encoding = entry.encoding;
          var cb = entry.callback;
          var len = state.objectMode ? 1 : chunk.length;
          doWrite(stream, state, false, len, chunk, encoding, cb);
          entry = entry.next;
          state.bufferedRequestCount--;
          // if we didn't call the onwrite immediately, then
          // it means that we need to wait until it does.
          // also, that means that the chunk and cb are currently
          // being processed, so move the buffer counter past them.
          if (state.writing) {
            break;
          }
        }
        if (entry === null) state.lastBufferedRequest = null;
      }
      state.bufferedRequest = entry;
      state.bufferProcessing = false;
    }
    Writable.prototype._write = function (chunk, encoding, cb) {
      cb(new ERR_METHOD_NOT_IMPLEMENTED('_write()'));
    };
    Writable.prototype._writev = null;
    Writable.prototype.end = function (chunk, encoding, cb) {
      var state = this._writableState;
      if (typeof chunk === 'function') {
        cb = chunk;
        chunk = null;
        encoding = null;
      } else if (typeof encoding === 'function') {
        cb = encoding;
        encoding = null;
      }
      if (chunk !== null && chunk !== undefined) this.write(chunk, encoding);
    
      // .end() fully uncorks
      if (state.corked) {
        state.corked = 1;
        this.uncork();
      }
    
      // ignore unnecessary end() calls.
      if (!state.ending) endWritable(this, state, cb);
      return this;
    };
    Object.defineProperty(Writable.prototype, 'writableLength', {
      // making it explicit this property is not enumerable
      // because otherwise some prototype manipulation in
      // userland will fail
      enumerable: false,
      get: function get() {
        return this._writableState.length;
      }
    });
    function needFinish(state) {
      return state.ending && state.length === 0 && state.bufferedRequest === null && !state.finished && !state.writing;
    }
    function callFinal(stream, state) {
      stream._final(function (err) {
        state.pendingcb--;
        if (err) {
          errorOrDestroy(stream, err);
        }
        state.prefinished = true;
        stream.emit('prefinish');
        finishMaybe(stream, state);
      });
    }
    function prefinish(stream, state) {
      if (!state.prefinished && !state.finalCalled) {
        if (typeof stream._final === 'function' && !state.destroyed) {
          state.pendingcb++;
          state.finalCalled = true;
          process.nextTick(callFinal, stream, state);
        } else {
          state.prefinished = true;
          stream.emit('prefinish');
        }
      }
    }
    function finishMaybe(stream, state) {
      var need = needFinish(state);
      if (need) {
        prefinish(stream, state);
        if (state.pendingcb === 0) {
          state.finished = true;
          stream.emit('finish');
          if (state.autoDestroy) {
            // In case of duplex streams we need a way to detect
            // if the readable side is ready for autoDestroy as well
            var rState = stream._readableState;
            if (!rState || rState.autoDestroy && rState.endEmitted) {
              stream.destroy();
            }
          }
        }
      }
      return need;
    }
    function endWritable(stream, state, cb) {
      state.ending = true;
      finishMaybe(stream, state);
      if (cb) {
        if (state.finished) process.nextTick(cb);else stream.once('finish', cb);
      }
      state.ended = true;
      stream.writable = false;
    }
    function onCorkedFinish(corkReq, state, err) {
      var entry = corkReq.entry;
      corkReq.entry = null;
      while (entry) {
        var cb = entry.callback;
        state.pendingcb--;
        cb(err);
        entry = entry.next;
      }
    
      // reuse the free corkReq.
      state.corkedRequestsFree.next = corkReq;
    }
    Object.defineProperty(Writable.prototype, 'destroyed', {
      // making it explicit this property is not enumerable
      // because otherwise some prototype manipulation in
      // userland will fail
      enumerable: false,
      get: function get() {
        if (this._writableState === undefined) {
          return false;
        }
        return this._writableState.destroyed;
      },
      set: function set(value) {
        // we ignore the value if the stream
        // has not been initialized yet
        if (!this._writableState) {
          return;
        }
    
        // backward compatibility, the user is explicitly
        // managing destroyed
        this._writableState.destroyed = value;
      }
    });
    Writable.prototype.destroy = destroyImpl.destroy;
    Writable.prototype._undestroy = destroyImpl.undestroy;
    Writable.prototype._destroy = function (err, cb) {
      cb(err);
    };
    }).call(this)}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
    },{"../errors":52,"./_stream_duplex":53,"./internal/streams/destroy":60,"./internal/streams/state":64,"./internal/streams/stream":65,"_process":176,"buffer":68,"inherits":149,"util-deprecate":213}],58:[function(require,module,exports){
    (function (process){(function (){
    'use strict';
    
    var _Object$setPrototypeO;
    function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
    function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
    function _toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
    var finished = require('./end-of-stream');
    var kLastResolve = Symbol('lastResolve');
    var kLastReject = Symbol('lastReject');
    var kError = Symbol('error');
    var kEnded = Symbol('ended');
    var kLastPromise = Symbol('lastPromise');
    var kHandlePromise = Symbol('handlePromise');
    var kStream = Symbol('stream');
    function createIterResult(value, done) {
      return {
        value: value,
        done: done
      };
    }
    function readAndResolve(iter) {
      var resolve = iter[kLastResolve];
      if (resolve !== null) {
        var data = iter[kStream].read();
        // we defer if data is null
        // we can be expecting either 'end' or
        // 'error'
        if (data !== null) {
          iter[kLastPromise] = null;
          iter[kLastResolve] = null;
          iter[kLastReject] = null;
          resolve(createIterResult(data, false));
        }
      }
    }
    function onReadable(iter) {
      // we wait for the next tick, because it might
      // emit an error with process.nextTick
      process.nextTick(readAndResolve, iter);
    }
    function wrapForNext(lastPromise, iter) {
      return function (resolve, reject) {
        lastPromise.then(function () {
          if (iter[kEnded]) {
            resolve(createIterResult(undefined, true));
            return;
          }
          iter[kHandlePromise](resolve, reject);
        }, reject);
      };
    }
    var AsyncIteratorPrototype = Object.getPrototypeOf(function () {});
    var ReadableStreamAsyncIteratorPrototype = Object.setPrototypeOf((_Object$setPrototypeO = {
      get stream() {
        return this[kStream];
      },
      next: function next() {
        var _this = this;
        // if we have detected an error in the meanwhile
        // reject straight away
        var error = this[kError];
        if (error !== null) {
          return Promise.reject(error);
        }
        if (this[kEnded]) {
          return Promise.resolve(createIterResult(undefined, true));
        }
        if (this[kStream].destroyed) {
          // We need to defer via nextTick because if .destroy(err) is
          // called, the error will be emitted via nextTick, and
          // we cannot guarantee that there is no error lingering around
          // waiting to be emitted.
          return new Promise(function (resolve, reject) {
            process.nextTick(function () {
              if (_this[kError]) {
                reject(_this[kError]);
              } else {
                resolve(createIterResult(undefined, true));
              }
            });
          });
        }
    
        // if we have multiple next() calls
        // we will wait for the previous Promise to finish
        // this logic is optimized to support for await loops,
        // where next() is only called once at a time
        var lastPromise = this[kLastPromise];
        var promise;
        if (lastPromise) {
          promise = new Promise(wrapForNext(lastPromise, this));
        } else {
          // fast path needed to support multiple this.push()
          // without triggering the next() queue
          var data = this[kStream].read();
          if (data !== null) {
            return Promise.resolve(createIterResult(data, false));
          }
          promise = new Promise(this[kHandlePromise]);
        }
        this[kLastPromise] = promise;
        return promise;
      }
    }, _defineProperty(_Object$setPrototypeO, Symbol.asyncIterator, function () {
      return this;
    }), _defineProperty(_Object$setPrototypeO, "return", function _return() {
      var _this2 = this;
      // destroy(err, cb) is a private API
      // we can guarantee we have that here, because we control the
      // Readable class this is attached to
      return new Promise(function (resolve, reject) {
        _this2[kStream].destroy(null, function (err) {
          if (err) {
            reject(err);
            return;
          }
          resolve(createIterResult(undefined, true));
        });
      });
    }), _Object$setPrototypeO), AsyncIteratorPrototype);
    var createReadableStreamAsyncIterator = function createReadableStreamAsyncIterator(stream) {
      var _Object$create;
      var iterator = Object.create(ReadableStreamAsyncIteratorPrototype, (_Object$create = {}, _defineProperty(_Object$create, kStream, {
        value: stream,
        writable: true
      }), _defineProperty(_Object$create, kLastResolve, {
        value: null,
        writable: true
      }), _defineProperty(_Object$create, kLastReject, {
        value: null,
        writable: true
      }), _defineProperty(_Object$create, kError, {
        value: null,
        writable: true
      }), _defineProperty(_Object$create, kEnded, {
        value: stream._readableState.endEmitted,
        writable: true
      }), _defineProperty(_Object$create, kHandlePromise, {
        value: function value(resolve, reject) {
          var data = iterator[kStream].read();
          if (data) {
            iterator[kLastPromise] = null;
            iterator[kLastResolve] = null;
            iterator[kLastReject] = null;
            resolve(createIterResult(data, false));
          } else {
            iterator[kLastResolve] = resolve;
            iterator[kLastReject] = reject;
          }
        },
        writable: true
      }), _Object$create));
      iterator[kLastPromise] = null;
      finished(stream, function (err) {
        if (err && err.code !== 'ERR_STREAM_PREMATURE_CLOSE') {
          var reject = iterator[kLastReject];
          // reject if we are waiting for data in the Promise
          // returned by next() and store the error
          if (reject !== null) {
            iterator[kLastPromise] = null;
            iterator[kLastResolve] = null;
            iterator[kLastReject] = null;
            reject(err);
          }
          iterator[kError] = err;
          return;
        }
        var resolve = iterator[kLastResolve];
        if (resolve !== null) {
          iterator[kLastPromise] = null;
          iterator[kLastResolve] = null;
          iterator[kLastReject] = null;
          resolve(createIterResult(undefined, true));
        }
        iterator[kEnded] = true;
      });
      stream.on('readable', onReadable.bind(null, iterator));
      return iterator;
    };
    module.exports = createReadableStreamAsyncIterator;
    }).call(this)}).call(this,require('_process'))
    },{"./end-of-stream":61,"_process":176}],59:[function(require,module,exports){
    'use strict';
    
    function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
    function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
    function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
    function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
    function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } }
    function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
    function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
    function _toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
    var _require = require('buffer'),
      Buffer = _require.Buffer;
    var _require2 = require('util'),
      inspect = _require2.inspect;
    var custom = inspect && inspect.custom || 'inspect';
    function copyBuffer(src, target, offset) {
      Buffer.prototype.copy.call(src, target, offset);
    }
    module.exports = /*#__PURE__*/function () {
      function BufferList() {
        _classCallCheck(this, BufferList);
        this.head = null;
        this.tail = null;
        this.length = 0;
      }
      _createClass(BufferList, [{
        key: "push",
        value: function push(v) {
          var entry = {
            data: v,
            next: null
          };
          if (this.length > 0) this.tail.next = entry;else this.head = entry;
          this.tail = entry;
          ++this.length;
        }
      }, {
        key: "unshift",
        value: function unshift(v) {
          var entry = {
            data: v,
            next: this.head
          };
          if (this.length === 0) this.tail = entry;
          this.head = entry;
          ++this.length;
        }
      }, {
        key: "shift",
        value: function shift() {
          if (this.length === 0) return;
          var ret = this.head.data;
          if (this.length === 1) this.head = this.tail = null;else this.head = this.head.next;
          --this.length;
          return ret;
        }
      }, {
        key: "clear",
        value: function clear() {
          this.head = this.tail = null;
          this.length = 0;
        }
      }, {
        key: "join",
        value: function join(s) {
          if (this.length === 0) return '';
          var p = this.head;
          var ret = '' + p.data;
          while (p = p.next) ret += s + p.data;
          return ret;
        }
      }, {
        key: "concat",
        value: function concat(n) {
          if (this.length === 0) return Buffer.alloc(0);
          var ret = Buffer.allocUnsafe(n >>> 0);
          var p = this.head;
          var i = 0;
          while (p) {
            copyBuffer(p.data, ret, i);
            i += p.data.length;
            p = p.next;
          }
          return ret;
        }
    
        // Consumes a specified amount of bytes or characters from the buffered data.
      }, {
        key: "consume",
        value: function consume(n, hasStrings) {
          var ret;
          if (n < this.head.data.length) {
            // `slice` is the same for buffers and strings.
            ret = this.head.data.slice(0, n);
            this.head.data = this.head.data.slice(n);
          } else if (n === this.head.data.length) {
            // First chunk is a perfect match.
            ret = this.shift();
          } else {
            // Result spans more than one buffer.
            ret = hasStrings ? this._getString(n) : this._getBuffer(n);
          }
          return ret;
        }
      }, {
        key: "first",
        value: function first() {
          return this.head.data;
        }
    
        // Consumes a specified amount of characters from the buffered data.
      }, {
        key: "_getString",
        value: function _getString(n) {
          var p = this.head;
          var c = 1;
          var ret = p.data;
          n -= ret.length;
          while (p = p.next) {
            var str = p.data;
            var nb = n > str.length ? str.length : n;
            if (nb === str.length) ret += str;else ret += str.slice(0, n);
            n -= nb;
            if (n === 0) {
              if (nb === str.length) {
                ++c;
                if (p.next) this.head = p.next;else this.head = this.tail = null;
              } else {
                this.head = p;
                p.data = str.slice(nb);
              }
              break;
            }
            ++c;
          }
          this.length -= c;
          return ret;
        }
    
        // Consumes a specified amount of bytes from the buffered data.
      }, {
        key: "_getBuffer",
        value: function _getBuffer(n) {
          var ret = Buffer.allocUnsafe(n);
          var p = this.head;
          var c = 1;
          p.data.copy(ret);
          n -= p.data.length;
          while (p = p.next) {
            var buf = p.data;
            var nb = n > buf.length ? buf.length : n;
            buf.copy(ret, ret.length - n, 0, nb);
            n -= nb;
            if (n === 0) {
              if (nb === buf.length) {
                ++c;
                if (p.next) this.head = p.next;else this.head = this.tail = null;
              } else {
                this.head = p;
                p.data = buf.slice(nb);
              }
              break;
            }
            ++c;
          }
          this.length -= c;
          return ret;
        }
    
        // Make sure the linked list only shows the minimal necessary information.
      }, {
        key: custom,
        value: function value(_, options) {
          return inspect(this, _objectSpread(_objectSpread({}, options), {}, {
            // Only inspect one level.
            depth: 0,
            // It should not recurse.
            customInspect: false
          }));
        }
      }]);
      return BufferList;
    }();
    },{"buffer":68,"util":24}],60:[function(require,module,exports){
    (function (process){(function (){
    'use strict';
    
    // undocumented cb() API, needed for core, not for public API
    function destroy(err, cb) {
      var _this = this;
      var readableDestroyed = this._readableState && this._readableState.destroyed;
      var writableDestroyed = this._writableState && this._writableState.destroyed;
      if (readableDestroyed || writableDestroyed) {
        if (cb) {
          cb(err);
        } else if (err) {
          if (!this._writableState) {
            process.nextTick(emitErrorNT, this, err);
          } else if (!this._writableState.errorEmitted) {
            this._writableState.errorEmitted = true;
            process.nextTick(emitErrorNT, this, err);
          }
        }
        return this;
      }
    
      // we set destroyed to true before firing error callbacks in order
      // to make it re-entrance safe in case destroy() is called within callbacks
    
      if (this._readableState) {
        this._readableState.destroyed = true;
      }
    
      // if this is a duplex stream mark the writable part as destroyed as well
      if (this._writableState) {
        this._writableState.destroyed = true;
      }
      this._destroy(err || null, function (err) {
        if (!cb && err) {
          if (!_this._writableState) {
            process.nextTick(emitErrorAndCloseNT, _this, err);
          } else if (!_this._writableState.errorEmitted) {
            _this._writableState.errorEmitted = true;
            process.nextTick(emitErrorAndCloseNT, _this, err);
          } else {
            process.nextTick(emitCloseNT, _this);
          }
        } else if (cb) {
          process.nextTick(emitCloseNT, _this);
          cb(err);
        } else {
          process.nextTick(emitCloseNT, _this);
        }
      });
      return this;
    }
    function emitErrorAndCloseNT(self, err) {
      emitErrorNT(self, err);
      emitCloseNT(self);
    }
    function emitCloseNT(self) {
      if (self._writableState && !self._writableState.emitClose) return;
      if (self._readableState && !self._readableState.emitClose) return;
      self.emit('close');
    }
    function undestroy() {
      if (this._readableState) {
        this._readableState.destroyed = false;
        this._readableState.reading = false;
        this._readableState.ended = false;
        this._readableState.endEmitted = false;
      }
      if (this._writableState) {
        this._writableState.destroyed = false;
        this._writableState.ended = false;
        this._writableState.ending = false;
        this._writableState.finalCalled = false;
        this._writableState.prefinished = false;
        this._writableState.finished = false;
        this._writableState.errorEmitted = false;
      }
    }
    function emitErrorNT(self, err) {
      self.emit('error', err);
    }
    function errorOrDestroy(stream, err) {
      // We have tests that rely on errors being emitted
      // in the same tick, so changing this is semver major.
      // For now when you opt-in to autoDestroy we allow
      // the error to be emitted nextTick. In a future
      // semver major update we should change the default to this.
    
      var rState = stream._readableState;
      var wState = stream._writableState;
      if (rState && rState.autoDestroy || wState && wState.autoDestroy) stream.destroy(err);else stream.emit('error', err);
    }
    module.exports = {
      destroy: destroy,
      undestroy: undestroy,
      errorOrDestroy: errorOrDestroy
    };
    }).call(this)}).call(this,require('_process'))
    },{"_process":176}],61:[function(require,module,exports){
    // Ported from https://github.com/mafintosh/end-of-stream with
    // permission from the author, Mathias Buus (@mafintosh).
    
    'use strict';
    
    var ERR_STREAM_PREMATURE_CLOSE = require('../../../errors').codes.ERR_STREAM_PREMATURE_CLOSE;
    function once(callback) {
      var called = false;
      return function () {
        if (called) return;
        called = true;
        for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
          args[_key] = arguments[_key];
        }
        callback.apply(this, args);
      };
    }
    function noop() {}
    function isRequest(stream) {
      return stream.setHeader && typeof stream.abort === 'function';
    }
    function eos(stream, opts, callback) {
      if (typeof opts === 'function') return eos(stream, null, opts);
      if (!opts) opts = {};
      callback = once(callback || noop);
      var readable = opts.readable || opts.readable !== false && stream.readable;
      var writable = opts.writable || opts.writable !== false && stream.writable;
      var onlegacyfinish = function onlegacyfinish() {
        if (!stream.writable) onfinish();
      };
      var writableEnded = stream._writableState && stream._writableState.finished;
      var onfinish = function onfinish() {
        writable = false;
        writableEnded = true;
        if (!readable) callback.call(stream);
      };
      var readableEnded = stream._readableState && stream._readableState.endEmitted;
      var onend = function onend() {
        readable = false;
        readableEnded = true;
        if (!writable) callback.call(stream);
      };
      var onerror = function onerror(err) {
        callback.call(stream, err);
      };
      var onclose = function onclose() {
        var err;
        if (readable && !readableEnded) {
          if (!stream._readableState || !stream._readableState.ended) err = new ERR_STREAM_PREMATURE_CLOSE();
          return callback.call(stream, err);
        }
        if (writable && !writableEnded) {
          if (!stream._writableState || !stream._writableState.ended) err = new ERR_STREAM_PREMATURE_CLOSE();
          return callback.call(stream, err);
        }
      };
      var onrequest = function onrequest() {
        stream.req.on('finish', onfinish);
      };
      if (isRequest(stream)) {
        stream.on('complete', onfinish);
        stream.on('abort', onclose);
        if (stream.req) onrequest();else stream.on('request', onrequest);
      } else if (writable && !stream._writableState) {
        // legacy streams
        stream.on('end', onlegacyfinish);
        stream.on('close', onlegacyfinish);
      }
      stream.on('end', onend);
      stream.on('finish', onfinish);
      if (opts.error !== false) stream.on('error', onerror);
      stream.on('close', onclose);
      return function () {
        stream.removeListener('complete', onfinish);
        stream.removeListener('abort', onclose);
        stream.removeListener('request', onrequest);
        if (stream.req) stream.req.removeListener('finish', onfinish);
        stream.removeListener('end', onlegacyfinish);
        stream.removeListener('close', onlegacyfinish);
        stream.removeListener('finish', onfinish);
        stream.removeListener('end', onend);
        stream.removeListener('error', onerror);
        stream.removeListener('close', onclose);
      };
    }
    module.exports = eos;
    },{"../../../errors":52}],62:[function(require,module,exports){
    module.exports = function () {
      throw new Error('Readable.from is not available in the browser')
    };
    
    },{}],63:[function(require,module,exports){
    // Ported from https://github.com/mafintosh/pump with
    // permission from the author, Mathias Buus (@mafintosh).
    
    'use strict';
    
    var eos;
    function once(callback) {
      var called = false;
      return function () {
        if (called) return;
        called = true;
        callback.apply(void 0, arguments);
      };
    }
    var _require$codes = require('../../../errors').codes,
      ERR_MISSING_ARGS = _require$codes.ERR_MISSING_ARGS,
      ERR_STREAM_DESTROYED = _require$codes.ERR_STREAM_DESTROYED;
    function noop(err) {
      // Rethrow the error if it exists to avoid swallowing it
      if (err) throw err;
    }
    function isRequest(stream) {
      return stream.setHeader && typeof stream.abort === 'function';
    }
    function destroyer(stream, reading, writing, callback) {
      callback = once(callback);
      var closed = false;
      stream.on('close', function () {
        closed = true;
      });
      if (eos === undefined) eos = require('./end-of-stream');
      eos(stream, {
        readable: reading,
        writable: writing
      }, function (err) {
        if (err) return callback(err);
        closed = true;
        callback();
      });
      var destroyed = false;
      return function (err) {
        if (closed) return;
        if (destroyed) return;
        destroyed = true;
    
        // request.destroy just do .end - .abort is what we want
        if (isRequest(stream)) return stream.abort();
        if (typeof stream.destroy === 'function') return stream.destroy();
        callback(err || new ERR_STREAM_DESTROYED('pipe'));
      };
    }
    function call(fn) {
      fn();
    }
    function pipe(from, to) {
      return from.pipe(to);
    }
    function popCallback(streams) {
      if (!streams.length) return noop;
      if (typeof streams[streams.length - 1] !== 'function') return noop;
      return streams.pop();
    }
    function pipeline() {
      for (var _len = arguments.length, streams = new Array(_len), _key = 0; _key < _len; _key++) {
        streams[_key] = arguments[_key];
      }
      var callback = popCallback(streams);
      if (Array.isArray(streams[0])) streams = streams[0];
      if (streams.length < 2) {
        throw new ERR_MISSING_ARGS('streams');
      }
      var error;
      var destroys = streams.map(function (stream, i) {
        var reading = i < streams.length - 1;
        var writing = i > 0;
        return destroyer(stream, reading, writing, function (err) {
          if (!error) error = err;
          if (err) destroys.forEach(call);
          if (reading) return;
          destroys.forEach(call);
          callback(error);
        });
      });
      return streams.reduce(pipe);
    }
    module.exports = pipeline;
    },{"../../../errors":52,"./end-of-stream":61}],64:[function(require,module,exports){
    'use strict';
    
    var ERR_INVALID_OPT_VALUE = require('../../../errors').codes.ERR_INVALID_OPT_VALUE;
    function highWaterMarkFrom(options, isDuplex, duplexKey) {
      return options.highWaterMark != null ? options.highWaterMark : isDuplex ? options[duplexKey] : null;
    }
    function getHighWaterMark(state, options, duplexKey, isDuplex) {
      var hwm = highWaterMarkFrom(options, isDuplex, duplexKey);
      if (hwm != null) {
        if (!(isFinite(hwm) && Math.floor(hwm) === hwm) || hwm < 0) {
          var name = isDuplex ? duplexKey : 'highWaterMark';
          throw new ERR_INVALID_OPT_VALUE(name, hwm);
        }
        return Math.floor(hwm);
      }
    
      // Default value
      return state.objectMode ? 16 : 16 * 1024;
    }
    module.exports = {
      getHighWaterMark: getHighWaterMark
    };
    },{"../../../errors":52}],65:[function(require,module,exports){
    module.exports = require('events').EventEmitter;
    
    },{"events":107}],66:[function(require,module,exports){
    exports = module.exports = require('./lib/_stream_readable.js');
    exports.Stream = exports;
    exports.Readable = exports;
    exports.Writable = require('./lib/_stream_writable.js');
    exports.Duplex = require('./lib/_stream_duplex.js');
    exports.Transform = require('./lib/_stream_transform.js');
    exports.PassThrough = require('./lib/_stream_passthrough.js');
    exports.finished = require('./lib/internal/streams/end-of-stream.js');
    exports.pipeline = require('./lib/internal/streams/pipeline.js');
    
    },{"./lib/_stream_duplex.js":53,"./lib/_stream_passthrough.js":54,"./lib/_stream_readable.js":55,"./lib/_stream_transform.js":56,"./lib/_stream_writable.js":57,"./lib/internal/streams/end-of-stream.js":61,"./lib/internal/streams/pipeline.js":63}],67:[function(require,module,exports){
    (function (Buffer){(function (){
    module.exports = function xor (a, b) {
      var length = Math.min(a.length, b.length)
      var buffer = new Buffer(length)
    
      for (var i = 0; i < length; ++i) {
        buffer[i] = a[i] ^ b[i]
      }
    
      return buffer
    }
    
    }).call(this)}).call(this,require("buffer").Buffer)
    },{"buffer":68}],68:[function(require,module,exports){
    (function (Buffer){(function (){
    /*!
     * The buffer module from node.js, for the browser.
     *
     * @author   Feross Aboukhadijeh <https://feross.org>
     * @license  MIT
     */
    /* eslint-disable no-proto */
    
    'use strict'
    
    var base64 = require('base64-js')
    var ieee754 = require('ieee754')
    
    exports.Buffer = Buffer
    exports.SlowBuffer = SlowBuffer
    exports.INSPECT_MAX_BYTES = 50
    
    var K_MAX_LENGTH = 0x7fffffff
    exports.kMaxLength = K_MAX_LENGTH
    
    /**
     * If `Buffer.TYPED_ARRAY_SUPPORT`:
     *   === true    Use Uint8Array implementation (fastest)
     *   === false   Print warning and recommend using `buffer` v4.x which has an Object
     *               implementation (most compatible, even IE6)
     *
     * Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+,
     * Opera 11.6+, iOS 4.2+.
     *
     * We report that the browser does not support typed arrays if the are not subclassable
     * using __proto__. Firefox 4-29 lacks support for adding new properties to `Uint8Array`
     * (See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438). IE 10 lacks support
     * for __proto__ and has a buggy typed array implementation.
     */
    Buffer.TYPED_ARRAY_SUPPORT = typedArraySupport()
    
    if (!Buffer.TYPED_ARRAY_SUPPORT && typeof console !== 'undefined' &&
        typeof console.error === 'function') {
      console.error(
        'This browser lacks typed array (Uint8Array) support which is required by ' +
        '`buffer` v5.x. Use `buffer` v4.x if you require old browser support.'
      )
    }
    
    function typedArraySupport () {
      // Can typed array instances can be augmented?
      try {
        var arr = new Uint8Array(1)
        arr.__proto__ = { __proto__: Uint8Array.prototype, foo: function () { return 42 } }
        return arr.foo() === 42
      } catch (e) {
        return false
      }
    }
    
    Object.defineProperty(Buffer.prototype, 'parent', {
      enumerable: true,
      get: function () {
        if (!Buffer.isBuffer(this)) return undefined
        return this.buffer
      }
    })
    
    Object.defineProperty(Buffer.prototype, 'offset', {
      enumerable: true,
      get: function () {
        if (!Buffer.isBuffer(this)) return undefined
        return this.byteOffset
      }
    })
    
    function createBuffer (length) {
      if (length > K_MAX_LENGTH) {
        throw new RangeError('The value "' + length + '" is invalid for option "size"')
      }
      // Return an augmented `Uint8Array` instance
      var buf = new Uint8Array(length)
      buf.__proto__ = Buffer.prototype
      return buf
    }
    
    /**
     * The Buffer constructor returns instances of `Uint8Array` that have their
     * prototype changed to `Buffer.prototype`. Furthermore, `Buffer` is a subclass of
     * `Uint8Array`, so the returned instances will have all the node `Buffer` methods
     * and the `Uint8Array` methods. Square bracket notation works as expected -- it
     * returns a single octet.
     *
     * The `Uint8Array` prototype remains unmodified.
     */
    
    function Buffer (arg, encodingOrOffset, length) {
      // Common case.
      if (typeof arg === 'number') {
        if (typeof encodingOrOffset === 'string') {
          throw new TypeError(
            'The "string" argument must be of type string. Received type number'
          )
        }
        return allocUnsafe(arg)
      }
      return from(arg, encodingOrOffset, length)
    }
    
    // Fix subarray() in ES2016. See: https://github.com/feross/buffer/pull/97
    if (typeof Symbol !== 'undefined' && Symbol.species != null &&
        Buffer[Symbol.species] === Buffer) {
      Object.defineProperty(Buffer, Symbol.species, {
        value: null,
        configurable: true,
        enumerable: false,
        writable: false
      })
    }
    
    Buffer.poolSize = 8192 // not used by this implementation
    
    function from (value, encodingOrOffset, length) {
      if (typeof value === 'string') {
        return fromString(value, encodingOrOffset)
      }
    
      if (ArrayBuffer.isView(value)) {
        return fromArrayLike(value)
      }
    
      if (value == null) {
        throw TypeError(
          'The first argument must be one of type string, Buffer, ArrayBuffer, Array, ' +
          'or Array-like Object. Received type ' + (typeof value)
        )
      }
    
      if (isInstance(value, ArrayBuffer) ||
          (value && isInstance(value.buffer, ArrayBuffer))) {
        return fromArrayBuffer(value, encodingOrOffset, length)
      }
    
      if (typeof value === 'number') {
        throw new TypeError(
          'The "value" argument must not be of type number. Received type number'
        )
      }
    
      var valueOf = value.valueOf && value.valueOf()
      if (valueOf != null && valueOf !== value) {
        return Buffer.from(valueOf, encodingOrOffset, length)
      }
    
      var b = fromObject(value)
      if (b) return b
    
      if (typeof Symbol !== 'undefined' && Symbol.toPrimitive != null &&
          typeof value[Symbol.toPrimitive] === 'function') {
        return Buffer.from(
          value[Symbol.toPrimitive]('string'), encodingOrOffset, length
        )
      }
    
      throw new TypeError(
        'The first argument must be one of type string, Buffer, ArrayBuffer, Array, ' +
        'or Array-like Object. Received type ' + (typeof value)
      )
    }
    
    /**
     * Functionally equivalent to Buffer(arg, encoding) but throws a TypeError
     * if value is a number.
     * Buffer.from(str[, encoding])
     * Buffer.from(array)
     * Buffer.from(buffer)
     * Buffer.from(arrayBuffer[, byteOffset[, length]])
     **/
    Buffer.from = function (value, encodingOrOffset, length) {
      return from(value, encodingOrOffset, length)
    }
    
    // Note: Change prototype *after* Buffer.from is defined to workaround Chrome bug:
    // https://github.com/feross/buffer/pull/148
    Buffer.prototype.__proto__ = Uint8Array.prototype
    Buffer.__proto__ = Uint8Array
    
    function assertSize (size) {
      if (typeof size !== 'number') {
        throw new TypeError('"size" argument must be of type number')
      } else if (size < 0) {
        throw new RangeError('The value "' + size + '" is invalid for option "size"')
      }
    }
    
    function alloc (size, fill, encoding) {
      assertSize(size)
      if (size <= 0) {
        return createBuffer(size)
      }
      if (fill !== undefined) {
        // Only pay attention to encoding if it's a string. This
        // prevents accidentally sending in a number that would
        // be interpretted as a start offset.
        return typeof encoding === 'string'
          ? createBuffer(size).fill(fill, encoding)
          : createBuffer(size).fill(fill)
      }
      return createBuffer(size)
    }
    
    /**
     * Creates a new filled Buffer instance.
     * alloc(size[, fill[, encoding]])
     **/
    Buffer.alloc = function (size, fill, encoding) {
      return alloc(size, fill, encoding)
    }
    
    function allocUnsafe (size) {
      assertSize(size)
      return createBuffer(size < 0 ? 0 : checked(size) | 0)
    }
    
    /**
     * Equivalent to Buffer(num), by default creates a non-zero-filled Buffer instance.
     * */
    Buffer.allocUnsafe = function (size) {
      return allocUnsafe(size)
    }
    /**
     * Equivalent to SlowBuffer(num), by default creates a non-zero-filled Buffer instance.
     */
    Buffer.allocUnsafeSlow = function (size) {
      return allocUnsafe(size)
    }
    
    function fromString (string, encoding) {
      if (typeof encoding !== 'string' || encoding === '') {
        encoding = 'utf8'
      }
    
      if (!Buffer.isEncoding(encoding)) {
        throw new TypeError('Unknown encoding: ' + encoding)
      }
    
      var length = byteLength(string, encoding) | 0
      var buf = createBuffer(length)
    
      var actual = buf.write(string, encoding)
    
      if (actual !== length) {
        // Writing a hex string, for example, that contains invalid characters will
        // cause everything after the first invalid character to be ignored. (e.g.
        // 'abxxcd' will be treated as 'ab')
        buf = buf.slice(0, actual)
      }
    
      return buf
    }
    
    function fromArrayLike (array) {
      var length = array.length < 0 ? 0 : checked(array.length) | 0
      var buf = createBuffer(length)
      for (var i = 0; i < length; i += 1) {
        buf[i] = array[i] & 255
      }
      return buf
    }
    
    function fromArrayBuffer (array, byteOffset, length) {
      if (byteOffset < 0 || array.byteLength < byteOffset) {
        throw new RangeError('"offset" is outside of buffer bounds')
      }
    
      if (array.byteLength < byteOffset + (length || 0)) {
        throw new RangeError('"length" is outside of buffer bounds')
      }
    
      var buf
      if (byteOffset === undefined && length === undefined) {
        buf = new Uint8Array(array)
      } else if (length === undefined) {
        buf = new Uint8Array(array, byteOffset)
      } else {
        buf = new Uint8Array(array, byteOffset, length)
      }
    
      // Return an augmented `Uint8Array` instance
      buf.__proto__ = Buffer.prototype
      return buf
    }
    
    function fromObject (obj) {
      if (Buffer.isBuffer(obj)) {
        var len = checked(obj.length) | 0
        var buf = createBuffer(len)
    
        if (buf.length === 0) {
          return buf
        }
    
        obj.copy(buf, 0, 0, len)
        return buf
      }
    
      if (obj.length !== undefined) {
        if (typeof obj.length !== 'number' || numberIsNaN(obj.length)) {
          return createBuffer(0)
        }
        return fromArrayLike(obj)
      }
    
      if (obj.type === 'Buffer' && Array.isArray(obj.data)) {
        return fromArrayLike(obj.data)
      }
    }
    
    function checked (length) {
      // Note: cannot use `length < K_MAX_LENGTH` here because that fails when
      // length is NaN (which is otherwise coerced to zero.)
      if (length >= K_MAX_LENGTH) {
        throw new RangeError('Attempt to allocate Buffer larger than maximum ' +
                             'size: 0x' + K_MAX_LENGTH.toString(16) + ' bytes')
      }
      return length | 0
    }
    
    function SlowBuffer (length) {
      if (+length != length) { // eslint-disable-line eqeqeq
        length = 0
      }
      return Buffer.alloc(+length)
    }
    
    Buffer.isBuffer = function isBuffer (b) {
      return b != null && b._isBuffer === true &&
        b !== Buffer.prototype // so Buffer.isBuffer(Buffer.prototype) will be false
    }
    
    Buffer.compare = function compare (a, b) {
      if (isInstance(a, Uint8Array)) a = Buffer.from(a, a.offset, a.byteLength)
      if (isInstance(b, Uint8Array)) b = Buffer.from(b, b.offset, b.byteLength)
      if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) {
        throw new TypeError(
          'The "buf1", "buf2" arguments must be one of type Buffer or Uint8Array'
        )
      }
    
      if (a === b) return 0
    
      var x = a.length
      var y = b.length
    
      for (var i = 0, len = Math.min(x, y); i < len; ++i) {
        if (a[i] !== b[i]) {
          x = a[i]
          y = b[i]
          break
        }
      }
    
      if (x < y) return -1
      if (y < x) return 1
      return 0
    }
    
    Buffer.isEncoding = function isEncoding (encoding) {
      switch (String(encoding).toLowerCase()) {
        case 'hex':
        case 'utf8':
        case 'utf-8':
        case 'ascii':
        case 'latin1':
        case 'binary':
        case 'base64':
        case 'ucs2':
        case 'ucs-2':
        case 'utf16le':
        case 'utf-16le':
          return true
        default:
          return false
      }
    }
    
    Buffer.concat = function concat (list, length) {
      if (!Array.isArray(list)) {
        throw new TypeError('"list" argument must be an Array of Buffers')
      }
    
      if (list.length === 0) {
        return Buffer.alloc(0)
      }
    
      var i
      if (length === undefined) {
        length = 0
        for (i = 0; i < list.length; ++i) {
          length += list[i].length
        }
      }
    
      var buffer = Buffer.allocUnsafe(length)
      var pos = 0
      for (i = 0; i < list.length; ++i) {
        var buf = list[i]
        if (isInstance(buf, Uint8Array)) {
          buf = Buffer.from(buf)
        }
        if (!Buffer.isBuffer(buf)) {
          throw new TypeError('"list" argument must be an Array of Buffers')
        }
        buf.copy(buffer, pos)
        pos += buf.length
      }
      return buffer
    }
    
    function byteLength (string, encoding) {
      if (Buffer.isBuffer(string)) {
        return string.length
      }
      if (ArrayBuffer.isView(string) || isInstance(string, ArrayBuffer)) {
        return string.byteLength
      }
      if (typeof string !== 'string') {
        throw new TypeError(
          'The "string" argument must be one of type string, Buffer, or ArrayBuffer. ' +
          'Received type ' + typeof string
        )
      }
    
      var len = string.length
      var mustMatch = (arguments.length > 2 && arguments[2] === true)
      if (!mustMatch && len === 0) return 0
    
      // Use a for loop to avoid recursion
      var loweredCase = false
      for (;;) {
        switch (encoding) {
          case 'ascii':
          case 'latin1':
          case 'binary':
            return len
          case 'utf8':
          case 'utf-8':
            return utf8ToBytes(string).length
          case 'ucs2':
          case 'ucs-2':
          case 'utf16le':
          case 'utf-16le':
            return len * 2
          case 'hex':
            return len >>> 1
          case 'base64':
            return base64ToBytes(string).length
          default:
            if (loweredCase) {
              return mustMatch ? -1 : utf8ToBytes(string).length // assume utf8
            }
            encoding = ('' + encoding).toLowerCase()
            loweredCase = true
        }
      }
    }
    Buffer.byteLength = byteLength
    
    function slowToString (encoding, start, end) {
      var loweredCase = false
    
      // No need to verify that "this.length <= MAX_UINT32" since it's a read-only
      // property of a typed array.
    
      // This behaves neither like String nor Uint8Array in that we set start/end
      // to their upper/lower bounds if the value passed is out of range.
      // undefined is handled specially as per ECMA-262 6th Edition,
      // Section 13.3.3.7 Runtime Semantics: KeyedBindingInitialization.
      if (start === undefined || start < 0) {
        start = 0
      }
      // Return early if start > this.length. Done here to prevent potential uint32
      // coercion fail below.
      if (start > this.length) {
        return ''
      }
    
      if (end === undefined || end > this.length) {
        end = this.length
      }
    
      if (end <= 0) {
        return ''
      }
    
      // Force coersion to uint32. This will also coerce falsey/NaN values to 0.
      end >>>= 0
      start >>>= 0
    
      if (end <= start) {
        return ''
      }
    
      if (!encoding) encoding = 'utf8'
    
      while (true) {
        switch (encoding) {
          case 'hex':
            return hexSlice(this, start, end)
    
          case 'utf8':
          case 'utf-8':
            return utf8Slice(this, start, end)
    
          case 'ascii':
            return asciiSlice(this, start, end)
    
          case 'latin1':
          case 'binary':
            return latin1Slice(this, start, end)
    
          case 'base64':
            return base64Slice(this, start, end)
    
          case 'ucs2':
          case 'ucs-2':
          case 'utf16le':
          case 'utf-16le':
            return utf16leSlice(this, start, end)
    
          default:
            if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)
            encoding = (encoding + '').toLowerCase()
            loweredCase = true
        }
      }
    }
    
    // This property is used by `Buffer.isBuffer` (and the `is-buffer` npm package)
    // to detect a Buffer instance. It's not possible to use `instanceof Buffer`
    // reliably in a browserify context because there could be multiple different
    // copies of the 'buffer' package in use. This method works even for Buffer
    // instances that were created from another copy of the `buffer` package.
    // See: https://github.com/feross/buffer/issues/154
    Buffer.prototype._isBuffer = true
    
    function swap (b, n, m) {
      var i = b[n]
      b[n] = b[m]
      b[m] = i
    }
    
    Buffer.prototype.swap16 = function swap16 () {
      var len = this.length
      if (len % 2 !== 0) {
        throw new RangeError('Buffer size must be a multiple of 16-bits')
      }
      for (var i = 0; i < len; i += 2) {
        swap(this, i, i + 1)
      }
      return this
    }
    
    Buffer.prototype.swap32 = function swap32 () {
      var len = this.length
      if (len % 4 !== 0) {
        throw new RangeError('Buffer size must be a multiple of 32-bits')
      }
      for (var i = 0; i < len; i += 4) {
        swap(this, i, i + 3)
        swap(this, i + 1, i + 2)
      }
      return this
    }
    
    Buffer.prototype.swap64 = function swap64 () {
      var len = this.length
      if (len % 8 !== 0) {
        throw new RangeError('Buffer size must be a multiple of 64-bits')
      }
      for (var i = 0; i < len; i += 8) {
        swap(this, i, i + 7)
        swap(this, i + 1, i + 6)
        swap(this, i + 2, i + 5)
        swap(this, i + 3, i + 4)
      }
      return this
    }
    
    Buffer.prototype.toString = function toString () {
      var length = this.length
      if (length === 0) return ''
      if (arguments.length === 0) return utf8Slice(this, 0, length)
      return slowToString.apply(this, arguments)
    }
    
    Buffer.prototype.toLocaleString = Buffer.prototype.toString
    
    Buffer.prototype.equals = function equals (b) {
      if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer')
      if (this === b) return true
      return Buffer.compare(this, b) === 0
    }
    
    Buffer.prototype.inspect = function inspect () {
      var str = ''
      var max = exports.INSPECT_MAX_BYTES
      str = this.toString('hex', 0, max).replace(/(.{2})/g, '$1 ').trim()
      if (this.length > max) str += ' ... '
      return '<Buffer ' + str + '>'
    }
    
    Buffer.prototype.compare = function compare (target, start, end, thisStart, thisEnd) {
      if (isInstance(target, Uint8Array)) {
        target = Buffer.from(target, target.offset, target.byteLength)
      }
      if (!Buffer.isBuffer(target)) {
        throw new TypeError(
          'The "target" argument must be one of type Buffer or Uint8Array. ' +
          'Received type ' + (typeof target)
        )
      }
    
      if (start === undefined) {
        start = 0
      }
      if (end === undefined) {
        end = target ? target.length : 0
      }
      if (thisStart === undefined) {
        thisStart = 0
      }
      if (thisEnd === undefined) {
        thisEnd = this.length
      }
    
      if (start < 0 || end > target.length || thisStart < 0 || thisEnd > this.length) {
        throw new RangeError('out of range index')
      }
    
      if (thisStart >= thisEnd && start >= end) {
        return 0
      }
      if (thisStart >= thisEnd) {
        return -1
      }
      if (start >= end) {
        return 1
      }
    
      start >>>= 0
      end >>>= 0
      thisStart >>>= 0
      thisEnd >>>= 0
    
      if (this === target) return 0
    
      var x = thisEnd - thisStart
      var y = end - start
      var len = Math.min(x, y)
    
      var thisCopy = this.slice(thisStart, thisEnd)
      var targetCopy = target.slice(start, end)
    
      for (var i = 0; i < len; ++i) {
        if (thisCopy[i] !== targetCopy[i]) {
          x = thisCopy[i]
          y = targetCopy[i]
          break
        }
      }
    
      if (x < y) return -1
      if (y < x) return 1
      return 0
    }
    
    // Finds either the first index of `val` in `buffer` at offset >= `byteOffset`,
    // OR the last index of `val` in `buffer` at offset <= `byteOffset`.
    //
    // Arguments:
    // - buffer - a Buffer to search
    // - val - a string, Buffer, or number
    // - byteOffset - an index into `buffer`; will be clamped to an int32
    // - encoding - an optional encoding, relevant is val is a string
    // - dir - true for indexOf, false for lastIndexOf
    function bidirectionalIndexOf (buffer, val, byteOffset, encoding, dir) {
      // Empty buffer means no match
      if (buffer.length === 0) return -1
    
      // Normalize byteOffset
      if (typeof byteOffset === 'string') {
        encoding = byteOffset
        byteOffset = 0
      } else if (byteOffset > 0x7fffffff) {
        byteOffset = 0x7fffffff
      } else if (byteOffset < -0x80000000) {
        byteOffset = -0x80000000
      }
      byteOffset = +byteOffset // Coerce to Number.
      if (numberIsNaN(byteOffset)) {
        // byteOffset: it it's undefined, null, NaN, "foo", etc, search whole buffer
        byteOffset = dir ? 0 : (buffer.length - 1)
      }
    
      // Normalize byteOffset: negative offsets start from the end of the buffer
      if (byteOffset < 0) byteOffset = buffer.length + byteOffset
      if (byteOffset >= buffer.length) {
        if (dir) return -1
        else byteOffset = buffer.length - 1
      } else if (byteOffset < 0) {
        if (dir) byteOffset = 0
        else return -1
      }
    
      // Normalize val
      if (typeof val === 'string') {
        val = Buffer.from(val, encoding)
      }
    
      // Finally, search either indexOf (if dir is true) or lastIndexOf
      if (Buffer.isBuffer(val)) {
        // Special case: looking for empty string/buffer always fails
        if (val.length === 0) {
          return -1
        }
        return arrayIndexOf(buffer, val, byteOffset, encoding, dir)
      } else if (typeof val === 'number') {
        val = val & 0xFF // Search for a byte value [0-255]
        if (typeof Uint8Array.prototype.indexOf === 'function') {
          if (dir) {
            return Uint8Array.prototype.indexOf.call(buffer, val, byteOffset)
          } else {
            return Uint8Array.prototype.lastIndexOf.call(buffer, val, byteOffset)
          }
        }
        return arrayIndexOf(buffer, [ val ], byteOffset, encoding, dir)
      }
    
      throw new TypeError('val must be string, number or Buffer')
    }
    
    function arrayIndexOf (arr, val, byteOffset, encoding, dir) {
      var indexSize = 1
      var arrLength = arr.length
      var valLength = val.length
    
      if (encoding !== undefined) {
        encoding = String(encoding).toLowerCase()
        if (encoding === 'ucs2' || encoding === 'ucs-2' ||
            encoding === 'utf16le' || encoding === 'utf-16le') {
          if (arr.length < 2 || val.length < 2) {
            return -1
          }
          indexSize = 2
          arrLength /= 2
          valLength /= 2
          byteOffset /= 2
        }
      }
    
      function read (buf, i) {
        if (indexSize === 1) {
          return buf[i]
        } else {
          return buf.readUInt16BE(i * indexSize)
        }
      }
    
      var i
      if (dir) {
        var foundIndex = -1
        for (i = byteOffset; i < arrLength; i++) {
          if (read(arr, i) === read(val, foundIndex === -1 ? 0 : i - foundIndex)) {
            if (foundIndex === -1) foundIndex = i
            if (i - foundIndex + 1 === valLength) return foundIndex * indexSize
          } else {
            if (foundIndex !== -1) i -= i - foundIndex
            foundIndex = -1
          }
        }
      } else {
        if (byteOffset + valLength > arrLength) byteOffset = arrLength - valLength
        for (i = byteOffset; i >= 0; i--) {
          var found = true
          for (var j = 0; j < valLength; j++) {
            if (read(arr, i + j) !== read(val, j)) {
              found = false
              break
            }
          }
          if (found) return i
        }
      }
    
      return -1
    }
    
    Buffer.prototype.includes = function includes (val, byteOffset, encoding) {
      return this.indexOf(val, byteOffset, encoding) !== -1
    }
    
    Buffer.prototype.indexOf = function indexOf (val, byteOffset, encoding) {
      return bidirectionalIndexOf(this, val, byteOffset, encoding, true)
    }
    
    Buffer.prototype.lastIndexOf = function lastIndexOf (val, byteOffset, encoding) {
      return bidirectionalIndexOf(this, val, byteOffset, encoding, false)
    }
    
    function hexWrite (buf, string, offset, length) {
      offset = Number(offset) || 0
      var remaining = buf.length - offset
      if (!length) {
        length = remaining
      } else {
        length = Number(length)
        if (length > remaining) {
          length = remaining
        }
      }
    
      var strLen = string.length
    
      if (length > strLen / 2) {
        length = strLen / 2
      }
      for (var i = 0; i < length; ++i) {
        var parsed = parseInt(string.substr(i * 2, 2), 16)
        if (numberIsNaN(parsed)) return i
        buf[offset + i] = parsed
      }
      return i
    }
    
    function utf8Write (buf, string, offset, length) {
      return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length)
    }
    
    function asciiWrite (buf, string, offset, length) {
      return blitBuffer(asciiToBytes(string), buf, offset, length)
    }
    
    function latin1Write (buf, string, offset, length) {
      return asciiWrite(buf, string, offset, length)
    }
    
    function base64Write (buf, string, offset, length) {
      return blitBuffer(base64ToBytes(string), buf, offset, length)
    }
    
    function ucs2Write (buf, string, offset, length) {
      return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length)
    }
    
    Buffer.prototype.write = function write (string, offset, length, encoding) {
      // Buffer#write(string)
      if (offset === undefined) {
        encoding = 'utf8'
        length = this.length
        offset = 0
      // Buffer#write(string, encoding)
      } else if (length === undefined && typeof offset === 'string') {
        encoding = offset
        length = this.length
        offset = 0
      // Buffer#write(string, offset[, length][, encoding])
      } else if (isFinite(offset)) {
        offset = offset >>> 0
        if (isFinite(length)) {
          length = length >>> 0
          if (encoding === undefined) encoding = 'utf8'
        } else {
          encoding = length
          length = undefined
        }
      } else {
        throw new Error(
          'Buffer.write(string, encoding, offset[, length]) is no longer supported'
        )
      }
    
      var remaining = this.length - offset
      if (length === undefined || length > remaining) length = remaining
    
      if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) {
        throw new RangeError('Attempt to write outside buffer bounds')
      }
    
      if (!encoding) encoding = 'utf8'
    
      var loweredCase = false
      for (;;) {
        switch (encoding) {
          case 'hex':
            return hexWrite(this, string, offset, length)
    
          case 'utf8':
          case 'utf-8':
            return utf8Write(this, string, offset, length)
    
          case 'ascii':
            return asciiWrite(this, string, offset, length)
    
          case 'latin1':
          case 'binary':
            return latin1Write(this, string, offset, length)
    
          case 'base64':
            // Warning: maxLength not taken into account in base64Write
            return base64Write(this, string, offset, length)
    
          case 'ucs2':
          case 'ucs-2':
          case 'utf16le':
          case 'utf-16le':
            return ucs2Write(this, string, offset, length)
    
          default:
            if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)
            encoding = ('' + encoding).toLowerCase()
            loweredCase = true
        }
      }
    }
    
    Buffer.prototype.toJSON = function toJSON () {
      return {
        type: 'Buffer',
        data: Array.prototype.slice.call(this._arr || this, 0)
      }
    }
    
    function base64Slice (buf, start, end) {
      if (start === 0 && end === buf.length) {
        return base64.fromByteArray(buf)
      } else {
        return base64.fromByteArray(buf.slice(start, end))
      }
    }
    
    function utf8Slice (buf, start, end) {
      end = Math.min(buf.length, end)
      var res = []
    
      var i = start
      while (i < end) {
        var firstByte = buf[i]
        var codePoint = null
        var bytesPerSequence = (firstByte > 0xEF) ? 4
          : (firstByte > 0xDF) ? 3
            : (firstByte > 0xBF) ? 2
              : 1
    
        if (i + bytesPerSequence <= end) {
          var secondByte, thirdByte, fourthByte, tempCodePoint
    
          switch (bytesPerSequence) {
            case 1:
              if (firstByte < 0x80) {
                codePoint = firstByte
              }
              break
            case 2:
              secondByte = buf[i + 1]
              if ((secondByte & 0xC0) === 0x80) {
                tempCodePoint = (firstByte & 0x1F) << 0x6 | (secondByte & 0x3F)
                if (tempCodePoint > 0x7F) {
                  codePoint = tempCodePoint
                }
              }
              break
            case 3:
              secondByte = buf[i + 1]
              thirdByte = buf[i + 2]
              if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) {
                tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | (thirdByte & 0x3F)
                if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) {
                  codePoint = tempCodePoint
                }
              }
              break
            case 4:
              secondByte = buf[i + 1]
              thirdByte = buf[i + 2]
              fourthByte = buf[i + 3]
              if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) {
                tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | (fourthByte & 0x3F)
                if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) {
                  codePoint = tempCodePoint
                }
              }
          }
        }
    
        if (codePoint === null) {
          // we did not generate a valid codePoint so insert a
          // replacement char (U+FFFD) and advance only 1 byte
          codePoint = 0xFFFD
          bytesPerSequence = 1
        } else if (codePoint > 0xFFFF) {
          // encode to utf16 (surrogate pair dance)
          codePoint -= 0x10000
          res.push(codePoint >>> 10 & 0x3FF | 0xD800)
          codePoint = 0xDC00 | codePoint & 0x3FF
        }
    
        res.push(codePoint)
        i += bytesPerSequence
      }
    
      return decodeCodePointsArray(res)
    }
    
    // Based on http://stackoverflow.com/a/22747272/680742, the browser with
    // the lowest limit is Chrome, with 0x10000 args.
    // We go 1 magnitude less, for safety
    var MAX_ARGUMENTS_LENGTH = 0x1000
    
    function decodeCodePointsArray (codePoints) {
      var len = codePoints.length
      if (len <= MAX_ARGUMENTS_LENGTH) {
        return String.fromCharCode.apply(String, codePoints) // avoid extra slice()
      }
    
      // Decode in chunks to avoid "call stack size exceeded".
      var res = ''
      var i = 0
      while (i < len) {
        res += String.fromCharCode.apply(
          String,
          codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH)
        )
      }
      return res
    }
    
    function asciiSlice (buf, start, end) {
      var ret = ''
      end = Math.min(buf.length, end)
    
      for (var i = start; i < end; ++i) {
        ret += String.fromCharCode(buf[i] & 0x7F)
      }
      return ret
    }
    
    function latin1Slice (buf, start, end) {
      var ret = ''
      end = Math.min(buf.length, end)
    
      for (var i = start; i < end; ++i) {
        ret += String.fromCharCode(buf[i])
      }
      return ret
    }
    
    function hexSlice (buf, start, end) {
      var len = buf.length
    
      if (!start || start < 0) start = 0
      if (!end || end < 0 || end > len) end = len
    
      var out = ''
      for (var i = start; i < end; ++i) {
        out += toHex(buf[i])
      }
      return out
    }
    
    function utf16leSlice (buf, start, end) {
      var bytes = buf.slice(start, end)
      var res = ''
      for (var i = 0; i < bytes.length; i += 2) {
        res += String.fromCharCode(bytes[i] + (bytes[i + 1] * 256))
      }
      return res
    }
    
    Buffer.prototype.slice = function slice (start, end) {
      var len = this.length
      start = ~~start
      end = end === undefined ? len : ~~end
    
      if (start < 0) {
        start += len
        if (start < 0) start = 0
      } else if (start > len) {
        start = len
      }
    
      if (end < 0) {
        end += len
        if (end < 0) end = 0
      } else if (end > len) {
        end = len
      }
    
      if (end < start) end = start
    
      var newBuf = this.subarray(start, end)
      // Return an augmented `Uint8Array` instance
      newBuf.__proto__ = Buffer.prototype
      return newBuf
    }
    
    /*
     * Need to make sure that buffer isn't trying to write out of bounds.
     */
    function checkOffset (offset, ext, length) {
      if ((offset % 1) !== 0 || offset < 0) throw new RangeError('offset is not uint')
      if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length')
    }
    
    Buffer.prototype.readUIntLE = function readUIntLE (offset, byteLength, noAssert) {
      offset = offset >>> 0
      byteLength = byteLength >>> 0
      if (!noAssert) checkOffset(offset, byteLength, this.length)
    
      var val = this[offset]
      var mul = 1
      var i = 0
      while (++i < byteLength && (mul *= 0x100)) {
        val += this[offset + i] * mul
      }
    
      return val
    }
    
    Buffer.prototype.readUIntBE = function readUIntBE (offset, byteLength, noAssert) {
      offset = offset >>> 0
      byteLength = byteLength >>> 0
      if (!noAssert) {
        checkOffset(offset, byteLength, this.length)
      }
    
      var val = this[offset + --byteLength]
      var mul = 1
      while (byteLength > 0 && (mul *= 0x100)) {
        val += this[offset + --byteLength] * mul
      }
    
      return val
    }
    
    Buffer.prototype.readUInt8 = function readUInt8 (offset, noAssert) {
      offset = offset >>> 0
      if (!noAssert) checkOffset(offset, 1, this.length)
      return this[offset]
    }
    
    Buffer.prototype.readUInt16LE = function readUInt16LE (offset, noAssert) {
      offset = offset >>> 0
      if (!noAssert) checkOffset(offset, 2, this.length)
      return this[offset] | (this[offset + 1] << 8)
    }
    
    Buffer.prototype.readUInt16BE = function readUInt16BE (offset, noAssert) {
      offset = offset >>> 0
      if (!noAssert) checkOffset(offset, 2, this.length)
      return (this[offset] << 8) | this[offset + 1]
    }
    
    Buffer.prototype.readUInt32LE = function readUInt32LE (offset, noAssert) {
      offset = offset >>> 0
      if (!noAssert) checkOffset(offset, 4, this.length)
    
      return ((this[offset]) |
          (this[offset + 1] << 8) |
          (this[offset + 2] << 16)) +
          (this[offset + 3] * 0x1000000)
    }
    
    Buffer.prototype.readUInt32BE = function readUInt32BE (offset, noAssert) {
      offset = offset >>> 0
      if (!noAssert) checkOffset(offset, 4, this.length)
    
      return (this[offset] * 0x1000000) +
        ((this[offset + 1] << 16) |
        (this[offset + 2] << 8) |
        this[offset + 3])
    }
    
    Buffer.prototype.readIntLE = function readIntLE (offset, byteLength, noAssert) {
      offset = offset >>> 0
      byteLength = byteLength >>> 0
      if (!noAssert) checkOffset(offset, byteLength, this.length)
    
      var val = this[offset]
      var mul = 1
      var i = 0
      while (++i < byteLength && (mul *= 0x100)) {
        val += this[offset + i] * mul
      }
      mul *= 0x80
    
      if (val >= mul) val -= Math.pow(2, 8 * byteLength)
    
      return val
    }
    
    Buffer.prototype.readIntBE = function readIntBE (offset, byteLength, noAssert) {
      offset = offset >>> 0
      byteLength = byteLength >>> 0
      if (!noAssert) checkOffset(offset, byteLength, this.length)
    
      var i = byteLength
      var mul = 1
      var val = this[offset + --i]
      while (i > 0 && (mul *= 0x100)) {
        val += this[offset + --i] * mul
      }
      mul *= 0x80
    
      if (val >= mul) val -= Math.pow(2, 8 * byteLength)
    
      return val
    }
    
    Buffer.prototype.readInt8 = function readInt8 (offset, noAssert) {
      offset = offset >>> 0
      if (!noAssert) checkOffset(offset, 1, this.length)
      if (!(this[offset] & 0x80)) return (this[offset])
      return ((0xff - this[offset] + 1) * -1)
    }
    
    Buffer.prototype.readInt16LE = function readInt16LE (offset, noAssert) {
      offset = offset >>> 0
      if (!noAssert) checkOffset(offset, 2, this.length)
      var val = this[offset] | (this[offset + 1] << 8)
      return (val & 0x8000) ? val | 0xFFFF0000 : val
    }
    
    Buffer.prototype.readInt16BE = function readInt16BE (offset, noAssert) {
      offset = offset >>> 0
      if (!noAssert) checkOffset(offset, 2, this.length)
      var val = this[offset + 1] | (this[offset] << 8)
      return (val & 0x8000) ? val | 0xFFFF0000 : val
    }
    
    Buffer.prototype.readInt32LE = function readInt32LE (offset, noAssert) {
      offset = offset >>> 0
      if (!noAssert) checkOffset(offset, 4, this.length)
    
      return (this[offset]) |
        (this[offset + 1] << 8) |
        (this[offset + 2] << 16) |
        (this[offset + 3] << 24)
    }
    
    Buffer.prototype.readInt32BE = function readInt32BE (offset, noAssert) {
      offset = offset >>> 0
      if (!noAssert) checkOffset(offset, 4, this.length)
    
      return (this[offset] << 24) |
        (this[offset + 1] << 16) |
        (this[offset + 2] << 8) |
        (this[offset + 3])
    }
    
    Buffer.prototype.readFloatLE = function readFloatLE (offset, noAssert) {
      offset = offset >>> 0
      if (!noAssert) checkOffset(offset, 4, this.length)
      return ieee754.read(this, offset, true, 23, 4)
    }
    
    Buffer.prototype.readFloatBE = function readFloatBE (offset, noAssert) {
      offset = offset >>> 0
      if (!noAssert) checkOffset(offset, 4, this.length)
      return ieee754.read(this, offset, false, 23, 4)
    }
    
    Buffer.prototype.readDoubleLE = function readDoubleLE (offset, noAssert) {
      offset = offset >>> 0
      if (!noAssert) checkOffset(offset, 8, this.length)
      return ieee754.read(this, offset, true, 52, 8)
    }
    
    Buffer.prototype.readDoubleBE = function readDoubleBE (offset, noAssert) {
      offset = offset >>> 0
      if (!noAssert) checkOffset(offset, 8, this.length)
      return ieee754.read(this, offset, false, 52, 8)
    }
    
    function checkInt (buf, value, offset, ext, max, min) {
      if (!Buffer.isBuffer(buf)) throw new TypeError('"buffer" argument must be a Buffer instance')
      if (value > max || value < min) throw new RangeError('"value" argument is out of bounds')
      if (offset + ext > buf.length) throw new RangeError('Index out of range')
    }
    
    Buffer.prototype.writeUIntLE = function writeUIntLE (value, offset, byteLength, noAssert) {
      value = +value
      offset = offset >>> 0
      byteLength = byteLength >>> 0
      if (!noAssert) {
        var maxBytes = Math.pow(2, 8 * byteLength) - 1
        checkInt(this, value, offset, byteLength, maxBytes, 0)
      }
    
      var mul = 1
      var i = 0
      this[offset] = value & 0xFF
      while (++i < byteLength && (mul *= 0x100)) {
        this[offset + i] = (value / mul) & 0xFF
      }
    
      return offset + byteLength
    }
    
    Buffer.prototype.writeUIntBE = function writeUIntBE (value, offset, byteLength, noAssert) {
      value = +value
      offset = offset >>> 0
      byteLength = byteLength >>> 0
      if (!noAssert) {
        var maxBytes = Math.pow(2, 8 * byteLength) - 1
        checkInt(this, value, offset, byteLength, maxBytes, 0)
      }
    
      var i = byteLength - 1
      var mul = 1
      this[offset + i] = value & 0xFF
      while (--i >= 0 && (mul *= 0x100)) {
        this[offset + i] = (value / mul) & 0xFF
      }
    
      return offset + byteLength
    }
    
    Buffer.prototype.writeUInt8 = function writeUInt8 (value, offset, noAssert) {
      value = +value
      offset = offset >>> 0
      if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0)
      this[offset] = (value & 0xff)
      return offset + 1
    }
    
    Buffer.prototype.writeUInt16LE = function writeUInt16LE (value, offset, noAssert) {
      value = +value
      offset = offset >>> 0
      if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)
      this[offset] = (value & 0xff)
      this[offset + 1] = (value >>> 8)
      return offset + 2
    }
    
    Buffer.prototype.writeUInt16BE = function writeUInt16BE (value, offset, noAssert) {
      value = +value
      offset = offset >>> 0
      if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)
      this[offset] = (value >>> 8)
      this[offset + 1] = (value & 0xff)
      return offset + 2
    }
    
    Buffer.prototype.writeUInt32LE = function writeUInt32LE (value, offset, noAssert) {
      value = +value
      offset = offset >>> 0
      if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0)
      this[offset + 3] = (value >>> 24)
      this[offset + 2] = (value >>> 16)
      this[offset + 1] = (value >>> 8)
      this[offset] = (value & 0xff)
      return offset + 4
    }
    
    Buffer.prototype.writeUInt32BE = function writeUInt32BE (value, offset, noAssert) {
      value = +value
      offset = offset >>> 0
      if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0)
      this[offset] = (value >>> 24)
      this[offset + 1] = (value >>> 16)
      this[offset + 2] = (value >>> 8)
      this[offset + 3] = (value & 0xff)
      return offset + 4
    }
    
    Buffer.prototype.writeIntLE = function writeIntLE (value, offset, byteLength, noAssert) {
      value = +value
      offset = offset >>> 0
      if (!noAssert) {
        var limit = Math.pow(2, (8 * byteLength) - 1)
    
        checkInt(this, value, offset, byteLength, limit - 1, -limit)
      }
    
      var i = 0
      var mul = 1
      var sub = 0
      this[offset] = value & 0xFF
      while (++i < byteLength && (mul *= 0x100)) {
        if (value < 0 && sub === 0 && this[offset + i - 1] !== 0) {
          sub = 1
        }
        this[offset + i] = ((value / mul) >> 0) - sub & 0xFF
      }
    
      return offset + byteLength
    }
    
    Buffer.prototype.writeIntBE = function writeIntBE (value, offset, byteLength, noAssert) {
      value = +value
      offset = offset >>> 0
      if (!noAssert) {
        var limit = Math.pow(2, (8 * byteLength) - 1)
    
        checkInt(this, value, offset, byteLength, limit - 1, -limit)
      }
    
      var i = byteLength - 1
      var mul = 1
      var sub = 0
      this[offset + i] = value & 0xFF
      while (--i >= 0 && (mul *= 0x100)) {
        if (value < 0 && sub === 0 && this[offset + i + 1] !== 0) {
          sub = 1
        }
        this[offset + i] = ((value / mul) >> 0) - sub & 0xFF
      }
    
      return offset + byteLength
    }
    
    Buffer.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) {
      value = +value
      offset = offset >>> 0
      if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80)
      if (value < 0) value = 0xff + value + 1
      this[offset] = (value & 0xff)
      return offset + 1
    }
    
    Buffer.prototype.writeInt16LE = function writeInt16LE (value, offset, noAssert) {
      value = +value
      offset = offset >>> 0
      if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)
      this[offset] = (value & 0xff)
      this[offset + 1] = (value >>> 8)
      return offset + 2
    }
    
    Buffer.prototype.writeInt16BE = function writeInt16BE (value, offset, noAssert) {
      value = +value
      offset = offset >>> 0
      if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)
      this[offset] = (value >>> 8)
      this[offset + 1] = (value & 0xff)
      return offset + 2
    }
    
    Buffer.prototype.writeInt32LE = function writeInt32LE (value, offset, noAssert) {
      value = +value
      offset = offset >>> 0
      if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)
      this[offset] = (value & 0xff)
      this[offset + 1] = (value >>> 8)
      this[offset + 2] = (value >>> 16)
      this[offset + 3] = (value >>> 24)
      return offset + 4
    }
    
    Buffer.prototype.writeInt32BE = function writeInt32BE (value, offset, noAssert) {
      value = +value
      offset = offset >>> 0
      if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)
      if (value < 0) value = 0xffffffff + value + 1
      this[offset] = (value >>> 24)
      this[offset + 1] = (value >>> 16)
      this[offset + 2] = (value >>> 8)
      this[offset + 3] = (value & 0xff)
      return offset + 4
    }
    
    function checkIEEE754 (buf, value, offset, ext, max, min) {
      if (offset + ext > buf.length) throw new RangeError('Index out of range')
      if (offset < 0) throw new RangeError('Index out of range')
    }
    
    function writeFloat (buf, value, offset, littleEndian, noAssert) {
      value = +value
      offset = offset >>> 0
      if (!noAssert) {
        checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38)
      }
      ieee754.write(buf, value, offset, littleEndian, 23, 4)
      return offset + 4
    }
    
    Buffer.prototype.writeFloatLE = function writeFloatLE (value, offset, noAssert) {
      return writeFloat(this, value, offset, true, noAssert)
    }
    
    Buffer.prototype.writeFloatBE = function writeFloatBE (value, offset, noAssert) {
      return writeFloat(this, value, offset, false, noAssert)
    }
    
    function writeDouble (buf, value, offset, littleEndian, noAssert) {
      value = +value
      offset = offset >>> 0
      if (!noAssert) {
        checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308)
      }
      ieee754.write(buf, value, offset, littleEndian, 52, 8)
      return offset + 8
    }
    
    Buffer.prototype.writeDoubleLE = function writeDoubleLE (value, offset, noAssert) {
      return writeDouble(this, value, offset, true, noAssert)
    }
    
    Buffer.prototype.writeDoubleBE = function writeDoubleBE (value, offset, noAssert) {
      return writeDouble(this, value, offset, false, noAssert)
    }
    
    // copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length)
    Buffer.prototype.copy = function copy (target, targetStart, start, end) {
      if (!Buffer.isBuffer(target)) throw new TypeError('argument should be a Buffer')
      if (!start) start = 0
      if (!end && end !== 0) end = this.length
      if (targetStart >= target.length) targetStart = target.length
      if (!targetStart) targetStart = 0
      if (end > 0 && end < start) end = start
    
      // Copy 0 bytes; we're done
      if (end === start) return 0
      if (target.length === 0 || this.length === 0) return 0
    
      // Fatal error conditions
      if (targetStart < 0) {
        throw new RangeError('targetStart out of bounds')
      }
      if (start < 0 || start >= this.length) throw new RangeError('Index out of range')
      if (end < 0) throw new RangeError('sourceEnd out of bounds')
    
      // Are we oob?
      if (end > this.length) end = this.length
      if (target.length - targetStart < end - start) {
        end = target.length - targetStart + start
      }
    
      var len = end - start
    
      if (this === target && typeof Uint8Array.prototype.copyWithin === 'function') {
        // Use built-in when available, missing from IE11
        this.copyWithin(targetStart, start, end)
      } else if (this === target && start < targetStart && targetStart < end) {
        // descending copy from end
        for (var i = len - 1; i >= 0; --i) {
          target[i + targetStart] = this[i + start]
        }
      } else {
        Uint8Array.prototype.set.call(
          target,
          this.subarray(start, end),
          targetStart
        )
      }
    
      return len
    }
    
    // Usage:
    //    buffer.fill(number[, offset[, end]])
    //    buffer.fill(buffer[, offset[, end]])
    //    buffer.fill(string[, offset[, end]][, encoding])
    Buffer.prototype.fill = function fill (val, start, end, encoding) {
      // Handle string cases:
      if (typeof val === 'string') {
        if (typeof start === 'string') {
          encoding = start
          start = 0
          end = this.length
        } else if (typeof end === 'string') {
          encoding = end
          end = this.length
        }
        if (encoding !== undefined && typeof encoding !== 'string') {
          throw new TypeError('encoding must be a string')
        }
        if (typeof encoding === 'string' && !Buffer.isEncoding(encoding)) {
          throw new TypeError('Unknown encoding: ' + encoding)
        }
        if (val.length === 1) {
          var code = val.charCodeAt(0)
          if ((encoding === 'utf8' && code < 128) ||
              encoding === 'latin1') {
            // Fast path: If `val` fits into a single byte, use that numeric value.
            val = code
          }
        }
      } else if (typeof val === 'number') {
        val = val & 255
      }
    
      // Invalid ranges are not set to a default, so can range check early.
      if (start < 0 || this.length < start || this.length < end) {
        throw new RangeError('Out of range index')
      }
    
      if (end <= start) {
        return this
      }
    
      start = start >>> 0
      end = end === undefined ? this.length : end >>> 0
    
      if (!val) val = 0
    
      var i
      if (typeof val === 'number') {
        for (i = start; i < end; ++i) {
          this[i] = val
        }
      } else {
        var bytes = Buffer.isBuffer(val)
          ? val
          : Buffer.from(val, encoding)
        var len = bytes.length
        if (len === 0) {
          throw new TypeError('The value "' + val +
            '" is invalid for argument "value"')
        }
        for (i = 0; i < end - start; ++i) {
          this[i + start] = bytes[i % len]
        }
      }
    
      return this
    }
    
    // HELPER FUNCTIONS
    // ================
    
    var INVALID_BASE64_RE = /[^+/0-9A-Za-z-_]/g
    
    function base64clean (str) {
      // Node takes equal signs as end of the Base64 encoding
      str = str.split('=')[0]
      // Node strips out invalid characters like \n and \t from the string, base64-js does not
      str = str.trim().replace(INVALID_BASE64_RE, '')
      // Node converts strings with length < 2 to ''
      if (str.length < 2) return ''
      // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not
      while (str.length % 4 !== 0) {
        str = str + '='
      }
      return str
    }
    
    function toHex (n) {
      if (n < 16) return '0' + n.toString(16)
      return n.toString(16)
    }
    
    function utf8ToBytes (string, units) {
      units = units || Infinity
      var codePoint
      var length = string.length
      var leadSurrogate = null
      var bytes = []
    
      for (var i = 0; i < length; ++i) {
        codePoint = string.charCodeAt(i)
    
        // is surrogate component
        if (codePoint > 0xD7FF && codePoint < 0xE000) {
          // last char was a lead
          if (!leadSurrogate) {
            // no lead yet
            if (codePoint > 0xDBFF) {
              // unexpected trail
              if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
              continue
            } else if (i + 1 === length) {
              // unpaired lead
              if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
              continue
            }
    
            // valid lead
            leadSurrogate = codePoint
    
            continue
          }
    
          // 2 leads in a row
          if (codePoint < 0xDC00) {
            if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
            leadSurrogate = codePoint
            continue
          }
    
          // valid surrogate pair
          codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000
        } else if (leadSurrogate) {
          // valid bmp char, but last char was a lead
          if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
        }
    
        leadSurrogate = null
    
        // encode utf8
        if (codePoint < 0x80) {
          if ((units -= 1) < 0) break
          bytes.push(codePoint)
        } else if (codePoint < 0x800) {
          if ((units -= 2) < 0) break
          bytes.push(
            codePoint >> 0x6 | 0xC0,
            codePoint & 0x3F | 0x80
          )
        } else if (codePoint < 0x10000) {
          if ((units -= 3) < 0) break
          bytes.push(
            codePoint >> 0xC | 0xE0,
            codePoint >> 0x6 & 0x3F | 0x80,
            codePoint & 0x3F | 0x80
          )
        } else if (codePoint < 0x110000) {
          if ((units -= 4) < 0) break
          bytes.push(
            codePoint >> 0x12 | 0xF0,
            codePoint >> 0xC & 0x3F | 0x80,
            codePoint >> 0x6 & 0x3F | 0x80,
            codePoint & 0x3F | 0x80
          )
        } else {
          throw new Error('Invalid code point')
        }
      }
    
      return bytes
    }
    
    function asciiToBytes (str) {
      var byteArray = []
      for (var i = 0; i < str.length; ++i) {
        // Node's code seems to be doing this and not & 0x7F..
        byteArray.push(str.charCodeAt(i) & 0xFF)
      }
      return byteArray
    }
    
    function utf16leToBytes (str, units) {
      var c, hi, lo
      var byteArray = []
      for (var i = 0; i < str.length; ++i) {
        if ((units -= 2) < 0) break
    
        c = str.charCodeAt(i)
        hi = c >> 8
        lo = c % 256
        byteArray.push(lo)
        byteArray.push(hi)
      }
    
      return byteArray
    }
    
    function base64ToBytes (str) {
      return base64.toByteArray(base64clean(str))
    }
    
    function blitBuffer (src, dst, offset, length) {
      for (var i = 0; i < length; ++i) {
        if ((i + offset >= dst.length) || (i >= src.length)) break
        dst[i + offset] = src[i]
      }
      return i
    }
    
    // ArrayBuffer or Uint8Array objects from other contexts (i.e. iframes) do not pass
    // the `instanceof` check but they should be treated as of that type.
    // See: https://github.com/feross/buffer/issues/166
    function isInstance (obj, type) {
      return obj instanceof type ||
        (obj != null && obj.constructor != null && obj.constructor.name != null &&
          obj.constructor.name === type.name)
    }
    function numberIsNaN (obj) {
      // For IE11 support
      return obj !== obj // eslint-disable-line no-self-compare
    }
    
    }).call(this)}).call(this,require("buffer").Buffer)
    },{"base64-js":21,"buffer":68,"ieee754":148}],69:[function(require,module,exports){
    'use strict';
    
    var GetIntrinsic = require('get-intrinsic');
    
    var callBind = require('./');
    
    var $indexOf = callBind(GetIntrinsic('String.prototype.indexOf'));
    
    module.exports = function callBoundIntrinsic(name, allowMissing) {
        var intrinsic = GetIntrinsic(name, !!allowMissing);
        if (typeof intrinsic === 'function' && $indexOf(name, '.prototype.') > -1) {
            return callBind(intrinsic);
        }
        return intrinsic;
    };
    
    },{"./":70,"get-intrinsic":112}],70:[function(require,module,exports){
    'use strict';
    
    var bind = require('function-bind');
    var GetIntrinsic = require('get-intrinsic');
    
    var $apply = GetIntrinsic('%Function.prototype.apply%');
    var $call = GetIntrinsic('%Function.prototype.call%');
    var $reflectApply = GetIntrinsic('%Reflect.apply%', true) || bind.call($call, $apply);
    
    var $gOPD = GetIntrinsic('%Object.getOwnPropertyDescriptor%', true);
    var $defineProperty = GetIntrinsic('%Object.defineProperty%', true);
    var $max = GetIntrinsic('%Math.max%');
    
    if ($defineProperty) {
        try {
            $defineProperty({}, 'a', { value: 1 });
        } catch (e) {
            // IE 8 has a broken defineProperty
            $defineProperty = null;
        }
    }
    
    module.exports = function callBind(originalFunction) {
        var func = $reflectApply(bind, $call, arguments);
        if ($gOPD && $defineProperty) {
            var desc = $gOPD(func, 'length');
            if (desc.configurable) {
                // original length, plus the receiver, minus any additional arguments (after the receiver)
                $defineProperty(
                    func,
                    'length',
                    { value: 1 + $max(0, originalFunction.length - (arguments.length - 1)) }
                );
            }
        }
        return func;
    };
    
    var applyBind = function applyBind() {
        return $reflectApply(bind, $apply, arguments);
    };
    
    if ($defineProperty) {
        $defineProperty(module.exports, 'apply', { value: applyBind });
    } else {
        module.exports.apply = applyBind;
    }
    
    },{"function-bind":111,"get-intrinsic":112}],71:[function(require,module,exports){
    var Buffer = require('safe-buffer').Buffer
    var Transform = require('stream').Transform
    var StringDecoder = require('string_decoder').StringDecoder
    var inherits = require('inherits')
    
    function CipherBase (hashMode) {
      Transform.call(this)
      this.hashMode = typeof hashMode === 'string'
      if (this.hashMode) {
        this[hashMode] = this._finalOrDigest
      } else {
        this.final = this._finalOrDigest
      }
      if (this._final) {
        this.__final = this._final
        this._final = null
      }
      this._decoder = null
      this._encoding = null
    }
    inherits(CipherBase, Transform)
    
    CipherBase.prototype.update = function (data, inputEnc, outputEnc) {
      if (typeof data === 'string') {
        data = Buffer.from(data, inputEnc)
      }
    
      var outData = this._update(data)
      if (this.hashMode) return this
    
      if (outputEnc) {
        outData = this._toString(outData, outputEnc)
      }
    
      return outData
    }
    
    CipherBase.prototype.setAutoPadding = function () {}
    CipherBase.prototype.getAuthTag = function () {
      throw new Error('trying to get auth tag in unsupported state')
    }
    
    CipherBase.prototype.setAuthTag = function () {
      throw new Error('trying to set auth tag in unsupported state')
    }
    
    CipherBase.prototype.setAAD = function () {
      throw new Error('trying to set aad in unsupported state')
    }
    
    CipherBase.prototype._transform = function (data, _, next) {
      var err
      try {
        if (this.hashMode) {
          this._update(data)
        } else {
          this.push(this._update(data))
        }
      } catch (e) {
        err = e
      } finally {
        next(err)
      }
    }
    CipherBase.prototype._flush = function (done) {
      var err
      try {
        this.push(this.__final())
      } catch (e) {
        err = e
      }
    
      done(err)
    }
    CipherBase.prototype._finalOrDigest = function (outputEnc) {
      var outData = this.__final() || Buffer.alloc(0)
      if (outputEnc) {
        outData = this._toString(outData, outputEnc, true)
      }
      return outData
    }
    
    CipherBase.prototype._toString = function (value, enc, fin) {
      if (!this._decoder) {
        this._decoder = new StringDecoder(enc)
        this._encoding = enc
      }
    
      if (this._encoding !== enc) throw new Error('can\'t switch encodings')
    
      var out = this._decoder.write(value)
      if (fin) {
        out += this._decoder.end()
      }
    
      return out
    }
    
    module.exports = CipherBase
    
    },{"inherits":149,"safe-buffer":187,"stream":197,"string_decoder":212}],72:[function(require,module,exports){
    (function (Buffer){(function (){
    var elliptic = require('elliptic')
    var BN = require('bn.js')
    
    module.exports = function createECDH (curve) {
      return new ECDH(curve)
    }
    
    var aliases = {
      secp256k1: {
        name: 'secp256k1',
        byteLength: 32
      },
      secp224r1: {
        name: 'p224',
        byteLength: 28
      },
      prime256v1: {
        name: 'p256',
        byteLength: 32
      },
      prime192v1: {
        name: 'p192',
        byteLength: 24
      },
      ed25519: {
        name: 'ed25519',
        byteLength: 32
      },
      secp384r1: {
        name: 'p384',
        byteLength: 48
      },
      secp521r1: {
        name: 'p521',
        byteLength: 66
      }
    }
    
    aliases.p224 = aliases.secp224r1
    aliases.p256 = aliases.secp256r1 = aliases.prime256v1
    aliases.p192 = aliases.secp192r1 = aliases.prime192v1
    aliases.p384 = aliases.secp384r1
    aliases.p521 = aliases.secp521r1
    
    function ECDH (curve) {
      this.curveType = aliases[curve]
      if (!this.curveType) {
        this.curveType = {
          name: curve
        }
      }
      this.curve = new elliptic.ec(this.curveType.name) // eslint-disable-line new-cap
      this.keys = void 0
    }
    
    ECDH.prototype.generateKeys = function (enc, format) {
      this.keys = this.curve.genKeyPair()
      return this.getPublicKey(enc, format)
    }
    
    ECDH.prototype.computeSecret = function (other, inenc, enc) {
      inenc = inenc || 'utf8'
      if (!Buffer.isBuffer(other)) {
        other = new Buffer(other, inenc)
      }
      var otherPub = this.curve.keyFromPublic(other).getPublic()
      var out = otherPub.mul(this.keys.getPrivate()).getX()
      return formatReturnValue(out, enc, this.curveType.byteLength)
    }
    
    ECDH.prototype.getPublicKey = function (enc, format) {
      var key = this.keys.getPublic(format === 'compressed', true)
      if (format === 'hybrid') {
        if (key[key.length - 1] % 2) {
          key[0] = 7
        } else {
          key[0] = 6
        }
      }
      return formatReturnValue(key, enc)
    }
    
    ECDH.prototype.getPrivateKey = function (enc) {
      return formatReturnValue(this.keys.getPrivate(), enc)
    }
    
    ECDH.prototype.setPublicKey = function (pub, enc) {
      enc = enc || 'utf8'
      if (!Buffer.isBuffer(pub)) {
        pub = new Buffer(pub, enc)
      }
      this.keys._importPublic(pub)
      return this
    }
    
    ECDH.prototype.setPrivateKey = function (priv, enc) {
      enc = enc || 'utf8'
      if (!Buffer.isBuffer(priv)) {
        priv = new Buffer(priv, enc)
      }
    
      var _priv = new BN(priv)
      _priv = _priv.toString(16)
      this.keys = this.curve.genKeyPair()
      this.keys._importPrivate(_priv)
      return this
    }
    
    function formatReturnValue (bn, enc, len) {
      if (!Array.isArray(bn)) {
        bn = bn.toArray()
      }
      var buf = new Buffer(bn)
      if (len && buf.length < len) {
        var zeros = new Buffer(len - buf.length)
        zeros.fill(0)
        buf = Buffer.concat([zeros, buf])
      }
      if (!enc) {
        return buf
      } else {
        return buf.toString(enc)
      }
    }
    
    }).call(this)}).call(this,require("buffer").Buffer)
    },{"bn.js":73,"buffer":68,"elliptic":90}],73:[function(require,module,exports){
    arguments[4][15][0].apply(exports,arguments)
    },{"buffer":24,"dup":15}],74:[function(require,module,exports){
    'use strict'
    var inherits = require('inherits')
    var MD5 = require('md5.js')
    var RIPEMD160 = require('ripemd160')
    var sha = require('sha.js')
    var Base = require('cipher-base')
    
    function Hash (hash) {
      Base.call(this, 'digest')
    
      this._hash = hash
    }
    
    inherits(Hash, Base)
    
    Hash.prototype._update = function (data) {
      this._hash.update(data)
    }
    
    Hash.prototype._final = function () {
      return this._hash.digest()
    }
    
    module.exports = function createHash (alg) {
      alg = alg.toLowerCase()
      if (alg === 'md5') return new MD5()
      if (alg === 'rmd160' || alg === 'ripemd160') return new RIPEMD160()
    
      return new Hash(sha(alg))
    }
    
    },{"cipher-base":71,"inherits":149,"md5.js":155,"ripemd160":186,"sha.js":190}],75:[function(require,module,exports){
    var MD5 = require('md5.js')
    
    module.exports = function (buffer) {
      return new MD5().update(buffer).digest()
    }
    
    },{"md5.js":155}],76:[function(require,module,exports){
    'use strict'
    var inherits = require('inherits')
    var Legacy = require('./legacy')
    var Base = require('cipher-base')
    var Buffer = require('safe-buffer').Buffer
    var md5 = require('create-hash/md5')
    var RIPEMD160 = require('ripemd160')
    
    var sha = require('sha.js')
    
    var ZEROS = Buffer.alloc(128)
    
    function Hmac (alg, key) {
      Base.call(this, 'digest')
      if (typeof key === 'string') {
        key = Buffer.from(key)
      }
    
      var blocksize = (alg === 'sha512' || alg === 'sha384') ? 128 : 64
    
      this._alg = alg
      this._key = key
      if (key.length > blocksize) {
        var hash = alg === 'rmd160' ? new RIPEMD160() : sha(alg)
        key = hash.update(key).digest()
      } else if (key.length < blocksize) {
        key = Buffer.concat([key, ZEROS], blocksize)
      }
    
      var ipad = this._ipad = Buffer.allocUnsafe(blocksize)
      var opad = this._opad = Buffer.allocUnsafe(blocksize)
    
      for (var i = 0; i < blocksize; i++) {
        ipad[i] = key[i] ^ 0x36
        opad[i] = key[i] ^ 0x5C
      }
      this._hash = alg === 'rmd160' ? new RIPEMD160() : sha(alg)
      this._hash.update(ipad)
    }
    
    inherits(Hmac, Base)
    
    Hmac.prototype._update = function (data) {
      this._hash.update(data)
    }
    
    Hmac.prototype._final = function () {
      var h = this._hash.digest()
      var hash = this._alg === 'rmd160' ? new RIPEMD160() : sha(this._alg)
      return hash.update(this._opad).update(h).digest()
    }
    
    module.exports = function createHmac (alg, key) {
      alg = alg.toLowerCase()
      if (alg === 'rmd160' || alg === 'ripemd160') {
        return new Hmac('rmd160', key)
      }
      if (alg === 'md5') {
        return new Legacy(md5, key)
      }
      return new Hmac(alg, key)
    }
    
    },{"./legacy":77,"cipher-base":71,"create-hash/md5":75,"inherits":149,"ripemd160":186,"safe-buffer":187,"sha.js":190}],77:[function(require,module,exports){
    'use strict'
    var inherits = require('inherits')
    var Buffer = require('safe-buffer').Buffer
    
    var Base = require('cipher-base')
    
    var ZEROS = Buffer.alloc(128)
    var blocksize = 64
    
    function Hmac (alg, key) {
      Base.call(this, 'digest')
      if (typeof key === 'string') {
        key = Buffer.from(key)
      }
    
      this._alg = alg
      this._key = key
    
      if (key.length > blocksize) {
        key = alg(key)
      } else if (key.length < blocksize) {
        key = Buffer.concat([key, ZEROS], blocksize)
      }
    
      var ipad = this._ipad = Buffer.allocUnsafe(blocksize)
      var opad = this._opad = Buffer.allocUnsafe(blocksize)
    
      for (var i = 0; i < blocksize; i++) {
        ipad[i] = key[i] ^ 0x36
        opad[i] = key[i] ^ 0x5C
      }
    
      this._hash = [ipad]
    }
    
    inherits(Hmac, Base)
    
    Hmac.prototype._update = function (data) {
      this._hash.push(data)
    }
    
    Hmac.prototype._final = function () {
      var h = this._alg(Buffer.concat(this._hash))
      return this._alg(Buffer.concat([this._opad, h]))
    }
    module.exports = Hmac
    
    },{"cipher-base":71,"inherits":149,"safe-buffer":187}],78:[function(require,module,exports){
    'use strict'
    
    exports.randomBytes = exports.rng = exports.pseudoRandomBytes = exports.prng = require('randombytes')
    exports.createHash = exports.Hash = require('create-hash')
    exports.createHmac = exports.Hmac = require('create-hmac')
    
    var algos = require('browserify-sign/algos')
    var algoKeys = Object.keys(algos)
    var hashes = ['sha1', 'sha224', 'sha256', 'sha384', 'sha512', 'md5', 'rmd160'].concat(algoKeys)
    exports.getHashes = function () {
      return hashes
    }
    
    var p = require('pbkdf2')
    exports.pbkdf2 = p.pbkdf2
    exports.pbkdf2Sync = p.pbkdf2Sync
    
    var aes = require('browserify-cipher')
    
    exports.Cipher = aes.Cipher
    exports.createCipher = aes.createCipher
    exports.Cipheriv = aes.Cipheriv
    exports.createCipheriv = aes.createCipheriv
    exports.Decipher = aes.Decipher
    exports.createDecipher = aes.createDecipher
    exports.Decipheriv = aes.Decipheriv
    exports.createDecipheriv = aes.createDecipheriv
    exports.getCiphers = aes.getCiphers
    exports.listCiphers = aes.listCiphers
    
    var dh = require('diffie-hellman')
    
    exports.DiffieHellmanGroup = dh.DiffieHellmanGroup
    exports.createDiffieHellmanGroup = dh.createDiffieHellmanGroup
    exports.getDiffieHellman = dh.getDiffieHellman
    exports.createDiffieHellman = dh.createDiffieHellman
    exports.DiffieHellman = dh.DiffieHellman
    
    var sign = require('browserify-sign')
    
    exports.createSign = sign.createSign
    exports.Sign = sign.Sign
    exports.createVerify = sign.createVerify
    exports.Verify = sign.Verify
    
    exports.createECDH = require('create-ecdh')
    
    var publicEncrypt = require('public-encrypt')
    
    exports.publicEncrypt = publicEncrypt.publicEncrypt
    exports.privateEncrypt = publicEncrypt.privateEncrypt
    exports.publicDecrypt = publicEncrypt.publicDecrypt
    exports.privateDecrypt = publicEncrypt.privateDecrypt
    
    // the least I can do is make error messages for the rest of the node.js/crypto api.
    // ;[
    //   'createCredentials'
    // ].forEach(function (name) {
    //   exports[name] = function () {
    //     throw new Error([
    //       'sorry, ' + name + ' is not implemented yet',
    //       'we accept pull requests',
    //       'https://github.com/crypto-browserify/crypto-browserify'
    //     ].join('\n'))
    //   }
    // })
    
    var rf = require('randomfill')
    
    exports.randomFill = rf.randomFill
    exports.randomFillSync = rf.randomFillSync
    
    exports.createCredentials = function () {
      throw new Error([
        'sorry, createCredentials is not implemented yet',
        'we accept pull requests',
        'https://github.com/crypto-browserify/crypto-browserify'
      ].join('\n'))
    }
    
    exports.constants = {
      'DH_CHECK_P_NOT_SAFE_PRIME': 2,
      'DH_CHECK_P_NOT_PRIME': 1,
      'DH_UNABLE_TO_CHECK_GENERATOR': 4,
      'DH_NOT_SUITABLE_GENERATOR': 8,
      'NPN_ENABLED': 1,
      'ALPN_ENABLED': 1,
      'RSA_PKCS1_PADDING': 1,
      'RSA_SSLV23_PADDING': 2,
      'RSA_NO_PADDING': 3,
      'RSA_PKCS1_OAEP_PADDING': 4,
      'RSA_X931_PADDING': 5,
      'RSA_PKCS1_PSS_PADDING': 6,
      'POINT_CONVERSION_COMPRESSED': 2,
      'POINT_CONVERSION_UNCOMPRESSED': 4,
      'POINT_CONVERSION_HYBRID': 6
    }
    
    },{"browserify-cipher":42,"browserify-sign":49,"browserify-sign/algos":46,"create-ecdh":72,"create-hash":74,"create-hmac":76,"diffie-hellman":85,"pbkdf2":170,"public-encrypt":177,"randombytes":184,"randomfill":185}],79:[function(require,module,exports){
    'use strict';
    
    exports.utils = require('./des/utils');
    exports.Cipher = require('./des/cipher');
    exports.DES = require('./des/des');
    exports.CBC = require('./des/cbc');
    exports.EDE = require('./des/ede');
    
    },{"./des/cbc":80,"./des/cipher":81,"./des/des":82,"./des/ede":83,"./des/utils":84}],80:[function(require,module,exports){
    'use strict';
    
    var assert = require('minimalistic-assert');
    var inherits = require('inherits');
    
    var proto = {};
    
    function CBCState(iv) {
      assert.equal(iv.length, 8, 'Invalid IV length');
    
      this.iv = new Array(8);
      for (var i = 0; i < this.iv.length; i++)
        this.iv[i] = iv[i];
    }
    
    function instantiate(Base) {
      function CBC(options) {
        Base.call(this, options);
        this._cbcInit();
      }
      inherits(CBC, Base);
    
      var keys = Object.keys(proto);
      for (var i = 0; i < keys.length; i++) {
        var key = keys[i];
        CBC.prototype[key] = proto[key];
      }
    
      CBC.create = function create(options) {
        return new CBC(options);
      };
    
      return CBC;
    }
    
    exports.instantiate = instantiate;
    
    proto._cbcInit = function _cbcInit() {
      var state = new CBCState(this.options.iv);
      this._cbcState = state;
    };
    
    proto._update = function _update(inp, inOff, out, outOff) {
      var state = this._cbcState;
      var superProto = this.constructor.super_.prototype;
    
      var iv = state.iv;
      if (this.type === 'encrypt') {
        for (var i = 0; i < this.blockSize; i++)
          iv[i] ^= inp[inOff + i];
    
        superProto._update.call(this, iv, 0, out, outOff);
    
        for (var i = 0; i < this.blockSize; i++)
          iv[i] = out[outOff + i];
      } else {
        superProto._update.call(this, inp, inOff, out, outOff);
    
        for (var i = 0; i < this.blockSize; i++)
          out[outOff + i] ^= iv[i];
    
        for (var i = 0; i < this.blockSize; i++)
          iv[i] = inp[inOff + i];
      }
    };
    
    },{"inherits":149,"minimalistic-assert":158}],81:[function(require,module,exports){
    'use strict';
    
    var assert = require('minimalistic-assert');
    
    function Cipher(options) {
      this.options = options;
    
      this.type = this.options.type;
      this.blockSize = 8;
      this._init();
    
      this.buffer = new Array(this.blockSize);
      this.bufferOff = 0;
      this.padding = options.padding !== false
    }
    module.exports = Cipher;
    
    Cipher.prototype._init = function _init() {
      // Might be overrided
    };
    
    Cipher.prototype.update = function update(data) {
      if (data.length === 0)
        return [];
    
      if (this.type === 'decrypt')
        return this._updateDecrypt(data);
      else
        return this._updateEncrypt(data);
    };
    
    Cipher.prototype._buffer = function _buffer(data, off) {
      // Append data to buffer
      var min = Math.min(this.buffer.length - this.bufferOff, data.length - off);
      for (var i = 0; i < min; i++)
        this.buffer[this.bufferOff + i] = data[off + i];
      this.bufferOff += min;
    
      // Shift next
      return min;
    };
    
    Cipher.prototype._flushBuffer = function _flushBuffer(out, off) {
      this._update(this.buffer, 0, out, off);
      this.bufferOff = 0;
      return this.blockSize;
    };
    
    Cipher.prototype._updateEncrypt = function _updateEncrypt(data) {
      var inputOff = 0;
      var outputOff = 0;
    
      var count = ((this.bufferOff + data.length) / this.blockSize) | 0;
      var out = new Array(count * this.blockSize);
    
      if (this.bufferOff !== 0) {
        inputOff += this._buffer(data, inputOff);
    
        if (this.bufferOff === this.buffer.length)
          outputOff += this._flushBuffer(out, outputOff);
      }
    
      // Write blocks
      var max = data.length - ((data.length - inputOff) % this.blockSize);
      for (; inputOff < max; inputOff += this.blockSize) {
        this._update(data, inputOff, out, outputOff);
        outputOff += this.blockSize;
      }
    
      // Queue rest
      for (; inputOff < data.length; inputOff++, this.bufferOff++)
        this.buffer[this.bufferOff] = data[inputOff];
    
      return out;
    };
    
    Cipher.prototype._updateDecrypt = function _updateDecrypt(data) {
      var inputOff = 0;
      var outputOff = 0;
    
      var count = Math.ceil((this.bufferOff + data.length) / this.blockSize) - 1;
      var out = new Array(count * this.blockSize);
    
      // TODO(indutny): optimize it, this is far from optimal
      for (; count > 0; count--) {
        inputOff += this._buffer(data, inputOff);
        outputOff += this._flushBuffer(out, outputOff);
      }
    
      // Buffer rest of the input
      inputOff += this._buffer(data, inputOff);
    
      return out;
    };
    
    Cipher.prototype.final = function final(buffer) {
      var first;
      if (buffer)
        first = this.update(buffer);
    
      var last;
      if (this.type === 'encrypt')
        last = this._finalEncrypt();
      else
        last = this._finalDecrypt();
    
      if (first)
        return first.concat(last);
      else
        return last;
    };
    
    Cipher.prototype._pad = function _pad(buffer, off) {
      if (off === 0)
        return false;
    
      while (off < buffer.length)
        buffer[off++] = 0;
    
      return true;
    };
    
    Cipher.prototype._finalEncrypt = function _finalEncrypt() {
      if (!this._pad(this.buffer, this.bufferOff))
        return [];
    
      var out = new Array(this.blockSize);
      this._update(this.buffer, 0, out, 0);
      return out;
    };
    
    Cipher.prototype._unpad = function _unpad(buffer) {
      return buffer;
    };
    
    Cipher.prototype._finalDecrypt = function _finalDecrypt() {
      assert.equal(this.bufferOff, this.blockSize, 'Not enough data to decrypt');
      var out = new Array(this.blockSize);
      this._flushBuffer(out, 0);
    
      return this._unpad(out);
    };
    
    },{"minimalistic-assert":158}],82:[function(require,module,exports){
    'use strict';
    
    var assert = require('minimalistic-assert');
    var inherits = require('inherits');
    
    var utils = require('./utils');
    var Cipher = require('./cipher');
    
    function DESState() {
      this.tmp = new Array(2);
      this.keys = null;
    }
    
    function DES(options) {
      Cipher.call(this, options);
    
      var state = new DESState();
      this._desState = state;
    
      this.deriveKeys(state, options.key);
    }
    inherits(DES, Cipher);
    module.exports = DES;
    
    DES.create = function create(options) {
      return new DES(options);
    };
    
    var shiftTable = [
      1, 1, 2, 2, 2, 2, 2, 2,
      1, 2, 2, 2, 2, 2, 2, 1
    ];
    
    DES.prototype.deriveKeys = function deriveKeys(state, key) {
      state.keys = new Array(16 * 2);
    
      assert.equal(key.length, this.blockSize, 'Invalid key length');
    
      var kL = utils.readUInt32BE(key, 0);
      var kR = utils.readUInt32BE(key, 4);
    
      utils.pc1(kL, kR, state.tmp, 0);
      kL = state.tmp[0];
      kR = state.tmp[1];
      for (var i = 0; i < state.keys.length; i += 2) {
        var shift = shiftTable[i >>> 1];
        kL = utils.r28shl(kL, shift);
        kR = utils.r28shl(kR, shift);
        utils.pc2(kL, kR, state.keys, i);
      }
    };
    
    DES.prototype._update = function _update(inp, inOff, out, outOff) {
      var state = this._desState;
    
      var l = utils.readUInt32BE(inp, inOff);
      var r = utils.readUInt32BE(inp, inOff + 4);
    
      // Initial Permutation
      utils.ip(l, r, state.tmp, 0);
      l = state.tmp[0];
      r = state.tmp[1];
    
      if (this.type === 'encrypt')
        this._encrypt(state, l, r, state.tmp, 0);
      else
        this._decrypt(state, l, r, state.tmp, 0);
    
      l = state.tmp[0];
      r = state.tmp[1];
    
      utils.writeUInt32BE(out, l, outOff);
      utils.writeUInt32BE(out, r, outOff + 4);
    };
    
    DES.prototype._pad = function _pad(buffer, off) {
      if (this.padding === false) {
        return false;
      }
    
      var value = buffer.length - off;
      for (var i = off; i < buffer.length; i++)
        buffer[i] = value;
    
      return true;
    };
    
    DES.prototype._unpad = function _unpad(buffer) {
      if (this.padding === false) {
        return buffer;
      }
    
      var pad = buffer[buffer.length - 1];
      for (var i = buffer.length - pad; i < buffer.length; i++)
        assert.equal(buffer[i], pad);
    
      return buffer.slice(0, buffer.length - pad);
    };
    
    DES.prototype._encrypt = function _encrypt(state, lStart, rStart, out, off) {
      var l = lStart;
      var r = rStart;
    
      // Apply f() x16 times
      for (var i = 0; i < state.keys.length; i += 2) {
        var keyL = state.keys[i];
        var keyR = state.keys[i + 1];
    
        // f(r, k)
        utils.expand(r, state.tmp, 0);
    
        keyL ^= state.tmp[0];
        keyR ^= state.tmp[1];
        var s = utils.substitute(keyL, keyR);
        var f = utils.permute(s);
    
        var t = r;
        r = (l ^ f) >>> 0;
        l = t;
      }
    
      // Reverse Initial Permutation
      utils.rip(r, l, out, off);
    };
    
    DES.prototype._decrypt = function _decrypt(state, lStart, rStart, out, off) {
      var l = rStart;
      var r = lStart;
    
      // Apply f() x16 times
      for (var i = state.keys.length - 2; i >= 0; i -= 2) {
        var keyL = state.keys[i];
        var keyR = state.keys[i + 1];
    
        // f(r, k)
        utils.expand(l, state.tmp, 0);
    
        keyL ^= state.tmp[0];
        keyR ^= state.tmp[1];
        var s = utils.substitute(keyL, keyR);
        var f = utils.permute(s);
    
        var t = l;
        l = (r ^ f) >>> 0;
        r = t;
      }
    
      // Reverse Initial Permutation
      utils.rip(l, r, out, off);
    };
    
    },{"./cipher":81,"./utils":84,"inherits":149,"minimalistic-assert":158}],83:[function(require,module,exports){
    'use strict';
    
    var assert = require('minimalistic-assert');
    var inherits = require('inherits');
    
    var Cipher = require('./cipher');
    var DES = require('./des');
    
    function EDEState(type, key) {
      assert.equal(key.length, 24, 'Invalid key length');
    
      var k1 = key.slice(0, 8);
      var k2 = key.slice(8, 16);
      var k3 = key.slice(16, 24);
    
      if (type === 'encrypt') {
        this.ciphers = [
          DES.create({ type: 'encrypt', key: k1 }),
          DES.create({ type: 'decrypt', key: k2 }),
          DES.create({ type: 'encrypt', key: k3 })
        ];
      } else {
        this.ciphers = [
          DES.create({ type: 'decrypt', key: k3 }),
          DES.create({ type: 'encrypt', key: k2 }),
          DES.create({ type: 'decrypt', key: k1 })
        ];
      }
    }
    
    function EDE(options) {
      Cipher.call(this, options);
    
      var state = new EDEState(this.type, this.options.key);
      this._edeState = state;
    }
    inherits(EDE, Cipher);
    
    module.exports = EDE;
    
    EDE.create = function create(options) {
      return new EDE(options);
    };
    
    EDE.prototype._update = function _update(inp, inOff, out, outOff) {
      var state = this._edeState;
    
      state.ciphers[0]._update(inp, inOff, out, outOff);
      state.ciphers[1]._update(out, outOff, out, outOff);
      state.ciphers[2]._update(out, outOff, out, outOff);
    };
    
    EDE.prototype._pad = DES.prototype._pad;
    EDE.prototype._unpad = DES.prototype._unpad;
    
    },{"./cipher":81,"./des":82,"inherits":149,"minimalistic-assert":158}],84:[function(require,module,exports){
    'use strict';
    
    exports.readUInt32BE = function readUInt32BE(bytes, off) {
      var res =  (bytes[0 + off] << 24) |
                 (bytes[1 + off] << 16) |
                 (bytes[2 + off] << 8) |
                 bytes[3 + off];
      return res >>> 0;
    };
    
    exports.writeUInt32BE = function writeUInt32BE(bytes, value, off) {
      bytes[0 + off] = value >>> 24;
      bytes[1 + off] = (value >>> 16) & 0xff;
      bytes[2 + off] = (value >>> 8) & 0xff;
      bytes[3 + off] = value & 0xff;
    };
    
    exports.ip = function ip(inL, inR, out, off) {
      var outL = 0;
      var outR = 0;
    
      for (var i = 6; i >= 0; i -= 2) {
        for (var j = 0; j <= 24; j += 8) {
          outL <<= 1;
          outL |= (inR >>> (j + i)) & 1;
        }
        for (var j = 0; j <= 24; j += 8) {
          outL <<= 1;
          outL |= (inL >>> (j + i)) & 1;
        }
      }
    
      for (var i = 6; i >= 0; i -= 2) {
        for (var j = 1; j <= 25; j += 8) {
          outR <<= 1;
          outR |= (inR >>> (j + i)) & 1;
        }
        for (var j = 1; j <= 25; j += 8) {
          outR <<= 1;
          outR |= (inL >>> (j + i)) & 1;
        }
      }
    
      out[off + 0] = outL >>> 0;
      out[off + 1] = outR >>> 0;
    };
    
    exports.rip = function rip(inL, inR, out, off) {
      var outL = 0;
      var outR = 0;
    
      for (var i = 0; i < 4; i++) {
        for (var j = 24; j >= 0; j -= 8) {
          outL <<= 1;
          outL |= (inR >>> (j + i)) & 1;
          outL <<= 1;
          outL |= (inL >>> (j + i)) & 1;
        }
      }
      for (var i = 4; i < 8; i++) {
        for (var j = 24; j >= 0; j -= 8) {
          outR <<= 1;
          outR |= (inR >>> (j + i)) & 1;
          outR <<= 1;
          outR |= (inL >>> (j + i)) & 1;
        }
      }
    
      out[off + 0] = outL >>> 0;
      out[off + 1] = outR >>> 0;
    };
    
    exports.pc1 = function pc1(inL, inR, out, off) {
      var outL = 0;
      var outR = 0;
    
      // 7, 15, 23, 31, 39, 47, 55, 63
      // 6, 14, 22, 30, 39, 47, 55, 63
      // 5, 13, 21, 29, 39, 47, 55, 63
      // 4, 12, 20, 28
      for (var i = 7; i >= 5; i--) {
        for (var j = 0; j <= 24; j += 8) {
          outL <<= 1;
          outL |= (inR >> (j + i)) & 1;
        }
        for (var j = 0; j <= 24; j += 8) {
          outL <<= 1;
          outL |= (inL >> (j + i)) & 1;
        }
      }
      for (var j = 0; j <= 24; j += 8) {
        outL <<= 1;
        outL |= (inR >> (j + i)) & 1;
      }
    
      // 1, 9, 17, 25, 33, 41, 49, 57
      // 2, 10, 18, 26, 34, 42, 50, 58
      // 3, 11, 19, 27, 35, 43, 51, 59
      // 36, 44, 52, 60
      for (var i = 1; i <= 3; i++) {
        for (var j = 0; j <= 24; j += 8) {
          outR <<= 1;
          outR |= (inR >> (j + i)) & 1;
        }
        for (var j = 0; j <= 24; j += 8) {
          outR <<= 1;
          outR |= (inL >> (j + i)) & 1;
        }
      }
      for (var j = 0; j <= 24; j += 8) {
        outR <<= 1;
        outR |= (inL >> (j + i)) & 1;
      }
    
      out[off + 0] = outL >>> 0;
      out[off + 1] = outR >>> 0;
    };
    
    exports.r28shl = function r28shl(num, shift) {
      return ((num << shift) & 0xfffffff) | (num >>> (28 - shift));
    };
    
    var pc2table = [
      // inL => outL
      14, 11, 17, 4, 27, 23, 25, 0,
      13, 22, 7, 18, 5, 9, 16, 24,
      2, 20, 12, 21, 1, 8, 15, 26,
    
      // inR => outR
      15, 4, 25, 19, 9, 1, 26, 16,
      5, 11, 23, 8, 12, 7, 17, 0,
      22, 3, 10, 14, 6, 20, 27, 24
    ];
    
    exports.pc2 = function pc2(inL, inR, out, off) {
      var outL = 0;
      var outR = 0;
    
      var len = pc2table.length >>> 1;
      for (var i = 0; i < len; i++) {
        outL <<= 1;
        outL |= (inL >>> pc2table[i]) & 0x1;
      }
      for (var i = len; i < pc2table.length; i++) {
        outR <<= 1;
        outR |= (inR >>> pc2table[i]) & 0x1;
      }
    
      out[off + 0] = outL >>> 0;
      out[off + 1] = outR >>> 0;
    };
    
    exports.expand = function expand(r, out, off) {
      var outL = 0;
      var outR = 0;
    
      outL = ((r & 1) << 5) | (r >>> 27);
      for (var i = 23; i >= 15; i -= 4) {
        outL <<= 6;
        outL |= (r >>> i) & 0x3f;
      }
      for (var i = 11; i >= 3; i -= 4) {
        outR |= (r >>> i) & 0x3f;
        outR <<= 6;
      }
      outR |= ((r & 0x1f) << 1) | (r >>> 31);
    
      out[off + 0] = outL >>> 0;
      out[off + 1] = outR >>> 0;
    };
    
    var sTable = [
      14, 0, 4, 15, 13, 7, 1, 4, 2, 14, 15, 2, 11, 13, 8, 1,
      3, 10, 10, 6, 6, 12, 12, 11, 5, 9, 9, 5, 0, 3, 7, 8,
      4, 15, 1, 12, 14, 8, 8, 2, 13, 4, 6, 9, 2, 1, 11, 7,
      15, 5, 12, 11, 9, 3, 7, 14, 3, 10, 10, 0, 5, 6, 0, 13,
    
      15, 3, 1, 13, 8, 4, 14, 7, 6, 15, 11, 2, 3, 8, 4, 14,
      9, 12, 7, 0, 2, 1, 13, 10, 12, 6, 0, 9, 5, 11, 10, 5,
      0, 13, 14, 8, 7, 10, 11, 1, 10, 3, 4, 15, 13, 4, 1, 2,
      5, 11, 8, 6, 12, 7, 6, 12, 9, 0, 3, 5, 2, 14, 15, 9,
    
      10, 13, 0, 7, 9, 0, 14, 9, 6, 3, 3, 4, 15, 6, 5, 10,
      1, 2, 13, 8, 12, 5, 7, 14, 11, 12, 4, 11, 2, 15, 8, 1,
      13, 1, 6, 10, 4, 13, 9, 0, 8, 6, 15, 9, 3, 8, 0, 7,
      11, 4, 1, 15, 2, 14, 12, 3, 5, 11, 10, 5, 14, 2, 7, 12,
    
      7, 13, 13, 8, 14, 11, 3, 5, 0, 6, 6, 15, 9, 0, 10, 3,
      1, 4, 2, 7, 8, 2, 5, 12, 11, 1, 12, 10, 4, 14, 15, 9,
      10, 3, 6, 15, 9, 0, 0, 6, 12, 10, 11, 1, 7, 13, 13, 8,
      15, 9, 1, 4, 3, 5, 14, 11, 5, 12, 2, 7, 8, 2, 4, 14,
    
      2, 14, 12, 11, 4, 2, 1, 12, 7, 4, 10, 7, 11, 13, 6, 1,
      8, 5, 5, 0, 3, 15, 15, 10, 13, 3, 0, 9, 14, 8, 9, 6,
      4, 11, 2, 8, 1, 12, 11, 7, 10, 1, 13, 14, 7, 2, 8, 13,
      15, 6, 9, 15, 12, 0, 5, 9, 6, 10, 3, 4, 0, 5, 14, 3,
    
      12, 10, 1, 15, 10, 4, 15, 2, 9, 7, 2, 12, 6, 9, 8, 5,
      0, 6, 13, 1, 3, 13, 4, 14, 14, 0, 7, 11, 5, 3, 11, 8,
      9, 4, 14, 3, 15, 2, 5, 12, 2, 9, 8, 5, 12, 15, 3, 10,
      7, 11, 0, 14, 4, 1, 10, 7, 1, 6, 13, 0, 11, 8, 6, 13,
    
      4, 13, 11, 0, 2, 11, 14, 7, 15, 4, 0, 9, 8, 1, 13, 10,
      3, 14, 12, 3, 9, 5, 7, 12, 5, 2, 10, 15, 6, 8, 1, 6,
      1, 6, 4, 11, 11, 13, 13, 8, 12, 1, 3, 4, 7, 10, 14, 7,
      10, 9, 15, 5, 6, 0, 8, 15, 0, 14, 5, 2, 9, 3, 2, 12,
    
      13, 1, 2, 15, 8, 13, 4, 8, 6, 10, 15, 3, 11, 7, 1, 4,
      10, 12, 9, 5, 3, 6, 14, 11, 5, 0, 0, 14, 12, 9, 7, 2,
      7, 2, 11, 1, 4, 14, 1, 7, 9, 4, 12, 10, 14, 8, 2, 13,
      0, 15, 6, 12, 10, 9, 13, 0, 15, 3, 3, 5, 5, 6, 8, 11
    ];
    
    exports.substitute = function substitute(inL, inR) {
      var out = 0;
      for (var i = 0; i < 4; i++) {
        var b = (inL >>> (18 - i * 6)) & 0x3f;
        var sb = sTable[i * 0x40 + b];
    
        out <<= 4;
        out |= sb;
      }
      for (var i = 0; i < 4; i++) {
        var b = (inR >>> (18 - i * 6)) & 0x3f;
        var sb = sTable[4 * 0x40 + i * 0x40 + b];
    
        out <<= 4;
        out |= sb;
      }
      return out >>> 0;
    };
    
    var permuteTable = [
      16, 25, 12, 11, 3, 20, 4, 15, 31, 17, 9, 6, 27, 14, 1, 22,
      30, 24, 8, 18, 0, 5, 29, 23, 13, 19, 2, 26, 10, 21, 28, 7
    ];
    
    exports.permute = function permute(num) {
      var out = 0;
      for (var i = 0; i < permuteTable.length; i++) {
        out <<= 1;
        out |= (num >>> permuteTable[i]) & 0x1;
      }
      return out >>> 0;
    };
    
    exports.padSplit = function padSplit(num, size, group) {
      var str = num.toString(2);
      while (str.length < size)
        str = '0' + str;
    
      var out = [];
      for (var i = 0; i < size; i += group)
        out.push(str.slice(i, i + group));
      return out.join(' ');
    };
    
    },{}],85:[function(require,module,exports){
    (function (Buffer){(function (){
    var generatePrime = require('./lib/generatePrime')
    var primes = require('./lib/primes.json')
    
    var DH = require('./lib/dh')
    
    function getDiffieHellman (mod) {
      var prime = new Buffer(primes[mod].prime, 'hex')
      var gen = new Buffer(primes[mod].gen, 'hex')
    
      return new DH(prime, gen)
    }
    
    var ENCODINGS = {
      'binary': true, 'hex': true, 'base64': true
    }
    
    function createDiffieHellman (prime, enc, generator, genc) {
      if (Buffer.isBuffer(enc) || ENCODINGS[enc] === undefined) {
        return createDiffieHellman(prime, 'binary', enc, generator)
      }
    
      enc = enc || 'binary'
      genc = genc || 'binary'
      generator = generator || new Buffer([2])
    
      if (!Buffer.isBuffer(generator)) {
        generator = new Buffer(generator, genc)
      }
    
      if (typeof prime === 'number') {
        return new DH(generatePrime(prime, generator), generator, true)
      }
    
      if (!Buffer.isBuffer(prime)) {
        prime = new Buffer(prime, enc)
      }
    
      return new DH(prime, generator, true)
    }
    
    exports.DiffieHellmanGroup = exports.createDiffieHellmanGroup = exports.getDiffieHellman = getDiffieHellman
    exports.createDiffieHellman = exports.DiffieHellman = createDiffieHellman
    
    }).call(this)}).call(this,require("buffer").Buffer)
    },{"./lib/dh":86,"./lib/generatePrime":87,"./lib/primes.json":88,"buffer":68}],86:[function(require,module,exports){
    (function (Buffer){(function (){
    var BN = require('bn.js');
    var MillerRabin = require('miller-rabin');
    var millerRabin = new MillerRabin();
    var TWENTYFOUR = new BN(24);
    var ELEVEN = new BN(11);
    var TEN = new BN(10);
    var THREE = new BN(3);
    var SEVEN = new BN(7);
    var primes = require('./generatePrime');
    var randomBytes = require('randombytes');
    module.exports = DH;
    
    function setPublicKey(pub, enc) {
      enc = enc || 'utf8';
      if (!Buffer.isBuffer(pub)) {
        pub = new Buffer(pub, enc);
      }
      this._pub = new BN(pub);
      return this;
    }
    
    function setPrivateKey(priv, enc) {
      enc = enc || 'utf8';
      if (!Buffer.isBuffer(priv)) {
        priv = new Buffer(priv, enc);
      }
      this._priv = new BN(priv);
      return this;
    }
    
    var primeCache = {};
    function checkPrime(prime, generator) {
      var gen = generator.toString('hex');
      var hex = [gen, prime.toString(16)].join('_');
      if (hex in primeCache) {
        return primeCache[hex];
      }
      var error = 0;
    
      if (prime.isEven() ||
        !primes.simpleSieve ||
        !primes.fermatTest(prime) ||
        !millerRabin.test(prime)) {
        //not a prime so +1
        error += 1;
    
        if (gen === '02' || gen === '05') {
          // we'd be able to check the generator
          // it would fail so +8
          error += 8;
        } else {
          //we wouldn't be able to test the generator
          // so +4
          error += 4;
        }
        primeCache[hex] = error;
        return error;
      }
      if (!millerRabin.test(prime.shrn(1))) {
        //not a safe prime
        error += 2;
      }
      var rem;
      switch (gen) {
        case '02':
          if (prime.mod(TWENTYFOUR).cmp(ELEVEN)) {
            // unsuidable generator
            error += 8;
          }
          break;
        case '05':
          rem = prime.mod(TEN);
          if (rem.cmp(THREE) && rem.cmp(SEVEN)) {
            // prime mod 10 needs to equal 3 or 7
            error += 8;
          }
          break;
        default:
          error += 4;
      }
      primeCache[hex] = error;
      return error;
    }
    
    function DH(prime, generator, malleable) {
      this.setGenerator(generator);
      this.__prime = new BN(prime);
      this._prime = BN.mont(this.__prime);
      this._primeLen = prime.length;
      this._pub = undefined;
      this._priv = undefined;
      this._primeCode = undefined;
      if (malleable) {
        this.setPublicKey = setPublicKey;
        this.setPrivateKey = setPrivateKey;
      } else {
        this._primeCode = 8;
      }
    }
    Object.defineProperty(DH.prototype, 'verifyError', {
      enumerable: true,
      get: function () {
        if (typeof this._primeCode !== 'number') {
          this._primeCode = checkPrime(this.__prime, this.__gen);
        }
        return this._primeCode;
      }
    });
    DH.prototype.generateKeys = function () {
      if (!this._priv) {
        this._priv = new BN(randomBytes(this._primeLen));
      }
      this._pub = this._gen.toRed(this._prime).redPow(this._priv).fromRed();
      return this.getPublicKey();
    };
    
    DH.prototype.computeSecret = function (other) {
      other = new BN(other);
      other = other.toRed(this._prime);
      var secret = other.redPow(this._priv).fromRed();
      var out = new Buffer(secret.toArray());
      var prime = this.getPrime();
      if (out.length < prime.length) {
        var front = new Buffer(prime.length - out.length);
        front.fill(0);
        out = Buffer.concat([front, out]);
      }
      return out;
    };
    
    DH.prototype.getPublicKey = function getPublicKey(enc) {
      return formatReturnValue(this._pub, enc);
    };
    
    DH.prototype.getPrivateKey = function getPrivateKey(enc) {
      return formatReturnValue(this._priv, enc);
    };
    
    DH.prototype.getPrime = function (enc) {
      return formatReturnValue(this.__prime, enc);
    };
    
    DH.prototype.getGenerator = function (enc) {
      return formatReturnValue(this._gen, enc);
    };
    
    DH.prototype.setGenerator = function (gen, enc) {
      enc = enc || 'utf8';
      if (!Buffer.isBuffer(gen)) {
        gen = new Buffer(gen, enc);
      }
      this.__gen = gen;
      this._gen = new BN(gen);
      return this;
    };
    
    function formatReturnValue(bn, enc) {
      var buf = new Buffer(bn.toArray());
      if (!enc) {
        return buf;
      } else {
        return buf.toString(enc);
      }
    }
    
    }).call(this)}).call(this,require("buffer").Buffer)
    },{"./generatePrime":87,"bn.js":89,"buffer":68,"miller-rabin":156,"randombytes":184}],87:[function(require,module,exports){
    var randomBytes = require('randombytes');
    module.exports = findPrime;
    findPrime.simpleSieve = simpleSieve;
    findPrime.fermatTest = fermatTest;
    var BN = require('bn.js');
    var TWENTYFOUR = new BN(24);
    var MillerRabin = require('miller-rabin');
    var millerRabin = new MillerRabin();
    var ONE = new BN(1);
    var TWO = new BN(2);
    var FIVE = new BN(5);
    var SIXTEEN = new BN(16);
    var EIGHT = new BN(8);
    var TEN = new BN(10);
    var THREE = new BN(3);
    var SEVEN = new BN(7);
    var ELEVEN = new BN(11);
    var FOUR = new BN(4);
    var TWELVE = new BN(12);
    var primes = null;
    
    function _getPrimes() {
      if (primes !== null)
        return primes;
    
      var limit = 0x100000;
      var res = [];
      res[0] = 2;
      for (var i = 1, k = 3; k < limit; k += 2) {
        var sqrt = Math.ceil(Math.sqrt(k));
        for (var j = 0; j < i && res[j] <= sqrt; j++)
          if (k % res[j] === 0)
            break;
    
        if (i !== j && res[j] <= sqrt)
          continue;
    
        res[i++] = k;
      }
      primes = res;
      return res;
    }
    
    function simpleSieve(p) {
      var primes = _getPrimes();
    
      for (var i = 0; i < primes.length; i++)
        if (p.modn(primes[i]) === 0) {
          if (p.cmpn(primes[i]) === 0) {
            return true;
          } else {
            return false;
          }
        }
    
      return true;
    }
    
    function fermatTest(p) {
      var red = BN.mont(p);
      return TWO.toRed(red).redPow(p.subn(1)).fromRed().cmpn(1) === 0;
    }
    
    function findPrime(bits, gen) {
      if (bits < 16) {
        // this is what openssl does
        if (gen === 2 || gen === 5) {
          return new BN([0x8c, 0x7b]);
        } else {
          return new BN([0x8c, 0x27]);
        }
      }
      gen = new BN(gen);
    
      var num, n2;
    
      while (true) {
        num = new BN(randomBytes(Math.ceil(bits / 8)));
        while (num.bitLength() > bits) {
          num.ishrn(1);
        }
        if (num.isEven()) {
          num.iadd(ONE);
        }
        if (!num.testn(1)) {
          num.iadd(TWO);
        }
        if (!gen.cmp(TWO)) {
          while (num.mod(TWENTYFOUR).cmp(ELEVEN)) {
            num.iadd(FOUR);
          }
        } else if (!gen.cmp(FIVE)) {
          while (num.mod(TEN).cmp(THREE)) {
            num.iadd(FOUR);
          }
        }
        n2 = num.shrn(1);
        if (simpleSieve(n2) && simpleSieve(num) &&
          fermatTest(n2) && fermatTest(num) &&
          millerRabin.test(n2) && millerRabin.test(num)) {
          return num;
        }
      }
    
    }
    
    },{"bn.js":89,"miller-rabin":156,"randombytes":184}],88:[function(require,module,exports){
    module.exports={
        "modp1": {
            "gen": "02",
            "prime": "ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a63a3620ffffffffffffffff"
        },
        "modp2": {
            "gen": "02",
            "prime": "ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece65381ffffffffffffffff"
        },
        "modp5": {
            "gen": "02",
            "prime": "ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca237327ffffffffffffffff"
        },
        "modp14": {
            "gen": "02",
            "prime": "ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca18217c32905e462e36ce3be39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf6955817183995497cea956ae515d2261898fa051015728e5a8aacaa68ffffffffffffffff"
        },
        "modp15": {
            "gen": "02",
            "prime": "ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca18217c32905e462e36ce3be39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf6955817183995497cea956ae515d2261898fa051015728e5a8aaac42dad33170d04507a33a85521abdf1cba64ecfb850458dbef0a8aea71575d060c7db3970f85a6e1e4c7abf5ae8cdb0933d71e8c94e04a25619dcee3d2261ad2ee6bf12ffa06d98a0864d87602733ec86a64521f2b18177b200cbbe117577a615d6c770988c0bad946e208e24fa074e5ab3143db5bfce0fd108e4b82d120a93ad2caffffffffffffffff"
        },
        "modp16": {
            "gen": "02",
            "prime": "ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca18217c32905e462e36ce3be39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf6955817183995497cea956ae515d2261898fa051015728e5a8aaac42dad33170d04507a33a85521abdf1cba64ecfb850458dbef0a8aea71575d060c7db3970f85a6e1e4c7abf5ae8cdb0933d71e8c94e04a25619dcee3d2261ad2ee6bf12ffa06d98a0864d87602733ec86a64521f2b18177b200cbbe117577a615d6c770988c0bad946e208e24fa074e5ab3143db5bfce0fd108e4b82d120a92108011a723c12a787e6d788719a10bdba5b2699c327186af4e23c1a946834b6150bda2583e9ca2ad44ce8dbbbc2db04de8ef92e8efc141fbecaa6287c59474e6bc05d99b2964fa090c3a2233ba186515be7ed1f612970cee2d7afb81bdd762170481cd0069127d5b05aa993b4ea988d8fddc186ffb7dc90a6c08f4df435c934063199ffffffffffffffff"
        },
        "modp17": {
            "gen": "02",
            "prime": "ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca18217c32905e462e36ce3be39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf6955817183995497cea956ae515d2261898fa051015728e5a8aaac42dad33170d04507a33a85521abdf1cba64ecfb850458dbef0a8aea71575d060c7db3970f85a6e1e4c7abf5ae8cdb0933d71e8c94e04a25619dcee3d2261ad2ee6bf12ffa06d98a0864d87602733ec86a64521f2b18177b200cbbe117577a615d6c770988c0bad946e208e24fa074e5ab3143db5bfce0fd108e4b82d120a92108011a723c12a787e6d788719a10bdba5b2699c327186af4e23c1a946834b6150bda2583e9ca2ad44ce8dbbbc2db04de8ef92e8efc141fbecaa6287c59474e6bc05d99b2964fa090c3a2233ba186515be7ed1f612970cee2d7afb81bdd762170481cd0069127d5b05aa993b4ea988d8fddc186ffb7dc90a6c08f4df435c93402849236c3fab4d27c7026c1d4dcb2602646dec9751e763dba37bdf8ff9406ad9e530ee5db382f413001aeb06a53ed9027d831179727b0865a8918da3edbebcf9b14ed44ce6cbaced4bb1bdb7f1447e6cc254b332051512bd7af426fb8f401378cd2bf5983ca01c64b92ecf032ea15d1721d03f482d7ce6e74fef6d55e702f46980c82b5a84031900b1c9e59e7c97fbec7e8f323a97a7e36cc88be0f1d45b7ff585ac54bd407b22b4154aacc8f6d7ebf48e1d814cc5ed20f8037e0a79715eef29be32806a1d58bb7c5da76f550aa3d8a1fbff0eb19ccb1a313d55cda56c9ec2ef29632387fe8d76e3c0468043e8f663f4860ee12bf2d5b0b7474d6e694f91e6dcc4024ffffffffffffffff"
        },
        "modp18": {
            "gen": "02",
            "prime": "ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca18217c32905e462e36ce3be39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf6955817183995497cea956ae515d2261898fa051015728e5a8aaac42dad33170d04507a33a85521abdf1cba64ecfb850458dbef0a8aea71575d060c7db3970f85a6e1e4c7abf5ae8cdb0933d71e8c94e04a25619dcee3d2261ad2ee6bf12ffa06d98a0864d87602733ec86a64521f2b18177b200cbbe117577a615d6c770988c0bad946e208e24fa074e5ab3143db5bfce0fd108e4b82d120a92108011a723c12a787e6d788719a10bdba5b2699c327186af4e23c1a946834b6150bda2583e9ca2ad44ce8dbbbc2db04de8ef92e8efc141fbecaa6287c59474e6bc05d99b2964fa090c3a2233ba186515be7ed1f612970cee2d7afb81bdd762170481cd0069127d5b05aa993b4ea988d8fddc186ffb7dc90a6c08f4df435c93402849236c3fab4d27c7026c1d4dcb2602646dec9751e763dba37bdf8ff9406ad9e530ee5db382f413001aeb06a53ed9027d831179727b0865a8918da3edbebcf9b14ed44ce6cbaced4bb1bdb7f1447e6cc254b332051512bd7af426fb8f401378cd2bf5983ca01c64b92ecf032ea15d1721d03f482d7ce6e74fef6d55e702f46980c82b5a84031900b1c9e59e7c97fbec7e8f323a97a7e36cc88be0f1d45b7ff585ac54bd407b22b4154aacc8f6d7ebf48e1d814cc5ed20f8037e0a79715eef29be32806a1d58bb7c5da76f550aa3d8a1fbff0eb19ccb1a313d55cda56c9ec2ef29632387fe8d76e3c0468043e8f663f4860ee12bf2d5b0b7474d6e694f91e6dbe115974a3926f12fee5e438777cb6a932df8cd8bec4d073b931ba3bc832b68d9dd300741fa7bf8afc47ed2576f6936ba424663aab639c5ae4f5683423b4742bf1c978238f16cbe39d652de3fdb8befc848ad922222e04a4037c0713eb57a81a23f0c73473fc646cea306b4bcbc8862f8385ddfa9d4b7fa2c087e879683303ed5bdd3a062b3cf5b3a278a66d2a13f83f44f82ddf310ee074ab6a364597e899a0255dc164f31cc50846851df9ab48195ded7ea1b1d510bd7ee74d73faf36bc31ecfa268359046f4eb879f924009438b481c6cd7889a002ed5ee382bc9190da6fc026e479558e4475677e9aa9e3050e2765694dfc81f56e880b96e7160c980dd98edd3dfffffffffffffffff"
        }
    }
    },{}],89:[function(require,module,exports){
    arguments[4][15][0].apply(exports,arguments)
    },{"buffer":24,"dup":15}],90:[function(require,module,exports){
    'use strict';
    
    var elliptic = exports;
    
    elliptic.version = require('../package.json').version;
    elliptic.utils = require('./elliptic/utils');
    elliptic.rand = require('brorand');
    elliptic.curve = require('./elliptic/curve');
    elliptic.curves = require('./elliptic/curves');
    
    // Protocols
    elliptic.ec = require('./elliptic/ec');
    elliptic.eddsa = require('./elliptic/eddsa');
    
    },{"../package.json":106,"./elliptic/curve":93,"./elliptic/curves":96,"./elliptic/ec":97,"./elliptic/eddsa":100,"./elliptic/utils":104,"brorand":23}],91:[function(require,module,exports){
    'use strict';
    
    var BN = require('bn.js');
    var utils = require('../utils');
    var getNAF = utils.getNAF;
    var getJSF = utils.getJSF;
    var assert = utils.assert;
    
    function BaseCurve(type, conf) {
      this.type = type;
      this.p = new BN(conf.p, 16);
    
      // Use Montgomery, when there is no fast reduction for the prime
      this.red = conf.prime ? BN.red(conf.prime) : BN.mont(this.p);
    
      // Useful for many curves
      this.zero = new BN(0).toRed(this.red);
      this.one = new BN(1).toRed(this.red);
      this.two = new BN(2).toRed(this.red);
    
      // Curve configuration, optional
      this.n = conf.n && new BN(conf.n, 16);
      this.g = conf.g && this.pointFromJSON(conf.g, conf.gRed);
    
      // Temporary arrays
      this._wnafT1 = new Array(4);
      this._wnafT2 = new Array(4);
      this._wnafT3 = new Array(4);
      this._wnafT4 = new Array(4);
    
      this._bitLength = this.n ? this.n.bitLength() : 0;
    
      // Generalized Greg Maxwell's trick
      var adjustCount = this.n && this.p.div(this.n);
      if (!adjustCount || adjustCount.cmpn(100) > 0) {
        this.redN = null;
      } else {
        this._maxwellTrick = true;
        this.redN = this.n.toRed(this.red);
      }
    }
    module.exports = BaseCurve;
    
    BaseCurve.prototype.point = function point() {
      throw new Error('Not implemented');
    };
    
    BaseCurve.prototype.validate = function validate() {
      throw new Error('Not implemented');
    };
    
    BaseCurve.prototype._fixedNafMul = function _fixedNafMul(p, k) {
      assert(p.precomputed);
      var doubles = p._getDoubles();
    
      var naf = getNAF(k, 1, this._bitLength);
      var I = (1 << (doubles.step + 1)) - (doubles.step % 2 === 0 ? 2 : 1);
      I /= 3;
    
      // Translate into more windowed form
      var repr = [];
      var j;
      var nafW;
      for (j = 0; j < naf.length; j += doubles.step) {
        nafW = 0;
        for (var l = j + doubles.step - 1; l >= j; l--)
          nafW = (nafW << 1) + naf[l];
        repr.push(nafW);
      }
    
      var a = this.jpoint(null, null, null);
      var b = this.jpoint(null, null, null);
      for (var i = I; i > 0; i--) {
        for (j = 0; j < repr.length; j++) {
          nafW = repr[j];
          if (nafW === i)
            b = b.mixedAdd(doubles.points[j]);
          else if (nafW === -i)
            b = b.mixedAdd(doubles.points[j].neg());
        }
        a = a.add(b);
      }
      return a.toP();
    };
    
    BaseCurve.prototype._wnafMul = function _wnafMul(p, k) {
      var w = 4;
    
      // Precompute window
      var nafPoints = p._getNAFPoints(w);
      w = nafPoints.wnd;
      var wnd = nafPoints.points;
    
      // Get NAF form
      var naf = getNAF(k, w, this._bitLength);
    
      // Add `this`*(N+1) for every w-NAF index
      var acc = this.jpoint(null, null, null);
      for (var i = naf.length - 1; i >= 0; i--) {
        // Count zeroes
        for (var l = 0; i >= 0 && naf[i] === 0; i--)
          l++;
        if (i >= 0)
          l++;
        acc = acc.dblp(l);
    
        if (i < 0)
          break;
        var z = naf[i];
        assert(z !== 0);
        if (p.type === 'affine') {
          // J +- P
          if (z > 0)
            acc = acc.mixedAdd(wnd[(z - 1) >> 1]);
          else
            acc = acc.mixedAdd(wnd[(-z - 1) >> 1].neg());
        } else {
          // J +- J
          if (z > 0)
            acc = acc.add(wnd[(z - 1) >> 1]);
          else
            acc = acc.add(wnd[(-z - 1) >> 1].neg());
        }
      }
      return p.type === 'affine' ? acc.toP() : acc;
    };
    
    BaseCurve.prototype._wnafMulAdd = function _wnafMulAdd(defW,
      points,
      coeffs,
      len,
      jacobianResult) {
      var wndWidth = this._wnafT1;
      var wnd = this._wnafT2;
      var naf = this._wnafT3;
    
      // Fill all arrays
      var max = 0;
      var i;
      var j;
      var p;
      for (i = 0; i < len; i++) {
        p = points[i];
        var nafPoints = p._getNAFPoints(defW);
        wndWidth[i] = nafPoints.wnd;
        wnd[i] = nafPoints.points;
      }
    
      // Comb small window NAFs
      for (i = len - 1; i >= 1; i -= 2) {
        var a = i - 1;
        var b = i;
        if (wndWidth[a] !== 1 || wndWidth[b] !== 1) {
          naf[a] = getNAF(coeffs[a], wndWidth[a], this._bitLength);
          naf[b] = getNAF(coeffs[b], wndWidth[b], this._bitLength);
          max = Math.max(naf[a].length, max);
          max = Math.max(naf[b].length, max);
          continue;
        }
    
        var comb = [
          points[a], /* 1 */
          null, /* 3 */
          null, /* 5 */
          points[b], /* 7 */
        ];
    
        // Try to avoid Projective points, if possible
        if (points[a].y.cmp(points[b].y) === 0) {
          comb[1] = points[a].add(points[b]);
          comb[2] = points[a].toJ().mixedAdd(points[b].neg());
        } else if (points[a].y.cmp(points[b].y.redNeg()) === 0) {
          comb[1] = points[a].toJ().mixedAdd(points[b]);
          comb[2] = points[a].add(points[b].neg());
        } else {
          comb[1] = points[a].toJ().mixedAdd(points[b]);
          comb[2] = points[a].toJ().mixedAdd(points[b].neg());
        }
    
        var index = [
          -3, /* -1 -1 */
          -1, /* -1 0 */
          -5, /* -1 1 */
          -7, /* 0 -1 */
          0, /* 0 0 */
          7, /* 0 1 */
          5, /* 1 -1 */
          1, /* 1 0 */
          3,  /* 1 1 */
        ];
    
        var jsf = getJSF(coeffs[a], coeffs[b]);
        max = Math.max(jsf[0].length, max);
        naf[a] = new Array(max);
        naf[b] = new Array(max);
        for (j = 0; j < max; j++) {
          var ja = jsf[0][j] | 0;
          var jb = jsf[1][j] | 0;
    
          naf[a][j] = index[(ja + 1) * 3 + (jb + 1)];
          naf[b][j] = 0;
          wnd[a] = comb;
        }
      }
    
      var acc = this.jpoint(null, null, null);
      var tmp = this._wnafT4;
      for (i = max; i >= 0; i--) {
        var k = 0;
    
        while (i >= 0) {
          var zero = true;
          for (j = 0; j < len; j++) {
            tmp[j] = naf[j][i] | 0;
            if (tmp[j] !== 0)
              zero = false;
          }
          if (!zero)
            break;
          k++;
          i--;
        }
        if (i >= 0)
          k++;
        acc = acc.dblp(k);
        if (i < 0)
          break;
    
        for (j = 0; j < len; j++) {
          var z = tmp[j];
          p;
          if (z === 0)
            continue;
          else if (z > 0)
            p = wnd[j][(z - 1) >> 1];
          else if (z < 0)
            p = wnd[j][(-z - 1) >> 1].neg();
    
          if (p.type === 'affine')
            acc = acc.mixedAdd(p);
          else
            acc = acc.add(p);
        }
      }
      // Zeroify references
      for (i = 0; i < len; i++)
        wnd[i] = null;
    
      if (jacobianResult)
        return acc;
      else
        return acc.toP();
    };
    
    function BasePoint(curve, type) {
      this.curve = curve;
      this.type = type;
      this.precomputed = null;
    }
    BaseCurve.BasePoint = BasePoint;
    
    BasePoint.prototype.eq = function eq(/*other*/) {
      throw new Error('Not implemented');
    };
    
    BasePoint.prototype.validate = function validate() {
      return this.curve.validate(this);
    };
    
    BaseCurve.prototype.decodePoint = function decodePoint(bytes, enc) {
      bytes = utils.toArray(bytes, enc);
    
      var len = this.p.byteLength();
    
      // uncompressed, hybrid-odd, hybrid-even
      if ((bytes[0] === 0x04 || bytes[0] === 0x06 || bytes[0] === 0x07) &&
          bytes.length - 1 === 2 * len) {
        if (bytes[0] === 0x06)
          assert(bytes[bytes.length - 1] % 2 === 0);
        else if (bytes[0] === 0x07)
          assert(bytes[bytes.length - 1] % 2 === 1);
    
        var res =  this.point(bytes.slice(1, 1 + len),
          bytes.slice(1 + len, 1 + 2 * len));
    
        return res;
      } else if ((bytes[0] === 0x02 || bytes[0] === 0x03) &&
                  bytes.length - 1 === len) {
        return this.pointFromX(bytes.slice(1, 1 + len), bytes[0] === 0x03);
      }
      throw new Error('Unknown point format');
    };
    
    BasePoint.prototype.encodeCompressed = function encodeCompressed(enc) {
      return this.encode(enc, true);
    };
    
    BasePoint.prototype._encode = function _encode(compact) {
      var len = this.curve.p.byteLength();
      var x = this.getX().toArray('be', len);
    
      if (compact)
        return [ this.getY().isEven() ? 0x02 : 0x03 ].concat(x);
    
      return [ 0x04 ].concat(x, this.getY().toArray('be', len));
    };
    
    BasePoint.prototype.encode = function encode(enc, compact) {
      return utils.encode(this._encode(compact), enc);
    };
    
    BasePoint.prototype.precompute = function precompute(power) {
      if (this.precomputed)
        return this;
    
      var precomputed = {
        doubles: null,
        naf: null,
        beta: null,
      };
      precomputed.naf = this._getNAFPoints(8);
      precomputed.doubles = this._getDoubles(4, power);
      precomputed.beta = this._getBeta();
      this.precomputed = precomputed;
    
      return this;
    };
    
    BasePoint.prototype._hasDoubles = function _hasDoubles(k) {
      if (!this.precomputed)
        return false;
    
      var doubles = this.precomputed.doubles;
      if (!doubles)
        return false;
    
      return doubles.points.length >= Math.ceil((k.bitLength() + 1) / doubles.step);
    };
    
    BasePoint.prototype._getDoubles = function _getDoubles(step, power) {
      if (this.precomputed && this.precomputed.doubles)
        return this.precomputed.doubles;
    
      var doubles = [ this ];
      var acc = this;
      for (var i = 0; i < power; i += step) {
        for (var j = 0; j < step; j++)
          acc = acc.dbl();
        doubles.push(acc);
      }
      return {
        step: step,
        points: doubles,
      };
    };
    
    BasePoint.prototype._getNAFPoints = function _getNAFPoints(wnd) {
      if (this.precomputed && this.precomputed.naf)
        return this.precomputed.naf;
    
      var res = [ this ];
      var max = (1 << wnd) - 1;
      var dbl = max === 1 ? null : this.dbl();
      for (var i = 1; i < max; i++)
        res[i] = res[i - 1].add(dbl);
      return {
        wnd: wnd,
        points: res,
      };
    };
    
    BasePoint.prototype._getBeta = function _getBeta() {
      return null;
    };
    
    BasePoint.prototype.dblp = function dblp(k) {
      var r = this;
      for (var i = 0; i < k; i++)
        r = r.dbl();
      return r;
    };
    
    },{"../utils":104,"bn.js":105}],92:[function(require,module,exports){
    'use strict';
    
    var utils = require('../utils');
    var BN = require('bn.js');
    var inherits = require('inherits');
    var Base = require('./base');
    
    var assert = utils.assert;
    
    function EdwardsCurve(conf) {
      // NOTE: Important as we are creating point in Base.call()
      this.twisted = (conf.a | 0) !== 1;
      this.mOneA = this.twisted && (conf.a | 0) === -1;
      this.extended = this.mOneA;
    
      Base.call(this, 'edwards', conf);
    
      this.a = new BN(conf.a, 16).umod(this.red.m);
      this.a = this.a.toRed(this.red);
      this.c = new BN(conf.c, 16).toRed(this.red);
      this.c2 = this.c.redSqr();
      this.d = new BN(conf.d, 16).toRed(this.red);
      this.dd = this.d.redAdd(this.d);
    
      assert(!this.twisted || this.c.fromRed().cmpn(1) === 0);
      this.oneC = (conf.c | 0) === 1;
    }
    inherits(EdwardsCurve, Base);
    module.exports = EdwardsCurve;
    
    EdwardsCurve.prototype._mulA = function _mulA(num) {
      if (this.mOneA)
        return num.redNeg();
      else
        return this.a.redMul(num);
    };
    
    EdwardsCurve.prototype._mulC = function _mulC(num) {
      if (this.oneC)
        return num;
      else
        return this.c.redMul(num);
    };
    
    // Just for compatibility with Short curve
    EdwardsCurve.prototype.jpoint = function jpoint(x, y, z, t) {
      return this.point(x, y, z, t);
    };
    
    EdwardsCurve.prototype.pointFromX = function pointFromX(x, odd) {
      x = new BN(x, 16);
      if (!x.red)
        x = x.toRed(this.red);
    
      var x2 = x.redSqr();
      var rhs = this.c2.redSub(this.a.redMul(x2));
      var lhs = this.one.redSub(this.c2.redMul(this.d).redMul(x2));
    
      var y2 = rhs.redMul(lhs.redInvm());
      var y = y2.redSqrt();
      if (y.redSqr().redSub(y2).cmp(this.zero) !== 0)
        throw new Error('invalid point');
    
      var isOdd = y.fromRed().isOdd();
      if (odd && !isOdd || !odd && isOdd)
        y = y.redNeg();
    
      return this.point(x, y);
    };
    
    EdwardsCurve.prototype.pointFromY = function pointFromY(y, odd) {
      y = new BN(y, 16);
      if (!y.red)
        y = y.toRed(this.red);
    
      // x^2 = (y^2 - c^2) / (c^2 d y^2 - a)
      var y2 = y.redSqr();
      var lhs = y2.redSub(this.c2);
      var rhs = y2.redMul(this.d).redMul(this.c2).redSub(this.a);
      var x2 = lhs.redMul(rhs.redInvm());
    
      if (x2.cmp(this.zero) === 0) {
        if (odd)
          throw new Error('invalid point');
        else
          return this.point(this.zero, y);
      }
    
      var x = x2.redSqrt();
      if (x.redSqr().redSub(x2).cmp(this.zero) !== 0)
        throw new Error('invalid point');
    
      if (x.fromRed().isOdd() !== odd)
        x = x.redNeg();
    
      return this.point(x, y);
    };
    
    EdwardsCurve.prototype.validate = function validate(point) {
      if (point.isInfinity())
        return true;
    
      // Curve: A * X^2 + Y^2 = C^2 * (1 + D * X^2 * Y^2)
      point.normalize();
    
      var x2 = point.x.redSqr();
      var y2 = point.y.redSqr();
      var lhs = x2.redMul(this.a).redAdd(y2);
      var rhs = this.c2.redMul(this.one.redAdd(this.d.redMul(x2).redMul(y2)));
    
      return lhs.cmp(rhs) === 0;
    };
    
    function Point(curve, x, y, z, t) {
      Base.BasePoint.call(this, curve, 'projective');
      if (x === null && y === null && z === null) {
        this.x = this.curve.zero;
        this.y = this.curve.one;
        this.z = this.curve.one;
        this.t = this.curve.zero;
        this.zOne = true;
      } else {
        this.x = new BN(x, 16);
        this.y = new BN(y, 16);
        this.z = z ? new BN(z, 16) : this.curve.one;
        this.t = t && new BN(t, 16);
        if (!this.x.red)
          this.x = this.x.toRed(this.curve.red);
        if (!this.y.red)
          this.y = this.y.toRed(this.curve.red);
        if (!this.z.red)
          this.z = this.z.toRed(this.curve.red);
        if (this.t && !this.t.red)
          this.t = this.t.toRed(this.curve.red);
        this.zOne = this.z === this.curve.one;
    
        // Use extended coordinates
        if (this.curve.extended && !this.t) {
          this.t = this.x.redMul(this.y);
          if (!this.zOne)
            this.t = this.t.redMul(this.z.redInvm());
        }
      }
    }
    inherits(Point, Base.BasePoint);
    
    EdwardsCurve.prototype.pointFromJSON = function pointFromJSON(obj) {
      return Point.fromJSON(this, obj);
    };
    
    EdwardsCurve.prototype.point = function point(x, y, z, t) {
      return new Point(this, x, y, z, t);
    };
    
    Point.fromJSON = function fromJSON(curve, obj) {
      return new Point(curve, obj[0], obj[1], obj[2]);
    };
    
    Point.prototype.inspect = function inspect() {
      if (this.isInfinity())
        return '<EC Point Infinity>';
      return '<EC Point x: ' + this.x.fromRed().toString(16, 2) +
          ' y: ' + this.y.fromRed().toString(16, 2) +
          ' z: ' + this.z.fromRed().toString(16, 2) + '>';
    };
    
    Point.prototype.isInfinity = function isInfinity() {
      // XXX This code assumes that zero is always zero in red
      return this.x.cmpn(0) === 0 &&
        (this.y.cmp(this.z) === 0 ||
        (this.zOne && this.y.cmp(this.curve.c) === 0));
    };
    
    Point.prototype._extDbl = function _extDbl() {
      // hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html
      //     #doubling-dbl-2008-hwcd
      // 4M + 4S
    
      // A = X1^2
      var a = this.x.redSqr();
      // B = Y1^2
      var b = this.y.redSqr();
      // C = 2 * Z1^2
      var c = this.z.redSqr();
      c = c.redIAdd(c);
      // D = a * A
      var d = this.curve._mulA(a);
      // E = (X1 + Y1)^2 - A - B
      var e = this.x.redAdd(this.y).redSqr().redISub(a).redISub(b);
      // G = D + B
      var g = d.redAdd(b);
      // F = G - C
      var f = g.redSub(c);
      // H = D - B
      var h = d.redSub(b);
      // X3 = E * F
      var nx = e.redMul(f);
      // Y3 = G * H
      var ny = g.redMul(h);
      // T3 = E * H
      var nt = e.redMul(h);
      // Z3 = F * G
      var nz = f.redMul(g);
      return this.curve.point(nx, ny, nz, nt);
    };
    
    Point.prototype._projDbl = function _projDbl() {
      // hyperelliptic.org/EFD/g1p/auto-twisted-projective.html
      //     #doubling-dbl-2008-bbjlp
      //     #doubling-dbl-2007-bl
      // and others
      // Generally 3M + 4S or 2M + 4S
    
      // B = (X1 + Y1)^2
      var b = this.x.redAdd(this.y).redSqr();
      // C = X1^2
      var c = this.x.redSqr();
      // D = Y1^2
      var d = this.y.redSqr();
    
      var nx;
      var ny;
      var nz;
      var e;
      var h;
      var j;
      if (this.curve.twisted) {
        // E = a * C
        e = this.curve._mulA(c);
        // F = E + D
        var f = e.redAdd(d);
        if (this.zOne) {
          // X3 = (B - C - D) * (F - 2)
          nx = b.redSub(c).redSub(d).redMul(f.redSub(this.curve.two));
          // Y3 = F * (E - D)
          ny = f.redMul(e.redSub(d));
          // Z3 = F^2 - 2 * F
          nz = f.redSqr().redSub(f).redSub(f);
        } else {
          // H = Z1^2
          h = this.z.redSqr();
          // J = F - 2 * H
          j = f.redSub(h).redISub(h);
          // X3 = (B-C-D)*J
          nx = b.redSub(c).redISub(d).redMul(j);
          // Y3 = F * (E - D)
          ny = f.redMul(e.redSub(d));
          // Z3 = F * J
          nz = f.redMul(j);
        }
      } else {
        // E = C + D
        e = c.redAdd(d);
        // H = (c * Z1)^2
        h = this.curve._mulC(this.z).redSqr();
        // J = E - 2 * H
        j = e.redSub(h).redSub(h);
        // X3 = c * (B - E) * J
        nx = this.curve._mulC(b.redISub(e)).redMul(j);
        // Y3 = c * E * (C - D)
        ny = this.curve._mulC(e).redMul(c.redISub(d));
        // Z3 = E * J
        nz = e.redMul(j);
      }
      return this.curve.point(nx, ny, nz);
    };
    
    Point.prototype.dbl = function dbl() {
      if (this.isInfinity())
        return this;
    
      // Double in extended coordinates
      if (this.curve.extended)
        return this._extDbl();
      else
        return this._projDbl();
    };
    
    Point.prototype._extAdd = function _extAdd(p) {
      // hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html
      //     #addition-add-2008-hwcd-3
      // 8M
    
      // A = (Y1 - X1) * (Y2 - X2)
      var a = this.y.redSub(this.x).redMul(p.y.redSub(p.x));
      // B = (Y1 + X1) * (Y2 + X2)
      var b = this.y.redAdd(this.x).redMul(p.y.redAdd(p.x));
      // C = T1 * k * T2
      var c = this.t.redMul(this.curve.dd).redMul(p.t);
      // D = Z1 * 2 * Z2
      var d = this.z.redMul(p.z.redAdd(p.z));
      // E = B - A
      var e = b.redSub(a);
      // F = D - C
      var f = d.redSub(c);
      // G = D + C
      var g = d.redAdd(c);
      // H = B + A
      var h = b.redAdd(a);
      // X3 = E * F
      var nx = e.redMul(f);
      // Y3 = G * H
      var ny = g.redMul(h);
      // T3 = E * H
      var nt = e.redMul(h);
      // Z3 = F * G
      var nz = f.redMul(g);
      return this.curve.point(nx, ny, nz, nt);
    };
    
    Point.prototype._projAdd = function _projAdd(p) {
      // hyperelliptic.org/EFD/g1p/auto-twisted-projective.html
      //     #addition-add-2008-bbjlp
      //     #addition-add-2007-bl
      // 10M + 1S
    
      // A = Z1 * Z2
      var a = this.z.redMul(p.z);
      // B = A^2
      var b = a.redSqr();
      // C = X1 * X2
      var c = this.x.redMul(p.x);
      // D = Y1 * Y2
      var d = this.y.redMul(p.y);
      // E = d * C * D
      var e = this.curve.d.redMul(c).redMul(d);
      // F = B - E
      var f = b.redSub(e);
      // G = B + E
      var g = b.redAdd(e);
      // X3 = A * F * ((X1 + Y1) * (X2 + Y2) - C - D)
      var tmp = this.x.redAdd(this.y).redMul(p.x.redAdd(p.y)).redISub(c).redISub(d);
      var nx = a.redMul(f).redMul(tmp);
      var ny;
      var nz;
      if (this.curve.twisted) {
        // Y3 = A * G * (D - a * C)
        ny = a.redMul(g).redMul(d.redSub(this.curve._mulA(c)));
        // Z3 = F * G
        nz = f.redMul(g);
      } else {
        // Y3 = A * G * (D - C)
        ny = a.redMul(g).redMul(d.redSub(c));
        // Z3 = c * F * G
        nz = this.curve._mulC(f).redMul(g);
      }
      return this.curve.point(nx, ny, nz);
    };
    
    Point.prototype.add = function add(p) {
      if (this.isInfinity())
        return p;
      if (p.isInfinity())
        return this;
    
      if (this.curve.extended)
        return this._extAdd(p);
      else
        return this._projAdd(p);
    };
    
    Point.prototype.mul = function mul(k) {
      if (this._hasDoubles(k))
        return this.curve._fixedNafMul(this, k);
      else
        return this.curve._wnafMul(this, k);
    };
    
    Point.prototype.mulAdd = function mulAdd(k1, p, k2) {
      return this.curve._wnafMulAdd(1, [ this, p ], [ k1, k2 ], 2, false);
    };
    
    Point.prototype.jmulAdd = function jmulAdd(k1, p, k2) {
      return this.curve._wnafMulAdd(1, [ this, p ], [ k1, k2 ], 2, true);
    };
    
    Point.prototype.normalize = function normalize() {
      if (this.zOne)
        return this;
    
      // Normalize coordinates
      var zi = this.z.redInvm();
      this.x = this.x.redMul(zi);
      this.y = this.y.redMul(zi);
      if (this.t)
        this.t = this.t.redMul(zi);
      this.z = this.curve.one;
      this.zOne = true;
      return this;
    };
    
    Point.prototype.neg = function neg() {
      return this.curve.point(this.x.redNeg(),
        this.y,
        this.z,
        this.t && this.t.redNeg());
    };
    
    Point.prototype.getX = function getX() {
      this.normalize();
      return this.x.fromRed();
    };
    
    Point.prototype.getY = function getY() {
      this.normalize();
      return this.y.fromRed();
    };
    
    Point.prototype.eq = function eq(other) {
      return this === other ||
             this.getX().cmp(other.getX()) === 0 &&
             this.getY().cmp(other.getY()) === 0;
    };
    
    Point.prototype.eqXToP = function eqXToP(x) {
      var rx = x.toRed(this.curve.red).redMul(this.z);
      if (this.x.cmp(rx) === 0)
        return true;
    
      var xc = x.clone();
      var t = this.curve.redN.redMul(this.z);
      for (;;) {
        xc.iadd(this.curve.n);
        if (xc.cmp(this.curve.p) >= 0)
          return false;
    
        rx.redIAdd(t);
        if (this.x.cmp(rx) === 0)
          return true;
      }
    };
    
    // Compatibility with BaseCurve
    Point.prototype.toP = Point.prototype.normalize;
    Point.prototype.mixedAdd = Point.prototype.add;
    
    },{"../utils":104,"./base":91,"bn.js":105,"inherits":149}],93:[function(require,module,exports){
    'use strict';
    
    var curve = exports;
    
    curve.base = require('./base');
    curve.short = require('./short');
    curve.mont = require('./mont');
    curve.edwards = require('./edwards');
    
    },{"./base":91,"./edwards":92,"./mont":94,"./short":95}],94:[function(require,module,exports){
    'use strict';
    
    var BN = require('bn.js');
    var inherits = require('inherits');
    var Base = require('./base');
    
    var utils = require('../utils');
    
    function MontCurve(conf) {
      Base.call(this, 'mont', conf);
    
      this.a = new BN(conf.a, 16).toRed(this.red);
      this.b = new BN(conf.b, 16).toRed(this.red);
      this.i4 = new BN(4).toRed(this.red).redInvm();
      this.two = new BN(2).toRed(this.red);
      this.a24 = this.i4.redMul(this.a.redAdd(this.two));
    }
    inherits(MontCurve, Base);
    module.exports = MontCurve;
    
    MontCurve.prototype.validate = function validate(point) {
      var x = point.normalize().x;
      var x2 = x.redSqr();
      var rhs = x2.redMul(x).redAdd(x2.redMul(this.a)).redAdd(x);
      var y = rhs.redSqrt();
    
      return y.redSqr().cmp(rhs) === 0;
    };
    
    function Point(curve, x, z) {
      Base.BasePoint.call(this, curve, 'projective');
      if (x === null && z === null) {
        this.x = this.curve.one;
        this.z = this.curve.zero;
      } else {
        this.x = new BN(x, 16);
        this.z = new BN(z, 16);
        if (!this.x.red)
          this.x = this.x.toRed(this.curve.red);
        if (!this.z.red)
          this.z = this.z.toRed(this.curve.red);
      }
    }
    inherits(Point, Base.BasePoint);
    
    MontCurve.prototype.decodePoint = function decodePoint(bytes, enc) {
      return this.point(utils.toArray(bytes, enc), 1);
    };
    
    MontCurve.prototype.point = function point(x, z) {
      return new Point(this, x, z);
    };
    
    MontCurve.prototype.pointFromJSON = function pointFromJSON(obj) {
      return Point.fromJSON(this, obj);
    };
    
    Point.prototype.precompute = function precompute() {
      // No-op
    };
    
    Point.prototype._encode = function _encode() {
      return this.getX().toArray('be', this.curve.p.byteLength());
    };
    
    Point.fromJSON = function fromJSON(curve, obj) {
      return new Point(curve, obj[0], obj[1] || curve.one);
    };
    
    Point.prototype.inspect = function inspect() {
      if (this.isInfinity())
        return '<EC Point Infinity>';
      return '<EC Point x: ' + this.x.fromRed().toString(16, 2) +
          ' z: ' + this.z.fromRed().toString(16, 2) + '>';
    };
    
    Point.prototype.isInfinity = function isInfinity() {
      // XXX This code assumes that zero is always zero in red
      return this.z.cmpn(0) === 0;
    };
    
    Point.prototype.dbl = function dbl() {
      // http://hyperelliptic.org/EFD/g1p/auto-montgom-xz.html#doubling-dbl-1987-m-3
      // 2M + 2S + 4A
    
      // A = X1 + Z1
      var a = this.x.redAdd(this.z);
      // AA = A^2
      var aa = a.redSqr();
      // B = X1 - Z1
      var b = this.x.redSub(this.z);
      // BB = B^2
      var bb = b.redSqr();
      // C = AA - BB
      var c = aa.redSub(bb);
      // X3 = AA * BB
      var nx = aa.redMul(bb);
      // Z3 = C * (BB + A24 * C)
      var nz = c.redMul(bb.redAdd(this.curve.a24.redMul(c)));
      return this.curve.point(nx, nz);
    };
    
    Point.prototype.add = function add() {
      throw new Error('Not supported on Montgomery curve');
    };
    
    Point.prototype.diffAdd = function diffAdd(p, diff) {
      // http://hyperelliptic.org/EFD/g1p/auto-montgom-xz.html#diffadd-dadd-1987-m-3
      // 4M + 2S + 6A
    
      // A = X2 + Z2
      var a = this.x.redAdd(this.z);
      // B = X2 - Z2
      var b = this.x.redSub(this.z);
      // C = X3 + Z3
      var c = p.x.redAdd(p.z);
      // D = X3 - Z3
      var d = p.x.redSub(p.z);
      // DA = D * A
      var da = d.redMul(a);
      // CB = C * B
      var cb = c.redMul(b);
      // X5 = Z1 * (DA + CB)^2
      var nx = diff.z.redMul(da.redAdd(cb).redSqr());
      // Z5 = X1 * (DA - CB)^2
      var nz = diff.x.redMul(da.redISub(cb).redSqr());
      return this.curve.point(nx, nz);
    };
    
    Point.prototype.mul = function mul(k) {
      var t = k.clone();
      var a = this; // (N / 2) * Q + Q
      var b = this.curve.point(null, null); // (N / 2) * Q
      var c = this; // Q
    
      for (var bits = []; t.cmpn(0) !== 0; t.iushrn(1))
        bits.push(t.andln(1));
    
      for (var i = bits.length - 1; i >= 0; i--) {
        if (bits[i] === 0) {
          // N * Q + Q = ((N / 2) * Q + Q)) + (N / 2) * Q
          a = a.diffAdd(b, c);
          // N * Q = 2 * ((N / 2) * Q + Q))
          b = b.dbl();
        } else {
          // N * Q = ((N / 2) * Q + Q) + ((N / 2) * Q)
          b = a.diffAdd(b, c);
          // N * Q + Q = 2 * ((N / 2) * Q + Q)
          a = a.dbl();
        }
      }
      return b;
    };
    
    Point.prototype.mulAdd = function mulAdd() {
      throw new Error('Not supported on Montgomery curve');
    };
    
    Point.prototype.jumlAdd = function jumlAdd() {
      throw new Error('Not supported on Montgomery curve');
    };
    
    Point.prototype.eq = function eq(other) {
      return this.getX().cmp(other.getX()) === 0;
    };
    
    Point.prototype.normalize = function normalize() {
      this.x = this.x.redMul(this.z.redInvm());
      this.z = this.curve.one;
      return this;
    };
    
    Point.prototype.getX = function getX() {
      // Normalize coordinates
      this.normalize();
    
      return this.x.fromRed();
    };
    
    },{"../utils":104,"./base":91,"bn.js":105,"inherits":149}],95:[function(require,module,exports){
    'use strict';
    
    var utils = require('../utils');
    var BN = require('bn.js');
    var inherits = require('inherits');
    var Base = require('./base');
    
    var assert = utils.assert;
    
    function ShortCurve(conf) {
      Base.call(this, 'short', conf);
    
      this.a = new BN(conf.a, 16).toRed(this.red);
      this.b = new BN(conf.b, 16).toRed(this.red);
      this.tinv = this.two.redInvm();
    
      this.zeroA = this.a.fromRed().cmpn(0) === 0;
      this.threeA = this.a.fromRed().sub(this.p).cmpn(-3) === 0;
    
      // If the curve is endomorphic, precalculate beta and lambda
      this.endo = this._getEndomorphism(conf);
      this._endoWnafT1 = new Array(4);
      this._endoWnafT2 = new Array(4);
    }
    inherits(ShortCurve, Base);
    module.exports = ShortCurve;
    
    ShortCurve.prototype._getEndomorphism = function _getEndomorphism(conf) {
      // No efficient endomorphism
      if (!this.zeroA || !this.g || !this.n || this.p.modn(3) !== 1)
        return;
    
      // Compute beta and lambda, that lambda * P = (beta * Px; Py)
      var beta;
      var lambda;
      if (conf.beta) {
        beta = new BN(conf.beta, 16).toRed(this.red);
      } else {
        var betas = this._getEndoRoots(this.p);
        // Choose the smallest beta
        beta = betas[0].cmp(betas[1]) < 0 ? betas[0] : betas[1];
        beta = beta.toRed(this.red);
      }
      if (conf.lambda) {
        lambda = new BN(conf.lambda, 16);
      } else {
        // Choose the lambda that is matching selected beta
        var lambdas = this._getEndoRoots(this.n);
        if (this.g.mul(lambdas[0]).x.cmp(this.g.x.redMul(beta)) === 0) {
          lambda = lambdas[0];
        } else {
          lambda = lambdas[1];
          assert(this.g.mul(lambda).x.cmp(this.g.x.redMul(beta)) === 0);
        }
      }
    
      // Get basis vectors, used for balanced length-two representation
      var basis;
      if (conf.basis) {
        basis = conf.basis.map(function(vec) {
          return {
            a: new BN(vec.a, 16),
            b: new BN(vec.b, 16),
          };
        });
      } else {
        basis = this._getEndoBasis(lambda);
      }
    
      return {
        beta: beta,
        lambda: lambda,
        basis: basis,
      };
    };
    
    ShortCurve.prototype._getEndoRoots = function _getEndoRoots(num) {
      // Find roots of for x^2 + x + 1 in F
      // Root = (-1 +- Sqrt(-3)) / 2
      //
      var red = num === this.p ? this.red : BN.mont(num);
      var tinv = new BN(2).toRed(red).redInvm();
      var ntinv = tinv.redNeg();
    
      var s = new BN(3).toRed(red).redNeg().redSqrt().redMul(tinv);
    
      var l1 = ntinv.redAdd(s).fromRed();
      var l2 = ntinv.redSub(s).fromRed();
      return [ l1, l2 ];
    };
    
    ShortCurve.prototype._getEndoBasis = function _getEndoBasis(lambda) {
      // aprxSqrt >= sqrt(this.n)
      var aprxSqrt = this.n.ushrn(Math.floor(this.n.bitLength() / 2));
    
      // 3.74
      // Run EGCD, until r(L + 1) < aprxSqrt
      var u = lambda;
      var v = this.n.clone();
      var x1 = new BN(1);
      var y1 = new BN(0);
      var x2 = new BN(0);
      var y2 = new BN(1);
    
      // NOTE: all vectors are roots of: a + b * lambda = 0 (mod n)
      var a0;
      var b0;
      // First vector
      var a1;
      var b1;
      // Second vector
      var a2;
      var b2;
    
      var prevR;
      var i = 0;
      var r;
      var x;
      while (u.cmpn(0) !== 0) {
        var q = v.div(u);
        r = v.sub(q.mul(u));
        x = x2.sub(q.mul(x1));
        var y = y2.sub(q.mul(y1));
    
        if (!a1 && r.cmp(aprxSqrt) < 0) {
          a0 = prevR.neg();
          b0 = x1;
          a1 = r.neg();
          b1 = x;
        } else if (a1 && ++i === 2) {
          break;
        }
        prevR = r;
    
        v = u;
        u = r;
        x2 = x1;
        x1 = x;
        y2 = y1;
        y1 = y;
      }
      a2 = r.neg();
      b2 = x;
    
      var len1 = a1.sqr().add(b1.sqr());
      var len2 = a2.sqr().add(b2.sqr());
      if (len2.cmp(len1) >= 0) {
        a2 = a0;
        b2 = b0;
      }
    
      // Normalize signs
      if (a1.negative) {
        a1 = a1.neg();
        b1 = b1.neg();
      }
      if (a2.negative) {
        a2 = a2.neg();
        b2 = b2.neg();
      }
    
      return [
        { a: a1, b: b1 },
        { a: a2, b: b2 },
      ];
    };
    
    ShortCurve.prototype._endoSplit = function _endoSplit(k) {
      var basis = this.endo.basis;
      var v1 = basis[0];
      var v2 = basis[1];
    
      var c1 = v2.b.mul(k).divRound(this.n);
      var c2 = v1.b.neg().mul(k).divRound(this.n);
    
      var p1 = c1.mul(v1.a);
      var p2 = c2.mul(v2.a);
      var q1 = c1.mul(v1.b);
      var q2 = c2.mul(v2.b);
    
      // Calculate answer
      var k1 = k.sub(p1).sub(p2);
      var k2 = q1.add(q2).neg();
      return { k1: k1, k2: k2 };
    };
    
    ShortCurve.prototype.pointFromX = function pointFromX(x, odd) {
      x = new BN(x, 16);
      if (!x.red)
        x = x.toRed(this.red);
    
      var y2 = x.redSqr().redMul(x).redIAdd(x.redMul(this.a)).redIAdd(this.b);
      var y = y2.redSqrt();
      if (y.redSqr().redSub(y2).cmp(this.zero) !== 0)
        throw new Error('invalid point');
    
      // XXX Is there any way to tell if the number is odd without converting it
      // to non-red form?
      var isOdd = y.fromRed().isOdd();
      if (odd && !isOdd || !odd && isOdd)
        y = y.redNeg();
    
      return this.point(x, y);
    };
    
    ShortCurve.prototype.validate = function validate(point) {
      if (point.inf)
        return true;
    
      var x = point.x;
      var y = point.y;
    
      var ax = this.a.redMul(x);
      var rhs = x.redSqr().redMul(x).redIAdd(ax).redIAdd(this.b);
      return y.redSqr().redISub(rhs).cmpn(0) === 0;
    };
    
    ShortCurve.prototype._endoWnafMulAdd =
        function _endoWnafMulAdd(points, coeffs, jacobianResult) {
          var npoints = this._endoWnafT1;
          var ncoeffs = this._endoWnafT2;
          for (var i = 0; i < points.length; i++) {
            var split = this._endoSplit(coeffs[i]);
            var p = points[i];
            var beta = p._getBeta();
    
            if (split.k1.negative) {
              split.k1.ineg();
              p = p.neg(true);
            }
            if (split.k2.negative) {
              split.k2.ineg();
              beta = beta.neg(true);
            }
    
            npoints[i * 2] = p;
            npoints[i * 2 + 1] = beta;
            ncoeffs[i * 2] = split.k1;
            ncoeffs[i * 2 + 1] = split.k2;
          }
          var res = this._wnafMulAdd(1, npoints, ncoeffs, i * 2, jacobianResult);
    
          // Clean-up references to points and coefficients
          for (var j = 0; j < i * 2; j++) {
            npoints[j] = null;
            ncoeffs[j] = null;
          }
          return res;
        };
    
    function Point(curve, x, y, isRed) {
      Base.BasePoint.call(this, curve, 'affine');
      if (x === null && y === null) {
        this.x = null;
        this.y = null;
        this.inf = true;
      } else {
        this.x = new BN(x, 16);
        this.y = new BN(y, 16);
        // Force redgomery representation when loading from JSON
        if (isRed) {
          this.x.forceRed(this.curve.red);
          this.y.forceRed(this.curve.red);
        }
        if (!this.x.red)
          this.x = this.x.toRed(this.curve.red);
        if (!this.y.red)
          this.y = this.y.toRed(this.curve.red);
        this.inf = false;
      }
    }
    inherits(Point, Base.BasePoint);
    
    ShortCurve.prototype.point = function point(x, y, isRed) {
      return new Point(this, x, y, isRed);
    };
    
    ShortCurve.prototype.pointFromJSON = function pointFromJSON(obj, red) {
      return Point.fromJSON(this, obj, red);
    };
    
    Point.prototype._getBeta = function _getBeta() {
      if (!this.curve.endo)
        return;
    
      var pre = this.precomputed;
      if (pre && pre.beta)
        return pre.beta;
    
      var beta = this.curve.point(this.x.redMul(this.curve.endo.beta), this.y);
      if (pre) {
        var curve = this.curve;
        var endoMul = function(p) {
          return curve.point(p.x.redMul(curve.endo.beta), p.y);
        };
        pre.beta = beta;
        beta.precomputed = {
          beta: null,
          naf: pre.naf && {
            wnd: pre.naf.wnd,
            points: pre.naf.points.map(endoMul),
          },
          doubles: pre.doubles && {
            step: pre.doubles.step,
            points: pre.doubles.points.map(endoMul),
          },
        };
      }
      return beta;
    };
    
    Point.prototype.toJSON = function toJSON() {
      if (!this.precomputed)
        return [ this.x, this.y ];
    
      return [ this.x, this.y, this.precomputed && {
        doubles: this.precomputed.doubles && {
          step: this.precomputed.doubles.step,
          points: this.precomputed.doubles.points.slice(1),
        },
        naf: this.precomputed.naf && {
          wnd: this.precomputed.naf.wnd,
          points: this.precomputed.naf.points.slice(1),
        },
      } ];
    };
    
    Point.fromJSON = function fromJSON(curve, obj, red) {
      if (typeof obj === 'string')
        obj = JSON.parse(obj);
      var res = curve.point(obj[0], obj[1], red);
      if (!obj[2])
        return res;
    
      function obj2point(obj) {
        return curve.point(obj[0], obj[1], red);
      }
    
      var pre = obj[2];
      res.precomputed = {
        beta: null,
        doubles: pre.doubles && {
          step: pre.doubles.step,
          points: [ res ].concat(pre.doubles.points.map(obj2point)),
        },
        naf: pre.naf && {
          wnd: pre.naf.wnd,
          points: [ res ].concat(pre.naf.points.map(obj2point)),
        },
      };
      return res;
    };
    
    Point.prototype.inspect = function inspect() {
      if (this.isInfinity())
        return '<EC Point Infinity>';
      return '<EC Point x: ' + this.x.fromRed().toString(16, 2) +
          ' y: ' + this.y.fromRed().toString(16, 2) + '>';
    };
    
    Point.prototype.isInfinity = function isInfinity() {
      return this.inf;
    };
    
    Point.prototype.add = function add(p) {
      // O + P = P
      if (this.inf)
        return p;
    
      // P + O = P
      if (p.inf)
        return this;
    
      // P + P = 2P
      if (this.eq(p))
        return this.dbl();
    
      // P + (-P) = O
      if (this.neg().eq(p))
        return this.curve.point(null, null);
    
      // P + Q = O
      if (this.x.cmp(p.x) === 0)
        return this.curve.point(null, null);
    
      var c = this.y.redSub(p.y);
      if (c.cmpn(0) !== 0)
        c = c.redMul(this.x.redSub(p.x).redInvm());
      var nx = c.redSqr().redISub(this.x).redISub(p.x);
      var ny = c.redMul(this.x.redSub(nx)).redISub(this.y);
      return this.curve.point(nx, ny);
    };
    
    Point.prototype.dbl = function dbl() {
      if (this.inf)
        return this;
    
      // 2P = O
      var ys1 = this.y.redAdd(this.y);
      if (ys1.cmpn(0) === 0)
        return this.curve.point(null, null);
    
      var a = this.curve.a;
    
      var x2 = this.x.redSqr();
      var dyinv = ys1.redInvm();
      var c = x2.redAdd(x2).redIAdd(x2).redIAdd(a).redMul(dyinv);
    
      var nx = c.redSqr().redISub(this.x.redAdd(this.x));
      var ny = c.redMul(this.x.redSub(nx)).redISub(this.y);
      return this.curve.point(nx, ny);
    };
    
    Point.prototype.getX = function getX() {
      return this.x.fromRed();
    };
    
    Point.prototype.getY = function getY() {
      return this.y.fromRed();
    };
    
    Point.prototype.mul = function mul(k) {
      k = new BN(k, 16);
      if (this.isInfinity())
        return this;
      else if (this._hasDoubles(k))
        return this.curve._fixedNafMul(this, k);
      else if (this.curve.endo)
        return this.curve._endoWnafMulAdd([ this ], [ k ]);
      else
        return this.curve._wnafMul(this, k);
    };
    
    Point.prototype.mulAdd = function mulAdd(k1, p2, k2) {
      var points = [ this, p2 ];
      var coeffs = [ k1, k2 ];
      if (this.curve.endo)
        return this.curve._endoWnafMulAdd(points, coeffs);
      else
        return this.curve._wnafMulAdd(1, points, coeffs, 2);
    };
    
    Point.prototype.jmulAdd = function jmulAdd(k1, p2, k2) {
      var points = [ this, p2 ];
      var coeffs = [ k1, k2 ];
      if (this.curve.endo)
        return this.curve._endoWnafMulAdd(points, coeffs, true);
      else
        return this.curve._wnafMulAdd(1, points, coeffs, 2, true);
    };
    
    Point.prototype.eq = function eq(p) {
      return this === p ||
             this.inf === p.inf &&
                 (this.inf || this.x.cmp(p.x) === 0 && this.y.cmp(p.y) === 0);
    };
    
    Point.prototype.neg = function neg(_precompute) {
      if (this.inf)
        return this;
    
      var res = this.curve.point(this.x, this.y.redNeg());
      if (_precompute && this.precomputed) {
        var pre = this.precomputed;
        var negate = function(p) {
          return p.neg();
        };
        res.precomputed = {
          naf: pre.naf && {
            wnd: pre.naf.wnd,
            points: pre.naf.points.map(negate),
          },
          doubles: pre.doubles && {
            step: pre.doubles.step,
            points: pre.doubles.points.map(negate),
          },
        };
      }
      return res;
    };
    
    Point.prototype.toJ = function toJ() {
      if (this.inf)
        return this.curve.jpoint(null, null, null);
    
      var res = this.curve.jpoint(this.x, this.y, this.curve.one);
      return res;
    };
    
    function JPoint(curve, x, y, z) {
      Base.BasePoint.call(this, curve, 'jacobian');
      if (x === null && y === null && z === null) {
        this.x = this.curve.one;
        this.y = this.curve.one;
        this.z = new BN(0);
      } else {
        this.x = new BN(x, 16);
        this.y = new BN(y, 16);
        this.z = new BN(z, 16);
      }
      if (!this.x.red)
        this.x = this.x.toRed(this.curve.red);
      if (!this.y.red)
        this.y = this.y.toRed(this.curve.red);
      if (!this.z.red)
        this.z = this.z.toRed(this.curve.red);
    
      this.zOne = this.z === this.curve.one;
    }
    inherits(JPoint, Base.BasePoint);
    
    ShortCurve.prototype.jpoint = function jpoint(x, y, z) {
      return new JPoint(this, x, y, z);
    };
    
    JPoint.prototype.toP = function toP() {
      if (this.isInfinity())
        return this.curve.point(null, null);
    
      var zinv = this.z.redInvm();
      var zinv2 = zinv.redSqr();
      var ax = this.x.redMul(zinv2);
      var ay = this.y.redMul(zinv2).redMul(zinv);
    
      return this.curve.point(ax, ay);
    };
    
    JPoint.prototype.neg = function neg() {
      return this.curve.jpoint(this.x, this.y.redNeg(), this.z);
    };
    
    JPoint.prototype.add = function add(p) {
      // O + P = P
      if (this.isInfinity())
        return p;
    
      // P + O = P
      if (p.isInfinity())
        return this;
    
      // 12M + 4S + 7A
      var pz2 = p.z.redSqr();
      var z2 = this.z.redSqr();
      var u1 = this.x.redMul(pz2);
      var u2 = p.x.redMul(z2);
      var s1 = this.y.redMul(pz2.redMul(p.z));
      var s2 = p.y.redMul(z2.redMul(this.z));
    
      var h = u1.redSub(u2);
      var r = s1.redSub(s2);
      if (h.cmpn(0) === 0) {
        if (r.cmpn(0) !== 0)
          return this.curve.jpoint(null, null, null);
        else
          return this.dbl();
      }
    
      var h2 = h.redSqr();
      var h3 = h2.redMul(h);
      var v = u1.redMul(h2);
    
      var nx = r.redSqr().redIAdd(h3).redISub(v).redISub(v);
      var ny = r.redMul(v.redISub(nx)).redISub(s1.redMul(h3));
      var nz = this.z.redMul(p.z).redMul(h);
    
      return this.curve.jpoint(nx, ny, nz);
    };
    
    JPoint.prototype.mixedAdd = function mixedAdd(p) {
      // O + P = P
      if (this.isInfinity())
        return p.toJ();
    
      // P + O = P
      if (p.isInfinity())
        return this;
    
      // 8M + 3S + 7A
      var z2 = this.z.redSqr();
      var u1 = this.x;
      var u2 = p.x.redMul(z2);
      var s1 = this.y;
      var s2 = p.y.redMul(z2).redMul(this.z);
    
      var h = u1.redSub(u2);
      var r = s1.redSub(s2);
      if (h.cmpn(0) === 0) {
        if (r.cmpn(0) !== 0)
          return this.curve.jpoint(null, null, null);
        else
          return this.dbl();
      }
    
      var h2 = h.redSqr();
      var h3 = h2.redMul(h);
      var v = u1.redMul(h2);
    
      var nx = r.redSqr().redIAdd(h3).redISub(v).redISub(v);
      var ny = r.redMul(v.redISub(nx)).redISub(s1.redMul(h3));
      var nz = this.z.redMul(h);
    
      return this.curve.jpoint(nx, ny, nz);
    };
    
    JPoint.prototype.dblp = function dblp(pow) {
      if (pow === 0)
        return this;
      if (this.isInfinity())
        return this;
      if (!pow)
        return this.dbl();
    
      var i;
      if (this.curve.zeroA || this.curve.threeA) {
        var r = this;
        for (i = 0; i < pow; i++)
          r = r.dbl();
        return r;
      }
    
      // 1M + 2S + 1A + N * (4S + 5M + 8A)
      // N = 1 => 6M + 6S + 9A
      var a = this.curve.a;
      var tinv = this.curve.tinv;
    
      var jx = this.x;
      var jy = this.y;
      var jz = this.z;
      var jz4 = jz.redSqr().redSqr();
    
      // Reuse results
      var jyd = jy.redAdd(jy);
      for (i = 0; i < pow; i++) {
        var jx2 = jx.redSqr();
        var jyd2 = jyd.redSqr();
        var jyd4 = jyd2.redSqr();
        var c = jx2.redAdd(jx2).redIAdd(jx2).redIAdd(a.redMul(jz4));
    
        var t1 = jx.redMul(jyd2);
        var nx = c.redSqr().redISub(t1.redAdd(t1));
        var t2 = t1.redISub(nx);
        var dny = c.redMul(t2);
        dny = dny.redIAdd(dny).redISub(jyd4);
        var nz = jyd.redMul(jz);
        if (i + 1 < pow)
          jz4 = jz4.redMul(jyd4);
    
        jx = nx;
        jz = nz;
        jyd = dny;
      }
    
      return this.curve.jpoint(jx, jyd.redMul(tinv), jz);
    };
    
    JPoint.prototype.dbl = function dbl() {
      if (this.isInfinity())
        return this;
    
      if (this.curve.zeroA)
        return this._zeroDbl();
      else if (this.curve.threeA)
        return this._threeDbl();
      else
        return this._dbl();
    };
    
    JPoint.prototype._zeroDbl = function _zeroDbl() {
      var nx;
      var ny;
      var nz;
      // Z = 1
      if (this.zOne) {
        // hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html
        //     #doubling-mdbl-2007-bl
        // 1M + 5S + 14A
    
        // XX = X1^2
        var xx = this.x.redSqr();
        // YY = Y1^2
        var yy = this.y.redSqr();
        // YYYY = YY^2
        var yyyy = yy.redSqr();
        // S = 2 * ((X1 + YY)^2 - XX - YYYY)
        var s = this.x.redAdd(yy).redSqr().redISub(xx).redISub(yyyy);
        s = s.redIAdd(s);
        // M = 3 * XX + a; a = 0
        var m = xx.redAdd(xx).redIAdd(xx);
        // T = M ^ 2 - 2*S
        var t = m.redSqr().redISub(s).redISub(s);
    
        // 8 * YYYY
        var yyyy8 = yyyy.redIAdd(yyyy);
        yyyy8 = yyyy8.redIAdd(yyyy8);
        yyyy8 = yyyy8.redIAdd(yyyy8);
    
        // X3 = T
        nx = t;
        // Y3 = M * (S - T) - 8 * YYYY
        ny = m.redMul(s.redISub(t)).redISub(yyyy8);
        // Z3 = 2*Y1
        nz = this.y.redAdd(this.y);
      } else {
        // hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html
        //     #doubling-dbl-2009-l
        // 2M + 5S + 13A
    
        // A = X1^2
        var a = this.x.redSqr();
        // B = Y1^2
        var b = this.y.redSqr();
        // C = B^2
        var c = b.redSqr();
        // D = 2 * ((X1 + B)^2 - A - C)
        var d = this.x.redAdd(b).redSqr().redISub(a).redISub(c);
        d = d.redIAdd(d);
        // E = 3 * A
        var e = a.redAdd(a).redIAdd(a);
        // F = E^2
        var f = e.redSqr();
    
        // 8 * C
        var c8 = c.redIAdd(c);
        c8 = c8.redIAdd(c8);
        c8 = c8.redIAdd(c8);
    
        // X3 = F - 2 * D
        nx = f.redISub(d).redISub(d);
        // Y3 = E * (D - X3) - 8 * C
        ny = e.redMul(d.redISub(nx)).redISub(c8);
        // Z3 = 2 * Y1 * Z1
        nz = this.y.redMul(this.z);
        nz = nz.redIAdd(nz);
      }
    
      return this.curve.jpoint(nx, ny, nz);
    };
    
    JPoint.prototype._threeDbl = function _threeDbl() {
      var nx;
      var ny;
      var nz;
      // Z = 1
      if (this.zOne) {
        // hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html
        //     #doubling-mdbl-2007-bl
        // 1M + 5S + 15A
    
        // XX = X1^2
        var xx = this.x.redSqr();
        // YY = Y1^2
        var yy = this.y.redSqr();
        // YYYY = YY^2
        var yyyy = yy.redSqr();
        // S = 2 * ((X1 + YY)^2 - XX - YYYY)
        var s = this.x.redAdd(yy).redSqr().redISub(xx).redISub(yyyy);
        s = s.redIAdd(s);
        // M = 3 * XX + a
        var m = xx.redAdd(xx).redIAdd(xx).redIAdd(this.curve.a);
        // T = M^2 - 2 * S
        var t = m.redSqr().redISub(s).redISub(s);
        // X3 = T
        nx = t;
        // Y3 = M * (S - T) - 8 * YYYY
        var yyyy8 = yyyy.redIAdd(yyyy);
        yyyy8 = yyyy8.redIAdd(yyyy8);
        yyyy8 = yyyy8.redIAdd(yyyy8);
        ny = m.redMul(s.redISub(t)).redISub(yyyy8);
        // Z3 = 2 * Y1
        nz = this.y.redAdd(this.y);
      } else {
        // hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2001-b
        // 3M + 5S
    
        // delta = Z1^2
        var delta = this.z.redSqr();
        // gamma = Y1^2
        var gamma = this.y.redSqr();
        // beta = X1 * gamma
        var beta = this.x.redMul(gamma);
        // alpha = 3 * (X1 - delta) * (X1 + delta)
        var alpha = this.x.redSub(delta).redMul(this.x.redAdd(delta));
        alpha = alpha.redAdd(alpha).redIAdd(alpha);
        // X3 = alpha^2 - 8 * beta
        var beta4 = beta.redIAdd(beta);
        beta4 = beta4.redIAdd(beta4);
        var beta8 = beta4.redAdd(beta4);
        nx = alpha.redSqr().redISub(beta8);
        // Z3 = (Y1 + Z1)^2 - gamma - delta
        nz = this.y.redAdd(this.z).redSqr().redISub(gamma).redISub(delta);
        // Y3 = alpha * (4 * beta - X3) - 8 * gamma^2
        var ggamma8 = gamma.redSqr();
        ggamma8 = ggamma8.redIAdd(ggamma8);
        ggamma8 = ggamma8.redIAdd(ggamma8);
        ggamma8 = ggamma8.redIAdd(ggamma8);
        ny = alpha.redMul(beta4.redISub(nx)).redISub(ggamma8);
      }
    
      return this.curve.jpoint(nx, ny, nz);
    };
    
    JPoint.prototype._dbl = function _dbl() {
      var a = this.curve.a;
    
      // 4M + 6S + 10A
      var jx = this.x;
      var jy = this.y;
      var jz = this.z;
      var jz4 = jz.redSqr().redSqr();
    
      var jx2 = jx.redSqr();
      var jy2 = jy.redSqr();
    
      var c = jx2.redAdd(jx2).redIAdd(jx2).redIAdd(a.redMul(jz4));
    
      var jxd4 = jx.redAdd(jx);
      jxd4 = jxd4.redIAdd(jxd4);
      var t1 = jxd4.redMul(jy2);
      var nx = c.redSqr().redISub(t1.redAdd(t1));
      var t2 = t1.redISub(nx);
    
      var jyd8 = jy2.redSqr();
      jyd8 = jyd8.redIAdd(jyd8);
      jyd8 = jyd8.redIAdd(jyd8);
      jyd8 = jyd8.redIAdd(jyd8);
      var ny = c.redMul(t2).redISub(jyd8);
      var nz = jy.redAdd(jy).redMul(jz);
    
      return this.curve.jpoint(nx, ny, nz);
    };
    
    JPoint.prototype.trpl = function trpl() {
      if (!this.curve.zeroA)
        return this.dbl().add(this);
    
      // hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#tripling-tpl-2007-bl
      // 5M + 10S + ...
    
      // XX = X1^2
      var xx = this.x.redSqr();
      // YY = Y1^2
      var yy = this.y.redSqr();
      // ZZ = Z1^2
      var zz = this.z.redSqr();
      // YYYY = YY^2
      var yyyy = yy.redSqr();
      // M = 3 * XX + a * ZZ2; a = 0
      var m = xx.redAdd(xx).redIAdd(xx);
      // MM = M^2
      var mm = m.redSqr();
      // E = 6 * ((X1 + YY)^2 - XX - YYYY) - MM
      var e = this.x.redAdd(yy).redSqr().redISub(xx).redISub(yyyy);
      e = e.redIAdd(e);
      e = e.redAdd(e).redIAdd(e);
      e = e.redISub(mm);
      // EE = E^2
      var ee = e.redSqr();
      // T = 16*YYYY
      var t = yyyy.redIAdd(yyyy);
      t = t.redIAdd(t);
      t = t.redIAdd(t);
      t = t.redIAdd(t);
      // U = (M + E)^2 - MM - EE - T
      var u = m.redIAdd(e).redSqr().redISub(mm).redISub(ee).redISub(t);
      // X3 = 4 * (X1 * EE - 4 * YY * U)
      var yyu4 = yy.redMul(u);
      yyu4 = yyu4.redIAdd(yyu4);
      yyu4 = yyu4.redIAdd(yyu4);
      var nx = this.x.redMul(ee).redISub(yyu4);
      nx = nx.redIAdd(nx);
      nx = nx.redIAdd(nx);
      // Y3 = 8 * Y1 * (U * (T - U) - E * EE)
      var ny = this.y.redMul(u.redMul(t.redISub(u)).redISub(e.redMul(ee)));
      ny = ny.redIAdd(ny);
      ny = ny.redIAdd(ny);
      ny = ny.redIAdd(ny);
      // Z3 = (Z1 + E)^2 - ZZ - EE
      var nz = this.z.redAdd(e).redSqr().redISub(zz).redISub(ee);
    
      return this.curve.jpoint(nx, ny, nz);
    };
    
    JPoint.prototype.mul = function mul(k, kbase) {
      k = new BN(k, kbase);
    
      return this.curve._wnafMul(this, k);
    };
    
    JPoint.prototype.eq = function eq(p) {
      if (p.type === 'affine')
        return this.eq(p.toJ());
    
      if (this === p)
        return true;
    
      // x1 * z2^2 == x2 * z1^2
      var z2 = this.z.redSqr();
      var pz2 = p.z.redSqr();
      if (this.x.redMul(pz2).redISub(p.x.redMul(z2)).cmpn(0) !== 0)
        return false;
    
      // y1 * z2^3 == y2 * z1^3
      var z3 = z2.redMul(this.z);
      var pz3 = pz2.redMul(p.z);
      return this.y.redMul(pz3).redISub(p.y.redMul(z3)).cmpn(0) === 0;
    };
    
    JPoint.prototype.eqXToP = function eqXToP(x) {
      var zs = this.z.redSqr();
      var rx = x.toRed(this.curve.red).redMul(zs);
      if (this.x.cmp(rx) === 0)
        return true;
    
      var xc = x.clone();
      var t = this.curve.redN.redMul(zs);
      for (;;) {
        xc.iadd(this.curve.n);
        if (xc.cmp(this.curve.p) >= 0)
          return false;
    
        rx.redIAdd(t);
        if (this.x.cmp(rx) === 0)
          return true;
      }
    };
    
    JPoint.prototype.inspect = function inspect() {
      if (this.isInfinity())
        return '<EC JPoint Infinity>';
      return '<EC JPoint x: ' + this.x.toString(16, 2) +
          ' y: ' + this.y.toString(16, 2) +
          ' z: ' + this.z.toString(16, 2) + '>';
    };
    
    JPoint.prototype.isInfinity = function isInfinity() {
      // XXX This code assumes that zero is always zero in red
      return this.z.cmpn(0) === 0;
    };
    
    },{"../utils":104,"./base":91,"bn.js":105,"inherits":149}],96:[function(require,module,exports){
    'use strict';
    
    var curves = exports;
    
    var hash = require('hash.js');
    var curve = require('./curve');
    var utils = require('./utils');
    
    var assert = utils.assert;
    
    function PresetCurve(options) {
      if (options.type === 'short')
        this.curve = new curve.short(options);
      else if (options.type === 'edwards')
        this.curve = new curve.edwards(options);
      else
        this.curve = new curve.mont(options);
      this.g = this.curve.g;
      this.n = this.curve.n;
      this.hash = options.hash;
    
      assert(this.g.validate(), 'Invalid curve');
      assert(this.g.mul(this.n).isInfinity(), 'Invalid curve, G*N != O');
    }
    curves.PresetCurve = PresetCurve;
    
    function defineCurve(name, options) {
      Object.defineProperty(curves, name, {
        configurable: true,
        enumerable: true,
        get: function() {
          var curve = new PresetCurve(options);
          Object.defineProperty(curves, name, {
            configurable: true,
            enumerable: true,
            value: curve,
          });
          return curve;
        },
      });
    }
    
    defineCurve('p192', {
      type: 'short',
      prime: 'p192',
      p: 'ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff',
      a: 'ffffffff ffffffff ffffffff fffffffe ffffffff fffffffc',
      b: '64210519 e59c80e7 0fa7e9ab 72243049 feb8deec c146b9b1',
      n: 'ffffffff ffffffff ffffffff 99def836 146bc9b1 b4d22831',
      hash: hash.sha256,
      gRed: false,
      g: [
        '188da80e b03090f6 7cbf20eb 43a18800 f4ff0afd 82ff1012',
        '07192b95 ffc8da78 631011ed 6b24cdd5 73f977a1 1e794811',
      ],
    });
    
    defineCurve('p224', {
      type: 'short',
      prime: 'p224',
      p: 'ffffffff ffffffff ffffffff ffffffff 00000000 00000000 00000001',
      a: 'ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff fffffffe',
      b: 'b4050a85 0c04b3ab f5413256 5044b0b7 d7bfd8ba 270b3943 2355ffb4',
      n: 'ffffffff ffffffff ffffffff ffff16a2 e0b8f03e 13dd2945 5c5c2a3d',
      hash: hash.sha256,
      gRed: false,
      g: [
        'b70e0cbd 6bb4bf7f 321390b9 4a03c1d3 56c21122 343280d6 115c1d21',
        'bd376388 b5f723fb 4c22dfe6 cd4375a0 5a074764 44d58199 85007e34',
      ],
    });
    
    defineCurve('p256', {
      type: 'short',
      prime: null,
      p: 'ffffffff 00000001 00000000 00000000 00000000 ffffffff ffffffff ffffffff',
      a: 'ffffffff 00000001 00000000 00000000 00000000 ffffffff ffffffff fffffffc',
      b: '5ac635d8 aa3a93e7 b3ebbd55 769886bc 651d06b0 cc53b0f6 3bce3c3e 27d2604b',
      n: 'ffffffff 00000000 ffffffff ffffffff bce6faad a7179e84 f3b9cac2 fc632551',
      hash: hash.sha256,
      gRed: false,
      g: [
        '6b17d1f2 e12c4247 f8bce6e5 63a440f2 77037d81 2deb33a0 f4a13945 d898c296',
        '4fe342e2 fe1a7f9b 8ee7eb4a 7c0f9e16 2bce3357 6b315ece cbb64068 37bf51f5',
      ],
    });
    
    defineCurve('p384', {
      type: 'short',
      prime: null,
      p: 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ' +
         'fffffffe ffffffff 00000000 00000000 ffffffff',
      a: 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ' +
         'fffffffe ffffffff 00000000 00000000 fffffffc',
      b: 'b3312fa7 e23ee7e4 988e056b e3f82d19 181d9c6e fe814112 0314088f ' +
         '5013875a c656398d 8a2ed19d 2a85c8ed d3ec2aef',
      n: 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff c7634d81 ' +
         'f4372ddf 581a0db2 48b0a77a ecec196a ccc52973',
      hash: hash.sha384,
      gRed: false,
      g: [
        'aa87ca22 be8b0537 8eb1c71e f320ad74 6e1d3b62 8ba79b98 59f741e0 82542a38 ' +
        '5502f25d bf55296c 3a545e38 72760ab7',
        '3617de4a 96262c6f 5d9e98bf 9292dc29 f8f41dbd 289a147c e9da3113 b5f0b8c0 ' +
        '0a60b1ce 1d7e819d 7a431d7c 90ea0e5f',
      ],
    });
    
    defineCurve('p521', {
      type: 'short',
      prime: null,
      p: '000001ff ffffffff ffffffff ffffffff ffffffff ffffffff ' +
         'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ' +
         'ffffffff ffffffff ffffffff ffffffff ffffffff',
      a: '000001ff ffffffff ffffffff ffffffff ffffffff ffffffff ' +
         'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ' +
         'ffffffff ffffffff ffffffff ffffffff fffffffc',
      b: '00000051 953eb961 8e1c9a1f 929a21a0 b68540ee a2da725b ' +
         '99b315f3 b8b48991 8ef109e1 56193951 ec7e937b 1652c0bd ' +
         '3bb1bf07 3573df88 3d2c34f1 ef451fd4 6b503f00',
      n: '000001ff ffffffff ffffffff ffffffff ffffffff ffffffff ' +
         'ffffffff ffffffff fffffffa 51868783 bf2f966b 7fcc0148 ' +
         'f709a5d0 3bb5c9b8 899c47ae bb6fb71e 91386409',
      hash: hash.sha512,
      gRed: false,
      g: [
        '000000c6 858e06b7 0404e9cd 9e3ecb66 2395b442 9c648139 ' +
        '053fb521 f828af60 6b4d3dba a14b5e77 efe75928 fe1dc127 ' +
        'a2ffa8de 3348b3c1 856a429b f97e7e31 c2e5bd66',
        '00000118 39296a78 9a3bc004 5c8a5fb4 2c7d1bd9 98f54449 ' +
        '579b4468 17afbd17 273e662c 97ee7299 5ef42640 c550b901 ' +
        '3fad0761 353c7086 a272c240 88be9476 9fd16650',
      ],
    });
    
    defineCurve('curve25519', {
      type: 'mont',
      prime: 'p25519',
      p: '7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed',
      a: '76d06',
      b: '1',
      n: '1000000000000000 0000000000000000 14def9dea2f79cd6 5812631a5cf5d3ed',
      hash: hash.sha256,
      gRed: false,
      g: [
        '9',
      ],
    });
    
    defineCurve('ed25519', {
      type: 'edwards',
      prime: 'p25519',
      p: '7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed',
      a: '-1',
      c: '1',
      // -121665 * (121666^(-1)) (mod P)
      d: '52036cee2b6ffe73 8cc740797779e898 00700a4d4141d8ab 75eb4dca135978a3',
      n: '1000000000000000 0000000000000000 14def9dea2f79cd6 5812631a5cf5d3ed',
      hash: hash.sha256,
      gRed: false,
      g: [
        '216936d3cd6e53fec0a4e231fdd6dc5c692cc7609525a7b2c9562d608f25d51a',
    
        // 4/5
        '6666666666666666666666666666666666666666666666666666666666666658',
      ],
    });
    
    var pre;
    try {
      pre = require('./precomputed/secp256k1');
    } catch (e) {
      pre = undefined;
    }
    
    defineCurve('secp256k1', {
      type: 'short',
      prime: 'k256',
      p: 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc2f',
      a: '0',
      b: '7',
      n: 'ffffffff ffffffff ffffffff fffffffe baaedce6 af48a03b bfd25e8c d0364141',
      h: '1',
      hash: hash.sha256,
    
      // Precomputed endomorphism
      beta: '7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee',
      lambda: '5363ad4cc05c30e0a5261c028812645a122e22ea20816678df02967c1b23bd72',
      basis: [
        {
          a: '3086d221a7d46bcde86c90e49284eb15',
          b: '-e4437ed6010e88286f547fa90abfe4c3',
        },
        {
          a: '114ca50f7a8e2f3f657c1108d9d44cfd8',
          b: '3086d221a7d46bcde86c90e49284eb15',
        },
      ],
    
      gRed: false,
      g: [
        '79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798',
        '483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8',
        pre,
      ],
    });
    
    },{"./curve":93,"./precomputed/secp256k1":103,"./utils":104,"hash.js":135}],97:[function(require,module,exports){
    'use strict';
    
    var BN = require('bn.js');
    var HmacDRBG = require('hmac-drbg');
    var utils = require('../utils');
    var curves = require('../curves');
    var rand = require('brorand');
    var assert = utils.assert;
    
    var KeyPair = require('./key');
    var Signature = require('./signature');
    
    function EC(options) {
      if (!(this instanceof EC))
        return new EC(options);
    
      // Shortcut `elliptic.ec(curve-name)`
      if (typeof options === 'string') {
        assert(Object.prototype.hasOwnProperty.call(curves, options),
          'Unknown curve ' + options);
    
        options = curves[options];
      }
    
      // Shortcut for `elliptic.ec(elliptic.curves.curveName)`
      if (options instanceof curves.PresetCurve)
        options = { curve: options };
    
      this.curve = options.curve.curve;
      this.n = this.curve.n;
      this.nh = this.n.ushrn(1);
      this.g = this.curve.g;
    
      // Point on curve
      this.g = options.curve.g;
      this.g.precompute(options.curve.n.bitLength() + 1);
    
      // Hash for function for DRBG
      this.hash = options.hash || options.curve.hash;
    }
    module.exports = EC;
    
    EC.prototype.keyPair = function keyPair(options) {
      return new KeyPair(this, options);
    };
    
    EC.prototype.keyFromPrivate = function keyFromPrivate(priv, enc) {
      return KeyPair.fromPrivate(this, priv, enc);
    };
    
    EC.prototype.keyFromPublic = function keyFromPublic(pub, enc) {
      return KeyPair.fromPublic(this, pub, enc);
    };
    
    EC.prototype.genKeyPair = function genKeyPair(options) {
      if (!options)
        options = {};
    
      // Instantiate Hmac_DRBG
      var drbg = new HmacDRBG({
        hash: this.hash,
        pers: options.pers,
        persEnc: options.persEnc || 'utf8',
        entropy: options.entropy || rand(this.hash.hmacStrength),
        entropyEnc: options.entropy && options.entropyEnc || 'utf8',
        nonce: this.n.toArray(),
      });
    
      var bytes = this.n.byteLength();
      var ns2 = this.n.sub(new BN(2));
      for (;;) {
        var priv = new BN(drbg.generate(bytes));
        if (priv.cmp(ns2) > 0)
          continue;
    
        priv.iaddn(1);
        return this.keyFromPrivate(priv);
      }
    };
    
    EC.prototype._truncateToN = function _truncateToN(msg, truncOnly) {
      var delta = msg.byteLength() * 8 - this.n.bitLength();
      if (delta > 0)
        msg = msg.ushrn(delta);
      if (!truncOnly && msg.cmp(this.n) >= 0)
        return msg.sub(this.n);
      else
        return msg;
    };
    
    EC.prototype.sign = function sign(msg, key, enc, options) {
      if (typeof enc === 'object') {
        options = enc;
        enc = null;
      }
      if (!options)
        options = {};
    
      key = this.keyFromPrivate(key, enc);
      msg = this._truncateToN(new BN(msg, 16));
    
      // Zero-extend key to provide enough entropy
      var bytes = this.n.byteLength();
      var bkey = key.getPrivate().toArray('be', bytes);
    
      // Zero-extend nonce to have the same byte size as N
      var nonce = msg.toArray('be', bytes);
    
      // Instantiate Hmac_DRBG
      var drbg = new HmacDRBG({
        hash: this.hash,
        entropy: bkey,
        nonce: nonce,
        pers: options.pers,
        persEnc: options.persEnc || 'utf8',
      });
    
      // Number of bytes to generate
      var ns1 = this.n.sub(new BN(1));
    
      for (var iter = 0; ; iter++) {
        var k = options.k ?
          options.k(iter) :
          new BN(drbg.generate(this.n.byteLength()));
        k = this._truncateToN(k, true);
        if (k.cmpn(1) <= 0 || k.cmp(ns1) >= 0)
          continue;
    
        var kp = this.g.mul(k);
        if (kp.isInfinity())
          continue;
    
        var kpX = kp.getX();
        var r = kpX.umod(this.n);
        if (r.cmpn(0) === 0)
          continue;
    
        var s = k.invm(this.n).mul(r.mul(key.getPrivate()).iadd(msg));
        s = s.umod(this.n);
        if (s.cmpn(0) === 0)
          continue;
    
        var recoveryParam = (kp.getY().isOdd() ? 1 : 0) |
                            (kpX.cmp(r) !== 0 ? 2 : 0);
    
        // Use complement of `s`, if it is > `n / 2`
        if (options.canonical && s.cmp(this.nh) > 0) {
          s = this.n.sub(s);
          recoveryParam ^= 1;
        }
    
        return new Signature({ r: r, s: s, recoveryParam: recoveryParam });
      }
    };
    
    EC.prototype.verify = function verify(msg, signature, key, enc) {
      msg = this._truncateToN(new BN(msg, 16));
      key = this.keyFromPublic(key, enc);
      signature = new Signature(signature, 'hex');
    
      // Perform primitive values validation
      var r = signature.r;
      var s = signature.s;
      if (r.cmpn(1) < 0 || r.cmp(this.n) >= 0)
        return false;
      if (s.cmpn(1) < 0 || s.cmp(this.n) >= 0)
        return false;
    
      // Validate signature
      var sinv = s.invm(this.n);
      var u1 = sinv.mul(msg).umod(this.n);
      var u2 = sinv.mul(r).umod(this.n);
      var p;
    
      if (!this.curve._maxwellTrick) {
        p = this.g.mulAdd(u1, key.getPublic(), u2);
        if (p.isInfinity())
          return false;
    
        return p.getX().umod(this.n).cmp(r) === 0;
      }
    
      // NOTE: Greg Maxwell's trick, inspired by:
      // https://git.io/vad3K
    
      p = this.g.jmulAdd(u1, key.getPublic(), u2);
      if (p.isInfinity())
        return false;
    
      // Compare `p.x` of Jacobian point with `r`,
      // this will do `p.x == r * p.z^2` instead of multiplying `p.x` by the
      // inverse of `p.z^2`
      return p.eqXToP(r);
    };
    
    EC.prototype.recoverPubKey = function(msg, signature, j, enc) {
      assert((3 & j) === j, 'The recovery param is more than two bits');
      signature = new Signature(signature, enc);
    
      var n = this.n;
      var e = new BN(msg);
      var r = signature.r;
      var s = signature.s;
    
      // A set LSB signifies that the y-coordinate is odd
      var isYOdd = j & 1;
      var isSecondKey = j >> 1;
      if (r.cmp(this.curve.p.umod(this.curve.n)) >= 0 && isSecondKey)
        throw new Error('Unable to find sencond key candinate');
    
      // 1.1. Let x = r + jn.
      if (isSecondKey)
        r = this.curve.pointFromX(r.add(this.curve.n), isYOdd);
      else
        r = this.curve.pointFromX(r, isYOdd);
    
      var rInv = signature.r.invm(n);
      var s1 = n.sub(e).mul(rInv).umod(n);
      var s2 = s.mul(rInv).umod(n);
    
      // 1.6.1 Compute Q = r^-1 (sR -  eG)
      //               Q = r^-1 (sR + -eG)
      return this.g.mulAdd(s1, r, s2);
    };
    
    EC.prototype.getKeyRecoveryParam = function(e, signature, Q, enc) {
      signature = new Signature(signature, enc);
      if (signature.recoveryParam !== null)
        return signature.recoveryParam;
    
      for (var i = 0; i < 4; i++) {
        var Qprime;
        try {
          Qprime = this.recoverPubKey(e, signature, i);
        } catch (e) {
          continue;
        }
    
        if (Qprime.eq(Q))
          return i;
      }
      throw new Error('Unable to find valid recovery factor');
    };
    
    },{"../curves":96,"../utils":104,"./key":98,"./signature":99,"bn.js":105,"brorand":23,"hmac-drbg":147}],98:[function(require,module,exports){
    'use strict';
    
    var BN = require('bn.js');
    var utils = require('../utils');
    var assert = utils.assert;
    
    function KeyPair(ec, options) {
      this.ec = ec;
      this.priv = null;
      this.pub = null;
    
      // KeyPair(ec, { priv: ..., pub: ... })
      if (options.priv)
        this._importPrivate(options.priv, options.privEnc);
      if (options.pub)
        this._importPublic(options.pub, options.pubEnc);
    }
    module.exports = KeyPair;
    
    KeyPair.fromPublic = function fromPublic(ec, pub, enc) {
      if (pub instanceof KeyPair)
        return pub;
    
      return new KeyPair(ec, {
        pub: pub,
        pubEnc: enc,
      });
    };
    
    KeyPair.fromPrivate = function fromPrivate(ec, priv, enc) {
      if (priv instanceof KeyPair)
        return priv;
    
      return new KeyPair(ec, {
        priv: priv,
        privEnc: enc,
      });
    };
    
    KeyPair.prototype.validate = function validate() {
      var pub = this.getPublic();
    
      if (pub.isInfinity())
        return { result: false, reason: 'Invalid public key' };
      if (!pub.validate())
        return { result: false, reason: 'Public key is not a point' };
      if (!pub.mul(this.ec.curve.n).isInfinity())
        return { result: false, reason: 'Public key * N != O' };
    
      return { result: true, reason: null };
    };
    
    KeyPair.prototype.getPublic = function getPublic(compact, enc) {
      // compact is optional argument
      if (typeof compact === 'string') {
        enc = compact;
        compact = null;
      }
    
      if (!this.pub)
        this.pub = this.ec.g.mul(this.priv);
    
      if (!enc)
        return this.pub;
    
      return this.pub.encode(enc, compact);
    };
    
    KeyPair.prototype.getPrivate = function getPrivate(enc) {
      if (enc === 'hex')
        return this.priv.toString(16, 2);
      else
        return this.priv;
    };
    
    KeyPair.prototype._importPrivate = function _importPrivate(key, enc) {
      this.priv = new BN(key, enc || 16);
    
      // Ensure that the priv won't be bigger than n, otherwise we may fail
      // in fixed multiplication method
      this.priv = this.priv.umod(this.ec.curve.n);
    };
    
    KeyPair.prototype._importPublic = function _importPublic(key, enc) {
      if (key.x || key.y) {
        // Montgomery points only have an `x` coordinate.
        // Weierstrass/Edwards points on the other hand have both `x` and
        // `y` coordinates.
        if (this.ec.curve.type === 'mont') {
          assert(key.x, 'Need x coordinate');
        } else if (this.ec.curve.type === 'short' ||
                   this.ec.curve.type === 'edwards') {
          assert(key.x && key.y, 'Need both x and y coordinate');
        }
        this.pub = this.ec.curve.point(key.x, key.y);
        return;
      }
      this.pub = this.ec.curve.decodePoint(key, enc);
    };
    
    // ECDH
    KeyPair.prototype.derive = function derive(pub) {
      if(!pub.validate()) {
        assert(pub.validate(), 'public point not validated');
      }
      return pub.mul(this.priv).getX();
    };
    
    // ECDSA
    KeyPair.prototype.sign = function sign(msg, enc, options) {
      return this.ec.sign(msg, this, enc, options);
    };
    
    KeyPair.prototype.verify = function verify(msg, signature) {
      return this.ec.verify(msg, signature, this);
    };
    
    KeyPair.prototype.inspect = function inspect() {
      return '<Key priv: ' + (this.priv && this.priv.toString(16, 2)) +
             ' pub: ' + (this.pub && this.pub.inspect()) + ' >';
    };
    
    },{"../utils":104,"bn.js":105}],99:[function(require,module,exports){
    'use strict';
    
    var BN = require('bn.js');
    
    var utils = require('../utils');
    var assert = utils.assert;
    
    function Signature(options, enc) {
      if (options instanceof Signature)
        return options;
    
      if (this._importDER(options, enc))
        return;
    
      assert(options.r && options.s, 'Signature without r or s');
      this.r = new BN(options.r, 16);
      this.s = new BN(options.s, 16);
      if (options.recoveryParam === undefined)
        this.recoveryParam = null;
      else
        this.recoveryParam = options.recoveryParam;
    }
    module.exports = Signature;
    
    function Position() {
      this.place = 0;
    }
    
    function getLength(buf, p) {
      var initial = buf[p.place++];
      if (!(initial & 0x80)) {
        return initial;
      }
      var octetLen = initial & 0xf;
    
      // Indefinite length or overflow
      if (octetLen === 0 || octetLen > 4) {
        return false;
      }
    
      var val = 0;
      for (var i = 0, off = p.place; i < octetLen; i++, off++) {
        val <<= 8;
        val |= buf[off];
        val >>>= 0;
      }
    
      // Leading zeroes
      if (val <= 0x7f) {
        return false;
      }
    
      p.place = off;
      return val;
    }
    
    function rmPadding(buf) {
      var i = 0;
      var len = buf.length - 1;
      while (!buf[i] && !(buf[i + 1] & 0x80) && i < len) {
        i++;
      }
      if (i === 0) {
        return buf;
      }
      return buf.slice(i);
    }
    
    Signature.prototype._importDER = function _importDER(data, enc) {
      data = utils.toArray(data, enc);
      var p = new Position();
      if (data[p.place++] !== 0x30) {
        return false;
      }
      var len = getLength(data, p);
      if (len === false) {
        return false;
      }
      if ((len + p.place) !== data.length) {
        return false;
      }
      if (data[p.place++] !== 0x02) {
        return false;
      }
      var rlen = getLength(data, p);
      if (rlen === false) {
        return false;
      }
      var r = data.slice(p.place, rlen + p.place);
      p.place += rlen;
      if (data[p.place++] !== 0x02) {
        return false;
      }
      var slen = getLength(data, p);
      if (slen === false) {
        return false;
      }
      if (data.length !== slen + p.place) {
        return false;
      }
      var s = data.slice(p.place, slen + p.place);
      if (r[0] === 0) {
        if (r[1] & 0x80) {
          r = r.slice(1);
        } else {
          // Leading zeroes
          return false;
        }
      }
      if (s[0] === 0) {
        if (s[1] & 0x80) {
          s = s.slice(1);
        } else {
          // Leading zeroes
          return false;
        }
      }
    
      this.r = new BN(r);
      this.s = new BN(s);
      this.recoveryParam = null;
    
      return true;
    };
    
    function constructLength(arr, len) {
      if (len < 0x80) {
        arr.push(len);
        return;
      }
      var octets = 1 + (Math.log(len) / Math.LN2 >>> 3);
      arr.push(octets | 0x80);
      while (--octets) {
        arr.push((len >>> (octets << 3)) & 0xff);
      }
      arr.push(len);
    }
    
    Signature.prototype.toDER = function toDER(enc) {
      var r = this.r.toArray();
      var s = this.s.toArray();
    
      // Pad values
      if (r[0] & 0x80)
        r = [ 0 ].concat(r);
      // Pad values
      if (s[0] & 0x80)
        s = [ 0 ].concat(s);
    
      r = rmPadding(r);
      s = rmPadding(s);
    
      while (!s[0] && !(s[1] & 0x80)) {
        s = s.slice(1);
      }
      var arr = [ 0x02 ];
      constructLength(arr, r.length);
      arr = arr.concat(r);
      arr.push(0x02);
      constructLength(arr, s.length);
      var backHalf = arr.concat(s);
      var res = [ 0x30 ];
      constructLength(res, backHalf.length);
      res = res.concat(backHalf);
      return utils.encode(res, enc);
    };
    
    },{"../utils":104,"bn.js":105}],100:[function(require,module,exports){
    'use strict';
    
    var hash = require('hash.js');
    var curves = require('../curves');
    var utils = require('../utils');
    var assert = utils.assert;
    var parseBytes = utils.parseBytes;
    var KeyPair = require('./key');
    var Signature = require('./signature');
    
    function EDDSA(curve) {
      assert(curve === 'ed25519', 'only tested with ed25519 so far');
    
      if (!(this instanceof EDDSA))
        return new EDDSA(curve);
    
      curve = curves[curve].curve;
      this.curve = curve;
      this.g = curve.g;
      this.g.precompute(curve.n.bitLength() + 1);
    
      this.pointClass = curve.point().constructor;
      this.encodingLength = Math.ceil(curve.n.bitLength() / 8);
      this.hash = hash.sha512;
    }
    
    module.exports = EDDSA;
    
    /**
    * @param {Array|String} message - message bytes
    * @param {Array|String|KeyPair} secret - secret bytes or a keypair
    * @returns {Signature} - signature
    */
    EDDSA.prototype.sign = function sign(message, secret) {
      message = parseBytes(message);
      var key = this.keyFromSecret(secret);
      var r = this.hashInt(key.messagePrefix(), message);
      var R = this.g.mul(r);
      var Rencoded = this.encodePoint(R);
      var s_ = this.hashInt(Rencoded, key.pubBytes(), message)
        .mul(key.priv());
      var S = r.add(s_).umod(this.curve.n);
      return this.makeSignature({ R: R, S: S, Rencoded: Rencoded });
    };
    
    /**
    * @param {Array} message - message bytes
    * @param {Array|String|Signature} sig - sig bytes
    * @param {Array|String|Point|KeyPair} pub - public key
    * @returns {Boolean} - true if public key matches sig of message
    */
    EDDSA.prototype.verify = function verify(message, sig, pub) {
      message = parseBytes(message);
      sig = this.makeSignature(sig);
      var key = this.keyFromPublic(pub);
      var h = this.hashInt(sig.Rencoded(), key.pubBytes(), message);
      var SG = this.g.mul(sig.S());
      var RplusAh = sig.R().add(key.pub().mul(h));
      return RplusAh.eq(SG);
    };
    
    EDDSA.prototype.hashInt = function hashInt() {
      var hash = this.hash();
      for (var i = 0; i < arguments.length; i++)
        hash.update(arguments[i]);
      return utils.intFromLE(hash.digest()).umod(this.curve.n);
    };
    
    EDDSA.prototype.keyFromPublic = function keyFromPublic(pub) {
      return KeyPair.fromPublic(this, pub);
    };
    
    EDDSA.prototype.keyFromSecret = function keyFromSecret(secret) {
      return KeyPair.fromSecret(this, secret);
    };
    
    EDDSA.prototype.makeSignature = function makeSignature(sig) {
      if (sig instanceof Signature)
        return sig;
      return new Signature(this, sig);
    };
    
    /**
    * * https://tools.ietf.org/html/draft-josefsson-eddsa-ed25519-03#section-5.2
    *
    * EDDSA defines methods for encoding and decoding points and integers. These are
    * helper convenience methods, that pass along to utility functions implied
    * parameters.
    *
    */
    EDDSA.prototype.encodePoint = function encodePoint(point) {
      var enc = point.getY().toArray('le', this.encodingLength);
      enc[this.encodingLength - 1] |= point.getX().isOdd() ? 0x80 : 0;
      return enc;
    };
    
    EDDSA.prototype.decodePoint = function decodePoint(bytes) {
      bytes = utils.parseBytes(bytes);
    
      var lastIx = bytes.length - 1;
      var normed = bytes.slice(0, lastIx).concat(bytes[lastIx] & ~0x80);
      var xIsOdd = (bytes[lastIx] & 0x80) !== 0;
    
      var y = utils.intFromLE(normed);
      return this.curve.pointFromY(y, xIsOdd);
    };
    
    EDDSA.prototype.encodeInt = function encodeInt(num) {
      return num.toArray('le', this.encodingLength);
    };
    
    EDDSA.prototype.decodeInt = function decodeInt(bytes) {
      return utils.intFromLE(bytes);
    };
    
    EDDSA.prototype.isPoint = function isPoint(val) {
      return val instanceof this.pointClass;
    };
    
    },{"../curves":96,"../utils":104,"./key":101,"./signature":102,"hash.js":135}],101:[function(require,module,exports){
    'use strict';
    
    var utils = require('../utils');
    var assert = utils.assert;
    var parseBytes = utils.parseBytes;
    var cachedProperty = utils.cachedProperty;
    
    /**
    * @param {EDDSA} eddsa - instance
    * @param {Object} params - public/private key parameters
    *
    * @param {Array<Byte>} [params.secret] - secret seed bytes
    * @param {Point} [params.pub] - public key point (aka `A` in eddsa terms)
    * @param {Array<Byte>} [params.pub] - public key point encoded as bytes
    *
    */
    function KeyPair(eddsa, params) {
      this.eddsa = eddsa;
      this._secret = parseBytes(params.secret);
      if (eddsa.isPoint(params.pub))
        this._pub = params.pub;
      else
        this._pubBytes = parseBytes(params.pub);
    }
    
    KeyPair.fromPublic = function fromPublic(eddsa, pub) {
      if (pub instanceof KeyPair)
        return pub;
      return new KeyPair(eddsa, { pub: pub });
    };
    
    KeyPair.fromSecret = function fromSecret(eddsa, secret) {
      if (secret instanceof KeyPair)
        return secret;
      return new KeyPair(eddsa, { secret: secret });
    };
    
    KeyPair.prototype.secret = function secret() {
      return this._secret;
    };
    
    cachedProperty(KeyPair, 'pubBytes', function pubBytes() {
      return this.eddsa.encodePoint(this.pub());
    });
    
    cachedProperty(KeyPair, 'pub', function pub() {
      if (this._pubBytes)
        return this.eddsa.decodePoint(this._pubBytes);
      return this.eddsa.g.mul(this.priv());
    });
    
    cachedProperty(KeyPair, 'privBytes', function privBytes() {
      var eddsa = this.eddsa;
      var hash = this.hash();
      var lastIx = eddsa.encodingLength - 1;
    
      var a = hash.slice(0, eddsa.encodingLength);
      a[0] &= 248;
      a[lastIx] &= 127;
      a[lastIx] |= 64;
    
      return a;
    });
    
    cachedProperty(KeyPair, 'priv', function priv() {
      return this.eddsa.decodeInt(this.privBytes());
    });
    
    cachedProperty(KeyPair, 'hash', function hash() {
      return this.eddsa.hash().update(this.secret()).digest();
    });
    
    cachedProperty(KeyPair, 'messagePrefix', function messagePrefix() {
      return this.hash().slice(this.eddsa.encodingLength);
    });
    
    KeyPair.prototype.sign = function sign(message) {
      assert(this._secret, 'KeyPair can only verify');
      return this.eddsa.sign(message, this);
    };
    
    KeyPair.prototype.verify = function verify(message, sig) {
      return this.eddsa.verify(message, sig, this);
    };
    
    KeyPair.prototype.getSecret = function getSecret(enc) {
      assert(this._secret, 'KeyPair is public only');
      return utils.encode(this.secret(), enc);
    };
    
    KeyPair.prototype.getPublic = function getPublic(enc) {
      return utils.encode(this.pubBytes(), enc);
    };
    
    module.exports = KeyPair;
    
    },{"../utils":104}],102:[function(require,module,exports){
    'use strict';
    
    var BN = require('bn.js');
    var utils = require('../utils');
    var assert = utils.assert;
    var cachedProperty = utils.cachedProperty;
    var parseBytes = utils.parseBytes;
    
    /**
    * @param {EDDSA} eddsa - eddsa instance
    * @param {Array<Bytes>|Object} sig -
    * @param {Array<Bytes>|Point} [sig.R] - R point as Point or bytes
    * @param {Array<Bytes>|bn} [sig.S] - S scalar as bn or bytes
    * @param {Array<Bytes>} [sig.Rencoded] - R point encoded
    * @param {Array<Bytes>} [sig.Sencoded] - S scalar encoded
    */
    function Signature(eddsa, sig) {
      this.eddsa = eddsa;
    
      if (typeof sig !== 'object')
        sig = parseBytes(sig);
    
      if (Array.isArray(sig)) {
        sig = {
          R: sig.slice(0, eddsa.encodingLength),
          S: sig.slice(eddsa.encodingLength),
        };
      }
    
      assert(sig.R && sig.S, 'Signature without R or S');
    
      if (eddsa.isPoint(sig.R))
        this._R = sig.R;
      if (sig.S instanceof BN)
        this._S = sig.S;
    
      this._Rencoded = Array.isArray(sig.R) ? sig.R : sig.Rencoded;
      this._Sencoded = Array.isArray(sig.S) ? sig.S : sig.Sencoded;
    }
    
    cachedProperty(Signature, 'S', function S() {
      return this.eddsa.decodeInt(this.Sencoded());
    });
    
    cachedProperty(Signature, 'R', function R() {
      return this.eddsa.decodePoint(this.Rencoded());
    });
    
    cachedProperty(Signature, 'Rencoded', function Rencoded() {
      return this.eddsa.encodePoint(this.R());
    });
    
    cachedProperty(Signature, 'Sencoded', function Sencoded() {
      return this.eddsa.encodeInt(this.S());
    });
    
    Signature.prototype.toBytes = function toBytes() {
      return this.Rencoded().concat(this.Sencoded());
    };
    
    Signature.prototype.toHex = function toHex() {
      return utils.encode(this.toBytes(), 'hex').toUpperCase();
    };
    
    module.exports = Signature;
    
    },{"../utils":104,"bn.js":105}],103:[function(require,module,exports){
    module.exports = {
      doubles: {
        step: 4,
        points: [
          [
            'e60fce93b59e9ec53011aabc21c23e97b2a31369b87a5ae9c44ee89e2a6dec0a',
            'f7e3507399e595929db99f34f57937101296891e44d23f0be1f32cce69616821',
          ],
          [
            '8282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508',
            '11f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf',
          ],
          [
            '175e159f728b865a72f99cc6c6fc846de0b93833fd2222ed73fce5b551e5b739',
            'd3506e0d9e3c79eba4ef97a51ff71f5eacb5955add24345c6efa6ffee9fed695',
          ],
          [
            '363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640',
            '4e273adfc732221953b445397f3363145b9a89008199ecb62003c7f3bee9de9',
          ],
          [
            '8b4b5f165df3c2be8c6244b5b745638843e4a781a15bcd1b69f79a55dffdf80c',
            '4aad0a6f68d308b4b3fbd7813ab0da04f9e336546162ee56b3eff0c65fd4fd36',
          ],
          [
            '723cbaa6e5db996d6bf771c00bd548c7b700dbffa6c0e77bcb6115925232fcda',
            '96e867b5595cc498a921137488824d6e2660a0653779494801dc069d9eb39f5f',
          ],
          [
            'eebfa4d493bebf98ba5feec812c2d3b50947961237a919839a533eca0e7dd7fa',
            '5d9a8ca3970ef0f269ee7edaf178089d9ae4cdc3a711f712ddfd4fdae1de8999',
          ],
          [
            '100f44da696e71672791d0a09b7bde459f1215a29b3c03bfefd7835b39a48db0',
            'cdd9e13192a00b772ec8f3300c090666b7ff4a18ff5195ac0fbd5cd62bc65a09',
          ],
          [
            'e1031be262c7ed1b1dc9227a4a04c017a77f8d4464f3b3852c8acde6e534fd2d',
            '9d7061928940405e6bb6a4176597535af292dd419e1ced79a44f18f29456a00d',
          ],
          [
            'feea6cae46d55b530ac2839f143bd7ec5cf8b266a41d6af52d5e688d9094696d',
            'e57c6b6c97dce1bab06e4e12bf3ecd5c981c8957cc41442d3155debf18090088',
          ],
          [
            'da67a91d91049cdcb367be4be6ffca3cfeed657d808583de33fa978bc1ec6cb1',
            '9bacaa35481642bc41f463f7ec9780e5dec7adc508f740a17e9ea8e27a68be1d',
          ],
          [
            '53904faa0b334cdda6e000935ef22151ec08d0f7bb11069f57545ccc1a37b7c0',
            '5bc087d0bc80106d88c9eccac20d3c1c13999981e14434699dcb096b022771c8',
          ],
          [
            '8e7bcd0bd35983a7719cca7764ca906779b53a043a9b8bcaeff959f43ad86047',
            '10b7770b2a3da4b3940310420ca9514579e88e2e47fd68b3ea10047e8460372a',
          ],
          [
            '385eed34c1cdff21e6d0818689b81bde71a7f4f18397e6690a841e1599c43862',
            '283bebc3e8ea23f56701de19e9ebf4576b304eec2086dc8cc0458fe5542e5453',
          ],
          [
            '6f9d9b803ecf191637c73a4413dfa180fddf84a5947fbc9c606ed86c3fac3a7',
            '7c80c68e603059ba69b8e2a30e45c4d47ea4dd2f5c281002d86890603a842160',
          ],
          [
            '3322d401243c4e2582a2147c104d6ecbf774d163db0f5e5313b7e0e742d0e6bd',
            '56e70797e9664ef5bfb019bc4ddaf9b72805f63ea2873af624f3a2e96c28b2a0',
          ],
          [
            '85672c7d2de0b7da2bd1770d89665868741b3f9af7643397721d74d28134ab83',
            '7c481b9b5b43b2eb6374049bfa62c2e5e77f17fcc5298f44c8e3094f790313a6',
          ],
          [
            '948bf809b1988a46b06c9f1919413b10f9226c60f668832ffd959af60c82a0a',
            '53a562856dcb6646dc6b74c5d1c3418c6d4dff08c97cd2bed4cb7f88d8c8e589',
          ],
          [
            '6260ce7f461801c34f067ce0f02873a8f1b0e44dfc69752accecd819f38fd8e8',
            'bc2da82b6fa5b571a7f09049776a1ef7ecd292238051c198c1a84e95b2b4ae17',
          ],
          [
            'e5037de0afc1d8d43d8348414bbf4103043ec8f575bfdc432953cc8d2037fa2d',
            '4571534baa94d3b5f9f98d09fb990bddbd5f5b03ec481f10e0e5dc841d755bda',
          ],
          [
            'e06372b0f4a207adf5ea905e8f1771b4e7e8dbd1c6a6c5b725866a0ae4fce725',
            '7a908974bce18cfe12a27bb2ad5a488cd7484a7787104870b27034f94eee31dd',
          ],
          [
            '213c7a715cd5d45358d0bbf9dc0ce02204b10bdde2a3f58540ad6908d0559754',
            '4b6dad0b5ae462507013ad06245ba190bb4850f5f36a7eeddff2c27534b458f2',
          ],
          [
            '4e7c272a7af4b34e8dbb9352a5419a87e2838c70adc62cddf0cc3a3b08fbd53c',
            '17749c766c9d0b18e16fd09f6def681b530b9614bff7dd33e0b3941817dcaae6',
          ],
          [
            'fea74e3dbe778b1b10f238ad61686aa5c76e3db2be43057632427e2840fb27b6',
            '6e0568db9b0b13297cf674deccb6af93126b596b973f7b77701d3db7f23cb96f',
          ],
          [
            '76e64113f677cf0e10a2570d599968d31544e179b760432952c02a4417bdde39',
            'c90ddf8dee4e95cf577066d70681f0d35e2a33d2b56d2032b4b1752d1901ac01',
          ],
          [
            'c738c56b03b2abe1e8281baa743f8f9a8f7cc643df26cbee3ab150242bcbb891',
            '893fb578951ad2537f718f2eacbfbbbb82314eef7880cfe917e735d9699a84c3',
          ],
          [
            'd895626548b65b81e264c7637c972877d1d72e5f3a925014372e9f6588f6c14b',
            'febfaa38f2bc7eae728ec60818c340eb03428d632bb067e179363ed75d7d991f',
          ],
          [
            'b8da94032a957518eb0f6433571e8761ceffc73693e84edd49150a564f676e03',
            '2804dfa44805a1e4d7c99cc9762808b092cc584d95ff3b511488e4e74efdf6e7',
          ],
          [
            'e80fea14441fb33a7d8adab9475d7fab2019effb5156a792f1a11778e3c0df5d',
            'eed1de7f638e00771e89768ca3ca94472d155e80af322ea9fcb4291b6ac9ec78',
          ],
          [
            'a301697bdfcd704313ba48e51d567543f2a182031efd6915ddc07bbcc4e16070',
            '7370f91cfb67e4f5081809fa25d40f9b1735dbf7c0a11a130c0d1a041e177ea1',
          ],
          [
            '90ad85b389d6b936463f9d0512678de208cc330b11307fffab7ac63e3fb04ed4',
            'e507a3620a38261affdcbd9427222b839aefabe1582894d991d4d48cb6ef150',
          ],
          [
            '8f68b9d2f63b5f339239c1ad981f162ee88c5678723ea3351b7b444c9ec4c0da',
            '662a9f2dba063986de1d90c2b6be215dbbea2cfe95510bfdf23cbf79501fff82',
          ],
          [
            'e4f3fb0176af85d65ff99ff9198c36091f48e86503681e3e6686fd5053231e11',
            '1e63633ad0ef4f1c1661a6d0ea02b7286cc7e74ec951d1c9822c38576feb73bc',
          ],
          [
            '8c00fa9b18ebf331eb961537a45a4266c7034f2f0d4e1d0716fb6eae20eae29e',
            'efa47267fea521a1a9dc343a3736c974c2fadafa81e36c54e7d2a4c66702414b',
          ],
          [
            'e7a26ce69dd4829f3e10cec0a9e98ed3143d084f308b92c0997fddfc60cb3e41',
            '2a758e300fa7984b471b006a1aafbb18d0a6b2c0420e83e20e8a9421cf2cfd51',
          ],
          [
            'b6459e0ee3662ec8d23540c223bcbdc571cbcb967d79424f3cf29eb3de6b80ef',
            '67c876d06f3e06de1dadf16e5661db3c4b3ae6d48e35b2ff30bf0b61a71ba45',
          ],
          [
            'd68a80c8280bb840793234aa118f06231d6f1fc67e73c5a5deda0f5b496943e8',
            'db8ba9fff4b586d00c4b1f9177b0e28b5b0e7b8f7845295a294c84266b133120',
          ],
          [
            '324aed7df65c804252dc0270907a30b09612aeb973449cea4095980fc28d3d5d',
            '648a365774b61f2ff130c0c35aec1f4f19213b0c7e332843967224af96ab7c84',
          ],
          [
            '4df9c14919cde61f6d51dfdbe5fee5dceec4143ba8d1ca888e8bd373fd054c96',
            '35ec51092d8728050974c23a1d85d4b5d506cdc288490192ebac06cad10d5d',
          ],
          [
            '9c3919a84a474870faed8a9c1cc66021523489054d7f0308cbfc99c8ac1f98cd',
            'ddb84f0f4a4ddd57584f044bf260e641905326f76c64c8e6be7e5e03d4fc599d',
          ],
          [
            '6057170b1dd12fdf8de05f281d8e06bb91e1493a8b91d4cc5a21382120a959e5',
            '9a1af0b26a6a4807add9a2daf71df262465152bc3ee24c65e899be932385a2a8',
          ],
          [
            'a576df8e23a08411421439a4518da31880cef0fba7d4df12b1a6973eecb94266',
            '40a6bf20e76640b2c92b97afe58cd82c432e10a7f514d9f3ee8be11ae1b28ec8',
          ],
          [
            '7778a78c28dec3e30a05fe9629de8c38bb30d1f5cf9a3a208f763889be58ad71',
            '34626d9ab5a5b22ff7098e12f2ff580087b38411ff24ac563b513fc1fd9f43ac',
          ],
          [
            '928955ee637a84463729fd30e7afd2ed5f96274e5ad7e5cb09eda9c06d903ac',
            'c25621003d3f42a827b78a13093a95eeac3d26efa8a8d83fc5180e935bcd091f',
          ],
          [
            '85d0fef3ec6db109399064f3a0e3b2855645b4a907ad354527aae75163d82751',
            '1f03648413a38c0be29d496e582cf5663e8751e96877331582c237a24eb1f962',
          ],
          [
            'ff2b0dce97eece97c1c9b6041798b85dfdfb6d8882da20308f5404824526087e',
            '493d13fef524ba188af4c4dc54d07936c7b7ed6fb90e2ceb2c951e01f0c29907',
          ],
          [
            '827fbbe4b1e880ea9ed2b2e6301b212b57f1ee148cd6dd28780e5e2cf856e241',
            'c60f9c923c727b0b71bef2c67d1d12687ff7a63186903166d605b68baec293ec',
          ],
          [
            'eaa649f21f51bdbae7be4ae34ce6e5217a58fdce7f47f9aa7f3b58fa2120e2b3',
            'be3279ed5bbbb03ac69a80f89879aa5a01a6b965f13f7e59d47a5305ba5ad93d',
          ],
          [
            'e4a42d43c5cf169d9391df6decf42ee541b6d8f0c9a137401e23632dda34d24f',
            '4d9f92e716d1c73526fc99ccfb8ad34ce886eedfa8d8e4f13a7f7131deba9414',
          ],
          [
            '1ec80fef360cbdd954160fadab352b6b92b53576a88fea4947173b9d4300bf19',
            'aeefe93756b5340d2f3a4958a7abbf5e0146e77f6295a07b671cdc1cc107cefd',
          ],
          [
            '146a778c04670c2f91b00af4680dfa8bce3490717d58ba889ddb5928366642be',
            'b318e0ec3354028add669827f9d4b2870aaa971d2f7e5ed1d0b297483d83efd0',
          ],
          [
            'fa50c0f61d22e5f07e3acebb1aa07b128d0012209a28b9776d76a8793180eef9',
            '6b84c6922397eba9b72cd2872281a68a5e683293a57a213b38cd8d7d3f4f2811',
          ],
          [
            'da1d61d0ca721a11b1a5bf6b7d88e8421a288ab5d5bba5220e53d32b5f067ec2',
            '8157f55a7c99306c79c0766161c91e2966a73899d279b48a655fba0f1ad836f1',
          ],
          [
            'a8e282ff0c9706907215ff98e8fd416615311de0446f1e062a73b0610d064e13',
            '7f97355b8db81c09abfb7f3c5b2515888b679a3e50dd6bd6cef7c73111f4cc0c',
          ],
          [
            '174a53b9c9a285872d39e56e6913cab15d59b1fa512508c022f382de8319497c',
            'ccc9dc37abfc9c1657b4155f2c47f9e6646b3a1d8cb9854383da13ac079afa73',
          ],
          [
            '959396981943785c3d3e57edf5018cdbe039e730e4918b3d884fdff09475b7ba',
            '2e7e552888c331dd8ba0386a4b9cd6849c653f64c8709385e9b8abf87524f2fd',
          ],
          [
            'd2a63a50ae401e56d645a1153b109a8fcca0a43d561fba2dbb51340c9d82b151',
            'e82d86fb6443fcb7565aee58b2948220a70f750af484ca52d4142174dcf89405',
          ],
          [
            '64587e2335471eb890ee7896d7cfdc866bacbdbd3839317b3436f9b45617e073',
            'd99fcdd5bf6902e2ae96dd6447c299a185b90a39133aeab358299e5e9faf6589',
          ],
          [
            '8481bde0e4e4d885b3a546d3e549de042f0aa6cea250e7fd358d6c86dd45e458',
            '38ee7b8cba5404dd84a25bf39cecb2ca900a79c42b262e556d64b1b59779057e',
          ],
          [
            '13464a57a78102aa62b6979ae817f4637ffcfed3c4b1ce30bcd6303f6caf666b',
            '69be159004614580ef7e433453ccb0ca48f300a81d0942e13f495a907f6ecc27',
          ],
          [
            'bc4a9df5b713fe2e9aef430bcc1dc97a0cd9ccede2f28588cada3a0d2d83f366',
            'd3a81ca6e785c06383937adf4b798caa6e8a9fbfa547b16d758d666581f33c1',
          ],
          [
            '8c28a97bf8298bc0d23d8c749452a32e694b65e30a9472a3954ab30fe5324caa',
            '40a30463a3305193378fedf31f7cc0eb7ae784f0451cb9459e71dc73cbef9482',
          ],
          [
            '8ea9666139527a8c1dd94ce4f071fd23c8b350c5a4bb33748c4ba111faccae0',
            '620efabbc8ee2782e24e7c0cfb95c5d735b783be9cf0f8e955af34a30e62b945',
          ],
          [
            'dd3625faef5ba06074669716bbd3788d89bdde815959968092f76cc4eb9a9787',
            '7a188fa3520e30d461da2501045731ca941461982883395937f68d00c644a573',
          ],
          [
            'f710d79d9eb962297e4f6232b40e8f7feb2bc63814614d692c12de752408221e',
            'ea98e67232d3b3295d3b535532115ccac8612c721851617526ae47a9c77bfc82',
          ],
        ],
      },
      naf: {
        wnd: 7,
        points: [
          [
            'f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9',
            '388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e672',
          ],
          [
            '2f8bde4d1a07209355b4a7250a5c5128e88b84bddc619ab7cba8d569b240efe4',
            'd8ac222636e5e3d6d4dba9dda6c9c426f788271bab0d6840dca87d3aa6ac62d6',
          ],
          [
            '5cbdf0646e5db4eaa398f365f2ea7a0e3d419b7e0330e39ce92bddedcac4f9bc',
            '6aebca40ba255960a3178d6d861a54dba813d0b813fde7b5a5082628087264da',
          ],
          [
            'acd484e2f0c7f65309ad178a9f559abde09796974c57e714c35f110dfc27ccbe',
            'cc338921b0a7d9fd64380971763b61e9add888a4375f8e0f05cc262ac64f9c37',
          ],
          [
            '774ae7f858a9411e5ef4246b70c65aac5649980be5c17891bbec17895da008cb',
            'd984a032eb6b5e190243dd56d7b7b365372db1e2dff9d6a8301d74c9c953c61b',
          ],
          [
            'f28773c2d975288bc7d1d205c3748651b075fbc6610e58cddeeddf8f19405aa8',
            'ab0902e8d880a89758212eb65cdaf473a1a06da521fa91f29b5cb52db03ed81',
          ],
          [
            'd7924d4f7d43ea965a465ae3095ff41131e5946f3c85f79e44adbcf8e27e080e',
            '581e2872a86c72a683842ec228cc6defea40af2bd896d3a5c504dc9ff6a26b58',
          ],
          [
            'defdea4cdb677750a420fee807eacf21eb9898ae79b9768766e4faa04a2d4a34',
            '4211ab0694635168e997b0ead2a93daeced1f4a04a95c0f6cfb199f69e56eb77',
          ],
          [
            '2b4ea0a797a443d293ef5cff444f4979f06acfebd7e86d277475656138385b6c',
            '85e89bc037945d93b343083b5a1c86131a01f60c50269763b570c854e5c09b7a',
          ],
          [
            '352bbf4a4cdd12564f93fa332ce333301d9ad40271f8107181340aef25be59d5',
            '321eb4075348f534d59c18259dda3e1f4a1b3b2e71b1039c67bd3d8bcf81998c',
          ],
          [
            '2fa2104d6b38d11b0230010559879124e42ab8dfeff5ff29dc9cdadd4ecacc3f',
            '2de1068295dd865b64569335bd5dd80181d70ecfc882648423ba76b532b7d67',
          ],
          [
            '9248279b09b4d68dab21a9b066edda83263c3d84e09572e269ca0cd7f5453714',
            '73016f7bf234aade5d1aa71bdea2b1ff3fc0de2a887912ffe54a32ce97cb3402',
          ],
          [
            'daed4f2be3a8bf278e70132fb0beb7522f570e144bf615c07e996d443dee8729',
            'a69dce4a7d6c98e8d4a1aca87ef8d7003f83c230f3afa726ab40e52290be1c55',
          ],
          [
            'c44d12c7065d812e8acf28d7cbb19f9011ecd9e9fdf281b0e6a3b5e87d22e7db',
            '2119a460ce326cdc76c45926c982fdac0e106e861edf61c5a039063f0e0e6482',
          ],
          [
            '6a245bf6dc698504c89a20cfded60853152b695336c28063b61c65cbd269e6b4',
            'e022cf42c2bd4a708b3f5126f16a24ad8b33ba48d0423b6efd5e6348100d8a82',
          ],
          [
            '1697ffa6fd9de627c077e3d2fe541084ce13300b0bec1146f95ae57f0d0bd6a5',
            'b9c398f186806f5d27561506e4557433a2cf15009e498ae7adee9d63d01b2396',
          ],
          [
            '605bdb019981718b986d0f07e834cb0d9deb8360ffb7f61df982345ef27a7479',
            '2972d2de4f8d20681a78d93ec96fe23c26bfae84fb14db43b01e1e9056b8c49',
          ],
          [
            '62d14dab4150bf497402fdc45a215e10dcb01c354959b10cfe31c7e9d87ff33d',
            '80fc06bd8cc5b01098088a1950eed0db01aa132967ab472235f5642483b25eaf',
          ],
          [
            '80c60ad0040f27dade5b4b06c408e56b2c50e9f56b9b8b425e555c2f86308b6f',
            '1c38303f1cc5c30f26e66bad7fe72f70a65eed4cbe7024eb1aa01f56430bd57a',
          ],
          [
            '7a9375ad6167ad54aa74c6348cc54d344cc5dc9487d847049d5eabb0fa03c8fb',
            'd0e3fa9eca8726909559e0d79269046bdc59ea10c70ce2b02d499ec224dc7f7',
          ],
          [
            'd528ecd9b696b54c907a9ed045447a79bb408ec39b68df504bb51f459bc3ffc9',
            'eecf41253136e5f99966f21881fd656ebc4345405c520dbc063465b521409933',
          ],
          [
            '49370a4b5f43412ea25f514e8ecdad05266115e4a7ecb1387231808f8b45963',
            '758f3f41afd6ed428b3081b0512fd62a54c3f3afbb5b6764b653052a12949c9a',
          ],
          [
            '77f230936ee88cbbd73df930d64702ef881d811e0e1498e2f1c13eb1fc345d74',
            '958ef42a7886b6400a08266e9ba1b37896c95330d97077cbbe8eb3c7671c60d6',
          ],
          [
            'f2dac991cc4ce4b9ea44887e5c7c0bce58c80074ab9d4dbaeb28531b7739f530',
            'e0dedc9b3b2f8dad4da1f32dec2531df9eb5fbeb0598e4fd1a117dba703a3c37',
          ],
          [
            '463b3d9f662621fb1b4be8fbbe2520125a216cdfc9dae3debcba4850c690d45b',
            '5ed430d78c296c3543114306dd8622d7c622e27c970a1de31cb377b01af7307e',
          ],
          [
            'f16f804244e46e2a09232d4aff3b59976b98fac14328a2d1a32496b49998f247',
            'cedabd9b82203f7e13d206fcdf4e33d92a6c53c26e5cce26d6579962c4e31df6',
          ],
          [
            'caf754272dc84563b0352b7a14311af55d245315ace27c65369e15f7151d41d1',
            'cb474660ef35f5f2a41b643fa5e460575f4fa9b7962232a5c32f908318a04476',
          ],
          [
            '2600ca4b282cb986f85d0f1709979d8b44a09c07cb86d7c124497bc86f082120',
            '4119b88753c15bd6a693b03fcddbb45d5ac6be74ab5f0ef44b0be9475a7e4b40',
          ],
          [
            '7635ca72d7e8432c338ec53cd12220bc01c48685e24f7dc8c602a7746998e435',
            '91b649609489d613d1d5e590f78e6d74ecfc061d57048bad9e76f302c5b9c61',
          ],
          [
            '754e3239f325570cdbbf4a87deee8a66b7f2b33479d468fbc1a50743bf56cc18',
            '673fb86e5bda30fb3cd0ed304ea49a023ee33d0197a695d0c5d98093c536683',
          ],
          [
            'e3e6bd1071a1e96aff57859c82d570f0330800661d1c952f9fe2694691d9b9e8',
            '59c9e0bba394e76f40c0aa58379a3cb6a5a2283993e90c4167002af4920e37f5',
          ],
          [
            '186b483d056a033826ae73d88f732985c4ccb1f32ba35f4b4cc47fdcf04aa6eb',
            '3b952d32c67cf77e2e17446e204180ab21fb8090895138b4a4a797f86e80888b',
          ],
          [
            'df9d70a6b9876ce544c98561f4be4f725442e6d2b737d9c91a8321724ce0963f',
            '55eb2dafd84d6ccd5f862b785dc39d4ab157222720ef9da217b8c45cf2ba2417',
          ],
          [
            '5edd5cc23c51e87a497ca815d5dce0f8ab52554f849ed8995de64c5f34ce7143',
            'efae9c8dbc14130661e8cec030c89ad0c13c66c0d17a2905cdc706ab7399a868',
          ],
          [
            '290798c2b6476830da12fe02287e9e777aa3fba1c355b17a722d362f84614fba',
            'e38da76dcd440621988d00bcf79af25d5b29c094db2a23146d003afd41943e7a',
          ],
          [
            'af3c423a95d9f5b3054754efa150ac39cd29552fe360257362dfdecef4053b45',
            'f98a3fd831eb2b749a93b0e6f35cfb40c8cd5aa667a15581bc2feded498fd9c6',
          ],
          [
            '766dbb24d134e745cccaa28c99bf274906bb66b26dcf98df8d2fed50d884249a',
            '744b1152eacbe5e38dcc887980da38b897584a65fa06cedd2c924f97cbac5996',
          ],
          [
            '59dbf46f8c94759ba21277c33784f41645f7b44f6c596a58ce92e666191abe3e',
            'c534ad44175fbc300f4ea6ce648309a042ce739a7919798cd85e216c4a307f6e',
          ],
          [
            'f13ada95103c4537305e691e74e9a4a8dd647e711a95e73cb62dc6018cfd87b8',
            'e13817b44ee14de663bf4bc808341f326949e21a6a75c2570778419bdaf5733d',
          ],
          [
            '7754b4fa0e8aced06d4167a2c59cca4cda1869c06ebadfb6488550015a88522c',
            '30e93e864e669d82224b967c3020b8fa8d1e4e350b6cbcc537a48b57841163a2',
          ],
          [
            '948dcadf5990e048aa3874d46abef9d701858f95de8041d2a6828c99e2262519',
            'e491a42537f6e597d5d28a3224b1bc25df9154efbd2ef1d2cbba2cae5347d57e',
          ],
          [
            '7962414450c76c1689c7b48f8202ec37fb224cf5ac0bfa1570328a8a3d7c77ab',
            '100b610ec4ffb4760d5c1fc133ef6f6b12507a051f04ac5760afa5b29db83437',
          ],
          [
            '3514087834964b54b15b160644d915485a16977225b8847bb0dd085137ec47ca',
            'ef0afbb2056205448e1652c48e8127fc6039e77c15c2378b7e7d15a0de293311',
          ],
          [
            'd3cc30ad6b483e4bc79ce2c9dd8bc54993e947eb8df787b442943d3f7b527eaf',
            '8b378a22d827278d89c5e9be8f9508ae3c2ad46290358630afb34db04eede0a4',
          ],
          [
            '1624d84780732860ce1c78fcbfefe08b2b29823db913f6493975ba0ff4847610',
            '68651cf9b6da903e0914448c6cd9d4ca896878f5282be4c8cc06e2a404078575',
          ],
          [
            '733ce80da955a8a26902c95633e62a985192474b5af207da6df7b4fd5fc61cd4',
            'f5435a2bd2badf7d485a4d8b8db9fcce3e1ef8e0201e4578c54673bc1dc5ea1d',
          ],
          [
            '15d9441254945064cf1a1c33bbd3b49f8966c5092171e699ef258dfab81c045c',
            'd56eb30b69463e7234f5137b73b84177434800bacebfc685fc37bbe9efe4070d',
          ],
          [
            'a1d0fcf2ec9de675b612136e5ce70d271c21417c9d2b8aaaac138599d0717940',
            'edd77f50bcb5a3cab2e90737309667f2641462a54070f3d519212d39c197a629',
          ],
          [
            'e22fbe15c0af8ccc5780c0735f84dbe9a790badee8245c06c7ca37331cb36980',
            'a855babad5cd60c88b430a69f53a1a7a38289154964799be43d06d77d31da06',
          ],
          [
            '311091dd9860e8e20ee13473c1155f5f69635e394704eaa74009452246cfa9b3',
            '66db656f87d1f04fffd1f04788c06830871ec5a64feee685bd80f0b1286d8374',
          ],
          [
            '34c1fd04d301be89b31c0442d3e6ac24883928b45a9340781867d4232ec2dbdf',
            '9414685e97b1b5954bd46f730174136d57f1ceeb487443dc5321857ba73abee',
          ],
          [
            'f219ea5d6b54701c1c14de5b557eb42a8d13f3abbcd08affcc2a5e6b049b8d63',
            '4cb95957e83d40b0f73af4544cccf6b1f4b08d3c07b27fb8d8c2962a400766d1',
          ],
          [
            'd7b8740f74a8fbaab1f683db8f45de26543a5490bca627087236912469a0b448',
            'fa77968128d9c92ee1010f337ad4717eff15db5ed3c049b3411e0315eaa4593b',
          ],
          [
            '32d31c222f8f6f0ef86f7c98d3a3335ead5bcd32abdd94289fe4d3091aa824bf',
            '5f3032f5892156e39ccd3d7915b9e1da2e6dac9e6f26e961118d14b8462e1661',
          ],
          [
            '7461f371914ab32671045a155d9831ea8793d77cd59592c4340f86cbc18347b5',
            '8ec0ba238b96bec0cbdddcae0aa442542eee1ff50c986ea6b39847b3cc092ff6',
          ],
          [
            'ee079adb1df1860074356a25aa38206a6d716b2c3e67453d287698bad7b2b2d6',
            '8dc2412aafe3be5c4c5f37e0ecc5f9f6a446989af04c4e25ebaac479ec1c8c1e',
          ],
          [
            '16ec93e447ec83f0467b18302ee620f7e65de331874c9dc72bfd8616ba9da6b5',
            '5e4631150e62fb40d0e8c2a7ca5804a39d58186a50e497139626778e25b0674d',
          ],
          [
            'eaa5f980c245f6f038978290afa70b6bd8855897f98b6aa485b96065d537bd99',
            'f65f5d3e292c2e0819a528391c994624d784869d7e6ea67fb18041024edc07dc',
          ],
          [
            '78c9407544ac132692ee1910a02439958ae04877151342ea96c4b6b35a49f51',
            'f3e0319169eb9b85d5404795539a5e68fa1fbd583c064d2462b675f194a3ddb4',
          ],
          [
            '494f4be219a1a77016dcd838431aea0001cdc8ae7a6fc688726578d9702857a5',
            '42242a969283a5f339ba7f075e36ba2af925ce30d767ed6e55f4b031880d562c',
          ],
          [
            'a598a8030da6d86c6bc7f2f5144ea549d28211ea58faa70ebf4c1e665c1fe9b5',
            '204b5d6f84822c307e4b4a7140737aec23fc63b65b35f86a10026dbd2d864e6b',
          ],
          [
            'c41916365abb2b5d09192f5f2dbeafec208f020f12570a184dbadc3e58595997',
            '4f14351d0087efa49d245b328984989d5caf9450f34bfc0ed16e96b58fa9913',
          ],
          [
            '841d6063a586fa475a724604da03bc5b92a2e0d2e0a36acfe4c73a5514742881',
            '73867f59c0659e81904f9a1c7543698e62562d6744c169ce7a36de01a8d6154',
          ],
          [
            '5e95bb399a6971d376026947f89bde2f282b33810928be4ded112ac4d70e20d5',
            '39f23f366809085beebfc71181313775a99c9aed7d8ba38b161384c746012865',
          ],
          [
            '36e4641a53948fd476c39f8a99fd974e5ec07564b5315d8bf99471bca0ef2f66',
            'd2424b1b1abe4eb8164227b085c9aa9456ea13493fd563e06fd51cf5694c78fc',
          ],
          [
            '336581ea7bfbbb290c191a2f507a41cf5643842170e914faeab27c2c579f726',
            'ead12168595fe1be99252129b6e56b3391f7ab1410cd1e0ef3dcdcabd2fda224',
          ],
          [
            '8ab89816dadfd6b6a1f2634fcf00ec8403781025ed6890c4849742706bd43ede',
            '6fdcef09f2f6d0a044e654aef624136f503d459c3e89845858a47a9129cdd24e',
          ],
          [
            '1e33f1a746c9c5778133344d9299fcaa20b0938e8acff2544bb40284b8c5fb94',
            '60660257dd11b3aa9c8ed618d24edff2306d320f1d03010e33a7d2057f3b3b6',
          ],
          [
            '85b7c1dcb3cec1b7ee7f30ded79dd20a0ed1f4cc18cbcfcfa410361fd8f08f31',
            '3d98a9cdd026dd43f39048f25a8847f4fcafad1895d7a633c6fed3c35e999511',
          ],
          [
            '29df9fbd8d9e46509275f4b125d6d45d7fbe9a3b878a7af872a2800661ac5f51',
            'b4c4fe99c775a606e2d8862179139ffda61dc861c019e55cd2876eb2a27d84b',
          ],
          [
            'a0b1cae06b0a847a3fea6e671aaf8adfdfe58ca2f768105c8082b2e449fce252',
            'ae434102edde0958ec4b19d917a6a28e6b72da1834aff0e650f049503a296cf2',
          ],
          [
            '4e8ceafb9b3e9a136dc7ff67e840295b499dfb3b2133e4ba113f2e4c0e121e5',
            'cf2174118c8b6d7a4b48f6d534ce5c79422c086a63460502b827ce62a326683c',
          ],
          [
            'd24a44e047e19b6f5afb81c7ca2f69080a5076689a010919f42725c2b789a33b',
            '6fb8d5591b466f8fc63db50f1c0f1c69013f996887b8244d2cdec417afea8fa3',
          ],
          [
            'ea01606a7a6c9cdd249fdfcfacb99584001edd28abbab77b5104e98e8e3b35d4',
            '322af4908c7312b0cfbfe369f7a7b3cdb7d4494bc2823700cfd652188a3ea98d',
          ],
          [
            'af8addbf2b661c8a6c6328655eb96651252007d8c5ea31be4ad196de8ce2131f',
            '6749e67c029b85f52a034eafd096836b2520818680e26ac8f3dfbcdb71749700',
          ],
          [
            'e3ae1974566ca06cc516d47e0fb165a674a3dabcfca15e722f0e3450f45889',
            '2aeabe7e4531510116217f07bf4d07300de97e4874f81f533420a72eeb0bd6a4',
          ],
          [
            '591ee355313d99721cf6993ffed1e3e301993ff3ed258802075ea8ced397e246',
            'b0ea558a113c30bea60fc4775460c7901ff0b053d25ca2bdeee98f1a4be5d196',
          ],
          [
            '11396d55fda54c49f19aa97318d8da61fa8584e47b084945077cf03255b52984',
            '998c74a8cd45ac01289d5833a7beb4744ff536b01b257be4c5767bea93ea57a4',
          ],
          [
            '3c5d2a1ba39c5a1790000738c9e0c40b8dcdfd5468754b6405540157e017aa7a',
            'b2284279995a34e2f9d4de7396fc18b80f9b8b9fdd270f6661f79ca4c81bd257',
          ],
          [
            'cc8704b8a60a0defa3a99a7299f2e9c3fbc395afb04ac078425ef8a1793cc030',
            'bdd46039feed17881d1e0862db347f8cf395b74fc4bcdc4e940b74e3ac1f1b13',
          ],
          [
            'c533e4f7ea8555aacd9777ac5cad29b97dd4defccc53ee7ea204119b2889b197',
            '6f0a256bc5efdf429a2fb6242f1a43a2d9b925bb4a4b3a26bb8e0f45eb596096',
          ],
          [
            'c14f8f2ccb27d6f109f6d08d03cc96a69ba8c34eec07bbcf566d48e33da6593',
            'c359d6923bb398f7fd4473e16fe1c28475b740dd098075e6c0e8649113dc3a38',
          ],
          [
            'a6cbc3046bc6a450bac24789fa17115a4c9739ed75f8f21ce441f72e0b90e6ef',
            '21ae7f4680e889bb130619e2c0f95a360ceb573c70603139862afd617fa9b9f',
          ],
          [
            '347d6d9a02c48927ebfb86c1359b1caf130a3c0267d11ce6344b39f99d43cc38',
            '60ea7f61a353524d1c987f6ecec92f086d565ab687870cb12689ff1e31c74448',
          ],
          [
            'da6545d2181db8d983f7dcb375ef5866d47c67b1bf31c8cf855ef7437b72656a',
            '49b96715ab6878a79e78f07ce5680c5d6673051b4935bd897fea824b77dc208a',
          ],
          [
            'c40747cc9d012cb1a13b8148309c6de7ec25d6945d657146b9d5994b8feb1111',
            '5ca560753be2a12fc6de6caf2cb489565db936156b9514e1bb5e83037e0fa2d4',
          ],
          [
            '4e42c8ec82c99798ccf3a610be870e78338c7f713348bd34c8203ef4037f3502',
            '7571d74ee5e0fb92a7a8b33a07783341a5492144cc54bcc40a94473693606437',
          ],
          [
            '3775ab7089bc6af823aba2e1af70b236d251cadb0c86743287522a1b3b0dedea',
            'be52d107bcfa09d8bcb9736a828cfa7fac8db17bf7a76a2c42ad961409018cf7',
          ],
          [
            'cee31cbf7e34ec379d94fb814d3d775ad954595d1314ba8846959e3e82f74e26',
            '8fd64a14c06b589c26b947ae2bcf6bfa0149ef0be14ed4d80f448a01c43b1c6d',
          ],
          [
            'b4f9eaea09b6917619f6ea6a4eb5464efddb58fd45b1ebefcdc1a01d08b47986',
            '39e5c9925b5a54b07433a4f18c61726f8bb131c012ca542eb24a8ac07200682a',
          ],
          [
            'd4263dfc3d2df923a0179a48966d30ce84e2515afc3dccc1b77907792ebcc60e',
            '62dfaf07a0f78feb30e30d6295853ce189e127760ad6cf7fae164e122a208d54',
          ],
          [
            '48457524820fa65a4f8d35eb6930857c0032acc0a4a2de422233eeda897612c4',
            '25a748ab367979d98733c38a1fa1c2e7dc6cc07db2d60a9ae7a76aaa49bd0f77',
          ],
          [
            'dfeeef1881101f2cb11644f3a2afdfc2045e19919152923f367a1767c11cceda',
            'ecfb7056cf1de042f9420bab396793c0c390bde74b4bbdff16a83ae09a9a7517',
          ],
          [
            '6d7ef6b17543f8373c573f44e1f389835d89bcbc6062ced36c82df83b8fae859',
            'cd450ec335438986dfefa10c57fea9bcc521a0959b2d80bbf74b190dca712d10',
          ],
          [
            'e75605d59102a5a2684500d3b991f2e3f3c88b93225547035af25af66e04541f',
            'f5c54754a8f71ee540b9b48728473e314f729ac5308b06938360990e2bfad125',
          ],
          [
            'eb98660f4c4dfaa06a2be453d5020bc99a0c2e60abe388457dd43fefb1ed620c',
            '6cb9a8876d9cb8520609af3add26cd20a0a7cd8a9411131ce85f44100099223e',
          ],
          [
            '13e87b027d8514d35939f2e6892b19922154596941888336dc3563e3b8dba942',
            'fef5a3c68059a6dec5d624114bf1e91aac2b9da568d6abeb2570d55646b8adf1',
          ],
          [
            'ee163026e9fd6fe017c38f06a5be6fc125424b371ce2708e7bf4491691e5764a',
            '1acb250f255dd61c43d94ccc670d0f58f49ae3fa15b96623e5430da0ad6c62b2',
          ],
          [
            'b268f5ef9ad51e4d78de3a750c2dc89b1e626d43505867999932e5db33af3d80',
            '5f310d4b3c99b9ebb19f77d41c1dee018cf0d34fd4191614003e945a1216e423',
          ],
          [
            'ff07f3118a9df035e9fad85eb6c7bfe42b02f01ca99ceea3bf7ffdba93c4750d',
            '438136d603e858a3a5c440c38eccbaddc1d2942114e2eddd4740d098ced1f0d8',
          ],
          [
            '8d8b9855c7c052a34146fd20ffb658bea4b9f69e0d825ebec16e8c3ce2b526a1',
            'cdb559eedc2d79f926baf44fb84ea4d44bcf50fee51d7ceb30e2e7f463036758',
          ],
          [
            '52db0b5384dfbf05bfa9d472d7ae26dfe4b851ceca91b1eba54263180da32b63',
            'c3b997d050ee5d423ebaf66a6db9f57b3180c902875679de924b69d84a7b375',
          ],
          [
            'e62f9490d3d51da6395efd24e80919cc7d0f29c3f3fa48c6fff543becbd43352',
            '6d89ad7ba4876b0b22c2ca280c682862f342c8591f1daf5170e07bfd9ccafa7d',
          ],
          [
            '7f30ea2476b399b4957509c88f77d0191afa2ff5cb7b14fd6d8e7d65aaab1193',
            'ca5ef7d4b231c94c3b15389a5f6311e9daff7bb67b103e9880ef4bff637acaec',
          ],
          [
            '5098ff1e1d9f14fb46a210fada6c903fef0fb7b4a1dd1d9ac60a0361800b7a00',
            '9731141d81fc8f8084d37c6e7542006b3ee1b40d60dfe5362a5b132fd17ddc0',
          ],
          [
            '32b78c7de9ee512a72895be6b9cbefa6e2f3c4ccce445c96b9f2c81e2778ad58',
            'ee1849f513df71e32efc3896ee28260c73bb80547ae2275ba497237794c8753c',
          ],
          [
            'e2cb74fddc8e9fbcd076eef2a7c72b0ce37d50f08269dfc074b581550547a4f7',
            'd3aa2ed71c9dd2247a62df062736eb0baddea9e36122d2be8641abcb005cc4a4',
          ],
          [
            '8438447566d4d7bedadc299496ab357426009a35f235cb141be0d99cd10ae3a8',
            'c4e1020916980a4da5d01ac5e6ad330734ef0d7906631c4f2390426b2edd791f',
          ],
          [
            '4162d488b89402039b584c6fc6c308870587d9c46f660b878ab65c82c711d67e',
            '67163e903236289f776f22c25fb8a3afc1732f2b84b4e95dbda47ae5a0852649',
          ],
          [
            '3fad3fa84caf0f34f0f89bfd2dcf54fc175d767aec3e50684f3ba4a4bf5f683d',
            'cd1bc7cb6cc407bb2f0ca647c718a730cf71872e7d0d2a53fa20efcdfe61826',
          ],
          [
            '674f2600a3007a00568c1a7ce05d0816c1fb84bf1370798f1c69532faeb1a86b',
            '299d21f9413f33b3edf43b257004580b70db57da0b182259e09eecc69e0d38a5',
          ],
          [
            'd32f4da54ade74abb81b815ad1fb3b263d82d6c692714bcff87d29bd5ee9f08f',
            'f9429e738b8e53b968e99016c059707782e14f4535359d582fc416910b3eea87',
          ],
          [
            '30e4e670435385556e593657135845d36fbb6931f72b08cb1ed954f1e3ce3ff6',
            '462f9bce619898638499350113bbc9b10a878d35da70740dc695a559eb88db7b',
          ],
          [
            'be2062003c51cc3004682904330e4dee7f3dcd10b01e580bf1971b04d4cad297',
            '62188bc49d61e5428573d48a74e1c655b1c61090905682a0d5558ed72dccb9bc',
          ],
          [
            '93144423ace3451ed29e0fb9ac2af211cb6e84a601df5993c419859fff5df04a',
            '7c10dfb164c3425f5c71a3f9d7992038f1065224f72bb9d1d902a6d13037b47c',
          ],
          [
            'b015f8044f5fcbdcf21ca26d6c34fb8197829205c7b7d2a7cb66418c157b112c',
            'ab8c1e086d04e813744a655b2df8d5f83b3cdc6faa3088c1d3aea1454e3a1d5f',
          ],
          [
            'd5e9e1da649d97d89e4868117a465a3a4f8a18de57a140d36b3f2af341a21b52',
            '4cb04437f391ed73111a13cc1d4dd0db1693465c2240480d8955e8592f27447a',
          ],
          [
            'd3ae41047dd7ca065dbf8ed77b992439983005cd72e16d6f996a5316d36966bb',
            'bd1aeb21ad22ebb22a10f0303417c6d964f8cdd7df0aca614b10dc14d125ac46',
          ],
          [
            '463e2763d885f958fc66cdd22800f0a487197d0a82e377b49f80af87c897b065',
            'bfefacdb0e5d0fd7df3a311a94de062b26b80c61fbc97508b79992671ef7ca7f',
          ],
          [
            '7985fdfd127c0567c6f53ec1bb63ec3158e597c40bfe747c83cddfc910641917',
            '603c12daf3d9862ef2b25fe1de289aed24ed291e0ec6708703a5bd567f32ed03',
          ],
          [
            '74a1ad6b5f76e39db2dd249410eac7f99e74c59cb83d2d0ed5ff1543da7703e9',
            'cc6157ef18c9c63cd6193d83631bbea0093e0968942e8c33d5737fd790e0db08',
          ],
          [
            '30682a50703375f602d416664ba19b7fc9bab42c72747463a71d0896b22f6da3',
            '553e04f6b018b4fa6c8f39e7f311d3176290d0e0f19ca73f17714d9977a22ff8',
          ],
          [
            '9e2158f0d7c0d5f26c3791efefa79597654e7a2b2464f52b1ee6c1347769ef57',
            '712fcdd1b9053f09003a3481fa7762e9ffd7c8ef35a38509e2fbf2629008373',
          ],
          [
            '176e26989a43c9cfeba4029c202538c28172e566e3c4fce7322857f3be327d66',
            'ed8cc9d04b29eb877d270b4878dc43c19aefd31f4eee09ee7b47834c1fa4b1c3',
          ],
          [
            '75d46efea3771e6e68abb89a13ad747ecf1892393dfc4f1b7004788c50374da8',
            '9852390a99507679fd0b86fd2b39a868d7efc22151346e1a3ca4726586a6bed8',
          ],
          [
            '809a20c67d64900ffb698c4c825f6d5f2310fb0451c869345b7319f645605721',
            '9e994980d9917e22b76b061927fa04143d096ccc54963e6a5ebfa5f3f8e286c1',
          ],
          [
            '1b38903a43f7f114ed4500b4eac7083fdefece1cf29c63528d563446f972c180',
            '4036edc931a60ae889353f77fd53de4a2708b26b6f5da72ad3394119daf408f9',
          ],
        ],
      },
    };
    
    },{}],104:[function(require,module,exports){
    'use strict';
    
    var utils = exports;
    var BN = require('bn.js');
    var minAssert = require('minimalistic-assert');
    var minUtils = require('minimalistic-crypto-utils');
    
    utils.assert = minAssert;
    utils.toArray = minUtils.toArray;
    utils.zero2 = minUtils.zero2;
    utils.toHex = minUtils.toHex;
    utils.encode = minUtils.encode;
    
    // Represent num in a w-NAF form
    function getNAF(num, w, bits) {
      var naf = new Array(Math.max(num.bitLength(), bits) + 1);
      naf.fill(0);
    
      var ws = 1 << (w + 1);
      var k = num.clone();
    
      for (var i = 0; i < naf.length; i++) {
        var z;
        var mod = k.andln(ws - 1);
        if (k.isOdd()) {
          if (mod > (ws >> 1) - 1)
            z = (ws >> 1) - mod;
          else
            z = mod;
          k.isubn(z);
        } else {
          z = 0;
        }
    
        naf[i] = z;
        k.iushrn(1);
      }
    
      return naf;
    }
    utils.getNAF = getNAF;
    
    // Represent k1, k2 in a Joint Sparse Form
    function getJSF(k1, k2) {
      var jsf = [
        [],
        [],
      ];
    
      k1 = k1.clone();
      k2 = k2.clone();
      var d1 = 0;
      var d2 = 0;
      var m8;
      while (k1.cmpn(-d1) > 0 || k2.cmpn(-d2) > 0) {
        // First phase
        var m14 = (k1.andln(3) + d1) & 3;
        var m24 = (k2.andln(3) + d2) & 3;
        if (m14 === 3)
          m14 = -1;
        if (m24 === 3)
          m24 = -1;
        var u1;
        if ((m14 & 1) === 0) {
          u1 = 0;
        } else {
          m8 = (k1.andln(7) + d1) & 7;
          if ((m8 === 3 || m8 === 5) && m24 === 2)
            u1 = -m14;
          else
            u1 = m14;
        }
        jsf[0].push(u1);
    
        var u2;
        if ((m24 & 1) === 0) {
          u2 = 0;
        } else {
          m8 = (k2.andln(7) + d2) & 7;
          if ((m8 === 3 || m8 === 5) && m14 === 2)
            u2 = -m24;
          else
            u2 = m24;
        }
        jsf[1].push(u2);
    
        // Second phase
        if (2 * d1 === u1 + 1)
          d1 = 1 - d1;
        if (2 * d2 === u2 + 1)
          d2 = 1 - d2;
        k1.iushrn(1);
        k2.iushrn(1);
      }
    
      return jsf;
    }
    utils.getJSF = getJSF;
    
    function cachedProperty(obj, name, computer) {
      var key = '_' + name;
      obj.prototype[name] = function cachedProperty() {
        return this[key] !== undefined ? this[key] :
          this[key] = computer.call(this);
      };
    }
    utils.cachedProperty = cachedProperty;
    
    function parseBytes(bytes) {
      return typeof bytes === 'string' ? utils.toArray(bytes, 'hex') :
        bytes;
    }
    utils.parseBytes = parseBytes;
    
    function intFromLE(bytes) {
      return new BN(bytes, 'hex', 'le');
    }
    utils.intFromLE = intFromLE;
    
    
    },{"bn.js":105,"minimalistic-assert":158,"minimalistic-crypto-utils":159}],105:[function(require,module,exports){
    arguments[4][15][0].apply(exports,arguments)
    },{"buffer":24,"dup":15}],106:[function(require,module,exports){
    module.exports={
      "name": "elliptic",
      "version": "6.5.4",
      "description": "EC cryptography",
      "main": "lib/elliptic.js",
      "files": [
        "lib"
      ],
      "scripts": {
        "lint": "eslint lib test",
        "lint:fix": "npm run lint -- --fix",
        "unit": "istanbul test _mocha --reporter=spec test/index.js",
        "test": "npm run lint && npm run unit",
        "version": "grunt dist && git add dist/"
      },
      "repository": {
        "type": "git",
        "url": "git@github.com:indutny/elliptic"
      },
      "keywords": [
        "EC",
        "Elliptic",
        "curve",
        "Cryptography"
      ],
      "author": "Fedor Indutny <fedor@indutny.com>",
      "license": "MIT",
      "bugs": {
        "url": "https://github.com/indutny/elliptic/issues"
      },
      "homepage": "https://github.com/indutny/elliptic",
      "devDependencies": {
        "brfs": "^2.0.2",
        "coveralls": "^3.1.0",
        "eslint": "^7.6.0",
        "grunt": "^1.2.1",
        "grunt-browserify": "^5.3.0",
        "grunt-cli": "^1.3.2",
        "grunt-contrib-connect": "^3.0.0",
        "grunt-contrib-copy": "^1.0.0",
        "grunt-contrib-uglify": "^5.0.0",
        "grunt-mocha-istanbul": "^5.0.2",
        "grunt-saucelabs": "^9.0.1",
        "istanbul": "^0.4.5",
        "mocha": "^8.0.1"
      },
      "dependencies": {
        "bn.js": "^4.11.9",
        "brorand": "^1.1.0",
        "hash.js": "^1.0.0",
        "hmac-drbg": "^1.0.1",
        "inherits": "^2.0.4",
        "minimalistic-assert": "^1.0.1",
        "minimalistic-crypto-utils": "^1.0.1"
      }
    }
    
    },{}],107:[function(require,module,exports){
    // Copyright Joyent, Inc. and other Node contributors.
    //
    // Permission is hereby granted, free of charge, to any person obtaining a
    // copy of this software and associated documentation files (the
    // "Software"), to deal in the Software without restriction, including
    // without limitation the rights to use, copy, modify, merge, publish,
    // distribute, sublicense, and/or sell copies of the Software, and to permit
    // persons to whom the Software is furnished to do so, subject to the
    // following conditions:
    //
    // The above copyright notice and this permission notice shall be included
    // in all copies or substantial portions of the Software.
    //
    // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
    // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
    // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
    // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
    // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
    // USE OR OTHER DEALINGS IN THE SOFTWARE.
    
    'use strict';
    
    var R = typeof Reflect === 'object' ? Reflect : null
    var ReflectApply = R && typeof R.apply === 'function'
      ? R.apply
      : function ReflectApply(target, receiver, args) {
        return Function.prototype.apply.call(target, receiver, args);
      }
    
    var ReflectOwnKeys
    if (R && typeof R.ownKeys === 'function') {
      ReflectOwnKeys = R.ownKeys
    } else if (Object.getOwnPropertySymbols) {
      ReflectOwnKeys = function ReflectOwnKeys(target) {
        return Object.getOwnPropertyNames(target)
          .concat(Object.getOwnPropertySymbols(target));
      };
    } else {
      ReflectOwnKeys = function ReflectOwnKeys(target) {
        return Object.getOwnPropertyNames(target);
      };
    }
    
    function ProcessEmitWarning(warning) {
      if (console && console.warn) console.warn(warning);
    }
    
    var NumberIsNaN = Number.isNaN || function NumberIsNaN(value) {
      return value !== value;
    }
    
    function EventEmitter() {
      EventEmitter.init.call(this);
    }
    module.exports = EventEmitter;
    module.exports.once = once;
    
    // Backwards-compat with node 0.10.x
    EventEmitter.EventEmitter = EventEmitter;
    
    EventEmitter.prototype._events = undefined;
    EventEmitter.prototype._eventsCount = 0;
    EventEmitter.prototype._maxListeners = undefined;
    
    // By default EventEmitters will print a warning if more than 10 listeners are
    // added to it. This is a useful default which helps finding memory leaks.
    var defaultMaxListeners = 10;
    
    function checkListener(listener) {
      if (typeof listener !== 'function') {
        throw new TypeError('The "listener" argument must be of type Function. Received type ' + typeof listener);
      }
    }
    
    Object.defineProperty(EventEmitter, 'defaultMaxListeners', {
      enumerable: true,
      get: function() {
        return defaultMaxListeners;
      },
      set: function(arg) {
        if (typeof arg !== 'number' || arg < 0 || NumberIsNaN(arg)) {
          throw new RangeError('The value of "defaultMaxListeners" is out of range. It must be a non-negative number. Received ' + arg + '.');
        }
        defaultMaxListeners = arg;
      }
    });
    
    EventEmitter.init = function() {
    
      if (this._events === undefined ||
          this._events === Object.getPrototypeOf(this)._events) {
        this._events = Object.create(null);
        this._eventsCount = 0;
      }
    
      this._maxListeners = this._maxListeners || undefined;
    };
    
    // Obviously not all Emitters should be limited to 10. This function allows
    // that to be increased. Set to zero for unlimited.
    EventEmitter.prototype.setMaxListeners = function setMaxListeners(n) {
      if (typeof n !== 'number' || n < 0 || NumberIsNaN(n)) {
        throw new RangeError('The value of "n" is out of range. It must be a non-negative number. Received ' + n + '.');
      }
      this._maxListeners = n;
      return this;
    };
    
    function _getMaxListeners(that) {
      if (that._maxListeners === undefined)
        return EventEmitter.defaultMaxListeners;
      return that._maxListeners;
    }
    
    EventEmitter.prototype.getMaxListeners = function getMaxListeners() {
      return _getMaxListeners(this);
    };
    
    EventEmitter.prototype.emit = function emit(type) {
      var args = [];
      for (var i = 1; i < arguments.length; i++) args.push(arguments[i]);
      var doError = (type === 'error');
    
      var events = this._events;
      if (events !== undefined)
        doError = (doError && events.error === undefined);
      else if (!doError)
        return false;
    
      // If there is no 'error' event listener then throw.
      if (doError) {
        var er;
        if (args.length > 0)
          er = args[0];
        if (er instanceof Error) {
          // Note: The comments on the `throw` lines are intentional, they show
          // up in Node's output if this results in an unhandled exception.
          throw er; // Unhandled 'error' event
        }
        // At least give some kind of context to the user
        var err = new Error('Unhandled error.' + (er ? ' (' + er.message + ')' : ''));
        err.context = er;
        throw err; // Unhandled 'error' event
      }
    
      var handler = events[type];
    
      if (handler === undefined)
        return false;
    
      if (typeof handler === 'function') {
        ReflectApply(handler, this, args);
      } else {
        var len = handler.length;
        var listeners = arrayClone(handler, len);
        for (var i = 0; i < len; ++i)
          ReflectApply(listeners[i], this, args);
      }
    
      return true;
    };
    
    function _addListener(target, type, listener, prepend) {
      var m;
      var events;
      var existing;
    
      checkListener(listener);
    
      events = target._events;
      if (events === undefined) {
        events = target._events = Object.create(null);
        target._eventsCount = 0;
      } else {
        // To avoid recursion in the case that type === "newListener"! Before
        // adding it to the listeners, first emit "newListener".
        if (events.newListener !== undefined) {
          target.emit('newListener', type,
                      listener.listener ? listener.listener : listener);
    
          // Re-assign `events` because a newListener handler could have caused the
          // this._events to be assigned to a new object
          events = target._events;
        }
        existing = events[type];
      }
    
      if (existing === undefined) {
        // Optimize the case of one listener. Don't need the extra array object.
        existing = events[type] = listener;
        ++target._eventsCount;
      } else {
        if (typeof existing === 'function') {
          // Adding the second element, need to change to array.
          existing = events[type] =
            prepend ? [listener, existing] : [existing, listener];
          // If we've already got an array, just append.
        } else if (prepend) {
          existing.unshift(listener);
        } else {
          existing.push(listener);
        }
    
        // Check for listener leak
        m = _getMaxListeners(target);
        if (m > 0 && existing.length > m && !existing.warned) {
          existing.warned = true;
          // No error code for this since it is a Warning
          // eslint-disable-next-line no-restricted-syntax
          var w = new Error('Possible EventEmitter memory leak detected. ' +
                              existing.length + ' ' + String(type) + ' listeners ' +
                              'added. Use emitter.setMaxListeners() to ' +
                              'increase limit');
          w.name = 'MaxListenersExceededWarning';
          w.emitter = target;
          w.type = type;
          w.count = existing.length;
          ProcessEmitWarning(w);
        }
      }
    
      return target;
    }
    
    EventEmitter.prototype.addListener = function addListener(type, listener) {
      return _addListener(this, type, listener, false);
    };
    
    EventEmitter.prototype.on = EventEmitter.prototype.addListener;
    
    EventEmitter.prototype.prependListener =
        function prependListener(type, listener) {
          return _addListener(this, type, listener, true);
        };
    
    function onceWrapper() {
      if (!this.fired) {
        this.target.removeListener(this.type, this.wrapFn);
        this.fired = true;
        if (arguments.length === 0)
          return this.listener.call(this.target);
        return this.listener.apply(this.target, arguments);
      }
    }
    
    function _onceWrap(target, type, listener) {
      var state = { fired: false, wrapFn: undefined, target: target, type: type, listener: listener };
      var wrapped = onceWrapper.bind(state);
      wrapped.listener = listener;
      state.wrapFn = wrapped;
      return wrapped;
    }
    
    EventEmitter.prototype.once = function once(type, listener) {
      checkListener(listener);
      this.on(type, _onceWrap(this, type, listener));
      return this;
    };
    
    EventEmitter.prototype.prependOnceListener =
        function prependOnceListener(type, listener) {
          checkListener(listener);
          this.prependListener(type, _onceWrap(this, type, listener));
          return this;
        };
    
    // Emits a 'removeListener' event if and only if the listener was removed.
    EventEmitter.prototype.removeListener =
        function removeListener(type, listener) {
          var list, events, position, i, originalListener;
    
          checkListener(listener);
    
          events = this._events;
          if (events === undefined)
            return this;
    
          list = events[type];
          if (list === undefined)
            return this;
    
          if (list === listener || list.listener === listener) {
            if (--this._eventsCount === 0)
              this._events = Object.create(null);
            else {
              delete events[type];
              if (events.removeListener)
                this.emit('removeListener', type, list.listener || listener);
            }
          } else if (typeof list !== 'function') {
            position = -1;
    
            for (i = list.length - 1; i >= 0; i--) {
              if (list[i] === listener || list[i].listener === listener) {
                originalListener = list[i].listener;
                position = i;
                break;
              }
            }
    
            if (position < 0)
              return this;
    
            if (position === 0)
              list.shift();
            else {
              spliceOne(list, position);
            }
    
            if (list.length === 1)
              events[type] = list[0];
    
            if (events.removeListener !== undefined)
              this.emit('removeListener', type, originalListener || listener);
          }
    
          return this;
        };
    
    EventEmitter.prototype.off = EventEmitter.prototype.removeListener;
    
    EventEmitter.prototype.removeAllListeners =
        function removeAllListeners(type) {
          var listeners, events, i;
    
          events = this._events;
          if (events === undefined)
            return this;
    
          // not listening for removeListener, no need to emit
          if (events.removeListener === undefined) {
            if (arguments.length === 0) {
              this._events = Object.create(null);
              this._eventsCount = 0;
            } else if (events[type] !== undefined) {
              if (--this._eventsCount === 0)
                this._events = Object.create(null);
              else
                delete events[type];
            }
            return this;
          }
    
          // emit removeListener for all listeners on all events
          if (arguments.length === 0) {
            var keys = Object.keys(events);
            var key;
            for (i = 0; i < keys.length; ++i) {
              key = keys[i];
              if (key === 'removeListener') continue;
              this.removeAllListeners(key);
            }
            this.removeAllListeners('removeListener');
            this._events = Object.create(null);
            this._eventsCount = 0;
            return this;
          }
    
          listeners = events[type];
    
          if (typeof listeners === 'function') {
            this.removeListener(type, listeners);
          } else if (listeners !== undefined) {
            // LIFO order
            for (i = listeners.length - 1; i >= 0; i--) {
              this.removeListener(type, listeners[i]);
            }
          }
    
          return this;
        };
    
    function _listeners(target, type, unwrap) {
      var events = target._events;
    
      if (events === undefined)
        return [];
    
      var evlistener = events[type];
      if (evlistener === undefined)
        return [];
    
      if (typeof evlistener === 'function')
        return unwrap ? [evlistener.listener || evlistener] : [evlistener];
    
      return unwrap ?
        unwrapListeners(evlistener) : arrayClone(evlistener, evlistener.length);
    }
    
    EventEmitter.prototype.listeners = function listeners(type) {
      return _listeners(this, type, true);
    };
    
    EventEmitter.prototype.rawListeners = function rawListeners(type) {
      return _listeners(this, type, false);
    };
    
    EventEmitter.listenerCount = function(emitter, type) {
      if (typeof emitter.listenerCount === 'function') {
        return emitter.listenerCount(type);
      } else {
        return listenerCount.call(emitter, type);
      }
    };
    
    EventEmitter.prototype.listenerCount = listenerCount;
    function listenerCount(type) {
      var events = this._events;
    
      if (events !== undefined) {
        var evlistener = events[type];
    
        if (typeof evlistener === 'function') {
          return 1;
        } else if (evlistener !== undefined) {
          return evlistener.length;
        }
      }
    
      return 0;
    }
    
    EventEmitter.prototype.eventNames = function eventNames() {
      return this._eventsCount > 0 ? ReflectOwnKeys(this._events) : [];
    };
    
    function arrayClone(arr, n) {
      var copy = new Array(n);
      for (var i = 0; i < n; ++i)
        copy[i] = arr[i];
      return copy;
    }
    
    function spliceOne(list, index) {
      for (; index + 1 < list.length; index++)
        list[index] = list[index + 1];
      list.pop();
    }
    
    function unwrapListeners(arr) {
      var ret = new Array(arr.length);
      for (var i = 0; i < ret.length; ++i) {
        ret[i] = arr[i].listener || arr[i];
      }
      return ret;
    }
    
    function once(emitter, name) {
      return new Promise(function (resolve, reject) {
        function errorListener(err) {
          emitter.removeListener(name, resolver);
          reject(err);
        }
    
        function resolver() {
          if (typeof emitter.removeListener === 'function') {
            emitter.removeListener('error', errorListener);
          }
          resolve([].slice.call(arguments));
        };
    
        eventTargetAgnosticAddListener(emitter, name, resolver, { once: true });
        if (name !== 'error') {
          addErrorHandlerIfEventEmitter(emitter, errorListener, { once: true });
        }
      });
    }
    
    function addErrorHandlerIfEventEmitter(emitter, handler, flags) {
      if (typeof emitter.on === 'function') {
        eventTargetAgnosticAddListener(emitter, 'error', handler, flags);
      }
    }
    
    function eventTargetAgnosticAddListener(emitter, name, listener, flags) {
      if (typeof emitter.on === 'function') {
        if (flags.once) {
          emitter.once(name, listener);
        } else {
          emitter.on(name, listener);
        }
      } else if (typeof emitter.addEventListener === 'function') {
        // EventTarget does not have `error` event semantics like Node
        // EventEmitters, we do not listen for `error` events here.
        emitter.addEventListener(name, function wrapListener(arg) {
          // IE does not have builtin `{ once: true }` support so we
          // have to do it manually.
          if (flags.once) {
            emitter.removeEventListener(name, wrapListener);
          }
          listener(arg);
        });
      } else {
        throw new TypeError('The "emitter" argument must be of type EventEmitter. Received type ' + typeof emitter);
      }
    }
    
    },{}],108:[function(require,module,exports){
    var Buffer = require('safe-buffer').Buffer
    var MD5 = require('md5.js')
    
    /* eslint-disable camelcase */
    function EVP_BytesToKey (password, salt, keyBits, ivLen) {
      if (!Buffer.isBuffer(password)) password = Buffer.from(password, 'binary')
      if (salt) {
        if (!Buffer.isBuffer(salt)) salt = Buffer.from(salt, 'binary')
        if (salt.length !== 8) throw new RangeError('salt should be Buffer with 8 byte length')
      }
    
      var keyLen = keyBits / 8
      var key = Buffer.alloc(keyLen)
      var iv = Buffer.alloc(ivLen || 0)
      var tmp = Buffer.alloc(0)
    
      while (keyLen > 0 || ivLen > 0) {
        var hash = new MD5()
        hash.update(tmp)
        hash.update(password)
        if (salt) hash.update(salt)
        tmp = hash.digest()
    
        var used = 0
    
        if (keyLen > 0) {
          var keyStart = key.length - keyLen
          used = Math.min(keyLen, tmp.length)
          tmp.copy(key, keyStart, 0, used)
          keyLen -= used
        }
    
        if (used < tmp.length && ivLen > 0) {
          var ivStart = iv.length - ivLen
          var length = Math.min(ivLen, tmp.length - used)
          tmp.copy(iv, ivStart, used, used + length)
          ivLen -= length
        }
      }
    
      tmp.fill(0)
      return { key: key, iv: iv }
    }
    
    module.exports = EVP_BytesToKey
    
    },{"md5.js":155,"safe-buffer":187}],109:[function(require,module,exports){
    'use strict';
    
    var isCallable = require('is-callable');
    
    var toStr = Object.prototype.toString;
    var hasOwnProperty = Object.prototype.hasOwnProperty;
    
    var forEachArray = function forEachArray(array, iterator, receiver) {
        for (var i = 0, len = array.length; i < len; i++) {
            if (hasOwnProperty.call(array, i)) {
                if (receiver == null) {
                    iterator(array[i], i, array);
                } else {
                    iterator.call(receiver, array[i], i, array);
                }
            }
        }
    };
    
    var forEachString = function forEachString(string, iterator, receiver) {
        for (var i = 0, len = string.length; i < len; i++) {
            // no such thing as a sparse string.
            if (receiver == null) {
                iterator(string.charAt(i), i, string);
            } else {
                iterator.call(receiver, string.charAt(i), i, string);
            }
        }
    };
    
    var forEachObject = function forEachObject(object, iterator, receiver) {
        for (var k in object) {
            if (hasOwnProperty.call(object, k)) {
                if (receiver == null) {
                    iterator(object[k], k, object);
                } else {
                    iterator.call(receiver, object[k], k, object);
                }
            }
        }
    };
    
    var forEach = function forEach(list, iterator, thisArg) {
        if (!isCallable(iterator)) {
            throw new TypeError('iterator must be a function');
        }
    
        var receiver;
        if (arguments.length >= 3) {
            receiver = thisArg;
        }
    
        if (toStr.call(list) === '[object Array]') {
            forEachArray(list, iterator, receiver);
        } else if (typeof list === 'string') {
            forEachString(list, iterator, receiver);
        } else {
            forEachObject(list, iterator, receiver);
        }
    };
    
    module.exports = forEach;
    
    },{"is-callable":152}],110:[function(require,module,exports){
    'use strict';
    
    /* eslint no-invalid-this: 1 */
    
    var ERROR_MESSAGE = 'Function.prototype.bind called on incompatible ';
    var slice = Array.prototype.slice;
    var toStr = Object.prototype.toString;
    var funcType = '[object Function]';
    
    module.exports = function bind(that) {
        var target = this;
        if (typeof target !== 'function' || toStr.call(target) !== funcType) {
            throw new TypeError(ERROR_MESSAGE + target);
        }
        var args = slice.call(arguments, 1);
    
        var bound;
        var binder = function () {
            if (this instanceof bound) {
                var result = target.apply(
                    this,
                    args.concat(slice.call(arguments))
                );
                if (Object(result) === result) {
                    return result;
                }
                return this;
            } else {
                return target.apply(
                    that,
                    args.concat(slice.call(arguments))
                );
            }
        };
    
        var boundLength = Math.max(0, target.length - args.length);
        var boundArgs = [];
        for (var i = 0; i < boundLength; i++) {
            boundArgs.push('$' + i);
        }
    
        bound = Function('binder', 'return function (' + boundArgs.join(',') + '){ return binder.apply(this,arguments); }')(binder);
    
        if (target.prototype) {
            var Empty = function Empty() {};
            Empty.prototype = target.prototype;
            bound.prototype = new Empty();
            Empty.prototype = null;
        }
    
        return bound;
    };
    
    },{}],111:[function(require,module,exports){
    'use strict';
    
    var implementation = require('./implementation');
    
    module.exports = Function.prototype.bind || implementation;
    
    },{"./implementation":110}],112:[function(require,module,exports){
    'use strict';
    
    var undefined;
    
    var $SyntaxError = SyntaxError;
    var $Function = Function;
    var $TypeError = TypeError;
    
    // eslint-disable-next-line consistent-return
    var getEvalledConstructor = function (expressionSyntax) {
        try {
            return $Function('"use strict"; return (' + expressionSyntax + ').constructor;')();
        } catch (e) {}
    };
    
    var $gOPD = Object.getOwnPropertyDescriptor;
    if ($gOPD) {
        try {
            $gOPD({}, '');
        } catch (e) {
            $gOPD = null; // this is IE 8, which has a broken gOPD
        }
    }
    
    var throwTypeError = function () {
        throw new $TypeError();
    };
    var ThrowTypeError = $gOPD
        ? (function () {
            try {
                // eslint-disable-next-line no-unused-expressions, no-caller, no-restricted-properties
                arguments.callee; // IE 8 does not throw here
                return throwTypeError;
            } catch (calleeThrows) {
                try {
                    // IE 8 throws on Object.getOwnPropertyDescriptor(arguments, '')
                    return $gOPD(arguments, 'callee').get;
                } catch (gOPDthrows) {
                    return throwTypeError;
                }
            }
        }())
        : throwTypeError;
    
    var hasSymbols = require('has-symbols')();
    var hasProto = require('has-proto')();
    
    var getProto = Object.getPrototypeOf || (
        hasProto
            ? function (x) { return x.__proto__; } // eslint-disable-line no-proto
            : null
    );
    
    var needsEval = {};
    
    var TypedArray = typeof Uint8Array === 'undefined' || !getProto ? undefined : getProto(Uint8Array);
    
    var INTRINSICS = {
        '%AggregateError%': typeof AggregateError === 'undefined' ? undefined : AggregateError,
        '%Array%': Array,
        '%ArrayBuffer%': typeof ArrayBuffer === 'undefined' ? undefined : ArrayBuffer,
        '%ArrayIteratorPrototype%': hasSymbols && getProto ? getProto([][Symbol.iterator]()) : undefined,
        '%AsyncFromSyncIteratorPrototype%': undefined,
        '%AsyncFunction%': needsEval,
        '%AsyncGenerator%': needsEval,
        '%AsyncGeneratorFunction%': needsEval,
        '%AsyncIteratorPrototype%': needsEval,
        '%Atomics%': typeof Atomics === 'undefined' ? undefined : Atomics,
        '%BigInt%': typeof BigInt === 'undefined' ? undefined : BigInt,
        '%BigInt64Array%': typeof BigInt64Array === 'undefined' ? undefined : BigInt64Array,
        '%BigUint64Array%': typeof BigUint64Array === 'undefined' ? undefined : BigUint64Array,
        '%Boolean%': Boolean,
        '%DataView%': typeof DataView === 'undefined' ? undefined : DataView,
        '%Date%': Date,
        '%decodeURI%': decodeURI,
        '%decodeURIComponent%': decodeURIComponent,
        '%encodeURI%': encodeURI,
        '%encodeURIComponent%': encodeURIComponent,
        '%Error%': Error,
        '%eval%': eval, // eslint-disable-line no-eval
        '%EvalError%': EvalError,
        '%Float32Array%': typeof Float32Array === 'undefined' ? undefined : Float32Array,
        '%Float64Array%': typeof Float64Array === 'undefined' ? undefined : Float64Array,
        '%FinalizationRegistry%': typeof FinalizationRegistry === 'undefined' ? undefined : FinalizationRegistry,
        '%Function%': $Function,
        '%GeneratorFunction%': needsEval,
        '%Int8Array%': typeof Int8Array === 'undefined' ? undefined : Int8Array,
        '%Int16Array%': typeof Int16Array === 'undefined' ? undefined : Int16Array,
        '%Int32Array%': typeof Int32Array === 'undefined' ? undefined : Int32Array,
        '%isFinite%': isFinite,
        '%isNaN%': isNaN,
        '%IteratorPrototype%': hasSymbols && getProto ? getProto(getProto([][Symbol.iterator]())) : undefined,
        '%JSON%': typeof JSON === 'object' ? JSON : undefined,
        '%Map%': typeof Map === 'undefined' ? undefined : Map,
        '%MapIteratorPrototype%': typeof Map === 'undefined' || !hasSymbols || !getProto ? undefined : getProto(new Map()[Symbol.iterator]()),
        '%Math%': Math,
        '%Number%': Number,
        '%Object%': Object,
        '%parseFloat%': parseFloat,
        '%parseInt%': parseInt,
        '%Promise%': typeof Promise === 'undefined' ? undefined : Promise,
        '%Proxy%': typeof Proxy === 'undefined' ? undefined : Proxy,
        '%RangeError%': RangeError,
        '%ReferenceError%': ReferenceError,
        '%Reflect%': typeof Reflect === 'undefined' ? undefined : Reflect,
        '%RegExp%': RegExp,
        '%Set%': typeof Set === 'undefined' ? undefined : Set,
        '%SetIteratorPrototype%': typeof Set === 'undefined' || !hasSymbols || !getProto ? undefined : getProto(new Set()[Symbol.iterator]()),
        '%SharedArrayBuffer%': typeof SharedArrayBuffer === 'undefined' ? undefined : SharedArrayBuffer,
        '%String%': String,
        '%StringIteratorPrototype%': hasSymbols && getProto ? getProto(''[Symbol.iterator]()) : undefined,
        '%Symbol%': hasSymbols ? Symbol : undefined,
        '%SyntaxError%': $SyntaxError,
        '%ThrowTypeError%': ThrowTypeError,
        '%TypedArray%': TypedArray,
        '%TypeError%': $TypeError,
        '%Uint8Array%': typeof Uint8Array === 'undefined' ? undefined : Uint8Array,
        '%Uint8ClampedArray%': typeof Uint8ClampedArray === 'undefined' ? undefined : Uint8ClampedArray,
        '%Uint16Array%': typeof Uint16Array === 'undefined' ? undefined : Uint16Array,
        '%Uint32Array%': typeof Uint32Array === 'undefined' ? undefined : Uint32Array,
        '%URIError%': URIError,
        '%WeakMap%': typeof WeakMap === 'undefined' ? undefined : WeakMap,
        '%WeakRef%': typeof WeakRef === 'undefined' ? undefined : WeakRef,
        '%WeakSet%': typeof WeakSet === 'undefined' ? undefined : WeakSet
    };
    
    if (getProto) {
        try {
            null.error; // eslint-disable-line no-unused-expressions
        } catch (e) {
            // https://github.com/tc39/proposal-shadowrealm/pull/384#issuecomment-1364264229
            var errorProto = getProto(getProto(e));
            INTRINSICS['%Error.prototype%'] = errorProto;
        }
    }
    
    var doEval = function doEval(name) {
        var value;
        if (name === '%AsyncFunction%') {
            value = getEvalledConstructor('async function () {}');
        } else if (name === '%GeneratorFunction%') {
            value = getEvalledConstructor('function* () {}');
        } else if (name === '%AsyncGeneratorFunction%') {
            value = getEvalledConstructor('async function* () {}');
        } else if (name === '%AsyncGenerator%') {
            var fn = doEval('%AsyncGeneratorFunction%');
            if (fn) {
                value = fn.prototype;
            }
        } else if (name === '%AsyncIteratorPrototype%') {
            var gen = doEval('%AsyncGenerator%');
            if (gen && getProto) {
                value = getProto(gen.prototype);
            }
        }
    
        INTRINSICS[name] = value;
    
        return value;
    };
    
    var LEGACY_ALIASES = {
        '%ArrayBufferPrototype%': ['ArrayBuffer', 'prototype'],
        '%ArrayPrototype%': ['Array', 'prototype'],
        '%ArrayProto_entries%': ['Array', 'prototype', 'entries'],
        '%ArrayProto_forEach%': ['Array', 'prototype', 'forEach'],
        '%ArrayProto_keys%': ['Array', 'prototype', 'keys'],
        '%ArrayProto_values%': ['Array', 'prototype', 'values'],
        '%AsyncFunctionPrototype%': ['AsyncFunction', 'prototype'],
        '%AsyncGenerator%': ['AsyncGeneratorFunction', 'prototype'],
        '%AsyncGeneratorPrototype%': ['AsyncGeneratorFunction', 'prototype', 'prototype'],
        '%BooleanPrototype%': ['Boolean', 'prototype'],
        '%DataViewPrototype%': ['DataView', 'prototype'],
        '%DatePrototype%': ['Date', 'prototype'],
        '%ErrorPrototype%': ['Error', 'prototype'],
        '%EvalErrorPrototype%': ['EvalError', 'prototype'],
        '%Float32ArrayPrototype%': ['Float32Array', 'prototype'],
        '%Float64ArrayPrototype%': ['Float64Array', 'prototype'],
        '%FunctionPrototype%': ['Function', 'prototype'],
        '%Generator%': ['GeneratorFunction', 'prototype'],
        '%GeneratorPrototype%': ['GeneratorFunction', 'prototype', 'prototype'],
        '%Int8ArrayPrototype%': ['Int8Array', 'prototype'],
        '%Int16ArrayPrototype%': ['Int16Array', 'prototype'],
        '%Int32ArrayPrototype%': ['Int32Array', 'prototype'],
        '%JSONParse%': ['JSON', 'parse'],
        '%JSONStringify%': ['JSON', 'stringify'],
        '%MapPrototype%': ['Map', 'prototype'],
        '%NumberPrototype%': ['Number', 'prototype'],
        '%ObjectPrototype%': ['Object', 'prototype'],
        '%ObjProto_toString%': ['Object', 'prototype', 'toString'],
        '%ObjProto_valueOf%': ['Object', 'prototype', 'valueOf'],
        '%PromisePrototype%': ['Promise', 'prototype'],
        '%PromiseProto_then%': ['Promise', 'prototype', 'then'],
        '%Promise_all%': ['Promise', 'all'],
        '%Promise_reject%': ['Promise', 'reject'],
        '%Promise_resolve%': ['Promise', 'resolve'],
        '%RangeErrorPrototype%': ['RangeError', 'prototype'],
        '%ReferenceErrorPrototype%': ['ReferenceError', 'prototype'],
        '%RegExpPrototype%': ['RegExp', 'prototype'],
        '%SetPrototype%': ['Set', 'prototype'],
        '%SharedArrayBufferPrototype%': ['SharedArrayBuffer', 'prototype'],
        '%StringPrototype%': ['String', 'prototype'],
        '%SymbolPrototype%': ['Symbol', 'prototype'],
        '%SyntaxErrorPrototype%': ['SyntaxError', 'prototype'],
        '%TypedArrayPrototype%': ['TypedArray', 'prototype'],
        '%TypeErrorPrototype%': ['TypeError', 'prototype'],
        '%Uint8ArrayPrototype%': ['Uint8Array', 'prototype'],
        '%Uint8ClampedArrayPrototype%': ['Uint8ClampedArray', 'prototype'],
        '%Uint16ArrayPrototype%': ['Uint16Array', 'prototype'],
        '%Uint32ArrayPrototype%': ['Uint32Array', 'prototype'],
        '%URIErrorPrototype%': ['URIError', 'prototype'],
        '%WeakMapPrototype%': ['WeakMap', 'prototype'],
        '%WeakSetPrototype%': ['WeakSet', 'prototype']
    };
    
    var bind = require('function-bind');
    var hasOwn = require('has');
    var $concat = bind.call(Function.call, Array.prototype.concat);
    var $spliceApply = bind.call(Function.apply, Array.prototype.splice);
    var $replace = bind.call(Function.call, String.prototype.replace);
    var $strSlice = bind.call(Function.call, String.prototype.slice);
    var $exec = bind.call(Function.call, RegExp.prototype.exec);
    
    /* adapted from https://github.com/lodash/lodash/blob/4.17.15/dist/lodash.js#L6735-L6744 */
    var rePropName = /[^%.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|%$))/g;
    var reEscapeChar = /\\(\\)?/g; /** Used to match backslashes in property paths. */
    var stringToPath = function stringToPath(string) {
        var first = $strSlice(string, 0, 1);
        var last = $strSlice(string, -1);
        if (first === '%' && last !== '%') {
            throw new $SyntaxError('invalid intrinsic syntax, expected closing `%`');
        } else if (last === '%' && first !== '%') {
            throw new $SyntaxError('invalid intrinsic syntax, expected opening `%`');
        }
        var result = [];
        $replace(string, rePropName, function (match, number, quote, subString) {
            result[result.length] = quote ? $replace(subString, reEscapeChar, '$1') : number || match;
        });
        return result;
    };
    /* end adaptation */
    
    var getBaseIntrinsic = function getBaseIntrinsic(name, allowMissing) {
        var intrinsicName = name;
        var alias;
        if (hasOwn(LEGACY_ALIASES, intrinsicName)) {
            alias = LEGACY_ALIASES[intrinsicName];
            intrinsicName = '%' + alias[0] + '%';
        }
    
        if (hasOwn(INTRINSICS, intrinsicName)) {
            var value = INTRINSICS[intrinsicName];
            if (value === needsEval) {
                value = doEval(intrinsicName);
            }
            if (typeof value === 'undefined' && !allowMissing) {
                throw new $TypeError('intrinsic ' + name + ' exists, but is not available. Please file an issue!');
            }
    
            return {
                alias: alias,
                name: intrinsicName,
                value: value
            };
        }
    
        throw new $SyntaxError('intrinsic ' + name + ' does not exist!');
    };
    
    module.exports = function GetIntrinsic(name, allowMissing) {
        if (typeof name !== 'string' || name.length === 0) {
            throw new $TypeError('intrinsic name must be a non-empty string');
        }
        if (arguments.length > 1 && typeof allowMissing !== 'boolean') {
            throw new $TypeError('"allowMissing" argument must be a boolean');
        }
    
        if ($exec(/^%?[^%]*%?$/, name) === null) {
            throw new $SyntaxError('`%` may not be present anywhere but at the beginning and end of the intrinsic name');
        }
        var parts = stringToPath(name);
        var intrinsicBaseName = parts.length > 0 ? parts[0] : '';
    
        var intrinsic = getBaseIntrinsic('%' + intrinsicBaseName + '%', allowMissing);
        var intrinsicRealName = intrinsic.name;
        var value = intrinsic.value;
        var skipFurtherCaching = false;
    
        var alias = intrinsic.alias;
        if (alias) {
            intrinsicBaseName = alias[0];
            $spliceApply(parts, $concat([0, 1], alias));
        }
    
        for (var i = 1, isOwn = true; i < parts.length; i += 1) {
            var part = parts[i];
            var first = $strSlice(part, 0, 1);
            var last = $strSlice(part, -1);
            if (
                (
                    (first === '"' || first === "'" || first === '`')
                    || (last === '"' || last === "'" || last === '`')
                )
                && first !== last
            ) {
                throw new $SyntaxError('property names with quotes must have matching quotes');
            }
            if (part === 'constructor' || !isOwn) {
                skipFurtherCaching = true;
            }
    
            intrinsicBaseName += '.' + part;
            intrinsicRealName = '%' + intrinsicBaseName + '%';
    
            if (hasOwn(INTRINSICS, intrinsicRealName)) {
                value = INTRINSICS[intrinsicRealName];
            } else if (value != null) {
                if (!(part in value)) {
                    if (!allowMissing) {
                        throw new $TypeError('base intrinsic for ' + name + ' exists, but the property is not available.');
                    }
                    return void undefined;
                }
                if ($gOPD && (i + 1) >= parts.length) {
                    var desc = $gOPD(value, part);
                    isOwn = !!desc;
    
                    // By convention, when a data property is converted to an accessor
                    // property to emulate a data property that does not suffer from
                    // the override mistake, that accessor's getter is marked with
                    // an `originalValue` property. Here, when we detect this, we
                    // uphold the illusion by pretending to see that original data
                    // property, i.e., returning the value rather than the getter
                    // itself.
                    if (isOwn && 'get' in desc && !('originalValue' in desc.get)) {
                        value = desc.get;
                    } else {
                        value = value[part];
                    }
                } else {
                    isOwn = hasOwn(value, part);
                    value = value[part];
                }
    
                if (isOwn && !skipFurtherCaching) {
                    INTRINSICS[intrinsicRealName] = value;
                }
            }
        }
        return value;
    };
    
    },{"function-bind":111,"has":118,"has-proto":114,"has-symbols":115}],113:[function(require,module,exports){
    'use strict';
    
    var GetIntrinsic = require('get-intrinsic');
    
    var $gOPD = GetIntrinsic('%Object.getOwnPropertyDescriptor%', true);
    
    if ($gOPD) {
        try {
            $gOPD([], 'length');
        } catch (e) {
            // IE 8 has a broken gOPD
            $gOPD = null;
        }
    }
    
    module.exports = $gOPD;
    
    },{"get-intrinsic":112}],114:[function(require,module,exports){
    'use strict';
    
    var test = {
        foo: {}
    };
    
    var $Object = Object;
    
    module.exports = function hasProto() {
        return { __proto__: test }.foo === test.foo && !({ __proto__: null } instanceof $Object);
    };
    
    },{}],115:[function(require,module,exports){
    'use strict';
    
    var origSymbol = typeof Symbol !== 'undefined' && Symbol;
    var hasSymbolSham = require('./shams');
    
    module.exports = function hasNativeSymbols() {
        if (typeof origSymbol !== 'function') { return false; }
        if (typeof Symbol !== 'function') { return false; }
        if (typeof origSymbol('foo') !== 'symbol') { return false; }
        if (typeof Symbol('bar') !== 'symbol') { return false; }
    
        return hasSymbolSham();
    };
    
    },{"./shams":116}],116:[function(require,module,exports){
    'use strict';
    
    /* eslint complexity: [2, 18], max-statements: [2, 33] */
    module.exports = function hasSymbols() {
        if (typeof Symbol !== 'function' || typeof Object.getOwnPropertySymbols !== 'function') { return false; }
        if (typeof Symbol.iterator === 'symbol') { return true; }
    
        var obj = {};
        var sym = Symbol('test');
        var symObj = Object(sym);
        if (typeof sym === 'string') { return false; }
    
        if (Object.prototype.toString.call(sym) !== '[object Symbol]') { return false; }
        if (Object.prototype.toString.call(symObj) !== '[object Symbol]') { return false; }
    
        // temp disabled per https://github.com/ljharb/object.assign/issues/17
        // if (sym instanceof Symbol) { return false; }
        // temp disabled per https://github.com/WebReflection/get-own-property-symbols/issues/4
        // if (!(symObj instanceof Symbol)) { return false; }
    
        // if (typeof Symbol.prototype.toString !== 'function') { return false; }
        // if (String(sym) !== Symbol.prototype.toString.call(sym)) { return false; }
    
        var symVal = 42;
        obj[sym] = symVal;
        for (sym in obj) { return false; } // eslint-disable-line no-restricted-syntax, no-unreachable-loop
        if (typeof Object.keys === 'function' && Object.keys(obj).length !== 0) { return false; }
    
        if (typeof Object.getOwnPropertyNames === 'function' && Object.getOwnPropertyNames(obj).length !== 0) { return false; }
    
        var syms = Object.getOwnPropertySymbols(obj);
        if (syms.length !== 1 || syms[0] !== sym) { return false; }
    
        if (!Object.prototype.propertyIsEnumerable.call(obj, sym)) { return false; }
    
        if (typeof Object.getOwnPropertyDescriptor === 'function') {
            var descriptor = Object.getOwnPropertyDescriptor(obj, sym);
            if (descriptor.value !== symVal || descriptor.enumerable !== true) { return false; }
        }
    
        return true;
    };
    
    },{}],117:[function(require,module,exports){
    'use strict';
    
    var hasSymbols = require('has-symbols/shams');
    
    module.exports = function hasToStringTagShams() {
        return hasSymbols() && !!Symbol.toStringTag;
    };
    
    },{"has-symbols/shams":116}],118:[function(require,module,exports){
    'use strict';
    
    var hasOwnProperty = {}.hasOwnProperty;
    var call = Function.prototype.call;
    
    module.exports = call.bind ? call.bind(hasOwnProperty) : function (O, P) {
      return call.call(hasOwnProperty, O, P);
    };
    
    },{}],119:[function(require,module,exports){
    'use strict'
    var Buffer = require('safe-buffer').Buffer
    var Transform = require('readable-stream').Transform
    var inherits = require('inherits')
    
    function throwIfNotStringOrBuffer (val, prefix) {
      if (!Buffer.isBuffer(val) && typeof val !== 'string') {
        throw new TypeError(prefix + ' must be a string or a buffer')
      }
    }
    
    function HashBase (blockSize) {
      Transform.call(this)
    
      this._block = Buffer.allocUnsafe(blockSize)
      this._blockSize = blockSize
      this._blockOffset = 0
      this._length = [0, 0, 0, 0]
    
      this._finalized = false
    }
    
    inherits(HashBase, Transform)
    
    HashBase.prototype._transform = function (chunk, encoding, callback) {
      var error = null
      try {
        this.update(chunk, encoding)
      } catch (err) {
        error = err
      }
    
      callback(error)
    }
    
    HashBase.prototype._flush = function (callback) {
      var error = null
      try {
        this.push(this.digest())
      } catch (err) {
        error = err
      }
    
      callback(error)
    }
    
    HashBase.prototype.update = function (data, encoding) {
      throwIfNotStringOrBuffer(data, 'Data')
      if (this._finalized) throw new Error('Digest already called')
      if (!Buffer.isBuffer(data)) data = Buffer.from(data, encoding)
    
      // consume data
      var block = this._block
      var offset = 0
      while (this._blockOffset + data.length - offset >= this._blockSize) {
        for (var i = this._blockOffset; i < this._blockSize;) block[i++] = data[offset++]
        this._update()
        this._blockOffset = 0
      }
      while (offset < data.length) block[this._blockOffset++] = data[offset++]
    
      // update length
      for (var j = 0, carry = data.length * 8; carry > 0; ++j) {
        this._length[j] += carry
        carry = (this._length[j] / 0x0100000000) | 0
        if (carry > 0) this._length[j] -= 0x0100000000 * carry
      }
    
      return this
    }
    
    HashBase.prototype._update = function () {
      throw new Error('_update is not implemented')
    }
    
    HashBase.prototype.digest = function (encoding) {
      if (this._finalized) throw new Error('Digest already called')
      this._finalized = true
    
      var digest = this._digest()
      if (encoding !== undefined) digest = digest.toString(encoding)
    
      // reset state
      this._block.fill(0)
      this._blockOffset = 0
      for (var i = 0; i < 4; ++i) this._length[i] = 0
    
      return digest
    }
    
    HashBase.prototype._digest = function () {
      throw new Error('_digest is not implemented')
    }
    
    module.exports = HashBase
    
    },{"inherits":149,"readable-stream":134,"safe-buffer":187}],120:[function(require,module,exports){
    arguments[4][52][0].apply(exports,arguments)
    },{"dup":52}],121:[function(require,module,exports){
    arguments[4][53][0].apply(exports,arguments)
    },{"./_stream_readable":123,"./_stream_writable":125,"_process":176,"dup":53,"inherits":149}],122:[function(require,module,exports){
    arguments[4][54][0].apply(exports,arguments)
    },{"./_stream_transform":124,"dup":54,"inherits":149}],123:[function(require,module,exports){
    arguments[4][55][0].apply(exports,arguments)
    },{"../errors":120,"./_stream_duplex":121,"./internal/streams/async_iterator":126,"./internal/streams/buffer_list":127,"./internal/streams/destroy":128,"./internal/streams/from":130,"./internal/streams/state":132,"./internal/streams/stream":133,"_process":176,"buffer":68,"dup":55,"events":107,"inherits":149,"string_decoder/":212,"util":24}],124:[function(require,module,exports){
    arguments[4][56][0].apply(exports,arguments)
    },{"../errors":120,"./_stream_duplex":121,"dup":56,"inherits":149}],125:[function(require,module,exports){
    arguments[4][57][0].apply(exports,arguments)
    },{"../errors":120,"./_stream_duplex":121,"./internal/streams/destroy":128,"./internal/streams/state":132,"./internal/streams/stream":133,"_process":176,"buffer":68,"dup":57,"inherits":149,"util-deprecate":213}],126:[function(require,module,exports){
    arguments[4][58][0].apply(exports,arguments)
    },{"./end-of-stream":129,"_process":176,"dup":58}],127:[function(require,module,exports){
    arguments[4][59][0].apply(exports,arguments)
    },{"buffer":68,"dup":59,"util":24}],128:[function(require,module,exports){
    arguments[4][60][0].apply(exports,arguments)
    },{"_process":176,"dup":60}],129:[function(require,module,exports){
    arguments[4][61][0].apply(exports,arguments)
    },{"../../../errors":120,"dup":61}],130:[function(require,module,exports){
    arguments[4][62][0].apply(exports,arguments)
    },{"dup":62}],131:[function(require,module,exports){
    arguments[4][63][0].apply(exports,arguments)
    },{"../../../errors":120,"./end-of-stream":129,"dup":63}],132:[function(require,module,exports){
    arguments[4][64][0].apply(exports,arguments)
    },{"../../../errors":120,"dup":64}],133:[function(require,module,exports){
    arguments[4][65][0].apply(exports,arguments)
    },{"dup":65,"events":107}],134:[function(require,module,exports){
    arguments[4][66][0].apply(exports,arguments)
    },{"./lib/_stream_duplex.js":121,"./lib/_stream_passthrough.js":122,"./lib/_stream_readable.js":123,"./lib/_stream_transform.js":124,"./lib/_stream_writable.js":125,"./lib/internal/streams/end-of-stream.js":129,"./lib/internal/streams/pipeline.js":131,"dup":66}],135:[function(require,module,exports){
    var hash = exports;
    
    hash.utils = require('./hash/utils');
    hash.common = require('./hash/common');
    hash.sha = require('./hash/sha');
    hash.ripemd = require('./hash/ripemd');
    hash.hmac = require('./hash/hmac');
    
    // Proxy hash functions to the main object
    hash.sha1 = hash.sha.sha1;
    hash.sha256 = hash.sha.sha256;
    hash.sha224 = hash.sha.sha224;
    hash.sha384 = hash.sha.sha384;
    hash.sha512 = hash.sha.sha512;
    hash.ripemd160 = hash.ripemd.ripemd160;
    
    },{"./hash/common":136,"./hash/hmac":137,"./hash/ripemd":138,"./hash/sha":139,"./hash/utils":146}],136:[function(require,module,exports){
    'use strict';
    
    var utils = require('./utils');
    var assert = require('minimalistic-assert');
    
    function BlockHash() {
      this.pending = null;
      this.pendingTotal = 0;
      this.blockSize = this.constructor.blockSize;
      this.outSize = this.constructor.outSize;
      this.hmacStrength = this.constructor.hmacStrength;
      this.padLength = this.constructor.padLength / 8;
      this.endian = 'big';
    
      this._delta8 = this.blockSize / 8;
      this._delta32 = this.blockSize / 32;
    }
    exports.BlockHash = BlockHash;
    
    BlockHash.prototype.update = function update(msg, enc) {
      // Convert message to array, pad it, and join into 32bit blocks
      msg = utils.toArray(msg, enc);
      if (!this.pending)
        this.pending = msg;
      else
        this.pending = this.pending.concat(msg);
      this.pendingTotal += msg.length;
    
      // Enough data, try updating
      if (this.pending.length >= this._delta8) {
        msg = this.pending;
    
        // Process pending data in blocks
        var r = msg.length % this._delta8;
        this.pending = msg.slice(msg.length - r, msg.length);
        if (this.pending.length === 0)
          this.pending = null;
    
        msg = utils.join32(msg, 0, msg.length - r, this.endian);
        for (var i = 0; i < msg.length; i += this._delta32)
          this._update(msg, i, i + this._delta32);
      }
    
      return this;
    };
    
    BlockHash.prototype.digest = function digest(enc) {
      this.update(this._pad());
      assert(this.pending === null);
    
      return this._digest(enc);
    };
    
    BlockHash.prototype._pad = function pad() {
      var len = this.pendingTotal;
      var bytes = this._delta8;
      var k = bytes - ((len + this.padLength) % bytes);
      var res = new Array(k + this.padLength);
      res[0] = 0x80;
      for (var i = 1; i < k; i++)
        res[i] = 0;
    
      // Append length
      len <<= 3;
      if (this.endian === 'big') {
        for (var t = 8; t < this.padLength; t++)
          res[i++] = 0;
    
        res[i++] = 0;
        res[i++] = 0;
        res[i++] = 0;
        res[i++] = 0;
        res[i++] = (len >>> 24) & 0xff;
        res[i++] = (len >>> 16) & 0xff;
        res[i++] = (len >>> 8) & 0xff;
        res[i++] = len & 0xff;
      } else {
        res[i++] = len & 0xff;
        res[i++] = (len >>> 8) & 0xff;
        res[i++] = (len >>> 16) & 0xff;
        res[i++] = (len >>> 24) & 0xff;
        res[i++] = 0;
        res[i++] = 0;
        res[i++] = 0;
        res[i++] = 0;
    
        for (t = 8; t < this.padLength; t++)
          res[i++] = 0;
      }
    
      return res;
    };
    
    },{"./utils":146,"minimalistic-assert":158}],137:[function(require,module,exports){
    'use strict';
    
    var utils = require('./utils');
    var assert = require('minimalistic-assert');
    
    function Hmac(hash, key, enc) {
      if (!(this instanceof Hmac))
        return new Hmac(hash, key, enc);
      this.Hash = hash;
      this.blockSize = hash.blockSize / 8;
      this.outSize = hash.outSize / 8;
      this.inner = null;
      this.outer = null;
    
      this._init(utils.toArray(key, enc));
    }
    module.exports = Hmac;
    
    Hmac.prototype._init = function init(key) {
      // Shorten key, if needed
      if (key.length > this.blockSize)
        key = new this.Hash().update(key).digest();
      assert(key.length <= this.blockSize);
    
      // Add padding to key
      for (var i = key.length; i < this.blockSize; i++)
        key.push(0);
    
      for (i = 0; i < key.length; i++)
        key[i] ^= 0x36;
      this.inner = new this.Hash().update(key);
    
      // 0x36 ^ 0x5c = 0x6a
      for (i = 0; i < key.length; i++)
        key[i] ^= 0x6a;
      this.outer = new this.Hash().update(key);
    };
    
    Hmac.prototype.update = function update(msg, enc) {
      this.inner.update(msg, enc);
      return this;
    };
    
    Hmac.prototype.digest = function digest(enc) {
      this.outer.update(this.inner.digest());
      return this.outer.digest(enc);
    };
    
    },{"./utils":146,"minimalistic-assert":158}],138:[function(require,module,exports){
    'use strict';
    
    var utils = require('./utils');
    var common = require('./common');
    
    var rotl32 = utils.rotl32;
    var sum32 = utils.sum32;
    var sum32_3 = utils.sum32_3;
    var sum32_4 = utils.sum32_4;
    var BlockHash = common.BlockHash;
    
    function RIPEMD160() {
      if (!(this instanceof RIPEMD160))
        return new RIPEMD160();
    
      BlockHash.call(this);
    
      this.h = [ 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0 ];
      this.endian = 'little';
    }
    utils.inherits(RIPEMD160, BlockHash);
    exports.ripemd160 = RIPEMD160;
    
    RIPEMD160.blockSize = 512;
    RIPEMD160.outSize = 160;
    RIPEMD160.hmacStrength = 192;
    RIPEMD160.padLength = 64;
    
    RIPEMD160.prototype._update = function update(msg, start) {
      var A = this.h[0];
      var B = this.h[1];
      var C = this.h[2];
      var D = this.h[3];
      var E = this.h[4];
      var Ah = A;
      var Bh = B;
      var Ch = C;
      var Dh = D;
      var Eh = E;
      for (var j = 0; j < 80; j++) {
        var T = sum32(
          rotl32(
            sum32_4(A, f(j, B, C, D), msg[r[j] + start], K(j)),
            s[j]),
          E);
        A = E;
        E = D;
        D = rotl32(C, 10);
        C = B;
        B = T;
        T = sum32(
          rotl32(
            sum32_4(Ah, f(79 - j, Bh, Ch, Dh), msg[rh[j] + start], Kh(j)),
            sh[j]),
          Eh);
        Ah = Eh;
        Eh = Dh;
        Dh = rotl32(Ch, 10);
        Ch = Bh;
        Bh = T;
      }
      T = sum32_3(this.h[1], C, Dh);
      this.h[1] = sum32_3(this.h[2], D, Eh);
      this.h[2] = sum32_3(this.h[3], E, Ah);
      this.h[3] = sum32_3(this.h[4], A, Bh);
      this.h[4] = sum32_3(this.h[0], B, Ch);
      this.h[0] = T;
    };
    
    RIPEMD160.prototype._digest = function digest(enc) {
      if (enc === 'hex')
        return utils.toHex32(this.h, 'little');
      else
        return utils.split32(this.h, 'little');
    };
    
    function f(j, x, y, z) {
      if (j <= 15)
        return x ^ y ^ z;
      else if (j <= 31)
        return (x & y) | ((~x) & z);
      else if (j <= 47)
        return (x | (~y)) ^ z;
      else if (j <= 63)
        return (x & z) | (y & (~z));
      else
        return x ^ (y | (~z));
    }
    
    function K(j) {
      if (j <= 15)
        return 0x00000000;
      else if (j <= 31)
        return 0x5a827999;
      else if (j <= 47)
        return 0x6ed9eba1;
      else if (j <= 63)
        return 0x8f1bbcdc;
      else
        return 0xa953fd4e;
    }
    
    function Kh(j) {
      if (j <= 15)
        return 0x50a28be6;
      else if (j <= 31)
        return 0x5c4dd124;
      else if (j <= 47)
        return 0x6d703ef3;
      else if (j <= 63)
        return 0x7a6d76e9;
      else
        return 0x00000000;
    }
    
    var r = [
      0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
      7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8,
      3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12,
      1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2,
      4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13
    ];
    
    var rh = [
      5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12,
      6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2,
      15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13,
      8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14,
      12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11
    ];
    
    var s = [
      11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8,
      7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12,
      11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5,
      11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12,
      9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6
    ];
    
    var sh = [
      8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6,
      9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11,
      9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5,
      15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8,
      8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11
    ];
    
    },{"./common":136,"./utils":146}],139:[function(require,module,exports){
    'use strict';
    
    exports.sha1 = require('./sha/1');
    exports.sha224 = require('./sha/224');
    exports.sha256 = require('./sha/256');
    exports.sha384 = require('./sha/384');
    exports.sha512 = require('./sha/512');
    
    },{"./sha/1":140,"./sha/224":141,"./sha/256":142,"./sha/384":143,"./sha/512":144}],140:[function(require,module,exports){
    'use strict';
    
    var utils = require('../utils');
    var common = require('../common');
    var shaCommon = require('./common');
    
    var rotl32 = utils.rotl32;
    var sum32 = utils.sum32;
    var sum32_5 = utils.sum32_5;
    var ft_1 = shaCommon.ft_1;
    var BlockHash = common.BlockHash;
    
    var sha1_K = [
      0x5A827999, 0x6ED9EBA1,
      0x8F1BBCDC, 0xCA62C1D6
    ];
    
    function SHA1() {
      if (!(this instanceof SHA1))
        return new SHA1();
    
      BlockHash.call(this);
      this.h = [
        0x67452301, 0xefcdab89, 0x98badcfe,
        0x10325476, 0xc3d2e1f0 ];
      this.W = new Array(80);
    }
    
    utils.inherits(SHA1, BlockHash);
    module.exports = SHA1;
    
    SHA1.blockSize = 512;
    SHA1.outSize = 160;
    SHA1.hmacStrength = 80;
    SHA1.padLength = 64;
    
    SHA1.prototype._update = function _update(msg, start) {
      var W = this.W;
    
      for (var i = 0; i < 16; i++)
        W[i] = msg[start + i];
    
      for(; i < W.length; i++)
        W[i] = rotl32(W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16], 1);
    
      var a = this.h[0];
      var b = this.h[1];
      var c = this.h[2];
      var d = this.h[3];
      var e = this.h[4];
    
      for (i = 0; i < W.length; i++) {
        var s = ~~(i / 20);
        var t = sum32_5(rotl32(a, 5), ft_1(s, b, c, d), e, W[i], sha1_K[s]);
        e = d;
        d = c;
        c = rotl32(b, 30);
        b = a;
        a = t;
      }
    
      this.h[0] = sum32(this.h[0], a);
      this.h[1] = sum32(this.h[1], b);
      this.h[2] = sum32(this.h[2], c);
      this.h[3] = sum32(this.h[3], d);
      this.h[4] = sum32(this.h[4], e);
    };
    
    SHA1.prototype._digest = function digest(enc) {
      if (enc === 'hex')
        return utils.toHex32(this.h, 'big');
      else
        return utils.split32(this.h, 'big');
    };
    
    },{"../common":136,"../utils":146,"./common":145}],141:[function(require,module,exports){
    'use strict';
    
    var utils = require('../utils');
    var SHA256 = require('./256');
    
    function SHA224() {
      if (!(this instanceof SHA224))
        return new SHA224();
    
      SHA256.call(this);
      this.h = [
        0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939,
        0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4 ];
    }
    utils.inherits(SHA224, SHA256);
    module.exports = SHA224;
    
    SHA224.blockSize = 512;
    SHA224.outSize = 224;
    SHA224.hmacStrength = 192;
    SHA224.padLength = 64;
    
    SHA224.prototype._digest = function digest(enc) {
      // Just truncate output
      if (enc === 'hex')
        return utils.toHex32(this.h.slice(0, 7), 'big');
      else
        return utils.split32(this.h.slice(0, 7), 'big');
    };
    
    
    },{"../utils":146,"./256":142}],142:[function(require,module,exports){
    'use strict';
    
    var utils = require('../utils');
    var common = require('../common');
    var shaCommon = require('./common');
    var assert = require('minimalistic-assert');
    
    var sum32 = utils.sum32;
    var sum32_4 = utils.sum32_4;
    var sum32_5 = utils.sum32_5;
    var ch32 = shaCommon.ch32;
    var maj32 = shaCommon.maj32;
    var s0_256 = shaCommon.s0_256;
    var s1_256 = shaCommon.s1_256;
    var g0_256 = shaCommon.g0_256;
    var g1_256 = shaCommon.g1_256;
    
    var BlockHash = common.BlockHash;
    
    var sha256_K = [
      0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
      0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
      0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
      0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
      0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
      0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
      0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
      0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
      0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
      0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
      0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
      0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
      0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
      0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
      0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
      0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
    ];
    
    function SHA256() {
      if (!(this instanceof SHA256))
        return new SHA256();
    
      BlockHash.call(this);
      this.h = [
        0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
        0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
      ];
      this.k = sha256_K;
      this.W = new Array(64);
    }
    utils.inherits(SHA256, BlockHash);
    module.exports = SHA256;
    
    SHA256.blockSize = 512;
    SHA256.outSize = 256;
    SHA256.hmacStrength = 192;
    SHA256.padLength = 64;
    
    SHA256.prototype._update = function _update(msg, start) {
      var W = this.W;
    
      for (var i = 0; i < 16; i++)
        W[i] = msg[start + i];
      for (; i < W.length; i++)
        W[i] = sum32_4(g1_256(W[i - 2]), W[i - 7], g0_256(W[i - 15]), W[i - 16]);
    
      var a = this.h[0];
      var b = this.h[1];
      var c = this.h[2];
      var d = this.h[3];
      var e = this.h[4];
      var f = this.h[5];
      var g = this.h[6];
      var h = this.h[7];
    
      assert(this.k.length === W.length);
      for (i = 0; i < W.length; i++) {
        var T1 = sum32_5(h, s1_256(e), ch32(e, f, g), this.k[i], W[i]);
        var T2 = sum32(s0_256(a), maj32(a, b, c));
        h = g;
        g = f;
        f = e;
        e = sum32(d, T1);
        d = c;
        c = b;
        b = a;
        a = sum32(T1, T2);
      }
    
      this.h[0] = sum32(this.h[0], a);
      this.h[1] = sum32(this.h[1], b);
      this.h[2] = sum32(this.h[2], c);
      this.h[3] = sum32(this.h[3], d);
      this.h[4] = sum32(this.h[4], e);
      this.h[5] = sum32(this.h[5], f);
      this.h[6] = sum32(this.h[6], g);
      this.h[7] = sum32(this.h[7], h);
    };
    
    SHA256.prototype._digest = function digest(enc) {
      if (enc === 'hex')
        return utils.toHex32(this.h, 'big');
      else
        return utils.split32(this.h, 'big');
    };
    
    },{"../common":136,"../utils":146,"./common":145,"minimalistic-assert":158}],143:[function(require,module,exports){
    'use strict';
    
    var utils = require('../utils');
    
    var SHA512 = require('./512');
    
    function SHA384() {
      if (!(this instanceof SHA384))
        return new SHA384();
    
      SHA512.call(this);
      this.h = [
        0xcbbb9d5d, 0xc1059ed8,
        0x629a292a, 0x367cd507,
        0x9159015a, 0x3070dd17,
        0x152fecd8, 0xf70e5939,
        0x67332667, 0xffc00b31,
        0x8eb44a87, 0x68581511,
        0xdb0c2e0d, 0x64f98fa7,
        0x47b5481d, 0xbefa4fa4 ];
    }
    utils.inherits(SHA384, SHA512);
    module.exports = SHA384;
    
    SHA384.blockSize = 1024;
    SHA384.outSize = 384;
    SHA384.hmacStrength = 192;
    SHA384.padLength = 128;
    
    SHA384.prototype._digest = function digest(enc) {
      if (enc === 'hex')
        return utils.toHex32(this.h.slice(0, 12), 'big');
      else
        return utils.split32(this.h.slice(0, 12), 'big');
    };
    
    },{"../utils":146,"./512":144}],144:[function(require,module,exports){
    'use strict';
    
    var utils = require('../utils');
    var common = require('../common');
    var assert = require('minimalistic-assert');
    
    var rotr64_hi = utils.rotr64_hi;
    var rotr64_lo = utils.rotr64_lo;
    var shr64_hi = utils.shr64_hi;
    var shr64_lo = utils.shr64_lo;
    var sum64 = utils.sum64;
    var sum64_hi = utils.sum64_hi;
    var sum64_lo = utils.sum64_lo;
    var sum64_4_hi = utils.sum64_4_hi;
    var sum64_4_lo = utils.sum64_4_lo;
    var sum64_5_hi = utils.sum64_5_hi;
    var sum64_5_lo = utils.sum64_5_lo;
    
    var BlockHash = common.BlockHash;
    
    var sha512_K = [
      0x428a2f98, 0xd728ae22, 0x71374491, 0x23ef65cd,
      0xb5c0fbcf, 0xec4d3b2f, 0xe9b5dba5, 0x8189dbbc,
      0x3956c25b, 0xf348b538, 0x59f111f1, 0xb605d019,
      0x923f82a4, 0xaf194f9b, 0xab1c5ed5, 0xda6d8118,
      0xd807aa98, 0xa3030242, 0x12835b01, 0x45706fbe,
      0x243185be, 0x4ee4b28c, 0x550c7dc3, 0xd5ffb4e2,
      0x72be5d74, 0xf27b896f, 0x80deb1fe, 0x3b1696b1,
      0x9bdc06a7, 0x25c71235, 0xc19bf174, 0xcf692694,
      0xe49b69c1, 0x9ef14ad2, 0xefbe4786, 0x384f25e3,
      0x0fc19dc6, 0x8b8cd5b5, 0x240ca1cc, 0x77ac9c65,
      0x2de92c6f, 0x592b0275, 0x4a7484aa, 0x6ea6e483,
      0x5cb0a9dc, 0xbd41fbd4, 0x76f988da, 0x831153b5,
      0x983e5152, 0xee66dfab, 0xa831c66d, 0x2db43210,
      0xb00327c8, 0x98fb213f, 0xbf597fc7, 0xbeef0ee4,
      0xc6e00bf3, 0x3da88fc2, 0xd5a79147, 0x930aa725,
      0x06ca6351, 0xe003826f, 0x14292967, 0x0a0e6e70,
      0x27b70a85, 0x46d22ffc, 0x2e1b2138, 0x5c26c926,
      0x4d2c6dfc, 0x5ac42aed, 0x53380d13, 0x9d95b3df,
      0x650a7354, 0x8baf63de, 0x766a0abb, 0x3c77b2a8,
      0x81c2c92e, 0x47edaee6, 0x92722c85, 0x1482353b,
      0xa2bfe8a1, 0x4cf10364, 0xa81a664b, 0xbc423001,
      0xc24b8b70, 0xd0f89791, 0xc76c51a3, 0x0654be30,
      0xd192e819, 0xd6ef5218, 0xd6990624, 0x5565a910,
      0xf40e3585, 0x5771202a, 0x106aa070, 0x32bbd1b8,
      0x19a4c116, 0xb8d2d0c8, 0x1e376c08, 0x5141ab53,
      0x2748774c, 0xdf8eeb99, 0x34b0bcb5, 0xe19b48a8,
      0x391c0cb3, 0xc5c95a63, 0x4ed8aa4a, 0xe3418acb,
      0x5b9cca4f, 0x7763e373, 0x682e6ff3, 0xd6b2b8a3,
      0x748f82ee, 0x5defb2fc, 0x78a5636f, 0x43172f60,
      0x84c87814, 0xa1f0ab72, 0x8cc70208, 0x1a6439ec,
      0x90befffa, 0x23631e28, 0xa4506ceb, 0xde82bde9,
      0xbef9a3f7, 0xb2c67915, 0xc67178f2, 0xe372532b,
      0xca273ece, 0xea26619c, 0xd186b8c7, 0x21c0c207,
      0xeada7dd6, 0xcde0eb1e, 0xf57d4f7f, 0xee6ed178,
      0x06f067aa, 0x72176fba, 0x0a637dc5, 0xa2c898a6,
      0x113f9804, 0xbef90dae, 0x1b710b35, 0x131c471b,
      0x28db77f5, 0x23047d84, 0x32caab7b, 0x40c72493,
      0x3c9ebe0a, 0x15c9bebc, 0x431d67c4, 0x9c100d4c,
      0x4cc5d4be, 0xcb3e42b6, 0x597f299c, 0xfc657e2a,
      0x5fcb6fab, 0x3ad6faec, 0x6c44198c, 0x4a475817
    ];
    
    function SHA512() {
      if (!(this instanceof SHA512))
        return new SHA512();
    
      BlockHash.call(this);
      this.h = [
        0x6a09e667, 0xf3bcc908,
        0xbb67ae85, 0x84caa73b,
        0x3c6ef372, 0xfe94f82b,
        0xa54ff53a, 0x5f1d36f1,
        0x510e527f, 0xade682d1,
        0x9b05688c, 0x2b3e6c1f,
        0x1f83d9ab, 0xfb41bd6b,
        0x5be0cd19, 0x137e2179 ];
      this.k = sha512_K;
      this.W = new Array(160);
    }
    utils.inherits(SHA512, BlockHash);
    module.exports = SHA512;
    
    SHA512.blockSize = 1024;
    SHA512.outSize = 512;
    SHA512.hmacStrength = 192;
    SHA512.padLength = 128;
    
    SHA512.prototype._prepareBlock = function _prepareBlock(msg, start) {
      var W = this.W;
    
      // 32 x 32bit words
      for (var i = 0; i < 32; i++)
        W[i] = msg[start + i];
      for (; i < W.length; i += 2) {
        var c0_hi = g1_512_hi(W[i - 4], W[i - 3]);  // i - 2
        var c0_lo = g1_512_lo(W[i - 4], W[i - 3]);
        var c1_hi = W[i - 14];  // i - 7
        var c1_lo = W[i - 13];
        var c2_hi = g0_512_hi(W[i - 30], W[i - 29]);  // i - 15
        var c2_lo = g0_512_lo(W[i - 30], W[i - 29]);
        var c3_hi = W[i - 32];  // i - 16
        var c3_lo = W[i - 31];
    
        W[i] = sum64_4_hi(
          c0_hi, c0_lo,
          c1_hi, c1_lo,
          c2_hi, c2_lo,
          c3_hi, c3_lo);
        W[i + 1] = sum64_4_lo(
          c0_hi, c0_lo,
          c1_hi, c1_lo,
          c2_hi, c2_lo,
          c3_hi, c3_lo);
      }
    };
    
    SHA512.prototype._update = function _update(msg, start) {
      this._prepareBlock(msg, start);
    
      var W = this.W;
    
      var ah = this.h[0];
      var al = this.h[1];
      var bh = this.h[2];
      var bl = this.h[3];
      var ch = this.h[4];
      var cl = this.h[5];
      var dh = this.h[6];
      var dl = this.h[7];
      var eh = this.h[8];
      var el = this.h[9];
      var fh = this.h[10];
      var fl = this.h[11];
      var gh = this.h[12];
      var gl = this.h[13];
      var hh = this.h[14];
      var hl = this.h[15];
    
      assert(this.k.length === W.length);
      for (var i = 0; i < W.length; i += 2) {
        var c0_hi = hh;
        var c0_lo = hl;
        var c1_hi = s1_512_hi(eh, el);
        var c1_lo = s1_512_lo(eh, el);
        var c2_hi = ch64_hi(eh, el, fh, fl, gh, gl);
        var c2_lo = ch64_lo(eh, el, fh, fl, gh, gl);
        var c3_hi = this.k[i];
        var c3_lo = this.k[i + 1];
        var c4_hi = W[i];
        var c4_lo = W[i + 1];
    
        var T1_hi = sum64_5_hi(
          c0_hi, c0_lo,
          c1_hi, c1_lo,
          c2_hi, c2_lo,
          c3_hi, c3_lo,
          c4_hi, c4_lo);
        var T1_lo = sum64_5_lo(
          c0_hi, c0_lo,
          c1_hi, c1_lo,
          c2_hi, c2_lo,
          c3_hi, c3_lo,
          c4_hi, c4_lo);
    
        c0_hi = s0_512_hi(ah, al);
        c0_lo = s0_512_lo(ah, al);
        c1_hi = maj64_hi(ah, al, bh, bl, ch, cl);
        c1_lo = maj64_lo(ah, al, bh, bl, ch, cl);
    
        var T2_hi = sum64_hi(c0_hi, c0_lo, c1_hi, c1_lo);
        var T2_lo = sum64_lo(c0_hi, c0_lo, c1_hi, c1_lo);
    
        hh = gh;
        hl = gl;
    
        gh = fh;
        gl = fl;
    
        fh = eh;
        fl = el;
    
        eh = sum64_hi(dh, dl, T1_hi, T1_lo);
        el = sum64_lo(dl, dl, T1_hi, T1_lo);
    
        dh = ch;
        dl = cl;
    
        ch = bh;
        cl = bl;
    
        bh = ah;
        bl = al;
    
        ah = sum64_hi(T1_hi, T1_lo, T2_hi, T2_lo);
        al = sum64_lo(T1_hi, T1_lo, T2_hi, T2_lo);
      }
    
      sum64(this.h, 0, ah, al);
      sum64(this.h, 2, bh, bl);
      sum64(this.h, 4, ch, cl);
      sum64(this.h, 6, dh, dl);
      sum64(this.h, 8, eh, el);
      sum64(this.h, 10, fh, fl);
      sum64(this.h, 12, gh, gl);
      sum64(this.h, 14, hh, hl);
    };
    
    SHA512.prototype._digest = function digest(enc) {
      if (enc === 'hex')
        return utils.toHex32(this.h, 'big');
      else
        return utils.split32(this.h, 'big');
    };
    
    function ch64_hi(xh, xl, yh, yl, zh) {
      var r = (xh & yh) ^ ((~xh) & zh);
      if (r < 0)
        r += 0x100000000;
      return r;
    }
    
    function ch64_lo(xh, xl, yh, yl, zh, zl) {
      var r = (xl & yl) ^ ((~xl) & zl);
      if (r < 0)
        r += 0x100000000;
      return r;
    }
    
    function maj64_hi(xh, xl, yh, yl, zh) {
      var r = (xh & yh) ^ (xh & zh) ^ (yh & zh);
      if (r < 0)
        r += 0x100000000;
      return r;
    }
    
    function maj64_lo(xh, xl, yh, yl, zh, zl) {
      var r = (xl & yl) ^ (xl & zl) ^ (yl & zl);
      if (r < 0)
        r += 0x100000000;
      return r;
    }
    
    function s0_512_hi(xh, xl) {
      var c0_hi = rotr64_hi(xh, xl, 28);
      var c1_hi = rotr64_hi(xl, xh, 2);  // 34
      var c2_hi = rotr64_hi(xl, xh, 7);  // 39
    
      var r = c0_hi ^ c1_hi ^ c2_hi;
      if (r < 0)
        r += 0x100000000;
      return r;
    }
    
    function s0_512_lo(xh, xl) {
      var c0_lo = rotr64_lo(xh, xl, 28);
      var c1_lo = rotr64_lo(xl, xh, 2);  // 34
      var c2_lo = rotr64_lo(xl, xh, 7);  // 39
    
      var r = c0_lo ^ c1_lo ^ c2_lo;
      if (r < 0)
        r += 0x100000000;
      return r;
    }
    
    function s1_512_hi(xh, xl) {
      var c0_hi = rotr64_hi(xh, xl, 14);
      var c1_hi = rotr64_hi(xh, xl, 18);
      var c2_hi = rotr64_hi(xl, xh, 9);  // 41
    
      var r = c0_hi ^ c1_hi ^ c2_hi;
      if (r < 0)
        r += 0x100000000;
      return r;
    }
    
    function s1_512_lo(xh, xl) {
      var c0_lo = rotr64_lo(xh, xl, 14);
      var c1_lo = rotr64_lo(xh, xl, 18);
      var c2_lo = rotr64_lo(xl, xh, 9);  // 41
    
      var r = c0_lo ^ c1_lo ^ c2_lo;
      if (r < 0)
        r += 0x100000000;
      return r;
    }
    
    function g0_512_hi(xh, xl) {
      var c0_hi = rotr64_hi(xh, xl, 1);
      var c1_hi = rotr64_hi(xh, xl, 8);
      var c2_hi = shr64_hi(xh, xl, 7);
    
      var r = c0_hi ^ c1_hi ^ c2_hi;
      if (r < 0)
        r += 0x100000000;
      return r;
    }
    
    function g0_512_lo(xh, xl) {
      var c0_lo = rotr64_lo(xh, xl, 1);
      var c1_lo = rotr64_lo(xh, xl, 8);
      var c2_lo = shr64_lo(xh, xl, 7);
    
      var r = c0_lo ^ c1_lo ^ c2_lo;
      if (r < 0)
        r += 0x100000000;
      return r;
    }
    
    function g1_512_hi(xh, xl) {
      var c0_hi = rotr64_hi(xh, xl, 19);
      var c1_hi = rotr64_hi(xl, xh, 29);  // 61
      var c2_hi = shr64_hi(xh, xl, 6);
    
      var r = c0_hi ^ c1_hi ^ c2_hi;
      if (r < 0)
        r += 0x100000000;
      return r;
    }
    
    function g1_512_lo(xh, xl) {
      var c0_lo = rotr64_lo(xh, xl, 19);
      var c1_lo = rotr64_lo(xl, xh, 29);  // 61
      var c2_lo = shr64_lo(xh, xl, 6);
    
      var r = c0_lo ^ c1_lo ^ c2_lo;
      if (r < 0)
        r += 0x100000000;
      return r;
    }
    
    },{"../common":136,"../utils":146,"minimalistic-assert":158}],145:[function(require,module,exports){
    'use strict';
    
    var utils = require('../utils');
    var rotr32 = utils.rotr32;
    
    function ft_1(s, x, y, z) {
      if (s === 0)
        return ch32(x, y, z);
      if (s === 1 || s === 3)
        return p32(x, y, z);
      if (s === 2)
        return maj32(x, y, z);
    }
    exports.ft_1 = ft_1;
    
    function ch32(x, y, z) {
      return (x & y) ^ ((~x) & z);
    }
    exports.ch32 = ch32;
    
    function maj32(x, y, z) {
      return (x & y) ^ (x & z) ^ (y & z);
    }
    exports.maj32 = maj32;
    
    function p32(x, y, z) {
      return x ^ y ^ z;
    }
    exports.p32 = p32;
    
    function s0_256(x) {
      return rotr32(x, 2) ^ rotr32(x, 13) ^ rotr32(x, 22);
    }
    exports.s0_256 = s0_256;
    
    function s1_256(x) {
      return rotr32(x, 6) ^ rotr32(x, 11) ^ rotr32(x, 25);
    }
    exports.s1_256 = s1_256;
    
    function g0_256(x) {
      return rotr32(x, 7) ^ rotr32(x, 18) ^ (x >>> 3);
    }
    exports.g0_256 = g0_256;
    
    function g1_256(x) {
      return rotr32(x, 17) ^ rotr32(x, 19) ^ (x >>> 10);
    }
    exports.g1_256 = g1_256;
    
    },{"../utils":146}],146:[function(require,module,exports){
    'use strict';
    
    var assert = require('minimalistic-assert');
    var inherits = require('inherits');
    
    exports.inherits = inherits;
    
    function isSurrogatePair(msg, i) {
      if ((msg.charCodeAt(i) & 0xFC00) !== 0xD800) {
        return false;
      }
      if (i < 0 || i + 1 >= msg.length) {
        return false;
      }
      return (msg.charCodeAt(i + 1) & 0xFC00) === 0xDC00;
    }
    
    function toArray(msg, enc) {
      if (Array.isArray(msg))
        return msg.slice();
      if (!msg)
        return [];
      var res = [];
      if (typeof msg === 'string') {
        if (!enc) {
          // Inspired by stringToUtf8ByteArray() in closure-library by Google
          // https://github.com/google/closure-library/blob/8598d87242af59aac233270742c8984e2b2bdbe0/closure/goog/crypt/crypt.js#L117-L143
          // Apache License 2.0
          // https://github.com/google/closure-library/blob/master/LICENSE
          var p = 0;
          for (var i = 0; i < msg.length; i++) {
            var c = msg.charCodeAt(i);
            if (c < 128) {
              res[p++] = c;
            } else if (c < 2048) {
              res[p++] = (c >> 6) | 192;
              res[p++] = (c & 63) | 128;
            } else if (isSurrogatePair(msg, i)) {
              c = 0x10000 + ((c & 0x03FF) << 10) + (msg.charCodeAt(++i) & 0x03FF);
              res[p++] = (c >> 18) | 240;
              res[p++] = ((c >> 12) & 63) | 128;
              res[p++] = ((c >> 6) & 63) | 128;
              res[p++] = (c & 63) | 128;
            } else {
              res[p++] = (c >> 12) | 224;
              res[p++] = ((c >> 6) & 63) | 128;
              res[p++] = (c & 63) | 128;
            }
          }
        } else if (enc === 'hex') {
          msg = msg.replace(/[^a-z0-9]+/ig, '');
          if (msg.length % 2 !== 0)
            msg = '0' + msg;
          for (i = 0; i < msg.length; i += 2)
            res.push(parseInt(msg[i] + msg[i + 1], 16));
        }
      } else {
        for (i = 0; i < msg.length; i++)
          res[i] = msg[i] | 0;
      }
      return res;
    }
    exports.toArray = toArray;
    
    function toHex(msg) {
      var res = '';
      for (var i = 0; i < msg.length; i++)
        res += zero2(msg[i].toString(16));
      return res;
    }
    exports.toHex = toHex;
    
    function htonl(w) {
      var res = (w >>> 24) |
                ((w >>> 8) & 0xff00) |
                ((w << 8) & 0xff0000) |
                ((w & 0xff) << 24);
      return res >>> 0;
    }
    exports.htonl = htonl;
    
    function toHex32(msg, endian) {
      var res = '';
      for (var i = 0; i < msg.length; i++) {
        var w = msg[i];
        if (endian === 'little')
          w = htonl(w);
        res += zero8(w.toString(16));
      }
      return res;
    }
    exports.toHex32 = toHex32;
    
    function zero2(word) {
      if (word.length === 1)
        return '0' + word;
      else
        return word;
    }
    exports.zero2 = zero2;
    
    function zero8(word) {
      if (word.length === 7)
        return '0' + word;
      else if (word.length === 6)
        return '00' + word;
      else if (word.length === 5)
        return '000' + word;
      else if (word.length === 4)
        return '0000' + word;
      else if (word.length === 3)
        return '00000' + word;
      else if (word.length === 2)
        return '000000' + word;
      else if (word.length === 1)
        return '0000000' + word;
      else
        return word;
    }
    exports.zero8 = zero8;
    
    function join32(msg, start, end, endian) {
      var len = end - start;
      assert(len % 4 === 0);
      var res = new Array(len / 4);
      for (var i = 0, k = start; i < res.length; i++, k += 4) {
        var w;
        if (endian === 'big')
          w = (msg[k] << 24) | (msg[k + 1] << 16) | (msg[k + 2] << 8) | msg[k + 3];
        else
          w = (msg[k + 3] << 24) | (msg[k + 2] << 16) | (msg[k + 1] << 8) | msg[k];
        res[i] = w >>> 0;
      }
      return res;
    }
    exports.join32 = join32;
    
    function split32(msg, endian) {
      var res = new Array(msg.length * 4);
      for (var i = 0, k = 0; i < msg.length; i++, k += 4) {
        var m = msg[i];
        if (endian === 'big') {
          res[k] = m >>> 24;
          res[k + 1] = (m >>> 16) & 0xff;
          res[k + 2] = (m >>> 8) & 0xff;
          res[k + 3] = m & 0xff;
        } else {
          res[k + 3] = m >>> 24;
          res[k + 2] = (m >>> 16) & 0xff;
          res[k + 1] = (m >>> 8) & 0xff;
          res[k] = m & 0xff;
        }
      }
      return res;
    }
    exports.split32 = split32;
    
    function rotr32(w, b) {
      return (w >>> b) | (w << (32 - b));
    }
    exports.rotr32 = rotr32;
    
    function rotl32(w, b) {
      return (w << b) | (w >>> (32 - b));
    }
    exports.rotl32 = rotl32;
    
    function sum32(a, b) {
      return (a + b) >>> 0;
    }
    exports.sum32 = sum32;
    
    function sum32_3(a, b, c) {
      return (a + b + c) >>> 0;
    }
    exports.sum32_3 = sum32_3;
    
    function sum32_4(a, b, c, d) {
      return (a + b + c + d) >>> 0;
    }
    exports.sum32_4 = sum32_4;
    
    function sum32_5(a, b, c, d, e) {
      return (a + b + c + d + e) >>> 0;
    }
    exports.sum32_5 = sum32_5;
    
    function sum64(buf, pos, ah, al) {
      var bh = buf[pos];
      var bl = buf[pos + 1];
    
      var lo = (al + bl) >>> 0;
      var hi = (lo < al ? 1 : 0) + ah + bh;
      buf[pos] = hi >>> 0;
      buf[pos + 1] = lo;
    }
    exports.sum64 = sum64;
    
    function sum64_hi(ah, al, bh, bl) {
      var lo = (al + bl) >>> 0;
      var hi = (lo < al ? 1 : 0) + ah + bh;
      return hi >>> 0;
    }
    exports.sum64_hi = sum64_hi;
    
    function sum64_lo(ah, al, bh, bl) {
      var lo = al + bl;
      return lo >>> 0;
    }
    exports.sum64_lo = sum64_lo;
    
    function sum64_4_hi(ah, al, bh, bl, ch, cl, dh, dl) {
      var carry = 0;
      var lo = al;
      lo = (lo + bl) >>> 0;
      carry += lo < al ? 1 : 0;
      lo = (lo + cl) >>> 0;
      carry += lo < cl ? 1 : 0;
      lo = (lo + dl) >>> 0;
      carry += lo < dl ? 1 : 0;
    
      var hi = ah + bh + ch + dh + carry;
      return hi >>> 0;
    }
    exports.sum64_4_hi = sum64_4_hi;
    
    function sum64_4_lo(ah, al, bh, bl, ch, cl, dh, dl) {
      var lo = al + bl + cl + dl;
      return lo >>> 0;
    }
    exports.sum64_4_lo = sum64_4_lo;
    
    function sum64_5_hi(ah, al, bh, bl, ch, cl, dh, dl, eh, el) {
      var carry = 0;
      var lo = al;
      lo = (lo + bl) >>> 0;
      carry += lo < al ? 1 : 0;
      lo = (lo + cl) >>> 0;
      carry += lo < cl ? 1 : 0;
      lo = (lo + dl) >>> 0;
      carry += lo < dl ? 1 : 0;
      lo = (lo + el) >>> 0;
      carry += lo < el ? 1 : 0;
    
      var hi = ah + bh + ch + dh + eh + carry;
      return hi >>> 0;
    }
    exports.sum64_5_hi = sum64_5_hi;
    
    function sum64_5_lo(ah, al, bh, bl, ch, cl, dh, dl, eh, el) {
      var lo = al + bl + cl + dl + el;
    
      return lo >>> 0;
    }
    exports.sum64_5_lo = sum64_5_lo;
    
    function rotr64_hi(ah, al, num) {
      var r = (al << (32 - num)) | (ah >>> num);
      return r >>> 0;
    }
    exports.rotr64_hi = rotr64_hi;
    
    function rotr64_lo(ah, al, num) {
      var r = (ah << (32 - num)) | (al >>> num);
      return r >>> 0;
    }
    exports.rotr64_lo = rotr64_lo;
    
    function shr64_hi(ah, al, num) {
      return ah >>> num;
    }
    exports.shr64_hi = shr64_hi;
    
    function shr64_lo(ah, al, num) {
      var r = (ah << (32 - num)) | (al >>> num);
      return r >>> 0;
    }
    exports.shr64_lo = shr64_lo;
    
    },{"inherits":149,"minimalistic-assert":158}],147:[function(require,module,exports){
    'use strict';
    
    var hash = require('hash.js');
    var utils = require('minimalistic-crypto-utils');
    var assert = require('minimalistic-assert');
    
    function HmacDRBG(options) {
      if (!(this instanceof HmacDRBG))
        return new HmacDRBG(options);
      this.hash = options.hash;
      this.predResist = !!options.predResist;
    
      this.outLen = this.hash.outSize;
      this.minEntropy = options.minEntropy || this.hash.hmacStrength;
    
      this._reseed = null;
      this.reseedInterval = null;
      this.K = null;
      this.V = null;
    
      var entropy = utils.toArray(options.entropy, options.entropyEnc || 'hex');
      var nonce = utils.toArray(options.nonce, options.nonceEnc || 'hex');
      var pers = utils.toArray(options.pers, options.persEnc || 'hex');
      assert(entropy.length >= (this.minEntropy / 8),
             'Not enough entropy. Minimum is: ' + this.minEntropy + ' bits');
      this._init(entropy, nonce, pers);
    }
    module.exports = HmacDRBG;
    
    HmacDRBG.prototype._init = function init(entropy, nonce, pers) {
      var seed = entropy.concat(nonce).concat(pers);
    
      this.K = new Array(this.outLen / 8);
      this.V = new Array(this.outLen / 8);
      for (var i = 0; i < this.V.length; i++) {
        this.K[i] = 0x00;
        this.V[i] = 0x01;
      }
    
      this._update(seed);
      this._reseed = 1;
      this.reseedInterval = 0x1000000000000;  // 2^48
    };
    
    HmacDRBG.prototype._hmac = function hmac() {
      return new hash.hmac(this.hash, this.K);
    };
    
    HmacDRBG.prototype._update = function update(seed) {
      var kmac = this._hmac()
                     .update(this.V)
                     .update([ 0x00 ]);
      if (seed)
        kmac = kmac.update(seed);
      this.K = kmac.digest();
      this.V = this._hmac().update(this.V).digest();
      if (!seed)
        return;
    
      this.K = this._hmac()
                   .update(this.V)
                   .update([ 0x01 ])
                   .update(seed)
                   .digest();
      this.V = this._hmac().update(this.V).digest();
    };
    
    HmacDRBG.prototype.reseed = function reseed(entropy, entropyEnc, add, addEnc) {
      // Optional entropy enc
      if (typeof entropyEnc !== 'string') {
        addEnc = add;
        add = entropyEnc;
        entropyEnc = null;
      }
    
      entropy = utils.toArray(entropy, entropyEnc);
      add = utils.toArray(add, addEnc);
    
      assert(entropy.length >= (this.minEntropy / 8),
             'Not enough entropy. Minimum is: ' + this.minEntropy + ' bits');
    
      this._update(entropy.concat(add || []));
      this._reseed = 1;
    };
    
    HmacDRBG.prototype.generate = function generate(len, enc, add, addEnc) {
      if (this._reseed > this.reseedInterval)
        throw new Error('Reseed is required');
    
      // Optional encoding
      if (typeof enc !== 'string') {
        addEnc = add;
        add = enc;
        enc = null;
      }
    
      // Optional additional data
      if (add) {
        add = utils.toArray(add, addEnc || 'hex');
        this._update(add);
      }
    
      var temp = [];
      while (temp.length < len) {
        this.V = this._hmac().update(this.V).digest();
        temp = temp.concat(this.V);
      }
    
      var res = temp.slice(0, len);
      this._update(add);
      this._reseed++;
      return utils.encode(res, enc);
    };
    
    },{"hash.js":135,"minimalistic-assert":158,"minimalistic-crypto-utils":159}],148:[function(require,module,exports){
    /*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh <https://feross.org/opensource> */
    exports.read = function (buffer, offset, isLE, mLen, nBytes) {
      var e, m
      var eLen = (nBytes * 8) - mLen - 1
      var eMax = (1 << eLen) - 1
      var eBias = eMax >> 1
      var nBits = -7
      var i = isLE ? (nBytes - 1) : 0
      var d = isLE ? -1 : 1
      var s = buffer[offset + i]
    
      i += d
    
      e = s & ((1 << (-nBits)) - 1)
      s >>= (-nBits)
      nBits += eLen
      for (; nBits > 0; e = (e * 256) + buffer[offset + i], i += d, nBits -= 8) {}
    
      m = e & ((1 << (-nBits)) - 1)
      e >>= (-nBits)
      nBits += mLen
      for (; nBits > 0; m = (m * 256) + buffer[offset + i], i += d, nBits -= 8) {}
    
      if (e === 0) {
        e = 1 - eBias
      } else if (e === eMax) {
        return m ? NaN : ((s ? -1 : 1) * Infinity)
      } else {
        m = m + Math.pow(2, mLen)
        e = e - eBias
      }
      return (s ? -1 : 1) * m * Math.pow(2, e - mLen)
    }
    
    exports.write = function (buffer, value, offset, isLE, mLen, nBytes) {
      var e, m, c
      var eLen = (nBytes * 8) - mLen - 1
      var eMax = (1 << eLen) - 1
      var eBias = eMax >> 1
      var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0)
      var i = isLE ? 0 : (nBytes - 1)
      var d = isLE ? 1 : -1
      var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0
    
      value = Math.abs(value)
    
      if (isNaN(value) || value === Infinity) {
        m = isNaN(value) ? 1 : 0
        e = eMax
      } else {
        e = Math.floor(Math.log(value) / Math.LN2)
        if (value * (c = Math.pow(2, -e)) < 1) {
          e--
          c *= 2
        }
        if (e + eBias >= 1) {
          value += rt / c
        } else {
          value += rt * Math.pow(2, 1 - eBias)
        }
        if (value * c >= 2) {
          e++
          c /= 2
        }
    
        if (e + eBias >= eMax) {
          m = 0
          e = eMax
        } else if (e + eBias >= 1) {
          m = ((value * c) - 1) * Math.pow(2, mLen)
          e = e + eBias
        } else {
          m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen)
          e = 0
        }
      }
    
      for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {}
    
      e = (e << mLen) | m
      eLen += mLen
      for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {}
    
      buffer[offset + i - d] |= s * 128
    }
    
    },{}],149:[function(require,module,exports){
    if (typeof Object.create === 'function') {
      // implementation from standard node.js 'util' module
      module.exports = function inherits(ctor, superCtor) {
        if (superCtor) {
          ctor.super_ = superCtor
          ctor.prototype = Object.create(superCtor.prototype, {
            constructor: {
              value: ctor,
              enumerable: false,
              writable: true,
              configurable: true
            }
          })
        }
      };
    } else {
      // old school shim for old browsers
      module.exports = function inherits(ctor, superCtor) {
        if (superCtor) {
          ctor.super_ = superCtor
          var TempCtor = function () {}
          TempCtor.prototype = superCtor.prototype
          ctor.prototype = new TempCtor()
          ctor.prototype.constructor = ctor
        }
      }
    }
    
    },{}],150:[function(require,module,exports){
    'use strict';
    
    var hasToStringTag = require('has-tostringtag/shams')();
    var callBound = require('call-bind/callBound');
    
    var $toString = callBound('Object.prototype.toString');
    
    var isStandardArguments = function isArguments(value) {
        if (hasToStringTag && value && typeof value === 'object' && Symbol.toStringTag in value) {
            return false;
        }
        return $toString(value) === '[object Arguments]';
    };
    
    var isLegacyArguments = function isArguments(value) {
        if (isStandardArguments(value)) {
            return true;
        }
        return value !== null &&
            typeof value === 'object' &&
            typeof value.length === 'number' &&
            value.length >= 0 &&
            $toString(value) !== '[object Array]' &&
            $toString(value.callee) === '[object Function]';
    };
    
    var supportsStandardArguments = (function () {
        return isStandardArguments(arguments);
    }());
    
    isStandardArguments.isLegacyArguments = isLegacyArguments; // for tests
    
    module.exports = supportsStandardArguments ? isStandardArguments : isLegacyArguments;
    
    },{"call-bind/callBound":69,"has-tostringtag/shams":117}],151:[function(require,module,exports){
    /*!
     * Determine if an object is a Buffer
     *
     * @author   Feross Aboukhadijeh <https://feross.org>
     * @license  MIT
     */
    
    // The _isBuffer check is for Safari 5-7 support, because it's missing
    // Object.prototype.constructor. Remove this eventually
    module.exports = function (obj) {
      return obj != null && (isBuffer(obj) || isSlowBuffer(obj) || !!obj._isBuffer)
    }
    
    function isBuffer (obj) {
      return !!obj.constructor && typeof obj.constructor.isBuffer === 'function' && obj.constructor.isBuffer(obj)
    }
    
    // For Node v0.10 support. Remove this eventually.
    function isSlowBuffer (obj) {
      return typeof obj.readFloatLE === 'function' && typeof obj.slice === 'function' && isBuffer(obj.slice(0, 0))
    }
    
    },{}],152:[function(require,module,exports){
    'use strict';
    
    var fnToStr = Function.prototype.toString;
    var reflectApply = typeof Reflect === 'object' && Reflect !== null && Reflect.apply;
    var badArrayLike;
    var isCallableMarker;
    if (typeof reflectApply === 'function' && typeof Object.defineProperty === 'function') {
        try {
            badArrayLike = Object.defineProperty({}, 'length', {
                get: function () {
                    throw isCallableMarker;
                }
            });
            isCallableMarker = {};
            // eslint-disable-next-line no-throw-literal
            reflectApply(function () { throw 42; }, null, badArrayLike);
        } catch (_) {
            if (_ !== isCallableMarker) {
                reflectApply = null;
            }
        }
    } else {
        reflectApply = null;
    }
    
    var constructorRegex = /^\s*class\b/;
    var isES6ClassFn = function isES6ClassFunction(value) {
        try {
            var fnStr = fnToStr.call(value);
            return constructorRegex.test(fnStr);
        } catch (e) {
            return false; // not a function
        }
    };
    
    var tryFunctionObject = function tryFunctionToStr(value) {
        try {
            if (isES6ClassFn(value)) { return false; }
            fnToStr.call(value);
            return true;
        } catch (e) {
            return false;
        }
    };
    var toStr = Object.prototype.toString;
    var objectClass = '[object Object]';
    var fnClass = '[object Function]';
    var genClass = '[object GeneratorFunction]';
    var ddaClass = '[object HTMLAllCollection]'; // IE 11
    var ddaClass2 = '[object HTML document.all class]';
    var ddaClass3 = '[object HTMLCollection]'; // IE 9-10
    var hasToStringTag = typeof Symbol === 'function' && !!Symbol.toStringTag; // better: use `has-tostringtag`
    
    var isIE68 = !(0 in [,]); // eslint-disable-line no-sparse-arrays, comma-spacing
    
    var isDDA = function isDocumentDotAll() { return false; };
    if (typeof document === 'object') {
        // Firefox 3 canonicalizes DDA to undefined when it's not accessed directly
        var all = document.all;
        if (toStr.call(all) === toStr.call(document.all)) {
            isDDA = function isDocumentDotAll(value) {
                /* globals document: false */
                // in IE 6-8, typeof document.all is "object" and it's truthy
                if ((isIE68 || !value) && (typeof value === 'undefined' || typeof value === 'object')) {
                    try {
                        var str = toStr.call(value);
                        return (
                            str === ddaClass
                            || str === ddaClass2
                            || str === ddaClass3 // opera 12.16
                            || str === objectClass // IE 6-8
                        ) && value('') == null; // eslint-disable-line eqeqeq
                    } catch (e) { /**/ }
                }
                return false;
            };
        }
    }
    
    module.exports = reflectApply
        ? function isCallable(value) {
            if (isDDA(value)) { return true; }
            if (!value) { return false; }
            if (typeof value !== 'function' && typeof value !== 'object') { return false; }
            try {
                reflectApply(value, null, badArrayLike);
            } catch (e) {
                if (e !== isCallableMarker) { return false; }
            }
            return !isES6ClassFn(value) && tryFunctionObject(value);
        }
        : function isCallable(value) {
            if (isDDA(value)) { return true; }
            if (!value) { return false; }
            if (typeof value !== 'function' && typeof value !== 'object') { return false; }
            if (hasToStringTag) { return tryFunctionObject(value); }
            if (isES6ClassFn(value)) { return false; }
            var strClass = toStr.call(value);
            if (strClass !== fnClass && strClass !== genClass && !(/^\[object HTML/).test(strClass)) { return false; }
            return tryFunctionObject(value);
        };
    
    },{}],153:[function(require,module,exports){
    'use strict';
    
    var toStr = Object.prototype.toString;
    var fnToStr = Function.prototype.toString;
    var isFnRegex = /^\s*(?:function)?\*/;
    var hasToStringTag = require('has-tostringtag/shams')();
    var getProto = Object.getPrototypeOf;
    var getGeneratorFunc = function () { // eslint-disable-line consistent-return
        if (!hasToStringTag) {
            return false;
        }
        try {
            return Function('return function*() {}')();
        } catch (e) {
        }
    };
    var GeneratorFunction;
    
    module.exports = function isGeneratorFunction(fn) {
        if (typeof fn !== 'function') {
            return false;
        }
        if (isFnRegex.test(fnToStr.call(fn))) {
            return true;
        }
        if (!hasToStringTag) {
            var str = toStr.call(fn);
            return str === '[object GeneratorFunction]';
        }
        if (!getProto) {
            return false;
        }
        if (typeof GeneratorFunction === 'undefined') {
            var generatorFunc = getGeneratorFunc();
            GeneratorFunction = generatorFunc ? getProto(generatorFunc) : false;
        }
        return getProto(fn) === GeneratorFunction;
    };
    
    },{"has-tostringtag/shams":117}],154:[function(require,module,exports){
    'use strict';
    
    var whichTypedArray = require('which-typed-array');
    
    module.exports = function isTypedArray(value) {
        return !!whichTypedArray(value);
    };
    
    },{"which-typed-array":217}],155:[function(require,module,exports){
    'use strict'
    var inherits = require('inherits')
    var HashBase = require('hash-base')
    var Buffer = require('safe-buffer').Buffer
    
    var ARRAY16 = new Array(16)
    
    function MD5 () {
      HashBase.call(this, 64)
    
      // state
      this._a = 0x67452301
      this._b = 0xefcdab89
      this._c = 0x98badcfe
      this._d = 0x10325476
    }
    
    inherits(MD5, HashBase)
    
    MD5.prototype._update = function () {
      var M = ARRAY16
      for (var i = 0; i < 16; ++i) M[i] = this._block.readInt32LE(i * 4)
    
      var a = this._a
      var b = this._b
      var c = this._c
      var d = this._d
    
      a = fnF(a, b, c, d, M[0], 0xd76aa478, 7)
      d = fnF(d, a, b, c, M[1], 0xe8c7b756, 12)
      c = fnF(c, d, a, b, M[2], 0x242070db, 17)
      b = fnF(b, c, d, a, M[3], 0xc1bdceee, 22)
      a = fnF(a, b, c, d, M[4], 0xf57c0faf, 7)
      d = fnF(d, a, b, c, M[5], 0x4787c62a, 12)
      c = fnF(c, d, a, b, M[6], 0xa8304613, 17)
      b = fnF(b, c, d, a, M[7], 0xfd469501, 22)
      a = fnF(a, b, c, d, M[8], 0x698098d8, 7)
      d = fnF(d, a, b, c, M[9], 0x8b44f7af, 12)
      c = fnF(c, d, a, b, M[10], 0xffff5bb1, 17)
      b = fnF(b, c, d, a, M[11], 0x895cd7be, 22)
      a = fnF(a, b, c, d, M[12], 0x6b901122, 7)
      d = fnF(d, a, b, c, M[13], 0xfd987193, 12)
      c = fnF(c, d, a, b, M[14], 0xa679438e, 17)
      b = fnF(b, c, d, a, M[15], 0x49b40821, 22)
    
      a = fnG(a, b, c, d, M[1], 0xf61e2562, 5)
      d = fnG(d, a, b, c, M[6], 0xc040b340, 9)
      c = fnG(c, d, a, b, M[11], 0x265e5a51, 14)
      b = fnG(b, c, d, a, M[0], 0xe9b6c7aa, 20)
      a = fnG(a, b, c, d, M[5], 0xd62f105d, 5)
      d = fnG(d, a, b, c, M[10], 0x02441453, 9)
      c = fnG(c, d, a, b, M[15], 0xd8a1e681, 14)
      b = fnG(b, c, d, a, M[4], 0xe7d3fbc8, 20)
      a = fnG(a, b, c, d, M[9], 0x21e1cde6, 5)
      d = fnG(d, a, b, c, M[14], 0xc33707d6, 9)
      c = fnG(c, d, a, b, M[3], 0xf4d50d87, 14)
      b = fnG(b, c, d, a, M[8], 0x455a14ed, 20)
      a = fnG(a, b, c, d, M[13], 0xa9e3e905, 5)
      d = fnG(d, a, b, c, M[2], 0xfcefa3f8, 9)
      c = fnG(c, d, a, b, M[7], 0x676f02d9, 14)
      b = fnG(b, c, d, a, M[12], 0x8d2a4c8a, 20)
    
      a = fnH(a, b, c, d, M[5], 0xfffa3942, 4)
      d = fnH(d, a, b, c, M[8], 0x8771f681, 11)
      c = fnH(c, d, a, b, M[11], 0x6d9d6122, 16)
      b = fnH(b, c, d, a, M[14], 0xfde5380c, 23)
      a = fnH(a, b, c, d, M[1], 0xa4beea44, 4)
      d = fnH(d, a, b, c, M[4], 0x4bdecfa9, 11)
      c = fnH(c, d, a, b, M[7], 0xf6bb4b60, 16)
      b = fnH(b, c, d, a, M[10], 0xbebfbc70, 23)
      a = fnH(a, b, c, d, M[13], 0x289b7ec6, 4)
      d = fnH(d, a, b, c, M[0], 0xeaa127fa, 11)
      c = fnH(c, d, a, b, M[3], 0xd4ef3085, 16)
      b = fnH(b, c, d, a, M[6], 0x04881d05, 23)
      a = fnH(a, b, c, d, M[9], 0xd9d4d039, 4)
      d = fnH(d, a, b, c, M[12], 0xe6db99e5, 11)
      c = fnH(c, d, a, b, M[15], 0x1fa27cf8, 16)
      b = fnH(b, c, d, a, M[2], 0xc4ac5665, 23)
    
      a = fnI(a, b, c, d, M[0], 0xf4292244, 6)
      d = fnI(d, a, b, c, M[7], 0x432aff97, 10)
      c = fnI(c, d, a, b, M[14], 0xab9423a7, 15)
      b = fnI(b, c, d, a, M[5], 0xfc93a039, 21)
      a = fnI(a, b, c, d, M[12], 0x655b59c3, 6)
      d = fnI(d, a, b, c, M[3], 0x8f0ccc92, 10)
      c = fnI(c, d, a, b, M[10], 0xffeff47d, 15)
      b = fnI(b, c, d, a, M[1], 0x85845dd1, 21)
      a = fnI(a, b, c, d, M[8], 0x6fa87e4f, 6)
      d = fnI(d, a, b, c, M[15], 0xfe2ce6e0, 10)
      c = fnI(c, d, a, b, M[6], 0xa3014314, 15)
      b = fnI(b, c, d, a, M[13], 0x4e0811a1, 21)
      a = fnI(a, b, c, d, M[4], 0xf7537e82, 6)
      d = fnI(d, a, b, c, M[11], 0xbd3af235, 10)
      c = fnI(c, d, a, b, M[2], 0x2ad7d2bb, 15)
      b = fnI(b, c, d, a, M[9], 0xeb86d391, 21)
    
      this._a = (this._a + a) | 0
      this._b = (this._b + b) | 0
      this._c = (this._c + c) | 0
      this._d = (this._d + d) | 0
    }
    
    MD5.prototype._digest = function () {
      // create padding and handle blocks
      this._block[this._blockOffset++] = 0x80
      if (this._blockOffset > 56) {
        this._block.fill(0, this._blockOffset, 64)
        this._update()
        this._blockOffset = 0
      }
    
      this._block.fill(0, this._blockOffset, 56)
      this._block.writeUInt32LE(this._length[0], 56)
      this._block.writeUInt32LE(this._length[1], 60)
      this._update()
    
      // produce result
      var buffer = Buffer.allocUnsafe(16)
      buffer.writeInt32LE(this._a, 0)
      buffer.writeInt32LE(this._b, 4)
      buffer.writeInt32LE(this._c, 8)
      buffer.writeInt32LE(this._d, 12)
      return buffer
    }
    
    function rotl (x, n) {
      return (x << n) | (x >>> (32 - n))
    }
    
    function fnF (a, b, c, d, m, k, s) {
      return (rotl((a + ((b & c) | ((~b) & d)) + m + k) | 0, s) + b) | 0
    }
    
    function fnG (a, b, c, d, m, k, s) {
      return (rotl((a + ((b & d) | (c & (~d))) + m + k) | 0, s) + b) | 0
    }
    
    function fnH (a, b, c, d, m, k, s) {
      return (rotl((a + (b ^ c ^ d) + m + k) | 0, s) + b) | 0
    }
    
    function fnI (a, b, c, d, m, k, s) {
      return (rotl((a + ((c ^ (b | (~d)))) + m + k) | 0, s) + b) | 0
    }
    
    module.exports = MD5
    
    },{"hash-base":119,"inherits":149,"safe-buffer":187}],156:[function(require,module,exports){
    var bn = require('bn.js');
    var brorand = require('brorand');
    
    function MillerRabin(rand) {
      this.rand = rand || new brorand.Rand();
    }
    module.exports = MillerRabin;
    
    MillerRabin.create = function create(rand) {
      return new MillerRabin(rand);
    };
    
    MillerRabin.prototype._randbelow = function _randbelow(n) {
      var len = n.bitLength();
      var min_bytes = Math.ceil(len / 8);
    
      // Generage random bytes until a number less than n is found.
      // This ensures that 0..n-1 have an equal probability of being selected.
      do
        var a = new bn(this.rand.generate(min_bytes));
      while (a.cmp(n) >= 0);
    
      return a;
    };
    
    MillerRabin.prototype._randrange = function _randrange(start, stop) {
      // Generate a random number greater than or equal to start and less than stop.
      var size = stop.sub(start);
      return start.add(this._randbelow(size));
    };
    
    MillerRabin.prototype.test = function test(n, k, cb) {
      var len = n.bitLength();
      var red = bn.mont(n);
      var rone = new bn(1).toRed(red);
    
      if (!k)
        k = Math.max(1, (len / 48) | 0);
    
      // Find d and s, (n - 1) = (2 ^ s) * d;
      var n1 = n.subn(1);
      for (var s = 0; !n1.testn(s); s++) {}
      var d = n.shrn(s);
    
      var rn1 = n1.toRed(red);
    
      var prime = true;
      for (; k > 0; k--) {
        var a = this._randrange(new bn(2), n1);
        if (cb)
          cb(a);
    
        var x = a.toRed(red).redPow(d);
        if (x.cmp(rone) === 0 || x.cmp(rn1) === 0)
          continue;
    
        for (var i = 1; i < s; i++) {
          x = x.redSqr();
    
          if (x.cmp(rone) === 0)
            return false;
          if (x.cmp(rn1) === 0)
            break;
        }
    
        if (i === s)
          return false;
      }
    
      return prime;
    };
    
    MillerRabin.prototype.getDivisor = function getDivisor(n, k) {
      var len = n.bitLength();
      var red = bn.mont(n);
      var rone = new bn(1).toRed(red);
    
      if (!k)
        k = Math.max(1, (len / 48) | 0);
    
      // Find d and s, (n - 1) = (2 ^ s) * d;
      var n1 = n.subn(1);
      for (var s = 0; !n1.testn(s); s++) {}
      var d = n.shrn(s);
    
      var rn1 = n1.toRed(red);
    
      for (; k > 0; k--) {
        var a = this._randrange(new bn(2), n1);
    
        var g = n.gcd(a);
        if (g.cmpn(1) !== 0)
          return g;
    
        var x = a.toRed(red).redPow(d);
        if (x.cmp(rone) === 0 || x.cmp(rn1) === 0)
          continue;
    
        for (var i = 1; i < s; i++) {
          x = x.redSqr();
    
          if (x.cmp(rone) === 0)
            return x.fromRed().subn(1).gcd(n);
          if (x.cmp(rn1) === 0)
            break;
        }
    
        if (i === s) {
          x = x.redSqr();
          return x.fromRed().subn(1).gcd(n);
        }
      }
    
      return false;
    };
    
    },{"bn.js":157,"brorand":23}],157:[function(require,module,exports){
    arguments[4][15][0].apply(exports,arguments)
    },{"buffer":24,"dup":15}],158:[function(require,module,exports){
    module.exports = assert;
    
    function assert(val, msg) {
      if (!val)
        throw new Error(msg || 'Assertion failed');
    }
    
    assert.equal = function assertEqual(l, r, msg) {
      if (l != r)
        throw new Error(msg || ('Assertion failed: ' + l + ' != ' + r));
    };
    
    },{}],159:[function(require,module,exports){
    'use strict';
    
    var utils = exports;
    
    function toArray(msg, enc) {
      if (Array.isArray(msg))
        return msg.slice();
      if (!msg)
        return [];
      var res = [];
      if (typeof msg !== 'string') {
        for (var i = 0; i < msg.length; i++)
          res[i] = msg[i] | 0;
        return res;
      }
      if (enc === 'hex') {
        msg = msg.replace(/[^a-z0-9]+/ig, '');
        if (msg.length % 2 !== 0)
          msg = '0' + msg;
        for (var i = 0; i < msg.length; i += 2)
          res.push(parseInt(msg[i] + msg[i + 1], 16));
      } else {
        for (var i = 0; i < msg.length; i++) {
          var c = msg.charCodeAt(i);
          var hi = c >> 8;
          var lo = c & 0xff;
          if (hi)
            res.push(hi, lo);
          else
            res.push(lo);
        }
      }
      return res;
    }
    utils.toArray = toArray;
    
    function zero2(word) {
      if (word.length === 1)
        return '0' + word;
      else
        return word;
    }
    utils.zero2 = zero2;
    
    function toHex(msg) {
      var res = '';
      for (var i = 0; i < msg.length; i++)
        res += zero2(msg[i].toString(16));
      return res;
    }
    utils.toHex = toHex;
    
    utils.encode = function encode(arr, enc) {
      if (enc === 'hex')
        return toHex(arr);
      else
        return arr;
    };
    
    },{}],160:[function(require,module,exports){
    'use strict';
    
    var keysShim;
    if (!Object.keys) {
        // modified from https://github.com/es-shims/es5-shim
        var has = Object.prototype.hasOwnProperty;
        var toStr = Object.prototype.toString;
        var isArgs = require('./isArguments'); // eslint-disable-line global-require
        var isEnumerable = Object.prototype.propertyIsEnumerable;
        var hasDontEnumBug = !isEnumerable.call({ toString: null }, 'toString');
        var hasProtoEnumBug = isEnumerable.call(function () {}, 'prototype');
        var dontEnums = [
            'toString',
            'toLocaleString',
            'valueOf',
            'hasOwnProperty',
            'isPrototypeOf',
            'propertyIsEnumerable',
            'constructor'
        ];
        var equalsConstructorPrototype = function (o) {
            var ctor = o.constructor;
            return ctor && ctor.prototype === o;
        };
        var excludedKeys = {
            $applicationCache: true,
            $console: true,
            $external: true,
            $frame: true,
            $frameElement: true,
            $frames: true,
            $innerHeight: true,
            $innerWidth: true,
            $onmozfullscreenchange: true,
            $onmozfullscreenerror: true,
            $outerHeight: true,
            $outerWidth: true,
            $pageXOffset: true,
            $pageYOffset: true,
            $parent: true,
            $scrollLeft: true,
            $scrollTop: true,
            $scrollX: true,
            $scrollY: true,
            $self: true,
            $webkitIndexedDB: true,
            $webkitStorageInfo: true,
            $window: true
        };
        var hasAutomationEqualityBug = (function () {
            /* global window */
            if (typeof window === 'undefined') { return false; }
            for (var k in window) {
                try {
                    if (!excludedKeys['$' + k] && has.call(window, k) && window[k] !== null && typeof window[k] === 'object') {
                        try {
                            equalsConstructorPrototype(window[k]);
                        } catch (e) {
                            return true;
                        }
                    }
                } catch (e) {
                    return true;
                }
            }
            return false;
        }());
        var equalsConstructorPrototypeIfNotBuggy = function (o) {
            /* global window */
            if (typeof window === 'undefined' || !hasAutomationEqualityBug) {
                return equalsConstructorPrototype(o);
            }
            try {
                return equalsConstructorPrototype(o);
            } catch (e) {
                return false;
            }
        };
    
        keysShim = function keys(object) {
            var isObject = object !== null && typeof object === 'object';
            var isFunction = toStr.call(object) === '[object Function]';
            var isArguments = isArgs(object);
            var isString = isObject && toStr.call(object) === '[object String]';
            var theKeys = [];
    
            if (!isObject && !isFunction && !isArguments) {
                throw new TypeError('Object.keys called on a non-object');
            }
    
            var skipProto = hasProtoEnumBug && isFunction;
            if (isString && object.length > 0 && !has.call(object, 0)) {
                for (var i = 0; i < object.length; ++i) {
                    theKeys.push(String(i));
                }
            }
    
            if (isArguments && object.length > 0) {
                for (var j = 0; j < object.length; ++j) {
                    theKeys.push(String(j));
                }
            } else {
                for (var name in object) {
                    if (!(skipProto && name === 'prototype') && has.call(object, name)) {
                        theKeys.push(String(name));
                    }
                }
            }
    
            if (hasDontEnumBug) {
                var skipConstructor = equalsConstructorPrototypeIfNotBuggy(object);
    
                for (var k = 0; k < dontEnums.length; ++k) {
                    if (!(skipConstructor && dontEnums[k] === 'constructor') && has.call(object, dontEnums[k])) {
                        theKeys.push(dontEnums[k]);
                    }
                }
            }
            return theKeys;
        };
    }
    module.exports = keysShim;
    
    },{"./isArguments":162}],161:[function(require,module,exports){
    'use strict';
    
    var slice = Array.prototype.slice;
    var isArgs = require('./isArguments');
    
    var origKeys = Object.keys;
    var keysShim = origKeys ? function keys(o) { return origKeys(o); } : require('./implementation');
    
    var originalKeys = Object.keys;
    
    keysShim.shim = function shimObjectKeys() {
        if (Object.keys) {
            var keysWorksWithArguments = (function () {
                // Safari 5.0 bug
                var args = Object.keys(arguments);
                return args && args.length === arguments.length;
            }(1, 2));
            if (!keysWorksWithArguments) {
                Object.keys = function keys(object) { // eslint-disable-line func-name-matching
                    if (isArgs(object)) {
                        return originalKeys(slice.call(object));
                    }
                    return originalKeys(object);
                };
            }
        } else {
            Object.keys = keysShim;
        }
        return Object.keys || keysShim;
    };
    
    module.exports = keysShim;
    
    },{"./implementation":160,"./isArguments":162}],162:[function(require,module,exports){
    'use strict';
    
    var toStr = Object.prototype.toString;
    
    module.exports = function isArguments(value) {
        var str = toStr.call(value);
        var isArgs = str === '[object Arguments]';
        if (!isArgs) {
            isArgs = str !== '[object Array]' &&
                value !== null &&
                typeof value === 'object' &&
                typeof value.length === 'number' &&
                value.length >= 0 &&
                toStr.call(value.callee) === '[object Function]';
        }
        return isArgs;
    };
    
    },{}],163:[function(require,module,exports){
    'use strict';
    
    // modified from https://github.com/es-shims/es6-shim
    var objectKeys = require('object-keys');
    var hasSymbols = require('has-symbols/shams')();
    var callBound = require('call-bind/callBound');
    var toObject = Object;
    var $push = callBound('Array.prototype.push');
    var $propIsEnumerable = callBound('Object.prototype.propertyIsEnumerable');
    var originalGetSymbols = hasSymbols ? Object.getOwnPropertySymbols : null;
    
    // eslint-disable-next-line no-unused-vars
    module.exports = function assign(target, source1) {
        if (target == null) { throw new TypeError('target must be an object'); }
        var to = toObject(target); // step 1
        if (arguments.length === 1) {
            return to; // step 2
        }
        for (var s = 1; s < arguments.length; ++s) {
            var from = toObject(arguments[s]); // step 3.a.i
    
            // step 3.a.ii:
            var keys = objectKeys(from);
            var getSymbols = hasSymbols && (Object.getOwnPropertySymbols || originalGetSymbols);
            if (getSymbols) {
                var syms = getSymbols(from);
                for (var j = 0; j < syms.length; ++j) {
                    var key = syms[j];
                    if ($propIsEnumerable(from, key)) {
                        $push(keys, key);
                    }
                }
            }
    
            // step 3.a.iii:
            for (var i = 0; i < keys.length; ++i) {
                var nextKey = keys[i];
                if ($propIsEnumerable(from, nextKey)) { // step 3.a.iii.2
                    var propValue = from[nextKey]; // step 3.a.iii.2.a
                    to[nextKey] = propValue; // step 3.a.iii.2.b
                }
            }
        }
    
        return to; // step 4
    };
    
    },{"call-bind/callBound":69,"has-symbols/shams":116,"object-keys":161}],164:[function(require,module,exports){
    'use strict';
    
    var implementation = require('./implementation');
    
    var lacksProperEnumerationOrder = function () {
        if (!Object.assign) {
            return false;
        }
        /*
         * v8, specifically in node 4.x, has a bug with incorrect property enumeration order
         * note: this does not detect the bug unless there's 20 characters
         */
        var str = 'abcdefghijklmnopqrst';
        var letters = str.split('');
        var map = {};
        for (var i = 0; i < letters.length; ++i) {
            map[letters[i]] = letters[i];
        }
        var obj = Object.assign({}, map);
        var actual = '';
        for (var k in obj) {
            actual += k;
        }
        return str !== actual;
    };
    
    var assignHasPendingExceptions = function () {
        if (!Object.assign || !Object.preventExtensions) {
            return false;
        }
        /*
         * Firefox 37 still has "pending exception" logic in its Object.assign implementation,
         * which is 72% slower than our shim, and Firefox 40's native implementation.
         */
        var thrower = Object.preventExtensions({ 1: 2 });
        try {
            Object.assign(thrower, 'xy');
        } catch (e) {
            return thrower[1] === 'y';
        }
        return false;
    };
    
    module.exports = function getPolyfill() {
        if (!Object.assign) {
            return implementation;
        }
        if (lacksProperEnumerationOrder()) {
            return implementation;
        }
        if (assignHasPendingExceptions()) {
            return implementation;
        }
        return Object.assign;
    };
    
    },{"./implementation":163}],165:[function(require,module,exports){
    module.exports={"2.16.840.1.101.3.4.1.1": "aes-128-ecb",
    "2.16.840.1.101.3.4.1.2": "aes-128-cbc",
    "2.16.840.1.101.3.4.1.3": "aes-128-ofb",
    "2.16.840.1.101.3.4.1.4": "aes-128-cfb",
    "2.16.840.1.101.3.4.1.21": "aes-192-ecb",
    "2.16.840.1.101.3.4.1.22": "aes-192-cbc",
    "2.16.840.1.101.3.4.1.23": "aes-192-ofb",
    "2.16.840.1.101.3.4.1.24": "aes-192-cfb",
    "2.16.840.1.101.3.4.1.41": "aes-256-ecb",
    "2.16.840.1.101.3.4.1.42": "aes-256-cbc",
    "2.16.840.1.101.3.4.1.43": "aes-256-ofb",
    "2.16.840.1.101.3.4.1.44": "aes-256-cfb"
    }
    },{}],166:[function(require,module,exports){
    // from https://github.com/indutny/self-signed/blob/gh-pages/lib/asn1.js
    // Fedor, you are amazing.
    'use strict'
    
    var asn1 = require('asn1.js')
    
    exports.certificate = require('./certificate')
    
    var RSAPrivateKey = asn1.define('RSAPrivateKey', function () {
      this.seq().obj(
        this.key('version').int(),
        this.key('modulus').int(),
        this.key('publicExponent').int(),
        this.key('privateExponent').int(),
        this.key('prime1').int(),
        this.key('prime2').int(),
        this.key('exponent1').int(),
        this.key('exponent2').int(),
        this.key('coefficient').int()
      )
    })
    exports.RSAPrivateKey = RSAPrivateKey
    
    var RSAPublicKey = asn1.define('RSAPublicKey', function () {
      this.seq().obj(
        this.key('modulus').int(),
        this.key('publicExponent').int()
      )
    })
    exports.RSAPublicKey = RSAPublicKey
    
    var PublicKey = asn1.define('SubjectPublicKeyInfo', function () {
      this.seq().obj(
        this.key('algorithm').use(AlgorithmIdentifier),
        this.key('subjectPublicKey').bitstr()
      )
    })
    exports.PublicKey = PublicKey
    
    var AlgorithmIdentifier = asn1.define('AlgorithmIdentifier', function () {
      this.seq().obj(
        this.key('algorithm').objid(),
        this.key('none').null_().optional(),
        this.key('curve').objid().optional(),
        this.key('params').seq().obj(
          this.key('p').int(),
          this.key('q').int(),
          this.key('g').int()
        ).optional()
      )
    })
    
    var PrivateKeyInfo = asn1.define('PrivateKeyInfo', function () {
      this.seq().obj(
        this.key('version').int(),
        this.key('algorithm').use(AlgorithmIdentifier),
        this.key('subjectPrivateKey').octstr()
      )
    })
    exports.PrivateKey = PrivateKeyInfo
    var EncryptedPrivateKeyInfo = asn1.define('EncryptedPrivateKeyInfo', function () {
      this.seq().obj(
        this.key('algorithm').seq().obj(
          this.key('id').objid(),
          this.key('decrypt').seq().obj(
            this.key('kde').seq().obj(
              this.key('id').objid(),
              this.key('kdeparams').seq().obj(
                this.key('salt').octstr(),
                this.key('iters').int()
              )
            ),
            this.key('cipher').seq().obj(
              this.key('algo').objid(),
              this.key('iv').octstr()
            )
          )
        ),
        this.key('subjectPrivateKey').octstr()
      )
    })
    
    exports.EncryptedPrivateKey = EncryptedPrivateKeyInfo
    
    var DSAPrivateKey = asn1.define('DSAPrivateKey', function () {
      this.seq().obj(
        this.key('version').int(),
        this.key('p').int(),
        this.key('q').int(),
        this.key('g').int(),
        this.key('pub_key').int(),
        this.key('priv_key').int()
      )
    })
    exports.DSAPrivateKey = DSAPrivateKey
    
    exports.DSAparam = asn1.define('DSAparam', function () {
      this.int()
    })
    
    var ECPrivateKey = asn1.define('ECPrivateKey', function () {
      this.seq().obj(
        this.key('version').int(),
        this.key('privateKey').octstr(),
        this.key('parameters').optional().explicit(0).use(ECParameters),
        this.key('publicKey').optional().explicit(1).bitstr()
      )
    })
    exports.ECPrivateKey = ECPrivateKey
    
    var ECParameters = asn1.define('ECParameters', function () {
      this.choice({
        namedCurve: this.objid()
      })
    })
    
    exports.signature = asn1.define('signature', function () {
      this.seq().obj(
        this.key('r').int(),
        this.key('s').int()
      )
    })
    
    },{"./certificate":167,"asn1.js":1}],167:[function(require,module,exports){
    // from https://github.com/Rantanen/node-dtls/blob/25a7dc861bda38cfeac93a723500eea4f0ac2e86/Certificate.js
    // thanks to @Rantanen
    
    'use strict'
    
    var asn = require('asn1.js')
    
    var Time = asn.define('Time', function () {
      this.choice({
        utcTime: this.utctime(),
        generalTime: this.gentime()
      })
    })
    
    var AttributeTypeValue = asn.define('AttributeTypeValue', function () {
      this.seq().obj(
        this.key('type').objid(),
        this.key('value').any()
      )
    })
    
    var AlgorithmIdentifier = asn.define('AlgorithmIdentifier', function () {
      this.seq().obj(
        this.key('algorithm').objid(),
        this.key('parameters').optional(),
        this.key('curve').objid().optional()
      )
    })
    
    var SubjectPublicKeyInfo = asn.define('SubjectPublicKeyInfo', function () {
      this.seq().obj(
        this.key('algorithm').use(AlgorithmIdentifier),
        this.key('subjectPublicKey').bitstr()
      )
    })
    
    var RelativeDistinguishedName = asn.define('RelativeDistinguishedName', function () {
      this.setof(AttributeTypeValue)
    })
    
    var RDNSequence = asn.define('RDNSequence', function () {
      this.seqof(RelativeDistinguishedName)
    })
    
    var Name = asn.define('Name', function () {
      this.choice({
        rdnSequence: this.use(RDNSequence)
      })
    })
    
    var Validity = asn.define('Validity', function () {
      this.seq().obj(
        this.key('notBefore').use(Time),
        this.key('notAfter').use(Time)
      )
    })
    
    var Extension = asn.define('Extension', function () {
      this.seq().obj(
        this.key('extnID').objid(),
        this.key('critical').bool().def(false),
        this.key('extnValue').octstr()
      )
    })
    
    var TBSCertificate = asn.define('TBSCertificate', function () {
      this.seq().obj(
        this.key('version').explicit(0).int().optional(),
        this.key('serialNumber').int(),
        this.key('signature').use(AlgorithmIdentifier),
        this.key('issuer').use(Name),
        this.key('validity').use(Validity),
        this.key('subject').use(Name),
        this.key('subjectPublicKeyInfo').use(SubjectPublicKeyInfo),
        this.key('issuerUniqueID').implicit(1).bitstr().optional(),
        this.key('subjectUniqueID').implicit(2).bitstr().optional(),
        this.key('extensions').explicit(3).seqof(Extension).optional()
      )
    })
    
    var X509Certificate = asn.define('X509Certificate', function () {
      this.seq().obj(
        this.key('tbsCertificate').use(TBSCertificate),
        this.key('signatureAlgorithm').use(AlgorithmIdentifier),
        this.key('signatureValue').bitstr()
      )
    })
    
    module.exports = X509Certificate
    
    },{"asn1.js":1}],168:[function(require,module,exports){
    // adapted from https://github.com/apatil/pemstrip
    var findProc = /Proc-Type: 4,ENCRYPTED[\n\r]+DEK-Info: AES-((?:128)|(?:192)|(?:256))-CBC,([0-9A-H]+)[\n\r]+([0-9A-z\n\r+/=]+)[\n\r]+/m
    var startRegex = /^-----BEGIN ((?:.*? KEY)|CERTIFICATE)-----/m
    var fullRegex = /^-----BEGIN ((?:.*? KEY)|CERTIFICATE)-----([0-9A-z\n\r+/=]+)-----END \1-----$/m
    var evp = require('evp_bytestokey')
    var ciphers = require('browserify-aes')
    var Buffer = require('safe-buffer').Buffer
    module.exports = function (okey, password) {
      var key = okey.toString()
      var match = key.match(findProc)
      var decrypted
      if (!match) {
        var match2 = key.match(fullRegex)
        decrypted = Buffer.from(match2[2].replace(/[\r\n]/g, ''), 'base64')
      } else {
        var suite = 'aes' + match[1]
        var iv = Buffer.from(match[2], 'hex')
        var cipherText = Buffer.from(match[3].replace(/[\r\n]/g, ''), 'base64')
        var cipherKey = evp(password, iv.slice(0, 8), parseInt(match[1], 10)).key
        var out = []
        var cipher = ciphers.createDecipheriv(suite, cipherKey, iv)
        out.push(cipher.update(cipherText))
        out.push(cipher.final())
        decrypted = Buffer.concat(out)
      }
      var tag = key.match(startRegex)[1]
      return {
        tag: tag,
        data: decrypted
      }
    }
    
    },{"browserify-aes":27,"evp_bytestokey":108,"safe-buffer":187}],169:[function(require,module,exports){
    var asn1 = require('./asn1')
    var aesid = require('./aesid.json')
    var fixProc = require('./fixProc')
    var ciphers = require('browserify-aes')
    var compat = require('pbkdf2')
    var Buffer = require('safe-buffer').Buffer
    module.exports = parseKeys
    
    function parseKeys (buffer) {
      var password
      if (typeof buffer === 'object' && !Buffer.isBuffer(buffer)) {
        password = buffer.passphrase
        buffer = buffer.key
      }
      if (typeof buffer === 'string') {
        buffer = Buffer.from(buffer)
      }
    
      var stripped = fixProc(buffer, password)
    
      var type = stripped.tag
      var data = stripped.data
      var subtype, ndata
      switch (type) {
        case 'CERTIFICATE':
          ndata = asn1.certificate.decode(data, 'der').tbsCertificate.subjectPublicKeyInfo
          // falls through
        case 'PUBLIC KEY':
          if (!ndata) {
            ndata = asn1.PublicKey.decode(data, 'der')
          }
          subtype = ndata.algorithm.algorithm.join('.')
          switch (subtype) {
            case '1.2.840.113549.1.1.1':
              return asn1.RSAPublicKey.decode(ndata.subjectPublicKey.data, 'der')
            case '1.2.840.10045.2.1':
              ndata.subjectPrivateKey = ndata.subjectPublicKey
              return {
                type: 'ec',
                data: ndata
              }
            case '1.2.840.10040.4.1':
              ndata.algorithm.params.pub_key = asn1.DSAparam.decode(ndata.subjectPublicKey.data, 'der')
              return {
                type: 'dsa',
                data: ndata.algorithm.params
              }
            default: throw new Error('unknown key id ' + subtype)
          }
          // throw new Error('unknown key type ' + type)
        case 'ENCRYPTED PRIVATE KEY':
          data = asn1.EncryptedPrivateKey.decode(data, 'der')
          data = decrypt(data, password)
          // falls through
        case 'PRIVATE KEY':
          ndata = asn1.PrivateKey.decode(data, 'der')
          subtype = ndata.algorithm.algorithm.join('.')
          switch (subtype) {
            case '1.2.840.113549.1.1.1':
              return asn1.RSAPrivateKey.decode(ndata.subjectPrivateKey, 'der')
            case '1.2.840.10045.2.1':
              return {
                curve: ndata.algorithm.curve,
                privateKey: asn1.ECPrivateKey.decode(ndata.subjectPrivateKey, 'der').privateKey
              }
            case '1.2.840.10040.4.1':
              ndata.algorithm.params.priv_key = asn1.DSAparam.decode(ndata.subjectPrivateKey, 'der')
              return {
                type: 'dsa',
                params: ndata.algorithm.params
              }
            default: throw new Error('unknown key id ' + subtype)
          }
          // throw new Error('unknown key type ' + type)
        case 'RSA PUBLIC KEY':
          return asn1.RSAPublicKey.decode(data, 'der')
        case 'RSA PRIVATE KEY':
          return asn1.RSAPrivateKey.decode(data, 'der')
        case 'DSA PRIVATE KEY':
          return {
            type: 'dsa',
            params: asn1.DSAPrivateKey.decode(data, 'der')
          }
        case 'EC PRIVATE KEY':
          data = asn1.ECPrivateKey.decode(data, 'der')
          return {
            curve: data.parameters.value,
            privateKey: data.privateKey
          }
        default: throw new Error('unknown key type ' + type)
      }
    }
    parseKeys.signature = asn1.signature
    function decrypt (data, password) {
      var salt = data.algorithm.decrypt.kde.kdeparams.salt
      var iters = parseInt(data.algorithm.decrypt.kde.kdeparams.iters.toString(), 10)
      var algo = aesid[data.algorithm.decrypt.cipher.algo.join('.')]
      var iv = data.algorithm.decrypt.cipher.iv
      var cipherText = data.subjectPrivateKey
      var keylen = parseInt(algo.split('-')[1], 10) / 8
      var key = compat.pbkdf2Sync(password, salt, iters, keylen, 'sha1')
      var cipher = ciphers.createDecipheriv(algo, key, iv)
      var out = []
      out.push(cipher.update(cipherText))
      out.push(cipher.final())
      return Buffer.concat(out)
    }
    
    },{"./aesid.json":165,"./asn1":166,"./fixProc":168,"browserify-aes":27,"pbkdf2":170,"safe-buffer":187}],170:[function(require,module,exports){
    exports.pbkdf2 = require('./lib/async')
    exports.pbkdf2Sync = require('./lib/sync')
    
    },{"./lib/async":171,"./lib/sync":174}],171:[function(require,module,exports){
    (function (global){(function (){
    var Buffer = require('safe-buffer').Buffer
    
    var checkParameters = require('./precondition')
    var defaultEncoding = require('./default-encoding')
    var sync = require('./sync')
    var toBuffer = require('./to-buffer')
    
    var ZERO_BUF
    var subtle = global.crypto && global.crypto.subtle
    var toBrowser = {
      sha: 'SHA-1',
      'sha-1': 'SHA-1',
      sha1: 'SHA-1',
      sha256: 'SHA-256',
      'sha-256': 'SHA-256',
      sha384: 'SHA-384',
      'sha-384': 'SHA-384',
      'sha-512': 'SHA-512',
      sha512: 'SHA-512'
    }
    var checks = []
    function checkNative (algo) {
      if (global.process && !global.process.browser) {
        return Promise.resolve(false)
      }
      if (!subtle || !subtle.importKey || !subtle.deriveBits) {
        return Promise.resolve(false)
      }
      if (checks[algo] !== undefined) {
        return checks[algo]
      }
      ZERO_BUF = ZERO_BUF || Buffer.alloc(8)
      var prom = browserPbkdf2(ZERO_BUF, ZERO_BUF, 10, 128, algo)
        .then(function () {
          return true
        }).catch(function () {
          return false
        })
      checks[algo] = prom
      return prom
    }
    var nextTick
    function getNextTick () {
      if (nextTick) {
        return nextTick
      }
      if (global.process && global.process.nextTick) {
        nextTick = global.process.nextTick
      } else if (global.queueMicrotask) {
        nextTick = global.queueMicrotask
      } else if (global.setImmediate) {
        nextTick = global.setImmediate
      } else {
        nextTick = global.setTimeout
      }
      return nextTick
    }
    function browserPbkdf2 (password, salt, iterations, length, algo) {
      return subtle.importKey(
        'raw', password, { name: 'PBKDF2' }, false, ['deriveBits']
      ).then(function (key) {
        return subtle.deriveBits({
          name: 'PBKDF2',
          salt: salt,
          iterations: iterations,
          hash: {
            name: algo
          }
        }, key, length << 3)
      }).then(function (res) {
        return Buffer.from(res)
      })
    }
    
    function resolvePromise (promise, callback) {
      promise.then(function (out) {
        getNextTick()(function () {
          callback(null, out)
        })
      }, function (e) {
        getNextTick()(function () {
          callback(e)
        })
      })
    }
    module.exports = function (password, salt, iterations, keylen, digest, callback) {
      if (typeof digest === 'function') {
        callback = digest
        digest = undefined
      }
    
      digest = digest || 'sha1'
      var algo = toBrowser[digest.toLowerCase()]
    
      if (!algo || typeof global.Promise !== 'function') {
        getNextTick()(function () {
          var out
          try {
            out = sync(password, salt, iterations, keylen, digest)
          } catch (e) {
            return callback(e)
          }
          callback(null, out)
        })
        return
      }
    
      checkParameters(iterations, keylen)
      password = toBuffer(password, defaultEncoding, 'Password')
      salt = toBuffer(salt, defaultEncoding, 'Salt')
      if (typeof callback !== 'function') throw new Error('No callback provided to pbkdf2')
    
      resolvePromise(checkNative(algo).then(function (resp) {
        if (resp) return browserPbkdf2(password, salt, iterations, keylen, algo)
    
        return sync(password, salt, iterations, keylen, digest)
      }), callback)
    }
    
    }).call(this)}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
    },{"./default-encoding":172,"./precondition":173,"./sync":174,"./to-buffer":175,"safe-buffer":187}],172:[function(require,module,exports){
    (function (process,global){(function (){
    var defaultEncoding
    /* istanbul ignore next */
    if (global.process && global.process.browser) {
      defaultEncoding = 'utf-8'
    } else if (global.process && global.process.version) {
      var pVersionMajor = parseInt(process.version.split('.')[0].slice(1), 10)
    
      defaultEncoding = pVersionMajor >= 6 ? 'utf-8' : 'binary'
    } else {
      defaultEncoding = 'utf-8'
    }
    module.exports = defaultEncoding
    
    }).call(this)}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
    },{"_process":176}],173:[function(require,module,exports){
    var MAX_ALLOC = Math.pow(2, 30) - 1 // default in iojs
    
    module.exports = function (iterations, keylen) {
      if (typeof iterations !== 'number') {
        throw new TypeError('Iterations not a number')
      }
    
      if (iterations < 0) {
        throw new TypeError('Bad iterations')
      }
    
      if (typeof keylen !== 'number') {
        throw new TypeError('Key length not a number')
      }
    
      if (keylen < 0 || keylen > MAX_ALLOC || keylen !== keylen) { /* eslint no-self-compare: 0 */
        throw new TypeError('Bad key length')
      }
    }
    
    },{}],174:[function(require,module,exports){
    var md5 = require('create-hash/md5')
    var RIPEMD160 = require('ripemd160')
    var sha = require('sha.js')
    var Buffer = require('safe-buffer').Buffer
    
    var checkParameters = require('./precondition')
    var defaultEncoding = require('./default-encoding')
    var toBuffer = require('./to-buffer')
    
    var ZEROS = Buffer.alloc(128)
    var sizes = {
      md5: 16,
      sha1: 20,
      sha224: 28,
      sha256: 32,
      sha384: 48,
      sha512: 64,
      rmd160: 20,
      ripemd160: 20
    }
    
    function Hmac (alg, key, saltLen) {
      var hash = getDigest(alg)
      var blocksize = (alg === 'sha512' || alg === 'sha384') ? 128 : 64
    
      if (key.length > blocksize) {
        key = hash(key)
      } else if (key.length < blocksize) {
        key = Buffer.concat([key, ZEROS], blocksize)
      }
    
      var ipad = Buffer.allocUnsafe(blocksize + sizes[alg])
      var opad = Buffer.allocUnsafe(blocksize + sizes[alg])
      for (var i = 0; i < blocksize; i++) {
        ipad[i] = key[i] ^ 0x36
        opad[i] = key[i] ^ 0x5C
      }
    
      var ipad1 = Buffer.allocUnsafe(blocksize + saltLen + 4)
      ipad.copy(ipad1, 0, 0, blocksize)
      this.ipad1 = ipad1
      this.ipad2 = ipad
      this.opad = opad
      this.alg = alg
      this.blocksize = blocksize
      this.hash = hash
      this.size = sizes[alg]
    }
    
    Hmac.prototype.run = function (data, ipad) {
      data.copy(ipad, this.blocksize)
      var h = this.hash(ipad)
      h.copy(this.opad, this.blocksize)
      return this.hash(this.opad)
    }
    
    function getDigest (alg) {
      function shaFunc (data) {
        return sha(alg).update(data).digest()
      }
      function rmd160Func (data) {
        return new RIPEMD160().update(data).digest()
      }
    
      if (alg === 'rmd160' || alg === 'ripemd160') return rmd160Func
      if (alg === 'md5') return md5
      return shaFunc
    }
    
    function pbkdf2 (password, salt, iterations, keylen, digest) {
      checkParameters(iterations, keylen)
      password = toBuffer(password, defaultEncoding, 'Password')
      salt = toBuffer(salt, defaultEncoding, 'Salt')
    
      digest = digest || 'sha1'
    
      var hmac = new Hmac(digest, password, salt.length)
    
      var DK = Buffer.allocUnsafe(keylen)
      var block1 = Buffer.allocUnsafe(salt.length + 4)
      salt.copy(block1, 0, 0, salt.length)
    
      var destPos = 0
      var hLen = sizes[digest]
      var l = Math.ceil(keylen / hLen)
    
      for (var i = 1; i <= l; i++) {
        block1.writeUInt32BE(i, salt.length)
    
        var T = hmac.run(block1, hmac.ipad1)
        var U = T
    
        for (var j = 1; j < iterations; j++) {
          U = hmac.run(U, hmac.ipad2)
          for (var k = 0; k < hLen; k++) T[k] ^= U[k]
        }
    
        T.copy(DK, destPos)
        destPos += hLen
      }
    
      return DK
    }
    
    module.exports = pbkdf2
    
    },{"./default-encoding":172,"./precondition":173,"./to-buffer":175,"create-hash/md5":75,"ripemd160":186,"safe-buffer":187,"sha.js":190}],175:[function(require,module,exports){
    var Buffer = require('safe-buffer').Buffer
    
    module.exports = function (thing, encoding, name) {
      if (Buffer.isBuffer(thing)) {
        return thing
      } else if (typeof thing === 'string') {
        return Buffer.from(thing, encoding)
      } else if (ArrayBuffer.isView(thing)) {
        return Buffer.from(thing.buffer)
      } else {
        throw new TypeError(name + ' must be a string, a Buffer, a typed array or a DataView')
      }
    }
    
    },{"safe-buffer":187}],176:[function(require,module,exports){
    // shim for using process in browser
    var process = module.exports = {};
    
    // cached from whatever global is present so that test runners that stub it
    // don't break things.  But we need to wrap it in a try catch in case it is
    // wrapped in strict mode code which doesn't define any globals.  It's inside a
    // function because try/catches deoptimize in certain engines.
    
    var cachedSetTimeout;
    var cachedClearTimeout;
    
    function defaultSetTimout() {
        throw new Error('setTimeout has not been defined');
    }
    function defaultClearTimeout () {
        throw new Error('clearTimeout has not been defined');
    }
    (function () {
        try {
            if (typeof setTimeout === 'function') {
                cachedSetTimeout = setTimeout;
            } else {
                cachedSetTimeout = defaultSetTimout;
            }
        } catch (e) {
            cachedSetTimeout = defaultSetTimout;
        }
        try {
            if (typeof clearTimeout === 'function') {
                cachedClearTimeout = clearTimeout;
            } else {
                cachedClearTimeout = defaultClearTimeout;
            }
        } catch (e) {
            cachedClearTimeout = defaultClearTimeout;
        }
    } ())
    function runTimeout(fun) {
        if (cachedSetTimeout === setTimeout) {
            //normal enviroments in sane situations
            return setTimeout(fun, 0);
        }
        // if setTimeout wasn't available but was latter defined
        if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) {
            cachedSetTimeout = setTimeout;
            return setTimeout(fun, 0);
        }
        try {
            // when when somebody has screwed with setTimeout but no I.E. maddness
            return cachedSetTimeout(fun, 0);
        } catch(e){
            try {
                // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
                return cachedSetTimeout.call(null, fun, 0);
            } catch(e){
                // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error
                return cachedSetTimeout.call(this, fun, 0);
            }
        }
    
    
    }
    function runClearTimeout(marker) {
        if (cachedClearTimeout === clearTimeout) {
            //normal enviroments in sane situations
            return clearTimeout(marker);
        }
        // if clearTimeout wasn't available but was latter defined
        if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) {
            cachedClearTimeout = clearTimeout;
            return clearTimeout(marker);
        }
        try {
            // when when somebody has screwed with setTimeout but no I.E. maddness
            return cachedClearTimeout(marker);
        } catch (e){
            try {
                // When we are in I.E. but the script has been evaled so I.E. doesn't  trust the global object when called normally
                return cachedClearTimeout.call(null, marker);
            } catch (e){
                // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error.
                // Some versions of I.E. have different rules for clearTimeout vs setTimeout
                return cachedClearTimeout.call(this, marker);
            }
        }
    
    
    
    }
    var queue = [];
    var draining = false;
    var currentQueue;
    var queueIndex = -1;
    
    function cleanUpNextTick() {
        if (!draining || !currentQueue) {
            return;
        }
        draining = false;
        if (currentQueue.length) {
            queue = currentQueue.concat(queue);
        } else {
            queueIndex = -1;
        }
        if (queue.length) {
            drainQueue();
        }
    }
    
    function drainQueue() {
        if (draining) {
            return;
        }
        var timeout = runTimeout(cleanUpNextTick);
        draining = true;
    
        var len = queue.length;
        while(len) {
            currentQueue = queue;
            queue = [];
            while (++queueIndex < len) {
                if (currentQueue) {
                    currentQueue[queueIndex].run();
                }
            }
            queueIndex = -1;
            len = queue.length;
        }
        currentQueue = null;
        draining = false;
        runClearTimeout(timeout);
    }
    
    process.nextTick = function (fun) {
        var args = new Array(arguments.length - 1);
        if (arguments.length > 1) {
            for (var i = 1; i < arguments.length; i++) {
                args[i - 1] = arguments[i];
            }
        }
        queue.push(new Item(fun, args));
        if (queue.length === 1 && !draining) {
            runTimeout(drainQueue);
        }
    };
    
    // v8 likes predictible objects
    function Item(fun, array) {
        this.fun = fun;
        this.array = array;
    }
    Item.prototype.run = function () {
        this.fun.apply(null, this.array);
    };
    process.title = 'browser';
    process.browser = true;
    process.env = {};
    process.argv = [];
    process.version = ''; // empty string to avoid regexp issues
    process.versions = {};
    
    function noop() {}
    
    process.on = noop;
    process.addListener = noop;
    process.once = noop;
    process.off = noop;
    process.removeListener = noop;
    process.removeAllListeners = noop;
    process.emit = noop;
    process.prependListener = noop;
    process.prependOnceListener = noop;
    
    process.listeners = function (name) { return [] }
    
    process.binding = function (name) {
        throw new Error('process.binding is not supported');
    };
    
    process.cwd = function () { return '/' };
    process.chdir = function (dir) {
        throw new Error('process.chdir is not supported');
    };
    process.umask = function() { return 0; };
    
    },{}],177:[function(require,module,exports){
    exports.publicEncrypt = require('./publicEncrypt')
    exports.privateDecrypt = require('./privateDecrypt')
    
    exports.privateEncrypt = function privateEncrypt (key, buf) {
      return exports.publicEncrypt(key, buf, true)
    }
    
    exports.publicDecrypt = function publicDecrypt (key, buf) {
      return exports.privateDecrypt(key, buf, true)
    }
    
    },{"./privateDecrypt":180,"./publicEncrypt":181}],178:[function(require,module,exports){
    var createHash = require('create-hash')
    var Buffer = require('safe-buffer').Buffer
    
    module.exports = function (seed, len) {
      var t = Buffer.alloc(0)
      var i = 0
      var c
      while (t.length < len) {
        c = i2ops(i++)
        t = Buffer.concat([t, createHash('sha1').update(seed).update(c).digest()])
      }
      return t.slice(0, len)
    }
    
    function i2ops (c) {
      var out = Buffer.allocUnsafe(4)
      out.writeUInt32BE(c, 0)
      return out
    }
    
    },{"create-hash":74,"safe-buffer":187}],179:[function(require,module,exports){
    arguments[4][15][0].apply(exports,arguments)
    },{"buffer":24,"dup":15}],180:[function(require,module,exports){
    var parseKeys = require('parse-asn1')
    var mgf = require('./mgf')
    var xor = require('./xor')
    var BN = require('bn.js')
    var crt = require('browserify-rsa')
    var createHash = require('create-hash')
    var withPublic = require('./withPublic')
    var Buffer = require('safe-buffer').Buffer
    
    module.exports = function privateDecrypt (privateKey, enc, reverse) {
      var padding
      if (privateKey.padding) {
        padding = privateKey.padding
      } else if (reverse) {
        padding = 1
      } else {
        padding = 4
      }
    
      var key = parseKeys(privateKey)
      var k = key.modulus.byteLength()
      if (enc.length > k || new BN(enc).cmp(key.modulus) >= 0) {
        throw new Error('decryption error')
      }
      var msg
      if (reverse) {
        msg = withPublic(new BN(enc), key)
      } else {
        msg = crt(enc, key)
      }
      var zBuffer = Buffer.alloc(k - msg.length)
      msg = Buffer.concat([zBuffer, msg], k)
      if (padding === 4) {
        return oaep(key, msg)
      } else if (padding === 1) {
        return pkcs1(key, msg, reverse)
      } else if (padding === 3) {
        return msg
      } else {
        throw new Error('unknown padding')
      }
    }
    
    function oaep (key, msg) {
      var k = key.modulus.byteLength()
      var iHash = createHash('sha1').update(Buffer.alloc(0)).digest()
      var hLen = iHash.length
      if (msg[0] !== 0) {
        throw new Error('decryption error')
      }
      var maskedSeed = msg.slice(1, hLen + 1)
      var maskedDb = msg.slice(hLen + 1)
      var seed = xor(maskedSeed, mgf(maskedDb, hLen))
      var db = xor(maskedDb, mgf(seed, k - hLen - 1))
      if (compare(iHash, db.slice(0, hLen))) {
        throw new Error('decryption error')
      }
      var i = hLen
      while (db[i] === 0) {
        i++
      }
      if (db[i++] !== 1) {
        throw new Error('decryption error')
      }
      return db.slice(i)
    }
    
    function pkcs1 (key, msg, reverse) {
      var p1 = msg.slice(0, 2)
      var i = 2
      var status = 0
      while (msg[i++] !== 0) {
        if (i >= msg.length) {
          status++
          break
        }
      }
      var ps = msg.slice(2, i - 1)
    
      if ((p1.toString('hex') !== '0002' && !reverse) || (p1.toString('hex') !== '0001' && reverse)) {
        status++
      }
      if (ps.length < 8) {
        status++
      }
      if (status) {
        throw new Error('decryption error')
      }
      return msg.slice(i)
    }
    function compare (a, b) {
      a = Buffer.from(a)
      b = Buffer.from(b)
      var dif = 0
      var len = a.length
      if (a.length !== b.length) {
        dif++
        len = Math.min(a.length, b.length)
      }
      var i = -1
      while (++i < len) {
        dif += (a[i] ^ b[i])
      }
      return dif
    }
    
    },{"./mgf":178,"./withPublic":182,"./xor":183,"bn.js":179,"browserify-rsa":45,"create-hash":74,"parse-asn1":169,"safe-buffer":187}],181:[function(require,module,exports){
    var parseKeys = require('parse-asn1')
    var randomBytes = require('randombytes')
    var createHash = require('create-hash')
    var mgf = require('./mgf')
    var xor = require('./xor')
    var BN = require('bn.js')
    var withPublic = require('./withPublic')
    var crt = require('browserify-rsa')
    var Buffer = require('safe-buffer').Buffer
    
    module.exports = function publicEncrypt (publicKey, msg, reverse) {
      var padding
      if (publicKey.padding) {
        padding = publicKey.padding
      } else if (reverse) {
        padding = 1
      } else {
        padding = 4
      }
      var key = parseKeys(publicKey)
      var paddedMsg
      if (padding === 4) {
        paddedMsg = oaep(key, msg)
      } else if (padding === 1) {
        paddedMsg = pkcs1(key, msg, reverse)
      } else if (padding === 3) {
        paddedMsg = new BN(msg)
        if (paddedMsg.cmp(key.modulus) >= 0) {
          throw new Error('data too long for modulus')
        }
      } else {
        throw new Error('unknown padding')
      }
      if (reverse) {
        return crt(paddedMsg, key)
      } else {
        return withPublic(paddedMsg, key)
      }
    }
    
    function oaep (key, msg) {
      var k = key.modulus.byteLength()
      var mLen = msg.length
      var iHash = createHash('sha1').update(Buffer.alloc(0)).digest()
      var hLen = iHash.length
      var hLen2 = 2 * hLen
      if (mLen > k - hLen2 - 2) {
        throw new Error('message too long')
      }
      var ps = Buffer.alloc(k - mLen - hLen2 - 2)
      var dblen = k - hLen - 1
      var seed = randomBytes(hLen)
      var maskedDb = xor(Buffer.concat([iHash, ps, Buffer.alloc(1, 1), msg], dblen), mgf(seed, dblen))
      var maskedSeed = xor(seed, mgf(maskedDb, hLen))
      return new BN(Buffer.concat([Buffer.alloc(1), maskedSeed, maskedDb], k))
    }
    function pkcs1 (key, msg, reverse) {
      var mLen = msg.length
      var k = key.modulus.byteLength()
      if (mLen > k - 11) {
        throw new Error('message too long')
      }
      var ps
      if (reverse) {
        ps = Buffer.alloc(k - mLen - 3, 0xff)
      } else {
        ps = nonZero(k - mLen - 3)
      }
      return new BN(Buffer.concat([Buffer.from([0, reverse ? 1 : 2]), ps, Buffer.alloc(1), msg], k))
    }
    function nonZero (len) {
      var out = Buffer.allocUnsafe(len)
      var i = 0
      var cache = randomBytes(len * 2)
      var cur = 0
      var num
      while (i < len) {
        if (cur === cache.length) {
          cache = randomBytes(len * 2)
          cur = 0
        }
        num = cache[cur++]
        if (num) {
          out[i++] = num
        }
      }
      return out
    }
    
    },{"./mgf":178,"./withPublic":182,"./xor":183,"bn.js":179,"browserify-rsa":45,"create-hash":74,"parse-asn1":169,"randombytes":184,"safe-buffer":187}],182:[function(require,module,exports){
    var BN = require('bn.js')
    var Buffer = require('safe-buffer').Buffer
    
    function withPublic (paddedMsg, key) {
      return Buffer.from(paddedMsg
        .toRed(BN.mont(key.modulus))
        .redPow(new BN(key.publicExponent))
        .fromRed()
        .toArray())
    }
    
    module.exports = withPublic
    
    },{"bn.js":179,"safe-buffer":187}],183:[function(require,module,exports){
    module.exports = function xor (a, b) {
      var len = a.length
      var i = -1
      while (++i < len) {
        a[i] ^= b[i]
      }
      return a
    }
    
    },{}],184:[function(require,module,exports){
    (function (process,global){(function (){
    'use strict'
    
    // limit of Crypto.getRandomValues()
    // https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues
    var MAX_BYTES = 65536
    
    // Node supports requesting up to this number of bytes
    // https://github.com/nodejs/node/blob/master/lib/internal/crypto/random.js#L48
    var MAX_UINT32 = 4294967295
    
    function oldBrowser () {
      throw new Error('Secure random number generation is not supported by this browser.\nUse Chrome, Firefox or Internet Explorer 11')
    }
    
    var Buffer = require('safe-buffer').Buffer
    var crypto = global.crypto || global.msCrypto
    
    if (crypto && crypto.getRandomValues) {
      module.exports = randomBytes
    } else {
      module.exports = oldBrowser
    }
    
    function randomBytes (size, cb) {
      // phantomjs needs to throw
      if (size > MAX_UINT32) throw new RangeError('requested too many random bytes')
    
      var bytes = Buffer.allocUnsafe(size)
    
      if (size > 0) {  // getRandomValues fails on IE if size == 0
        if (size > MAX_BYTES) { // this is the max bytes crypto.getRandomValues
          // can do at once see https://developer.mozilla.org/en-US/docs/Web/API/window.crypto.getRandomValues
          for (var generated = 0; generated < size; generated += MAX_BYTES) {
            // buffer.slice automatically checks if the end is past the end of
            // the buffer so we don't have to here
            crypto.getRandomValues(bytes.slice(generated, generated + MAX_BYTES))
          }
        } else {
          crypto.getRandomValues(bytes)
        }
      }
    
      if (typeof cb === 'function') {
        return process.nextTick(function () {
          cb(null, bytes)
        })
      }
    
      return bytes
    }
    
    }).call(this)}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
    },{"_process":176,"safe-buffer":187}],185:[function(require,module,exports){
    (function (process,global){(function (){
    'use strict'
    
    function oldBrowser () {
      throw new Error('secure random number generation not supported by this browser\nuse chrome, FireFox or Internet Explorer 11')
    }
    var safeBuffer = require('safe-buffer')
    var randombytes = require('randombytes')
    var Buffer = safeBuffer.Buffer
    var kBufferMaxLength = safeBuffer.kMaxLength
    var crypto = global.crypto || global.msCrypto
    var kMaxUint32 = Math.pow(2, 32) - 1
    function assertOffset (offset, length) {
      if (typeof offset !== 'number' || offset !== offset) { // eslint-disable-line no-self-compare
        throw new TypeError('offset must be a number')
      }
    
      if (offset > kMaxUint32 || offset < 0) {
        throw new TypeError('offset must be a uint32')
      }
    
      if (offset > kBufferMaxLength || offset > length) {
        throw new RangeError('offset out of range')
      }
    }
    
    function assertSize (size, offset, length) {
      if (typeof size !== 'number' || size !== size) { // eslint-disable-line no-self-compare
        throw new TypeError('size must be a number')
      }
    
      if (size > kMaxUint32 || size < 0) {
        throw new TypeError('size must be a uint32')
      }
    
      if (size + offset > length || size > kBufferMaxLength) {
        throw new RangeError('buffer too small')
      }
    }
    if ((crypto && crypto.getRandomValues) || !process.browser) {
      exports.randomFill = randomFill
      exports.randomFillSync = randomFillSync
    } else {
      exports.randomFill = oldBrowser
      exports.randomFillSync = oldBrowser
    }
    function randomFill (buf, offset, size, cb) {
      if (!Buffer.isBuffer(buf) && !(buf instanceof global.Uint8Array)) {
        throw new TypeError('"buf" argument must be a Buffer or Uint8Array')
      }
    
      if (typeof offset === 'function') {
        cb = offset
        offset = 0
        size = buf.length
      } else if (typeof size === 'function') {
        cb = size
        size = buf.length - offset
      } else if (typeof cb !== 'function') {
        throw new TypeError('"cb" argument must be a function')
      }
      assertOffset(offset, buf.length)
      assertSize(size, offset, buf.length)
      return actualFill(buf, offset, size, cb)
    }
    
    function actualFill (buf, offset, size, cb) {
      if (process.browser) {
        var ourBuf = buf.buffer
        var uint = new Uint8Array(ourBuf, offset, size)
        crypto.getRandomValues(uint)
        if (cb) {
          process.nextTick(function () {
            cb(null, buf)
          })
          return
        }
        return buf
      }
      if (cb) {
        randombytes(size, function (err, bytes) {
          if (err) {
            return cb(err)
          }
          bytes.copy(buf, offset)
          cb(null, buf)
        })
        return
      }
      var bytes = randombytes(size)
      bytes.copy(buf, offset)
      return buf
    }
    function randomFillSync (buf, offset, size) {
      if (typeof offset === 'undefined') {
        offset = 0
      }
      if (!Buffer.isBuffer(buf) && !(buf instanceof global.Uint8Array)) {
        throw new TypeError('"buf" argument must be a Buffer or Uint8Array')
      }
    
      assertOffset(offset, buf.length)
    
      if (size === undefined) size = buf.length - offset
    
      assertSize(size, offset, buf.length)
    
      return actualFill(buf, offset, size)
    }
    
    }).call(this)}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
    },{"_process":176,"randombytes":184,"safe-buffer":187}],186:[function(require,module,exports){
    'use strict'
    var Buffer = require('buffer').Buffer
    var inherits = require('inherits')
    var HashBase = require('hash-base')
    
    var ARRAY16 = new Array(16)
    
    var zl = [
      0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
      7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8,
      3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12,
      1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2,
      4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13
    ]
    
    var zr = [
      5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12,
      6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2,
      15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13,
      8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14,
      12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11
    ]
    
    var sl = [
      11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8,
      7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12,
      11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5,
      11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12,
      9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6
    ]
    
    var sr = [
      8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6,
      9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11,
      9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5,
      15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8,
      8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11
    ]
    
    var hl = [0x00000000, 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xa953fd4e]
    var hr = [0x50a28be6, 0x5c4dd124, 0x6d703ef3, 0x7a6d76e9, 0x00000000]
    
    function RIPEMD160 () {
      HashBase.call(this, 64)
    
      // state
      this._a = 0x67452301
      this._b = 0xefcdab89
      this._c = 0x98badcfe
      this._d = 0x10325476
      this._e = 0xc3d2e1f0
    }
    
    inherits(RIPEMD160, HashBase)
    
    RIPEMD160.prototype._update = function () {
      var words = ARRAY16
      for (var j = 0; j < 16; ++j) words[j] = this._block.readInt32LE(j * 4)
    
      var al = this._a | 0
      var bl = this._b | 0
      var cl = this._c | 0
      var dl = this._d | 0
      var el = this._e | 0
    
      var ar = this._a | 0
      var br = this._b | 0
      var cr = this._c | 0
      var dr = this._d | 0
      var er = this._e | 0
    
      // computation
      for (var i = 0; i < 80; i += 1) {
        var tl
        var tr
        if (i < 16) {
          tl = fn1(al, bl, cl, dl, el, words[zl[i]], hl[0], sl[i])
          tr = fn5(ar, br, cr, dr, er, words[zr[i]], hr[0], sr[i])
        } else if (i < 32) {
          tl = fn2(al, bl, cl, dl, el, words[zl[i]], hl[1], sl[i])
          tr = fn4(ar, br, cr, dr, er, words[zr[i]], hr[1], sr[i])
        } else if (i < 48) {
          tl = fn3(al, bl, cl, dl, el, words[zl[i]], hl[2], sl[i])
          tr = fn3(ar, br, cr, dr, er, words[zr[i]], hr[2], sr[i])
        } else if (i < 64) {
          tl = fn4(al, bl, cl, dl, el, words[zl[i]], hl[3], sl[i])
          tr = fn2(ar, br, cr, dr, er, words[zr[i]], hr[3], sr[i])
        } else { // if (i<80) {
          tl = fn5(al, bl, cl, dl, el, words[zl[i]], hl[4], sl[i])
          tr = fn1(ar, br, cr, dr, er, words[zr[i]], hr[4], sr[i])
        }
    
        al = el
        el = dl
        dl = rotl(cl, 10)
        cl = bl
        bl = tl
    
        ar = er
        er = dr
        dr = rotl(cr, 10)
        cr = br
        br = tr
      }
    
      // update state
      var t = (this._b + cl + dr) | 0
      this._b = (this._c + dl + er) | 0
      this._c = (this._d + el + ar) | 0
      this._d = (this._e + al + br) | 0
      this._e = (this._a + bl + cr) | 0
      this._a = t
    }
    
    RIPEMD160.prototype._digest = function () {
      // create padding and handle blocks
      this._block[this._blockOffset++] = 0x80
      if (this._blockOffset > 56) {
        this._block.fill(0, this._blockOffset, 64)
        this._update()
        this._blockOffset = 0
      }
    
      this._block.fill(0, this._blockOffset, 56)
      this._block.writeUInt32LE(this._length[0], 56)
      this._block.writeUInt32LE(this._length[1], 60)
      this._update()
    
      // produce result
      var buffer = Buffer.alloc ? Buffer.alloc(20) : new Buffer(20)
      buffer.writeInt32LE(this._a, 0)
      buffer.writeInt32LE(this._b, 4)
      buffer.writeInt32LE(this._c, 8)
      buffer.writeInt32LE(this._d, 12)
      buffer.writeInt32LE(this._e, 16)
      return buffer
    }
    
    function rotl (x, n) {
      return (x << n) | (x >>> (32 - n))
    }
    
    function fn1 (a, b, c, d, e, m, k, s) {
      return (rotl((a + (b ^ c ^ d) + m + k) | 0, s) + e) | 0
    }
    
    function fn2 (a, b, c, d, e, m, k, s) {
      return (rotl((a + ((b & c) | ((~b) & d)) + m + k) | 0, s) + e) | 0
    }
    
    function fn3 (a, b, c, d, e, m, k, s) {
      return (rotl((a + ((b | (~c)) ^ d) + m + k) | 0, s) + e) | 0
    }
    
    function fn4 (a, b, c, d, e, m, k, s) {
      return (rotl((a + ((b & d) | (c & (~d))) + m + k) | 0, s) + e) | 0
    }
    
    function fn5 (a, b, c, d, e, m, k, s) {
      return (rotl((a + (b ^ (c | (~d))) + m + k) | 0, s) + e) | 0
    }
    
    module.exports = RIPEMD160
    
    },{"buffer":68,"hash-base":119,"inherits":149}],187:[function(require,module,exports){
    /*! safe-buffer. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */
    /* eslint-disable node/no-deprecated-api */
    var buffer = require('buffer')
    var Buffer = buffer.Buffer
    
    // alternative to using Object.keys for old browsers
    function copyProps (src, dst) {
      for (var key in src) {
        dst[key] = src[key]
      }
    }
    if (Buffer.from && Buffer.alloc && Buffer.allocUnsafe && Buffer.allocUnsafeSlow) {
      module.exports = buffer
    } else {
      // Copy properties from require('buffer')
      copyProps(buffer, exports)
      exports.Buffer = SafeBuffer
    }
    
    function SafeBuffer (arg, encodingOrOffset, length) {
      return Buffer(arg, encodingOrOffset, length)
    }
    
    SafeBuffer.prototype = Object.create(Buffer.prototype)
    
    // Copy static methods from Buffer
    copyProps(Buffer, SafeBuffer)
    
    SafeBuffer.from = function (arg, encodingOrOffset, length) {
      if (typeof arg === 'number') {
        throw new TypeError('Argument must not be a number')
      }
      return Buffer(arg, encodingOrOffset, length)
    }
    
    SafeBuffer.alloc = function (size, fill, encoding) {
      if (typeof size !== 'number') {
        throw new TypeError('Argument must be a number')
      }
      var buf = Buffer(size)
      if (fill !== undefined) {
        if (typeof encoding === 'string') {
          buf.fill(fill, encoding)
        } else {
          buf.fill(fill)
        }
      } else {
        buf.fill(0)
      }
      return buf
    }
    
    SafeBuffer.allocUnsafe = function (size) {
      if (typeof size !== 'number') {
        throw new TypeError('Argument must be a number')
      }
      return Buffer(size)
    }
    
    SafeBuffer.allocUnsafeSlow = function (size) {
      if (typeof size !== 'number') {
        throw new TypeError('Argument must be a number')
      }
      return buffer.SlowBuffer(size)
    }
    
    },{"buffer":68}],188:[function(require,module,exports){
    (function (process){(function (){
    /* eslint-disable node/no-deprecated-api */
    
    'use strict'
    
    var buffer = require('buffer')
    var Buffer = buffer.Buffer
    
    var safer = {}
    
    var key
    
    for (key in buffer) {
      if (!buffer.hasOwnProperty(key)) continue
      if (key === 'SlowBuffer' || key === 'Buffer') continue
      safer[key] = buffer[key]
    }
    
    var Safer = safer.Buffer = {}
    for (key in Buffer) {
      if (!Buffer.hasOwnProperty(key)) continue
      if (key === 'allocUnsafe' || key === 'allocUnsafeSlow') continue
      Safer[key] = Buffer[key]
    }
    
    safer.Buffer.prototype = Buffer.prototype
    
    if (!Safer.from || Safer.from === Uint8Array.from) {
      Safer.from = function (value, encodingOrOffset, length) {
        if (typeof value === 'number') {
          throw new TypeError('The "value" argument must not be of type number. Received type ' + typeof value)
        }
        if (value && typeof value.length === 'undefined') {
          throw new TypeError('The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type ' + typeof value)
        }
        return Buffer(value, encodingOrOffset, length)
      }
    }
    
    if (!Safer.alloc) {
      Safer.alloc = function (size, fill, encoding) {
        if (typeof size !== 'number') {
          throw new TypeError('The "size" argument must be of type number. Received type ' + typeof size)
        }
        if (size < 0 || size >= 2 * (1 << 30)) {
          throw new RangeError('The value "' + size + '" is invalid for option "size"')
        }
        var buf = Buffer(size)
        if (!fill || fill.length === 0) {
          buf.fill(0)
        } else if (typeof encoding === 'string') {
          buf.fill(fill, encoding)
        } else {
          buf.fill(fill)
        }
        return buf
      }
    }
    
    if (!safer.kStringMaxLength) {
      try {
        safer.kStringMaxLength = process.binding('buffer').kStringMaxLength
      } catch (e) {
        // we can't determine kStringMaxLength in environments where process.binding
        // is unsupported, so let's not set it
      }
    }
    
    if (!safer.constants) {
      safer.constants = {
        MAX_LENGTH: safer.kMaxLength
      }
      if (safer.kStringMaxLength) {
        safer.constants.MAX_STRING_LENGTH = safer.kStringMaxLength
      }
    }
    
    module.exports = safer
    
    }).call(this)}).call(this,require('_process'))
    },{"_process":176,"buffer":68}],189:[function(require,module,exports){
    var Buffer = require('safe-buffer').Buffer
    
    // prototype class for hash functions
    function Hash (blockSize, finalSize) {
      this._block = Buffer.alloc(blockSize)
      this._finalSize = finalSize
      this._blockSize = blockSize
      this._len = 0
    }
    
    Hash.prototype.update = function (data, enc) {
      if (typeof data === 'string') {
        enc = enc || 'utf8'
        data = Buffer.from(data, enc)
      }
    
      var block = this._block
      var blockSize = this._blockSize
      var length = data.length
      var accum = this._len
    
      for (var offset = 0; offset < length;) {
        var assigned = accum % blockSize
        var remainder = Math.min(length - offset, blockSize - assigned)
    
        for (var i = 0; i < remainder; i++) {
          block[assigned + i] = data[offset + i]
        }
    
        accum += remainder
        offset += remainder
    
        if ((accum % blockSize) === 0) {
          this._update(block)
        }
      }
    
      this._len += length
      return this
    }
    
    Hash.prototype.digest = function (enc) {
      var rem = this._len % this._blockSize
    
      this._block[rem] = 0x80
    
      // zero (rem + 1) trailing bits, where (rem + 1) is the smallest
      // non-negative solution to the equation (length + 1 + (rem + 1)) === finalSize mod blockSize
      this._block.fill(0, rem + 1)
    
      if (rem >= this._finalSize) {
        this._update(this._block)
        this._block.fill(0)
      }
    
      var bits = this._len * 8
    
      // uint32
      if (bits <= 0xffffffff) {
        this._block.writeUInt32BE(bits, this._blockSize - 4)
    
      // uint64
      } else {
        var lowBits = (bits & 0xffffffff) >>> 0
        var highBits = (bits - lowBits) / 0x100000000
    
        this._block.writeUInt32BE(highBits, this._blockSize - 8)
        this._block.writeUInt32BE(lowBits, this._blockSize - 4)
      }
    
      this._update(this._block)
      var hash = this._hash()
    
      return enc ? hash.toString(enc) : hash
    }
    
    Hash.prototype._update = function () {
      throw new Error('_update must be implemented by subclass')
    }
    
    module.exports = Hash
    
    },{"safe-buffer":187}],190:[function(require,module,exports){
    var exports = module.exports = function SHA (algorithm) {
      algorithm = algorithm.toLowerCase()
    
      var Algorithm = exports[algorithm]
      if (!Algorithm) throw new Error(algorithm + ' is not supported (we accept pull requests)')
    
      return new Algorithm()
    }
    
    exports.sha = require('./sha')
    exports.sha1 = require('./sha1')
    exports.sha224 = require('./sha224')
    exports.sha256 = require('./sha256')
    exports.sha384 = require('./sha384')
    exports.sha512 = require('./sha512')
    
    },{"./sha":191,"./sha1":192,"./sha224":193,"./sha256":194,"./sha384":195,"./sha512":196}],191:[function(require,module,exports){
    /*
     * A JavaScript implementation of the Secure Hash Algorithm, SHA-0, as defined
     * in FIPS PUB 180-1
     * This source code is derived from sha1.js of the same repository.
     * The difference between SHA-0 and SHA-1 is just a bitwise rotate left
     * operation was added.
     */
    
    var inherits = require('inherits')
    var Hash = require('./hash')
    var Buffer = require('safe-buffer').Buffer
    
    var K = [
      0x5a827999, 0x6ed9eba1, 0x8f1bbcdc | 0, 0xca62c1d6 | 0
    ]
    
    var W = new Array(80)
    
    function Sha () {
      this.init()
      this._w = W
    
      Hash.call(this, 64, 56)
    }
    
    inherits(Sha, Hash)
    
    Sha.prototype.init = function () {
      this._a = 0x67452301
      this._b = 0xefcdab89
      this._c = 0x98badcfe
      this._d = 0x10325476
      this._e = 0xc3d2e1f0
    
      return this
    }
    
    function rotl5 (num) {
      return (num << 5) | (num >>> 27)
    }
    
    function rotl30 (num) {
      return (num << 30) | (num >>> 2)
    }
    
    function ft (s, b, c, d) {
      if (s === 0) return (b & c) | ((~b) & d)
      if (s === 2) return (b & c) | (b & d) | (c & d)
      return b ^ c ^ d
    }
    
    Sha.prototype._update = function (M) {
      var W = this._w
    
      var a = this._a | 0
      var b = this._b | 0
      var c = this._c | 0
      var d = this._d | 0
      var e = this._e | 0
    
      for (var i = 0; i < 16; ++i) W[i] = M.readInt32BE(i * 4)
      for (; i < 80; ++i) W[i] = W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16]
    
      for (var j = 0; j < 80; ++j) {
        var s = ~~(j / 20)
        var t = (rotl5(a) + ft(s, b, c, d) + e + W[j] + K[s]) | 0
    
        e = d
        d = c
        c = rotl30(b)
        b = a
        a = t
      }
    
      this._a = (a + this._a) | 0
      this._b = (b + this._b) | 0
      this._c = (c + this._c) | 0
      this._d = (d + this._d) | 0
      this._e = (e + this._e) | 0
    }
    
    Sha.prototype._hash = function () {
      var H = Buffer.allocUnsafe(20)
    
      H.writeInt32BE(this._a | 0, 0)
      H.writeInt32BE(this._b | 0, 4)
      H.writeInt32BE(this._c | 0, 8)
      H.writeInt32BE(this._d | 0, 12)
      H.writeInt32BE(this._e | 0, 16)
    
      return H
    }
    
    module.exports = Sha
    
    },{"./hash":189,"inherits":149,"safe-buffer":187}],192:[function(require,module,exports){
    /*
     * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined
     * in FIPS PUB 180-1
     * Version 2.1a Copyright Paul Johnston 2000 - 2002.
     * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
     * Distributed under the BSD License
     * See http://pajhome.org.uk/crypt/md5 for details.
     */
    
    var inherits = require('inherits')
    var Hash = require('./hash')
    var Buffer = require('safe-buffer').Buffer
    
    var K = [
      0x5a827999, 0x6ed9eba1, 0x8f1bbcdc | 0, 0xca62c1d6 | 0
    ]
    
    var W = new Array(80)
    
    function Sha1 () {
      this.init()
      this._w = W
    
      Hash.call(this, 64, 56)
    }
    
    inherits(Sha1, Hash)
    
    Sha1.prototype.init = function () {
      this._a = 0x67452301
      this._b = 0xefcdab89
      this._c = 0x98badcfe
      this._d = 0x10325476
      this._e = 0xc3d2e1f0
    
      return this
    }
    
    function rotl1 (num) {
      return (num << 1) | (num >>> 31)
    }
    
    function rotl5 (num) {
      return (num << 5) | (num >>> 27)
    }
    
    function rotl30 (num) {
      return (num << 30) | (num >>> 2)
    }
    
    function ft (s, b, c, d) {
      if (s === 0) return (b & c) | ((~b) & d)
      if (s === 2) return (b & c) | (b & d) | (c & d)
      return b ^ c ^ d
    }
    
    Sha1.prototype._update = function (M) {
      var W = this._w
    
      var a = this._a | 0
      var b = this._b | 0
      var c = this._c | 0
      var d = this._d | 0
      var e = this._e | 0
    
      for (var i = 0; i < 16; ++i) W[i] = M.readInt32BE(i * 4)
      for (; i < 80; ++i) W[i] = rotl1(W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16])
    
      for (var j = 0; j < 80; ++j) {
        var s = ~~(j / 20)
        var t = (rotl5(a) + ft(s, b, c, d) + e + W[j] + K[s]) | 0
    
        e = d
        d = c
        c = rotl30(b)
        b = a
        a = t
      }
    
      this._a = (a + this._a) | 0
      this._b = (b + this._b) | 0
      this._c = (c + this._c) | 0
      this._d = (d + this._d) | 0
      this._e = (e + this._e) | 0
    }
    
    Sha1.prototype._hash = function () {
      var H = Buffer.allocUnsafe(20)
    
      H.writeInt32BE(this._a | 0, 0)
      H.writeInt32BE(this._b | 0, 4)
      H.writeInt32BE(this._c | 0, 8)
      H.writeInt32BE(this._d | 0, 12)
      H.writeInt32BE(this._e | 0, 16)
    
      return H
    }
    
    module.exports = Sha1
    
    },{"./hash":189,"inherits":149,"safe-buffer":187}],193:[function(require,module,exports){
    /**
     * A JavaScript implementation of the Secure Hash Algorithm, SHA-256, as defined
     * in FIPS 180-2
     * Version 2.2-beta Copyright Angel Marin, Paul Johnston 2000 - 2009.
     * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
     *
     */
    
    var inherits = require('inherits')
    var Sha256 = require('./sha256')
    var Hash = require('./hash')
    var Buffer = require('safe-buffer').Buffer
    
    var W = new Array(64)
    
    function Sha224 () {
      this.init()
    
      this._w = W // new Array(64)
    
      Hash.call(this, 64, 56)
    }
    
    inherits(Sha224, Sha256)
    
    Sha224.prototype.init = function () {
      this._a = 0xc1059ed8
      this._b = 0x367cd507
      this._c = 0x3070dd17
      this._d = 0xf70e5939
      this._e = 0xffc00b31
      this._f = 0x68581511
      this._g = 0x64f98fa7
      this._h = 0xbefa4fa4
    
      return this
    }
    
    Sha224.prototype._hash = function () {
      var H = Buffer.allocUnsafe(28)
    
      H.writeInt32BE(this._a, 0)
      H.writeInt32BE(this._b, 4)
      H.writeInt32BE(this._c, 8)
      H.writeInt32BE(this._d, 12)
      H.writeInt32BE(this._e, 16)
      H.writeInt32BE(this._f, 20)
      H.writeInt32BE(this._g, 24)
    
      return H
    }
    
    module.exports = Sha224
    
    },{"./hash":189,"./sha256":194,"inherits":149,"safe-buffer":187}],194:[function(require,module,exports){
    /**
     * A JavaScript implementation of the Secure Hash Algorithm, SHA-256, as defined
     * in FIPS 180-2
     * Version 2.2-beta Copyright Angel Marin, Paul Johnston 2000 - 2009.
     * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
     *
     */
    
    var inherits = require('inherits')
    var Hash = require('./hash')
    var Buffer = require('safe-buffer').Buffer
    
    var K = [
      0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5,
      0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5,
      0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3,
      0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174,
      0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC,
      0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA,
      0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7,
      0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967,
      0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13,
      0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85,
      0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3,
      0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070,
      0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5,
      0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3,
      0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208,
      0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2
    ]
    
    var W = new Array(64)
    
    function Sha256 () {
      this.init()
    
      this._w = W // new Array(64)
    
      Hash.call(this, 64, 56)
    }
    
    inherits(Sha256, Hash)
    
    Sha256.prototype.init = function () {
      this._a = 0x6a09e667
      this._b = 0xbb67ae85
      this._c = 0x3c6ef372
      this._d = 0xa54ff53a
      this._e = 0x510e527f
      this._f = 0x9b05688c
      this._g = 0x1f83d9ab
      this._h = 0x5be0cd19
    
      return this
    }
    
    function ch (x, y, z) {
      return z ^ (x & (y ^ z))
    }
    
    function maj (x, y, z) {
      return (x & y) | (z & (x | y))
    }
    
    function sigma0 (x) {
      return (x >>> 2 | x << 30) ^ (x >>> 13 | x << 19) ^ (x >>> 22 | x << 10)
    }
    
    function sigma1 (x) {
      return (x >>> 6 | x << 26) ^ (x >>> 11 | x << 21) ^ (x >>> 25 | x << 7)
    }
    
    function gamma0 (x) {
      return (x >>> 7 | x << 25) ^ (x >>> 18 | x << 14) ^ (x >>> 3)
    }
    
    function gamma1 (x) {
      return (x >>> 17 | x << 15) ^ (x >>> 19 | x << 13) ^ (x >>> 10)
    }
    
    Sha256.prototype._update = function (M) {
      var W = this._w
    
      var a = this._a | 0
      var b = this._b | 0
      var c = this._c | 0
      var d = this._d | 0
      var e = this._e | 0
      var f = this._f | 0
      var g = this._g | 0
      var h = this._h | 0
    
      for (var i = 0; i < 16; ++i) W[i] = M.readInt32BE(i * 4)
      for (; i < 64; ++i) W[i] = (gamma1(W[i - 2]) + W[i - 7] + gamma0(W[i - 15]) + W[i - 16]) | 0
    
      for (var j = 0; j < 64; ++j) {
        var T1 = (h + sigma1(e) + ch(e, f, g) + K[j] + W[j]) | 0
        var T2 = (sigma0(a) + maj(a, b, c)) | 0
    
        h = g
        g = f
        f = e
        e = (d + T1) | 0
        d = c
        c = b
        b = a
        a = (T1 + T2) | 0
      }
    
      this._a = (a + this._a) | 0
      this._b = (b + this._b) | 0
      this._c = (c + this._c) | 0
      this._d = (d + this._d) | 0
      this._e = (e + this._e) | 0
      this._f = (f + this._f) | 0
      this._g = (g + this._g) | 0
      this._h = (h + this._h) | 0
    }
    
    Sha256.prototype._hash = function () {
      var H = Buffer.allocUnsafe(32)
    
      H.writeInt32BE(this._a, 0)
      H.writeInt32BE(this._b, 4)
      H.writeInt32BE(this._c, 8)
      H.writeInt32BE(this._d, 12)
      H.writeInt32BE(this._e, 16)
      H.writeInt32BE(this._f, 20)
      H.writeInt32BE(this._g, 24)
      H.writeInt32BE(this._h, 28)
    
      return H
    }
    
    module.exports = Sha256
    
    },{"./hash":189,"inherits":149,"safe-buffer":187}],195:[function(require,module,exports){
    var inherits = require('inherits')
    var SHA512 = require('./sha512')
    var Hash = require('./hash')
    var Buffer = require('safe-buffer').Buffer
    
    var W = new Array(160)
    
    function Sha384 () {
      this.init()
      this._w = W
    
      Hash.call(this, 128, 112)
    }
    
    inherits(Sha384, SHA512)
    
    Sha384.prototype.init = function () {
      this._ah = 0xcbbb9d5d
      this._bh = 0x629a292a
      this._ch = 0x9159015a
      this._dh = 0x152fecd8
      this._eh = 0x67332667
      this._fh = 0x8eb44a87
      this._gh = 0xdb0c2e0d
      this._hh = 0x47b5481d
    
      this._al = 0xc1059ed8
      this._bl = 0x367cd507
      this._cl = 0x3070dd17
      this._dl = 0xf70e5939
      this._el = 0xffc00b31
      this._fl = 0x68581511
      this._gl = 0x64f98fa7
      this._hl = 0xbefa4fa4
    
      return this
    }
    
    Sha384.prototype._hash = function () {
      var H = Buffer.allocUnsafe(48)
    
      function writeInt64BE (h, l, offset) {
        H.writeInt32BE(h, offset)
        H.writeInt32BE(l, offset + 4)
      }
    
      writeInt64BE(this._ah, this._al, 0)
      writeInt64BE(this._bh, this._bl, 8)
      writeInt64BE(this._ch, this._cl, 16)
      writeInt64BE(this._dh, this._dl, 24)
      writeInt64BE(this._eh, this._el, 32)
      writeInt64BE(this._fh, this._fl, 40)
    
      return H
    }
    
    module.exports = Sha384
    
    },{"./hash":189,"./sha512":196,"inherits":149,"safe-buffer":187}],196:[function(require,module,exports){
    var inherits = require('inherits')
    var Hash = require('./hash')
    var Buffer = require('safe-buffer').Buffer
    
    var K = [
      0x428a2f98, 0xd728ae22, 0x71374491, 0x23ef65cd,
      0xb5c0fbcf, 0xec4d3b2f, 0xe9b5dba5, 0x8189dbbc,
      0x3956c25b, 0xf348b538, 0x59f111f1, 0xb605d019,
      0x923f82a4, 0xaf194f9b, 0xab1c5ed5, 0xda6d8118,
      0xd807aa98, 0xa3030242, 0x12835b01, 0x45706fbe,
      0x243185be, 0x4ee4b28c, 0x550c7dc3, 0xd5ffb4e2,
      0x72be5d74, 0xf27b896f, 0x80deb1fe, 0x3b1696b1,
      0x9bdc06a7, 0x25c71235, 0xc19bf174, 0xcf692694,
      0xe49b69c1, 0x9ef14ad2, 0xefbe4786, 0x384f25e3,
      0x0fc19dc6, 0x8b8cd5b5, 0x240ca1cc, 0x77ac9c65,
      0x2de92c6f, 0x592b0275, 0x4a7484aa, 0x6ea6e483,
      0x5cb0a9dc, 0xbd41fbd4, 0x76f988da, 0x831153b5,
      0x983e5152, 0xee66dfab, 0xa831c66d, 0x2db43210,
      0xb00327c8, 0x98fb213f, 0xbf597fc7, 0xbeef0ee4,
      0xc6e00bf3, 0x3da88fc2, 0xd5a79147, 0x930aa725,
      0x06ca6351, 0xe003826f, 0x14292967, 0x0a0e6e70,
      0x27b70a85, 0x46d22ffc, 0x2e1b2138, 0x5c26c926,
      0x4d2c6dfc, 0x5ac42aed, 0x53380d13, 0x9d95b3df,
      0x650a7354, 0x8baf63de, 0x766a0abb, 0x3c77b2a8,
      0x81c2c92e, 0x47edaee6, 0x92722c85, 0x1482353b,
      0xa2bfe8a1, 0x4cf10364, 0xa81a664b, 0xbc423001,
      0xc24b8b70, 0xd0f89791, 0xc76c51a3, 0x0654be30,
      0xd192e819, 0xd6ef5218, 0xd6990624, 0x5565a910,
      0xf40e3585, 0x5771202a, 0x106aa070, 0x32bbd1b8,
      0x19a4c116, 0xb8d2d0c8, 0x1e376c08, 0x5141ab53,
      0x2748774c, 0xdf8eeb99, 0x34b0bcb5, 0xe19b48a8,
      0x391c0cb3, 0xc5c95a63, 0x4ed8aa4a, 0xe3418acb,
      0x5b9cca4f, 0x7763e373, 0x682e6ff3, 0xd6b2b8a3,
      0x748f82ee, 0x5defb2fc, 0x78a5636f, 0x43172f60,
      0x84c87814, 0xa1f0ab72, 0x8cc70208, 0x1a6439ec,
      0x90befffa, 0x23631e28, 0xa4506ceb, 0xde82bde9,
      0xbef9a3f7, 0xb2c67915, 0xc67178f2, 0xe372532b,
      0xca273ece, 0xea26619c, 0xd186b8c7, 0x21c0c207,
      0xeada7dd6, 0xcde0eb1e, 0xf57d4f7f, 0xee6ed178,
      0x06f067aa, 0x72176fba, 0x0a637dc5, 0xa2c898a6,
      0x113f9804, 0xbef90dae, 0x1b710b35, 0x131c471b,
      0x28db77f5, 0x23047d84, 0x32caab7b, 0x40c72493,
      0x3c9ebe0a, 0x15c9bebc, 0x431d67c4, 0x9c100d4c,
      0x4cc5d4be, 0xcb3e42b6, 0x597f299c, 0xfc657e2a,
      0x5fcb6fab, 0x3ad6faec, 0x6c44198c, 0x4a475817
    ]
    
    var W = new Array(160)
    
    function Sha512 () {
      this.init()
      this._w = W
    
      Hash.call(this, 128, 112)
    }
    
    inherits(Sha512, Hash)
    
    Sha512.prototype.init = function () {
      this._ah = 0x6a09e667
      this._bh = 0xbb67ae85
      this._ch = 0x3c6ef372
      this._dh = 0xa54ff53a
      this._eh = 0x510e527f
      this._fh = 0x9b05688c
      this._gh = 0x1f83d9ab
      this._hh = 0x5be0cd19
    
      this._al = 0xf3bcc908
      this._bl = 0x84caa73b
      this._cl = 0xfe94f82b
      this._dl = 0x5f1d36f1
      this._el = 0xade682d1
      this._fl = 0x2b3e6c1f
      this._gl = 0xfb41bd6b
      this._hl = 0x137e2179
    
      return this
    }
    
    function Ch (x, y, z) {
      return z ^ (x & (y ^ z))
    }
    
    function maj (x, y, z) {
      return (x & y) | (z & (x | y))
    }
    
    function sigma0 (x, xl) {
      return (x >>> 28 | xl << 4) ^ (xl >>> 2 | x << 30) ^ (xl >>> 7 | x << 25)
    }
    
    function sigma1 (x, xl) {
      return (x >>> 14 | xl << 18) ^ (x >>> 18 | xl << 14) ^ (xl >>> 9 | x << 23)
    }
    
    function Gamma0 (x, xl) {
      return (x >>> 1 | xl << 31) ^ (x >>> 8 | xl << 24) ^ (x >>> 7)
    }
    
    function Gamma0l (x, xl) {
      return (x >>> 1 | xl << 31) ^ (x >>> 8 | xl << 24) ^ (x >>> 7 | xl << 25)
    }
    
    function Gamma1 (x, xl) {
      return (x >>> 19 | xl << 13) ^ (xl >>> 29 | x << 3) ^ (x >>> 6)
    }
    
    function Gamma1l (x, xl) {
      return (x >>> 19 | xl << 13) ^ (xl >>> 29 | x << 3) ^ (x >>> 6 | xl << 26)
    }
    
    function getCarry (a, b) {
      return (a >>> 0) < (b >>> 0) ? 1 : 0
    }
    
    Sha512.prototype._update = function (M) {
      var W = this._w
    
      var ah = this._ah | 0
      var bh = this._bh | 0
      var ch = this._ch | 0
      var dh = this._dh | 0
      var eh = this._eh | 0
      var fh = this._fh | 0
      var gh = this._gh | 0
      var hh = this._hh | 0
    
      var al = this._al | 0
      var bl = this._bl | 0
      var cl = this._cl | 0
      var dl = this._dl | 0
      var el = this._el | 0
      var fl = this._fl | 0
      var gl = this._gl | 0
      var hl = this._hl | 0
    
      for (var i = 0; i < 32; i += 2) {
        W[i] = M.readInt32BE(i * 4)
        W[i + 1] = M.readInt32BE(i * 4 + 4)
      }
      for (; i < 160; i += 2) {
        var xh = W[i - 15 * 2]
        var xl = W[i - 15 * 2 + 1]
        var gamma0 = Gamma0(xh, xl)
        var gamma0l = Gamma0l(xl, xh)
    
        xh = W[i - 2 * 2]
        xl = W[i - 2 * 2 + 1]
        var gamma1 = Gamma1(xh, xl)
        var gamma1l = Gamma1l(xl, xh)
    
        // W[i] = gamma0 + W[i - 7] + gamma1 + W[i - 16]
        var Wi7h = W[i - 7 * 2]
        var Wi7l = W[i - 7 * 2 + 1]
    
        var Wi16h = W[i - 16 * 2]
        var Wi16l = W[i - 16 * 2 + 1]
    
        var Wil = (gamma0l + Wi7l) | 0
        var Wih = (gamma0 + Wi7h + getCarry(Wil, gamma0l)) | 0
        Wil = (Wil + gamma1l) | 0
        Wih = (Wih + gamma1 + getCarry(Wil, gamma1l)) | 0
        Wil = (Wil + Wi16l) | 0
        Wih = (Wih + Wi16h + getCarry(Wil, Wi16l)) | 0
    
        W[i] = Wih
        W[i + 1] = Wil
      }
    
      for (var j = 0; j < 160; j += 2) {
        Wih = W[j]
        Wil = W[j + 1]
    
        var majh = maj(ah, bh, ch)
        var majl = maj(al, bl, cl)
    
        var sigma0h = sigma0(ah, al)
        var sigma0l = sigma0(al, ah)
        var sigma1h = sigma1(eh, el)
        var sigma1l = sigma1(el, eh)
    
        // t1 = h + sigma1 + ch + K[j] + W[j]
        var Kih = K[j]
        var Kil = K[j + 1]
    
        var chh = Ch(eh, fh, gh)
        var chl = Ch(el, fl, gl)
    
        var t1l = (hl + sigma1l) | 0
        var t1h = (hh + sigma1h + getCarry(t1l, hl)) | 0
        t1l = (t1l + chl) | 0
        t1h = (t1h + chh + getCarry(t1l, chl)) | 0
        t1l = (t1l + Kil) | 0
        t1h = (t1h + Kih + getCarry(t1l, Kil)) | 0
        t1l = (t1l + Wil) | 0
        t1h = (t1h + Wih + getCarry(t1l, Wil)) | 0
    
        // t2 = sigma0 + maj
        var t2l = (sigma0l + majl) | 0
        var t2h = (sigma0h + majh + getCarry(t2l, sigma0l)) | 0
    
        hh = gh
        hl = gl
        gh = fh
        gl = fl
        fh = eh
        fl = el
        el = (dl + t1l) | 0
        eh = (dh + t1h + getCarry(el, dl)) | 0
        dh = ch
        dl = cl
        ch = bh
        cl = bl
        bh = ah
        bl = al
        al = (t1l + t2l) | 0
        ah = (t1h + t2h + getCarry(al, t1l)) | 0
      }
    
      this._al = (this._al + al) | 0
      this._bl = (this._bl + bl) | 0
      this._cl = (this._cl + cl) | 0
      this._dl = (this._dl + dl) | 0
      this._el = (this._el + el) | 0
      this._fl = (this._fl + fl) | 0
      this._gl = (this._gl + gl) | 0
      this._hl = (this._hl + hl) | 0
    
      this._ah = (this._ah + ah + getCarry(this._al, al)) | 0
      this._bh = (this._bh + bh + getCarry(this._bl, bl)) | 0
      this._ch = (this._ch + ch + getCarry(this._cl, cl)) | 0
      this._dh = (this._dh + dh + getCarry(this._dl, dl)) | 0
      this._eh = (this._eh + eh + getCarry(this._el, el)) | 0
      this._fh = (this._fh + fh + getCarry(this._fl, fl)) | 0
      this._gh = (this._gh + gh + getCarry(this._gl, gl)) | 0
      this._hh = (this._hh + hh + getCarry(this._hl, hl)) | 0
    }
    
    Sha512.prototype._hash = function () {
      var H = Buffer.allocUnsafe(64)
    
      function writeInt64BE (h, l, offset) {
        H.writeInt32BE(h, offset)
        H.writeInt32BE(l, offset + 4)
      }
    
      writeInt64BE(this._ah, this._al, 0)
      writeInt64BE(this._bh, this._bl, 8)
      writeInt64BE(this._ch, this._cl, 16)
      writeInt64BE(this._dh, this._dl, 24)
      writeInt64BE(this._eh, this._el, 32)
      writeInt64BE(this._fh, this._fl, 40)
      writeInt64BE(this._gh, this._gl, 48)
      writeInt64BE(this._hh, this._hl, 56)
    
      return H
    }
    
    module.exports = Sha512
    
    },{"./hash":189,"inherits":149,"safe-buffer":187}],197:[function(require,module,exports){
    // Copyright Joyent, Inc. and other Node contributors.
    //
    // Permission is hereby granted, free of charge, to any person obtaining a
    // copy of this software and associated documentation files (the
    // "Software"), to deal in the Software without restriction, including
    // without limitation the rights to use, copy, modify, merge, publish,
    // distribute, sublicense, and/or sell copies of the Software, and to permit
    // persons to whom the Software is furnished to do so, subject to the
    // following conditions:
    //
    // The above copyright notice and this permission notice shall be included
    // in all copies or substantial portions of the Software.
    //
    // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
    // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
    // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
    // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
    // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
    // USE OR OTHER DEALINGS IN THE SOFTWARE.
    
    module.exports = Stream;
    
    var EE = require('events').EventEmitter;
    var inherits = require('inherits');
    
    inherits(Stream, EE);
    Stream.Readable = require('readable-stream/lib/_stream_readable.js');
    Stream.Writable = require('readable-stream/lib/_stream_writable.js');
    Stream.Duplex = require('readable-stream/lib/_stream_duplex.js');
    Stream.Transform = require('readable-stream/lib/_stream_transform.js');
    Stream.PassThrough = require('readable-stream/lib/_stream_passthrough.js');
    Stream.finished = require('readable-stream/lib/internal/streams/end-of-stream.js')
    Stream.pipeline = require('readable-stream/lib/internal/streams/pipeline.js')
    
    // Backwards-compat with node 0.4.x
    Stream.Stream = Stream;
    
    
    
    // old-style streams.  Note that the pipe method (the only relevant
    // part of this class) is overridden in the Readable class.
    
    function Stream() {
      EE.call(this);
    }
    
    Stream.prototype.pipe = function(dest, options) {
      var source = this;
    
      function ondata(chunk) {
        if (dest.writable) {
          if (false === dest.write(chunk) && source.pause) {
            source.pause();
          }
        }
      }
    
      source.on('data', ondata);
    
      function ondrain() {
        if (source.readable && source.resume) {
          source.resume();
        }
      }
    
      dest.on('drain', ondrain);
    
      // If the 'end' option is not supplied, dest.end() will be called when
      // source gets the 'end' or 'close' events.  Only dest.end() once.
      if (!dest._isStdio && (!options || options.end !== false)) {
        source.on('end', onend);
        source.on('close', onclose);
      }
    
      var didOnEnd = false;
      function onend() {
        if (didOnEnd) return;
        didOnEnd = true;
    
        dest.end();
      }
    
    
      function onclose() {
        if (didOnEnd) return;
        didOnEnd = true;
    
        if (typeof dest.destroy === 'function') dest.destroy();
      }
    
      // don't leave dangling pipes when there are errors.
      function onerror(er) {
        cleanup();
        if (EE.listenerCount(this, 'error') === 0) {
          throw er; // Unhandled stream error in pipe.
        }
      }
    
      source.on('error', onerror);
      dest.on('error', onerror);
    
      // remove all the event listeners that were added.
      function cleanup() {
        source.removeListener('data', ondata);
        dest.removeListener('drain', ondrain);
    
        source.removeListener('end', onend);
        source.removeListener('close', onclose);
    
        source.removeListener('error', onerror);
        dest.removeListener('error', onerror);
    
        source.removeListener('end', cleanup);
        source.removeListener('close', cleanup);
    
        dest.removeListener('close', cleanup);
      }
    
      source.on('end', cleanup);
      source.on('close', cleanup);
    
      dest.on('close', cleanup);
    
      dest.emit('pipe', source);
    
      // Allow for unix-like usage: A.pipe(B).pipe(C)
      return dest;
    };
    
    },{"events":107,"inherits":149,"readable-stream/lib/_stream_duplex.js":199,"readable-stream/lib/_stream_passthrough.js":200,"readable-stream/lib/_stream_readable.js":201,"readable-stream/lib/_stream_transform.js":202,"readable-stream/lib/_stream_writable.js":203,"readable-stream/lib/internal/streams/end-of-stream.js":207,"readable-stream/lib/internal/streams/pipeline.js":209}],198:[function(require,module,exports){
    arguments[4][52][0].apply(exports,arguments)
    },{"dup":52}],199:[function(require,module,exports){
    arguments[4][53][0].apply(exports,arguments)
    },{"./_stream_readable":201,"./_stream_writable":203,"_process":176,"dup":53,"inherits":149}],200:[function(require,module,exports){
    arguments[4][54][0].apply(exports,arguments)
    },{"./_stream_transform":202,"dup":54,"inherits":149}],201:[function(require,module,exports){
    arguments[4][55][0].apply(exports,arguments)
    },{"../errors":198,"./_stream_duplex":199,"./internal/streams/async_iterator":204,"./internal/streams/buffer_list":205,"./internal/streams/destroy":206,"./internal/streams/from":208,"./internal/streams/state":210,"./internal/streams/stream":211,"_process":176,"buffer":68,"dup":55,"events":107,"inherits":149,"string_decoder/":212,"util":24}],202:[function(require,module,exports){
    arguments[4][56][0].apply(exports,arguments)
    },{"../errors":198,"./_stream_duplex":199,"dup":56,"inherits":149}],203:[function(require,module,exports){
    arguments[4][57][0].apply(exports,arguments)
    },{"../errors":198,"./_stream_duplex":199,"./internal/streams/destroy":206,"./internal/streams/state":210,"./internal/streams/stream":211,"_process":176,"buffer":68,"dup":57,"inherits":149,"util-deprecate":213}],204:[function(require,module,exports){
    arguments[4][58][0].apply(exports,arguments)
    },{"./end-of-stream":207,"_process":176,"dup":58}],205:[function(require,module,exports){
    arguments[4][59][0].apply(exports,arguments)
    },{"buffer":68,"dup":59,"util":24}],206:[function(require,module,exports){
    arguments[4][60][0].apply(exports,arguments)
    },{"_process":176,"dup":60}],207:[function(require,module,exports){
    arguments[4][61][0].apply(exports,arguments)
    },{"../../../errors":198,"dup":61}],208:[function(require,module,exports){
    arguments[4][62][0].apply(exports,arguments)
    },{"dup":62}],209:[function(require,module,exports){
    arguments[4][63][0].apply(exports,arguments)
    },{"../../../errors":198,"./end-of-stream":207,"dup":63}],210:[function(require,module,exports){
    arguments[4][64][0].apply(exports,arguments)
    },{"../../../errors":198,"dup":64}],211:[function(require,module,exports){
    arguments[4][65][0].apply(exports,arguments)
    },{"dup":65,"events":107}],212:[function(require,module,exports){
    // Copyright Joyent, Inc. and other Node contributors.
    //
    // Permission is hereby granted, free of charge, to any person obtaining a
    // copy of this software and associated documentation files (the
    // "Software"), to deal in the Software without restriction, including
    // without limitation the rights to use, copy, modify, merge, publish,
    // distribute, sublicense, and/or sell copies of the Software, and to permit
    // persons to whom the Software is furnished to do so, subject to the
    // following conditions:
    //
    // The above copyright notice and this permission notice shall be included
    // in all copies or substantial portions of the Software.
    //
    // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
    // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
    // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
    // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
    // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
    // USE OR OTHER DEALINGS IN THE SOFTWARE.
    
    'use strict';
    
    /*<replacement>*/
    
    var Buffer = require('safe-buffer').Buffer;
    /*</replacement>*/
    
    var isEncoding = Buffer.isEncoding || function (encoding) {
      encoding = '' + encoding;
      switch (encoding && encoding.toLowerCase()) {
        case 'hex':case 'utf8':case 'utf-8':case 'ascii':case 'binary':case 'base64':case 'ucs2':case 'ucs-2':case 'utf16le':case 'utf-16le':case 'raw':
          return true;
        default:
          return false;
      }
    };
    
    function _normalizeEncoding(enc) {
      if (!enc) return 'utf8';
      var retried;
      while (true) {
        switch (enc) {
          case 'utf8':
          case 'utf-8':
            return 'utf8';
          case 'ucs2':
          case 'ucs-2':
          case 'utf16le':
          case 'utf-16le':
            return 'utf16le';
          case 'latin1':
          case 'binary':
            return 'latin1';
          case 'base64':
          case 'ascii':
          case 'hex':
            return enc;
          default:
            if (retried) return; // undefined
            enc = ('' + enc).toLowerCase();
            retried = true;
        }
      }
    };
    
    // Do not cache `Buffer.isEncoding` when checking encoding names as some
    // modules monkey-patch it to support additional encodings
    function normalizeEncoding(enc) {
      var nenc = _normalizeEncoding(enc);
      if (typeof nenc !== 'string' && (Buffer.isEncoding === isEncoding || !isEncoding(enc))) throw new Error('Unknown encoding: ' + enc);
      return nenc || enc;
    }
    
    // StringDecoder provides an interface for efficiently splitting a series of
    // buffers into a series of JS strings without breaking apart multi-byte
    // characters.
    exports.StringDecoder = StringDecoder;
    function StringDecoder(encoding) {
      this.encoding = normalizeEncoding(encoding);
      var nb;
      switch (this.encoding) {
        case 'utf16le':
          this.text = utf16Text;
          this.end = utf16End;
          nb = 4;
          break;
        case 'utf8':
          this.fillLast = utf8FillLast;
          nb = 4;
          break;
        case 'base64':
          this.text = base64Text;
          this.end = base64End;
          nb = 3;
          break;
        default:
          this.write = simpleWrite;
          this.end = simpleEnd;
          return;
      }
      this.lastNeed = 0;
      this.lastTotal = 0;
      this.lastChar = Buffer.allocUnsafe(nb);
    }
    
    StringDecoder.prototype.write = function (buf) {
      if (buf.length === 0) return '';
      var r;
      var i;
      if (this.lastNeed) {
        r = this.fillLast(buf);
        if (r === undefined) return '';
        i = this.lastNeed;
        this.lastNeed = 0;
      } else {
        i = 0;
      }
      if (i < buf.length) return r ? r + this.text(buf, i) : this.text(buf, i);
      return r || '';
    };
    
    StringDecoder.prototype.end = utf8End;
    
    // Returns only complete characters in a Buffer
    StringDecoder.prototype.text = utf8Text;
    
    // Attempts to complete a partial non-UTF-8 character using bytes from a Buffer
    StringDecoder.prototype.fillLast = function (buf) {
      if (this.lastNeed <= buf.length) {
        buf.copy(this.lastChar, this.lastTotal - this.lastNeed, 0, this.lastNeed);
        return this.lastChar.toString(this.encoding, 0, this.lastTotal);
      }
      buf.copy(this.lastChar, this.lastTotal - this.lastNeed, 0, buf.length);
      this.lastNeed -= buf.length;
    };
    
    // Checks the type of a UTF-8 byte, whether it's ASCII, a leading byte, or a
    // continuation byte. If an invalid byte is detected, -2 is returned.
    function utf8CheckByte(byte) {
      if (byte <= 0x7F) return 0;else if (byte >> 5 === 0x06) return 2;else if (byte >> 4 === 0x0E) return 3;else if (byte >> 3 === 0x1E) return 4;
      return byte >> 6 === 0x02 ? -1 : -2;
    }
    
    // Checks at most 3 bytes at the end of a Buffer in order to detect an
    // incomplete multi-byte UTF-8 character. The total number of bytes (2, 3, or 4)
    // needed to complete the UTF-8 character (if applicable) are returned.
    function utf8CheckIncomplete(self, buf, i) {
      var j = buf.length - 1;
      if (j < i) return 0;
      var nb = utf8CheckByte(buf[j]);
      if (nb >= 0) {
        if (nb > 0) self.lastNeed = nb - 1;
        return nb;
      }
      if (--j < i || nb === -2) return 0;
      nb = utf8CheckByte(buf[j]);
      if (nb >= 0) {
        if (nb > 0) self.lastNeed = nb - 2;
        return nb;
      }
      if (--j < i || nb === -2) return 0;
      nb = utf8CheckByte(buf[j]);
      if (nb >= 0) {
        if (nb > 0) {
          if (nb === 2) nb = 0;else self.lastNeed = nb - 3;
        }
        return nb;
      }
      return 0;
    }
    
    // Validates as many continuation bytes for a multi-byte UTF-8 character as
    // needed or are available. If we see a non-continuation byte where we expect
    // one, we "replace" the validated continuation bytes we've seen so far with
    // a single UTF-8 replacement character ('\ufffd'), to match v8's UTF-8 decoding
    // behavior. The continuation byte check is included three times in the case
    // where all of the continuation bytes for a character exist in the same buffer.
    // It is also done this way as a slight performance increase instead of using a
    // loop.
    function utf8CheckExtraBytes(self, buf, p) {
      if ((buf[0] & 0xC0) !== 0x80) {
        self.lastNeed = 0;
        return '\ufffd';
      }
      if (self.lastNeed > 1 && buf.length > 1) {
        if ((buf[1] & 0xC0) !== 0x80) {
          self.lastNeed = 1;
          return '\ufffd';
        }
        if (self.lastNeed > 2 && buf.length > 2) {
          if ((buf[2] & 0xC0) !== 0x80) {
            self.lastNeed = 2;
            return '\ufffd';
          }
        }
      }
    }
    
    // Attempts to complete a multi-byte UTF-8 character using bytes from a Buffer.
    function utf8FillLast(buf) {
      var p = this.lastTotal - this.lastNeed;
      var r = utf8CheckExtraBytes(this, buf, p);
      if (r !== undefined) return r;
      if (this.lastNeed <= buf.length) {
        buf.copy(this.lastChar, p, 0, this.lastNeed);
        return this.lastChar.toString(this.encoding, 0, this.lastTotal);
      }
      buf.copy(this.lastChar, p, 0, buf.length);
      this.lastNeed -= buf.length;
    }
    
    // Returns all complete UTF-8 characters in a Buffer. If the Buffer ended on a
    // partial character, the character's bytes are buffered until the required
    // number of bytes are available.
    function utf8Text(buf, i) {
      var total = utf8CheckIncomplete(this, buf, i);
      if (!this.lastNeed) return buf.toString('utf8', i);
      this.lastTotal = total;
      var end = buf.length - (total - this.lastNeed);
      buf.copy(this.lastChar, 0, end);
      return buf.toString('utf8', i, end);
    }
    
    // For UTF-8, a replacement character is added when ending on a partial
    // character.
    function utf8End(buf) {
      var r = buf && buf.length ? this.write(buf) : '';
      if (this.lastNeed) return r + '\ufffd';
      return r;
    }
    
    // UTF-16LE typically needs two bytes per character, but even if we have an even
    // number of bytes available, we need to check if we end on a leading/high
    // surrogate. In that case, we need to wait for the next two bytes in order to
    // decode the last character properly.
    function utf16Text(buf, i) {
      if ((buf.length - i) % 2 === 0) {
        var r = buf.toString('utf16le', i);
        if (r) {
          var c = r.charCodeAt(r.length - 1);
          if (c >= 0xD800 && c <= 0xDBFF) {
            this.lastNeed = 2;
            this.lastTotal = 4;
            this.lastChar[0] = buf[buf.length - 2];
            this.lastChar[1] = buf[buf.length - 1];
            return r.slice(0, -1);
          }
        }
        return r;
      }
      this.lastNeed = 1;
      this.lastTotal = 2;
      this.lastChar[0] = buf[buf.length - 1];
      return buf.toString('utf16le', i, buf.length - 1);
    }
    
    // For UTF-16LE we do not explicitly append special replacement characters if we
    // end on a partial character, we simply let v8 handle that.
    function utf16End(buf) {
      var r = buf && buf.length ? this.write(buf) : '';
      if (this.lastNeed) {
        var end = this.lastTotal - this.lastNeed;
        return r + this.lastChar.toString('utf16le', 0, end);
      }
      return r;
    }
    
    function base64Text(buf, i) {
      var n = (buf.length - i) % 3;
      if (n === 0) return buf.toString('base64', i);
      this.lastNeed = 3 - n;
      this.lastTotal = 3;
      if (n === 1) {
        this.lastChar[0] = buf[buf.length - 1];
      } else {
        this.lastChar[0] = buf[buf.length - 2];
        this.lastChar[1] = buf[buf.length - 1];
      }
      return buf.toString('base64', i, buf.length - n);
    }
    
    function base64End(buf) {
      var r = buf && buf.length ? this.write(buf) : '';
      if (this.lastNeed) return r + this.lastChar.toString('base64', 0, 3 - this.lastNeed);
      return r;
    }
    
    // Pass bytes on through for single-byte encodings (e.g. ascii, latin1, hex)
    function simpleWrite(buf) {
      return buf.toString(this.encoding);
    }
    
    function simpleEnd(buf) {
      return buf && buf.length ? this.write(buf) : '';
    }
    },{"safe-buffer":187}],213:[function(require,module,exports){
    (function (global){(function (){
    
    /**
     * Module exports.
     */
    
    module.exports = deprecate;
    
    /**
     * Mark that a method should not be used.
     * Returns a modified function which warns once by default.
     *
     * If `localStorage.noDeprecation = true` is set, then it is a no-op.
     *
     * If `localStorage.throwDeprecation = true` is set, then deprecated functions
     * will throw an Error when invoked.
     *
     * If `localStorage.traceDeprecation = true` is set, then deprecated functions
     * will invoke `console.trace()` instead of `console.error()`.
     *
     * @param {Function} fn - the function to deprecate
     * @param {String} msg - the string to print to the console when `fn` is invoked
     * @returns {Function} a new "deprecated" version of `fn`
     * @api public
     */
    
    function deprecate (fn, msg) {
      if (config('noDeprecation')) {
        return fn;
      }
    
      var warned = false;
      function deprecated() {
        if (!warned) {
          if (config('throwDeprecation')) {
            throw new Error(msg);
          } else if (config('traceDeprecation')) {
            console.trace(msg);
          } else {
            console.warn(msg);
          }
          warned = true;
        }
        return fn.apply(this, arguments);
      }
    
      return deprecated;
    }
    
    /**
     * Checks `localStorage` for boolean values for the given `name`.
     *
     * @param {String} name
     * @returns {Boolean}
     * @api private
     */
    
    function config (name) {
      // accessing global.localStorage can trigger a DOMException in sandboxed iframes
      try {
        if (!global.localStorage) return false;
      } catch (_) {
        return false;
      }
      var val = global.localStorage[name];
      if (null == val) return false;
      return String(val).toLowerCase() === 'true';
    }
    
    }).call(this)}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
    },{}],214:[function(require,module,exports){
    arguments[4][18][0].apply(exports,arguments)
    },{"dup":18}],215:[function(require,module,exports){
    // Currently in sync with Node.js lib/internal/util/types.js
    // https://github.com/nodejs/node/commit/112cc7c27551254aa2b17098fb774867f05ed0d9
    
    'use strict';
    
    var isArgumentsObject = require('is-arguments');
    var isGeneratorFunction = require('is-generator-function');
    var whichTypedArray = require('which-typed-array');
    var isTypedArray = require('is-typed-array');
    
    function uncurryThis(f) {
      return f.call.bind(f);
    }
    
    var BigIntSupported = typeof BigInt !== 'undefined';
    var SymbolSupported = typeof Symbol !== 'undefined';
    
    var ObjectToString = uncurryThis(Object.prototype.toString);
    
    var numberValue = uncurryThis(Number.prototype.valueOf);
    var stringValue = uncurryThis(String.prototype.valueOf);
    var booleanValue = uncurryThis(Boolean.prototype.valueOf);
    
    if (BigIntSupported) {
      var bigIntValue = uncurryThis(BigInt.prototype.valueOf);
    }
    
    if (SymbolSupported) {
      var symbolValue = uncurryThis(Symbol.prototype.valueOf);
    }
    
    function checkBoxedPrimitive(value, prototypeValueOf) {
      if (typeof value !== 'object') {
        return false;
      }
      try {
        prototypeValueOf(value);
        return true;
      } catch(e) {
        return false;
      }
    }
    
    exports.isArgumentsObject = isArgumentsObject;
    exports.isGeneratorFunction = isGeneratorFunction;
    exports.isTypedArray = isTypedArray;
    
    // Taken from here and modified for better browser support
    // https://github.com/sindresorhus/p-is-promise/blob/cda35a513bda03f977ad5cde3a079d237e82d7ef/index.js
    function isPromise(input) {
        return (
            (
                typeof Promise !== 'undefined' &&
                input instanceof Promise
            ) ||
            (
                input !== null &&
                typeof input === 'object' &&
                typeof input.then === 'function' &&
                typeof input.catch === 'function'
            )
        );
    }
    exports.isPromise = isPromise;
    
    function isArrayBufferView(value) {
      if (typeof ArrayBuffer !== 'undefined' && ArrayBuffer.isView) {
        return ArrayBuffer.isView(value);
      }
    
      return (
        isTypedArray(value) ||
        isDataView(value)
      );
    }
    exports.isArrayBufferView = isArrayBufferView;
    
    
    function isUint8Array(value) {
      return whichTypedArray(value) === 'Uint8Array';
    }
    exports.isUint8Array = isUint8Array;
    
    function isUint8ClampedArray(value) {
      return whichTypedArray(value) === 'Uint8ClampedArray';
    }
    exports.isUint8ClampedArray = isUint8ClampedArray;
    
    function isUint16Array(value) {
      return whichTypedArray(value) === 'Uint16Array';
    }
    exports.isUint16Array = isUint16Array;
    
    function isUint32Array(value) {
      return whichTypedArray(value) === 'Uint32Array';
    }
    exports.isUint32Array = isUint32Array;
    
    function isInt8Array(value) {
      return whichTypedArray(value) === 'Int8Array';
    }
    exports.isInt8Array = isInt8Array;
    
    function isInt16Array(value) {
      return whichTypedArray(value) === 'Int16Array';
    }
    exports.isInt16Array = isInt16Array;
    
    function isInt32Array(value) {
      return whichTypedArray(value) === 'Int32Array';
    }
    exports.isInt32Array = isInt32Array;
    
    function isFloat32Array(value) {
      return whichTypedArray(value) === 'Float32Array';
    }
    exports.isFloat32Array = isFloat32Array;
    
    function isFloat64Array(value) {
      return whichTypedArray(value) === 'Float64Array';
    }
    exports.isFloat64Array = isFloat64Array;
    
    function isBigInt64Array(value) {
      return whichTypedArray(value) === 'BigInt64Array';
    }
    exports.isBigInt64Array = isBigInt64Array;
    
    function isBigUint64Array(value) {
      return whichTypedArray(value) === 'BigUint64Array';
    }
    exports.isBigUint64Array = isBigUint64Array;
    
    function isMapToString(value) {
      return ObjectToString(value) === '[object Map]';
    }
    isMapToString.working = (
      typeof Map !== 'undefined' &&
      isMapToString(new Map())
    );
    
    function isMap(value) {
      if (typeof Map === 'undefined') {
        return false;
      }
    
      return isMapToString.working
        ? isMapToString(value)
        : value instanceof Map;
    }
    exports.isMap = isMap;
    
    function isSetToString(value) {
      return ObjectToString(value) === '[object Set]';
    }
    isSetToString.working = (
      typeof Set !== 'undefined' &&
      isSetToString(new Set())
    );
    function isSet(value) {
      if (typeof Set === 'undefined') {
        return false;
      }
    
      return isSetToString.working
        ? isSetToString(value)
        : value instanceof Set;
    }
    exports.isSet = isSet;
    
    function isWeakMapToString(value) {
      return ObjectToString(value) === '[object WeakMap]';
    }
    isWeakMapToString.working = (
      typeof WeakMap !== 'undefined' &&
      isWeakMapToString(new WeakMap())
    );
    function isWeakMap(value) {
      if (typeof WeakMap === 'undefined') {
        return false;
      }
    
      return isWeakMapToString.working
        ? isWeakMapToString(value)
        : value instanceof WeakMap;
    }
    exports.isWeakMap = isWeakMap;
    
    function isWeakSetToString(value) {
      return ObjectToString(value) === '[object WeakSet]';
    }
    isWeakSetToString.working = (
      typeof WeakSet !== 'undefined' &&
      isWeakSetToString(new WeakSet())
    );
    function isWeakSet(value) {
      return isWeakSetToString(value);
    }
    exports.isWeakSet = isWeakSet;
    
    function isArrayBufferToString(value) {
      return ObjectToString(value) === '[object ArrayBuffer]';
    }
    isArrayBufferToString.working = (
      typeof ArrayBuffer !== 'undefined' &&
      isArrayBufferToString(new ArrayBuffer())
    );
    function isArrayBuffer(value) {
      if (typeof ArrayBuffer === 'undefined') {
        return false;
      }
    
      return isArrayBufferToString.working
        ? isArrayBufferToString(value)
        : value instanceof ArrayBuffer;
    }
    exports.isArrayBuffer = isArrayBuffer;
    
    function isDataViewToString(value) {
      return ObjectToString(value) === '[object DataView]';
    }
    isDataViewToString.working = (
      typeof ArrayBuffer !== 'undefined' &&
      typeof DataView !== 'undefined' &&
      isDataViewToString(new DataView(new ArrayBuffer(1), 0, 1))
    );
    function isDataView(value) {
      if (typeof DataView === 'undefined') {
        return false;
      }
    
      return isDataViewToString.working
        ? isDataViewToString(value)
        : value instanceof DataView;
    }
    exports.isDataView = isDataView;
    
    // Store a copy of SharedArrayBuffer in case it's deleted elsewhere
    var SharedArrayBufferCopy = typeof SharedArrayBuffer !== 'undefined' ? SharedArrayBuffer : undefined;
    function isSharedArrayBufferToString(value) {
      return ObjectToString(value) === '[object SharedArrayBuffer]';
    }
    function isSharedArrayBuffer(value) {
      if (typeof SharedArrayBufferCopy === 'undefined') {
        return false;
      }
    
      if (typeof isSharedArrayBufferToString.working === 'undefined') {
        isSharedArrayBufferToString.working = isSharedArrayBufferToString(new SharedArrayBufferCopy());
      }
    
      return isSharedArrayBufferToString.working
        ? isSharedArrayBufferToString(value)
        : value instanceof SharedArrayBufferCopy;
    }
    exports.isSharedArrayBuffer = isSharedArrayBuffer;
    
    function isAsyncFunction(value) {
      return ObjectToString(value) === '[object AsyncFunction]';
    }
    exports.isAsyncFunction = isAsyncFunction;
    
    function isMapIterator(value) {
      return ObjectToString(value) === '[object Map Iterator]';
    }
    exports.isMapIterator = isMapIterator;
    
    function isSetIterator(value) {
      return ObjectToString(value) === '[object Set Iterator]';
    }
    exports.isSetIterator = isSetIterator;
    
    function isGeneratorObject(value) {
      return ObjectToString(value) === '[object Generator]';
    }
    exports.isGeneratorObject = isGeneratorObject;
    
    function isWebAssemblyCompiledModule(value) {
      return ObjectToString(value) === '[object WebAssembly.Module]';
    }
    exports.isWebAssemblyCompiledModule = isWebAssemblyCompiledModule;
    
    function isNumberObject(value) {
      return checkBoxedPrimitive(value, numberValue);
    }
    exports.isNumberObject = isNumberObject;
    
    function isStringObject(value) {
      return checkBoxedPrimitive(value, stringValue);
    }
    exports.isStringObject = isStringObject;
    
    function isBooleanObject(value) {
      return checkBoxedPrimitive(value, booleanValue);
    }
    exports.isBooleanObject = isBooleanObject;
    
    function isBigIntObject(value) {
      return BigIntSupported && checkBoxedPrimitive(value, bigIntValue);
    }
    exports.isBigIntObject = isBigIntObject;
    
    function isSymbolObject(value) {
      return SymbolSupported && checkBoxedPrimitive(value, symbolValue);
    }
    exports.isSymbolObject = isSymbolObject;
    
    function isBoxedPrimitive(value) {
      return (
        isNumberObject(value) ||
        isStringObject(value) ||
        isBooleanObject(value) ||
        isBigIntObject(value) ||
        isSymbolObject(value)
      );
    }
    exports.isBoxedPrimitive = isBoxedPrimitive;
    
    function isAnyArrayBuffer(value) {
      return typeof Uint8Array !== 'undefined' && (
        isArrayBuffer(value) ||
        isSharedArrayBuffer(value)
      );
    }
    exports.isAnyArrayBuffer = isAnyArrayBuffer;
    
    ['isProxy', 'isExternal', 'isModuleNamespaceObject'].forEach(function(method) {
      Object.defineProperty(exports, method, {
        enumerable: false,
        value: function() {
          throw new Error(method + ' is not supported in userland');
        }
      });
    });
    
    },{"is-arguments":150,"is-generator-function":153,"is-typed-array":154,"which-typed-array":217}],216:[function(require,module,exports){
    (function (process){(function (){
    // Copyright Joyent, Inc. and other Node contributors.
    //
    // Permission is hereby granted, free of charge, to any person obtaining a
    // copy of this software and associated documentation files (the
    // "Software"), to deal in the Software without restriction, including
    // without limitation the rights to use, copy, modify, merge, publish,
    // distribute, sublicense, and/or sell copies of the Software, and to permit
    // persons to whom the Software is furnished to do so, subject to the
    // following conditions:
    //
    // The above copyright notice and this permission notice shall be included
    // in all copies or substantial portions of the Software.
    //
    // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
    // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
    // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
    // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
    // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
    // USE OR OTHER DEALINGS IN THE SOFTWARE.
    
    var getOwnPropertyDescriptors = Object.getOwnPropertyDescriptors ||
      function getOwnPropertyDescriptors(obj) {
        var keys = Object.keys(obj);
        var descriptors = {};
        for (var i = 0; i < keys.length; i++) {
          descriptors[keys[i]] = Object.getOwnPropertyDescriptor(obj, keys[i]);
        }
        return descriptors;
      };
    
    var formatRegExp = /%[sdj%]/g;
    exports.format = function(f) {
      if (!isString(f)) {
        var objects = [];
        for (var i = 0; i < arguments.length; i++) {
          objects.push(inspect(arguments[i]));
        }
        return objects.join(' ');
      }
    
      var i = 1;
      var args = arguments;
      var len = args.length;
      var str = String(f).replace(formatRegExp, function(x) {
        if (x === '%%') return '%';
        if (i >= len) return x;
        switch (x) {
          case '%s': return String(args[i++]);
          case '%d': return Number(args[i++]);
          case '%j':
            try {
              return JSON.stringify(args[i++]);
            } catch (_) {
              return '[Circular]';
            }
          default:
            return x;
        }
      });
      for (var x = args[i]; i < len; x = args[++i]) {
        if (isNull(x) || !isObject(x)) {
          str += ' ' + x;
        } else {
          str += ' ' + inspect(x);
        }
      }
      return str;
    };
    
    
    // Mark that a method should not be used.
    // Returns a modified function which warns once by default.
    // If --no-deprecation is set, then it is a no-op.
    exports.deprecate = function(fn, msg) {
      if (typeof process !== 'undefined' && process.noDeprecation === true) {
        return fn;
      }
    
      // Allow for deprecating things in the process of starting up.
      if (typeof process === 'undefined') {
        return function() {
          return exports.deprecate(fn, msg).apply(this, arguments);
        };
      }
    
      var warned = false;
      function deprecated() {
        if (!warned) {
          if (process.throwDeprecation) {
            throw new Error(msg);
          } else if (process.traceDeprecation) {
            console.trace(msg);
          } else {
            console.error(msg);
          }
          warned = true;
        }
        return fn.apply(this, arguments);
      }
    
      return deprecated;
    };
    
    
    var debugs = {};
    var debugEnvRegex = /^$/;
    
    if (process.env.NODE_DEBUG) {
      var debugEnv = process.env.NODE_DEBUG;
      debugEnv = debugEnv.replace(/[|\\{}()[\]^$+?.]/g, '\\$&')
        .replace(/\*/g, '.*')
        .replace(/,/g, '$|^')
        .toUpperCase();
      debugEnvRegex = new RegExp('^' + debugEnv + '$', 'i');
    }
    exports.debuglog = function(set) {
      set = set.toUpperCase();
      if (!debugs[set]) {
        if (debugEnvRegex.test(set)) {
          var pid = process.pid;
          debugs[set] = function() {
            var msg = exports.format.apply(exports, arguments);
            console.error('%s %d: %s', set, pid, msg);
          };
        } else {
          debugs[set] = function() {};
        }
      }
      return debugs[set];
    };
    
    
    /**
     * Echos the value of a value. Trys to print the value out
     * in the best way possible given the different types.
     *
     * @param {Object} obj The object to print out.
     * @param {Object} opts Optional options object that alters the output.
     */
    /* legacy: obj, showHidden, depth, colors*/
    function inspect(obj, opts) {
      // default options
      var ctx = {
        seen: [],
        stylize: stylizeNoColor
      };
      // legacy...
      if (arguments.length >= 3) ctx.depth = arguments[2];
      if (arguments.length >= 4) ctx.colors = arguments[3];
      if (isBoolean(opts)) {
        // legacy...
        ctx.showHidden = opts;
      } else if (opts) {
        // got an "options" object
        exports._extend(ctx, opts);
      }
      // set default options
      if (isUndefined(ctx.showHidden)) ctx.showHidden = false;
      if (isUndefined(ctx.depth)) ctx.depth = 2;
      if (isUndefined(ctx.colors)) ctx.colors = false;
      if (isUndefined(ctx.customInspect)) ctx.customInspect = true;
      if (ctx.colors) ctx.stylize = stylizeWithColor;
      return formatValue(ctx, obj, ctx.depth);
    }
    exports.inspect = inspect;
    
    
    // http://en.wikipedia.org/wiki/ANSI_escape_code#graphics
    inspect.colors = {
      'bold' : [1, 22],
      'italic' : [3, 23],
      'underline' : [4, 24],
      'inverse' : [7, 27],
      'white' : [37, 39],
      'grey' : [90, 39],
      'black' : [30, 39],
      'blue' : [34, 39],
      'cyan' : [36, 39],
      'green' : [32, 39],
      'magenta' : [35, 39],
      'red' : [31, 39],
      'yellow' : [33, 39]
    };
    
    // Don't use 'blue' not visible on cmd.exe
    inspect.styles = {
      'special': 'cyan',
      'number': 'yellow',
      'boolean': 'yellow',
      'undefined': 'grey',
      'null': 'bold',
      'string': 'green',
      'date': 'magenta',
      // "name": intentionally not styling
      'regexp': 'red'
    };
    
    
    function stylizeWithColor(str, styleType) {
      var style = inspect.styles[styleType];
    
      if (style) {
        return '\u001b[' + inspect.colors[style][0] + 'm' + str +
               '\u001b[' + inspect.colors[style][1] + 'm';
      } else {
        return str;
      }
    }
    
    
    function stylizeNoColor(str, styleType) {
      return str;
    }
    
    
    function arrayToHash(array) {
      var hash = {};
    
      array.forEach(function(val, idx) {
        hash[val] = true;
      });
    
      return hash;
    }
    
    
    function formatValue(ctx, value, recurseTimes) {
      // Provide a hook for user-specified inspect functions.
      // Check that value is an object with an inspect function on it
      if (ctx.customInspect &&
          value &&
          isFunction(value.inspect) &&
          // Filter out the util module, it's inspect function is special
          value.inspect !== exports.inspect &&
          // Also filter out any prototype objects using the circular check.
          !(value.constructor && value.constructor.prototype === value)) {
        var ret = value.inspect(recurseTimes, ctx);
        if (!isString(ret)) {
          ret = formatValue(ctx, ret, recurseTimes);
        }
        return ret;
      }
    
      // Primitive types cannot have properties
      var primitive = formatPrimitive(ctx, value);
      if (primitive) {
        return primitive;
      }
    
      // Look up the keys of the object.
      var keys = Object.keys(value);
      var visibleKeys = arrayToHash(keys);
    
      if (ctx.showHidden) {
        keys = Object.getOwnPropertyNames(value);
      }
    
      // IE doesn't make error fields non-enumerable
      // http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx
      if (isError(value)
          && (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)) {
        return formatError(value);
      }
    
      // Some type of object without properties can be shortcutted.
      if (keys.length === 0) {
        if (isFunction(value)) {
          var name = value.name ? ': ' + value.name : '';
          return ctx.stylize('[Function' + name + ']', 'special');
        }
        if (isRegExp(value)) {
          return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
        }
        if (isDate(value)) {
          return ctx.stylize(Date.prototype.toString.call(value), 'date');
        }
        if (isError(value)) {
          return formatError(value);
        }
      }
    
      var base = '', array = false, braces = ['{', '}'];
    
      // Make Array say that they are Array
      if (isArray(value)) {
        array = true;
        braces = ['[', ']'];
      }
    
      // Make functions say that they are functions
      if (isFunction(value)) {
        var n = value.name ? ': ' + value.name : '';
        base = ' [Function' + n + ']';
      }
    
      // Make RegExps say that they are RegExps
      if (isRegExp(value)) {
        base = ' ' + RegExp.prototype.toString.call(value);
      }
    
      // Make dates with properties first say the date
      if (isDate(value)) {
        base = ' ' + Date.prototype.toUTCString.call(value);
      }
    
      // Make error with message first say the error
      if (isError(value)) {
        base = ' ' + formatError(value);
      }
    
      if (keys.length === 0 && (!array || value.length == 0)) {
        return braces[0] + base + braces[1];
      }
    
      if (recurseTimes < 0) {
        if (isRegExp(value)) {
          return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
        } else {
          return ctx.stylize('[Object]', 'special');
        }
      }
    
      ctx.seen.push(value);
    
      var output;
      if (array) {
        output = formatArray(ctx, value, recurseTimes, visibleKeys, keys);
      } else {
        output = keys.map(function(key) {
          return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array);
        });
      }
    
      ctx.seen.pop();
    
      return reduceToSingleString(output, base, braces);
    }
    
    
    function formatPrimitive(ctx, value) {
      if (isUndefined(value))
        return ctx.stylize('undefined', 'undefined');
      if (isString(value)) {
        var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '')
                                                 .replace(/'/g, "\\'")
                                                 .replace(/\\"/g, '"') + '\'';
        return ctx.stylize(simple, 'string');
      }
      if (isNumber(value))
        return ctx.stylize('' + value, 'number');
      if (isBoolean(value))
        return ctx.stylize('' + value, 'boolean');
      // For some reason typeof null is "object", so special case here.
      if (isNull(value))
        return ctx.stylize('null', 'null');
    }
    
    
    function formatError(value) {
      return '[' + Error.prototype.toString.call(value) + ']';
    }
    
    
    function formatArray(ctx, value, recurseTimes, visibleKeys, keys) {
      var output = [];
      for (var i = 0, l = value.length; i < l; ++i) {
        if (hasOwnProperty(value, String(i))) {
          output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
              String(i), true));
        } else {
          output.push('');
        }
      }
      keys.forEach(function(key) {
        if (!key.match(/^\d+$/)) {
          output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
              key, true));
        }
      });
      return output;
    }
    
    
    function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) {
      var name, str, desc;
      desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] };
      if (desc.get) {
        if (desc.set) {
          str = ctx.stylize('[Getter/Setter]', 'special');
        } else {
          str = ctx.stylize('[Getter]', 'special');
        }
      } else {
        if (desc.set) {
          str = ctx.stylize('[Setter]', 'special');
        }
      }
      if (!hasOwnProperty(visibleKeys, key)) {
        name = '[' + key + ']';
      }
      if (!str) {
        if (ctx.seen.indexOf(desc.value) < 0) {
          if (isNull(recurseTimes)) {
            str = formatValue(ctx, desc.value, null);
          } else {
            str = formatValue(ctx, desc.value, recurseTimes - 1);
          }
          if (str.indexOf('\n') > -1) {
            if (array) {
              str = str.split('\n').map(function(line) {
                return '  ' + line;
              }).join('\n').slice(2);
            } else {
              str = '\n' + str.split('\n').map(function(line) {
                return '   ' + line;
              }).join('\n');
            }
          }
        } else {
          str = ctx.stylize('[Circular]', 'special');
        }
      }
      if (isUndefined(name)) {
        if (array && key.match(/^\d+$/)) {
          return str;
        }
        name = JSON.stringify('' + key);
        if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) {
          name = name.slice(1, -1);
          name = ctx.stylize(name, 'name');
        } else {
          name = name.replace(/'/g, "\\'")
                     .replace(/\\"/g, '"')
                     .replace(/(^"|"$)/g, "'");
          name = ctx.stylize(name, 'string');
        }
      }
    
      return name + ': ' + str;
    }
    
    
    function reduceToSingleString(output, base, braces) {
      var numLinesEst = 0;
      var length = output.reduce(function(prev, cur) {
        numLinesEst++;
        if (cur.indexOf('\n') >= 0) numLinesEst++;
        return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1;
      }, 0);
    
      if (length > 60) {
        return braces[0] +
               (base === '' ? '' : base + '\n ') +
               ' ' +
               output.join(',\n  ') +
               ' ' +
               braces[1];
      }
    
      return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1];
    }
    
    
    // NOTE: These type checking functions intentionally don't use `instanceof`
    // because it is fragile and can be easily faked with `Object.create()`.
    exports.types = require('./support/types');
    
    function isArray(ar) {
      return Array.isArray(ar);
    }
    exports.isArray = isArray;
    
    function isBoolean(arg) {
      return typeof arg === 'boolean';
    }
    exports.isBoolean = isBoolean;
    
    function isNull(arg) {
      return arg === null;
    }
    exports.isNull = isNull;
    
    function isNullOrUndefined(arg) {
      return arg == null;
    }
    exports.isNullOrUndefined = isNullOrUndefined;
    
    function isNumber(arg) {
      return typeof arg === 'number';
    }
    exports.isNumber = isNumber;
    
    function isString(arg) {
      return typeof arg === 'string';
    }
    exports.isString = isString;
    
    function isSymbol(arg) {
      return typeof arg === 'symbol';
    }
    exports.isSymbol = isSymbol;
    
    function isUndefined(arg) {
      return arg === void 0;
    }
    exports.isUndefined = isUndefined;
    
    function isRegExp(re) {
      return isObject(re) && objectToString(re) === '[object RegExp]';
    }
    exports.isRegExp = isRegExp;
    exports.types.isRegExp = isRegExp;
    
    function isObject(arg) {
      return typeof arg === 'object' && arg !== null;
    }
    exports.isObject = isObject;
    
    function isDate(d) {
      return isObject(d) && objectToString(d) === '[object Date]';
    }
    exports.isDate = isDate;
    exports.types.isDate = isDate;
    
    function isError(e) {
      return isObject(e) &&
          (objectToString(e) === '[object Error]' || e instanceof Error);
    }
    exports.isError = isError;
    exports.types.isNativeError = isError;
    
    function isFunction(arg) {
      return typeof arg === 'function';
    }
    exports.isFunction = isFunction;
    
    function isPrimitive(arg) {
      return arg === null ||
             typeof arg === 'boolean' ||
             typeof arg === 'number' ||
             typeof arg === 'string' ||
             typeof arg === 'symbol' ||  // ES6 symbol
             typeof arg === 'undefined';
    }
    exports.isPrimitive = isPrimitive;
    
    exports.isBuffer = require('./support/isBuffer');
    
    function objectToString(o) {
      return Object.prototype.toString.call(o);
    }
    
    
    function pad(n) {
      return n < 10 ? '0' + n.toString(10) : n.toString(10);
    }
    
    
    var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep',
                  'Oct', 'Nov', 'Dec'];
    
    // 26 Feb 16:19:34
    function timestamp() {
      var d = new Date();
      var time = [pad(d.getHours()),
                  pad(d.getMinutes()),
                  pad(d.getSeconds())].join(':');
      return [d.getDate(), months[d.getMonth()], time].join(' ');
    }
    
    
    // log is just a thin wrapper to console.log that prepends a timestamp
    exports.log = function() {
      console.log('%s - %s', timestamp(), exports.format.apply(exports, arguments));
    };
    
    
    /**
     * Inherit the prototype methods from one constructor into another.
     *
     * The Function.prototype.inherits from lang.js rewritten as a standalone
     * function (not on Function.prototype). NOTE: If this file is to be loaded
     * during bootstrapping this function needs to be rewritten using some native
     * functions as prototype setup using normal JavaScript does not work as
     * expected during bootstrapping (see mirror.js in r114903).
     *
     * @param {function} ctor Constructor function which needs to inherit the
     *     prototype.
     * @param {function} superCtor Constructor function to inherit prototype from.
     */
    exports.inherits = require('inherits');
    
    exports._extend = function(origin, add) {
      // Don't do anything if add isn't an object
      if (!add || !isObject(add)) return origin;
    
      var keys = Object.keys(add);
      var i = keys.length;
      while (i--) {
        origin[keys[i]] = add[keys[i]];
      }
      return origin;
    };
    
    function hasOwnProperty(obj, prop) {
      return Object.prototype.hasOwnProperty.call(obj, prop);
    }
    
    var kCustomPromisifiedSymbol = typeof Symbol !== 'undefined' ? Symbol('util.promisify.custom') : undefined;
    
    exports.promisify = function promisify(original) {
      if (typeof original !== 'function')
        throw new TypeError('The "original" argument must be of type Function');
    
      if (kCustomPromisifiedSymbol && original[kCustomPromisifiedSymbol]) {
        var fn = original[kCustomPromisifiedSymbol];
        if (typeof fn !== 'function') {
          throw new TypeError('The "util.promisify.custom" argument must be of type Function');
        }
        Object.defineProperty(fn, kCustomPromisifiedSymbol, {
          value: fn, enumerable: false, writable: false, configurable: true
        });
        return fn;
      }
    
      function fn() {
        var promiseResolve, promiseReject;
        var promise = new Promise(function (resolve, reject) {
          promiseResolve = resolve;
          promiseReject = reject;
        });
    
        var args = [];
        for (var i = 0; i < arguments.length; i++) {
          args.push(arguments[i]);
        }
        args.push(function (err, value) {
          if (err) {
            promiseReject(err);
          } else {
            promiseResolve(value);
          }
        });
    
        try {
          original.apply(this, args);
        } catch (err) {
          promiseReject(err);
        }
    
        return promise;
      }
    
      Object.setPrototypeOf(fn, Object.getPrototypeOf(original));
    
      if (kCustomPromisifiedSymbol) Object.defineProperty(fn, kCustomPromisifiedSymbol, {
        value: fn, enumerable: false, writable: false, configurable: true
      });
      return Object.defineProperties(
        fn,
        getOwnPropertyDescriptors(original)
      );
    }
    
    exports.promisify.custom = kCustomPromisifiedSymbol
    
    function callbackifyOnRejected(reason, cb) {
      // `!reason` guard inspired by bluebird (Ref: https://goo.gl/t5IS6M).
      // Because `null` is a special error value in callbacks which means "no error
      // occurred", we error-wrap so the callback consumer can distinguish between
      // "the promise rejected with null" or "the promise fulfilled with undefined".
      if (!reason) {
        var newReason = new Error('Promise was rejected with a falsy value');
        newReason.reason = reason;
        reason = newReason;
      }
      return cb(reason);
    }
    
    function callbackify(original) {
      if (typeof original !== 'function') {
        throw new TypeError('The "original" argument must be of type Function');
      }
    
      // We DO NOT return the promise as it gives the user a false sense that
      // the promise is actually somehow related to the callback's execution
      // and that the callback throwing will reject the promise.
      function callbackified() {
        var args = [];
        for (var i = 0; i < arguments.length; i++) {
          args.push(arguments[i]);
        }
    
        var maybeCb = args.pop();
        if (typeof maybeCb !== 'function') {
          throw new TypeError('The last argument must be of type Function');
        }
        var self = this;
        var cb = function() {
          return maybeCb.apply(self, arguments);
        };
        // In true node style we process the callback on `nextTick` with all the
        // implications (stack, `uncaughtException`, `async_hooks`)
        original.apply(this, args)
          .then(function(ret) { process.nextTick(cb.bind(null, null, ret)) },
                function(rej) { process.nextTick(callbackifyOnRejected.bind(null, rej, cb)) });
      }
    
      Object.setPrototypeOf(callbackified, Object.getPrototypeOf(original));
      Object.defineProperties(callbackified,
                              getOwnPropertyDescriptors(original));
      return callbackified;
    }
    exports.callbackify = callbackify;
    
    }).call(this)}).call(this,require('_process'))
    },{"./support/isBuffer":214,"./support/types":215,"_process":176,"inherits":149}],217:[function(require,module,exports){
    (function (global){(function (){
    'use strict';
    
    var forEach = require('for-each');
    var availableTypedArrays = require('available-typed-arrays');
    var callBind = require('call-bind');
    var callBound = require('call-bind/callBound');
    var gOPD = require('gopd');
    
    var $toString = callBound('Object.prototype.toString');
    var hasToStringTag = require('has-tostringtag/shams')();
    
    var g = typeof globalThis === 'undefined' ? global : globalThis;
    var typedArrays = availableTypedArrays();
    
    var $slice = callBound('String.prototype.slice');
    var getPrototypeOf = Object.getPrototypeOf; // require('getprototypeof');
    
    var $indexOf = callBound('Array.prototype.indexOf', true) || function indexOf(array, value) {
        for (var i = 0; i < array.length; i += 1) {
            if (array[i] === value) {
                return i;
            }
        }
        return -1;
    };
    var cache = { __proto__: null };
    if (hasToStringTag && gOPD && getPrototypeOf) {
        forEach(typedArrays, function (typedArray) {
            var arr = new g[typedArray]();
            if (Symbol.toStringTag in arr) {
                var proto = getPrototypeOf(arr);
                var descriptor = gOPD(proto, Symbol.toStringTag);
                if (!descriptor) {
                    var superProto = getPrototypeOf(proto);
                    descriptor = gOPD(superProto, Symbol.toStringTag);
                }
                cache['$' + typedArray] = callBind(descriptor.get);
            }
        });
    } else {
        forEach(typedArrays, function (typedArray) {
            var arr = new g[typedArray]();
            cache['$' + typedArray] = callBind(arr.slice);
        });
    }
    
    var tryTypedArrays = function tryAllTypedArrays(value) {
        var found = false;
        forEach(cache, function (getter, typedArray) {
            if (!found) {
                try {
                    if ('$' + getter(value) === typedArray) {
                        found = $slice(typedArray, 1);
                    }
                } catch (e) { /**/ }
            }
        });
        return found;
    };
    
    var trySlices = function tryAllSlices(value) {
        var found = false;
        forEach(cache, function (getter, name) {
            if (!found) {
                try {
                    getter(value);
                    found = $slice(name, 1);
                } catch (e) { /**/ }
            }
        });
        return found;
    };
    
    module.exports = function whichTypedArray(value) {
        if (!value || typeof value !== 'object') { return false; }
        if (!hasToStringTag) {
            var tag = $slice($toString(value), 8, -1);
            if ($indexOf(typedArrays, tag) > -1) {
                return tag;
            }
            if (tag !== 'Object') {
                return false;
            }
            // node < 0.6 hits here on real Typed Arrays
            return trySlices(value);
        }
        if (!gOPD) { return null; } // unknown engine
        return tryTypedArrays(value);
    };
    
    }).call(this)}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
    },{"available-typed-arrays":20,"call-bind":70,"call-bind/callBound":69,"for-each":109,"gopd":113,"has-tostringtag/shams":117}],218:[function(require,module,exports){
    var WindowsAzure = require('azure-mobile-apps-client');
    // Create a reference to the Azure App Service
    client = new WindowsAzure.MobileServiceClient('https://grab-taxi-stg.azurewebsites.net/');
    },{"azure-mobile-apps-client":247}],219:[function(require,module,exports){
    (function (Buffer,process){(function (){
    // Copyright (c) 2012, Mark Cavage. All rights reserved.
    // Copyright 2015 Joyent, Inc.
    
    var assert = require('assert');
    var Stream = require('stream').Stream;
    var util = require('util');
    
    
    ///--- Globals
    
    /* JSSTYLED */
    var UUID_REGEXP = /^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$/;
    
    
    ///--- Internal
    
    function _capitalize(str) {
        return (str.charAt(0).toUpperCase() + str.slice(1));
    }
    
    function _toss(name, expected, oper, arg, actual) {
        throw new assert.AssertionError({
            message: util.format('%s (%s) is required', name, expected),
            actual: (actual === undefined) ? typeof (arg) : actual(arg),
            expected: expected,
            operator: oper || '===',
            stackStartFunction: _toss.caller
        });
    }
    
    function _getClass(arg) {
        return (Object.prototype.toString.call(arg).slice(8, -1));
    }
    
    function noop() {
        // Why even bother with asserts?
    }
    
    
    ///--- Exports
    
    var types = {
        bool: {
            check: function (arg) { return typeof (arg) === 'boolean'; }
        },
        func: {
            check: function (arg) { return typeof (arg) === 'function'; }
        },
        string: {
            check: function (arg) { return typeof (arg) === 'string'; }
        },
        object: {
            check: function (arg) {
                return typeof (arg) === 'object' && arg !== null;
            }
        },
        number: {
            check: function (arg) {
                return typeof (arg) === 'number' && !isNaN(arg);
            }
        },
        finite: {
            check: function (arg) {
                return typeof (arg) === 'number' && !isNaN(arg) && isFinite(arg);
            }
        },
        buffer: {
            check: function (arg) { return Buffer.isBuffer(arg); },
            operator: 'Buffer.isBuffer'
        },
        array: {
            check: function (arg) { return Array.isArray(arg); },
            operator: 'Array.isArray'
        },
        stream: {
            check: function (arg) { return arg instanceof Stream; },
            operator: 'instanceof',
            actual: _getClass
        },
        date: {
            check: function (arg) { return arg instanceof Date; },
            operator: 'instanceof',
            actual: _getClass
        },
        regexp: {
            check: function (arg) { return arg instanceof RegExp; },
            operator: 'instanceof',
            actual: _getClass
        },
        uuid: {
            check: function (arg) {
                return typeof (arg) === 'string' && UUID_REGEXP.test(arg);
            },
            operator: 'isUUID'
        }
    };
    
    function _setExports(ndebug) {
        var keys = Object.keys(types);
        var out;
    
        /* re-export standard assert */
        if (process.env.NODE_NDEBUG) {
            out = noop;
        } else {
            out = function (arg, msg) {
                if (!arg) {
                    _toss(msg, 'true', arg);
                }
            };
        }
    
        /* standard checks */
        keys.forEach(function (k) {
            if (ndebug) {
                out[k] = noop;
                return;
            }
            var type = types[k];
            out[k] = function (arg, msg) {
                if (!type.check(arg)) {
                    _toss(msg, k, type.operator, arg, type.actual);
                }
            };
        });
    
        /* optional checks */
        keys.forEach(function (k) {
            var name = 'optional' + _capitalize(k);
            if (ndebug) {
                out[name] = noop;
                return;
            }
            var type = types[k];
            out[name] = function (arg, msg) {
                if (arg === undefined || arg === null) {
                    return;
                }
                if (!type.check(arg)) {
                    _toss(msg, k, type.operator, arg, type.actual);
                }
            };
        });
    
        /* arrayOf checks */
        keys.forEach(function (k) {
            var name = 'arrayOf' + _capitalize(k);
            if (ndebug) {
                out[name] = noop;
                return;
            }
            var type = types[k];
            var expected = '[' + k + ']';
            out[name] = function (arg, msg) {
                if (!Array.isArray(arg)) {
                    _toss(msg, expected, type.operator, arg, type.actual);
                }
                var i;
                for (i = 0; i < arg.length; i++) {
                    if (!type.check(arg[i])) {
                        _toss(msg, expected, type.operator, arg, type.actual);
                    }
                }
            };
        });
    
        /* optionalArrayOf checks */
        keys.forEach(function (k) {
            var name = 'optionalArrayOf' + _capitalize(k);
            if (ndebug) {
                out[name] = noop;
                return;
            }
            var type = types[k];
            var expected = '[' + k + ']';
            out[name] = function (arg, msg) {
                if (arg === undefined || arg === null) {
                    return;
                }
                if (!Array.isArray(arg)) {
                    _toss(msg, expected, type.operator, arg, type.actual);
                }
                var i;
                for (i = 0; i < arg.length; i++) {
                    if (!type.check(arg[i])) {
                        _toss(msg, expected, type.operator, arg, type.actual);
                    }
                }
            };
        });
    
        /* re-export built-in assertions */
        Object.keys(assert).forEach(function (k) {
            if (k === 'AssertionError') {
                out[k] = assert[k];
                return;
            }
            if (ndebug) {
                out[k] = noop;
                return;
            }
            out[k] = assert[k];
        });
    
        /* export ourselves (for unit tests _only_) */
        out._setExports = _setExports;
    
        return out;
    }
    
    module.exports = _setExports(process.env.NODE_NDEBUG);
    
    }).call(this)}).call(this,{"isBuffer":require("../../AppData/Roaming/npm/node_modules/browserify/node_modules/is-buffer/index.js")},require('_process'))
    },{"../../AppData/Roaming/npm/node_modules/browserify/node_modules/is-buffer/index.js":151,"_process":176,"assert":16,"stream":197,"util":216}],220:[function(require,module,exports){
    module.exports={
      "name": "azure-mobile-apps-client",
      "description": "Javascript SDK for connecting to Azure Mobile Apps. For more details visit https://azure.microsoft.com/en-us/documentation/learning-paths/appservice-mobileapps/",
      "version": "2.0.1",
      "devDependencies": {
        "browserify": "~11.1.0",
        "browserify-derequire": "~0.9.4",
        "es6-promise": "^3.1.2",
        "fs-sync": "~1.0.2",
        "grunt": "~0.4.5",
        "grunt-browserify": "~4.0.1",
        "grunt-cli": "^0.1.13",
        "grunt-contrib-copy": "~0.8.2",
        "grunt-contrib-jshint": "^1.0.0",
        "grunt-contrib-nodeunit": "~0.4.1",
        "grunt-contrib-uglify": "~0.6.0",
        "grunt-contrib-watch": "~0.6.1",
        "grunt-exec": "~0.4.6",
        "grunt-multi-dest": "^1.0.0",
        "http-server": "^0.9.0",
        "jsdoc": "^3.4.1",
        "minami": "^1.1.1",
        "package-json-versionify": "^1.0.2",
        "qunitjs": "^1.23.1",
        "request": "^2.69.0",
        "rimraf": "^2.5.2",
        "wd": "^0.4.0"
      },
      "author": "Microsoft",
      "homepage": "https://azure.microsoft.com/en-us/documentation/learning-paths/appservice-mobileapps/",
      "license": "Apache-2.0",
      "main": "sdk/src/index.js",
      "repository": {
        "type": "git",
        "url": "https://github.com/azure/azure-mobile-apps-js-client.git"
      },
      "scripts": {
        "build": "grunt build",
        "buildall": "grunt build",
        "buildbrowser": "grunt buildbrowsermin",
        "buildcordova": "grunt buildcordovamin",
        "jsdoc": "jsdoc -c jsdoc/config.json",
        "watch": "grunt watch:all",
        "watchall": "grunt watch:all",
        "watchbrowser": "grunt watch:web",
        "watchcordova": "grunt watch:cordova",
        "browserut": "http-server sdk/test/app/browser/ -p 8081 -o http://localhost:8081/index.html -c-1",
        "hostandroidut": "http-server sdk/test/app/cordova/platforms/android/assets/www/ -p 8080 -c-1",
        "e2esetup": "grunt e2esetup"
      },
      "dependencies": {
        "azure-odata-sql": "^0.2.0",
        "azure-query-js": "^0.1.0",
        "node-uuid": "^1.4.7",
        "verror": "^1.8.1"
      },
      "keywords": [
        "microsoft",
        "azure",
        "mobile",
        "windowsazureofficial",
        "app",
        "service",
        "api",
        "apps"
      ]
    }
    
    },{}],221:[function(require,module,exports){
    // ----------------------------------------------------------------------------
    // Copyright (c) Microsoft Corporation. All rights reserved.
    // ----------------------------------------------------------------------------
    
    var PostMessageExchange = require('../Utilities/PostMessageExchange');
    
    exports.supportsCurrentRuntime = function () {
        /// <summary>
        /// Determines whether or not this login UI is usable in the current runtime.
        /// </summary>
        return true;
    };
    
    exports.login = function (startUri, endUri, callback) {
        /// <summary>
        /// Displays the login UI and calls back on completion
        /// </summary>
    
        // Tell the runtime which form of completion signal we are looking for,
        // and which origin should be allowed to receive the result (note that this
        // is validated against whitelist on the server; we are only supplying this
        // origin to indicate *which* of the whitelisted origins to use).
        var completionOrigin = PostMessageExchange.getOriginRoot(window.location.href),
            runtimeOrigin = PostMessageExchange.getOriginRoot(startUri),
            // IE does not support popup->opener postMessage calls, so we have to
            // route the message via an iframe
            useIntermediateIframe = window.navigator.userAgent.indexOf("MSIE") >= 0 || window.navigator.userAgent.indexOf("Trident") >= 0,
            intermediateIframe = useIntermediateIframe && createIntermediateIframeForLogin(runtimeOrigin, completionOrigin),
            completionType = useIntermediateIframe ? "iframe" : "postMessage";
    
        startUri += startUri.indexOf('?') == -1 ? '?' : '&';
        startUri += "completion_type=" + completionType + "&completion_origin=" + encodeURIComponent(completionOrigin);
    
        // Browsers don't allow postMessage to a file:// URL (except by setting origin to "*", which is unacceptable)
        // so abort the process early with an explanation in that case.
        if (!(completionOrigin && (completionOrigin.indexOf("http:") === 0 || completionOrigin.indexOf("https:") === 0))) {
            var error = "Login is only supported from http:// or https:// URLs. Please host your page in a web server.";
            callback(error, null);
            return;
        }
    
        var loginWindow = window.open(startUri, "_blank", "location=no,resizable=yes"),
            complete = function(errorValue, oauthValue) {
                // Clean up event handlers, windows, frames, ...
                window.clearInterval(checkForWindowClosedInterval);
                loginWindow.close();
                if (window.removeEventListener) {
                    window.removeEventListener("message", handlePostMessage);
                } else {
                    // For IE8
                    window.detachEvent("onmessage", handlePostMessage);
                }
                if (intermediateIframe) {
                    intermediateIframe.parentNode.removeChild(intermediateIframe);
                }
                
                // Finally, notify the caller
                callback(errorValue, oauthValue);
            },
            handlePostMessage = function(evt) {
                // Validate source
                var expectedSource = useIntermediateIframe ? intermediateIframe.contentWindow : loginWindow;
                if (evt.source !== expectedSource) {
                    return;
                }
    
                // Parse message
                var envelope;
                try {
                    // Temporary workaround for IE8 bug until it is fixed in EA.
                    if (typeof evt.data === 'string') {
                        envelope = JSON.parse(evt.data);
                    } else {
                        envelope = evt.data;
                    }
                } catch(ex) {
                    // Not JSON - it's not for us. Ignore it and keep waiting for the next message.
                    return;
                }
    
                // Process message only if it's for us
                if (envelope && envelope.type === "LoginCompleted" && (envelope.oauth || envelope.error)) {
                    complete(envelope.error, envelope.oauth);
                }
            },
            checkForWindowClosedInterval = window.setInterval(function() {
                // We can't directly catch any "onclose" event from the popup because it's usually on a different
                // origin, but in all the mainstream browsers we can poll for changes to its "closed" property
                if (loginWindow && loginWindow.closed === true) {
                    complete(new Error("canceled"), null);
                }
            }, 250);
    
        if (window.addEventListener) {
            window.addEventListener("message", handlePostMessage, false);
        } else {
            // For IE8
            window.attachEvent("onmessage", handlePostMessage);
        }
        
        // Permit cancellation, e.g., if the app tries to login again while the popup is still open
        return {
            cancelCallback: function () {
                complete(new Error("canceled"), null);
                return true; // Affirm that it was cancelled
            }
        };
    };
    
    function createIntermediateIframeForLogin(runtimeOrigin, completionOrigin) {
        var frame = document.createElement("iframe");
        frame.name = "zumo-login-receiver"; // loginviaiframe.html specifically looks for this name
        frame.src = runtimeOrigin + "/.auth/login/iframereceiver?completion_origin=" + encodeURIComponent(completionOrigin);
        frame.setAttribute("width", 0);
        frame.setAttribute("height", 0);
        frame.style.display = "none";
        document.body.appendChild(frame);
        return frame;
    }
    },{"../Utilities/PostMessageExchange":242}],222:[function(require,module,exports){
    // ----------------------------------------------------------------------------
    // Copyright (c) Microsoft Corporation. All rights reserved.
    // ----------------------------------------------------------------------------
    
    // Note: Cordova is PhoneGap.
    // This login UI implementation uses the InAppBrowser plugin,
    // to install the plugin use the following command
    //   cordova plugin add org.apache.cordova.inappbrowser
    
    var requiredCordovaVersion = { major: 3, minor: 0 };
    
    exports.supportsCurrentRuntime = function () {
        /// <summary>
        /// Determines whether or not this login UI is usable in the current runtime.
        /// </summary>
    
        // When running application inside of Ripple emulator, InAppBrowser functionality is not supported.
        // We should use Browser popup login method instead.
        return !!currentCordovaVersion() && !isRunUnderRippleEmulator();
    };
    
    exports.login = function (startUri, endUri, callback) {
        /// <summary>
        /// Displays the login UI and calls back on completion
        /// </summary>
    
        // Ensure it's a sufficiently new version of Cordova, and if not fail synchronously so that
        // the error message will show up in the browser console.
        var foundCordovaVersion = currentCordovaVersion(),
            message;
    
        if (!isSupportedCordovaVersion(foundCordovaVersion)) {
            message = "Not a supported version of Cordova. Detected: " + foundCordovaVersion +
                        ". Required: " + requiredCordovaVersion.major + "." + requiredCordovaVersion.minor;
            throw new Error(message);
        }
        if (!hasInAppBrowser) {
            message = 'A required plugin: "org.apache.cordova.inappbrowser" was not detected.';
            throw new Error(message);
        }
    
        // Initially we show a page with a spinner. This stays on screen until the login form has loaded.
        var redirectionScript = "<script>location.href = unescape('" + window.escape(startUri) + "')</script>",
            startPage = "data:text/html," + encodeURIComponent(getSpinnerMarkup() + redirectionScript);
    
        // iOS inAppBrowser issue requires this wrapping
        setTimeout(function () {
            var loginWindow = window.open(startPage, "_blank", "location=no,hardwareback=no"),
                flowHasFinished = false,
                loadEventHandler = function (evt) {
                    if (!flowHasFinished && evt.url.indexOf(endUri) === 0) {
                        flowHasFinished = true;
                        setTimeout(function () {
                            loginWindow.close();
                        }, 500);
                        var result = parseOAuthResultFromDoneUrl(evt.url);
                        callback(result.error, result.oAuthToken);
                    }
                };
    
            // Ideally we'd just use loadstart because it happens earlier, but it randomly skips
            // requests on iOS, so we have to listen for loadstop as well (which is reliable).
            loginWindow.addEventListener('loadstart', loadEventHandler);
            loginWindow.addEventListener('loadstop', loadEventHandler);
    
            loginWindow.addEventListener('exit', function (evt) {
                if (!flowHasFinished) {
                    flowHasFinished = true;
                    callback(new Error("UserCancelled"), null);
                }
            });
        }, 500);
    };
    
    function isRunUnderRippleEmulator () {
        // Returns true when application runs under Ripple emulator 
        return window.parent && !!window.parent.ripple;
    }
    
    function currentCordovaVersion() {
        // If running inside Cordova, returns a string similar to "3.5.0". Otherwise, returns a falsey value.
        // Note: We can only detect Cordova after its deviceready event has fired, so don't call login until then.
        return window.cordova && window.cordova.version;
    }
    
    function isSupportedCordovaVersion(version) {
        var versionParts = currentCordovaVersion().match(/^(\d+).(\d+)./);
        if (versionParts) {
            var major = Number(versionParts[1]),
                minor = Number(versionParts[2]),
                required = requiredCordovaVersion;
            return (major > required.major) ||
                   (major === required.major && minor >= required.minor);
        }
        return false;
    }
    
    function hasInAppBrowser() {
        return !window.open;
    }
    
    function parseOAuthResultFromDoneUrl(url) {
        var successMessage = extractMessageFromUrl(url, "#token="),
            errorMessage = extractMessageFromUrl(url, "#error=");
        return {
            oAuthToken: successMessage ? JSON.parse(successMessage) : null,
            error: errorMessage ? new Error(errorMessage) : null
        };
    }
    
    function extractMessageFromUrl(url, separator) {
        var pos = url.indexOf(separator);
        return pos < 0 ? null : decodeURIComponent(url.substring(pos + separator.length));
    }
    
    function getSpinnerMarkup() {
        // The default InAppBrowser experience isn't ideal, as it just shows the user a blank white screen
        // until the login form appears. This might take 10+ seconds during which it looks broken.
        // Also on iOS it's possible for the InAppBrowser to initially show the results of the *previous*
        // login flow if the InAppBrowser was dismissed before completion, which is totally undesirable.
        // To fix both of these problems, we display a simple "spinner" graphic via a data: URL until
        // the current login screen has loaded. We generate the spinner via CSS rather than referencing
        // an animated GIF just because this makes the client library smaller overall.
        var vendorPrefix = "webkitTransform" in document.documentElement.style ? "-webkit-" : "",
            numSpokes = 12,
            spokesMarkup = "";
        for (var i = 0; i < numSpokes; i++) {
            spokesMarkup += "<div style='-prefix-transform: rotateZ(" + (180 + i * 360 / numSpokes) + "deg);" +
                                        "-prefix-animation-delay: " + (0.75 * i / numSpokes) + "s;'></div>";
        }
        return [
            "<!DOCTYPE html><html>",
            "<head><meta name='viewport' content='width=device-width, initial-scale=1, maximum-scale=1'></head>",
            "<body><div id='spinner'>" + spokesMarkup + "</div>",
            "<style type='text/css'>",
            "    #spinner { position: absolute; top: 50%; left: 50%; -prefix-animation: spinner 10s linear infinite; }",
            "    #spinner > div {",
            "        background: #333; opacity: 0; position: absolute; top: 11px; left: -2px; width: 4px; height: 21px; border-radius: 2px;",
            "        -prefix-transform-origin: 50% -11px; -prefix-animation: spinner-spoke 0.75s linear infinite;",
            "    }",
            "    @-prefix-keyframes spinner { 0% { -prefix-transform: rotateZ(0deg); } 100% { -prefix-transform: rotateZ(-360deg); } }",
            "    @-prefix-keyframes spinner-spoke { 0% { opacity: 0; } 5% { opacity: 1; } 70% { opacity: 0; } 100% { opacity: 0; } }",
            "</style>",
            "</body></html>"
        ].join("").replace(/-prefix-/g, vendorPrefix);
    }
    },{}],223:[function(require,module,exports){
    // ----------------------------------------------------------------------------
    // Copyright (c) Microsoft Corporation. All rights reserved.
    // ----------------------------------------------------------------------------
    
    var _ = require('../Utilities/Extensions'),
        easyAuthRedirectUriKey = 'post_login_redirect_url';
    
    exports.supportsCurrentRuntime = function () {
        /// <summary>
        /// Determines whether or not this login UI is usable in the current runtime.
        /// </summary>
    
        return isWebAuthBrokerAvailable();
    };
    
    exports.login = function (startUri, endUri, callback) {
        /// <summary>
        /// Displays the login UI and calls back on completion
        /// </summary>
    
        // Define shortcuts for namespaces
        var windowsWebAuthBroker = Windows.Security.Authentication.Web.WebAuthenticationBroker;
        var noneWebAuthOptions = Windows.Security.Authentication.Web.WebAuthenticationOptions.none;
        var successWebAuthStatus = Windows.Security.Authentication.Web.WebAuthenticationStatus.success;
        var activationKindWebAuthContinuation = Windows.ApplicationModel.Activation.ActivationKind.webAuthenticationBrokerContinuation;
    
        var webAuthBrokerSuccessCallback = null;
        var webAuthBrokerErrorCallback = null;
        var webAuthBrokerContinuationCallback = null;
    
    
        // define callbacks for WebAuthenticationBroker
        webAuthBrokerSuccessCallback = function (result) {
            var error = null;
            var token = null;
    
            if (result.responseStatus !== successWebAuthStatus) {
                error = result;
            }
            else {
                var callbackEndUri = result.responseData;
                var tokenAsJson = null;
                var i = callbackEndUri.indexOf('#token=');
                if (i > 0) {
                    tokenAsJson = decodeURIComponent(callbackEndUri.substring(i + 7));
                }
                else {
                    i = callbackEndUri.indexOf('#error=');
                    if (i > 0) {
                        error = new Error(decodeURIComponent(callbackEndUri.substring(i + 7)));
                    }
                }
    
                if (tokenAsJson !== null) {
                    try {
                        token = JSON.parse(tokenAsJson);
                    }
                    catch (e) {
                        error = e;
                    }
                }
            }
    
            callback(error, token);
        };
        webAuthBrokerErrorCallback = function (error) {
            callback(error, null);
        };
        // Continuation callback is used when we're running on WindowsPhone which uses 
        // AuthenticateAndContinue method instead of AuthenticateAsync, which uses different async model
        // Continuation callback need to be assigned to Application's 'activated' event.
        webAuthBrokerContinuationCallback = function (activationArgs) {
            if (activationArgs.detail.kind === activationKindWebAuthContinuation) {
                var result = activationArgs.detail.webAuthenticationResult;
                if (result.responseStatus == successWebAuthStatus) {
                    webAuthBrokerSuccessCallback(result);
                } else {
                    webAuthBrokerErrorCallback(result);
                }
                WinJS.Application.removeEventListener('activated', webAuthBrokerContinuationCallback);
            }
        };
    
        // If no endURI was given, we construct the startUri with a redirect parameter 
        // pointing to the app SID for single sign on.
        // Single sign-on requires that the application's Package SID 
        // be registered with the Microsoft Azure Mobile Service, but it provides a better 
        // experience as HTTP cookies are supported so that users do not have to
        // login in everytime the application is launched.
        if (endUri) {
            endUri = new Windows.Foundation.Uri(endUri);
        } else {
            var ssoQueryParameter = {},
                redirectUri = windowsWebAuthBroker.getCurrentApplicationCallbackUri().absoluteUri;
    
            ssoQueryParameter[easyAuthRedirectUriKey] = redirectUri;
            startUri = _.url.combinePathAndQuery(startUri, _.url.getQueryString(ssoQueryParameter));
        }
        
        startUri = new Windows.Foundation.Uri(startUri);
        
        // If authenticateAndContinue method is available, we should use it instead of authenticateAsync.
        // In the event that it exists, but fails (which is the case with Win 10), we fallback to authenticateAsync.
        var isLoginWindowLaunched;
        try {
            WinJS.Application.addEventListener('activated', webAuthBrokerContinuationCallback, true);
            windowsWebAuthBroker.authenticateAndContinue(startUri, endUri);
    
            isLoginWindowLaunched = true;
        } catch (ex) {
            WinJS.Application.removeEventListener('activated', webAuthBrokerContinuationCallback);
        }
    
        if (!isLoginWindowLaunched) {
            windowsWebAuthBroker.authenticateAsync(noneWebAuthOptions, startUri, endUri)
            .done(webAuthBrokerSuccessCallback, webAuthBrokerErrorCallback);
        }
    };
    
    function isWebAuthBrokerAvailable() {
        // If running on windows8/8.1 or Windows Phone returns true, otherwise false
        return !!(window.Windows &&
            window.Windows.Security &&
            window.Windows.Security.Authentication &&
            window.Windows.Security.Authentication.Web &&
            window.Windows.Security.Authentication.Web.WebAuthenticationBroker);
    }
    
    },{"../Utilities/Extensions":241}],224:[function(require,module,exports){
    // ----------------------------------------------------------------------------
    // Copyright (c) Microsoft Corporation. All rights reserved.
    // ----------------------------------------------------------------------------
    
    var _ = require('./Utilities/Extensions'),
        constants = require('./constants'),
        Validate = require('./Utilities/Validate'),
        Platform = require('./Platform'),
        MobileServiceSyncContext = require('./sync/MobileServiceSyncContext'),
        MobileServiceSyncTable = require('./sync/MobileServiceSyncTable').MobileServiceSyncTable,
        MobileServiceTable = require('./MobileServiceTable'),
        MobileServiceLogin = require('./MobileServiceLogin');
    
    var Push;
    try {
        Push = require('./Push/Push').Push;
    } catch (e) { }
    
    var _alternateLoginHost = null;
    Object.defineProperties(MobileServiceClient.prototype, {
        alternateLoginHost: {
            get: function () {
                return this._alternateLoginHost;
            },
            set: function (value) {
                if (_.isNullOrEmpty(value)) {
                    this._alternateLoginHost = this.applicationUrl;
                }else if (_.url.isAbsoluteUrl(value) && _.url.isHttps(value)) {
                    this._alternateLoginHost = value;
                } else {
                    throw new Error(value + ' is not valid. Expected Absolute Url with https scheme');
                }
            }
        }
    });
    var _loginUriPrefix = null;
    Object.defineProperties(MobileServiceClient.prototype, {
        loginUriPrefix: {
            get: function () {
                return this._loginUriPrefix;
            },
            set: function (value) {
                if (_.isNullOrEmpty(value)) {
                    this._loginUriPrefix = ".auth/login";
                } else {
                    _.isString(value);
                    this._loginUriPrefix = value;
                }
            }
        }
    });
    
    /**
     * @class
     * @classdesc Client for connecting to the Azure Mobile Apps backend.
     * @protected
     * 
     * @param {string} applicationUrl The URL of the Azure Mobile backend.
     */
    function MobileServiceClient(applicationUrl) {
    
        Validate.isString(applicationUrl, 'applicationUrl');
        Validate.notNullOrEmpty(applicationUrl, 'applicationUrl');
    
        this.applicationUrl = applicationUrl;
    
        var sdkInfo = Platform.getSdkInfo();
        var osInfo = Platform.getOperatingSystemInfo();
        var sdkVersion = sdkInfo.fileVersion.split(".").slice(0, 2).join(".");
        this.version = "ZUMO/" + sdkVersion + " (lang=" + sdkInfo.language + "; " +
                                                "os=" + osInfo.name + "; " +
                                                "os_version=" + osInfo.version + "; " +
                                                "arch=" + osInfo.architecture + "; " +
                                                "version=" + sdkInfo.fileVersion + ")";
        this.currentUser = null;
        this._serviceFilter = null;
        this._login = new MobileServiceLogin(this);
    
        var _syncContext = new MobileServiceSyncContext(this);
    
        /**
         * Get the associated {@link MobileServiceSyncContext} instance.
         * 
         * @returns {MobileServiceSyncContext} The associated {@link MobileServiceSyncContext}.
         */
        this.getSyncContext = function() {
            return _syncContext;
        };
    
        /**
         * Gets a reference to the specified backend table.
         * 
         * @param {string} tableName The name of the backend table. 
         * 
         * @returns {MobileServiceTable} A reference to the specified table in the backend.
         */
        this.getTable = function (tableName) {
    
            Validate.isString(tableName, 'tableName');
            Validate.notNullOrEmpty(tableName, 'tableName');
            return new MobileServiceTable(tableName, this);
        };
    
        /**
         * Gets a reference to the specified local table.
         * 
         * @param {string} tableName The name of the table in the local store. 
         * 
         * @returns {MobileServiceSyncTable} A refence to the specified table in the local store.
         */
        this.getSyncTable = function (tableName) {
    
            Validate.isString(tableName, 'tableName');
            Validate.notNullOrEmpty(tableName, 'tableName');
            
            return new MobileServiceSyncTable(tableName, this);
        };
    
        if (Push) {
            /**
             * @member {Push} push Push registration manager.
             * @instance
             * @memberof MobileServiceClient
             */
            this.push = new Push(this, MobileServiceClient._applicationInstallationId);
        }
        
    }
    
    /**
     * @callback MobileServiceClient.Next
     * @param {Request} request The outgoing request.
     * @param {MobileServiceClient.Completion} callback Completion callback.
     */
    
    /**
     * @callback MobileServiceClient.Completion
     * @param {Error} error Error object.
     * @param {Response} response Server response.
     */
    
    /**
     * @callback MobileServiceClient.Filter
     * @param {Request} request The outgoing request.
     * @param {MobileServiceClient.Next} next Next {@link MobileServiceClient.Filter} in the chain of filters.
     * @param {MobileServiceClient.Completion} callback Completion callback.
     */
    
    /**
     * Create a new {@link MobileServiceClient} with a filter used to process all
     * of its network requests and responses.
     * 
     * @param {MobileServiceClient.Filter} serviceFilter The filter to use on the
     * {@link MobileServiceClient} instance's network requests and responses.
     * 
     * The Mobile Services HTTP pipeline is a chain of filters composed
     * together by giving each the next operation which it can invoke
     * (zero, one, or many times as necessary).
     * 
     * Filters are composed just like standard function composition.  If
     * we had the following:
     * 
     *     new MobileServiceClient().withFilter(F1).withFilter(F2),withFilter(F3),
     * 
     * it is conceptually equivalent to saying:
     * 
     *     var response = F3(F2(F1(next(request)));
     * 
     * @returns {MobileServiceClient} A client whose HTTP requests and responses will be
     * filtered as desired.
     * 
     * Here's a sample filter that will automatically retry request that fails with status code >= 400.
     * 
     * @example
     * function(req, next, callback) {
     *     next(req, function(err, rsp) {
     *         if (rsp.statusCode >= 400) {
     *             next(req, callback);
     *         } else {
     *             callback(err, rsp);
     *         }
     *     });
     * }
     *
     */
    MobileServiceClient.prototype.withFilter = function (serviceFilter) {
    
        Validate.notNull(serviceFilter, 'serviceFilter');
    
        // Clone the current instance
        var client = new MobileServiceClient(this.applicationUrl);
        client.currentUser = this.currentUser;
    
        // Chain the service filter with any existing filters
        var existingFilter = this._serviceFilter;
        client._serviceFilter = _.isNull(existingFilter) ?
            serviceFilter :
            function (req, next, callback) {
                // compose existingFilter with next so it can be used as the next
                // of the new serviceFilter
                var composed = function (req, callback) {
                    existingFilter(req, next, callback);
                };
                serviceFilter(req, composed, callback);
            };
    
        return client;
    };
    
    MobileServiceClient.prototype._request = function (method, uriFragment, content, ignoreFilters, headers, features, callback) {
        /// <summary>
        /// Perform a web request and include the standard Mobile Services headers.
        /// </summary>
        /// <param name="method" type="string">
        /// The HTTP method used to request the resource.
        /// </param>
        /// <param name="uriFragment" type="String">
        /// URI of the resource to request (relative to the Mobile Services
        /// runtime).
        /// </param>
        /// <param name="content" type="Object">
        /// Optional content to send to the resource.
        /// </param>
        /// <param name="ignoreFilters" type="Boolean" mayBeNull="true">
        /// Optional parameter to indicate if the client filters should be ignored
        /// and the request should be sent directly. Is false by default.
        /// </param>
        /// <param name="headers" type="Object">
        /// Optional request headers
        /// </param>
        /// <param name="features" type="Array">
        /// Codes for features which are used in this request, sent to the server for telemetry.
        /// </param>
        /// <param name="callback" type="function(error, response)">
        /// Handler that will be called on the response.
        /// </param>
    
        // Account for absent optional arguments
        if (_.isNull(callback) && (typeof features === 'function')) {
            callback = features;
            features = null;
        }
    
        if (_.isNull(callback) && (typeof headers === 'function')) {
            callback = headers;
            headers = null;
        }
    
        if (_.isNull(callback) && (typeof ignoreFilters === 'function')) {
            callback = ignoreFilters;
            ignoreFilters = false;
        }
    
        if (_.isNull(callback) && (typeof content === 'function')) {
            callback = content;
            content = null;
        }
    
        Validate.isString(method, 'method');
        Validate.notNullOrEmpty(method, 'method');
        Validate.isString(uriFragment, 'uriFragment');
        Validate.notNull(uriFragment, 'uriFragment');
        Validate.notNull(callback, 'callback');
    
        // Create the absolute URI
        var options = { type: method.toUpperCase() };
        if (_.url.isAbsoluteUrl(uriFragment)) {
            options.url = uriFragment;
        } else {
            options.url = _.url.combinePathSegments(this.applicationUrl, uriFragment);
        }
    
        // Set MobileServices authentication, application, User-Agent and telemetry headers
        options.headers = {};
        if (!_.isNull(headers)) {
            _.extend(options.headers, headers);
        }
        options.headers["X-ZUMO-INSTALLATION-ID"] = MobileServiceClient._applicationInstallationId;
        if (this.currentUser && !_.isNullOrEmpty(this.currentUser.mobileServiceAuthenticationToken)) {
            options.headers["X-ZUMO-AUTH"] = this.currentUser.mobileServiceAuthenticationToken;
        }
        if (!_.isNull(MobileServiceClient._userAgent)) {
            options.headers["User-Agent"] = MobileServiceClient._userAgent;
        }
        if (!_.isNullOrEmpty["X-ZUMO-VERSION"]) {
            options.headers["X-ZUMO-VERSION"] = this.version;
        }
    
        if (_.isNull(options.headers[constants.featuresHeaderName]) && features && features.length) {
            options.headers[constants.featuresHeaderName] = features.join(',');
        }
    
        // Add any content as JSON
        if (!_.isNull(content)) {
            if (!_.isString(content)) {
                options.data = _.toJson(content);
            } else {
                options.data = content;
            }
    
            if (!_.hasProperty(options.headers, ['Content-Type', 'content-type', 'CONTENT-TYPE', 'Content-type'])) {
                options.headers['Content-Type'] = 'application/json';
            }
        } else {
            // options.data must be set to null if there is no content or the xhr object
            // will set the content-type to "application/text" for non-GET requests.
            options.data = null;
        }
    
        // Treat any >=400 status codes as errors.  Also treat the status code 0 as
        // an error (which indicates a connection failure).
        var handler = function (error, response) {
            if (!_.isNull(error)) {
                error = _.createError(error);
            } else if (!_.isNull(response) && (response.status >= 400 || response.status === 0)) {
                error = _.createError(null, response);
                response = null;
            }
            callback(error, response);
        };
    
        // Make the web request
        if (!_.isNull(this._serviceFilter) && !ignoreFilters) {
            this._serviceFilter(options, Platform.webRequest, handler);
        } else {
            Platform.webRequest(options, handler);
        }
    };
    
    /**
     * Log a user into an Azure Mobile Apps backend.
     * 
     * @function
     * 
     * @param {string} provider Name of the authentication provider to use; one of _'facebook'_, _'twitter'_, _'google'_,
     *                          _'aad'_ (equivalent to _'windowsazureactivedirectory'_) or _'microsoftaccount'_.
     * @param {object} options Contains additional parameter information.
     * @param {object} options.token provider specific object with existing OAuth token to log in with.
     * @param {boolean} options.useSingleSignOn Indicates if single sign-on should be used. This parameter only applies to Windows clients 
     *                                  and is ignored on other platforms. Single sign-on requires that the 
     *                                  application's Package SID be registered with the Microsoft Azure Mobile Apps backend,
     *                                  but it provides a better experience as HTTP cookies are supported so that users 
     *                                  do not have to login in everytime the application is launched.
     * @param {object} options.parameters Any additional provider specific query string parameters.
     * @returns {Promise} A promise that is either resolved with the logged in user or rejected with the error.
     */
    MobileServiceClient.prototype.loginWithOptions = Platform.async(
         function (provider, options, callback) {
             this._login.loginWithOptions(provider, options, callback);
         });
    
    /**
     * Log a user into an Azure Mobile Apps backend.
     * 
     * @function
     * 
     * @param {string} provider Name of the authentication provider to use; one of _'facebook'_, _'twitter'_, _'google'_,
     *                          _'aad'_ (equivalent to _'windowsazureactivedirectory'_) or _'microsoftaccount'_. If no
     *                          provider is specified, the 'token' parameter is considered a Microsoft Account
     *                          authentication token. If a provider is specified, the 'token' parameter is 
     *                          considered a provider-specific authentication token.
     * @param {object} token provider specific object with existing OAuth token to log in with.  
     * @param {boolean} useSingleSignOn Indicates if single sign-on should be used. This parameter only applies to Windows clients 
     *                                  and is ignored on other platforms. Single sign-on requires that the 
     *                                  application's Package SID be registered with the Microsoft Azure Mobile Apps backend,
     *                                  but it provides a better experience as HTTP cookies are supported so that users 
     *                                  do not have to login in everytime the application is launched.
     * @returns {Promise} A promise that is either resolved with the logged in user or rejected with the error.
     */
    MobileServiceClient.prototype.login = Platform.async(
        function (provider, token, useSingleSignOn, callback) {
            this._login.login(provider, token, useSingleSignOn, callback);
        });
    
    /**
     * Log a user out of the Mobile Apps backend.
     * 
     * @function
     * 
     * @returns {Promise} A promise that is either resolved or rejected with the error. 
     */
    MobileServiceClient.prototype.logout = Platform.async(function(callback) {
        this.currentUser = null;
        callback();
    });
    
    /**
     * Invokes the specified custom api and returns a response object.
     * 
     * @function
     * 
     * @param {string} apiName The custom api to invoke.
     * @param {object} options Additional parameter information.
     * @param {object} options.body The body of the HTTP request.
     * @param {string} options.method The HTTP method to use in the request, with the default being 'POST'.
     * @param {object} options.parameters Additional query string parameters, if any, with property names and
     *                                    values as property keys and values respectively. 
     * @param {object} options.headers HTTP request headers.
     * 
     * @returns {Promise} A promise that is resolved with an _XMLHttpRequest_ object if the API is invoked succesfully.
     *                    If the server response is JSON, it is deserialized into _XMLHttpRequest.result_.
     *                    If _invokeApi_ fails, the promise is rejected with the error.
     */
    MobileServiceClient.prototype.invokeApi = Platform.async(
        function (apiName, options, callback) {
    
            Validate.isString(apiName, 'apiName');
    
            // Account for absent optional arguments
            if (_.isNull(callback)) {
                if (typeof options === 'function') {
                    callback = options;
                    options = null;
                }
            }
            Validate.notNull(callback, 'callback');
    
            var parameters, method, body, headers;
            if (!_.isNull(options)) {
                parameters = options.parameters;
                if (!_.isNull(parameters)) {
                    Validate.isValidParametersObject(options.parameters);
                }
    
                method = options.method;
                body = options.body;
                headers = options.headers;
            }
    
            headers = headers || {};
    
            if (_.isNull(method)) {
                method = "POST";
            }
    
            // if not specified, default to return results in JSON format
            if (_.isNull(headers.accept)) {
                headers.accept = 'application/json';
            }
    
            // Add version header on API requests
            if (_.isNull(headers[constants.apiVersionHeaderName])) {
                headers[constants.apiVersionHeaderName] = constants.apiVersion;
            }
    
            // Construct the URL
            var url;
            if (_.url.isAbsoluteUrl(apiName)) {
                url = apiName;
            } else {
                url = _.url.combinePathSegments("api", apiName);
            }
            if (!_.isNull(parameters)) {
                var queryString = _.url.getQueryString(parameters);
                url = _.url.combinePathAndQuery(url, queryString);
            }
    
            var features = [];
            if (!_.isNullOrEmpty(body)) {
                features.push(_.isString(body) ?
                    constants.features.GenericApiCall :
                    constants.features.JsonApiCall);
            }
    
            if (!_.isNull(parameters)) {
                features.push(constants.features.AdditionalQueryParameters);
            }
    
            // Make the request
            this._request(
                method,
                url,
                body,
                null,
                headers,
                features,
                function (error, response) {
                    if (!_.isNull(error)) {
                        callback(error, null);
                    } else {
                        var contentType;
                        if (typeof response.getResponseHeader !== 'undefined') { // (when not using IframeTransport, IE9)
                            contentType = response.getResponseHeader('Content-Type');
                        }
    
                        // If there was no header / can't get one, try json
                        if (!contentType) {
                            try {
                                response.result = _.fromJson(response.responseText);
                            } catch (e) {
                                // Do nothing, since we don't know the content-type, failing may be ok
                            }
                        } else if (contentType.toLowerCase().indexOf('json') !== -1) {
                            response.result = _.fromJson(response.responseText);
                        }
    
                        callback(null, response);
                    }
                });
    
        });
    
    function getApplicationInstallationId() {
        /// <summary>
        /// Gets or creates the static application installation ID.
        /// </summary>
        /// <returns type="string">
        /// The application installation ID.
        /// </returns>
    
        // Get or create a new installation ID that can be passed along on each
        // request to provide telemetry data
        var applicationInstallationId = null;
    
        // Check if the config settings exist
        var path = "MobileServices.Installation.config";
        var contents = Platform.readSetting(path);
        if (!_.isNull(contents)) {
            // Parse the contents of the file as JSON and pull out the
            // application's installation ID.
            try {
                var config = _.fromJson(contents);
                applicationInstallationId = config.applicationInstallationId;
            } catch (ex) {
                // Ignore any failures (like invalid JSON, etc.) which will allow
                // us to fall through to and regenerate a valid config below
            }
        }
    
        // If no installation ID was found, generate a new one and save the config
        // settings.  This is pulled out as a separate function because we'll do it
        // even if we successfully read an existing config but there's no
        // installation ID.
        if (_.isNullOrEmpty(applicationInstallationId)) {
            applicationInstallationId = _.createUniqueInstallationId();
    
            // TODO: How many other settings should we write out as well?
            var configText = _.toJson({ applicationInstallationId: applicationInstallationId });
            Platform.writeSetting(path, configText);
        }
    
        return applicationInstallationId;
    }
    
    /// <summary>
    /// Get or set the static _applicationInstallationId by checking the settings
    /// and create the value if necessary.
    /// </summary>
    MobileServiceClient._applicationInstallationId = getApplicationInstallationId();
    
    /// <summary>
    /// Get or set the static _userAgent by calling into the Platform.
    /// </summary>
    MobileServiceClient._userAgent = Platform.getUserAgent();
    
    // Define the module exports
    module.exports = MobileServiceClient;
    
    },{"./MobileServiceLogin":225,"./MobileServiceTable":226,"./Platform":234,"./Push/Push":238,"./Utilities/Extensions":241,"./Utilities/Validate":244,"./constants":246,"./sync/MobileServiceSyncContext":250,"./sync/MobileServiceSyncTable":251}],225:[function(require,module,exports){
    // ----------------------------------------------------------------------------
    // Copyright (c) Microsoft Corporation. All rights reserved.
    // ----------------------------------------------------------------------------
    
    var _ = require('./Utilities/Extensions');
    var Validate = require('./Utilities/Validate');
    var Platform = require('./Platform');
    
    var loginUrl = ".auth/login";
    var loginDone = "done";
    var sessionModeKey = 'session_mode';
    var sessionModeValueToken = 'token';
    
    function MobileServiceLogin(client, ignoreFilters) {
        /// <summary>
        /// Initializes a new instance of the MobileServiceLogin class.
        /// </summary>
        /// <param name="client" type="MobileServiceClient" mayBeNull="false">
        /// Reference to the MobileServiceClient associated with this login.
        /// </param>
        /// <param name="ignoreFilters" type="Boolean" mayBeNull="true">
        /// Optional parameter to indicate if the client filters should be ignored
        /// and requests should be sent directly. Is true by default. This should
        /// only be set to false for testing purposes when filters are needed to intercept
        /// and validate requests and responses.
        /// </param>
    
        // Account for absent optional arguments
        if (_.isNull(ignoreFilters)) {
            ignoreFilters = true;
        }
    
        // Validate arguments
        Validate.notNull(client);
        Validate.isObject(client, 'client');
    
        // Create read/write fields
        this._loginState = { inProcess: false, cancelCallback: null };
        this.ignoreFilters = ignoreFilters;
    
        // Create get accessors for read-only fields
        this.getMobileServiceClient = function () {
            /// <summary>
            /// Gets the MobileServiceClient associated with this table.
            /// <summary>
            /// <returns type="MobileServiceClient">
            /// The MobileServiceClient associated with this table.
            /// </returns>
            return client;
        };
    
        this.getLoginInProcess = function () {
            /// <summary>
            /// Indicates if a login is currently in process or not.
            /// <summary>
            /// <returns type="Boolean">
            /// True if a login is in process and false otherwise.
            /// </returns>
            return this._loginState.inProcess;
        };
    }
    
    MobileServiceLogin.prototype.loginWithOptions = function (provider, options, callback) {
        /// <summary>
        /// Log a user into a Mobile Services application given a provider name with
        /// given options.
        /// </summary>
        /// <param name="provider" type="String" mayBeNull="false">
        /// Name of the authentication provider to use; one of 'facebook', 'twitter', 'google', 
        /// 'windowsazureactivedirectory' (can also use 'aad')
        /// or 'microsoftaccount'.
        /// </param>
        /// <param name="options" type="Object" mayBeNull="true">
        /// Contains additional parameter information, valid values are:
        ///    token: provider specific object with existing OAuth token to log in with
        ///    useSingleSignOn: Only applies to Windows 8 clients.  Will be ignored on other platforms.
        /// Indicates if single sign-on should be used. Single sign-on requires that the 
        /// application's Package SID be registered with the Microsoft Azure Mobile Service, 
        /// but it provides a better experience as HTTP cookies are supported so that users 
        /// do not have to login in everytime the application is launched.
        ///    parameters: Any additional provider specific query string parameters.
        /// </param>
        /// <param name="callback" type="Function" mayBeNull="true">
        /// Optional callback accepting (error, user) parameters.
        /// </param>
    
        Validate.isString(provider, 'provider');
        Validate.notNull(provider, 'provider');
    
        if (_.isNull(callback)) {
            if (!_.isNull(options) && typeof options === 'function') {
                callback = options;
                options = null;
            } else {
                Validate.notNull(null, 'callback');
            }
        }
    
        // loginWithOptions('a.b.c')
        if (!options && this._isAuthToken(provider)) {
            this.loginWithMobileServiceToken(provider, callback);
        } else {
            // loginWithOptions('facebook', {});
            // loginWithOptions('facebook');
            options = options || {};
            this.loginWithProvider(provider, options.token, options.useSingleSignOn, options.parameters, callback);
        }
    };
    
    MobileServiceLogin.prototype.login = function (provider, token, useSingleSignOn, callback) {
        /// <summary>
        /// Log a user into a Mobile Services application given a provider name and optional token object
        /// Microsoft Account authentication token.
        /// </summary>
        /// <param name="provider" type="String" mayBeNull="true">
        /// Optional name of the authentication provider to use; one of 'facebook', 'twitter', 'google',
        /// 'windowsazureactivedirectory' (can also use 'aad'), or 'microsoftaccount'.
        /// </param>
        /// <param name="token" type="Object"  mayBeNull="true">
        /// Optional provider specific object with existing OAuth token to log in with or
        /// a JWT Mobile Services authentication token if the provider is null.
        /// </param>
        /// <param name="useSingleSignOn" type="Boolean" mayBeNull="true">
        /// Only applies to Windows 8 clients.  Will be ignored on other platforms.
        /// Indicates if single sign-on should be used. Single sign-on requires that the 
        /// application's Package SID be registered with the Microsoft Azure Mobile Service, 
        /// but it provides a better experience as HTTP cookies are supported so that users 
        /// do not have to login in everytime the application is launched.
        /// </param>
        /// <param name="callback" type="Function"  mayBeNull="true">
        /// Optional callback accepting (error, user) parameters.
        /// </param>
    
        // Account for absent optional arguments
        if (_.isNull(callback)) {
            if (!_.isNull(useSingleSignOn) && (typeof useSingleSignOn === 'function')) {
                callback = useSingleSignOn;
                useSingleSignOn = null;
            }
            else if (!_.isNull(token) && (typeof token === 'function')) {
                callback = token;
                useSingleSignOn = null;
                token = null;
            }
        }
        if (_.isNull(useSingleSignOn)) {
            if (_.isBool(token)) {
                useSingleSignOn = token;
                token = null;
            }
            else {
                useSingleSignOn = false;
            }
        }
    
        // Determine if the provider is actually a Mobile Services authentication token
        if (_.isNull(token) && this._isAuthToken(provider)) {
            token = provider;
            provider = null;
        }
    
        // Validate parameters; there must be either a provider, a token or both
        if (_.isNull(provider)) {
            Validate.notNull(token);
            Validate.isString(token);
        }
        if (_.isNull(token)) {
            Validate.notNull(provider);
            Validate.isString(provider);
            provider = provider.toLowerCase();
        }
    
        if (!_.isNull(provider)) {
            if (provider.toLowerCase() === 'windowsazureactivedirectory') {
                // The mobile service REST API uses '/login/aad' for Microsoft Azure Active Directory
                provider = 'aad';
            }
            this.loginWithProvider(provider, token, useSingleSignOn, {}, callback);
        }
        else {
            this.loginWithMobileServiceToken(token, callback);
        }
    };
    
    MobileServiceLogin.prototype._isAuthToken = function (value) {
        return value && _.isString(value) && value.split('.').length === 3;
    };
    
    MobileServiceLogin.prototype.loginWithMobileServiceToken = function (authenticationToken, callback) {
        /// <summary>
        /// Log a user into a Mobile Services application given an Mobile Service authentication token.
        /// </summary>
        /// <param name="authenticationToken" type="String">
        /// OAuth access token that authenticates the user.
        /// </param>
        /// <param name="callback" type="Function">
        /// Optional callback accepting (error, user) parameters.
        /// </param>
    
        var self = this;
        var client = self.getMobileServiceClient();
    
        Validate.isString(authenticationToken, 'authenticationToken');
        Validate.notNullOrEmpty(authenticationToken, 'authenticationToken');
    
        client._request(
            'POST',
            loginUrl,
            { authenticationToken: authenticationToken },
            self.ignoreFilters,
            function (error, response) {
                onLoginResponse(error, response, client, callback);
            });
    };
    
    MobileServiceLogin.prototype.loginWithProvider = function (provider, token, useSingleSignOn, parameters, callback) {
        /// <summary>
        /// Log a user into a Mobile Services application given a provider name and optional token object.
        /// </summary>
        /// <param name="provider" type="String">
        /// Name of the authentication provider to use; one of 'facebook', 'twitter', 'google',
        /// 'windowsazureactivedirectory' (can also use 'aad'), or 'microsoftaccount'.
        /// </param>
        /// <param name="token" type="Object">
        /// Optional, provider specific object with existing OAuth token to log in with.
        /// </param>
        /// <param name="useSingleSignOn" type="Boolean">
        /// Optional, indicates if single sign-on should be used.  Single sign-on requires that the
        /// application's Package SID be registered with the Microsoft Azure Mobile Service, but it
        /// provides a better experience as HTTP cookies are supported so that users do not have to
        /// login in everytime the application is launched. Is false be default.
        /// </param>
        /// <param name="parameters" type="Object">
        /// Any additional provider specific query string parameters. 
        /// </param>
        /// <param name="callback" type="Function">
        /// The callback to execute when the login completes: callback(error, user).
        /// </param>
    
        // Validate arguments
        Validate.isString(provider, 'provider');
        if (!_.isNull(token)) {
            Validate.isObject(token, 'token');
        }
    
        // Throw if a login is already in process and is not cancellable
        if (this._loginState.inProcess) {
            var didCancel = this._loginState.cancelCallback && this._loginState.cancelCallback();
            if (!didCancel) {
                throw new Error('Cannot start a login operation because login is already in progress.');
            }
        }
    
        provider = provider.toLowerCase();
    
        // Either login with the token or the platform specific login control.
        if (!_.isNull(token)) {
            loginWithProviderAndToken(this, provider, token, parameters, callback);
        }
        else {
            loginWithLoginControl(this, provider, useSingleSignOn, parameters, callback);
        }
    };
    
    function onLoginComplete(error, token, client, callback) {
        /// <summary>
        /// Handles the completion of the login and calls the user's callback with
        /// either a user or an error.
        /// </summary>
        /// <param name="error" type="string" mayBeNull="true">
        /// Optional error that may have occurred during login. Will be null if the
        /// login succeeded and their is a token.
        /// </param>
        /// <param name="token" type="string" mayBeNull="true">
        /// Optional token that represents the logged-in user. Will be null if the
        /// login failed and their is an error.
        /// </param>
        /// <param name="client" type="MobileServiceClient">
        /// The Mobile Service client associated with the login.
        /// </param>
        /// <param name="callback" type="Function" mayBeNull="true">
        /// The callback to execute when the login completes: callback(error, user).
        /// </param>
        var user = null;
    
        if (_.isNull(error)) {
    
            // Validate the token
            if (_.isNull(token) ||
                !_.isObject(token) ||
                !_.isObject(token.user) ||
                !_.isString(token.authenticationToken)) {
                error = Platform.getResourceString("MobileServiceLogin_InvalidResponseFormat");
            }
            else {
                // Set the current user on the client and return it in the callback
                client.currentUser = token.user;
                client.currentUser.mobileServiceAuthenticationToken = token.authenticationToken;
                user = client.currentUser;
            }
        }
    
        if (!_.isNull(callback)) {
            callback(error, user);
        }
    }
    
    function onLoginResponse(error, response, client, callback) {
        /// <summary>
        /// Handles the completion of the login HTTP call and calls the user's callback with
        /// either a user or an error.
        /// </summary>
        /// <param name="error" type="string" mayBeNull="true">
        /// Optional error that may have occurred during login. Will be null if the
        /// login succeeded and their is a token.
        /// </param>
        /// <param name="response" type="string" mayBeNull="true">
        /// Optional HTTP login response from the Mobile Service. Will be null if the
        /// login failed and their is an error.
        /// </param>
        /// <param name="client" type="MobileServiceClient">
        /// The Mobile Service client associated with the login.
        /// </param>
        /// <param name="callback" type="Function" mayBeNull="true">
        /// The callback to execute when the login completes: callback(error, user).
        /// </param>
    
        var mobileServiceToken = null;
        if (_.isNull(error)) {
            try {
                mobileServiceToken = _.fromJson(response.responseText);
            }
            catch (e) {
                error = e;
            }
        }
    
        onLoginComplete(error, mobileServiceToken, client, callback);
    }
    
    function loginWithProviderAndToken(login, provider, token, parameters, callback) {
        /// <summary>
        /// Log a user into a Mobile Services application given a provider name and token object.
        /// </summary>
        /// <param name="login" type="MobileServiceLogin">
        /// The login instance that holds the context used with the login process.
        /// </param>
        /// <param name="provider" type="String">
        /// Name of the authentication provider to use; one of 'facebook', 'twitter', 'google', or 
        /// 'microsoftaccount'. The provider should already have been validated.
        /// </param>
        /// <param name="token" type="Object">
        /// Provider specific object with existing OAuth token to log in with.
        /// </param>
        /// <param name="parameters" type="Object">
        /// Any additional provider specific query string parameters.
        /// </param>
        /// <param name="callback" type="Function" mayBeNull="true">
        /// The callback to execute when the login completes: callback(error, user).
        /// </param>
    
        var client = login.getMobileServiceClient();
    
        // This design has always been problematic, because the operation can take arbitrarily
        // long and there is no way for the UI to cancel it. We should probably remove this
        // one-at-a-time restriction.
        login._loginState = { inProcess: true, cancelCallback: null };
    
        var url = _.url.combinePathSegments(client.alternateLoginHost || client.applicationUrl,
                                            client.loginUriPrefix || loginUrl,
                                            provider);
    
        if (!_.isNull(parameters)) {
            var queryString = _.url.getQueryString(parameters);
            url = _.url.combinePathAndQuery(url, queryString);
        }
    
        // Invoke the POST endpoint to exchange provider-specific token for a 
        // Microsoft Azure Mobile Services token
        client._request(
            'POST',
            url,
            token,
            login.ignoreFilters,
            function (error, response) {
                login._loginState = { inProcess: false, cancelCallback: null };
                onLoginResponse(error, response, client, callback);
            });
    }
    
    function loginWithLoginControl(login, provider, useSingleSignOn, parameters, callback) {
        /// <summary>
        /// Log a user into a Mobile Services application using a platform specific
        /// login control that will present the user with the given provider's login web page.
        /// </summary>
        /// <param name="login" type="MobileServiceLogin">
        /// The login instance that holds the context used with the login process.
        /// </param>
        /// <param name="provider" type="String">
        /// Name of the authentication provider to use; one of 'facebook', 'twitter', 'google', or 'microsoftaccount'.
        /// </param>
        /// <param name="useSingleSignOn" type="Boolean">
        /// Optional, indicates if single sign-on should be used.  Single sign-on requires that the
        /// application's Package SID be registered with the Microsoft Azure Mobile Service, but it
        /// provides a better experience as HTTP cookies are supported so that users do not have to
        /// login in everytime the application is launched. Is false be default.
        /// </param>
        /// <param name="parameters" type="Object">
        /// Any additional provider specific query string parameters.
        /// </param>
        /// <param name="callback" type="Function"  mayBeNull="true">
        /// The callback to execute when the login completes: callback(error, user).
        /// </param>
    
        var client = login.getMobileServiceClient();
        var startUri = _.url.combinePathSegments(
            client.alternateLoginHost || client.applicationUrl,
            client.loginUriPrefix || loginUrl,
            provider);
    
        var endUri = null,
            queryParams = {},
            key;
    
        // Make a copy of the query parameters and set the session mode to token.
        for (key in parameters) {
            queryParams[key] = parameters[key];
        }
        queryParams[sessionModeKey] = sessionModeValueToken;
    
        var queryString = _.url.getQueryString(queryParams);
        startUri = _.url.combinePathAndQuery(startUri, queryString);
    
        // If not single sign-on, then we need to construct a non-null end uri.
        if (!useSingleSignOn) {
            endUri = _.url.combinePathSegments(
                client.alternateLoginHost || client.applicationUrl,
                client.loginUriPrefix || loginUrl,
                loginDone);
        }
    
        login._loginState = { inProcess: true, cancelCallback: null }; // cancelCallback gets set below
    
        // Call the platform to launch the login control, capturing any
        // 'cancel' callback that it returns
        var platformResult = Platform.login(
            startUri,
            endUri,
            function (error, mobileServiceToken) {
                login._loginState = { inProcess: false, cancelCallback: null };
                onLoginComplete(error, mobileServiceToken, client, callback);
            });
    
        if (login._loginState.inProcess && platformResult && platformResult.cancelCallback) {
            login._loginState.cancelCallback = platformResult.cancelCallback;
        }
    }
    
    // Define the module exports
    module.exports = MobileServiceLogin;
    
    },{"./Platform":234,"./Utilities/Extensions":241,"./Utilities/Validate":244}],226:[function(require,module,exports){
    // ----------------------------------------------------------------------------
    // Copyright (c) Microsoft Corporation. All rights reserved.
    // ----------------------------------------------------------------------------
    
    var _ = require('./Utilities/Extensions');
    var Validate = require('./Utilities/Validate');
    var Platform = require('./Platform');
    var Query = require('azure-query-js').Query;
    var constants = require('./constants');
    var tableHelper = require('./tableHelper');
    
    // Name of the reserved Mobile Services ID member.
    var idPropertyName = "id";
    
    // The route separator used to denote the table in a uri like
    // .../{app}/collections/{coll}.
    var tableRouteSeperatorName = "tables";
    var idNames = ["ID", "Id", "id", "iD"];
    var nextLinkRegex = /^(.*?);\s*rel\s*=\s*(\w+)\s*$/;
    
    var SystemProperties = {
        None: 0,
        CreatedAt: 1,
        UpdatedAt: 2,
        Version: 4,
        All: 0xFFFF
    };
    
    var MobileServiceSystemColumns = {
        CreatedAt: "createdAt",
        UpdatedAt: "updatedAt",
        Version: "version",
        Deleted: "deleted"
    };
    
    /**
     * @class
     * @classdesc Represents a table in the Azure Mobile Apps backend.
     * @protected
     * 
     * @param {string} tableName Name of the table in the backend.
     * @param {MobileServiceClient} client The {@link MobileServiceClient} instance associated with this table.
     */
    function MobileServiceTable(tableName, client) {
    
        /**
         * Gets the name of the backend table.
         * 
         * @returns {string} The name of the table.
         */
        this.getTableName = function () {
            return tableName;
        };
    
        /**
         * Gets the {@link MobileServiceClient} instance associated with this table.
         * 
         * @returns {MobileServiceClient} The {@link MobileServiceClient} associated with this table.
         *///FIXME
        this.getMobileServiceClient = function () {
            return client;
        };
    
        // Features to associate with all table operations
        this._features = undefined;
    }
    
    MobileServiceTable.SystemProperties = SystemProperties;
    
    // We have an internal _read method using callbacks since it's used by both
    // table.read(query) and query.read().
    MobileServiceTable.prototype._read = function (query, parameters, callback) {
        /// <summary>
        /// Query a table.
        /// </summary>
        /// <param name="query" type="Object" mayBeNull="true">
        /// The query to execute.  It can be null or undefined to get the entire
        /// collection.
        /// </param>
        /// <param name="parameters" type="Object" mayBeNull="true">
        /// An object of user-defined parameters and values to include in the request URI query string.
        /// </param>
        /// <param name="callback" type="Function">
        /// The callback to invoke when the query is complete.
        /// </param>
    
        // Account for absent optional arguments
        if (_.isNull(callback))
        {
            if (_.isNull(parameters) && (typeof query === 'function')) {
                callback = query;
                query = null;
                parameters = null;
            } else if (typeof parameters === 'function') {
                callback = parameters;
                parameters = null;
                if (!_.isNull(query) && _.isObject(query)) {
                    // This 'query' argument could be either the query or the user-defined 
                    // parameters object since both are optional.  A query is either (a) a simple string 
                    // or (b) an Object with an toOData member. A user-defined parameters object is just 
                    // an Object.  We need to detect which of these has been passed in here.
                    if (!_.isString(query) && _.isNull(query.toOData)) {
                        parameters = query;
                        query = null;
                    }
                }
            }
        }
    
        // Validate the arguments
        if (query && _.isString(query)) {
            Validate.notNullOrEmpty(query, 'query');
        }
        if (!_.isNull(parameters)) {
            Validate.isValidParametersObject(parameters, 'parameters');
        }
        Validate.notNull(callback, 'callback');
    
        // Get the query string
        var tableName = this.getTableName();
        var queryString = null;
        var projection = null;
        var features = this._features || [];
        if (_.isString(query)) {
            queryString = query;
            if (!_.isNullOrEmpty(query)) {
                features.push(constants.features.TableReadRaw);
            }
        } else if (_.isObject(query) && !_.isNull(query.toOData)) {
            if (query.getComponents) {
                features.push(constants.features.TableReadQuery);
                var components = query.getComponents();
                projection = components.projection;
                if (components.table) {
                    // If the query has a table name, make sure it's compatible with
                    // the table executing the query
                    
                    if (tableName !== components.table) {
                        var message = _.format(Platform.getResourceString("MobileServiceTable_ReadMismatchedQueryTables"), tableName, components.table);
                        callback(new Error(message), null);
                        return;
                    }
    
                    // The oDataQuery will include the table name; we need to remove
                    // because the url fragment already includes the table name.
                    var oDataQuery = query.toOData();
                    queryString = oDataQuery.replace(new RegExp('^/' + components.table), '');
                }
            }
        }
    
        addQueryParametersFeaturesIfApplicable(features, parameters);
    
        // Add any user-defined query string parameters
        if (!_.isNull(parameters)) {
            var userDefinedQueryString = _.url.getQueryString(parameters);
            if (!_.isNullOrEmpty(queryString)) {
                queryString += '&' + userDefinedQueryString;
            }
            else {
                queryString = userDefinedQueryString;
            }
        }
        
        // Construct the URL
        var urlFragment = queryString;
        if (!_.url.isAbsoluteUrl(urlFragment)) {
            urlFragment = _.url.combinePathSegments(tableRouteSeperatorName, tableName);
            if (!_.isNull(queryString)) {
                urlFragment = _.url.combinePathAndQuery(urlFragment, queryString);
            }
        }
    
        var headers = { };
        headers[constants.apiVersionHeaderName] = constants.apiVersion;
    
        // Make the request
        this.getMobileServiceClient()._request(
            'GET',
            urlFragment,
            null,
            false,
            headers,
            features,
            function (error, response) {
                var values = null;
                if (_.isNull(error)) {
                    // Parse the response
                    values = _.fromJson(response.responseText);
    
                    // If the values include the total count, we'll attach that
                    // directly to the array
                    if (values &&
                        !Array.isArray(values) &&
                        typeof values.count !== 'undefined' &&
                        typeof values.results !== 'undefined') {
                        // Create a new total count property on the values array
                        values.results.totalCount = values.count;
                        values = values.results;
                    }
    
                    // If we have a projection function, apply it to each item
                    // in the collection
                    if (projection !== null) {
                        var i = 0;
                        for (i = 0; i < values.length; i++) {
                            values[i] = projection.call(values[i]);
                        }
                    }
    
                    // Grab link header when possible
                    if (Array.isArray(values) && response.getResponseHeader && _.isNull(values.nextLink)) {
                        try {
                            var link = response.getResponseHeader('Link');
                            if (!_.isNullOrEmpty(link)) {
                                var result = nextLinkRegex.exec(link);
    
                                // Only add nextLink when relation is next
                                if (result && result.length === 3 && result[2] == 'next') {
                                    values.nextLink = result[1];
                                }
                            }
                        } catch (ex) {
                            // If cors doesn't allow us to access the Link header
                            // Just continue on without it
                        }
                    }
                }
                callback(error, values);
            });
    };
    
    /**
     * Reads records from the backend table.
     * 
     * @function
     * @instance
     * @public
     * @memberof MobileServiceTable
     * 
     * @param {(QueryJs | string)} query Either, a {@link QueryJs} object representing the query to use while
     *                        reading the backend table, OR, a URL encoded OData string for querying. 
     * @param {object} parameters An object of user-defined parameters and values to include in the request URI query string.
     * 
     * @returns {Promise} A promise that is resolved with an array of records read from the table, if the read is successful.
     *                    If read fails, the promise is rejected with the error.
     */
    MobileServiceTable.prototype.read = Platform.async(MobileServiceTable.prototype._read);
    
    /**
     * Inserts a new object / record in the backend table.
     * 
     * @function
     * @instance
     * @public
     * @memberof MobileServiceTable
     * 
     * @param {object} instance Object / record to be inserted in the backend table.
     * @param {string | number} instance.id id of the object / record.
     * @param {object} parameters An object of user-defined parameters and values to include in the request URI query string.
     * 
     * @returns {Promise} A promise that is resolved with the inserted object when the insert operation is completed successfully.
     *                    If the operation fails, the promise is rejected with the error.
     */
    MobileServiceTable.prototype.insert = Platform.async(
        function (instance, parameters, callback) {
    
            // Account for absent optional arguments
            if (_.isNull(callback) && (typeof parameters === 'function')) {
                callback = parameters;
                parameters = null;
            }
    
            // Validate the arguments
            Validate.notNull(instance, 'instance');
            if (!_.isNull(parameters)) {
                Validate.isValidParametersObject(parameters);
            }
            Validate.notNull(callback, 'callback');
    
            // Integer Ids can not have any Id set
            for (var i in idNames) {
                var id = instance[idNames[i]];
    
                if (!_.isNullOrZero(id)) {
                    if (_.isString(id)) {
                        // String Id's are allowed iif using 'id'
                        if (idNames[i] !== idPropertyName) {
                            throw new Error('Cannot insert if the ' + idPropertyName + ' member is already set.');
                        } else {
                            Validate.isValidId(id, idPropertyName);
                        }
                    } else {
                        throw new Error('Cannot insert if the ' + idPropertyName + ' member is already set.');
                    }
                }
            }
    
            var features = this._features || [];
            features = addQueryParametersFeaturesIfApplicable(features, parameters);
    
            // Construct the URL
            var urlFragment = _.url.combinePathSegments(tableRouteSeperatorName, this.getTableName());
            if (!_.isNull(parameters)) {
                var queryString = _.url.getQueryString(parameters);
                urlFragment = _.url.combinePathAndQuery(urlFragment, queryString);
            }
    
            var headers = { };
            headers[constants.apiVersionHeaderName] = constants.apiVersion;
    
            // Make the request
            this.getMobileServiceClient()._request(
                'POST',
                urlFragment,
                instance,
                false,
                headers,
                features,
                function (error, response) {
                    if (!_.isNull(error)) {
                        callback(error, null);
                    } else {
                        var result = getItemFromResponse(response);
                        result = Platform.allowPlatformToMutateOriginal(instance, result);
                        callback(null, result);
                    }
                });
        });
    
    /**
     * Update an object / record in the backend table.
     * 
     * @function
     * @instance
     * @public
     * @memberof MobileServiceTable
     * 
     * @param {object} instance New value of the object / record.
     * @param {string | number} instance.id The id of the object / record identifies the record that will be updated in the table.
     * @param {object} parameters An object of user-defined parameters and values to include in the request URI query string.
     * 
     * @returns {Promise} A promise that is resolved when the operation is completed successfully.
     *                    If the operation fails, the promise is rejected with the error.
     */
    MobileServiceTable.prototype.update = Platform.async(
        function (instance, parameters, callback) {
            var version,
                headers = {},
                features = this._features || [],
                serverInstance;
    
            // Account for absent optional arguments
            if (_.isNull(callback) && (typeof parameters === 'function')) {
                callback = parameters;
                parameters = null;
            }
    
            // Validate the arguments
            Validate.notNull(instance, 'instance');
            Validate.isValidId(instance[idPropertyName], 'instance.' + idPropertyName);
            if (!_.isNull(parameters)) {
                Validate.isValidParametersObject(parameters, 'parameters');
            }
            Validate.notNull(callback, 'callback');
    
            version = instance[MobileServiceSystemColumns.Version];
            serverInstance = removeSystemProperties(instance);
    
            if (!_.isNullOrEmpty(version)) {
                headers['If-Match'] = getEtagFromVersion(version);
                features.push(constants.features.OptimisticConcurrency);
            }
    
            headers[constants.apiVersionHeaderName] = constants.apiVersion;
    
            features = addQueryParametersFeaturesIfApplicable(features, parameters);
    
            // Construct the URL
            var urlFragment =  _.url.combinePathSegments(
                    tableRouteSeperatorName,
                    this.getTableName(),
                    encodeURIComponent(instance[idPropertyName].toString()));
            if (!_.isNull(parameters)) {
                var queryString = _.url.getQueryString(parameters);
                urlFragment = _.url.combinePathAndQuery(urlFragment, queryString);
            }
    
            // Make the request
            this.getMobileServiceClient()._request(
                'PATCH',
                urlFragment,
                serverInstance,
                false,
                headers,
                features,
                function (error, response) {
                    if (!_.isNull(error)) {
                        setServerItemIfPreconditionFailed(error);
                        callback(error);
                    } else {
                        var result = getItemFromResponse(response);
                        result = Platform.allowPlatformToMutateOriginal(instance, result);
                        callback(null, result);
                    }
                });
        });
    
    MobileServiceTable.prototype.refresh = Platform.async(
        function (instance, parameters, callback) {
            /// <summary>
            ///  Refresh the current instance with the latest values from the
            ///  table.
            /// </summary>
            /// <param name="instance" type="Object">
            /// The instance to refresh.
            /// </param>
            /// <param name="parameters" type="Object" mayBeNull="true">
            /// An object of user-defined parameters and values to include in the request URI query string.
            /// </param>
            /// <param name="callback" type="Function">
            /// The callback to invoke when the refresh is complete.
            /// </param>
    
            // Account for absent optional arguments
            if (_.isNull(callback) && (typeof parameters === 'function')) {
                callback = parameters;
                parameters = null;
            }
    
            // Validate the arguments
            Validate.notNull(instance, 'instance');
            if (!_.isValidId(instance[idPropertyName], idPropertyName))
            {
                if (typeof instance[idPropertyName] === 'string' && instance[idPropertyName] !== '') {
                    throw new Error(idPropertyName + ' "' + instance[idPropertyName] + '" is not valid.');
                } else {
                    callback(null, instance);
                }
                return;
            }
    
            if (!_.isNull(parameters)) {
                Validate.isValidParametersObject(parameters, 'parameters');
            }
            Validate.notNull(callback, 'callback');
    
            // Construct the URL
            var urlFragment = _.url.combinePathSegments(
                    tableRouteSeperatorName,
                    this.getTableName());
    
            if (typeof instance[idPropertyName] === 'string') {
                var id = encodeURIComponent(instance[idPropertyName]).replace(/\'/g, '%27%27');
                urlFragment = _.url.combinePathAndQuery(urlFragment, "?$filter=id eq '" + id + "'");
            } else {
                urlFragment = _.url.combinePathAndQuery(urlFragment, "?$filter=id eq " + encodeURIComponent(instance[idPropertyName].toString()));
            }
    
            if (!_.isNull(parameters)) {
                var queryString = _.url.getQueryString(parameters);
                urlFragment = _.url.combinePathAndQuery(urlFragment, queryString);
            }
    
            var features = this._features || [];
            features.push(constants.features.TableRefreshCall);
            features = addQueryParametersFeaturesIfApplicable(features, parameters);
    
            var headers = { };
            headers[constants.apiVersionHeaderName] = constants.apiVersion;
    
            // Make the request
            this.getMobileServiceClient()._request(
                'GET',
                urlFragment,
                instance,
                false,
                headers,
                features,
                function (error, response) {
                    if (!_.isNull(error)) {
                        callback(error, null);
                    } else {
                        var result = _.fromJson(response.responseText);
                        if (Array.isArray(result)) {
                            result = result[0]; //get first object from array
                        }
    
                        if (!result) {
                            var message =_.format(
                                Platform.getResourceString("MobileServiceTable_NotSingleObject"),
                                idPropertyName);
                            callback(new Error(message), null);
                        }
    
                        result = Platform.allowPlatformToMutateOriginal(instance, result);
                        callback(null, result);
                    }
                });
        });
    
    /**
     * Looks up an object / record in the backend table using the object id.
     * 
     * @function
     * @instance
     * @public
     * @memberof MobileServiceTable
     * 
     * @param {string} id id of the object to be looked up in the backend table.
     * @param {object} parameters An object of user-defined parameters and values to include in the request URI query string.
     * 
     * @returns {Promise} A promise that is resolved with the looked up object when the lookup is completed successfully.
     *                    If the operation fails, the promise is rejected with the error.
     */
    MobileServiceTable.prototype.lookup = Platform.async(
        function (id, parameters, callback) {
            /// <summary>
            /// Gets an instance from a given table.
            /// </summary>
            /// <param name="id" type="Number" integer="true">
            /// The id of the instance to get from the table.
            /// </param>
            /// <param name="parameters" type="Object" mayBeNull="true">
            /// An object of user-defined parameters and values to include in the request URI query string.
            /// </param>
            /// <param name="callback" type="Function">
            /// The callback to invoke when the lookup is complete.
            /// </param>
    
            // Account for absent optional arguments
            if (_.isNull(callback) && (typeof parameters === 'function')) {
                callback = parameters;
                parameters = null;
            }
    
            // Validate the arguments
            Validate.isValidId(id, idPropertyName);
            if (!_.isNull(parameters)) {
                Validate.isValidParametersObject(parameters);
            }
            Validate.notNull(callback, 'callback');
    
            // Construct the URL
            var urlFragment = _.url.combinePathSegments(
                    tableRouteSeperatorName,
                    this.getTableName(),
                    encodeURIComponent(id.toString()));
    
            var features = this._features || [];
            features = addQueryParametersFeaturesIfApplicable(features, parameters);
    
            if (!_.isNull(parameters)) {
                var queryString = _.url.getQueryString(parameters);
                urlFragment = _.url.combinePathAndQuery(urlFragment, queryString);
            }
    
            var headers = { };
            headers[constants.apiVersionHeaderName] = constants.apiVersion;
    
            // Make the request
            this.getMobileServiceClient()._request(
                'GET',
                urlFragment,
                null,
                false,
                headers,
                features,
                function (error, response) {
                    if (!_.isNull(error)) {
                        callback(error, null);
                    } else {
                        var result = getItemFromResponse(response);
                        callback(null, result);
                    }
                });
        });
    
    /**
     * Deletes an object / record from the backend table.
     * 
     * @function
     * @instance
     * @public
     * @memberof MobileServiceTable
     * 
     * @param {object} instance The object to delete from the backend table. 
     * @param {string} instance.id id of the record to be deleted.
     * @param {object} parameters An object of user-defined parameters and values to include in the request URI query string.
     * 
     * @returns {Promise} A promise that is resolved when the delete operation completes successfully.
     *                    If the operation fails, the promise is rejected with the error.
     */
    MobileServiceTable.prototype.del = Platform.async(
        function (instance, parameters, callback) {
    
            // Account for absent optional arguments
            if (_.isNull(callback) && (typeof parameters === 'function')) {
                callback = parameters;
                parameters = null;
            }        
    
            // Validate the arguments
            Validate.notNull(instance, 'instance');
            Validate.isValidId(instance[idPropertyName], 'instance.' + idPropertyName);
            Validate.notNull(callback, 'callback');
    
            var headers = {};
            var features = this._features || [];
            if (_.isString(instance[idPropertyName])) {
                if (!_.isNullOrEmpty(instance[MobileServiceSystemColumns.Version])) {
                    headers['If-Match'] = getEtagFromVersion(instance[MobileServiceSystemColumns.Version]);
                    features.push(constants.features.OptimisticConcurrency);
                }
            }
            headers[constants.apiVersionHeaderName] = constants.apiVersion;
    
            features = addQueryParametersFeaturesIfApplicable(features, parameters);
    
            if (!_.isNull(parameters)) {
                Validate.isValidParametersObject(parameters);
            }
    
            // Contruct the URL
            var urlFragment =  _.url.combinePathSegments(
                    tableRouteSeperatorName,
                    this.getTableName(),
                    encodeURIComponent(instance[idPropertyName].toString()));
            if (!_.isNull(parameters)) {
                var queryString = _.url.getQueryString(parameters);
                urlFragment = _.url.combinePathAndQuery(urlFragment, queryString);
            }
    
            // Make the request
            this.getMobileServiceClient()._request(
                'DELETE',
                urlFragment,
                null,
                false,
                headers,
                features,
                function (error, response) {
                    if (!_.isNull(error)) {
                        setServerItemIfPreconditionFailed(error);
                    }
                    callback(error);
                });
        });
    
    // Define query operators
    tableHelper.defineQueryOperators(MobileServiceTable);
    
    // Table system properties
    function removeSystemProperties(instance) {
        var copy = {};
        for (var property in instance) {
            if ((property != MobileServiceSystemColumns.Version) &&
                (property != MobileServiceSystemColumns.UpdatedAt) &&
                (property != MobileServiceSystemColumns.CreatedAt) &&
                (property != MobileServiceSystemColumns.Deleted))
            {
                copy[property] = instance[property];
            }
        }
        return copy;
    }
    
    // Add double quotes and unescape any internal quotes
    function getItemFromResponse(response) {
        var result = _.fromJson(response.responseText);
        if (response.getResponseHeader) {
            var eTag = response.getResponseHeader('ETag');
            if (!_.isNullOrEmpty(eTag)) {
                result[MobileServiceSystemColumns.Version] = getVersionFromEtag(eTag);
            }
        }
        return result;
    }
    
    // Converts an error to precondition failed error
    function setServerItemIfPreconditionFailed(error) {
        if (error.request && error.request.status === 412) {
            error.serverInstance = _.fromJson(error.request.responseText);
        }
    }
    
    // Add wrapping double quotes and escape all double quotes
    function getEtagFromVersion(version) {
        var result = version.replace(/\"/g, '\\\"');
        return "\"" + result + "\"";
    }
    
    // Remove surrounding double quotes and unescape internal quotes
    function getVersionFromEtag(etag) {
        var len = etag.length,
            result = etag;
    
        if (len > 1 && etag[0] === '"' && etag[len - 1] === '"') {
            result = etag.substr(1, len - 2);
        }
        return result.replace(/\\\"/g, '"');
    }
    
    // Updates and returns the headers parameters with features used in the call
    function addQueryParametersFeaturesIfApplicable(features, userQueryParameters) {
        var hasQueryParameters = false;
        if (userQueryParameters) {
            if (Array.isArray(userQueryParameters)) {
                hasQueryParameters = userQueryParameters.length > 0;
            } else if (_.isObject(userQueryParameters)) {
                for (var k in userQueryParameters) {
                    hasQueryParameters = true;
                    break;
                }
            }
        }
    
        if (hasQueryParameters) {
            features.push(constants.features.AdditionalQueryParameters);
        }
    
        return features;
    }
    
    // Define the module exports
    module.exports = MobileServiceTable;
    
    },{"./Platform":234,"./Utilities/Extensions":241,"./Utilities/Validate":244,"./constants":246,"./tableHelper":257,"azure-query-js":274}],227:[function(require,module,exports){
    // ----------------------------------------------------------------------------
    // Copyright (c) Microsoft Corporation. All rights reserved.
    // ----------------------------------------------------------------------------
    
    /**
     * @file SQLite implementation of the local store.
     * This uses the https://www.npmjs.com/package/cordova-sqlite-storage Cordova plugin.
     * @private
     */
     
    var Platform = require('.'),
        Validate = require('../../Utilities/Validate'),
        _ = require('../../Utilities/Extensions'),
        ColumnType = require('../../sync/ColumnType'),
        sqliteSerializer = require('./sqliteSerializer'),
        storeHelper = require('./storeHelper'),
        Query = require('azure-query-js').Query,
        formatSql = require('azure-odata-sql').format,
        taskRunner = require('../../Utilities/taskRunner'),
        idPropertyName = "id", // TODO: Add support for case insensitive ID and custom ID column
        defaultDbName = 'mobileapps.db';
    
    /**
     * @class
     * @classdesc A SQLite based implementation of {@link MobileServiceStore}.
     *            **Note** that this class is available **_only_** as part of the Cordova SDK.
     *       
     * @implements {MobileServiceStore}
     * @description Initializes a new instance of MobileServiceSqliteStore.
     * 
     * @param {string} [dbName] Name of the SQLite store file. If no name is specified, the default name will be used.
     */
    var MobileServiceSqliteStore = function (dbName) {
    
        // Guard against initialization without the new operator
        "use strict";
        if ( !(this instanceof MobileServiceSqliteStore) ) {
            return new MobileServiceSqliteStore(dbName);
        }
    
        if ( _.isNull(dbName) ) {
            dbName = defaultDbName;
        }
    
        var tableDefinitions = {},
            runner = taskRunner();
    
        /**
         * Initializes the store.
         * A handle to the underlying sqlite store will be opened as part of initialization.
         * 
         * @function
         * @instance
         * @memberof MobileServiceSqliteStore
         * 
         * @returns A promise that is resolved when the initialization is complete OR rejected if it fails.
         */
        this.init = function() {
            return runner.run(function() {
                return this._init();
            }.bind(this));
        };
    
        this._init = function() {
            var self = this;
            return Platform.async(function(callback) {
                if (self._db) {
                    return callback(); // already initialized.
                }
    
                var db = window.sqlitePlugin.openDatabase(
                    { name: dbName, location: 'default' },
                    function successcb() {
                        self._db = db; // openDatabase is complete, set self._db
                        callback();
                    },
                    callback
                );
            })();
        };
    
        /**
         * Closes the handle to the underlying sqlite store.
         * 
         * @function
         * @instance
         * @memberof MobileServiceSqliteStore
         * 
         * @returns A promise that is resolved when the sqlite store is closed successfully OR rejected if it fails.
         */
        this.close = function() {
            var self = this;
            return runner.run(function() {
                if (!self._db) {
                    return; // nothing to close
                }
    
                return Platform.async(function(callback) {
                    self._db.close(function successcb() {
                        self._db = undefined;
                        callback();
                    },
                    callback);
                })();
            });
        };
    
        /**
         * @inheritdoc
         */
        this.defineTable = function (tableDefinition) {
            var self = this;
            return runner.run(function() {
                storeHelper.validateTableDefinition(tableDefinition);
    
                tableDefinition = JSON.parse(JSON.stringify(tableDefinition)); // clone the table definition as we will need it later
    
                // Initialize the store before defining the table
                // If the store is already initialized, calling init() will have no effect. 
                return self._init().then(function() {
                    return Platform.async(function(callback) {
                        self._db.transaction(function(transaction) {
    
                            // Get the table information
                            var pragmaStatement = _.format("PRAGMA table_info({0});", tableDefinition.name);
                            transaction.executeSql(pragmaStatement, [], function (transaction, result) {
    
                                // Check if a table with the specified name exists 
                                if (result.rows.length > 0) { // table already exists, add missing columns.
    
                                    // Get a list of columns present in the SQLite table
                                    var existingColumns = {};
                                    for (var i = 0; i < result.rows.length; i++) {
                                        var column = result.rows.item(i);
                                        existingColumns[column.name.toLowerCase()] = true;
                                    }
    
                                    addMissingColumns(transaction, tableDefinition, existingColumns);
                                    
                                } else { // table does not exist, create it.
                                    createTable(transaction, tableDefinition);
                                }
                            });
    
                        },
                        callback,
                        function(result) {
                            // Table definition is successful, update the in-memory list of table definitions.
                            var error; 
                            try {
                                storeHelper.addTableDefinition(tableDefinitions, tableDefinition);
                            } catch (err) {
                                error = err;
                            }
                            callback(error);
                        });
                    })();
                });
            });
        };
    
        /**
         * @inheritdoc
         */
        this.upsert = function (tableName, data) {
            var self = this;
            return runner.run(function() {
                return Platform.async(function(callback) {
                    self._db.transaction(function(transaction) {
                        self._upsert(transaction, tableName, data);
                    },
                    callback,
                    callback);
                })();
            });
        };
        
        // Performs the upsert operation.
        // This method validates all arguments, callers can skip validation. 
        this._upsert = function (transaction, tableName, data) {
    
            Validate.isObject(transaction);
            Validate.notNull(transaction);
            Validate.isString(tableName, 'tableName');
            Validate.notNullOrEmpty(tableName, 'tableName');
    
            var tableDefinition = storeHelper.getTableDefinition(tableDefinitions, tableName);
            if (_.isNull(tableDefinition)) {
                throw new Error('Definition not found for table "' + tableName + '"');
            }
    
            // If no data is provided, there is nothing more to be done.
            if (_.isNull(data)) {
                return;
            }
    
            Validate.isObject(data);
    
            // Compute the array of records to be upserted.
            var records;
            if (!_.isArray(data)) {
                records = [data];
            } else {
                records = data;
            }
    
            // Serialize the records to a format that can be stored in SQLite.
            for (var i = 0; i < records.length; i++) {
                // Skip null or undefined record objects
                if (!_.isNull(records[i])) {
                    Validate.isValidId(storeHelper.getId(records[i]), 'records[' + i + '].' + idPropertyName);
                    records[i] = sqliteSerializer.serialize(records[i], tableDefinition.columnDefinitions);
                }
            }
    
    
            // Note: The default maximum number of parameters allowed by sqlite is 999
            // Refer http://www.sqlite.org/limits.html#max_variable_number
            // TODO: Add support for tables with more than 999 columns
            if (tableDefinition.columnDefinitions.length > 999) {
                throw new Error("Number of table columns cannot be more than 999");
            }
    
            var statements = [], // INSERT & UPDATE statements for each record we want to upsert
                parameters = [], // INSERT & UPDATE parameters for each record we want to upsert
                record,
                insertColumnNames = [],
                insertParams = [],
                insertValues = [],
                updateColumnNames = [],
                updateExpressions = [],
                updateValues = [];
    
            for (i = 0; i < records.length; i++) {
    
                if (_.isNull(records[i])) {
                    continue;
                }
                
                record = records[i];
    
                // Reset the variables dirtied in the previous iteration of the loop.
                insertColumnNames = [];
                insertParams = [];
                insertValues = [];
                updateColumnNames = [];
                updateExpressions = [];
                updateValues = [];
    
                for (var property in record) {
                    insertColumnNames.push(property);
                    insertParams.push('?');
                    insertValues.push(record[property]);
                    
                    if (!storeHelper.isId(property)) {
                        updateColumnNames.push(property);
                        updateExpressions.push(property + ' = ?');
                        updateValues.push(record[property]);
                    }
                }
                
                // Insert the instance. If one with the same id already exists, ignore it.
                statements.push(_.format("INSERT OR IGNORE INTO {0} ({1}) VALUES ({2})", tableName, insertColumnNames.join(), insertParams.join()));
                parameters.push(insertValues);
    
                // If there is any property other than id that needs to be upserted, update the record.
                if (updateValues.length > 0) {
                    statements.push(_.format("UPDATE {0} SET {1} WHERE {2} = ?", tableName, updateExpressions.join(), idPropertyName));
                    updateValues.push(storeHelper.getId(record)); // Add value of record ID as the last parameter.. for the WHERE clause in the statement.
                    parameters.push(updateValues);
                }
            }
    
            // Execute the INSERT and UPDATE statements.
            for (i = 0; i < statements.length; i++) {
                if (this._editStatement) { // test hook
                    statements[i] = this._editStatement(statements[i]);
                }
                transaction.executeSql(statements[i], parameters[i]);
            }
        };
    
        /** 
         * @inheritdoc
         */
        this.lookup = function (tableName, id, suppressRecordNotFoundError) {
            var self = this;
            return runner.run(function() {
                // Validate the arguments
                Validate.isString(tableName, 'tableName');
                Validate.notNullOrEmpty(tableName, 'tableName');
                Validate.isValidId(id, 'id');
                
                var tableDefinition = storeHelper.getTableDefinition(tableDefinitions, tableName);
                if (_.isNull(tableDefinition)) {
                    throw new Error('Definition not found for table "' + tableName + '"');
                }
    
                var lookupStatement = _.format("SELECT * FROM [{0}] WHERE {1} = ? COLLATE NOCASE", tableName, idPropertyName);
    
                return Platform.async(function(callback) {
                    self._db.executeSql(lookupStatement, [id], function (result) {
                        var error,
                            record;
                        try {
                            if (result.rows.length !== 0) {
                                record = result.rows.item(0);
                            }
    
                            if (record) {
                                // Deserialize the record read from the SQLite store into its original form.
                                record = sqliteSerializer.deserialize(record, tableDefinition.columnDefinitions);
                            } else if (!suppressRecordNotFoundError) {
                                throw new Error('Item with id "' + id + '" does not exist.');
                            }
                        } catch (err) {
                            error = err;
                        }
    
                        if (error) {
                            callback(error);
                        } else {
                            callback(null, record);
                        }
                    },
                    callback);
                })();
            });
        };
    
        /**
         * @inheritdoc
         */
        this.del = function (tableNameOrQuery, ids) {
            var self = this;
            return runner.run(function() {
                return Platform.async(function(callback) {
                    // Validate parameters
                    Validate.notNull(tableNameOrQuery);
    
                    if (_.isString(tableNameOrQuery)) { // tableNameOrQuery is table name, delete records with specified IDs.
                        Validate.notNullOrEmpty(tableNameOrQuery, 'tableNameOrQuery');
    
                        // If a single id is specified, convert it to an array and proceed.
                        // Detailed validation of individual IDs in the array will be taken care of later.
                        if (!_.isArray(ids)) {
                            ids = [ids];
                        }
                        
                        self._db.transaction(function(transaction) {
                            for (var i = 0; i < ids.length; i++) {
                                if (! _.isNull(ids[i])) {
                                    Validate.isValidId(ids[i]);
                                }
                            }
                            self._deleteIds(transaction, tableNameOrQuery /* table name */, ids);
                        },
                        callback,
                        callback);
    
                    } else if (_.isObject(tableNameOrQuery)) { // tableNameOrQuery is a query, delete all records specified by the query.
                        self._deleteUsingQuery(tableNameOrQuery /* query */, callback);
                    } else { // error
                        throw _.format(Platform.getResourceString("TypeCheckError"), 'tableNameOrQuery', 'Object or String', typeof tableNameOrQuery);
                    }
                })();
            });
        };
        
        // Deletes the records selected by the specified query and notifies the callback.
        this._deleteUsingQuery = function (query, callback) {
            var self = this;
        
            // The query can have a 'select' clause that queries only specific columns. However, we need to know the ID value
            // to be able to delete records. So we explicitly set selection to just the ID column.
            var components = query.getComponents();
            components.selections = [idPropertyName];
            query.setComponents(components);
    
            var tableName = components.table;
            Validate.isString(tableName);
            Validate.notNullOrEmpty(tableName);
    
            var tableDefinition = storeHelper.getTableDefinition(tableDefinitions, tableName);
            if (_.isNull(tableDefinition)) {
                throw new Error('Definition not found for table "' + tableName + '"');
            }
    
            var statements = getSqlStatementsFromQuery(query);
    
            // If the query requests the result count we expect 2 SQLite statements. Else, we expect a single statement.
            if (statements.length < 1 || statements.length > 2) {
                throw new Error('Unexpected number of statements');
            }
    
            self._db.transaction(function (transaction) {
    
                // The first statement gets the query results. Execute it.
                // Second statement, if any, is for geting the result count. Ignore it.
                // TODO: Figure out a better way to determine what the statements in the array correspond to.
                var deleteStatement = _.format("DELETE FROM [{0}] WHERE [{1}] in ({2})", tableName, idPropertyName, statements[0].sql);
                // Example deleteStatement: DELETE FROM [mytable] where [id] IN (SELECT [id] FROM [mytable] WHERE [language] = 'javascript')
                
                transaction.executeSql(deleteStatement, getStatementParameters(statements[0]));
            },
            callback,
            callback);
        };
    
        // Delete records from the table that match the specified IDs.
        this._deleteIds = function (transaction, tableName, ids) {
            var deleteExpressions = [],
                deleteParams = [];
            for (var i = 0; i < ids.length; i++) {
                if (!_.isNull(ids[i])) {
                    deleteExpressions.push('?');
                    deleteParams.push(ids[i]);
                }
            }
            
            var deleteStatement = _.format("DELETE FROM {0} WHERE {1} in ({2})", tableName, idPropertyName, deleteExpressions.join());
            if (this._editStatement) { // test hook
                deleteStatement = this._editStatement(deleteStatement);
            }
            transaction.executeSql(deleteStatement, deleteParams);
        };
    
        /**
         * @inheritdoc
         */
        this.read = function (query) {
            return runner.run(function() {
                Validate.notNull(query, 'query');
                Validate.isObject(query, 'query');
    
                return this._read(query);
            }.bind(this));
        };
    
        this._read = function (query) {
            return Platform.async(function(callback) {
    
                var tableDefinition = storeHelper.getTableDefinition(tableDefinitions, query.getComponents().table);
                if (_.isNull(tableDefinition)) {
                    throw new Error('Definition not found for table "' + query.getComponents().table + '"');
                }
    
                var count,
                    result = [],
                    statements = getSqlStatementsFromQuery(query);
    
                this._db.transaction(function (transaction) {
    
                    // If the query requests the result count we expect 2 SQLite statements. Else, we expect a single statement.
                    if (statements.length < 1 || statements.length > 2) {
                        throw new Error('Unexpected number of statements');
                    }
    
                    // The first statement gets the query results. Execute it.
                    // TODO: Figure out a better way to determine what the statements in the array correspond to.    
                    transaction.executeSql(statements[0].sql, getStatementParameters(statements[0]), function (transaction, res) {
                        var record;
                        for (var j = 0; j < res.rows.length; j++) {
                            // Deserialize the record read from the SQLite store into its original form.
                            record = sqliteSerializer.deserialize(res.rows.item(j), tableDefinition.columnDefinitions);
                            result.push(record);
                        }
                    });
    
                    // Check if there are multiple statements. If yes, the second is for the result count.
                    if (statements.length === 2) {
                        transaction.executeSql(statements[1].sql, getStatementParameters(statements[1]), function (transaction, res) {
                            count = res.rows.item(0).count;
                        });
                    }
                },
                callback,
                function () {
                    // If we fetched the record count, combine the records and the count into an object.
                    if (count !== undefined) {
                        result = {
                            result: result,
                            count: count
                        };
                    }
                    callback(null, result);
                });
            }.bind(this))();
        };
        
        /**
         * @inheritdoc
         */
        this.executeBatch = function (operations) {
            var self = this;
            return runner.run(function() {
                Validate.isArray(operations);
    
                return Platform.async(function(callback) {
                    self._db.transaction(function(transaction) {
                        for (var i = 0; i < operations.length; i++) {
                            var operation = operations[i];
                            
                            if (_.isNull(operation)) {
                                continue;
                            }
                            
                            Validate.isString(operation.action);
                            Validate.notNullOrEmpty(operation.action);
    
                            Validate.isString(operation.tableName);
                            Validate.notNullOrEmpty(operation.tableName);
                            
                            if (operation.action.toLowerCase() === 'upsert') {
                                self._upsert(transaction, operation.tableName, operation.data);
                            } else if (operation.action.toLowerCase() === 'delete') {
                                if ( ! _.isNull(operation.id) ) {
                                    Validate.isValidId(operation.id);
                                    self._deleteIds(transaction, operation.tableName, [operation.id]);
                                }
                            } else {
                                throw new Error(_.format("Operation '{0}' is not supported", operation.action));
                            }
                        }
                    },
                    callback,
                    callback);
                })();
            });
        };
    };
    
    // Converts the QueryJS object into equivalent SQLite statements
    function getSqlStatementsFromQuery(query) {
        
        // Convert QueryJS object to an OData query string
        var odataQuery = Query.Providers.OData.toOData(query);
        
        // Convert the OData query string into equivalent SQLite statements
        var statements = formatSql(odataQuery, { flavor: 'sqlite' });
        
        return statements;
    }
    
    // Gets the parameters from a statement defined by azure-odata-sql
    function getStatementParameters(statement) {
        var params = [];
    
        if (statement.parameters) {
            statement.parameters.forEach(function (param) {
                params.push(sqliteSerializer.serializeValue(param.value));
            });
        }
    
        return params;
    }
    
    // Creates a table as per the specified definition and as part of the specified SQL transaction. 
    function createTable(transaction, tableDefinition) {
    
        var columnDefinitions = tableDefinition.columnDefinitions;
        var columnDefinitionClauses = [];
    
        for (var columnName in columnDefinitions) {
            var columnType = storeHelper.getColumnType(columnDefinitions, columnName);
    
            var columnDefinitionClause = _.format("[{0}] {1}", columnName, sqliteSerializer.getSqliteType(columnType));
    
            if (storeHelper.isId(columnName)) {
                columnDefinitionClause += " PRIMARY KEY";
            }
    
            columnDefinitionClauses.push(columnDefinitionClause);
        }
        
        var createTableStatement = _.format("CREATE TABLE [{0}] ({1})", tableDefinition.name, columnDefinitionClauses.join());
    
        transaction.executeSql(createTableStatement);
    }
    
    // Alters the table to add the missing columns
    function addMissingColumns(transaction, tableDefinition, existingColumns) {
    
        // Add necessary columns to the table
        var columnDefinitions = tableDefinition.columnDefinitions;
        for (var columnName in columnDefinitions) {
    
            // If this column does not already exist, we need to create it.
            // SQLite does not support adding multiple columns using a single statement. Add one column at a time.
            if (!existingColumns[columnName.toLowerCase()]) {
                var alterStatement = _.format("ALTER TABLE {0} ADD COLUMN {1} {2}", tableDefinition.name, columnName, storeHelper.getColumnType(columnDefinitions, columnName));
                transaction.executeSql(alterStatement);
            }
        }
    }
    
    // Valid Column types
    MobileServiceSqliteStore.ColumnType = ColumnType;
    
    // Define the module exports
    module.exports = MobileServiceSqliteStore;
    
    },{".":228,"../../Utilities/Extensions":241,"../../Utilities/Validate":244,"../../Utilities/taskRunner":245,"../../sync/ColumnType":249,"./sqliteSerializer":230,"./storeHelper":231,"azure-odata-sql":264,"azure-query-js":274}],228:[function(require,module,exports){
    // ----------------------------------------------------------------------------
    // Copyright (c) Microsoft Corporation. All rights reserved.
    // ----------------------------------------------------------------------------
    
    /**
     * Defines Cordova implementation of target independent APIs.
     * For now, the browser implementation works as-is for Cordova, so we 
     * just reuse the browser definitions.
     * @private
     */
    
    var browserExports = require('../web');
    
    // Copy the browser exports into the exports object for Cordova, instead of module.exports = browserExports.
    // This way we can add more exports to module.exports (in the future) without having to worry about 
    // having an unintended side effect on the browser exports. 
    for (var i in browserExports) {
        exports[i] = browserExports[i];
    }
    
    
    },{"../web":236}],229:[function(require,module,exports){
    // ----------------------------------------------------------------------------
    // Copyright (c) Microsoft Corporation. All rights reserved.
    // ----------------------------------------------------------------------------
    
    // Cordova specific modules that need to be exposed outside the SDK
    module.exports = {
        MobileServiceSqliteStore: require('./MobileServiceSqliteStore')
    };
    
    },{"./MobileServiceSqliteStore":227}],230:[function(require,module,exports){
    // ----------------------------------------------------------------------------
    // Copyright (c) Microsoft Corporation. All rights reserved.
    // ----------------------------------------------------------------------------
    
    /**
     * @file Defines functions for serializing a JS object into an object that can be used for storing in a SQLite table and
     *       for deserializing a row / object read from a SQLite table into a JS object. The target type of a serialization or
     *       a deserialization operation is determined by the specified column definition.
     * @private
     */
    
    var Platform = require('.'),
        Validate = require('../../Utilities/Validate'),
        _ = require('../../Utilities/Extensions'),
        ColumnType = require('../../sync/ColumnType'),
        storeHelper = require('./storeHelper'),
        verror = require('verror'),
        typeConverter = require('./typeConverter');
    
    /**
     * Gets the SQLite type that matches the specified ColumnType.
     * @private
     * @param columnType - The type of values that will be stored in the SQLite table
     * @throw Will throw an error if columnType is not supported 
     */
    function getSqliteType (columnType) {
        var sqliteType;
    
        switch (columnType) {
            case ColumnType.Object:
            case ColumnType.Array:
            case ColumnType.String:
            case ColumnType.Text:
                sqliteType = "TEXT";
                break;
            case ColumnType.Integer:
            case ColumnType.Int:
            case ColumnType.Boolean:
            case ColumnType.Bool:
            case ColumnType.Date:
                sqliteType = "INTEGER";
                break;
            case ColumnType.Real:
            case ColumnType.Float:
                sqliteType = "REAL";
                break;
            default:
                throw new Error('Column type ' + columnType + ' is not supported');
        }
    
        return sqliteType;
    }
    
    /**
     * Checks if the value can be stored in a table column of the specified type.
     * Example: Float values can be stored in column of type ColumnType.Float but not ColumnType.Integer. 
     * @private
     */
    function isJSValueCompatibleWithColumnType(value, columnType) {
        
        // Allow NULL values to be stored in columns of any type
        if (_.isNull(value)) {
            return true;
        }
        
        switch (columnType) {
            case ColumnType.Object:
                return _.isObject(value);
            case ColumnType.Array:
                return _.isArray(value);
            case ColumnType.String:
            case ColumnType.Text:
                return true; // Allow any value to be stored in a string column
            case ColumnType.Boolean:
            case ColumnType.Bool:
            case ColumnType.Integer:
            case ColumnType.Int:
                return _.isBool(value) || _.isInteger(value);
            case ColumnType.Date:
                return _.isDate(value);
            case ColumnType.Real:
            case ColumnType.Float:
                return _.isNumber(value);
            default:
                return false;
        }
    }
    
    /**
     * Checks if the SQLite value matches the specified ColumnType.
     * A value read from a SQLite table can be incompatible with the specified column type, if it was stored
     * in the table using a column type different from columnType.
     * Example: If a non-integer numeric value is stored in a column of type ColumnType.Float and 
     * then deserialized into a column of type ColumnType.Integer, that will be an error. 
     * @private
     */
    function isSqliteValueCompatibleWithColumnType(value, columnType) {
        
        // Null is a valid value for any column type
        if (_.isNull(value)) {
            return true;
        }
        
        switch (columnType) {
            case ColumnType.Object:
                return _.isString(value);
            case ColumnType.Array:
                return _.isString(value);
            case ColumnType.String:
            case ColumnType.Text:
                return _.isString(value);
            case ColumnType.Boolean:
            case ColumnType.Bool:
                return _.isInteger(value);
            case ColumnType.Integer:
            case ColumnType.Int:
                return _.isInteger(value);
            case ColumnType.Date:
                return _.isInteger(value);
            case ColumnType.Real:
            case ColumnType.Float:
                return _.isNumber(value);
            default:
                return false;
        }
    }
    
    /**
     * Checks if type is a supported ColumnType
     * @private
     */
    function isColumnTypeValid(type) {
        for (var key in ColumnType) {
            if (ColumnType[key] === type) {
                return true;
            }
        }
        return false;
    }
    
    /**
     * Serializes an object into an object that can be stored in a SQLite table, as defined by columnDefinitions.
     * @private
     */
    function serialize (value, columnDefinitions) {
    
        var serializedValue = {};
    
        try {
            Validate.notNull(columnDefinitions, 'columnDefinitions');
            Validate.isObject(columnDefinitions);
            
            Validate.notNull(value);
            Validate.isObject(value);
    
            for (var property in value) {
    
                var columnType = storeHelper.getColumnType(columnDefinitions, property);
                // Skip properties that don't match any column in the table 
                if (!_.isNull(columnType)) {
                    serializedValue[property] = serializeMember(value[property], columnType);
                }
            }
            
        } catch (error) {
            throw new verror.VError(error, 'Failed to serialize value ' + JSON.stringify(value) + '. Column definitions: ' + JSON.stringify(columnDefinitions));
        }
    
        return serializedValue;
    }
    
    /**
     * Deserializes a row read from a SQLite table into a Javascript object, as defined by columnDefinitions.
     * @private
     */
    function deserialize (value, columnDefinitions) {
    
        var deserializedValue = {};
        
        try {
            Validate.notNull(columnDefinitions, 'columnDefinitions');
            Validate.isObject(columnDefinitions);
    
            Validate.notNull(value);
            Validate.isObject(value);
    
            for (var property in value) {
                var columnName = storeHelper.getColumnName(columnDefinitions, property); // this helps us deserialize with proper case for the property name
                deserializedValue[columnName] = deserializeMember(value[property], storeHelper.getColumnType(columnDefinitions, property));
            }
            
        } catch (error) {
            throw new verror.VError(error, 'Failed to deserialize value ' + JSON.stringify(value) + '. Column definitions: ' + JSON.stringify(columnDefinitions));
        }
    
        return deserializedValue;
    }
    
    /**
     * Serializes a property of an object into a value which can be stored in a SQLite column of type columnType. 
     * @private
     */
    function serializeMember(value, columnType) {
        
        // Start by checking if the specified column type is valid
        if (!isColumnTypeValid(columnType)) {
            throw new Error('Column type ' + columnType + ' is not supported');
        }
    
        // Now check if the specified value can be stored in a column of type columnType
        if (!isJSValueCompatibleWithColumnType(value, columnType)) {
            throw new Error('Converting value ' + JSON.stringify(value) + ' of type ' + typeof value + ' to type ' + columnType + ' is not supported.');
        }
    
        // If we are here, it means we are good to proceed with serialization
        
        var sqliteType = getSqliteType(columnType),
            serializedValue;
        
        switch (sqliteType) {
            case "TEXT":
                serializedValue = typeConverter.convertToText(value);
                break;
            case "INTEGER":
                serializedValue = typeConverter.convertToInteger(value);
                break;
            case "REAL":
                serializedValue = typeConverter.convertToReal(value);
                break;
            default:
                throw new Error('Column type ' + columnType + ' is not supported');
        }
        
        return serializedValue;
    }
    
    // Deserializes a property of an object read from SQLite into a value of type columnType
    function deserializeMember(value, columnType) {
        
        // Handle this special case first.
        // Simply return 'value' if a corresponding columnType is not defined.   
        if (!columnType) {
            return value;
        }
    
        // Start by checking if the specified column type is valid.
        if (!isColumnTypeValid(columnType)) {
                throw new Error('Column type ' + columnType + ' is not supported');
        }
    
        // Now check if the specified value can be stored in a column of type columnType.
        if (!isSqliteValueCompatibleWithColumnType(value, columnType)) {
            throw new Error('Converting value ' + JSON.stringify(value) + ' of type ' + typeof value +
                                ' to type ' + columnType + ' is not supported.');
        }
    
        // If we are here, it means we are good to proceed with deserialization
        
        var deserializedValue, error;
    
        switch (columnType) {
            case ColumnType.Object:
                deserializedValue = typeConverter.convertToObject(value);
                break;
            case ColumnType.Array:
                deserializedValue = typeConverter.convertToArray(value);
                break;
            case ColumnType.String:
            case ColumnType.Text:
                deserializedValue = typeConverter.convertToText(value);
                break;
            case ColumnType.Integer:
            case ColumnType.Int:
                deserializedValue = typeConverter.convertToInteger(value);
                break;
            case ColumnType.Boolean:
            case ColumnType.Bool:
                deserializedValue = typeConverter.convertToBoolean(value);
                break;
            case ColumnType.Date:
                deserializedValue = typeConverter.convertToDate(value);
                break;
            case ColumnType.Real:
            case ColumnType.Float:
                deserializedValue = typeConverter.convertToReal(value);
                break;
            default:
                throw new Error(_.format(Platform.getResourceString("sqliteSerializer_UnsupportedColumnType"), columnType));
        }
    
        return deserializedValue;
    }
    
    /**
     * Serializes a JS value to its equivalent that will be stored in the store.
     * This method is useful while querying to convert values to their store representations.
     * @private
     */
    function serializeValue(value) {
    
        var type;
        if ( _.isNull(value) ) {
            type = ColumnType.Object;
        } else if ( _.isNumber(value) ) {
            type = ColumnType.Real;
        } else if ( _.isDate(value) ) {
            type = ColumnType.Date;
        } else if ( _.isBool(value) ) {
            type = ColumnType.Boolean;
        } else if ( _.isString(value) ) {
            type = ColumnType.String;
        } else if ( _.isArray(value) ) {
            type = ColumnType.Array;
        } else if ( _.isObject(value) ) {
            type = ColumnType.Object;
        } else {
            type = ColumnType.Object;
        }
    
        return serializeMember(value, type);
    }
    
    exports.serialize = serialize;
    exports.serializeValue = serializeValue;
    exports.deserialize = deserialize;
    exports.getSqliteType = getSqliteType;
    
    },{".":228,"../../Utilities/Extensions":241,"../../Utilities/Validate":244,"../../sync/ColumnType":249,"./storeHelper":231,"./typeConverter":232,"verror":281}],231:[function(require,module,exports){
    // ----------------------------------------------------------------------------
    // Copyright (c) Microsoft Corporation. All rights reserved.
    // ----------------------------------------------------------------------------
    
    /**
     * @file Helper functions for performing store related operations
     * @private
     */
    
    var idPropertyName = require('../../constants').table.idPropertyName,
        Validate = require('../../Utilities/Validate');
    
    /**
     * Validates the table definition
     * @private
     */
    function validateTableDefinition(tableDefinition) {
        // Do basic table name validation and leave the rest to the store
        Validate.notNull(tableDefinition, 'tableDefinition');
        Validate.isObject(tableDefinition, 'tableDefinition');
    
        Validate.isString(tableDefinition.name, 'tableDefinition.name');
        Validate.notNullOrEmpty(tableDefinition.name, 'tableDefinition.name');
    
        // Validate the specified column types and check for duplicate columns
        var columnDefinitions = tableDefinition.columnDefinitions,
            definedColumns = {};
        
        Validate.isObject(columnDefinitions);
        Validate.notNull(columnDefinitions);
    
        for (var columnName in columnDefinitions) {
    
            Validate.isString(columnDefinitions[columnName], 'columnType');
            Validate.notNullOrEmpty(columnDefinitions[columnName], 'columnType');
    
            if (definedColumns[columnName.toLowerCase()]) {
                throw new Error('Duplicate definition for column ' + columnName + '" in table "' + tableDefinition.name + '"');
            }
    
            definedColumns[columnName.toLowerCase()] = true;
        }
    }
    
    /**
     * Adds a tableDefinition to the tableDefinitions object
     * @private
     */
    function addTableDefinition(tableDefinitions, tableDefinition) {
        Validate.isObject(tableDefinitions);
        Validate.notNull(tableDefinitions);
        validateTableDefinition(tableDefinition);
    
        tableDefinitions[tableDefinition.name.toLowerCase()] = tableDefinition;
    }
    
    /**
     * Gets the table definition for the specified table name from the tableDefinitions object
     * @private
     */
    function getTableDefinition(tableDefinitions, tableName) {
        Validate.isObject(tableDefinitions);
        Validate.notNull(tableDefinitions);
        Validate.isString(tableName);
        Validate.notNullOrEmpty(tableName);
    
        return tableDefinitions[tableName.toLowerCase()];
    }
    
    /**
     * Gets the type of the specified column
     * @private
     */
    function getColumnType(columnDefinitions, columnName) {
        Validate.isObject(columnDefinitions);
        Validate.notNull(columnDefinitions);
        Validate.isString(columnName);
        Validate.notNullOrEmpty(columnName);
    
        for (var column in columnDefinitions) {
            if (column.toLowerCase() === columnName.toLowerCase()) {
                return columnDefinitions[column];
            }
        }
    }
    
    /**
     * Returns the column name in the column definitions that matches the specified property
     * @private
     */
    function getColumnName(columnDefinitions, property) {
        Validate.isObject(columnDefinitions);
        Validate.notNull(columnDefinitions);
        Validate.isString(property);
        Validate.notNullOrEmpty(property);
    
        for (var column in columnDefinitions) {
            if (column.toLowerCase() === property.toLowerCase()) {
                return column;
            }
        }
    
        return property; // If no definition found for property, simply returns the column name as is
    }
    
    /**
     * Returns the Id property value OR undefined if none exists
     * @private
     */
    function getId(record) {
        Validate.isObject(record);
        Validate.notNull(record);
    
        for (var property in record) {
            if (property.toLowerCase() === idPropertyName.toLowerCase()) {
                return record[property];
            }
        }
    }
    
    /**
     * Checks if property is an ID property.
     * @private
     */
    function isId(property) {
        Validate.isString(property);
        Validate.notNullOrEmpty(property);
    
        return property.toLowerCase() === idPropertyName.toLowerCase();
    }
    
    module.exports = {
        addTableDefinition: addTableDefinition,
        getColumnName: getColumnName,
        getColumnType: getColumnType,
        getId: getId,
        getTableDefinition: getTableDefinition,
        isId: isId,
        validateTableDefinition: validateTableDefinition
    };
    
    },{"../../Utilities/Validate":244,"../../constants":246}],232:[function(require,module,exports){
    // ----------------------------------------------------------------------------
    // Copyright (c) Microsoft Corporation. All rights reserved.
    // ----------------------------------------------------------------------------
    
    /***
     * @file Defines converters for various data types.
     */
    
    var Validate = require('../../Utilities/Validate'),
        _ = require('../../Utilities/Extensions'),
        verror = require('verror');
    
    exports.convertToText = function (value) {
        
        if (_.isNull(value)) // undefined/null value should be converted to null
            return null;
    
        if (_.isString(value)) {
            return value;
        }
    
        return JSON.stringify(value);
    };
    
    exports.convertToInteger = function (value) {
    
        if (_.isNull(value)) // undefined/null value should be converted to null
            return null;
    
        if (_.isInteger(value)) {
            return value;
        }
    
        if (_.isBool(value)) {
            return value ? 1 : 0;
        }
        
        if (_.isDate(value)) {
            return value.getTime();
        }
    
        throw new Error(_.format(Platform.getResourceString('sqliteSerializer_UnsupportedTypeConversion'), JSON.stringify(value), typeof value, 'integer'));
    };
    
    exports.convertToBoolean = function (value) {
    
        if (_.isNull(value)) // undefined/null value should be converted to null
            return null;
    
        if (_.isBool(value)) {
            return value;
        }
    
        if (_.isInteger(value)) {
            return value === 0 ? false : true;
        }
            
        throw new Error(_.format(Platform.getResourceString('sqliteSerializer_UnsupportedTypeConversion'), JSON.stringify(value), typeof value, 'Boolean'));
    };
    
    exports.convertToDate = function (value) {
    
        if (_.isNull(value)) // undefined/null value should be converted to null
            return null;
    
        if (_.isDate(value)) {
            return value;
        }
    
        if (_.isInteger(value)) {
            return new Date(value);
        } 
    
        throw new Error(_.format(Platform.getResourceString('sqliteSerializer_UnsupportedTypeConversion'), JSON.stringify(value), typeof value, 'Date'));
    };
    
    exports.convertToReal = function (value) {
    
        if (_.isNull(value)) // undefined/null value should be converted to null
            return null;
    
        if (_.isNumber(value)) {
            return value;
        }
    
        throw new Error(_.format(Platform.getResourceString('sqliteSerializer_UnsupportedTypeConversion'), JSON.stringify(value), typeof value, 'Real'));
    };
    
    exports.convertToObject = function (value) {
    
        if (_.isNull(value)) // undefined/null value should be converted to null
            return null;
    
        if (_.isObject(value)) {
            return value;
        }
    
        var error;
        try {
            if (_.isString(value)) {
                var result = JSON.parse(value);
                
                // Make sure the deserialized value is indeed an object, and not some other type
                if (_.isObject(result)) {
                    return result;
                } 
            }
        } catch(err) {
            error = err; 
        }
    
        throw new verror.VError(error, Platform.getResourceString('sqliteSerializer_UnsupportedTypeConversion'), JSON.stringify(value), typeof value, 'Object');    
    };
    
    exports.convertToArray = function (value) {
    
        if (_.isNull(value)) // undefined/null value should be converted to null
            return null;
    
        if (_.isArray(value)) {
            return value;
        }
    
        var error;
        try {
            if (_.isString(value)) {
                var result = JSON.parse(value);
                
                // Make sure the deserialized value is indeed an object, and not some other type
                if (_.isArray(result)) {
                    return result;
                } 
            }
        } catch(err) {
            error = err; 
        }
    
        throw new verror.VError(error, Platform.getResourceString('sqliteSerializer_UnsupportedTypeConversion'), JSON.stringify(value), typeof value, 'Array');    
    };
    
    },{"../../Utilities/Extensions":241,"../../Utilities/Validate":244,"verror":281}],233:[function(require,module,exports){
    (function (global){(function (){
    // ----------------------------------------------------------------------------
    // Copyright (c) Microsoft Corporation. All rights reserved.
    // ----------------------------------------------------------------------------
    
    // Module to retrieve environment details
    
    /**
     * Gets details of the target
     * @private
     * 
     * @return 'Cordova', 'Web' or 'Unknown'
     */
    exports.getTarget = function() {
        if (typeof global !== 'undefined' && global.cordova && global.cordova.version) {
            return 'Cordova';
        } else if (typeof global !== 'undefined') {
            return 'Web';
        } else {
            return 'Unknown';
        }
    };
    
    }).call(this)}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
    },{}],234:[function(require,module,exports){
    // ----------------------------------------------------------------------------
    // Copyright (c) Microsoft Corporation. All rights reserved.
    // ----------------------------------------------------------------------------
    
    var target = require('./environment').getTarget();
    
    if (target === 'Cordova') {
        module.exports = require('./cordova');
    } else if (target === 'Web') {
        module.exports = require('./web');
    } else {
        throw new Error('Unsupported target');
    }
    
    },{"./cordova":228,"./environment":233,"./web":236}],235:[function(require,module,exports){
    // ----------------------------------------------------------------------------
    // Copyright (c) Microsoft Corporation. All rights reserved.
    // ----------------------------------------------------------------------------
    
    var target = require('./environment').getTarget();
    
    if (target === 'Cordova') {
        module.exports = require('./cordova/sdkExports');
    } else if (target === 'Web') {
        module.exports = require('./web/sdkExports');
    } else {
        throw new Error('Unsupported target');
    }
    
    },{"./cordova/sdkExports":229,"./environment":233,"./web/sdkExports":237}],236:[function(require,module,exports){
    // ----------------------------------------------------------------------------
    // Copyright (c) Microsoft Corporation. All rights reserved.
    // ----------------------------------------------------------------------------
    
    /// <reference path="..\Generated\MobileServices.DevIntellisense.js" />
    /*global $__fileVersion__:false, $__version__:false */
    
    var _ = require('../../Utilities/Extensions'),
        Validate = require('../../Utilities/Validate'),
        Promises = require('../../Utilities/Promises'),
        version = require('../../../../package.json').version,
        resources = require('../../resources.json'),
        environment = require('../environment'),
        inMemorySettingStore = {};
    
    try {
        var key = '___z';
        localStorage.setItem(key, key);
        localStorage.removeItem(key);
        inMemorySettingStore = localStorage;
    } catch (e) {
        // localStorage is not available
    }
    
    var bestAvailableTransport = null;
    var knownTransports = [ // In order of preference
        require('../../Transports/DirectAjaxTransport'),
        require('../../Transports/IframeTransport')
    ];
    var knownLoginUis = [ // In order of preference
        require('../../LoginUis/WebAuthBroker'),
        require('../../LoginUis/CordovaPopup'),
        require('../../LoginUis/BrowserPopup')
    ];
    
    // Matches an ISO date and separates out the fractional part of the seconds
    // because IE < 10 has quirks parsing fractional seconds
    var isoDateRegex = /^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2})(?:\.(\d*))?Z$/;
    
    // Feature-detect IE8's date serializer
    var dateSerializerOmitsDecimals = !JSON.stringify(new Date(100)).match(/\.100Z"$/);
    
    exports.async = function async(func) {
        /// <summary>
        /// Wrap a function that takes a callback into platform specific async
        /// operation (i.e., keep using callbacks or switch to promises).
        /// </summary>
        /// <param name="func" type="Function">
        /// An async function with a callback as its last parameter 
        /// </param>
        /// <returns type="Function">
        /// Function that when invoked will return a promise.
        /// </returns>
    
        return function () {
            // Capture the context of the original call
            var that = this;
            var args = arguments;
    
            // Create a new promise that will wrap the async call
            return new Promises.Promise(function (complete, error) {
    
                // Add a callback to the args which will call the appropriate
                // promise handlers
                var callback = function (err) {
                    if (_.isNull(err)) {
                        // Call complete with all the args except for err
                        complete.apply(null, Array.prototype.slice.call(arguments, 1));
                    } else {
                        error(err);
                    }
                };
                Array.prototype.push.call(args, callback);
    
                try {
                    // Invoke the async method which will in turn invoke our callback
                    // which will in turn invoke the promise's handlers
                    func.apply(that, args);
                } catch (ex) {
                    // Thread any immediate errors like parameter validation
                    // through the the callback
                    callback(_.createError(ex));
                }
            });
        };
    };
    
    exports.readSetting = function readSetting(name) {
        /// <summary>
        /// Read a setting from a global configuration store.
        /// </summary>
        /// <param name="name" type="String">
        /// Name of the setting to read.
        /// </param>
        /// <returns type="String" mayBeNull="true">
        /// The value of the setting or null if not set.
        /// </returns>
    
        return inMemorySettingStore[name];
    };
    
    exports.writeSetting = function writeSetting(name, value) {
        /// <summary>
        /// Write a setting to a global configuration store.
        /// </summary>
        /// <param name="name" type="String">
        /// Name of the setting to write.
        /// </param>
        /// <param name="value" type="String" mayBeNull="true">
        /// The value of the setting.
        /// </returns>
    
        inMemorySettingStore[name] = value;
    };
    
    exports.webRequest = function (request, callback) {
        /// <summary>
        /// Make a web request.
        /// </summary>
        /// <param name="request" type="Object">
        /// Object describing the request (in the WinJS.xhr format).
        /// </param>
        /// <param name="callback" type="Function">
        /// The callback to execute when the request completes.
        /// </param>
    
        return getBestTransport().performRequest(request, callback);
    };
    
    exports.getUserAgent = function () {
        // Browsers don't allow you to set a custom user-agent in ajax requests. Trying to do so
        // will cause an exception. So we don't.
        return null;
    };
    
    exports.getOperatingSystemInfo = function () {
        return {
            name: "--",
            version: "--",
            architecture: "--"
        };
    };
    
    exports.getSdkInfo = function () {
        return {
            language: environment.getTarget(),
            fileVersion: version
        };
    };
    
    exports.login = function (startUri, endUri, callback) {
        // Force logins to go over HTTPS because the runtime is hardcoded to redirect
        // the server flow back to HTTPS, and we need the origin to match.
        var findProtocol = /^[a-z]+:/,
            requiredProtocol = 'https:';
        startUri = startUri.replace(findProtocol, requiredProtocol);
        if (endUri) {
            endUri = endUri.replace(findProtocol, requiredProtocol);
        }
    
        return getBestProvider(knownLoginUis).login(startUri, endUri, callback);
    };
    
    exports.toJson = function (value) {
        /// <summary>
        /// Convert an object into JSON format.
        /// </summary>
        /// <param name="value" type="Object">The value to convert.</param>
        /// <returns type="String">The value as JSON.</returns>
    
        // We're wrapping this so we can hook the process and perform custom JSON
        // conversions.  Note that we don't have to add a special hook to correctly
        // serialize dates in ISO8061 because JSON.stringify does that by defualt.
        // TODO: Convert geolocations once they're supported
        // TODO: Expose the ability for developers to convert custom types
        return JSON.stringify(value, function (key, stringifiedValue) {
            if (dateSerializerOmitsDecimals && this && _.isDate(this[key])) {
                // IE8 doesn't include the decimal part in its serialization of dates
                // For consistency, we extract the non-decimal part from the string
                // representation, and then append the expected decimal part.
                var msec = this[key].getMilliseconds(),
                    msecString = String(msec + 1000).substring(1);
                return stringifiedValue.replace(isoDateRegex, function (all, datetime) {
                    return datetime + "." + msecString + "Z";
                });
            } else {
                return stringifiedValue;
            }
        });
    };
    
    exports.tryParseIsoDateString = function (text) {
        /// <summary>
        /// Try to parse an ISO date string.
        /// </summary>
        /// <param name="text" type="String">The text to parse.</param>
        /// <returns type="Date">The parsed Date or null.</returns>
    
        Validate.isString(text);
    
        // Check against a lenient regex
        var matchedDate = isoDateRegex.exec(text);
        if (matchedDate) {
            // IE9 only handles precisely 0 or 3 decimal places when parsing ISO dates,
            // and IE8 doesn't parse them at all. Fortunately, all browsers can handle 
            // 'yyyy/mm/dd hh:MM:ss UTC' (without fractional seconds), so we can rewrite
            // the date to that format, and the apply fractional seconds.
            var dateWithoutFraction = matchedDate[1],
                fraction = matchedDate[2] || "0",
                milliseconds = Math.round(1000 * Number("0." + fraction)); // 6 -> 600, 65 -> 650, etc.
            dateWithoutFraction = dateWithoutFraction
                .replace(/\-/g, "/")   // yyyy-mm-ddThh:mm:ss -> yyyy/mm/ddThh:mm:ss
                .replace("T", " ");    // yyyy/mm/ddThh:mm:ss -> yyyy/mm/dd hh:mm:ss
    
            // Try and parse - it will return NaN if invalid
            var ticks = Date.parse(dateWithoutFraction + " UTC");
            if (!isNaN(ticks)) {
                return new Date(ticks + milliseconds); // ticks are just milliseconds since 1970/01/01
            }
        }
    
        // Doesn't look like a date
        return null;
    };
    
    exports.getResourceString = function (resourceName) {
        return resources[resourceName];
    };
    
    
    exports.allowPlatformToMutateOriginal = function (original, updated) {
        // For the Web/HTML client, we don't modify the original object.
        // This is the more typical arrangement for most JavaScript data access.
        return updated;
    };
    
    function getBestTransport() {
        // We cache this just because it gets called such a lot
        if (!bestAvailableTransport) {
            bestAvailableTransport = getBestProvider(knownTransports);
        }
    
        return bestAvailableTransport;
    }
    
    function getBestProvider(providers) {
        /// <summary>
        /// Given an array of objects which each have a 'supportsCurrentRuntime' function,
        /// returns the first instance where that function returns true.
        /// </summary>
    
        for (var i = 0; i < providers.length; i++) {
            if (providers[i].supportsCurrentRuntime()) {
                return providers[i];
            }
        }
    
        throw new Error("Unsupported browser - no suitable providers are available.");
    }
    },{"../../../../package.json":220,"../../LoginUis/BrowserPopup":221,"../../LoginUis/CordovaPopup":222,"../../LoginUis/WebAuthBroker":223,"../../Transports/DirectAjaxTransport":239,"../../Transports/IframeTransport":240,"../../Utilities/Extensions":241,"../../Utilities/Promises":243,"../../Utilities/Validate":244,"../../resources.json":248,"../environment":233}],237:[function(require,module,exports){
    // ----------------------------------------------------------------------------
    // Copyright (c) Microsoft Corporation. All rights reserved.
    // ----------------------------------------------------------------------------
    
    // Browser specific modules that need to be exposed outside the SDK
    module.exports = {
        // None as of now.
    };
    
    },{}],238:[function(require,module,exports){
    // ----------------------------------------------------------------------------
    // Copyright (c) Microsoft Corporation. All rights reserved.
    // ----------------------------------------------------------------------------
    var Validate = require('../Utilities/Validate'),
        Platform = require('../Platform'),
        constants = require('../constants'),
        _ = require('../Utilities/Extensions');
    
    exports.Push = Push;
    
    /**
     * @class
     * @classdesc Push registration manager.
     * @protected
     */
    function Push(client, installationId) {
        this.client = client;
        this.installationId = installationId;
    }
    
    /**
     * Register a push channel with the Azure Mobile Apps backend to start receiving notifications.
     *
     * @function
     * 
     * @param {string} platform The device platform being used - _'wns'_, _'gcm'_ or _'apns'_.
     * @param {string} pushChannel The push channel identifier or URI.
     * @param {string} templates An object containing template definitions. Template objects should contain body, headers and tags properties.
     * @param {string} secondaryTiles An object containing template definitions to be used with secondary tiles when using WNS.
     * 
     * @returns {Promise} A promise that is resolved when registration is successful OR rejected with the error if it fails.
     */
    Push.prototype.register = Platform.async(
        function (platform, pushChannel, templates, secondaryTiles, callback) {
            Validate.isString(platform, 'platform');
            Validate.notNullOrEmpty(platform, 'platform');
    
            // in order to support the older callback style completion, we need to check optional parameters
            if (_.isNull(callback) && (typeof templates === 'function')) {
                callback = templates;
                templates = null;
            }
    
            if (_.isNull(callback) && (typeof secondaryTiles === 'function')) {
                callback = secondaryTiles;
                secondaryTiles = null;
            }
    
            var requestContent = {
                installationId: this.installationId,
                pushChannel: pushChannel,
                platform: platform,
                templates: stringifyTemplateBodies(templates),
                secondaryTiles: stringifyTemplateBodies(secondaryTiles)
            };
    
            executeRequest(this.client, 'PUT', pushChannel, requestContent, this.installationId, callback);
        }
    );
    
    /**
     * Unregister a push channel with the Azure Mobile Apps backend to stop receiving notifications.
     * 
     * @function
     * 
     * @param {string} pushChannel The push channel identifier or URI.
     * 
     * @returns {Promise} A promise that is resolved if unregister is successful and rejected with the error if it fails.
     */
    Push.prototype.unregister = Platform.async(
        function (pushChannel, callback) {
            executeRequest(this.client, 'DELETE', pushChannel, null, this.installationId, callback);
        }
    );
    
    function executeRequest(client, method, pushChannel, content, installationId, callback) {
        Validate.isString(pushChannel, 'pushChannel');
        Validate.notNullOrEmpty(pushChannel, 'pushChannel');
    
        var headers = { 'If-Modified-Since': 'Mon, 27 Mar 1972 00:00:00 GMT' };
        headers[constants.apiVersionHeaderName] = constants.apiVersion;
    
        client._request(
            method,
            'push/installations/' + encodeURIComponent(installationId),
            content,
            null,
            headers,
            callback
        );
    }
    
    function stringifyTemplateBodies(templates) {
        var result = {};
        for (var templateName in templates) {
            if (templates.hasOwnProperty(templateName)) {
                // clone the template so we are not modifying the original
                var template = _.extend({}, templates[templateName]);
                if (typeof template.body !== 'string') {
                    template.body = JSON.stringify(template.body);
                }
                result[templateName] = template;
            }
        }
        return result;
    }
    },{"../Platform":234,"../Utilities/Extensions":241,"../Utilities/Validate":244,"../constants":246}],239:[function(require,module,exports){
    (function (global){(function (){
    // ----------------------------------------------------------------------------
    // Copyright (c) Microsoft Corporation. All rights reserved.
    // ----------------------------------------------------------------------------
    
    /// <reference path="..\Generated\MobileServices.DevIntellisense.js" />
    
    // This transport is for modern browsers - it uses XMLHttpRequest with Cross-Origin Resource Sharing (CORS)
    
    exports.name = "DirectAjaxTransport";
    
    exports.supportsCurrentRuntime = function () {
        /// <summary>
        /// Determines whether or not this transport is usable in the current runtime.
        /// </summary>
    
        // Feature-detect support for CORS (for IE, it's in version 10+)
        return (typeof global.XMLHttpRequest !== "undefined") &&
               ('withCredentials' in new global.XMLHttpRequest());
    };
    
    exports.performRequest = function (request, callback) {
        /// <summary>
        /// Make a web request.
        /// </summary>
        /// <param name="request" type="Object">
        /// Object describing the request (in the WinJS.xhr format).
        /// </param>
        /// <param name="callback" type="Function">
        /// The callback to execute when the request completes.
        /// </param>
    
        var headers = request.headers || {},
            url = request.url.replace(/#.*$/, ""), // Strip hash part of URL for consistency across browsers
            httpMethod = request.type ? request.type.toUpperCase() : "GET",
            xhr = new global.XMLHttpRequest();
    
        xhr.onreadystatechange = function () {
            if (xhr.readyState === 4) {
                callback(null, xhr);
            }
        };
    
        xhr.open(httpMethod, url);
    
        for (var key in headers) {
            if (request.headers.hasOwnProperty(key)) {
                xhr.setRequestHeader(key, request.headers[key]);
            }
        }
    
        xhr.send(request.data);
    };
    }).call(this)}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
    },{}],240:[function(require,module,exports){
    (function (global){(function (){
    // ----------------------------------------------------------------------------
    // Copyright (c) Microsoft Corporation. All rights reserved.
    // ----------------------------------------------------------------------------
    
    /// <reference path="..\Generated\MobileServices.DevIntellisense.js" />
    
    // This transport is for midlevel browsers (IE8-9) that don't support CORS but do support postMessage.
    // It creates an invisible <iframe> that loads a special bridge.html page from the runtime domain.
    // To issue a request, it uses postMessage to pass the request into the <iframe>, which in turn makes
    // a same-domain Ajax request to the runtime. To associate postMessage replies with the original
    // request, we track an array of promises that eventually time out if not resolved (see PostMessageExchange).
    
    var Promises = require('../Utilities/Promises'),
        PostMessageExchange = require('../Utilities/PostMessageExchange'),
        loadBridgeFramePromises = [], // One per target proto/host/port triplet
        messageExchange = PostMessageExchange.instance;
    
    exports.name = "../../Transports/IframeTransport";
    
    exports.supportsCurrentRuntime = function () {
        /// <summary>
        /// Determines whether or not this transport is usable in the current runtime.
        /// </summary>
    
        return typeof global.postMessage !== "undefined";
    };
    
    exports.performRequest = function (request, callback) {
        /// <summary>
        /// Make a web request.
        /// </summary>
        /// <param name="request" type="Object">
        /// Object describing the request (in the WinJS.xhr format).
        /// </param>
        /// <param name="callback" type="Function">
        /// The callback to execute when the request completes.
        /// </param>
    
        var originRoot = PostMessageExchange.getOriginRoot(request.url);
        whenBridgeLoaded(originRoot, function (bridgeFrame) {
            var message = {
                type: request.type,
                url: request.url,
                headers: request.headers,
                data: request.data
            };
            messageExchange.request(bridgeFrame.contentWindow, message, originRoot).then(function (reply) {
                fixupAjax(reply);
                callback(null, reply);
            }, function (error) {
                callback(error, null);
            });
        });
    };
    
    function fixupAjax(xhr) {
        if (xhr) {
            // IE sometimes converts status 204 into 1223
            // http://stackoverflow.com/questions/10046972/msie-returns-status-code-of-1223-for-ajax-request
            if (xhr.status === 1223) {
                xhr.status = 204;
            }
        }
    }
    
    function whenBridgeLoaded(originRoot, callback) {
        /// <summary>
        /// Performs the callback once the bridge iframe has finished loading.
        /// Lazily creates the bridge iframe if necessary. Note that each proto/host/port
        /// triplet (i.e., same-domain origin) needs a separate bridge.
        /// </summary>
    
        var cacheEntry = loadBridgeFramePromises[originRoot];
    
        if (!cacheEntry) {
            cacheEntry = loadBridgeFramePromises[originRoot] = new Promises.Promise(function (complete, error) {
                var bridgeFrame = document.createElement("iframe"),
                    callerOrigin = PostMessageExchange.getOriginRoot(window.location.href),
                    handleBridgeLoaded = function() {
                        complete(bridgeFrame);
                    };
                
                if (bridgeFrame.addEventListener) {
                    bridgeFrame.addEventListener("load", handleBridgeLoaded, false);
                } else {
                    // For IE8
                    bridgeFrame.attachEvent("onload", handleBridgeLoaded);
                }
    
                bridgeFrame.src = originRoot + "/crossdomain/bridge?origin=" + encodeURIComponent(callerOrigin);
                
                // Try to keep it invisible, even if someone does $("iframe").show()
                bridgeFrame.setAttribute("width", 0);
                bridgeFrame.setAttribute("height", 0);
                bridgeFrame.style.display = "none";
    
                global.document.body.appendChild(bridgeFrame);
            });
        }
    
        cacheEntry.then(callback);
    }
    
    
    }).call(this)}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
    },{"../Utilities/PostMessageExchange":242,"../Utilities/Promises":243}],241:[function(require,module,exports){
    // ----------------------------------------------------------------------------
    // Copyright (c) Microsoft Corporation. All rights reserved.
    // ----------------------------------------------------------------------------
    
    // Declare JSHint globals
    /*global XMLHttpRequest:false */
    
    var Validate = require('./Validate');
    var Platform = require('../Platform');
    var _ = exports;
    
    exports.isNull = function (value) {
        /// <summary>
        /// Gets a value indicating whether the provided value is null (or
        /// undefined).
        /// </summary>
        /// <param name="value" type="Object" mayBeNull="true">
        /// The value to check.
        /// </param>
        /// <returns type="Boolean">
        /// A value indicating whether the provided value is null (or undefined).
        /// </returns>
        
        return value === null || value === undefined;
    };
    
    exports.isNullOrZero = function (value) {
        /// <summary>
        /// Gets a value indicating whether the provided value is null (or
        /// undefined) or zero / empty string
        /// </summary>
        /// <param name="value" type="Object" mayBeNull="true">
        /// The value to check.
        /// </param>
        /// <returns type="Boolean">
        /// A value indicating whether the provided value is null (or undefined) or zero or empty string.
        /// </returns>
    
        return value === null || value === undefined || value === 0 || value === '';
    };
    
    exports.isNullOrEmpty = function (value) {
        /// <summary>
        /// Gets a value indicating whether the provided value is null (or
        /// undefined) or empty.
        /// </summary>
        /// <param name="value" type="Object" mayBeNull="true">
        /// The value to check.
        /// </param>
        /// <returns type="Boolean">
        /// A value inHdicating whether the provided value is null (or undefined).
        /// </returns>
    
        return _.isNull(value) || value.length === 0;
    };
    
    exports.format = function (message) {
        /// <summary>
        /// Format a string by replacing all of its numbered arguments with
        /// parameters to the method. Arguments are of the form {0}, {1}, ..., like
        /// in .NET.
        /// </summary>
        /// <param name="message" type="string" mayBeNull="false">
        /// The format string for the message.
        /// </param>
        /// <param name="arguments" type="array" optional="true">
        /// A variable number of arguments that can be used to format the message.
        /// </param>
        /// <returns type="string">The formatted string.</returns>
    
        Validate.isString(message, 'message');
    
        // Note: There are several flaws in this implementation that we are
        // ignoring for simplicity as it's only used internally.  Examples that
        // could be handled better include:
        //    format('{0} {1}', 'arg') => 'arg {1}'
        //    format('{0} {1}', '{1}', 'abc') => 'abc abc'
        //    format('{0}', '{0}') => <stops responding>
    
        if (!_.isNullOrEmpty(message) && arguments.length > 1) {
            for (var i = 1; i < arguments.length; i++) {
                var pattern = '{' + (i - 1) + '}';
                while (message.indexOf(pattern) !== -1) {
                    message = message.replace(pattern, arguments[i]);
                }
            }
        }
    
        return message;
    };
    
    exports.has = function (value, key) {
        /// <summary>
        /// Determine if an object defines a given property.
        /// </summary>
        /// <param name="value" type="Object">The object to check.</param>
        /// <param name="key" type="String">
        /// The name of the property to check for.
        /// </param>
        /// <returns type="Boolean">
        /// A value indicating whether the object defines the property.
        /// </returns>
    
        Validate.notNull(key, 'key');
        Validate.isString(key, 'key');
    
        return !_.isNull(value) && value.hasOwnProperty(key);
    };
    
    exports.hasProperty = function (object, properties) {
        /// <summary>
        /// Determines if an object has any of the passed in properties
        /// </summary>
        /// <returns type="boolean">True if it contains any one of the properties
        /// </returns>
        for (var i = 0; i < properties.length; i++) {
            if (_.has(object, properties[i])) {
                return true;
            }
        }
        return false;
    };
    
    exports.extend = function extend(target, members) {
        /// <summary>
        /// Extends the target with the members of the members object.
        /// </summary>
        /// <param name="target" type="Object">The target object to extend.</param>
        /// <param name="members" type="Object">The members object to add to the target.</param>
        /// <returns type="Object">The target object extended with the members.
        /// </returns>
        for (var member in members) {
            if (members.hasOwnProperty(member)) {
                target[member] = members[member];
            }
        }
        return target;
    };
    
    exports.isObject = function (value) {
        /// <summary>
        /// Determine if a value is an object.
        /// </summary>
        /// <param name="value" type="Object">The value to check.</param>
        /// <returns type="boolean">
        /// True if the value is an object (or null), false othwerise.
        /// </returns>
    
        return _.isNull(value) || (typeof value === 'object' && !_.isDate(value));
    };
    
    exports.isValidId = function (value) {
        /// <summary>
        /// Determine if a value is an acceptable id for use by the mobile service
        /// </summary>
        /// <param name="value" type="Object">The value to check.</param>
        /// <returns type="boolean">
        /// True if the value is a string or number, meeting all criteria, or false othwerise.
        /// </returns>
        if (_.isNullOrZero(value)) {
            return false;
        }
    
        if (_.isString(value)) {
            // Strings must contain at least one non whitespace character
            if (value.length === 0 || value.length > 255 || value.trim().length === 0) {
                return false;
            }
    
            var ex = /[+"\/?`\\]|[\u0000-\u001F]|[\u007F-\u009F]|^\.{1,2}$/;
            if (value.match(ex) !== null) {
                return false;
            }
    
            return true;
    
        } else if (_.isNumber(value)) {
            return value > 0;
        }
    
        return false;
    };
    
    exports.isString = function (value) {
        /// <summary>
        /// Determine if a value is a string.
        /// </summary>
        /// <param name="value" type="Object">The value to check.</param>
        /// <returns type="boolean">
        /// True if the value is a string (or null), false othwerise.
        /// </returns>
    
        return _.isNull(value) || (typeof value === 'string');
    };
    
    exports.isNumber = function (value) {
        /// <summary>
        /// Determine if a value is a number.
        /// </summary>
        /// <param name="value" type="Object">The value to check.</param>
        /// <returns type="boolean">
        /// True if the value is a number, false othwerise.
        /// </returns>
    
        return !_.isNull(value) && (typeof value === 'number');
    };
    
    exports.isInteger = function(value) {
        /// <summary>
        /// Determine if a value is an integer.
        /// </summary>
        /// <param name="value" type="Object">The value to check.</param>
        /// <returns type="boolean">
        /// True if the value is an integer, false othwerise.
        /// </returns>
    
        return _.isNumber(value) && (parseInt(value, 10) === parseFloat(value));
    };
    
    exports.isBool = function (value) {
        /// <summary>
        /// Determine if a value is a boolean.
        /// </summary>
        /// <param name="value" type="Object">The value to check.</param>
        /// <returns type="boolean">
        /// True if the value is a boolean, false othwerise.
        /// </returns>
        return !_.isNull(value) && (typeof value == 'boolean');
    };
    
    exports.isFunction = function (value) {
        /// <summary>
        /// Determine if a value is a function.
        /// </summary>
        /// <param name="value" type="Object">The value to check.</param>
        /// <returns type="boolean">
        /// True if the value is a function, false othwerise.
        /// </returns>
        return typeof value == 'function';
    };
    
    exports.isArray = function (value) {
        /// <summary>
        /// Determine if a value is an array.
        /// </summary>
        /// <param name="value" type="Object">The value to check.</param>
        /// <returns type="boolean">
        /// True if the value is an array (or null), false othwerise.
        /// </returns>
    
        return !_.isNull(value) && (value.constructor === Array);
    };
    
    function classOf(value) {
        return Object.prototype.toString.call(value).slice(8, -1).toLowerCase();
    }
    
    exports.isDate = function (value) {
        /// <summary>
        /// Determine if a value is a date.
        /// </summary>
        /// <param name="value" type="Object">The value to check.</param>
        /// <returns type="boolean">
        /// True if the value is a date, false othwerise.
        /// </returns>
        return !_.isNull(value) && (classOf(value) == 'date');
    };
    
    exports.toJson = function (value) {
        /// <summary>
        /// Convert an object into JSON format.
        /// </summary>
        /// <param name="value" type="Object">The value to convert.</param>
        /// <returns type="String">The value as JSON.</returns>
    
        return Platform.toJson(value);
    };
    
    exports.fromJson = function (value) {
        /// <summary>
        /// Convert an object from JSON format.
        /// </summary>
        /// <param name="value" type="String">The value to convert.</param>
        /// <returns type="Object">The value as an object.</returns>
    
        var jsonValue = null;
        if (!_.isNullOrEmpty(value)) {
            // We're wrapping this so we can hook the process and perform custom JSON
            // conversions
            jsonValue = JSON.parse(
                value,
                function (k, v) {
                    // Try to convert the value as a Date
                    if (_.isString(v) && !_.isNullOrEmpty(v)) {
                        var date = exports.tryParseIsoDateString(v);
                        if (!_.isNull(date)) {
                            return date;
                        }
                    }
    
                    // TODO: Convert geolocations once they're supported
                    // TODO: Expose the ability for developers to convert custom types
    
                    // Return the original value if we couldn't do anything with it
                    return v;
                });
        }
    
        return jsonValue;
    };
    
    exports.createUniqueInstallationId = function () {
        /// <summary>
        /// Create a unique identifier that can be used for the installation of
        /// the current application.
        /// </summary>
        /// <returns type="String">Unique identifier.</returns>
    
        var pad4 = function (str) { return "0000".substring(str.length) + str; };
        var hex4 = function () { return pad4(Math.floor(Math.random() * 0x10000 /* 65536 */).toString(16)); };
    
        return (hex4() + hex4() + "-" + hex4() + "-" + hex4() + "-" + hex4() + "-" + hex4() + hex4() + hex4());
    };
    
    exports.mapProperties = function (instance, action) {
        /// <summary>
        /// Map a function over the key/value pairs in an instance.
        /// </summary>
        /// <param name="instance" type="Object">
        /// The instance to map over.
        /// </param>
        /// <param name="action" type="function (key, value)">
        /// The action to map over the key/value pairs.
        /// </param>
        /// <returns elementType="object">Mapped results.</returns>
    
        var results = [];
        if (!_.isNull(instance)) {
            var key = null;
            for (key in instance) {
                results.push(action(key, instance[key]));
            }
        }
        return results;
    };
    
    exports.pad = function (value, length, ch) {
        /// <summary>
        /// Pad the a value with a given character until it reaches the desired
        /// length.
        /// </summary>
        /// <param name="value" type="Object">The value to pad.</param>
        /// <param name="length" type="Number">The desired length.</param>
        /// <param name="ch" type="String">The character to pad with.</param>
        /// <returns type="String">The padded string.</returns>
    
        Validate.notNull(value, 'value');
        Validate.isInteger(length, 'length');
        Validate.isString(ch, 'ch');
        Validate.notNullOrEmpty(ch, 'ch');
        Validate.length(ch, 1, 'ch');
    
        var text = value.toString();
        while (text.length < length) {
            text = ch + text;
        }
        return text;
    };
    
    exports.trimEnd = function (text, ch) {
        /// <summary>
        /// Trim all instance of a given characher from the end of a string.
        /// </summary>
        /// <param name="text" type="String" mayBeNull="false">
        /// The string to trim.
        /// <param name="ch" type="String" mayBeNull="false">
        /// The character to trim.
        /// </param>
        /// <returns type="String">The trimmed string.</returns>
    
        Validate.isString(text, 'text');
        Validate.notNull(text, 'text');
        Validate.isString(ch, 'ch');
        Validate.notNullOrEmpty('ch', 'ch');
        Validate.length(ch, 1, 'ch');
    
        var end = text.length - 1;
        while (end >= 0 && text[end] === ch) {
            end--;
        }
    
        return end >= 0 ?
            text.substr(0, end + 1) :
            '';
    };
    
    exports.trimStart = function (text, ch) {
        /// <summary>
        /// Trim all instance of a given characher from the start of a string.
        /// </summary>
        /// <param name="text" type="String" mayBeNull="false">
        /// The string to trim.
        /// </param>
        /// <param name="ch" type="String" mayBeNull="false">
        /// The character to trim.
        /// </param>
        /// <returns type="String">The trimmed string.</returns>
    
        Validate.isString(text, 'text');
        Validate.notNull(text, 'text');
        Validate.isString(ch, 'ch');
        Validate.notNullOrEmpty(ch, 'ch');
        Validate.length(ch, 1, 'ch');
    
        var start = 0;
        while (start < text.length && text[start] === ch) {
            start++;
        }
    
        return start < text.length ?
            text.substr(start, text.length - start) :
            '';
    };
    
    exports.compareCaseInsensitive = function (first, second) {
        /// <summary>
        /// Compare two strings for equality while igorning case.
        /// </summary>
        /// <param name="first" type="String">First value.</param>
        /// <param name="second" type="String">Second value.</param>
        /// <returns type="Boolean">Whether the strings are the same.</returns>
    
        // NOTE: We prefer uppercase on Windows for historical reasons where it was
        // possible to have alphabets where several uppercase characters mapped to
        // the same lowercase character.
    
        if (_.isString(first) && !_.isNullOrEmpty(first)) {
            first = first.toUpperCase();
        }
    
        if (_.isString(first) && !_.isNullOrEmpty(second)) {
            second = second.toUpperCase();
        }
    
        return first === second;
    };
    
    /// <field name="url" type="Object">
    /// Path specific utilities for working with URIs.
    /// </field>
    exports.url = {
        /// <field name="separator" type="String">
        /// The path separator character used for combining path segments.
        /// </field>
        separator: '/',
    
        combinePathSegments: function () {
            /// <summary>
            /// Combine several segments into a path.
            /// </summary>
            /// <param parameterArray="true" elementType="String">
            /// The segments of the path that should be combined.
            /// </param>
            /// <returns type="String">The combined path.</returns>
    
            // Normalize the segements
            var segments = [];
            var i = 0;
            Validate.notNullOrEmpty(arguments, 'arguments');
            for (i = 0; i < arguments.length; i++) {
                var segment = arguments[i];
                Validate.isString(segment, _.format('argument[{0}]', i));
    
                if (i !== 0) {
                    segment = _.trimStart(segment || '', _.url.separator);
                }
                if (i < arguments.length - 1) {
                    segment = _.trimEnd(segment || '', _.url.separator);
                }
    
                segments.push(segment);
            }
    
            // Combine the segments
            return segments.reduce(
                function (a, b) { return a + _.url.separator + b; });
        },
    
        getQueryString: function (parameters) {
            /// <summary>
            /// Converts an Object instance into a query string
            /// </summary>
            /// <param name="parameters" type="Object">The parameters from which to create a query string.</param>
            /// <returns type="String">A query string</returns>
            
            Validate.notNull(parameters, 'parameters');
            Validate.isObject(parameters, 'parameters');
    
            var pairs = [];
            for (var parameter in parameters) {
                var value = parameters[parameter];
                if (exports.isObject(value)) {
                    value = exports.toJson(value);
                }
                pairs.push(encodeURIComponent(parameter) + "=" + encodeURIComponent(value));
            }
    
            return pairs.join("&");
        },
    
        combinePathAndQuery: function (path, queryString) {
            /// <summary>
            /// Concatenates the URI query string to the URI path.
            /// </summary>
            /// <param name="path" type="String>The URI path</param>
            /// <param name="queryString" type="String>The query string.</param>
            /// <returns type="String>The concatenated URI path and query string.</returns>
            Validate.notNullOrEmpty(path, 'path');
            Validate.isString(path, 'path');
            if (_.isNullOrEmpty(queryString)) {
                return path;
            }
            Validate.isString(queryString, 'queryString');
    
            if (path.indexOf('?') >= 0) {
                return path + '&' + exports.trimStart(queryString, '?');
            } else {
                return path + '?' + exports.trimStart(queryString, '?');
            }
        },
    
        isAbsoluteUrl: function (url) {
            /// <summary>
            /// Currently just a simple check if the url begins with http:// or https:/
            /// </summary>
            if (_.isNullOrEmpty(url)) {
                return false;
            }
    
            var start = url.substring(0, 7).toLowerCase();
            return (start  == "http://" || start == "https:/");
        },
    
        isHttps: function (url) {
            /// <summary>
            /// Simple check to verify if url begins with https:/
            /// </summary>
            if (_.isNullOrEmpty(url)) {
                return false;
            }
    
            var start = url.substring(0, 7).toLowerCase();
            return (start == "https:/");
        }
    
    };
    
    exports.tryParseIsoDateString = function (text) {
        /// <summary>
        /// Try to parse an ISO date string.
        /// </summary>
        /// <param name="text" type="String">The text to parse.</param>
        /// <returns type="Date">The parsed Date or null.</returns>
    
        return Platform.tryParseIsoDateString(text);
    };
    
    exports.createError = function (exceptionOrMessage, request) {
        /// <summary>
        /// Wrap an error thrown as an exception.
        /// </summary>
        /// <param name="exceptionOrMessage">
        /// The exception or message to throw.
        /// </param>
        /// <param name="request">
        /// The failing request.
        /// </param>
        /// <returns>An object with error details</returns>
    
        var error;
        if (request) {
            var message = Platform.getResourceString("Extensions_DefaultErrorMessage");
    
            if (request.status === 0) {
                // Provide a more helpful message for connection failures
                message = Platform.getResourceString("Extensions_ConnectionFailureMessage");
            } else {
                // Try to pull out an error message from the response before
                // defaulting to the status
                var isText = false;
                if (request.getResponseHeader) {
                    var contentType = request.getResponseHeader('Content-Type');
                    if (contentType) {
                        isText = contentType.toLowerCase().indexOf("text") >= 0;
                    }
                }
    
                try {
                    var response = JSON.parse(request.responseText);
                    if (typeof response === 'string') {
                        message = response;
                    } else {
                        message =
                            response.error ||
                            response.description ||
                            request.statusText ||
                            Platform.getResourceString("Extensions_DefaultErrorMessage");
                    }
                } catch (ex) {
                    if (isText) {
                        message = request.responseText;
                    } else {
                        message =
                            request.statusText ||
                            Platform.getResourceString("Extensions_DefaultErrorMessage");
                    }
                }
            }
    
            error = new Error(message);
            error.request = request;
        } else if (_.isString(exceptionOrMessage) && !_.isNullOrEmpty(exceptionOrMessage)) {
            error = new Error(exceptionOrMessage);
        } else if (exceptionOrMessage instanceof Error) { // If exceptionOrMessage is an Error object, use it as-is
            error = exceptionOrMessage; 
        } else if (!_.isNull(exceptionOrMessage)) {
            // Otherwise we'll use the object as an exception and leave the
            // default error message
            error = new Error(Platform.getResourceString("Extensions_DefaultErrorMessage"));
            error.exception = exceptionOrMessage;
        }
    
        return error;
    };
    },{"../Platform":234,"./Validate":244}],242:[function(require,module,exports){
    (function (global){(function (){
    // ----------------------------------------------------------------------------
    // Copyright (c) Microsoft Corporation. All rights reserved.
    // ----------------------------------------------------------------------------
    
    // window.postMessage does not have a concept of responses, so this class associates messages
    // with IDs so that we can identify which message a reply refers to.
    
    var Promises = require('./Promises'),
        messageTimeoutDuration = 5 * 60 * 1000; // If no reply after 5 mins, surely there will be no reply
    
    function PostMessageExchange() {
        var self = this;
        self._lastMessageId = 0;
        self._hasListener = false;
        self._pendingMessages = {};
    }
    
    PostMessageExchange.prototype.request = function (targetWindow, messageData, origin) {
        /// <summary>
        /// Issues a request to the target window via postMessage
        /// </summary>
        /// <param name="targetWindow" type="Object">
        /// The window object (on an actual window, or iframe) to send the request to
        /// </param>
        /// <param name="messageData" type="Object">
        /// A JSON-serializable object to pass to the target
        /// </param>
        /// <param name="origin" type="String">
        /// The expected origin (e.g., "http://example.com:81") of the recipient window.
        /// If at runtime the origin does not match, the request will not be issued.
        /// </param>
        /// <returns type="Object">
        /// A promise that completes once the target window sends back a reply, with
        /// value equal to that reply.
        /// </returns>
    
        var self = this,
            messageId = ++self._lastMessageId,
            envelope = { messageId: messageId, contents: messageData };
    
        self._ensureHasListener();
    
        return new Promises.Promise(function (complete, error) {
            // Track callbacks and origin data so we can complete the promise only for valid replies
            self._pendingMessages[messageId] = {
                messageId: messageId,
                complete: complete,
                error: error,
                targetWindow: targetWindow,
                origin: origin
            };
    
            // Don't want to leak memory, so if there's no reply, forget about it eventually
            self._pendingMessages[messageId].timeoutId = global.setTimeout(function () {
                var pendingMessage = self._pendingMessages[messageId];
                if (pendingMessage) {
                    delete self._pendingMessages[messageId];
                    pendingMessage.error({ status: 0, statusText: "Timeout", responseText: null });
                }
            }, messageTimeoutDuration);
    
            targetWindow.postMessage(JSON.stringify(envelope), origin);
        });
    };
    
    PostMessageExchange.prototype._ensureHasListener = function () {
        if (this._hasListener) {
            return;
        }
        this._hasListener = true;
    
        var self = this,
            boundHandleMessage = function () {
                self._handleMessage.apply(self, arguments);
            };
    
        if (window.addEventListener) {
            window.addEventListener('message', boundHandleMessage, false);
        } else {
            // For IE8
            window.attachEvent('onmessage', boundHandleMessage);
        }
    };
    
    PostMessageExchange.prototype._handleMessage = function (evt) {
        var envelope = this._tryDeserializeMessage(evt.data),
            messageId = envelope && envelope.messageId,
            pendingMessage = messageId && this._pendingMessages[messageId],
            isValidReply = pendingMessage && pendingMessage.targetWindow === evt.source &&
                           pendingMessage.origin === getOriginRoot(evt.origin);
        
        if (isValidReply) {
            global.clearTimeout(pendingMessage.timeoutId); // No point holding this in memory until the timeout expires
            delete this._pendingMessages[messageId];
            pendingMessage.complete(envelope.contents);
        }
    };
    
    PostMessageExchange.prototype._tryDeserializeMessage = function (messageString) {
        if (!messageString || typeof messageString !== 'string') {
            return null;
        }
    
        try {
            return JSON.parse(messageString);
        } catch (ex) {
            // It's not JSON, so it's not a message for us. Ignore it.
            return null;
        }
    };
    
    function getOriginRoot(url) {
        // Returns the proto/host/port part of a URL, i.e., the part that defines the access boundary
        // for same-origin policy. This is of the form "protocol://host:port", where ":port" is omitted
        // if it is the default port for that protocol.
        var parsedUrl = parseUrl(url),
            portString = parsedUrl.port ? parsedUrl.port.toString() : null,
            isDefaultPort = (parsedUrl.protocol === 'http:' && portString === '80') ||
                            (parsedUrl.protocol === 'https:' && portString === '443'),
            portSuffix = (portString && !isDefaultPort) ? ':' + portString : '';
        return parsedUrl.protocol + '//' + parsedUrl.hostname + portSuffix;
    }
    
    function parseUrl(url) {
        // https://gist.github.com/2428561 - works on IE8+. Could switch to a more manual, less magic
        // parser in the future if we need to support IE < 8.
        var elem = global.document.createElement('a');
        elem.href = url;
        return elem;
    }
    
    exports.instance = new PostMessageExchange();
    exports.getOriginRoot = getOriginRoot;
    }).call(this)}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
    },{"./Promises":243}],243:[function(require,module,exports){
    // ----------------------------------------------------------------------------
    // Copyright (c) Microsoft Corporation. All rights reserved.
    // ----------------------------------------------------------------------------
    
    // In WinJS, we use WinJS.Promise.
    // There's no native equivalent for regular JavaScript in the browser, so we implement it here.
    // This implementation conforms to Promises/A+, making it compatible with WinJS.Promise.
    
    // Note: There is a standard Promises/A+ test suite, to which this implementation conforms.
    // See test\Microsoft.Azure.Zumo.Web.Test\promiseTests
    
    // Declare JSHint globals
    /*global setTimeout:false */
    
    (function (exports) {
        "use strict";
    
        var resolutionState = { success: {}, error: {} },
            bind = function (func, target) { return function () { func.apply(target, arguments); }; }, // Older browsers lack Function.prototype.bind
            isGenericPromise = function (obj) { return obj && (typeof obj.then === "function"); };
    
        function Promise(init) {
            this._callbackFrames = [];
            this._resolutionState = null;
            this._resolutionValueOrError = null;
            this._resolveSuccess = bind(this._resolveSuccess, this);
            this._resolveError = bind(this._resolveError, this);
    
            if (init) {
                init(this._resolveSuccess, this._resolveError);
            }
        }
    
        Promise.prototype.then = function (success, error) {
            var callbackFrame = { success: success, error: error, chainedPromise: new Promise() };
    
            // If this promise is already resolved, invoke callbacks immediately. Otherwise queue them.
            if (this._resolutionState) {
                this._invokeCallback(callbackFrame);
            } else {
                this._callbackFrames.push(callbackFrame);
            }
    
            return callbackFrame.chainedPromise;
        };
    
        Promise.prototype._resolveSuccess = function (val) { this._resolve(resolutionState.success, val); };
        Promise.prototype._resolveError = function (err) { this._resolve(resolutionState.error, err); };
    
        Promise.prototype._resolve = function (state, valueOrError) {
            if (this._resolutionState) {
                // Can't affect resolution state when already resolved. We silently ignore the request, without throwing an error,
                // to prevent concurrent resolvers from affecting each other during race conditions.
                return;
            }
    
            this._resolutionState = state;
            this._resolutionValueOrError = valueOrError;
    
            // Notify all queued callbacks
            for (var i = 0, j = this._callbackFrames.length; i < j; i++) {
                this._invokeCallback(this._callbackFrames[i]);
            }
        };
    
        Promise.prototype._invokeCallback = function (frame) {
            var callbackToInvoke = this._resolutionState === resolutionState.success ? frame.success : frame.error;
            if (typeof callbackToInvoke === "function") {
                // Call the supplied callback either to transform the result (for success) or to handle the error (for error)
                // The setTimeout ensures handlers are always invoked asynchronosly, even if the promise was already resolved,
                // to avoid callers having to differentiate between sync/async cases
                setTimeout(bind(function () {
                    var passthroughValue, passthroughState, callbackDidNotThrow = true;
                    try {
                        passthroughValue = callbackToInvoke(this._resolutionValueOrError);
                        passthroughState = resolutionState.success;
                    } catch (ex) {
                        callbackDidNotThrow = false;
                        passthroughValue = ex;
                        passthroughState = resolutionState.error;
                    }
    
                    if (callbackDidNotThrow && isGenericPromise(passthroughValue)) {
                        // By returning a futher promise from a callback, you can insert it into the chain. This is the basis for composition.
                        // This rule is in the Promises/A+ spec, but not Promises/A.
                        passthroughValue.then(frame.chainedPromise._resolveSuccess, frame.chainedPromise._resolveError);
                    } else {
                        frame.chainedPromise._resolve(passthroughState, passthroughValue);
                    }
                }, this), 1);
            } else {
                // No callback of the applicable type, so transparently pass existing state/value down the chain
                frame.chainedPromise._resolve(this._resolutionState, this._resolutionValueOrError);
            }
        };
    
        // -----------
        // Everything from here on is extensions beyond the Promises/A+ spec intended to ease code
        // sharing between WinJS and browser-based Mobile Services apps
    
        Promise.prototype.done = function (success, error) {
            this.then(success, error).then(null, function(err) {
                // "done" throws any final errors as global uncaught exceptions. The setTimeout
                // ensures the exception won't get caught in the Promises machinery or user code.
                setTimeout(function () { throw new Error(err); }, 1);
            });
            return undefined; // You can't chain onto a .done()
        };
    
        // Note that we're not implementing any of the static WinJS.Promise.* functions because
        // the Mobile Services client doesn't even expose any static "Promise" object that you
        // could reference static functions on. Developers who want to use any of the WinJS-style
        // static functions (any, join, theneach, ...) can use any Promises/A-compatible library
        // such as when.js.
        //
        // Additionally, we don't implement .cancel() yet because Mobile Services operations don't
        // support cancellation in WinJS yet either. This could be added to both WinJS and Web
        // client libraries in the future.
    
        exports.Promise = Promise;
    })(exports);
    },{}],244:[function(require,module,exports){
    // ----------------------------------------------------------------------------
    // Copyright (c) Microsoft Corporation. All rights reserved.
    // ----------------------------------------------------------------------------
    
    var _ = require('./Extensions');
    var Platform = require('../Platform');
    
    exports.notNull = function (value, name) {
        /// <summary>
        /// Ensure the value is not null (or undefined).
        /// </summary>
        /// <param name="value" mayBeNull="true">The value to check.</param>
        /// <param name="name" mayBeNull="true" optional="true">
        /// Optional name of the value to throw.
        /// </param>
    
        if (_.isNull(value)) {
            throw _.format(Platform.getResourceString("Validate_NotNullError"), name || 'Value');
        }
    };
    
    exports.notNullOrEmpty = function (value, name) {
        /// <summary>
        /// Ensure the value is not null, undefined, or empty.
        /// </summary>
        /// <param name="value" mayBeNull="true">The value to check.</param>
        /// <param name="name" mayBeNull="true" optional="true" type="String">
        /// Optional name of the value to throw.
        /// </param>
    
        if (_.isNullOrEmpty(value)) {
            throw _.format(Platform.getResourceString("Validate_NotNullOrEmptyError"), name || 'Value');
        }
    };
    
    exports.notNullOrZero = function (value, name) {
        /// <summary>
        /// Ensure the value is not null, undefined, zero, or empty.
        /// </summary>
        /// <param name="value" mayBeNull="true">The value to check.</param>
        /// <param name="name" mayBeNull="true" optional="true" type="String">
        /// Optional name of the value to throw.
        /// </param>
    
        if (_.isNullOrZero(value)) {
            throw _.format(Platform.getResourceString("Validate_NotNullOrEmptyError"), name || 'Value');
        }
    };
    
    exports.isValidId = function (value, name) {
        /// <summary>
        /// Ensure the value is a valid id for mobile services.
        /// </summary>
        /// <param name="value" mayBeNull="true">The value to check.</param>
        /// <param name="name" mayBeNull="true" optional="true" type="String">
        /// Optional name of the value to throw.
        /// </param>
    
        if (!_.isValidId(value)) {
            throw new Error((name || 'id') + ' "' + value + '" is not valid.');
        }
    };
    
    exports.isDate = function (value, name) {
        /// <summary>
        /// Ensure the value is a date.
        /// </summary>
        /// <param name="value" mayBeNull="true">The value to check.</param>
        /// <param name="name" mayBeNull="true" optional="true" type="String">
        /// Optional name of the value to throw.
        /// </param>
        
        exports.notNull(value, name);    
        if (!_.isDate(value)) {
            throw _.format(
                Platform.getResourceString("TypeCheckError"),
                name || 'Value',
                'Date',
                typeof value);
        }
    };
    
    exports.isNumber = function (value, name) {
        /// <summary>
        /// Ensure the value is a number.
        /// </summary>
        /// <param name="value" mayBeNull="true">The value to check.</param>
        /// <param name="name" mayBeNull="true" optional="true" type="String">
        /// Optional name of the value to throw.
        /// </param>
    
        exports.notNull(value, name);
    
        if (!_.isNumber(value)) {
            throw _.format(
                Platform.getResourceString("TypeCheckError"),
                name || 'Value',
                'Number',
                typeof value);
        }
    };
    
    exports.isFunction = function (value, name) {
        /// <summary>
        /// Ensure the value is a function.
        /// </summary>
        /// <param name="value" mayBeNull="true">The value to check.</param>
        /// <param name="name" mayBeNull="true" optional="true" type="String">
        /// Optional name of the value to throw.
        /// </param>
    
        if (!_.isFunction(value)) {
            throw _.format(
                Platform.getResourceString("TypeCheckError"),
                name || 'Value',
                'Function',
                typeof value);
        }
    };
    
    exports.isValidParametersObject = function (value, name) {
        /// <summary>
        /// Ensure the Object instance of user-defined parameters is valid.
        /// </summary>
        /// <param name="value">The parameters to check.</param>
        /// <param name="name" mayBeNull="true" optional="true" type="String">
        /// Optional name of the value to throw.
        /// </param>
    
        exports.notNull(value, name);
        exports.isObject(value, name);
    
        for (var parameter in value) {
            if (parameter.indexOf('$') === 0) {
                throw _.format(
                    Platform.getResourceString("Validate_InvalidUserParameter"),
                    name,
                    parameter);
            }
        }
    };
    
    exports.isInteger = function (value, name) {
        /// <summary>
        /// Ensure the value is an integer.
        /// </summary>
        /// <param name="value" mayBeNull="true">The value to check.</param>
        /// <param name="name" mayBeNull="true" optional="true" type="String">
        /// Optional name of the value to throw.
        /// </param>
    
        exports.notNull(value, name);
        exports.isNumber(value, name);
    
        if (parseInt(value, 10) !== parseFloat(value)) {
            throw _.format(
                Platform.getResourceString("TypeCheckError"),
                name || 'Value',
                'number',
                typeof value);
        }
    };
    
    exports.isBool = function (value, name) {
        /// <summary>
        /// Ensure the value is a bool.
        /// </summary>
        /// <param name="value" mayBeNull="true">The value to check.</param>
        /// <param name="name" mayBeNull="true" optional="true" type="String">
        /// Optional name of the value to throw.
        /// </param>
    
        if (!_.isBool(value)) {
            throw _.format(
                Platform.getResourceString("TypeCheckError"),
                name || 'Value',
                'number',
                typeof value);
        }
    };
    
    exports.isString = function (value, name) {
        /// <summary>
        /// Ensure the value is a string.
        /// </summary>
        /// <param name="value" mayBeNull="true">The value to check.</param>
        /// <param name="name" mayBeNull="true" optional="true" type="String">
        /// Optional name of the value to throw.
        /// </param>
    
        if (!_.isString(value)) {
            throw _.format(
                Platform.getResourceString("TypeCheckError"),
                name || 'Value',
                'string',
                typeof value);
        }
    };
    
    exports.isObject = function (value, name) {
        /// <summary>
        /// Ensure the value is an Object.
        /// </summary>
        /// <param name="value" mayBeNull="true">The value to check.</param>
        /// <param name="name" mayBeNull="true" optional="true" type="String">
        /// Optional name of the value to throw.
        /// </param>
    
        if (!_.isObject(value)) {
            throw _.format(
                Platform.getResourceString("TypeCheckError"),
                name || 'Value',
                'object',
                typeof value);
        }
    };
    
    exports.isArray = function (value, name) {
        /// <summary>
        /// Ensure the value is an Array.
        /// </summary>
        /// <param name="value" mayBeNull="true">The value to check.</param>
        /// <param name="name" mayBeNull="true" optional="true" type="String">
        /// Optional name of the value to throw.
        /// </param>
    
        if (!Array.isArray(value)) {
            throw _.format(
                Platform.getResourceString("TypeCheckError"),
                name || 'Value',
                'array',
                typeof value);
        }
    };
    
    exports.length = function (value, length, name) {
        /// <summary>
        /// Ensure the value is of a given length.
        /// </summary>
        /// <param name="value" type="String">
        /// The value to check.
        /// </param>
        /// <param name="length" type="Number" integer="true">
        /// The desired length of the value.
        /// </param>
        /// <param name="name" mayBeNull="true" optional="true" type="String">
        /// Optional name of the value to throw.
        /// </param>
    
        exports.notNull(value, name);
        exports.isInteger(length, 'length');
    
        if (value.length !== length) {
            throw _.format(
                Platform.getResourceString("Validate_LengthUnexpected"),
                name || 'Value',
                length,
                value.length);
        }
    };
    
    },{"../Platform":234,"./Extensions":241}],245:[function(require,module,exports){
    // ----------------------------------------------------------------------------
    // Copyright (c) Microsoft Corporation. All rights reserved.
    // ----------------------------------------------------------------------------
    
    /**
     * @file Implements a task runner that runs synchronous / asynchronous tasks one after the other.
     * @private
     */
    
    var Validate = require('./Validate'),
        Platform = require('../Platform');
    
    module.exports = function () {
        
        var queue = [], // queue of pending tasks 
            isBusy; // true if a task is executing
        
        return {
            run: run
        };
        
        /**
         * Runs the specified task asynchronously after all the earlier tasks have completed
         * @param task Function / task to be executed. The task can either be a synchronous function or can return a promise.
         * @returns A promise that is resolved with the value returned by the task. If the task fails the promise is rejected.
         */
        function run(task) {
            return Platform.async(function(callback) {
                // parameter validation
                Validate.isFunction(task);
                Validate.isFunction(callback);
                
                // Add the task to the queue of pending tasks and trigger task processing
                queue.push({
                    task: task,
                    callback: callback
                });
                processTask();
            })();
        }
        
        /**
         * Asynchronously executes the first pending task
         */
        function processTask() {
            setTimeout(function() {
                if (isBusy || queue.length === 0) {
                    return;
                }
    
                isBusy = true;
    
                var next = queue.shift(),
                    result,
                    error;
    
                Platform.async(function(callback) { // Start a promise chain
                    callback();
                })().then(function() {
                    return next.task(); // Run the task
                }).then(function(res) { // task completed successfully
                    isBusy = false;
                    processTask();
                    next.callback(null, res); // resolve the promise returned by the run function
                }, function(err) { // task failed
                    isBusy = false;
                    processTask();
                    next.callback(err); // reject the promise returned by the run function
                });
            }, 0);
        }
    };
    
    },{"../Platform":234,"./Validate":244}],246:[function(require,module,exports){
    // ----------------------------------------------------------------------------
    // Copyright (c) Microsoft Corporation. All rights reserved.
    // ----------------------------------------------------------------------------
    
    module.exports = {
        featuresHeaderName: "X-ZUMO-FEATURES",
        features: {
            JsonApiCall: "AJ",               // Custom API call, where the request body is serialized as JSON
            GenericApiCall: "AG",            // Custom API call, where the request body is sent 'as-is'
            AdditionalQueryParameters: "QS", // Table or API call, where the caller passes additional query string parameters
            OptimisticConcurrency: "OC",     // Table update / delete call, using Optimistic Concurrency (If-Match headers)
            TableRefreshCall: "RF",          // Refresh table call
            TableReadRaw: "TR",              // Table reads where the caller uses a raw query string to determine the items to be returned
            TableReadQuery: "TQ",            // Table reads where the caller uses a function / query OM to determine the items to be returned
            OfflineSync: "OL",               // Table operations performed as part of offline sync (push and pull)
            IncrementalPull: "IP"            // Table reads performed as part of an incremental pull 
        },
        apiVersionHeaderName: "ZUMO-API-VERSION",
        apiVersion: "2.0.0",
        table: {
            idPropertyName: "id",
            sysProps: {
                deletedColumnName: "deleted",
                createdAtColumnName: "createdAt",
                updatedAtColumnName: "updatedAt",
                versionColumnName: "version"
            },
            includeDeletedFlag: "__includeDeleted",
            operationTableName: "__operations",
            pulltimeTableName: "__pulltime"
        }
    };
    
    },{}],247:[function(require,module,exports){
    // ----------------------------------------------------------------------------
    // Copyright (c) Microsoft Corporation. All rights reserved.
    // ----------------------------------------------------------------------------
    
    var _ = require('./Utilities/Extensions');
    
    /**
     * This module is the entry point for the _Azure Mobile Apps Javascript client SDK_. 
     *
     * The SDK can be consumed in multiple ways:
     * - In the form of [Cordova SDK](https://github.com/Azure/azure-mobile-apps-cordova-client) for use in a Cordova app.
     * - As a standalone Javascript bundle for use in web apps.
     * - As an npm package for use in web apps. 
     *
     * When used in the form of either Cordova SDK or a standalone Javascript bundle, the module's exports are added to the 
     * _WindowsAzure_ namespace. Here's an example of how to use it:
     * ```
     * var client = new WindowsAzure.MobileServiceClient('http://azure-mobile-apps-backend-url');
     * var table = client.getTable('mytable');
     * ```
     * 
     * When used as an npm package, here is how to use it:
     * ```
     * var AzureMobileApps = require('azure-mobile-apps-client');
     * var client = new AzureMobileApps.MobileServiceClient('http://azure-mobile-apps-backend-url');
     * var table = client.getTable('mytable');
     * ```
     * 
     * @exports azure-mobile-apps-client
     */
    var api = { // Modules that need to be exposed outside the SDK for all targets
        /**
         * @type {MobileServiceClient} 
         */
        MobileServiceClient: require('./MobileServiceClient'),
    
        /** 
         * @type {QueryJs}
         */
        Query: require('azure-query-js').Query
    };
    
    // Target (i.e. Cordova / Browser / etc) specific definitions that need to be exposed outside the SDK
    var targetExports = require('./Platform/sdkExports');
    
    // Export shared as well as target specific APIs
    for (var i in targetExports) {
        if ( _.isNull(api[i]) ) {
            api[i] = targetExports[i];
        } else {
            throw new Error('Cannot export definition ' + i + ' outside the SDK. Multiple definitions with the same name exist');
        }
    }
    
    /** 
     * @type {MobileServiceSqliteStore}
     * @name MobileServiceSqliteStore
     * @description **Note** that this class is available **_only_** as part of the Cordova SDK.
     */
    
    module.exports = api;
    
    
    },{"./MobileServiceClient":224,"./Platform/sdkExports":235,"./Utilities/Extensions":241,"azure-query-js":274}],248:[function(require,module,exports){
    module.exports={
        "TypeCheckError"                                        : "'{0}' is expected to be a value of type {1}, not {2}.",
        "Validate_NotNullError"                                 : "{0} cannot be null.",
        "Validate_NotNullOrEmptyError"                          : "{0} cannot be null or empty.",
        "Validate_LengthUnexpected"                             : "{0} is expected to have length {1}, not {2}.",
        "Validate_InvalidUserParameter"                         : "{0} contains an invalid user-defined query string parameter: {1}. User-defined query string parameters must not begin with a '$'.",
        "Extensions_DefaultErrorMessage"                        : "Unexpected failure.",
        "Extensions_ConnectionFailureMessage"                   : "Unexpected connection failure.",
        "MobileServiceTable_ReadMismatchedQueryTables"          : "Cannot get the results of a query for table '{1}' via table '{0}'.",
        "MobileServiceLogin_AuthenticationProviderNotSupported" : "Unsupported authentication provider name. Please specify one of {0}.",
        "MobileServiceLogin_InvalidResponseFormat"              : "Invalid format of the authentication response.",
        "MobileServiceLogin_InvalidProvider"                    : "The first parameter must be the name of the authentication provider or a Microsoft Account authentication token.",
        "MobileServiceTable_NotSingleObject"                    : "Could not get object from response {0}.",
        "Push_ConflictWithReservedName"                         : "Template name conflicts with reserved name '{0}'.",
        "Push_InvalidTemplateName"                              : "Template name can't contain ';' or ':'.",
        "Push_NotSupportedXMLFormatAsBodyTemplateWin8"          : "The bodyTemplate is not in accepted XML format. The first node of the bodyTemplate should be Badge\/Tile\/Toast, except for the wns\/raw template, which need to be a valid XML.",
        "Push_BodyTemplateMustBeXml"                            : "Valid XML is required for any template without a raw header.",
        "Push_TagNoCommas"                                      : "Tags must not contain ','.",
        "sqliteSerializer_SerializationFailed"                  : "Failed to serialize value {0}. Column definition: {1}",
        "sqliteSerializer_DeserializationFailed"                : "Failed to deserialize value {0}. Column definition: {1}",
        "sqliteSerializer_UnsupportedColumnType"                : "Column type '{0}' is not supported",
        "sqliteSerializer_UnsupportedTypeConversion"            : "Converting value {0} of type {1} to type {2} is not supported"
    }
    },{}],249:[function(require,module,exports){
    // ----------------------------------------------------------------------------
    // Copyright (c) Microsoft Corporation. All rights reserved.
    // ----------------------------------------------------------------------------
    
    /**
     * Valid column types to be used for defining table schema.
     * These types will be mapped to an equivalent SQLite type - TEXT / INT / REAL - while performing SQLite operations.
     */
    module.exports = {
        Object: "object",
        Array: "array",
        Integer: "integer",
        Int: "int",
        Float: "float",
        Real: "real",
        String: "string",
        Text: "text",
        Boolean: "boolean",
        Bool: "bool",
        Date: "date"
    };
    
    //TODO: Numeric / Number data type
    
    },{}],250:[function(require,module,exports){
    // ----------------------------------------------------------------------------
    // Copyright (c) Microsoft Corporation. All rights reserved.
    // ----------------------------------------------------------------------------
    
    var Validate = require('../Utilities/Validate'),
        Platform = require('../Platform'),
        createOperationTableManager = require('./operations').createOperationTableManager,
        taskRunner = require('../Utilities/taskRunner'),
        createPullManager = require('./pull').createPullManager,
        createPushManager = require('./push').createPushManager,
        createPurgeManager = require('./purge').createPurgeManager,
        uuid = require('node-uuid'),
        _ = require('../Utilities/Extensions');
    
    
    // NOTE: The store can be a custom store provided by the user code.
    // So we do parameter validation ourselves without delegating it to the
    // store, even where it is possible.
    
    /**
     * Settings for configuring the pull behavior
     * @typedef MobileServiceSyncContext.PullSettings
     * @property {number} pageSize Specifies the number of records to request as part of a page pulled from the server tables.
     */
    
    /**
     * Callback to delegate conflict handling to the user while pushing changes to the server. The conflict handler should
     * update the isHandled property of the pushConflict parameter appropriately on completion. If a conflict is marked as handled,
     * the push logic will attempt to push the change again. If not, the push logic will note the conflict, **skip** the change and
     * proceed to push the next change.
     * @callback MobileServiceSyncContext.ConflictHandler
     * @param {PushError} pushConflict Push conflict. 
     * @returns {Promise | undefined} This method can either return synchronously or can return a promise that is resolved 
     *                           or rejected when conflict handling completes / fails.
     */
    
    /**
     * Callback to delegate error handling to the user while pushing changes to the server. Note that an error is a failure other
     * than a conflict. The error handler should update the isHandled property of the pushError parameter appropriately on completion.
     * If a conflict is marked as handled, the push logic will attempt to push the change again.
     * If not, the push logic will **abort** the push operation without attempting to push the remaining changes.
     * @callback MobileServiceSyncContext.ErrorHandler
     * @param {PushError} pushError Push Error.
     * @returns {Promise | undefined} This method can either return synchronously or can return a promise that is resolved 
     *                           or rejected when conflict handling completes / fails.
     */
    
    /**
     * Defines callbacks for performing conflict and error handling.
     * @typedef {object} MobileServiceSyncContext.PushHandler
     * @property {MobileServiceSyncContext.ConflictHandler} onConflict Callback for delegating conflict handling to the user.
     * @property {MobileServiceSyncContext.ErrorHandler} onError Callback for delegating error handling to the user.
     */
    
    /**
     * @class
     * @classdesc Context for local store operations.
     * @protected
     * 
     * @param {MobileServiceClient} client The {@link MobileServiceClient} instance to be used to make 
     *                                     requests to the backend (server).
     */
    function MobileServiceSyncContext(client) {
    
        Validate.notNull(client, 'client');
        
        var store,
            operationTableManager,
            pullManager,
            pushManager,
            purgeManager,
            isInitialized = false,
            syncTaskRunner = taskRunner(), // Used to run push / pull tasks
            storeTaskRunner = taskRunner(); // Used to run insert / update / delete tasks on the store
    
        /**
         * Initializes the {@link MobileServiceSyncContext} instance. Initailizing an initialized instance of 
         * {@link MobileServiceSyncContext} will have no effect.
         * 
         * @param {MobileServiceStore} localStore An intitialized instance of the {@link MobileServiceStore local store} to be associated 
         *                                        with the {@link MobileServiceSyncContext} instance.
         * 
         * @returns {Promise} A promise that is resolved when the initialization is completed successfully.
          *                    If initialization fails, the promise is rejected with the error.
         */
        this.initialize = function (localStore) {
            
            return Platform.async(function(callback) {
                Validate.isObject(localStore);
                Validate.notNull(localStore);
                
                callback(null, createOperationTableManager(localStore));
            })().then(function(opManager) {
                operationTableManager = opManager;
                return operationTableManager.initialize(localStore);
            }).then(function() {
                store = localStore;
                pullManager = createPullManager(client, store, storeTaskRunner, operationTableManager);
                pushManager = createPushManager(client, store, storeTaskRunner, operationTableManager);
                purgeManager = createPurgeManager(store, storeTaskRunner);
            }).then(function() {
                return pullManager.initialize();
            }).then(function() {
                isInitialized = true;
            });
            
        };
    
        /**
         * Inserts a new object / record into the specified local table.
         * If the inserted object does not specify an id, a GUID will be used as the id.
         * 
         * @param {string} tableName Name of the local table in which the object / record is to be inserted.
         * @param {object} instance The object / record to be inserted into the local table.
         * @param {string} instance.id The id of the record. If this is null / undefined, a GUID string
         *                             will be used as the id.
         * 
         * @returns {Promise} A promise that is resolved with the inserted object when the insert operation is completed successfully.
         *                    If the operation fails, the promise is rejected with the error.
         */
        this.insert = function (tableName, instance) { //TODO: add an insert method to the store
            return storeTaskRunner.run(function() {
                validateInitialization();
                
                // Generate an id if it is not set already 
                if (_.isNull(instance.id)) {
                    instance.id = uuid.v4();
                }
    
                // Delegate parameter validation to upsertWithLogging
                return upsertWithLogging(tableName, instance, 'insert');
            });
        };
    
        /**
         * Update an object / record in the specified local table.
         * The id of the object / record identifies the record that will be updated in the table.
         * 
         * @param {string} tableName Name of the local table in which the object / record is to be updated.
         * @param {object} instance New value of the object / record to be updated.
         * @param {string} instance.id The id of the object / record identifies the record that will be updated in the table.
         * 
         * @returns {Promise} A promise that is resolved when the operation is completed successfully. 
         *                    If the operation fails, the promise is rejected.
         */
        this.update = function (tableName, instance) { //TODO: add an update method to the store
            return storeTaskRunner.run(function() {
                validateInitialization();
                
                // Delegate parameter validation to upsertWithLogging
                return upsertWithLogging(tableName, instance, 'update', true /* shouldOverwrite */);
            });
        };
    
        /**
         * Looks up an object / record from the specified local table using the object id.
         * 
         * @param {string} tableName Name of the local table in which to look up the object / record.
         * @param {string} id id of the object to be looked up in the local table.
         * @param {boolean} [suppressRecordNotFoundError] If set to true, lookup will return an undefined object
         *                                                if the record is not found. Otherwise, lookup will fail.
         *                                                This flag is useful to distinguish between a lookup
         *                                                failure due to the record not being present in the table
         *                                                versus a genuine failure in performing the lookup operation.
         * 
         * @returns {Promise} A promise that is resolved with the looked up object when the lookup is completed successfully.
         *                    If the operation fails, the promise is rejected with the error.
         */
        this.lookup = function (tableName, id, suppressRecordNotFoundError) {
            
            return Platform.async(function(callback) {
                validateInitialization();
                
                Validate.isString(tableName, 'tableName');
                Validate.notNullOrEmpty(tableName, 'tableName');
    
                Validate.isValidId(id, 'id');
    
                if (!store) {
                    throw new Error('MobileServiceSyncContext not initialized');
                }
                
                callback();
            })().then(function() {
                return store.lookup(tableName, id, suppressRecordNotFoundError);
            });
        };
    
    
        /**
         * Reads records from the specified local table.
         * 
         * @param {QueryJs} query A {@link QueryJs} object representing the query to use while
         *                        reading the local table
         * @returns {Promise} A promise that is resolved with an array of records read from the table, if the read is successful.
         *                    If read fails, the promise is rejected with the error.
         */
        this.read = function (query) {
            
            return Platform.async(function(callback) {
                callback();
            })().then(function() {
                validateInitialization();
    
                Validate.notNull(query, 'query');
                Validate.isObject(query, 'query');
    
                return store.read(query);
            });
        };
    
    
        /**
         * Deletes an object / record from the specified local table.
         * 
         * @param {string} tableName Name of the local table to delete the object from.
         * @param {object} instance The object to delete from the local table. 
         * @param {string} instance.id id of the record to be deleted.
         * 
         * @returns {Promise} A promise that is resolved when the delete operation completes successfully.
         *                    If the operation fails, the promise is rejected with the error.
         */
        this.del = function (tableName, instance) {
            
            return storeTaskRunner.run(function() {
                validateInitialization();
                
                Validate.isString(tableName, 'tableName');
                Validate.notNullOrEmpty(tableName, 'tableName');
    
                Validate.notNull(instance);
                Validate.isValidId(instance.id);
    
                if (!store) {
                    throw new Error('MobileServiceSyncContext not initialized');
                }
    
                return operationTableManager.getLoggingOperation(tableName, 'delete', instance).then(function(loggingOperation) {
                    return store.executeBatch([
                        {
                            action: 'delete',
                            tableName: tableName,
                            id: instance.id
                        },
                        loggingOperation
                    ]);
                });
            });
        };
        
        /**
         * Pulls changes from server table into the local store.
         * 
         * @param {QueryJs} query Query specifying which records to pull.
         * @param {string} queryId A unique string id for an incremental pull query. A null / undefined queryId 
         *                         will perform a vanilla pull, i.e. will pull all the records specified by the table
         *                         from the server 
         * @param {MobileServiceSyncContext.PullSettings} [settings] An object that defines various pull settings. 
         * 
         * @returns {Promise} A promise that is fulfilled when all records are pulled OR is rejected if the pull fails or is cancelled.  
         */
        this.pull = function (query, queryId, settings) { 
            //TODO: Implement cancel
            //TODO: Perform push before pulling
            return syncTaskRunner.run(function() {
                validateInitialization();
                
                return pullManager.pull(query, queryId, settings);
            });
        };
        
        /**
         * Pushes local changes to the corresponding tables on the server.
         * 
         * Conflict and error handling are delegated to {@link MobileServiceSyncContext#pushHandler}.
         * 
         * @returns {Promise} A promise that is fulfilled with an array of encountered conflicts when all changes
         *                    are pushed to the server without errors. Note that a conflict is not treated as an error.
         *                    The returned promise is rejected if the push fails.  
         */
        this.push = function () { //TODO: Implement cancel
            return syncTaskRunner.run(function() {
                validateInitialization();
    
                return pushManager.push(this.pushHandler);
            }.bind(this));
        };
        
        /**
         * Purges data from the local table as well as pending operations and any incremental sync state 
         * associated with the table.
         * 
         * A _regular purge_, would fail if there are any pending operations for the table being purged.
         * 
         * A _forced purge_ will proceed even if pending operations for the table being purged exist in the operation table. In addition,
         * it will also delete the table's pending operations.
         * 
         * @param {QueryJs} query A {@link QueryJs} object representing the query that specifies what records are to be purged.
         * @param {boolean} forcePurge If set to true, the method will perform a forced purge.
         * 
         * @returns {Promise} A promise that is fulfilled when purge is complete OR is rejected if it fails.  
         */
        this.purge = function (query, forcePurge) {
            return syncTaskRunner.run(function() {
                Validate.isObject(query, 'query');
                Validate.notNull(query, 'query');
                if (!_.isNull(forcePurge)) {
                    Validate.isBool(forcePurge, 'forcePurge');
                }
    
                validateInitialization();
    
                return purgeManager.purge(query, forcePurge);
            }.bind(this));
        };
    
        /**
         * @property {MobileServiceSyncContext.PushHandler} pushHandler Defines push handler.
         */
        this.pushHandler = undefined;
    
        // Unit test purposes only
        this._getOperationTableManager = function () {
            return operationTableManager;
        };
        this._getPurgeManager = function() {
            return purgeManager;
        };
        
        // Performs upsert and logs the action in the operation table
        // Validates parameters. Callers can skip validation
        function upsertWithLogging(tableName, instance, action, shouldOverwrite) {
            Validate.isString(tableName, 'tableName');
            Validate.notNullOrEmpty(tableName, 'tableName');
    
            Validate.notNull(instance, 'instance');
            Validate.isValidId(instance.id, 'instance.id');
            
            if (!store) {
                throw new Error('MobileServiceSyncContext not initialized');
            }
            
            return store.lookup(tableName, instance.id, true /* suppressRecordNotFoundError */).then(function(existingRecord) {
                if (existingRecord && !shouldOverwrite) {
                    throw new Error('Record with id ' + existingRecord.id + ' already exists in the table ' + tableName);
                }
            }).then(function() {
                return operationTableManager.getLoggingOperation(tableName, action, instance);
            }).then(function(loggingOperation) {
                return store.executeBatch([
                    {
                        action: 'upsert',
                        tableName: tableName,
                        data: instance
                    },
                    loggingOperation
                ]);
            }).then(function() {
                return instance;
            });
        }
    
        // Throws an error if the sync context is not initialized
        function validateInitialization() {
            if (!isInitialized) {
                throw new Error ('MobileServiceSyncContext is being used before it is initialized');
            }
        }
    }
    
    module.exports = MobileServiceSyncContext;
    
    },{"../Platform":234,"../Utilities/Extensions":241,"../Utilities/Validate":244,"../Utilities/taskRunner":245,"./operations":252,"./pull":253,"./purge":254,"./push":255,"node-uuid":280}],251:[function(require,module,exports){
    // ----------------------------------------------------------------------------
    // Copyright (c) Microsoft Corporation. All rights reserved.
    // ----------------------------------------------------------------------------
    
    var Validate = require('../Utilities/Validate'),
        Query = require('azure-query-js').Query,
        _ = require('../Utilities/Extensions'),
        tableHelper = require('../tableHelper'),
        Platform = require('../Platform');
    
    /**
     * @class
     * @classdesc Represents a table in the local store.
     * @protected
     * 
     * @param {string} tableName Name of the local table.
     * @param {MobileServiceClient} client The {@link MobileServiceClient} instance associated with this table.
     */
    function MobileServiceSyncTable(tableName, client) {
        Validate.isString(tableName, 'tableName');
        Validate.notNullOrEmpty(tableName, 'tableName');
    
        Validate.notNull(client, 'client');
    
        /**
         * Gets the name of the local table.
         * 
         * @returns {string} The name of the table.
         */
        this.getTableName = function () {
            return tableName;
        };
    
        /**
         * Gets the {@link MobileServiceClient} instance associated with this table.
         * 
         * @returns {MobileServiceClient} The {@link MobileServiceClient} associated with this table.
         */
        this.getMobileServiceClient = function () {
            return client;
        };
    
        /**
         * Inserts a new object / record in the local table.
         * If the inserted object does not specify an id, a GUID will be used as the id.
         * 
         * @param {object} instance Object / record to be inserted in the local table.
         * @param {string} instance.id The id of the record. If this is null / undefined, a GUID string
         *                             will be used as the id.
         * @returns {Promise} A promise that is resolved with the inserted object when the insert operation is completed successfully.
         *                    If the operation fails, the promise is rejected with the error.
         */
        this.insert = function (instance) {
            return client.getSyncContext().insert(tableName, instance);
        };
    
        /**
         * Update an object / record in the local table.
         * 
         * @param {object} instance New value of the object / record.
         * @param {string} instance.id The id of the object / record identifies the record that will be updated in the table.
         * 
         * @returns {Promise} A promise that is resolved when the operation is completed successfully.
         *                    If the operation fails, the promise is rejected with the error.
         */
        this.update = function (instance) {
            return client.getSyncContext().update(tableName, instance);
        };
    
        /**
         * Looks up an object / record from the local table using the object id.
         * 
         * @param {string} id id of the object to be looked up in the local table.
         * @param {boolean} [suppressRecordNotFoundError] If set to true, lookup will return an undefined object
         *                                                if the record is not found. Otherwise, lookup will fail.
         *                                                This flag is useful to distinguish between a lookup
         *                                                failure due to the record not being present in the table
         *                                                versus a genuine failure in performing the lookup operation.
         * 
         * @returns {Promise} A promise that is resolved with the looked up object when the lookup is completed successfully.
         *                    If the operation fails, the promise is rejected with the error.
         */
        this.lookup = function (id, suppressRecordNotFoundError) {
            return client.getSyncContext().lookup(tableName, id, suppressRecordNotFoundError);
        };
    
        /**
         * Reads records from the local table.
         * 
         * @param {QueryJs} query A {@link QueryJs} object representing the query to use while
         *                        reading the local table
         * @returns {Promise} A promise that is resolved with an array of records read from the table, if the read is successful.
         *                    If read fails, the promise is rejected with the error.
         */
        this.read = function (query) {
            if (_.isNull(query)) {
                query = new Query(tableName);
            }
            
            return client.getSyncContext().read(query);
        };
    
        /**
         * Deletes an object / record from the local table.
         * 
         * @param {object} instance The object to delete from the local table. 
         * @param {string} instance.id id of the record to be deleted.
         * 
         * @returns {Promise} A promise that is resolved when the delete operation completes successfully.
         *                    If the operation fails, the promise is rejected with the error.
         */
        this.del = function (instance) {
            return client.getSyncContext().del(tableName, instance);
        };
    
        /**
         * Pulls changes from server table into the local table.
         * 
         * @param {QueryJs} query Query specifying which records to pull.
         * @param {string} queryId A unique string id for an incremental pull query. A null / undefined queryId 
         *                         will perform a vanilla pull, i.e. will pull all the records specified by the table
         *                         from the server 
         * @param {MobileServiceSyncContext.PullSettings} [settings] An object that defines various pull settings. 
         * 
         * @returns {Promise} A promise that is fulfilled when all records are pulled OR is rejected  with the error if pull fails.  
         */
        this.pull = function (query, queryId, settings) {
            if (!query) {
                query = new Query(tableName);
            }
            
            return client.getSyncContext().pull(query, queryId, settings);
        };
    
        /**
         * Purges data from the local table as well as pending operations and any incremental sync state 
         * associated with the table.
         * 
         * A _regular purge_, would fail if there are any pending operations for the table being purged.
         * 
         * A _forced purge_ will proceed even if pending operations for the table being purged exist in the operation table. In addition,
         * it will also delete the table's pending operations.
         * 
         * @param {QueryJs} query A {@link QueryJs} object representing the query that specifies what records are to be purged.
         * @param {boolean} forcePurge If set to true, the method will perform a forced purge.
         * 
         * @returns {Promise} A promise that is fulfilled when purge is complete OR is rejected with the error if it fails.  
         */
        this.purge = function (query, forcePurge) {
            if (!query) {
                query = new Query(tableName);
            }
    
            return client.getSyncContext().purge(query, forcePurge);
        };
    }
    
    // Define query operators
    tableHelper.defineQueryOperators(MobileServiceSyncTable);
    
    exports.MobileServiceSyncTable = MobileServiceSyncTable;
    
    },{"../Platform":234,"../Utilities/Extensions":241,"../Utilities/Validate":244,"../tableHelper":257,"azure-query-js":274}],252:[function(require,module,exports){
    // ----------------------------------------------------------------------------
    // Copyright (c) Microsoft Corporation. All rights reserved.
    // ----------------------------------------------------------------------------
    
    /**
     * @file Implements operation table management functions like defining the operation table,
     * adding log operations to the operation table, condensing operations, etc
     * @private
     */
    
    var Validate = require('../Utilities/Validate'),
        Platform = require('../Platform'),
        ColumnType = require('./ColumnType'),
        taskRunner = require('../Utilities/taskRunner'),
        tableConstants = require('../constants').table,
        _ = require('../Utilities/Extensions'),
        Query = require('azure-query-js').Query;
    
    var idPropertyName = tableConstants.idPropertyName,
        versionColumnName = tableConstants.sysProps.versionColumnName,
        operationTableName = tableConstants.operationTableName;
        
    function createOperationTableManager(store) {
    
        Validate.isObject(store);
        Validate.notNull(store);
    
        var runner = taskRunner(),
            isInitialized,
            maxOperationId = 0,
            lockedOperationId,
            maxId;
    
        var api = {
            initialize: initialize,
            lockOperation: lockOperation,
            unlockOperation: unlockOperation,
            readPendingOperations: readPendingOperations,
            readFirstPendingOperationWithData: readFirstPendingOperationWithData,
            removeLockedOperation: removeLockedOperation,
            getLoggingOperation: getLoggingOperation,
            getMetadata: getMetadata
        };
    
        // Exports for testing purposes only
        api._getOperationForInsertingLog = getOperationForInsertingLog;
        api._getOperationForUpdatingLog = getOperationForUpdatingLog;
    
        return api;
        
        /**
         * Defines the operation table in the local store.
         * Schema of the operation table is: [ INT id | TEXT tableName | TEXT action | TEXT itemId ]
         * If the table already exists, it will have no effect.
         * @param localStore The local store to create the operation table in.
         * @returns A promise that is resolved when initialization is complete and rejected if it fails.
         */
        function initialize () {
            return store.defineTable({
                name: operationTableName,
                columnDefinitions: {
                    id: ColumnType.Integer,
                    tableName: ColumnType.String,
                    action: ColumnType.String,
                    itemId: ColumnType.String,
                    metadata: ColumnType.Object 
                }
            }).then(function() {
                return getMaxOperationId();
            }).then(function(id) {
                maxId = id;
                isInitialized = true;
            });
        }
        
        /**
         * Locks the operation with the specified id.
         * 
         * TODO: Lock state and the value of the locked operation should be persisted.
         * That way we can handle the following scenario: insert -> initiate push -> connection failure after item inserted in server table
         * -> client crashes or cancels push -> client app starts again -> delete -> condense. 
         * In the above scenario if we condense insert and delete into nothing, we end up not deleting the item we sent to server.
         * And if we do not condense, insert will have no corresponding data in the table to send to the server while pushing as 
         * the record would have been deleted.
         */
        function lockOperation(id) {
            return runner.run(function() {
                // Locking a locked operation should have no effect
                if (lockedOperationId === id) {
                    return;
                }
                
                if (!lockedOperationId) {
                    lockedOperationId = id;
                    return;
                }
    
                throw new Error('Only one operation can be locked at a time');
            });
        }
        
        /**
         * Unlock the locked operation
         */
        function unlockOperation() {
            return runner.run(function() {
                lockedOperationId = undefined;
            });
        }
        
        /**
         * Given an operation that will be performed on the store, this method returns a corresponding operation for recording it in the operation table.
         * The logging operation can add a new record, edit an earlier record or remove an earlier record from the operation table.
         * 
         * @param tableName Name of the table on which the action is performed
         * @param action Action performed on the table. Valid actions are 'insert', 'update' or 'delete'
         * @param item Record that is being inserted, updated or deleted. In case of 'delete', all properties other than id will be ignored.
         * 
         * @returns Promise that is resolved with the logging operation. In case of a failure the promise is rejected.
         */
        function getLoggingOperation(tableName, action, item) {
            
            // Run as a single task to avoid task interleaving.
            return runner.run(function() {
                Validate.notNull(tableName);
                Validate.isString(tableName);
                
                Validate.notNull(action);
                Validate.isString(action);
                
                Validate.notNull(item);
                Validate.isObject(item);
                Validate.isValidId(item[idPropertyName]);
    
                if (!isInitialized) {
                    throw new Error('Operation table manager is not initialized');
                }
                
                return readPendingOperations(tableName, item[idPropertyName]).then(function(pendingOperations) {
                    
                    // Multiple operations can be pending for <tableName, itemId> due to an opertion being locked in the past.
                    // Get the last pending operation
                    var pendingOperation = pendingOperations.pop(),
                        condenseAction;
                    
                    // If the operation table has a pending operation, we attempt to condense the new action into the pending operation.
                    // If not, we simply add a new operation.
                    if (pendingOperation) {
                        condenseAction = getCondenseAction(pendingOperation, action);
                    } else {
                        condenseAction = 'add';
                    }
    
                    if (condenseAction === 'add') { // Add a new operation
                        return getOperationForInsertingLog(tableName, action, item);
                    } else if (condenseAction === 'modify') { // Edit the pending operation's action to be the new action.
                        return getOperationForUpdatingLog(pendingOperation.id, tableName, action /* new action */, item);
                    } else if (condenseAction === 'remove') { // Remove the earlier log from the operation table
                        return getOperationForDeletingLog(pendingOperation.id);
                    } else if (condenseAction === 'nop') { // NO OP. Nothing to be logged
                        return; 
                    } else  { // Error
                        throw new Error('Unknown condenseAction: ' + condenseAction);
                    }
                });
            });
        }
        
        /**
         * Reads the pending operations for the specified table and item / record ID from the operation table.
         * @param tableName Name of the table whose operations we are looking for
         * @param itemId ID of the record whose operations we are looking for 
         */
        function readPendingOperations(tableName, itemId) {
            return Platform.async(function(callback) {
                callback();
            })().then(function() {
                var query = new Query(operationTableName);
                return store.read(query.where(function (tableName, itemId) {
                    return this.tableName === tableName && this.itemId === itemId;
                }, tableName, itemId).orderBy('id'));
            });
        }
        
        /**
         * Gets the first / oldest pending operation, i.e. the one with smallest id value
         * 
         * @returns Object containing logRecord (record from the operation table) and an optional data record (i.e. record associated with logRecord).
         * The data record will be present only for insert and update operations.
         */
        function readFirstPendingOperationWithData(lastProcessedOperationId) {
            return runner.run(function() {
                return readFirstPendingOperationWithDataInternal(lastProcessedOperationId);
            });
        }
    
        /**
         * Removes the operation that is currently locked
         * 
         * @returns A promise that is fulfilled when the locked operation is unlocked.
         * If no operation is currently locked, the promise is rejected.
         */
        function removeLockedOperation() {
            return removePendingOperation(lockedOperationId).then(function() {
                return unlockOperation();
            });
        }
        
    
        // Checks if the specified operation is locked
        function isLocked(operation) {
            return operation && operation.id === lockedOperationId;
        }
    
        function readFirstPendingOperationWithDataInternal(lastProcessedOperationId) {
            var logRecord, // the record logged in the operation table
                query = new Query(operationTableName).where(function(lastProcessedOperationId) {
                            return this.id > lastProcessedOperationId;
                        }, lastProcessedOperationId).orderBy('id').take(1);
            
            // Read record from operation table with the smallest ID
            return store.read(query).then(function(result) {
                if (result.length === 1) {
                    logRecord = result[0];
                } else if (result.length === 0) { // no pending records
                    return;
                } else {
                    throw new Error('Something is wrong!');
                }
            }).then(function() {
                if (!logRecord) { // no pending records
                    return;
                }
                
                if (logRecord.action === 'delete') {
                    return {
                        logRecord: logRecord
                    };
                }
                
                // Find the data record associated with the log record. 
                return store.lookup(logRecord.tableName, logRecord.itemId, true /* suppressRecordNotFoundError */).then(function(data) {
                    if (data) { // Return the log record and the data record.
                        return {
                            logRecord: logRecord,
                            data: data
                        };
                    }
                    
                    // It is possible that a log record corresponding to an insert / update operation has no corresponding
                    // data record. 
                    // 
                    // This can happen in the following scenario:
                    // insert -> push / lock operation begins -> delete -> push fails
                    //  
                    // In such a case, we remove the log operation from the operation table and proceed to the next log operation.
                    return removePendingOperationInternal(logRecord.id).then(function() {
                        lastProcessedOperationId = logRecord.id;
                        return readFirstPendingOperationWithDataInternal(lastProcessedOperationId);
                    });
                });
            });
        }
        
        function removePendingOperation(id) {
            return runner.run(function() {
                return removePendingOperationInternal(id);
            });
        }
    
        function removePendingOperationInternal(id) {
            return Platform.async(function(callback) {
                callback();
            })().then(function() {
                if (!id) {
                    throw new Error('Invalid operation id');
                }
                return store.del(operationTableName, id);
            });
        }
    
        /**
         * Determines how to condense the new action into the pending operation
         * @returns 'nop' - if no action is needed
         *          'remove' - if the pending operation should be removed
         *          'modify' - if the pending action should be modified to be the new action
         *          'add' - if a new operation should be added
         */
        function getCondenseAction(pendingOperation, newAction) {
            
            var pendingAction = pendingOperation.action,
                condenseAction;
            if (pendingAction === 'insert' && newAction === 'update') {
                condenseAction = 'nop';
            } else if (pendingAction === 'insert' && newAction === 'delete') {
                condenseAction = 'remove';
            } else if (pendingAction === 'update' && newAction === 'update') {
                condenseAction = 'nop';
            } else if (pendingAction === 'update' && newAction === 'delete') {
                condenseAction = 'modify';
            } else if (pendingAction === 'delete' && newAction === 'delete') {
                condenseAction = 'nop';
            } else if (pendingAction === 'delete') {
                throw new Error('Operation ' + newAction + ' not supported as a DELETE operation is pending'); //TODO: Limitation on all client SDKs
            } else {
                throw new Error('Condense not supported when pending action is ' + pendingAction + ' and new action is ' + newAction);
            }
            
            if (isLocked(pendingOperation)) {
                condenseAction = 'add';
            }
            
            return condenseAction;
        }
        
        /**
         * Gets the operation that will insert a new record in the operation table.
         */
        function getOperationForInsertingLog(tableName, action, item) {
            return api.getMetadata(tableName, action, item).then(function(metadata) {
                return {
                    tableName: operationTableName,
                    action: 'upsert',
                    data: {
                        id: ++maxId,
                        tableName: tableName,
                        action: action,
                        itemId: item[idPropertyName],
                        metadata: metadata
                    }
                };
            });
        }
        
        /**
         * Gets the operation that will update an existing record in the operation table.
         */
        function getOperationForUpdatingLog(operationId, tableName, action, item) {
            return api.getMetadata(tableName, action, item).then(function(metadata) {
                return {
                    tableName: operationTableName,
                    action: 'upsert',
                    data: {
                        id: operationId,
                        action: action,
                        metadata: metadata
                    }
                };
            });
        }
        
        /**
         * Gets an operation that will delete a record from the operation table.
         */
        function getOperationForDeletingLog(operationId) {
            return {
                tableName: operationTableName,
                action: 'delete',
                id: operationId
            };
        }
    
        /**
         * Gets the metadata to associate with a log record in the operation table
         * 
         * @param action 'insert', 'update' and 'delete' correspond to the insert, update and delete operations.
         *               'upsert' is a special action that is used only in the context of conflict handling.
         */
        function getMetadata(tableName, action, item) {
            
            return Platform.async(function(callback) {
                callback();
            })().then(function() {
                var metadata = {};
    
                // If action is update and item defines version property OR if action is insert / update,
                // define metadata.version to be the item's version property
                if (action === 'upsert' || 
                    action === 'insert' ||
                    (action === 'update' && item.hasOwnProperty(versionColumnName))) {
                    metadata[versionColumnName] = item[versionColumnName];
                    return metadata;
                } else if (action == 'update' || action === 'delete') { // Read item's version property from the table
                    return store.lookup(tableName, item[idPropertyName], true /* suppressRecordNotFoundError */).then(function(result) {
                        if (result) {
                            metadata[versionColumnName] = result[versionColumnName];
                        }
                        return metadata;
                    });
                } else {
                    throw new Error('Invalid action ' + action);
                }
            });
            
        }
    
        /**
         * Gets the largest operation ID from the operation table
         * If there are no records in the operation table, returns 0.
         */
        function getMaxOperationId() {
            var query = new Query(operationTableName);
            return store.read(query.orderByDescending('id').take(1)).then(function(result) {
                Validate.isArray(result);
                
                if (result.length === 0) {
                    return 0;
                } else if (result.length === 1) {
                    return result[0].id;
                } else {
                    throw new Error('something is wrong!');
                }
            });
        }
    }
    
    module.exports = {
        createOperationTableManager: createOperationTableManager
    };
    
    },{"../Platform":234,"../Utilities/Extensions":241,"../Utilities/Validate":244,"../Utilities/taskRunner":245,"../constants":246,"./ColumnType":249,"azure-query-js":274}],253:[function(require,module,exports){
    // ----------------------------------------------------------------------------
    // Copyright (c) Microsoft Corporation. All rights reserved.
    // ----------------------------------------------------------------------------
    
    /**
     * @file Table pull logic implementation
     * @private
     */
    
    var Validate = require('../Utilities/Validate'),
        Query = require('azure-query-js').Query,
        Platform = require('../Platform'),
        taskRunner = require('../Utilities/taskRunner'),
        MobileServiceTable = require('../MobileServiceTable'),
        constants = require('../constants'),
        tableConstants = constants.table,
        _ = require('../Utilities/Extensions');
        
    var defaultPageSize = 50,
        idPropertyName = tableConstants.idPropertyName,
        pulltimeTableName = tableConstants.pulltimeTableName,
        sysProps = tableConstants.sysProps;
        
    function createPullManager(client, store, storeTaskRunner, operationTableManager) {
        // Task runner for running pull tasks. We want only one pull to run at a time. 
        var pullTaskRunner = taskRunner(),
            mobileServiceTable,
            pageSize,
            lastKnownUpdatedAt, // get the largest known value of the updatedAt column 
            tablePullQuery, // the query specified by the user for pulling the table 
            pagePullQuery, // query for fetching a single page
            pullQueryId; // the query ID. if this is a non-null string, the pull will be performed incrementally.
        
        return {
            initialize: initialize,
            pull: pull
        };
    
        /**
         * Creates and initializes the table used to store the state for performing incremental pull
         */
        function initialize () {
            return pullTaskRunner.run(function() {
                return store.defineTable({
                    name: pulltimeTableName,
                    columnDefinitions: {
                        id: 'string', // column for storing queryId
                        tableName: 'string', // column for storing table name 
                        value: 'date' // column for storing lastKnownUpdatedAt
                    }
                });
            });
        }
        
        /**
         * Pulls changes from the server tables into the local store.
         * 
         * @param query Query specifying which records to pull
         * @param pullQueryId A unique string ID for an incremental pull query OR null for a vanilla pull query.
         * @param [settings] An object that defines the various pull settings - currently only pageSize
         * 
         * @returns A promise that is fulfilled when all records are pulled OR is rejected if the pull fails or is cancelled.  
         */
        function pull(query, queryId, settings) {
            //TODO: support pullQueryId
            //TODO: page size should be configurable
            
            return pullTaskRunner.run(function() {
                validateQuery(query, 'query');
                Validate.isString(queryId, 'queryId'); // non-null string or null - both are valid
                Validate.isObject(settings, 'settings');
    
                settings = settings || {};
                if (_.isNull(settings.pageSize)) {
                    pageSize = defaultPageSize;
                } else if (_.isInteger(settings.pageSize) && settings.pageSize > 0) {
                    pageSize = settings.pageSize;
                } else {
                    throw new Error('Page size must be a positive integer. Page size ' + settings.pageSize + ' is invalid.');
                }
    
                // Make a copy of the query as we will be modifying it
                tablePullQuery = copyQuery(query);            
    
                mobileServiceTable = client.getTable(tablePullQuery.getComponents().table);
                mobileServiceTable._features = queryId ? [constants.features.OfflineSync, constants.features.IncrementalPull] : [constants.features.OfflineSync];
                pullQueryId = queryId;
    
                // Set up the query for initiating a pull and then pull all pages          
                return setupQuery().then(function() {
                    return pullAllPages();
                });
            });
        }
    
        // Setup the query to get started with pull
        function setupQuery() {
            return getLastKnownUpdatedAt().then(function(updatedAt) {
                buildQueryFromLastKnownUpdateAt(updatedAt);
            });
        }
    
        // Pulls all pages from the server table, one page at a time.
        function pullAllPages() {
            // 1. Pull one page
            // 2. Check if Pull is complete
            // 3. If it is complete, go to 5. If not, update the query to fetch the next page.
            // 4. Go to 1
            // 5. DONE
            return pullPage().then(function(pulledRecords) {
                if (!isPullComplete(pulledRecords)) {
                    // update query and continue pulling the remaining pages
                    return updateQueryForNextPage(pulledRecords).then(function() {
                        return pullAllPages();
                    });
                }
            });
        }
        
        // Check if the pull is complete or if there are more records left to be pulled
        function isPullComplete(pulledRecords) {
             // Pull is NOT complete when the number of fetched records is less than page size as the server's page size
             // can cause the result set to be smaller than the requested page size.
             // We consider the pull to be complete only when the result contains 0 records.
            return pulledRecords.length === 0;
        }
        
        // Pull the page as described by the query
        function pullPage() {
    
            // Define appropriate parameter to enable fetching of deleted records from the server.
            // Assumption is that soft delete is enabled on the server table.
            var params = {};
            params[tableConstants.includeDeletedFlag] = true;
    
            var pulledRecords;
            
            // azure-query-js does not support datatimeoffset
            // As a temporary workaround, convert the query to an odata string and replace datetime' with datetimeoffset'. 
            var queryString = pagePullQuery.toOData();
            var tableName = pagePullQuery.getComponents().table;
            queryString = queryString.replace(new RegExp('^/' + tableName), '').replace("datetime'", "datetimeoffset'");
    
            return mobileServiceTable.read(queryString, params).then(function(result) {
                pulledRecords = result || [];
    
                var chain = Platform.async(function(callback) {
                    callback();
                })();
                
                // Process all records in the page
                for (var i = 0; i < pulledRecords.length; i++) {
                    chain = processPulledRecord(chain, tableName, pulledRecords[i]); 
                }
    
                return chain;
            }).then(function(pulled) {
                return onPagePulled();
            }).then(function() {
                return pulledRecords;
            });
        }
    
        // Processes the pulled record by taking an appropriate action, which can be one of:
        // inserting, updating, deleting in the local store or no action at all.
        function processPulledRecord(chain, tableName, pulledRecord) {
            return chain.then(function() {
    
                // Update the store as per the pulled record 
                return storeTaskRunner.run(function() {
                    if (Validate.isValidId(pulledRecord[idPropertyName])) {
                        throw new Error('Pulled record does not have a valid ID');
                    }
                    
                    return operationTableManager.readPendingOperations(tableName, pulledRecord[idPropertyName]).then(function(pendingOperations) {
                        // If there are pending operations for the record we just pulled, we ignore it.
                        if (pendingOperations.length > 0) {
                            return;
                        }
    
                        if (pulledRecord[sysProps.deletedColumnName] === true) {
                            return store.del(tableName, pulledRecord.id);
                        } else if (pulledRecord[sysProps.deletedColumnName] === false) {
                            return store.upsert(tableName, pulledRecord);
                        } else {
                            throw new Error("'" + sysProps.deletedColumnName + "' system property is missing. Pull cannot work without it.'");
                        }
                    });
                });
            });
        }
    
        // Gets the last known updatedAt timestamp.
        // For incremental pull, we check if we have any information about it in the store.
        // If not we simply use 1970 to start the sync operation, just like a non-incremental / vanilla pull.
        function getLastKnownUpdatedAt() {
            
            return Platform.async(function(callback) {
                callback();
            })().then(function() {
                
                if (pullQueryId) { // read lastKnownUpdatedAt from the store
                    return store.lookup(pulltimeTableName, pullQueryId, true /* suppressRecordNotFoundError */);
                }
    
            }).then(function(result) {
    
                if (result) {
                    return result.value;
                }
    
                return new Date (1970, 0, 0);
            });
        }
    
        // update the query to pull the next page
        function updateQueryForNextPage(pulledRecords) {
            return Platform.async(function(callback) {
                callback();
            })().then(function() {
    
                if (!pulledRecords) {
                    throw new Error('Something is wrong. pulledRecords cannot be null at this point');
                }
    
                var lastRecord = pulledRecords[ pulledRecords.length - 1];
    
                if (!lastRecord) {
                    throw new Error('Something is wrong. Possibly invalid response from the server. lastRecord cannot be null!');
                }
    
                var lastRecordTime = lastRecord[tableConstants.sysProps.updatedAtColumnName];
    
                if (!_.isDate(lastRecordTime)) {
                    throw new Error('Property ' + tableConstants.sysProps.updatedAtColumnName + ' of the last record should be a valid date');
                }
    
                if (lastRecordTime.getTime() === lastKnownUpdatedAt.getTime()) {
                    pagePullQuery.skip(pagePullQuery.getComponents().skip + pulledRecords.length);
                } else {
                    buildQueryFromLastKnownUpdateAt(lastRecordTime);
                }
            });
        }
    
        // Builds a query to fetch one page
        // Records with updatedAt values >= updatedAt will be fetched 
        function buildQueryFromLastKnownUpdateAt(updatedAt) {
    
            lastKnownUpdatedAt = updatedAt;
    
            // Make a copy of the table query and tweak it to fetch the next first page
            pagePullQuery = copyQuery(tablePullQuery);
            pagePullQuery = pagePullQuery.where(function(lastKnownUpdatedAt) {
                // Ideally we would have liked to set this[tableConstants.sysProps.updatedAtColumnName]
                // but this isn't supported
                return this.updatedAt >= lastKnownUpdatedAt;
            }, lastKnownUpdatedAt);
    
            pagePullQuery.orderBy(tableConstants.sysProps.updatedAtColumnName);
            pagePullQuery.take(pageSize);
        }
    
        // Called after a page is pulled and processed
        function onPagePulled() {
    
            // For incremental pull, make a note of the lastKnownUpdatedAt in the store
            if (pullQueryId) {
                return store.upsert(pulltimeTableName, {
                    id: pullQueryId,
                    tableName: pagePullQuery.getComponents().table,
                    value: lastKnownUpdatedAt
                });
            }
        }
    
        // Not all query operations are allowed while pulling.
        // This function validates that the query does not perform unsupported operations.
        function validateQuery(query) {
            Validate.isObject(query);
            Validate.notNull(query);
            
            var components = query.getComponents();
            
            for (var i in components.ordering) {
                throw new Error('orderBy and orderByDescending clauses are not supported in the pull query');
            }
            
            if (components.skip) {
                throw new Error('skip is not supported in the pull query');
            }
    
            if (components.take) {
                throw new Error('take is not supported in the pull query');
            }
    
            if (components.selections && components.selections.length !== 0) {
                throw new Error('select is not supported in the pull query');
            }
    
            if (components.includeTotalCount) {
                throw new Error('includeTotalCount is not supported in the pull query');
            }
        }
    
        // Makes a copy of the QueryJS object
        function copyQuery(query) {
            var components = query.getComponents();
            var queryCopy = new Query(components.table);
            queryCopy.setComponents(components);
    
            return queryCopy;
        }
    }
    
    exports.createPullManager = createPullManager;
    
    },{"../MobileServiceTable":226,"../Platform":234,"../Utilities/Extensions":241,"../Utilities/Validate":244,"../Utilities/taskRunner":245,"../constants":246,"azure-query-js":274}],254:[function(require,module,exports){
    // ----------------------------------------------------------------------------
    // Copyright (c) Microsoft Corporation. All rights reserved.
    // ----------------------------------------------------------------------------
    
    /**
     * @file Table purge logic implementation
     * @private
     */
    
    var Validate = require('../Utilities/Validate'),
        Query = require('azure-query-js').Query,
        Platform = require('../Platform'),
        taskRunner = require('../Utilities/taskRunner'),
        MobileServiceTable = require('../MobileServiceTable'),
        tableConstants = require('../constants').table,
        _ = require('../Utilities/Extensions');
        
    function createPurgeManager(store, storeTaskRunner) {
    
        return {
            purge: purge
        };
    
        /**
         * Purges data, pending operations and incremental sync state associated with a local table
         * A regular purge, would fail if there are any pending operations for the table being purged.
         * A forced purge will proceed even if pending operations for the table being purged exist in the operation table. In addition,
         * it will also delete the table's pending operations.
         * 
         * @param query Query object that specifies what records are to be purged
         * @param [forcePurge] An optional boolean, which if set to true, will perform a forced purge.
         * 
         * @returns A promise that is fulfilled when purge is complete OR is rejected if it fails.  
         */
        function purge(query, forcePurge) {
            return storeTaskRunner.run(function() {
                Validate.isObject(query, 'query');
                Validate.notNull(query, 'query');
                if (!_.isNull(forcePurge)) {
                    Validate.isBool(forcePurge, 'forcePurge');
                }
    
                // Query for pending operations associated with this table
                var operationQuery = new Query(tableConstants.operationTableName)
                    .where(function(tableName) {
                        return this.tableName === tableName; 
                    }, query.getComponents().table);
                
                // Query to search for the incremental sync state associated with this table
                var incrementalSyncStateQuery = new Query(tableConstants.pulltimeTableName)
                    .where(function(tableName) {
                        return this.tableName === tableName;
                    }, query.getComponents().table);
    
                // 1. In case of force purge, simply remove operation table entries for the table being purged
                //    Else, ensure no records exists in the operation table for the table being purged.
                // 2. Delete pull state for all incremental queries associated with this table
                // 3. Delete the records from the table as specified by 'query'
                // 
                // TODO: All store operations performed while purging should be part of a single transaction
                // Note: An incremental pull after a purge should fetch purged records again. If we run 3 before 2,
                // we might end up in a state where 3 is complete but 2 has failed. In such a case subsequent incremental pull
                // will not re-fetch purged records. Hence, it is important to run 2 before 3.
                // There still exists a possibility of pending operations being deleted while force purging and the subsequent
                // operations failing which is tracked by the above TODO. 
                return Platform.async(function(callback) {
                    callback();
                })().then(function() {
                    if (forcePurge) {
                        return store.del(operationQuery);
                    } else {
                        return store.read(operationQuery).then(function(operations) {
                            if (operations.length > 0) {
                                throw new Error('Cannot purge the table as it contains pending operations');
                            }
                        });
                    }
                }).then(function() {
                    return store.del(incrementalSyncStateQuery);
                }).then(function() {
                    return store.del(query);
                });
            });
        }
    }
    
    exports.createPurgeManager = createPurgeManager;
    
    },{"../MobileServiceTable":226,"../Platform":234,"../Utilities/Extensions":241,"../Utilities/Validate":244,"../Utilities/taskRunner":245,"../constants":246,"azure-query-js":274}],255:[function(require,module,exports){
    // ----------------------------------------------------------------------------
    // Copyright (c) Microsoft Corporation. All rights reserved.
    // ----------------------------------------------------------------------------
    
    /**
     * @file Table push logic implementation
     * @private
     */
    
    var Validate = require('../Utilities/Validate'),
        Query = require('azure-query-js').Query,
        verror = require('verror'),
        Platform = require('../Platform'),
        taskRunner = require('../Utilities/taskRunner'),
        MobileServiceTable = require('../MobileServiceTable'),
        constants = require('../constants'),
        tableConstants = constants.table,
        sysProps = require('../constants').table.sysProps,
        createPushError = require('./pushError').createPushError,
        handlePushError = require('./pushError').handlePushError,
        _ = require('../Utilities/Extensions');
    
    function createPushManager(client, store, storeTaskRunner, operationTableManager) {
        // Task runner for running push tasks. We want only one push to run at a time. 
        var pushTaskRunner = taskRunner(),
            lastProcessedOperationId,
            pushConflicts,
            lastFailedOperationId,
            retryCount,
            maxRetryCount = 5,
            pushHandler;
        
        return {
            push: push
        };
    
        /**
         * Pushes operations performed on the local store to the server tables.
         * 
         * @returns A promise that is fulfilled when all pending operations are pushed. Conflict errors won't fail the push operation.
         *          All conflicts are collected and returned to the user at the completion of the push operation. 
         *          The promise is rejected if pushing any record fails for reasons other than conflict or is cancelled.
         */
        function push(handler) {
            return pushTaskRunner.run(function() {
                reset();
                pushHandler = handler;
                return pushAllOperations().then(function() {
                    return pushConflicts;
                });
            });
        }
        
        // Resets the state for starting a new push operation
        function reset() {
            lastProcessedOperationId = -1; // Initialize to an invalid operation id
            lastFailedOperationId = -1; // Initialize to an invalid operation id
            retryCount = 0;
            pushConflicts = [];
        }
        
        // Pushes all pending operations, one at a time.
        // 1. Read the oldest pending operation
        // 2. If 1 did not fetch any operation, go to 6.
        // 3. Lock the operation obtained in step 1 and push it.
        // 4. If 3 is successful, unlock and remove the locked operation from the operation table and go to 1
        //    Else if 3 fails, unlock the operation.
        // 5. If the error is a conflict, handle the conflict and go to 1.
        // 6. Else, EXIT.
        function pushAllOperations() {
            var currentOperation,
                pushError;
            return readAndLockFirstPendingOperation().then(function(pendingOperation) {
                if (!pendingOperation) {
                    return; // No more pending operations. Push is complete
                }
                
                var currentOperation = pendingOperation;
                
                return pushOperation(currentOperation).then(function() {
                    return removeLockedOperation();
                }, function(error) {
                    // failed to push
                    return unlockPendingOperation().then(function() {
                        pushError = createPushError(store, operationTableManager, storeTaskRunner, currentOperation, error);
                        //TODO: If the conflict isn't resolved but the error is marked as handled by the user,
                        //we can end up in an infinite loop. Guard against this by capping the max number of 
                        //times handlePushError can be called for the same record.
    
                        // We want to reset the retryCount when we move on to the next record
                        if (lastFailedOperationId !== currentOperation.logRecord.id) {
                            lastFailedOperationId = currentOperation.logRecord.id;
                            retryCount = 0;
                        }
    
                        // Cap the number of times error handling logic is invoked for the same record
                        if (retryCount < maxRetryCount) {
                            ++retryCount;
                            return handlePushError(pushError, pushHandler);
                        }
                    });
                }).then(function() {
                    if (!pushError) { // no push error
                        lastProcessedOperationId = currentOperation.logRecord.id;
                    } else if (pushError && !pushError.isHandled) { // push failed and not handled
    
                        // For conflict errors, we add the error to the list of errors and continue pushing other records
                        // For other errors, we abort push.
                        if (pushError.isConflict()) {
                            lastProcessedOperationId = currentOperation.logRecord.id;
                            pushConflicts.push(pushError);
                        } else { 
                            throw new verror.VError(pushError.getError(), 'Push failed while pushing operation for tableName : ' + currentOperation.logRecord.tableName +
                                                                     ', action: ' + currentOperation.logRecord.action +
                                                                     ', and record ID: ' + currentOperation.logRecord.itemId);
                        }
                    } else { // push error handled
                        // No action needed - We want the operation to be re-pushed.
                        // No special handling is needed even if the operation was cancelled by the user as part of error handling  
                    }
                }).then(function() {
                    return pushAllOperations(); // push remaining operations
                });
            });
        }
        
        function readAndLockFirstPendingOperation() {
            return storeTaskRunner.run(function() {
                var pendingOperation;
                return operationTableManager.readFirstPendingOperationWithData(lastProcessedOperationId).then(function(operation) {
                    pendingOperation = operation;
                    
                    if (!pendingOperation) {
                        return;
                    }
                    
                    return operationTableManager.lockOperation(pendingOperation.logRecord.id);
                }).then(function() {
                    return pendingOperation;
                });
            });
        }
        
        function unlockPendingOperation() {
            return storeTaskRunner.run(function() {
                return operationTableManager.unlockOperation();
            });
        }
        
        function removeLockedOperation() {
            return storeTaskRunner.run(function() {
                return operationTableManager.removeLockedOperation();
            });
        }
        
        function pushOperation(operation) {
            
            return Platform.async(function(callback) {
                callback();
            })().then(function() {
                // TODO: Invoke push request filter to allow user to change how the record is sent to the server
            }).then(function() {
                // perform push
    
                var mobileServiceTable = client.getTable(operation.logRecord.tableName);
                mobileServiceTable._features = [constants.features.OfflineSync];
                switch(operation.logRecord.action) {
                    case 'insert':
                        removeSysProps(operation.data); // We need to remove system properties before we insert in the server table
                        return mobileServiceTable.insert(operation.data).then(function(result) {
                            return store.upsert(operation.logRecord.tableName, result); // Upsert the result of insert into the local table
                        });
                    case 'update':
                        return mobileServiceTable.update(operation.data).then(function(result) {
                            return store.upsert(operation.logRecord.tableName, result); // Upsert the result of update into the local table
                        });
                    case 'delete':
                        // Use the version info form the log record.
                        operation.logRecord.metadata = operation.logRecord.metadata || {};
                        return mobileServiceTable.del({id: operation.logRecord.itemId, version: operation.logRecord.metadata.version});
                    default:
                        throw new Error('Unsupported action ' + operation.logRecord.action);
                }
                
            }).then(function() {
                // TODO: Invoke hook to notify record push completed successfully
            });
            
        }
        
        function removeSysProps(record) {
            for (var i in sysProps) {
                delete record[sysProps[i]];
            }
        }
    }
    
    exports.createPushManager = createPushManager;
    
    },{"../MobileServiceTable":226,"../Platform":234,"../Utilities/Extensions":241,"../Utilities/Validate":244,"../Utilities/taskRunner":245,"../constants":246,"./pushError":256,"azure-query-js":274,"verror":281}],256:[function(require,module,exports){
    // ----------------------------------------------------------------------------
    // Copyright (c) Microsoft Corporation. All rights reserved.
    // ----------------------------------------------------------------------------
    
    /**
     * @file Table push error handling implementation. Defines various methods for resolving conflicts
     * @private
     */
    
    var Platform = require('../Platform'),
        _ = require('../Utilities/Extensions'),
        tableConstants = require('../constants').table;
        
    var operationTableName = tableConstants.operationTableName,
        deletedColumnName = tableConstants.sysProps.deletedColumnName;
    
    /**
     * Creates a pushError object that wraps the low level error encountered while pushing
     * and adds other useful methods for error handling.
     * @private
     */
    function createPushError(store, operationTableManager, storeTaskRunner, pushOperation, operationError) {
    
        // Calling getError will return the operationError object to the caller without cloning it.
        // (As operationError can have loops, our simplistic makeCopy(..) method won't be able to clone it)
        //
        // To guard ourselves from possible modifications to the operationError object by the caller,
        // we make a copy of its members we may need later.
        var serverRecord = makeCopy(operationError.serverInstance),
            statusCode = makeCopy(operationError.request.status);
        
        /**
         * @class PushError
         * @classdesc A conflict / error encountered while pushing a change to the server. This wraps the underlying error
         * and provides additional helper methods for handling the conflict / error. 
         * @protected
         */
        return {
            /**
             * @member {boolean} isHandled When set to true, the push logic will consider the conflict / error to be handled.
             *                             In such a case, an attempt would be made to push the change to the server again.
             *                             By default, `isHandled` is set to false.
             * @instance
             * @memberof PushError
             */
            isHandled: false,
    
            getError: getError,
            
            // Helper methods
            isConflict: isConflict,
            
            // Data query methods
            getTableName: getTableName,
            getAction: getAction,
            getServerRecord: getServerRecord,
            getClientRecord: getClientRecord,
    
            // Error handling methods
            cancelAndUpdate: cancelAndUpdate,
            cancelAndDiscard: cancelAndDiscard,
            cancel: cancel,
            update: update,
            changeAction: changeAction
        };
    
        /**
         * Gets the name of the table for which conflict / error occurred.
         * 
         * @function
         * @instance
         * @memberof PushError
         * 
         * @returns {string} The name of the table for which conflict / error occurred. 
         */
        function getTableName() {
            return makeCopy(pushOperation.logRecord.tableName);
        }
        
        /**
         * Gets the action for which conflict / error occurred.
         * 
         * @function
         * @instance
         * @memberof PushError 
         * 
         * @returns {string} The action for which conflict / error occurred. Valid action values
         *                   are _'insert'_, _'update'_ or _'delete'_.
         */
        function getAction() {
            return makeCopy(pushOperation.logRecord.action);
        }
        
        /**
         * Gets the value of the record on the server, if available, when the conflict / error occurred.
         * This is useful while handling conflicts. However, **note** that in the event of
         * a conflict / error, the server may not always respond with the server record's value.
         * Example: If the push failed even before the client value reaches the server, we won't have the server value.
         * Also, there are some scenarios where the server does not respond with the server value.
         * 
         * @function
         * @instance
         * @memberof PushError
         * 
         * @returns {object} Server record value.
         */
        function getServerRecord() {
            return makeCopy(serverRecord);
        }
        
        /**
         * Gets the value of the record that was pushed to the server when the conflict /error occurred.
         * Note that this may not be the latest value as local tables could have changed after we
         * started the push operation. 
         * 
         * @function
         * @instance
         * @memberof PushError
         * 
         * @returns {object} Client record value.
         */
        function getClientRecord() {
            return makeCopy(pushOperation.data);
        }
        
        /**
         * Gets the underlying error encountered while performing the push operation. This contains
         * grannular details of the failure like server response, error code, etc.
         * 
         * Note: Modifying value returned by this method will have a side effect of permanently
         * changing the underlying error object
         * 
         * @function
         * @instance
         * @memberof PushError
         * @returns {Error} The underlying error object.
         */
        function getError() {
            // As operationError can have loops, our simplistic makeCopy(..) method won't be able to clone it. 
            // Return without cloning.
            return operationError;
        }
        
        /**
         * Checks if the error is a conflict.
         * 
         * @function
         * @instance
         * @memberof PushError
         * 
         * @returns {boolean} true if the error is a conflict. False, otherwise.
         */
        function isConflict() {
            return statusCode === 409 || statusCode === 412;
        }
        
        /**
         * Cancels the push operation for the current record and updates the record in the local store.
         * This will also set {@link PushError#isHandled} to true.
         * 
         * @function
         * @instance
         * @memberof PushError
         * 
         * @param {object} newValue New value of the client record that will be updated in the local store.
         * 
         * @returns {Promise} A promise that is fulfilled when the operation is cancelled and the client record is updated.
         *                    The promise is rejected with the error if `cancelAndUpdate` fails.
         */
        function cancelAndUpdate(newValue) {
            var self = this;
            return storeTaskRunner.run(function() {
    
                if (pushOperation.logRecord.action === 'delete') {
                    throw new Error('Cannot update a deleted record');
                }
                
                if (_.isNull(newValue)) {
                    throw new Error('Need a valid object to update the record');
                }
                
                if (!_.isValidId(newValue.id)) {
                    throw new Error('Invalid ID: ' + newValue.id);
                }
                
                if (newValue.id !== pushOperation.data.id) {
                    throw new Error('Only updating the record being pushed is allowed');
                }
                
                // Operation to update the data record
                var dataUpdateOperation = {
                    tableName: pushOperation.logRecord.tableName,
                    action: 'upsert',
                    data: newValue
                };
                
                // Operation to delete the log record
                var logDeleteOperation = {
                    tableName: operationTableName,
                    action: 'delete',
                    id: pushOperation.logRecord.id
                };
                
                // Execute the log and data operations
                var operations = [dataUpdateOperation, logDeleteOperation];
                return store.executeBatch(operations).then(function() {
                    self.isHandled = true;
                });
            });
        }
        
        /**
         * Cancels the push operation for the current record and discards the record from the local store.
         * This will also set {@link PushError#isHandled} to true.
         * 
         * @function
         * @instance
         * @memberof PushError
         * 
         * @returns {Promise} A promise that is fulfilled when the operation is cancelled and the client record is discarded
         *                    and rejected with the error if `cancelAndDiscard` fails.
         */
        function cancelAndDiscard() {
            var self = this;
            return storeTaskRunner.run(function() {
                
                // Operation to delete the data record
                var dataDeleteOperation = {
                    tableName: pushOperation.logRecord.tableName,
                    action: 'delete',
                    id: pushOperation.logRecord.itemId
                };
                
                // Operation to delete the log record
                var logDeleteOperation = {
                    tableName: operationTableName,
                    action: 'delete',
                    id: pushOperation.logRecord.id
                };
                
                // Execute the log and data operations
                var operations = [dataDeleteOperation, logDeleteOperation];
                return store.executeBatch(operations).then(function() {
                    self.isHandled = true;
                });
            });
        }
        
        /**
         * Updates the client data record associated with the current operation.
         * If required, the metadata in the log record will also be associated.
         * This will also set {@link PushError#isHandled} to true.
         *
         * @function
         * @instance
         * @memberof PushError
         * 
         * @param {object} newValue New value of the data record. 
         * 
         * @returns {Promise} A promise that is fulfilled when the data record is updated in the localstore.
         */
        function update(newValue) {
            var self = this;
            return storeTaskRunner.run(function() {
                if (pushOperation.logRecord.action === 'delete') {
                    throw new Error('Cannot update a deleted record');
                }
                
                if (_.isNull(newValue)) {
                    throw new Error('Need a valid object to update the record');
                }
                
                if (!_.isValidId(newValue.id)) {
                    throw new Error('Invalid ID: ' + newValue.id);
                }
                
                if (newValue.id !== pushOperation.data.id) {
                    throw new Error('Only updating the record being pushed is allowed');
                }
    
                //TODO: Do we need to disallow updating record if the record has been deleted after
                //we attempted push?
    
                return operationTableManager.getMetadata(pushOperation.logRecord.tableName, 'upsert', newValue).then(function(metadata) {
                    pushOperation.logRecord.metadata = metadata;
                    return store.executeBatch([
                        { // Update the log record
                            tableName: operationTableName,
                            action: 'upsert',
                            data: pushOperation.logRecord
                        },
                        { // Update the record in the local table
                            tableName: pushOperation.logRecord.tableName,
                            action: 'upsert',
                            data: newValue
                        }
                    ]).then(function() {
                        self.isHandled = this;
                    });
                });
    
            });
        }
        
        /**
         * Changes the type of operation that will be pushed to the server.
         * This is useful for handling conflicts where you might need to change the type of the 
         * operation to be able to push the changes to the server.
         * This will also set {@link PushError#isHandled} to true.
         *
         * Example: You might need to change _'insert'_ to _'update'_ to be able to push a record that 
         * was already inserted on the server.
         * 
         * Note: Changing the action to _'delete'_' will automatically remove the associated record from the 
         * data table in the local store.
         * 
         * @function
         * @instance
         * @memberof PushError
         * 
         * @param {string} newAction New type of the operation. Valid values are _'insert'_, _'update'_ and _'delete'_.
         * @param {object} [newClientRecord] New value of the client record. 
         *                          The `id` property of the new record should match the `id` property of the original record.
         *                          If `newAction` is _'delete'_, only the `id` and `version` properties will be read from `newClientRecord`.
         *                          Reading the `version` property while deleting is useful if
         *                          the conflict handler changes an _'insert'_  /_'update'_ action to _'delete'_' and also updated the version
         *                          to reflect the server version.
         * 
         * @returns {Promise} A promise that is fulfilled when the action is changed and, optionally, the data record is updated / deleted.
         *                    If this fails, the promsie is rejected with the error.
         */
        function changeAction(newAction, newClientRecord) {
            var self = this;
            return storeTaskRunner.run(function() {
                var dataOperation, // operation to edit the data record
                    logOperation = { // operation to edit the log record 
                        tableName: operationTableName,
                        action: 'upsert',
                        data: makeCopy(pushOperation.logRecord)
                    };
    
                // If a new value for the record is specified, use the version property to update the metadata
                // If not, there is nothing that needs to be changed in the metadata. Just use the metadata we already have.
                if (newClientRecord) {
                    if (!newClientRecord.id) {
                        throw new Error('New client record value must specify the record ID');
                    }
                        
                    if (newClientRecord.id !== pushOperation.logRecord.itemId) {
                        throw new Error('New client record value cannot change the record ID. Original ID: ' +
                                        pushOperation.logRecord.id + ' New ID: ' + newClientRecord.id);
                    }
    
                    // FYI: logOperation.data and pushOperation.data are not the same thing!
                    logOperation.data.metadata = logOperation.data.metadata || {};
                    logOperation.data.metadata[tableConstants.sysProps.versionColumnName] = newClientRecord[tableConstants.sysProps.versionColumnName];
                }
    
                if (newAction === 'insert' || newAction === 'update') {
                    
                    // Change the action as specified
                    var oldAction = logOperation.data.action;
                    logOperation.data.action = newAction;
    
                    // Update the client record, if a new value is specified
                    if (newClientRecord) {
                        
                        dataOperation = {
                            tableName: pushOperation.logRecord.tableName,
                            action: 'upsert',
                            data: newClientRecord
                        };
                        
                    } else if (oldAction !== 'insert' && oldAction !== 'update') {
    
                        // If we are here, it means we are changing the action from delete to insert / update. 
                        // In such a case we expect newClientRecord to be non-null as we won't otherwise know what to insert / update.
                        // Example: changing delete to insert without specifying a newClientRecord is meaningless.
                        throw new Error('Changing action from ' + oldAction + ' to ' + newAction +
                                        ' without specifying a value for the associated record is not allowed!');
                    }
                    
                } else if (newAction === 'delete' || newAction === 'del') {
    
                    // Change the action to 'delete'
                    logOperation.data.action = 'delete';
    
                    // Delete the client record as the new action is 'delete'
                    dataOperation = {
                        tableName: pushOperation.logRecord.tableName,
                        action: 'delete',
                        id: pushOperation.logRecord.id
                    };
    
                } else {
                    throw new Error('Action ' + newAction + ' not supported.');
                }
                
                // Execute the log and data operations
                return store.executeBatch([logOperation, dataOperation]).then(function() {
                    self.isHandled = true;
                });
            });
        }
        
        /**
         * Cancels pushing the current operation to the server permanently.
         * This will also set {@link PushError#isHandled} to true.
         * 
         * This method simply removes the pending operation from the operation table, thereby 
         * permanently skipping the associated change from being pushed to the server. A future change 
         * done to the same record will not be affected and such changes will continue to be pushed.
         *  
         * @function
         * @instance
         * @memberof PushError
         *
         * @returns {Promise} A promise that is fulfilled when the operation is cancelled OR rejected
         *                    with the error if it fails to cancel it.
         */
        function cancel() {
            var self = this;
            return storeTaskRunner.run(function() {
                return store.del(operationTableName, pushOperation.logRecord.id).then(function() {
                    self.isHandled = true;
                });
            });
        }
    }
    
    function makeCopy(value) {
        if (!_.isNull(value)) {
            value = JSON.parse( JSON.stringify(value) );
        }
        return value;
    }
    
    /**
     * Attempts error handling by delegating it to the user, if a push handler is provided
     * @private
     */
    function handlePushError(pushError, pushHandler) {
        return Platform.async(function(callback) {
            callback();
        })().then(function() {
            
            if (pushError.isConflict()) {
                if (pushHandler && pushHandler.onConflict) {
                    // NOTE: value of server record will not be available in case of 409.
                    return pushHandler.onConflict(pushError);
                }
            } else if (pushHandler && pushHandler.onError) {
                return pushHandler.onError(pushError);
            }
    
        }).then(undefined, function(error) {
            // Set isHandled to false even if the user has set it to handled if the onConflict / onError failed 
            pushError.isHandled = false;
        });
    }
    
    exports.createPushError = createPushError;
    exports.handlePushError = handlePushError;
    
    },{"../Platform":234,"../Utilities/Extensions":241,"../constants":246}],257:[function(require,module,exports){
    // ----------------------------------------------------------------------------
    // Copyright (c) Microsoft Corporation. All rights reserved.
    // ----------------------------------------------------------------------------
    
    var Query = require('azure-query-js').Query,
        Platform = require('./Platform');
    
    // Copy select Query operators to the table so queries can be created
    // compactly.  We'll just add them to the table prototype and then
    // forward on directly to a new Query instance.
    var queryOperators = ['where', 'select', 'orderBy', 'orderByDescending', 'skip', 'take', 'includeTotalCount'];
    
    var copyOperator = function (table, operator) {
        table.prototype[operator] = function () {
            /// <summary>
            /// Creates a new query.
            /// </summary>
    
            // Create a query associated with this table
            var table = this;
            var query = new Query(table.getTableName());
    
            // Add a .read() method on the query which will execute the query.
            // This method is defined here per query instance because it's
            // implicitly tied to the table.
            query.read = function (parameters) {
                return table.read(query, parameters);
            };
    
            // Invoke the query operator on the newly created query
            return query[operator].apply(query, arguments);
        };
    };
    
    function defineQueryOperators(table) {
        var i = 0;
        for (; i < queryOperators.length; i++) {
            copyOperator(table, queryOperators[i]);
        }
    }
    
    exports.defineQueryOperators = defineQueryOperators;
    
    },{"./Platform":234,"azure-query-js":274}],258:[function(require,module,exports){
    // ----------------------------------------------------------------------------
    // Copyright (c) Microsoft Corporation. All rights reserved.
    // ----------------------------------------------------------------------------
    
    var types = require('./utilities/types'),
        expressions = require('./expressions');
    
    module.exports = types.defineClass(null, {
        visit: function (expr) {
            return expr.accept(this);
        },
    
        visitConstant: function (expr) {
            return expr;
        },
    
        visitFloatConstant: function (expr) {
            return expr;
        },
    
        visitBinary: function (expr) {
            var left = null;
            var right = null;
    
            if (expr.left !== null) {
                left = this.visit(expr.left);
            }
            if (expr.right !== null) {
                right = this.visit(expr.right);
            }
            if (left != expr.left || right != expr.right) {
                return new expressions.Binary(left, right, expr.expressionType);
            }
    
            return expr;
        },
    
        visitUnary: function (expr) {
            var operand = this.visit(expr.operand);
            if (operand != expr.operand) {
                return new expressions.Unary(operand, expr.expressionType);
            }
            return expr;
        },
    
        visitMember: function (expr) {
            return expr;
        },
    
        visitParameter: function (expr) {
            return expr;
        },
    
        visitFunction: function (expr) {
            var updated = false;
    
            var instance = expr.instance;
            if (expr.instance) {
                instance = this.visit(expr.instance);
                if (instance != expr.instance) {
                    updated = true;
                }
            }
    
            var args = [expr.args.length],
                i = 0,
                self = this;
            expr.args.forEach(function (arg) {
                var newArg = self.visit(arg);
                args[i++] = arg;
                if (newArg != arg) {
                    updated = true;
                }
            });
    
            if (updated) {
                return new expressions.FunctionCall(instance, expr.memberInfo, args);
            }
            return expr;
        }
    });
    
    },{"./expressions":261,"./utilities/types":267}],259:[function(require,module,exports){
    // ----------------------------------------------------------------------------
    // Copyright (c) Microsoft Corporation. All rights reserved.
    // ----------------------------------------------------------------------------
    
    var types = require('./utilities/types'),
        ExpressionVisitor = require('./ExpressionVisitor'),
        expressions = require('./expressions');
    
    var SqlBooleanizer = types.deriveClass(ExpressionVisitor, null, {
        visitUnary: function (expr) {
            var operand = this.visit(expr.operand);
    
            if (operand && expr.expressionType == 'Not') {
                // Convert expression 'x' to a boolean expression '(x = true)' since
                // the SQL Not operator requires a boolean expression (not a BIT)
                return new expressions.Unary(ensureExpressionIsBoolean(operand), 'Not');
            }
    
            if (operand != expr.operand) {
                return new expressions.Unary(operand, expr.expressionType);
            }
    
            return expr;
        },
    
        visitBinary: function (expr) {
            var left = null;
            var right = null;
    
            // first visit the expressions to do any sub conversions, before
            // doing any transformations below
            if (expr.left !== null) {
                left = this.visit(expr.left);
            }
            if (expr.right !== null) {
                right = this.visit(expr.right);
            }
    
            if ((expr.expressionType == 'And') || (expr.expressionType == 'Or')) {
                // both operands must be boolean expressions
                left = ensureExpressionIsBoolean(left);
                right = ensureExpressionIsBoolean(right);
            }
            else if ((expr.expressionType == 'Equal') || (expr.expressionType == 'NotEqual')) {
                // remove any comparisons between boolean and bit
                var converted = rewriteBitComparison(left, right);
                if (converted) {
                    return converted;
                }
            }
    
            if (left != expr.left || right != expr.right) {
                return new expressions.Binary(left, right, expr.expressionType);
            }
    
            return expr;
        }
    });
    
    // if a boolean expression is being compared to a bit expression, convert
    // by removing the comparison. E.g. (endswith('value', title) eq false) => not(endswith('value', title))
    function rewriteBitComparison(left, right) {
        if (isBooleanExpression(left) && isBitConstant(right)) {
            return (right.value === true) ? left : new expressions.Unary(left, 'Not');
        }
        else if (isBooleanExpression(right) && isBitConstant(left)) {
            return (left.value === true) ? right : new expressions.Unary(right, 'Not');
        }
    
        // no conversion necessary
        return null;
    }
    
    // returns true if the expression is the constant 'true' or 'false'
    function isBitConstant(expr) {
        return (expr.expressionType == 'Constant') && (expr.value === true || expr.value === false);
    }
    
    // if the expression isn't boolean, convert to a boolean expression (e.g. (isDiscontinued) => (isDiscontinued = 1))
    function ensureExpressionIsBoolean(expr) {
        if (!isBooleanExpression(expr)) {
            return new expressions.Binary(expr, new expressions.Constant(true), 'Equal');
        }
        return expr;
    }
    
    function isBooleanExpression(expr) {
        if (!expr) {
            return false;
        }
    
        // see if this is a logical boolean expression
        switch (expr.expressionType) {
            case 'And':
            case 'Or':
            case 'GreaterThan':
            case 'GreaterThanOrEqual':
            case 'LessThan':
            case 'LessThanOrEqual':
            case 'Not':
            case 'Equal':
            case 'NotEqual':
                return true;
            default:
                break;
        }
    
        // boolean odata functions
        if (expr.expressionType == 'Call') {
            switch (expr.memberInfo.memberName) {
                case 'startswith':
                case 'endswith':
                case 'substringof':
                    return true;
                default:
                    break;
            }
        }
    
        return false;
    }
    
    module.exports = function (expr) {
        var booleanizer = new SqlBooleanizer();
    
        expr = booleanizer.visit(expr);
        expr = ensureExpressionIsBoolean(expr);
    
        return expr;
    };
    
    },{"./ExpressionVisitor":258,"./expressions":261,"./utilities/types":267}],260:[function(require,module,exports){
    (function (Buffer){(function (){
    // ----------------------------------------------------------------------------
    // Copyright (c) Microsoft Corporation. All rights reserved.
    // ----------------------------------------------------------------------------
    
    var types = require('./utilities/types'),
        expressions = require('./expressions'),
        ExpressionVisitor = require('./ExpressionVisitor');
    
    function ctor(tableMetadata) {
        this.tableMetadata = tableMetadata;
    }
    
    var TypeConverter = types.deriveClass(ExpressionVisitor, ctor, {
        visitBinary: function (expr) {
            var left = expr.left ? this.visit(expr.left) : null;
            var right = expr.right ? this.visit(expr.right) : null;
    
            if (this._isStringConstant(left) && this._isBinaryMemberAccess(right)) {
                left.value = new Buffer(left.value, 'base64');
            }
            else if (this._isStringConstant(right) && this._isBinaryMemberAccess(left)) {
                right.value = new Buffer(right.value, 'base64');
            }
    
            if (left != expr.left || right != expr.right) {
                return new expressions.Binary(left, right, expr.expressionType);
            }
    
            return expr;
        },
    
        _isStringConstant: function(expr) {
            return expr &&
                   expr.expressionType === 'Constant' &&
                   types.isString(expr.value);
        },
    
        _isBinaryMemberAccess: function (expr) {
            return expr &&
                   expr.expressionType === 'MemberAccess' &&
                   types.isString(expr.member) && // tableConfig.binaryColumns is not currently used - hard coded __version column
                   ((this.tableMetadata.binaryColumns && this.tableMetadata.binaryColumns.indexOf(expr.member.toLowerCase()) > -1) || expr.member.toLowerCase() === 'version');
        }
    });
    
    module.exports = function (expr, tableMetadata) {
        return new TypeConverter(tableMetadata).visit(expr);
    };
    
    }).call(this)}).call(this,require("buffer").Buffer)
    },{"./ExpressionVisitor":258,"./expressions":261,"./utilities/types":267,"buffer":68}],261:[function(require,module,exports){
    // ----------------------------------------------------------------------------
    // Copyright (c) Microsoft Corporation. All rights reserved.
    // ----------------------------------------------------------------------------
    
    var types = require('./utilities/types');
    
    var Expression = types.defineClass(
        null, {
            accept: function (visitor) {
                return visitor.visit(this);
            }
        },
        null);
    
    module.exports = {
        MappedMemberInfo: types.defineClass(
            function (type, memberName, isStatic, isMethod) {
                this.type = type;
                this.memberName = memberName;
                this.isStatic = isStatic;
                this.isMethod = isMethod;
            }, null, null),
    
        Constant: types.deriveClass(
            Expression,
            function (value) {
                this.value = value;
                this.expressionType = 'Constant';
            }, {
                accept: function (visitor) {
                    return visitor.visitConstant(this);
                }
            },
            null),
    
        FloatConstant: types.deriveClass(
            Expression,
            function (value) {
                this.value = value;
                this.expressionType = 'FloatConstant';
            }, {
                accept: function (visitor) {
                    return visitor.visitFloatConstant(this);
                }
            },
            null),
    
        Binary: types.deriveClass(
            Expression,
            function (left, right, expressionType) {
                this.left = left;
                this.right = right;
                this.expressionType = expressionType;
            }, {
                accept: function (visitor) {
                    return visitor.visitBinary(this);
                }
            },
            null),
    
        Unary: types.deriveClass(
            Expression,
            function (operand, expressionType) {
                this.operand = operand;
                this.expressionType = expressionType;
            }, {
                accept: function (visitor) {
                    return visitor.visitUnary(this);
                }
            },
            null),
    
        Member: types.deriveClass(
            Expression,
            // member may be either a member name or a MappedMemberInfo
            function (instance, member) {
                this.instance = instance;
                this.member = member;
                this.expressionType = 'MemberAccess';
            }, {
                accept: function (visitor) {
                    return visitor.visitMember(this);
                }
            },
            null),
    
        FunctionCall: types.deriveClass(
            Expression,
            function (instance, memberInfo, args) {
                this.instance = instance;
                this.memberInfo = memberInfo;
                this.args = args;
                this.expressionType = 'Call';
            }, {
                accept: function (visitor) {
                    return visitor.visitFunction(this);
                }
            },
            null),
    
        Parameter: types.defineClass(
            function () {
                this.ExpressionType = 'Parameter';
            }, {
                accept: function (visitor) {
                    return visitor.visitParameter(this);
                }
            },
            null),
    
        Convert: types.deriveClass(
            Expression,
            function (desiredType, operand) {
                this.desiredType = desiredType;
                this.operand = operand;
                this.expressionType = 'Convert';
            }, {
                accept: function (visitor) {
                    return visitor.visitUnary(this);
                }
            },
            null)
    };
    
    },{"./utilities/types":267}],262:[function(require,module,exports){
    // ----------------------------------------------------------------------------
    // Copyright (c) Microsoft Corporation. All rights reserved.
    // ----------------------------------------------------------------------------
    
    var types = require('./utilities/types'),
        util = require('util'),
        parseOData = require('./parseOData'),
        ExpressionVisitor = require('./ExpressionVisitor'),
        convertTypes = require('./convertTypes'),
        booleanize = require('./booleanize'),
        helpers = require('./helpers'),
        expressions = require('./expressions');
    
    function ctor(tableConfig) {
        this.tableConfig = tableConfig || {};
        this.flavor = this.tableConfig.flavor || 'mssql';
        this.statement = { sql: '', parameters: [], multiple: true };
        this.paramNumber = 0;
        this.parameterPrefix = 'p';
    
        if (this.flavor !== 'sqlite') {
            this.schemaName = this.tableConfig.schema || 'dbo';
        }
    }
    
    var SqlFormatter = types.deriveClass(ExpressionVisitor, ctor, {
        format: function (query) {
            // if a skip is requested but no top is defined, we need
            // to still generate the paging query, so default top to
            // max. Really when doing paging, the user should also be
            // specifying a top explicitly however.
            if (query.skip > 0 && (query.take === undefined || query.take === null)) {
                if (this.flavor !== 'sqlite') {
                    query.take = 9007199254740992; // Number.MAX_SAFE_INTEGER + 1; // ES6
                } else {
                    // A negative LIMIT in sqlite returns all rows.
                    query.take = -1;
                }
            }
    
            var statements = [];
    
            this.statement.sql = this._formatQuery(query).trim();
            statements.push(this.statement);
    
            if (query.inlineCount === 'allpages' || query.includeTotalCount) {
                this.statement = { sql: '', parameters: [], multiple: true };
                this.statement.sql = this._formatCountQuery(helpers.formatTableName(this.schemaName, query.table), query).trim();
                statements.push(this.statement);
            }
    
            return statements;
        },
    
        _formatQuery: function (query) {
    
            if (this.flavor !== 'sqlite' && query.skip >= 0 && query.take >= 0 && query.skip !== null && query.take !== null) {
                return this._formatPagedQuery(query);
            }
    
            var takeClause = '',
                skipClause = '',
                whereClause = '',
                orderbyClause = '',
                limit = -1,
                formattedSql,
                selection = query.selections ? this._formatSelection(query.selections) : '*';
    
            // set the top clause to be the minimumn of the top
            // and result limit values if either has been set.
            var resultLimit = query.resultLimit || Number.MAX_VALUE;
            if (query.take >= 0 && query.take !== null) {
                limit = Math.min(resultLimit, query.take);
            } else if (resultLimit != Number.MAX_VALUE) {
                limit = query.resultLimit;
            }
    
            if (this.flavor !== 'sqlite') {
                if (limit != -1) {
                    takeClause = 'TOP ' + limit.toString() + ' ';
                }
            } else {
                if (query.skip > 0) {
                    skipClause = ' OFFSET ' + query.skip.toString();
                }
    
                // Specifiy a take clause if either skip or limit is specified.
                // Note: SQLite needs LIMIT for OFFSET to work.
                if (query.skip > 0 || limit >= 0) {
                    takeClause = ' LIMIT ' + limit.toString();
                }
            }
    
            var filter = this._formatFilter(query);
            if (filter.length > 0) {
                whereClause = ' WHERE ' + filter;
            }
    
            var ordering = this._formatOrderBy(query);
            if (ordering.length > 0) {
                orderbyClause = ' ORDER BY ' + ordering;
            }
    
            var tableName = helpers.formatTableName(this.schemaName, query.table);
    
            if (this.flavor !== 'sqlite') {
                formattedSql = util.format("SELECT %s%s FROM %s%s%s", takeClause, selection, tableName, whereClause, orderbyClause);
            } else {
                formattedSql = util.format("SELECT %s FROM %s%s%s%s%s", selection, tableName, whereClause, orderbyClause, takeClause, skipClause);
            }
    
            return formattedSql;
        },
    
        _formatPagedQuery: function (query) {
            var formattedSql, selection = '';
    
            if (query.selections) {
                selection = this._formatSelection(query.selections);
            } else {
                selection = "*";
            }
    
            var filter = this._formatFilter(query, '(1 = 1)');
            var ordering = this._formatOrderBy(query, '[id]');
    
            // Plug all the pieces into the template to get the paging sql
            var tableName = helpers.formatTableName(this.schemaName, query.table);
            formattedSql = util.format(
                "SELECT %s " +
                "FROM %s " +
                "WHERE %s " +
                "ORDER BY %s " +
                "OFFSET %d ROWS FETCH NEXT %d ROWS ONLY",
                selection, tableName, filter, ordering, query.skip,  query.take);
    
            return formattedSql;
        },
    
        _formatCountQuery: function (table, query) {
            var filter;
    
            if (query.filters || query.id !== undefined || this.tableConfig.supportsSoftDelete) {
                this.statement.sql = '';
                filter = this._formatFilter(query);
            }
    
            var sql = 'SELECT COUNT(*) AS [count] FROM ' + table;
            if (filter) {
                sql += ' WHERE ' + filter;
            }
            return sql;
        },
    
        _formatOrderBy: function (query, defaultOrder) {
            if (!query.ordering) {
                return defaultOrder || '';
            }
    
            var orderings = parseOData.orderBy(query.ordering),
                order = '',
                self = this;
    
            orderings.forEach(function (ordering) {
                if (order.length > 0) {
                    order += ', ';
                }
                self.statement.sql = '';
                self.visit(ordering.selector);
                if (!ordering.ascending) {
                    self.statement.sql += ' DESC';
                }
                order += self.statement.sql;
            });
    
            return order;
        },
    
        _formatSelection: function (selection, prefix) {
            var formattedSelection = '',
                columns = selection.split(',');
    
            columns.forEach(function (column) {
                var member = column.trim();
                if (formattedSelection.length > 0) {
                    formattedSelection += ', ';
                }
                formattedSelection += (prefix || '') + helpers.formatMember(member);
            });
    
            return formattedSelection;
        },
    
        _formatFilter: function (query, defaultFilter) {
            // if we already have a parsed filter use it,
            // otherwise parse the filter
            var filterExpr;
            if (query.filters && query.filters.length > 0) {
                filterExpr = parseOData(query.filters);
            }
    
            if (query.id !== undefined) {
                var id = this.tableConfig.hasStringId ? "'" + query.id.replace(/'/g, "''") + "'" : query.id;
                var idFilterExpr = parseOData(util.format('(id eq %s)', id));
    
                // append the id filter to any existing filter
                if (filterExpr) {
                    filterExpr = new expressions.Binary(filterExpr, idFilterExpr, 'And');
                }
                else {
                    filterExpr = idFilterExpr;
                }
            }
    
            // if soft delete is enabled filter out deleted records
            if (this.tableConfig.softDelete && !query.includeDeleted) {
                var deletedFilter = parseOData(util.format('(deleted eq false)'));
                if (filterExpr) {
                    filterExpr = new expressions.Binary(filterExpr, deletedFilter, 'And');
                }
                else {
                    filterExpr = deletedFilter;
                }
            }
    
            if (!filterExpr) {
                return defaultFilter || '';
            }
    
            this.statement.sql = '';
            filterExpr = this._finalizeExpression(filterExpr);
            this.visit(filterExpr);
    
            return this.statement.sql;
        },
    
        // run the final query translation pipeline on the specified
        // expression, modifying the expression tree as needed
        _finalizeExpression: function (expr) {
            expr = booleanize(expr);
            expr = convertTypes(expr, this.tableConfig);
            return expr;
        },
    
        visitBinary: function (expr) {
            this.statement.sql += '(';
    
            var left = null;
            var right = null;
    
            // modulo requires the dividend to be an integer, monetary or numeric
            // rewrite the expression to convert to numeric, allowing the DB to apply
            // rounding if needed. our default data type for number is float which
            // is incompatible with modulo.
            if (expr.expressionType == 'Modulo') {
                expr.left = new expressions.Convert('numeric', expr.left);
            }
    
            if (expr.left) {
                left = this.visit(expr.left);
            }
    
            if (expr.right && (expr.right.value === null)) {
                // inequality expressions against a null literal have a special
                // translation in SQL
                if (expr.expressionType == 'Equal') {
                    this.statement.sql += ' IS NULL';
                }
                else if (expr.expressionType == 'NotEqual') {
                    this.statement.sql += ' IS NOT NULL';
                }
            }
            else {
                switch (expr.expressionType) {
                    case 'Equal':
                        this.statement.sql += ' = ';
                        break;
                    case 'NotEqual':
                        this.statement.sql += ' != ';
                        break;
                    case 'LessThan':
                        this.statement.sql += ' < ';
                        break;
                    case 'LessThanOrEqual':
                        this.statement.sql += ' <= ';
                        break;
                    case 'GreaterThan':
                        this.statement.sql += ' > ';
                        break;
                    case 'GreaterThanOrEqual':
                        this.statement.sql += ' >= ';
                        break;
                    case 'And':
                        this.statement.sql += ' AND ';
                        break;
                    case 'Or':
                        this.statement.sql += ' OR ';
                        break;
                    case 'Concat':
                        if (this.flavor === 'sqlite') {
                            this.statement.sql += ' || ';
                        } else {
                            this.statement.sql += ' + ';
                        }
                        break;
                    case 'Add':
                        this.statement.sql += ' + ';
                        break;
                    case 'Subtract':
                        this.statement.sql += ' - ';
                        break;
                    case 'Multiply':
                        this.statement.sql += ' * ';
                        break;
                    case 'Divide':
                        this.statement.sql += ' / ';
                        break;
                    case 'Modulo':
                        this.statement.sql += ' % ';
                        break;
                }
    
                if (expr.right) {
                    right = this.visit(expr.right);
                }
            }
    
            this.statement.sql += ')';
    
            if ((left !== expr.left) || (right !== expr.right)) {
                return new expressions.Binary(left, right);
            }
    
            return expr;
        },
    
        visitConstant: function (expr) {
            if (expr.value === null) {
                this.statement.sql += 'NULL';
                return expr;
            }
    
            this.statement.sql += this._createParameter(expr.value);
    
            return expr;
        },
    
        visitFloatConstant: function (expr) {
            if (expr.value === null) {
                this.statement.sql += 'NULL';
                return expr;
            }
    
            this.statement.sql += this._createParameter(expr.value, 'float');
    
            return expr;
        },
    
        _createParameter: function (value, type) {
            var parameter = {
                name: this.parameterPrefix + (++this.paramNumber).toString(),
                pos: this.paramNumber,
                value: value,
                type: type
            };
    
            this.statement.parameters.push(parameter);
    
            return '@' + this.parameterPrefix + this.paramNumber.toString();
        },
    
        visitMember: function (expr) {
            if (typeof expr.member === 'string') {
                this.statement.sql += helpers.formatMember(expr.member);
            }
            else {
                this._formatMappedMember(expr);
            }
    
            return expr;
        },
    
        visitUnary: function (expr) {
            if (expr.expressionType == 'Not') {
                this.statement.sql += 'NOT ';
                this.visit(expr.operand);
            }
            else if (expr.expressionType == 'Convert') {
                this.statement.sql += util.format("CONVERT(%s, ", expr.desiredType);
                this.visit(expr.operand);
                this.statement.sql += ')';
            }
    
            return expr;
        },
    
        visitFunction: function (expr) {
            if (expr.memberInfo) {
                this._formatMappedFunction(expr);
            }
            return expr;
        },
    
        _formatMappedFunction: function (expr) {
            if (expr.memberInfo.type == 'string') {
                this._formatMappedStringMember(expr.instance, expr.memberInfo, expr.args);
            }
            else if (expr.memberInfo.type == 'date') {
                this._formatMappedDateMember(expr.instance, expr.memberInfo, expr.args);
            }
            else if (expr.memberInfo.type == 'math') {
                this._formatMappedMathMember(expr.instance, expr.memberInfo, expr.args);
            }
        },
    
        _formatMappedMember: function (expr) {
            if (expr.member.type == 'string') {
                this._formatMappedStringMember(expr.instance, expr.member, null);
            }
        },
    
        _formatMappedDateMember: function (instance, mappedMemberInfo, args) {
            var functionName = mappedMemberInfo.memberName;
    
            if (functionName == 'day') {
                this.statement.sql += 'DAY(';
                this.visit(instance);
                this.statement.sql += ')';
            }
            else if (mappedMemberInfo.memberName == 'month') {
                this.statement.sql += 'MONTH(';
                this.visit(instance);
                this.statement.sql += ')';
            }
            else if (mappedMemberInfo.memberName == 'year') {
                this.statement.sql += 'YEAR(';
                this.visit(instance);
                this.statement.sql += ')';
            }
            else if (mappedMemberInfo.memberName == 'hour') {
                this.statement.sql += 'DATEPART(HOUR, ';
                this.visit(instance);
                this.statement.sql += ')';
            }
            else if (mappedMemberInfo.memberName == 'minute') {
                this.statement.sql += 'DATEPART(MINUTE, ';
                this.visit(instance);
                this.statement.sql += ')';
            }
            else if (mappedMemberInfo.memberName == 'second') {
                this.statement.sql += 'DATEPART(SECOND, ';
                this.visit(instance);
                this.statement.sql += ')';
            }
        },
    
        _formatMappedMathMember: function (instance, mappedMemberInfo, args) {
            var functionName = mappedMemberInfo.memberName;
    
            if (functionName == 'floor') {
                this.statement.sql += 'FLOOR(';
                this.visit(instance);
                this.statement.sql += ')';
            }
            else if (functionName == 'ceiling') {
                this.statement.sql += 'CEILING(';
                this.visit(instance);
                this.statement.sql += ')';
            }
            else if (functionName == 'round') {
                // Use the 'away from zero' midpoint rounding strategy - when
                // a number is halfway between two others, it is rounded toward
                // the nearest number that is away from zero.
                this.statement.sql += 'ROUND(';
                this.visit(instance);
                this.statement.sql += ', 0)';
            }
        },
    
        _formatMappedStringMember: function (instance, mappedMemberInfo, args) {
            var functionName = mappedMemberInfo.memberName;
    
            if (functionName == 'substringof') {
                this.statement.sql += '(';
                this.visit(instance);
    
                this.statement.sql += ' LIKE ';
    
                // form '%' + <arg> + '%'
                this.statement.sql += "('%' + ";
                this.visit(args[0]);
                this.statement.sql += " + '%')";
    
                this.statement.sql += ')';
            }
            else if (functionName == 'startswith') {
                this.statement.sql += '(';
                this.visit(instance);
    
                this.statement.sql += ' LIKE ';
    
                // form '<arg> + '%'
                this.statement.sql += '(';
                this.visit(args[0]);
                this.statement.sql += " + '%')";
    
                this.statement.sql += ')';
            }
            else if (functionName == 'endswith') {
                this.statement.sql += '(';
                this.visit(instance);
    
                this.statement.sql += ' LIKE ';
    
                // form '%' + '<arg>
                this.statement.sql += "('%' + ";
                this.visit(args[0]);
                this.statement.sql += ')';
    
                this.statement.sql += ')';
            }
            else if (functionName == 'concat') {
                if (this.flavor !== 'sqlite') {
                    // Rewrite as an string addition with appropriate conversions.
                    // Note: due to sql operator precidence, we only need to inject a
                    // single conversion - the other will be upcast to string.
                    if (!isConstantOfType(args[0], 'string')) {
                        args[0] = new expressions.Convert(helpers.getSqlType(''), args[0]);
                    } else if (!isConstantOfType(args[1], 'string')) {
                        args[1] = new expressions.Convert(helpers.getSqlType(''), args[1]);
                    }
                }
                var concat = new expressions.Binary(args[0], args[1], 'Concat');
                this.visit(concat);
            }
            else if (functionName == 'tolower') {
                this.statement.sql += 'LOWER(';
                this.visit(instance);
                this.statement.sql += ')';
            }
            else if (functionName == 'toupper') {
                this.statement.sql += 'UPPER(';
                this.visit(instance);
                this.statement.sql += ')';
            }
            else if (functionName == 'length') {
                // special translation since SQL LEN function doesn't
                // preserve trailing spaces
                this.statement.sql += '(LEN(';
                this.visit(instance);
                this.statement.sql += " + 'X') - 1)";
            }
            else if (functionName == 'trim') {
                this.statement.sql += 'LTRIM(RTRIM(';
                this.visit(instance);
                this.statement.sql += '))';
            }
            else if (functionName == 'indexof') {
                if (this.flavor === 'sqlite') {
                    this.statement.sql += "(INSTR(";
                    this.visit(args[0]);
                    this.statement.sql += ", ";
                    this.visit(instance);
                    this.statement.sql += ') - 1)';
                } else {
                    this.statement.sql += "(PATINDEX('%' + ";
                    this.visit(args[0]);
                    this.statement.sql += " + '%', ";
                    this.visit(instance);
                    this.statement.sql += ') - 1)';
                }
            }
            else if (functionName == 'replace') {
                this.statement.sql += "REPLACE(";
                this.visit(instance);
                this.statement.sql += ", ";
                this.visit(args[0]);
                this.statement.sql += ", ";
                this.visit(args[1]);
                this.statement.sql += ')';
            }
            else if (functionName == 'substring') {
                if (this.flavor === 'sqlite') {
                    this.statement.sql += 'SUBSTR(';
                } else {
                    this.statement.sql += 'SUBSTRING(';
                }
                this.visit(instance);
    
                this.statement.sql += ", ";
                this.visit(args[0]);
                this.statement.sql += " + 1, ";  // need to add 1 since SQL is 1 based, but OData is zero based
    
                if (args.length == 1) {
                    // Overload not taking an explicit length. The
                    // LEN of the entire expression is used in this case
                    // which means everything after the start index will
                    // be taken.
                    this.statement.sql += 'LEN(';
                    this.visit(instance);
                    this.statement.sql += ')';
                }
                else if (args.length == 2) {
                    // overload taking a length
                    this.visit(args[1]);
                }
    
                this.statement.sql += ')';
            }
        }
    });
    
    function isConstantOfType(expr, type) {
        return (expr.expressionType == 'Constant') && (typeof expr.value === type);
    }
    
    // query should be in the format as generated by query.js toOData function
    module.exports = function (query, tableConfig) {
        query.table = (tableConfig && (tableConfig.containerName || tableConfig.databaseTableName || tableConfig.name)) || query.table;
        var formatter = new SqlFormatter(tableConfig);
        return formatter.format(query);
    };
    
    module.exports.filter = function (query, parameterPrefix, tableConfig) {
        var formatter = new SqlFormatter(tableConfig);
        formatter.parameterPrefix = parameterPrefix || 'p';
        formatter._formatFilter(query);
        return formatter.statement;
    };
    
    },{"./ExpressionVisitor":258,"./booleanize":259,"./convertTypes":260,"./expressions":261,"./helpers":263,"./parseOData":265,"./utilities/types":267,"util":216}],263:[function(require,module,exports){
    // ----------------------------------------------------------------------------
    // Copyright (c) Microsoft Corporation. All rights reserved.
    // ----------------------------------------------------------------------------
    
    var types = require('./utilities/types'),
        strings = require('./utilities/strings');
    
    var helpers = module.exports = {
        // Performs the following validations on the specified identifier:
        // - first char is alphabetic or an underscore
        // - all other characters are alphanumeric or underscore
        // - the identifier is LTE 128 in length
        isValidIdentifier: function (identifier) {
            if (!identifier || !types.isString(identifier) || identifier.length > 128) {
                return false;
            }
    
            for (var i = 0; i < identifier.length; i++) {
                var char = identifier[i];
                if (i === 0) {
                    if (!(strings.isLetter(char) || (char == '_'))) {
                        return false;
                    }
                } else {
                    if (!(strings.isLetter(char) || strings.isDigit(char) || (char == '_'))) {
                        return false;
                    }
                }
            }
    
            return true;
        },
    
        validateIdentifier: function (identifier) {
            if (!this.isValidIdentifier(identifier)) {
                throw new Error(identifier + " is not a valid identifier. Identifiers must be under 128 characters in length, start with a letter or underscore, and can contain only alpha-numeric and underscore characters.");
            }
        },
    
        formatTableName: function (schemaName, tableName) {
    
            this.validateIdentifier(tableName);
    
            if (schemaName !== undefined) {
                schemaName = module.exports.formatSchemaName(schemaName);
                this.validateIdentifier(schemaName);
                return '[' + schemaName + '].[' + tableName + ']';
            }
    
            return '[' + tableName + ']';
        },
    
        formatSchemaName: function (appName) {
            // Hyphens are not supported in schema names
            return appName.replace(/-/g, '_');
        },
    
        formatMember: function (memberName) {
            this.validateIdentifier(memberName);
            return '[' + memberName + ']';
        },
    
        getSqlType: function (value, primaryKey) {
            if(value === undefined || value === null)
                throw new Error('Cannot create column for null or undefined value');
    
            switch (value.constructor) {
                case String:
                    // 900 bytes is the maximum length for a primary key - http://stackoverflow.com/questions/10555642/varcharmax-column-not-allowed-to-be-a-primary-key-in-sql-server
                    return primaryKey ? "NVARCHAR(255)" : "NVARCHAR(MAX)";
                case Number:
                    return primaryKey ? "INT" : "FLOAT(53)";
                case Boolean:
                    return "BIT";
                case Date:
                    return "DATETIMEOFFSET(7)";
                default:
                    throw new Error("Unable to map value " + value.toString() + " to a SQL type.");
            }
        },
    
        getPredefinedColumnType: function (value) {
            switch(value) {
                case 'string':
                    return 'NVARCHAR(MAX)';
                case 'number':
                    return 'FLOAT(53)';
                case 'boolean':
                case 'bool':
                    return 'BIT';
                case 'datetime':
                case 'date':
                    return 'DATETIMEOFFSET(7)';
            }
    
            throw new Error('Unrecognised column type: ' + value);
        },
    
        getPredefinedType: function (value) {
            switch(value) {
                case 'nvarchar':
                    return 'string';
                case 'float':
                    return 'number';
                case 'bit':
                    return 'boolean';
                case 'datetimeoffset':
                    return 'datetime';
                case 'timestamp':
                    return 'string';
                default:
                    return value;
            }
        },
    
        getSystemPropertiesDDL: function () {
            return {
                version: 'version ROWVERSION NOT NULL',
                createdAt: 'createdAt DATETIMEOFFSET(7) NOT NULL DEFAULT CONVERT(DATETIMEOFFSET(7),SYSUTCDATETIME(),0)',
                updatedAt: 'updatedAt DATETIMEOFFSET(7) NOT NULL DEFAULT CONVERT(DATETIMEOFFSET(7),SYSUTCDATETIME(),0)',
                deleted: 'deleted bit NOT NULL DEFAULT 0'
            };
        },
    
        getSystemProperties: function () {
            return Object.keys(helpers.getSystemPropertiesDDL());
        },
    
        isSystemProperty: function (property) {
            return helpers.getSystemProperties().some(function (systemProperty) { return property === systemProperty; });
        },
    };
    
    },{"./utilities/strings":266,"./utilities/types":267}],264:[function(require,module,exports){
    // ----------------------------------------------------------------------------
    // Copyright (c) Microsoft Corporation. All rights reserved.
    // ----------------------------------------------------------------------------
    var format = require('./format');
    
    module.exports = {
        format: format
    };
    
    },{"./format":262}],265:[function(require,module,exports){
    // ----------------------------------------------------------------------------
    // Copyright (c) Microsoft Corporation. All rights reserved.
    // ----------------------------------------------------------------------------
    
    var util = require('util'),
        types = require('./utilities/types'),
        strings = require('./utilities/strings'),
        expressions = require('./expressions');
    
    function ctor(expression) {
        this.keywords = this._createKeywords();
    
        // define the default root parameter for all member expressions
        this.it = new expressions.Parameter();
    
        this.text = expression;
        this.textLen = this.text.length;
        this.token = {};
        this._setTextPos(0);
        this._nextToken();
    }
    
    var ODataParser = types.defineClass(ctor, {
        parse: function () {
            var expr = this._parseExpression();
    
            this._validateToken('End', 'Syntax error');
            return expr;
        },
    
        parseOrdering: function () {
            var orderings = [];
            while (true) {
                var expr = this._parseExpression();
                var ascending = true;
                if (this._tokenIdentifierIs('asc')) {
                    this._nextToken();
                }
                else if (this._tokenIdentifierIs('desc')) {
                    this._nextToken();
                    ascending = false;
                }
                orderings.push({
                    selector: expr,
                    ascending: ascending
                });
                if (this.token.id != 'Comma') {
                    break;
                }
                this._nextToken();
            }
            this._validateToken('End', 'Syntax error');
            return orderings;
        },
    
        _tokenIdentifierIs: function (id) {
            return this.token.id == 'Identifier' && id == this.token.text;
        },
    
        _parseExpression: function () {
            return this._parseLogicalOr();
        },
    
        // 'or' operator
        _parseLogicalOr: function () {
            var left = this._parseLogicalAnd();
            while (this.token.id == 'Or') {
                this._nextToken();
                var right = this._parseLogicalAnd();
                left = new expressions.Binary(left, right, 'Or');
            }
            return left;
        },
    
        // 'and' operator
        _parseLogicalAnd: function () {
            var left = this._parseComparison();
            while (this.token.id == 'And') {
                this._nextToken();
                var right = this._parseComparison();
                left = new expressions.Binary(left, right, 'And');
            }
            return left;
        },
    
        _parseComparison: function () {
            var left = this._parseAdditive();
            while (this.token.id == 'Equal' || this.token.id == 'NotEqual' || this.token.id == 'GreaterThan' ||
                this.token.id == 'GreaterThanEqual' || this.token.id == 'LessThan' || this.token.id == 'LessThanEqual') {
    
                var opId = this.token.id;
                this._nextToken();
                var right = this._parseAdditive();
    
                switch (opId) {
                    case 'Equal':
                        left = new expressions.Binary(left, right, 'Equal');
                        break;
                    case 'NotEqual':
                        left = new expressions.Binary(left, right, 'NotEqual');
                        break;
                    case 'GreaterThan':
                        left = new expressions.Binary(left, right, 'GreaterThan');
                        break;
                    case 'GreaterThanEqual':
                        left = new expressions.Binary(left, right, 'GreaterThanOrEqual');
                        break;
                    case 'LessThan':
                        left = new expressions.Binary(left, right, 'LessThan');
                        break;
                    case 'LessThanEqual':
                        left = new expressions.Binary(left, right, 'LessThanOrEqual');
                        break;
                }
            }
            return left;
        },
    
        // 'add','sub' operators
        _parseAdditive: function () {
            var left = this._parseMultiplicative();
            while (this.token.id == 'Add' || this.token.id == 'Sub') {
                var opId = this.token.id;
                this._nextToken();
                var right = this._parseMultiplicative();
                switch (opId) {
                    case 'Add':
                        left = new expressions.Binary(left, right, 'Add');
                        break;
                    case 'Sub':
                        left = new expressions.Binary(left, right, 'Subtract');
                        break;
                }
            }
            return left;
        },
    
        // 'mul', 'div', 'mod' operators
        _parseMultiplicative: function () {
            var left = this._parseUnary();
            while (this.token.id == 'Multiply' || this.token.id == 'Divide' ||
                    this.token.id == 'Modulo') {
                var opId = this.token.id;
                this._nextToken();
                var right = this._parseUnary();
                switch (opId) {
                    case 'Multiply':
                        left = new expressions.Binary(left, right, 'Multiply');
                        break;
                    case 'Divide':
                        left = new expressions.Binary(left, right, 'Divide');
                        break;
                    case 'Modulo':
                        left = new expressions.Binary(left, right, 'Modulo');
                        break;
                }
            }
            return left;
        },
    
        // -, 'not' unary operators
        _parseUnary: function () {
            if (this.token.id == 'Minus' || this.token.id == 'Not') {
                var opId = this.token.id;
                var opPos = this.token.pos;
                this._nextToken();
                if (opId == 'Minus' && (this.token.id == 'IntegerLiteral' ||
                    this.token.id == 'RealLiteral')) {
                    this.token.text = "-" + this.token.text;
                    this.token.pos = opPos;
                    return this._parsePrimary();
                }
    
                var expr = this._parseUnary();
                if (opId == 'Minus') {
                    expr = new expressions.Unary(expr, 'Negate');
                } else {
                    expr = new expressions.Unary(expr, 'Not');
                }
                return expr;
            }
            return this._parsePrimary();
        },
    
        _parsePrimary: function () {
            var expr = this._parsePrimaryStart();
            while (true) {
                if (this.token.id == 'Dot') {
                    this._nextToken();
                    expr = this._parseMemberAccess(expr);
                }
                else {
                    break;
                }
            }
            return expr;
        },
    
        _parseMemberAccess: function (instance) {
            var errorPos = this.token.pos;
            var id = this._getIdentifier();
            this._nextToken();
            if (this.token.id == 'OpenParen') {
                var mappedFunction = this._mapFunction(id);
                if (mappedFunction !== null) {
                    return this._parseMappedFunction(mappedFunction, errorPos);
                }
                else {
                    throw this._parseError(util.format("Unknown identifier '%s'", id), errorPos);
                }
            }
            else {
                return new expressions.Member(instance, id);
            }
        },
    
        _parseMappedFunction: function (mappedMember, errorPos) {
            var mappedMemberName = mappedMember.memberName;
            var args;
            var instance = null;
    
            this._beginValidateFunction(mappedMemberName, errorPos);
    
            if (this.token.id == 'OpenParen') {
                args = this._parseArgumentList();
    
                this._completeValidateFunction(mappedMemberName, args);
    
                if (mappedMember.mapParams) {
                    mappedMember.mapParams(args);
                }
    
                // static methods need to include the target
                if (!mappedMember.isStatic) {
                    if (args.length === 0) {
                        throw this._parseError(
                            util.format("No applicable method '%s' exists in type '%s'", mappedMember.memberName, mappedMember.type), errorPos);
                    }
    
                    instance = args[0];
                    args = args.slice(1);
                }
                else {
                    instance = null;
                }
            }
            else {
                // if it is a function it should begin with a '('
                throw this._parseError("'(' expected");
            }
    
            if (mappedMember.isMethod) {
                // a mapped function
                return new expressions.FunctionCall(instance, mappedMember, args);
            }
            else {
                // a mapped Property/Field
                return new expressions.Member(instance, mappedMember);
            }
        },
    
        _beginValidateFunction: function (functionName, errorPos) {
            if (functionName === 'replace') {
                // Security: nested calls to replace must be prevented to avoid an exploit
                // wherein the client can force the server to allocate arbitrarily large
                // strings.
                if (this.inStringReplace) {
                    throw this._parseError("Calls to 'replace' cannot be nested.", errorPos);
                }
                this.inStringReplace = true;
            }
        },
    
        _completeValidateFunction: function (functionName, functionArgs, errorPos) {
            // validate parameters
            switch (functionName) {
                case 'day':
                case 'month':
                case 'year':
                case 'hour':
                case 'minute':
                case 'second':
                case 'floor':
                case 'ceiling':
                case 'round':
                case 'tolower':
                case 'toupper':
                case 'length':
                case 'trim':
                    this._validateFunctionParameters(functionName, functionArgs, 1);
                    break;
                case 'substringof':
                case 'startswith':
                case 'endswith':
                case 'concat':
                case 'indexof':
                    this._validateFunctionParameters(functionName, functionArgs, 2);
                    break;
                case 'replace':
                    this._validateFunctionParameters(functionName, functionArgs, 3);
                    // Security: we limit the replacement value to avoid an exploit
                    // wherein the client can force the server to allocate arbitrarily large
                    // strings.
                    var replaceArg = functionArgs[2];
                    if ((replaceArg.expressionType !== 'Constant') || (replaceArg.value.length > 100)) {
                        throw this._parseError("The third parameter to 'replace' must be a string constant less than 100 in length.", errorPos);
                    }
                    break;
                case 'substring':
                    if (functionArgs.length != 2 && functionArgs.length != 3) {
                        throw new Error("Function 'substring' requires 2 or 3 parameters.");
                    }
                    break;
            }
    
            this.inStringReplace = false;
        },
    
        _validateFunctionParameters: function (functionName, args, expectedArgCount) {
            if (args.length !== expectedArgCount) {
                var error = util.format("Function '%s' requires %d %s",
                    functionName, expectedArgCount, (expectedArgCount > 1) ? "parameters." : "parameter.");
                throw new Error(error);
            }
        },
    
        _parseArgumentList: function () {
            this._validateToken('OpenParen', "'(' expected");
            this._nextToken();
            var args = this.token.id != 'CloseParen' ? this._parseArguments() : [];
            this._validateToken('CloseParen', "')' or ',' expected");
            this._nextToken();
            return args;
        },
    
        _parseArguments: function () {
            var args = [];
            while (true) {
                args.push(this._parseExpression());
                if (this.token.id != 'Comma') {
                    break;
                }
                this._nextToken();
            }
            return args;
        },
    
        _mapFunction: function (functionName) {
            var mappedMember = this._mapStringFunction(functionName);
            if (mappedMember !== null) {
                return mappedMember;
            }
    
            mappedMember = this._mapDateFunction(functionName);
            if (mappedMember !== null) {
                return mappedMember;
            }
    
            mappedMember = this._mapMathFunction(functionName);
            if (mappedMember !== null) {
                return mappedMember;
            }
    
            return null;
        },
    
        _mapStringFunction: function (functionName) {
            if (functionName == 'startswith') {
                return new expressions.MappedMemberInfo('string', functionName, false, true);
            }
            else if (functionName == 'endswith') {
                return new expressions.MappedMemberInfo('string', functionName, false, true);
            }
            else if (functionName == 'length') {
                return new expressions.MappedMemberInfo('string', functionName, false, false);
            }
            else if (functionName == 'toupper') {
                return new expressions.MappedMemberInfo('string', functionName, false, true);
            }
            else if (functionName == 'tolower') {
                return new expressions.MappedMemberInfo('string', functionName, false, true);
            }
            else if (functionName == 'trim') {
                return new expressions.MappedMemberInfo('string', functionName, false, true);
            }
            else if (functionName == 'substringof') {
                var memberInfo = new expressions.MappedMemberInfo('string', functionName, false, true);
                memberInfo.mapParams = function (args) {
                    // reverse the order of arguments for string.Contains
                    var tmp = args[0];
                    args[0] = args[1];
                    args[1] = tmp;
                };
                return memberInfo;
            }
            else if (functionName == 'indexof') {
                return new expressions.MappedMemberInfo('string', functionName, false, true);
            }
            else if (functionName == 'replace') {
                return new expressions.MappedMemberInfo('string', functionName, false, true);
            }
            else if (functionName == 'substring') {
                return new expressions.MappedMemberInfo('string', functionName, false, true);
            }
            else if (functionName == 'trim') {
                return new expressions.MappedMemberInfo('string', functionName, false, true);
            }
            else if (functionName == 'concat') {
                return new expressions.MappedMemberInfo('string', functionName, true, true);
            }
    
            return null;
        },
    
        _mapDateFunction: function (functionName) {
            if (functionName == 'day') {
                return new expressions.MappedMemberInfo('date', functionName, false, true);
            }
            else if (functionName == 'month') {
                return new expressions.MappedMemberInfo('date', functionName, false, true);
            }
            else if (functionName == 'year') {
                return new expressions.MappedMemberInfo('date', functionName, false, true);
            }
            if (functionName == 'hour') {
                return new expressions.MappedMemberInfo('date', functionName, false, true);
            }
            else if (functionName == 'minute') {
                return new expressions.MappedMemberInfo('date', functionName, false, true);
            }
            else if (functionName == 'second') {
                return new expressions.MappedMemberInfo('date', functionName, false, true);
            }
            return null;
        },
    
        _mapMathFunction: function (functionName) {
            if (functionName == 'floor') {
                return new expressions.MappedMemberInfo('math', functionName, false, true);
            }
            else if (functionName == 'ceiling') {
                return new expressions.MappedMemberInfo('math', functionName, false, true);
            }
            else if (functionName == 'round') {
                return new expressions.MappedMemberInfo('math', functionName, false, true);
            }
            return null;
        },
    
        _getIdentifier: function () {
            this._validateToken('Identifier', 'Identifier expected');
            return this.token.text;
        },
    
        _parsePrimaryStart: function () {
            switch (this.token.id) {
                case 'Identifier':
                    return this._parseIdentifier();
                case 'StringLiteral':
                    return this._parseStringLiteral();
                case 'IntegerLiteral':
                    return this._parseIntegerLiteral();
                case 'RealLiteral':
                    return this._parseRealLiteral();
                case 'OpenParen':
                    return this._parseParenExpression();
                default:
                    throw this._parseError('Expression expected');
            }
        },
    
        _parseIntegerLiteral: function () {
            this._validateToken('IntegerLiteral');
            var text = this.token.text;
    
            // parseInt will return the integer portion of the string, and won't
            // error on something like '1234xyz'.
            var value = parseInt(text, 10);
            if (isNaN(value) || (value != text)) {
                throw this._parseError(util.format("Invalid integer literal '%s'", text));
            }
    
            this._nextToken();
            if (this.token.text.toUpperCase() == 'L') {
                // in JS there is only one type of integer number, so this code is only here
                // to parse the OData 'L/l' correctly
                this._nextToken();
                return new expressions.Constant(value);
            }
            return new expressions.Constant(value);
        },
    
        _parseRealLiteral: function () {
            this._validateToken('RealLiteral');
            var text = this.token.text;
    
            var last = text.slice(-1);
            if (last.toUpperCase() == 'F' || last.toUpperCase() == 'M' || last.toUpperCase() == 'D') {
                // in JS there is only one floating point type,
                // so terminating F/f, M/m, D/d have no effect.
                text = text.slice(0, -1);
            }
    
            var value = parseFloat(text);
    
            if (isNaN(value) || (value != text)) {
                throw this._parseError(util.format("Invalid real literal '%s'", text));
            }
    
            this._nextToken();
            return new expressions.FloatConstant(value);
        },
    
        _parseParenExpression: function () {
            this._validateToken('OpenParen', "'(' expected");
            this._nextToken();
            var e = this._parseExpression();
            this._validateToken('CloseParen', "')' or operator expected");
            this._nextToken();
            return e;
        },
    
        _parseIdentifier: function () {
            this._validateToken('Identifier');
            var value = this.keywords[this.token.text];
            if (value) {
                // type construction has the format of type'value' e.g. datetime'2001-04-01T00:00:00Z'
                // therefore if the next character is a single quote then we try to
                // interpret this as type construction else its a normal member access
                if (typeof value === 'string' && this.ch == '\'') {
                    return this._parseTypeConstruction(value);
                }
                else if (typeof value !== 'string') {  // this is a constant
                    this._nextToken();
                    return value;
                }
            }
    
            if (this.it !== null) {
                return this._parseMemberAccess(this.it);
            }
    
            throw this._parseError(util.format("Unknown identifier '%s'", this.token.text));
        },
    
        _parseTypeConstruction: function (type) {
            var typeIdentifier = this.token.text;
            var errorPos = this.token.pos;
            this._nextToken();
            var typeExpression = null;
    
            if (this.token.id == 'StringLiteral') {
                errorPos = this.token.pos;
                var stringExpr = this._parseStringLiteral();
                var literalValue = stringExpr.value;
                var date = null;
    
                try {
                    if (type == 'datetime') {
                        date = strings.parseISODate(literalValue);
                        if (date) {
                            typeExpression = new expressions.Constant(date);
                        }
                    }
                    else if (type == 'datetimeoffset') {
                        date = strings.parseDateTimeOffset(literalValue);
                        if (date) {
                            typeExpression = new expressions.Constant(date);
                        }
                    }
                }
                catch (e) {
                    throw this._parseError(e, errorPos);
                }
            }
    
            if (!typeExpression) {
                throw this._parseError(util.format("Invalid '%s' type creation expression", typeIdentifier), errorPos);
            }
    
            return typeExpression;
        },
    
        _parseStringLiteral: function () {
            this._validateToken('StringLiteral');
            // Unwrap string (remove surrounding quotes) and unwrap escaped quotes.
            var s = this.token.text.substr(1, this.token.text.length - 2).replace(/''/g, "'");
    
            this._nextToken();
            return new expressions.Constant(s);
        },
    
        _validateToken: function (tokenId, error) {
            if (this.token.id != tokenId) {
                throw this._parseError(error || 'Syntax error');
            }
        },
    
        _createKeywords: function () {
            return {
                "true": new expressions.Constant(true),
                "false": new expressions.Constant(false),
                "null": new expressions.Constant(null),
    
                // type keywords
                datetime: 'datetime',
                datetimeoffset: 'datetimeoffset'
            };
        },
    
        _setTextPos: function (pos) {
            this.textPos = pos;
            this.ch = this.textPos < this.textLen ? this.text[this.textPos] : '\\0';
        },
    
        _nextToken: function () {
            while (this._isWhiteSpace(this.ch)) {
                this._nextChar();
            }
            var t; // TokenId
            var tokenPos = this.textPos;
            switch (this.ch) {
                case '(':
                    this._nextChar();
                    t = 'OpenParen';
                    break;
                case ')':
                    this._nextChar();
                    t = 'CloseParen';
                    break;
                case ',':
                    this._nextChar();
                    t = 'Comma';
                    break;
                case '-':
                    this._nextChar();
                    t = 'Minus';
                    break;
                case '/':
                    this._nextChar();
                    t = 'Dot';
                    break;
                case '\'':
                    var quote = this.ch;
                    do {
                        this._nextChar();
                        while (this.textPos < this.textLen && this.ch != quote) {
                            this._nextChar();
                        }
    
                        if (this.textPos == this.textLen) {
                            throw this._parseError("Unterminated string literal", this.textPos);
                        }
                        this._nextChar();
                    }
                    while (this.ch == quote);
                    t = 'StringLiteral';
                    break;
                default:
                    if (this._isIdentifierStart(this.ch) || this.ch == '@' || this.ch == '_') {
                        do {
                            this._nextChar();
                        }
                        while (this._isIdentifierPart(this.ch) || this.ch == '_');
                        t = 'Identifier';
                        break;
                    }
                    if (strings.isDigit(this.ch)) {
                        t = 'IntegerLiteral';
                        do {
                            this._nextChar();
                        }
                        while (strings.isDigit(this.ch));
                        if (this.ch == '.') {
                            t = 'RealLiteral';
                            this._nextChar();
                            this._validateDigit();
                            do {
                                this._nextChar();
                            }
                            while (strings.isDigit(this.ch));
                        }
                        if (this.ch == 'E' || this.ch == 'e') {
                            t = 'RealLiteral';
                            this._nextChar();
                            if (this.ch == '+' || this.ch == '-') {
                                this._nextChar();
                            }
                            this._validateDigit();
                            do {
                                this._nextChar();
                            }
                            while (strings.isDigit(this.ch));
                        }
                        if (this.ch == 'F' || this.ch == 'f' || this.ch == 'M' || this.ch == 'm' || this.ch == 'D' || this.ch == 'd') {
                            t = 'RealLiteral';
                            this._nextChar();
                        }
                        break;
                    }
                    if (this.textPos == this.textLen) {
                        t = 'End';
                        break;
                    }
                    throw this._parseError("Syntax error '" + this.ch + "'", this.textPos);
            }
            this.token.id = t;
            this.token.text = this.text.substr(tokenPos, this.textPos - tokenPos);
            this.token.pos = tokenPos;
    
            this.token.id = this._reclassifyToken(this.token);
        },
    
        _reclassifyToken: function (token) {
            if (token.id == 'Identifier') {
                if (token.text == "or") {
                    return 'Or';
                }
                else if (token.text == "add") {
                    return 'Add';
                }
                else if (token.text == "and") {
                    return 'And';
                }
                else if (token.text == "div") {
                    return 'Divide';
                }
                else if (token.text == "sub") {
                    return 'Sub';
                }
                else if (token.text == "mul") {
                    return 'Multiply';
                }
                else if (token.text == "mod") {
                    return 'Modulo';
                }
                else if (token.text == "ne") {
                    return 'NotEqual';
                }
                else if (token.text == "not") {
                    return 'Not';
                }
                else if (token.text == "le") {
                    return 'LessThanEqual';
                }
                else if (token.text == "lt") {
                    return 'LessThan';
                }
                else if (token.text == "eq") {
                    return 'Equal';
                }
                else if (token.text == "ge") {
                    return 'GreaterThanEqual';
                }
                else if (token.text == "gt") {
                    return 'GreaterThan';
                }
            }
    
            return token.id;
        },
    
        _nextChar: function () {
            if (this.textPos < this.textLen) {
                this.textPos++;
            }
            this.ch = this.textPos < this.textLen ? this.text[this.textPos] : '\\0';
        },
    
        _isWhiteSpace: function (ch) {
            return (/\s/).test(ch);
        },
    
        _validateDigit: function () {
            if (!strings.isDigit(this.ch)) {
                throw this._parseError('Digit expected', this.textPos);
            }
        },
    
        _parseError: function (error, pos) {
            pos = pos || this.token.pos || 0;
            return new Error(error + ' (at index ' + pos + ')');
        },
    
        _isIdentifierStart: function (ch) {
            return strings.isLetter(ch);
        },
    
        _isIdentifierPart: function (ch) {
            if (this._isIdentifierStart(ch)) {
                return true;
            }
    
            if (strings.isDigit(ch)) {
                return true;
            }
    
            if (ch == '_' || ch == '-') {
                return true;
            }
    
            return false;
        }
    });
    
    module.exports = function (predicate) {
        return new ODataParser(predicate).parse();
    };
    
    module.exports.orderBy = function (ordering) {
        return new ODataParser(ordering).parseOrdering();
    };
    
    },{"./expressions":261,"./utilities/strings":266,"./utilities/types":267,"util":216}],266:[function(require,module,exports){
    // ----------------------------------------------------------------------------
    // Copyright (c) Microsoft Corporation. All rights reserved.
    // ----------------------------------------------------------------------------
    
    // Regex to validate string ids to ensure that it does not include any characters which can be used within a URI
    var stringIdValidatorRegex = /([\u0000-\u001F]|[\u007F-\u009F]|["\+\?\\\/\`]|^\.{1,2}$)/;
    
    // Match YYYY-MM-DDTHH:MM:SS.sssZ, with the millisecond (.sss) part optional
    // Note: we only support a subset of ISO 8601
    var iso8601Regex = /^(\d{4})-(\d{2})-(\d{2})T(\d{2})\:(\d{2})\:(\d{2})(\.(\d{3}))?Z$/;
    
    // Match MS Date format "\/Date(1336003790912-0700)\/"
    var msDateRegex = /^\/Date\((-?)(\d+)(([+\-])(\d{2})(\d{2})?)?\)\/$/;
    
    var strings = module.exports = {
        isLetter: function (ch) {
            return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z');
        },
    
        isDigit: function (ch) {
            return ch >= '0' && ch <= '9';
        },
    
        isValidStringId: function (id) {
            return !stringIdValidatorRegex.test(id);
        },
    
        // remove starting and finishing quotes and remove quote escaping from the middle of a string
        getVersionFromEtag: function (etag) {
            return etag.replace(/^"|\\(?=")|"$/g, '');
        },
    
        getEtagFromVersion: function (version) {
            return '"' + version.replace(/\"/g, '\\"') + '"';
        },
    
        convertDate: function (value) {
            var date = strings.parseISODate(value);
            if (date) {
                return date;
            }
    
            date = strings.parseMsDate(value);
            if (date) {
                return date;
            }
    
            return null;
        },
    
        // attempt to parse the value as an ISO 8601 date (e.g. 2012-05-03T00:06:00.638Z)
        parseISODate: function (value) {
            if (iso8601Regex.test(value)) {
                return strings.parseDateTimeOffset(value);
            }
    
            return null;
        },
    
        // parse a date and convert to UTC
        parseDateTimeOffset: function (value) {
            var ms = Date.parse(value);
            if (!isNaN(ms)) {
                return new Date(ms);
            }
            return null;
        },
    
        // attempt to parse the value as an MS date (e.g. "\/Date(1336003790912-0700)\/")
        parseMsDate: function (value) {
            var match = msDateRegex.exec(value);
            if (match) {
                // Get the ms and offset
                var milliseconds = parseInt(match[2], 10);
                var offsetMinutes = 0;
                if (match[5]) {
                    var hours = parseInt(match[5], 10);
                    var minutes = parseInt(match[6] || '0', 10);
                    offsetMinutes = (hours * 60) + minutes;
                }
    
                // Handle negation
                if (match[1] === '-') {
                    milliseconds = -milliseconds;
                }
                if (match[4] === '-') {
                    offsetMinutes = -offsetMinutes;
                }
    
                var date = new Date();
                date.setTime(milliseconds + offsetMinutes * 60000);
                return date;
            }
            return null;
        },
    
        parseBoolean: function (bool) {
            if (bool === undefined || bool === null || typeof bool !== 'string') {
                return undefined;
            } else if (bool.toLowerCase() === 'true') {
                return true;
            } else if (bool.toLowerCase() === 'false') {
                return false;
            } else {
                return undefined;
            }
        }
    };
    
    },{}],267:[function(require,module,exports){
    // ----------------------------------------------------------------------------
    // Copyright (c) Microsoft Corporation. All rights reserved.
    // ----------------------------------------------------------------------------
    var types = module.exports = {
        curry: function (fn) {
            var slice = Array.prototype.slice,
                args = slice.call(arguments, 1);
            return function () {
                return fn.apply(null, args.concat(slice.call(arguments)));
            };
        },
    
        extend: function (target, members) {
            for (var member in members) {
                if(members.hasOwnProperty(member))
                    target[member] = members[member];
            }
            return target;
        },
    
        defineClass: function (ctor, instanceMembers, classMembers) {
            ctor = ctor || function () { };
            if (instanceMembers) {
                types.extend(ctor.prototype, instanceMembers);
            }
            if (classMembers) {
                types.extend(ctor, classMembers);
            }
            return ctor;
        },
    
        deriveClass: function (baseClass, ctor, instanceMembers) {
            var basePrototype = baseClass.prototype;
            var prototype = {};
            types.extend(prototype, basePrototype);
    
            var getPrototype = function (name, fn) {
                return function () {
                    var tmp = this._super;
                    this._super = basePrototype;
                    var ret = fn.apply(this, arguments);
                    this._super = tmp;
                    return ret;
                };
            };
    
            if (instanceMembers)
                for (var name in instanceMembers)
                    if(instanceMembers.hasOwnProperty(name))
                        // Check if we're overwriting an existing function
                        prototype[name] = typeof instanceMembers[name] === 'function' && typeof basePrototype[name] === 'function' ?
                            getPrototype(name, instanceMembers[name]) :
                            instanceMembers[name];
    
            ctor = ctor ?
                (function (fn) {
                    return function () {
                        var tmp = this._super;
                        this._super = basePrototype;
                        var ret = fn.apply(this, arguments);
                        this._super = tmp;
                        return ret;
                    };
                })(ctor)
                : function () { };
    
            ctor.prototype = prototype;
            ctor.prototype.constructor = ctor;
            return ctor;
        },
    
        classof: function (o) {
            if (o === null) {
                return 'null';
            }
            if (o === undefined) {
                return 'undefined';
            }
            return Object.prototype.toString.call(o).slice(8, -1).toLowerCase();
        },
    
        isArray: function (o) {
            return types.classof(o) === 'array';
        },
    
        isObject: function (o) {
            return types.classof(o) === 'object';
        },
    
        isDate: function (o) {
            return types.classof(o) === 'date';
        },
    
        isFunction: function (o) {
            return types.classof(o) === 'function';
        },
    
        isString: function (o) {
            return types.classof(o) === 'string';
        },
    
        isNumber: function (o) {
            return types.classof(o) === 'number';
        },
    
        isError: function (o) {
            return types.classof(o) === 'error';
        },
    
        isGuid: function (value) {
            return types.isString(value) && /[a-fA-F\d]{8}-(?:[a-fA-F\d]{4}-){3}[a-fA-F\d]{12}/.test(value);
        },
    
        isEmpty: function (obj) {
            if (obj === null || obj === undefined) {
                return true;
            }
            for (var key in obj) {
                if (obj.hasOwnProperty(key)) {
                    return false;
                }
            }
            return true;
        }
    };
    
    },{}],268:[function(require,module,exports){
    // Generated by CoffeeScript 1.10.0
    
    /*
     * ----------------------------------------------------------------------------
     * Copyright (c) Microsoft Corporation. All rights reserved.
     * ----------------------------------------------------------------------------
     */
    
    (function() {
      var JS, JavaScript, JavaScriptToQueryVisitor, PartialEvaluator, esprima;
    
      esprima = require('esprima');
    
      JS = require('./JavaScriptNodes');
    
      PartialEvaluator = require('./PartialEvaluator').PartialEvaluator;
    
      JavaScriptToQueryVisitor = require('./JavaScriptToQueryVisitor').JavaScriptToQueryVisitor;
    
    
      /*
       * Define operations on JavaScript
       */
    
      exports.JavaScript = JavaScript = (function() {
        function JavaScript() {}
    
    
        /*
         * Static method to transform a constraint specified as a function into
         * a QueryExpression tree.
         */
    
        JavaScript.transformConstraint = function(func, env) {
    
          /*
           * Parse the body of the function into a JavaScriptExpression tree
           * (into a context that also contains its source and manually reified
           * environment)
           */
          var context, translator;
          context = JavaScript.getExpression(func, env);
    
          /*
           * Evaluate any independent subexpressions and turn them into
           * literals.
           */
          context.expression = PartialEvaluator.evaluate(context);
    
          /*
           * Convert the JavaScriptExpression tree into a QueryExpression tree
           */
          translator = new JavaScriptToQueryVisitor(context);
          return translator.visit(context.expression);
        };
    
    
        /*
         * Static method to walk a projection specified as a function and
         * determine which fields it uses.
         */
    
        JavaScript.getProjectedFields = function(func) {
    
          /*
           * This currently returns an empty array which indicates all fields.
           * At some point we'll need to go through and walk the expression
           * tree for func and see exactly which fields it uses.  This is
           * complicated by the fact that we support arbitrary expressions and
           * could for example pass 'this' to a nested lambda which means we
           * can't just check for MemberExpressions (though in that case we'll
           * probably just default to [] rather than trying to do alias
           * analysis across function calls, etc.)
           */
          return [];
        };
    
    
        /*
         * Turn a function and its explicitly passed environment into an
         * expression tree
         */
    
        JavaScript.getExpression = function(func, env) {
    
          /*
           * An anonymous function isn't considered a valid program, so we'll wrap
           * it in an assignment statement to keep the parser happy
           */
          var environment, expr, i, j, len, name, names, program, ref, ref1, ref10, ref11, ref12, ref13, ref2, ref3, ref4, ref5, ref6, ref7, ref8, ref9, source;
          source = "var _$$_stmt_$$_ = " + func + ";";
    
          /*
           * Use esprima to parse the source of the function body (and have it
           * return source locations in character ranges )
           */
          program = esprima.parse(source, {
            range: true
    
            /*
             * Get the expression from return statement of the function body to use
             * as our lambda expression
             */
          });
          expr = (program != null ? program.type : void 0) === 'Program' && (program != null ? (ref = program.body) != null ? ref.length : void 0 : void 0) === 1 && ((ref1 = program.body[0]) != null ? ref1.type : void 0) === 'VariableDeclaration' && ((ref2 = program.body[0]) != null ? (ref3 = ref2.declarations) != null ? ref3.length : void 0 : void 0) === 1 && ((ref4 = program.body[0].declarations[0]) != null ? ref4.type : void 0) === 'VariableDeclarator' && ((ref5 = program.body[0].declarations[0]) != null ? (ref6 = ref5.init) != null ? ref6.type : void 0 : void 0) === 'FunctionExpression' && ((ref7 = program.body[0].declarations[0].init) != null ? (ref8 = ref7.body) != null ? ref8.type : void 0 : void 0) === 'BlockStatement' && ((ref9 = program.body[0].declarations[0].init.body) != null ? (ref10 = ref9.body) != null ? ref10.length : void 0 : void 0) === 1 && ((ref11 = program.body[0].declarations[0].init.body.body[0]) != null ? ref11.type : void 0) === 'ReturnStatement' && ((ref12 = program.body[0].declarations[0].init.body.body[0]) != null ? ref12.argument : void 0);
          if (!expr) {
            throw "Expected a predicate with a single return statement, not " + func;
          }
    
          /*
           * Create the environment mqpping parameters to values
           */
          names = (ref13 = program.body[0].declarations[0].init.params) != null ? ref13.map(function(p) {
            return p.name;
          }) : void 0;
          if (names.length > env.length) {
            throw "Expected value(s) for parameter(s) " + names.slice(env.length);
          } else if (env.length > names.length) {
            throw "Expected parameter(s) for value(s) " + env.slice(names.length);
          }
          environment = {};
          for (i = j = 0, len = names.length; j < len; i = ++j) {
            name = names[i];
            environment[name] = env[i];
          }
          return {
    
            /*
             * Return the environment context
             */
            source: source,
            expression: expr,
            environment: environment
          };
        };
    
        return JavaScript;
    
      })();
    
    }).call(this);
    
    },{"./JavaScriptNodes":269,"./JavaScriptToQueryVisitor":270,"./PartialEvaluator":273,"esprima":278}],269:[function(require,module,exports){
    // Generated by CoffeeScript 1.10.0
    
    /*
     * ----------------------------------------------------------------------------
     * Copyright (c) Microsoft Corporation. All rights reserved.
     * ----------------------------------------------------------------------------
     */
    
    
    /*
     * Define the Esprima node structure for JavaScript parse trees.  This is mostly
     * identical to the SpiderMonkey API defined at
     * https://developer.mozilla.org/en/SpiderMonkey/Parser_API without any of the
     * SpiderMonkey specifics and a few simplifications made by Esprima (i.e. it
     * doesn't have separate objects for operator types, etc.).
     *
     * It's important to note that the Esprima parse tree will return object literals
     * and not instances of these types.  They're provided primarily for reference
     * and for easily constructing new subtrees during transformations by visitors.
     */
    
    
    /* Get the base Node and Visitor classes. */
    
    (function() {
      var ArrayExpression, ArrayPattern, AssignmentExpression, BinaryExpression, BlockStatement, BreakStatement, CallExpression, CatchClause, ConditionalExpression, ContinueStatement, DebuggerStatement, Declaration, DoWhileStatement, EmptyStatement, Expression, ExpressionStatement, ForInStatement, ForStatement, Function, FunctionDeclaration, FunctionExpression, Identifier, IfStatement, JavaScriptNode, JavaScriptVisitor, LabeledStatement, Literal, LogicalExpression, MemberExpression, NewExpression, Node, ObjectExpression, ObjectPattern, Pattern, Program, ReturnStatement, SequenceExpression, Statement, SwitchCase, SwitchStatement, ThisExpression, ThrowStatement, TryStatement, UnaryExpression, UpdateExpression, VariableDeclaration, VariableDeclarator, Visitor, WhileStatement, WithStatement, ref,
        extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
        hasProp = {}.hasOwnProperty;
    
      ref = require('./Node'), Node = ref.Node, Visitor = ref.Visitor;
    
    
      /*
       * Base node for all JavaScript nodes.
       */
    
      exports.JavaScriptNode = JavaScriptNode = (function(superClass) {
        extend(JavaScriptNode, superClass);
    
        function JavaScriptNode() {
          JavaScriptNode.__super__.constructor.call(this);
        }
    
        return JavaScriptNode;
    
      })(Node);
    
    
      /*
       * Base visitor for all JavaScript nodes.
       */
    
      exports.JavaScriptVisitor = JavaScriptVisitor = (function(superClass) {
        extend(JavaScriptVisitor, superClass);
    
        function JavaScriptVisitor() {
          JavaScriptVisitor.__super__.constructor.call(this);
        }
    
        JavaScriptVisitor.prototype.JavaScriptNode = function(node) {
          return node;
        };
    
        return JavaScriptVisitor;
    
      })(Visitor);
    
    
      /*
       * A complete program source tree.
       */
    
      exports.Program = Program = (function(superClass) {
        extend(Program, superClass);
    
    
        /*
         * @elements: [Statement]
         */
    
        function Program(elements) {
          this.elements = elements;
          Program.__super__.constructor.call(this);
        }
    
        return Program;
    
      })(JavaScriptNode);
    
      JavaScriptVisitor.prototype.Program = function(node) {
        node = this.JavaScriptNode(node);
        node.elements = this.visit(node.elements);
        return node;
      };
    
    
      /*
       * A function declaration or expression. The body of the function is a  block
       * statement.
       */
    
      exports.Function = Function = (function(superClass) {
        extend(Function, superClass);
    
    
        /*
         * @id: Identifier | null
         * @params: [Pattern]
         * @body: BlockStatement
         */
    
        function Function(id, params, body) {
          this.id = id;
          this.params = params;
          this.body = body;
          Function.__super__.constructor.call(this);
        }
    
        return Function;
    
      })(JavaScriptNode);
    
      JavaScriptVisitor.prototype.Function = function(node) {
        node = this.JavaScriptNode(node);
        node.id = this.visit(node.id);
        node.params = this.visit(node.params);
        node.body = this.visit(node.body);
        return node;
      };
    
    
      /*
       * Any statement.
       */
    
      exports.Statement = Statement = (function(superClass) {
        extend(Statement, superClass);
    
        function Statement() {
          Statement.__super__.constructor.call(this);
        }
    
        return Statement;
    
      })(JavaScriptNode);
    
      JavaScriptVisitor.prototype.Statement = function(node) {
        node = this.JavaScriptNode(node);
        return node;
      };
    
    
      /*
       * An empty statement, i.e., a solitary semicolon.
       */
    
      exports.EmptyStatement = EmptyStatement = (function(superClass) {
        extend(EmptyStatement, superClass);
    
        function EmptyStatement() {
          EmptyStatement.__super__.constructor.call(this);
        }
    
        return EmptyStatement;
    
      })(JavaScriptNode);
    
      JavaScriptVisitor.prototype.EmptyStatement = function(node) {
        node = this.JavaScriptNode(node);
        return node;
      };
    
    
      /*
       * A block statement, i.e., a sequence of statements surrounded by braces.
       */
    
      exports.BlockStatement = BlockStatement = (function(superClass) {
        extend(BlockStatement, superClass);
    
    
        /*
         * @body: [Statement]
         */
    
        function BlockStatement(body) {
          this.body = body;
          BlockStatement.__super__.constructor.call(this);
        }
    
        return BlockStatement;
    
      })(Statement);
    
      JavaScriptVisitor.prototype.BlockStatement = function(node) {
        node = this.Statement(node);
        node.body = this.visit(node.body);
        return node;
      };
    
    
      /*
       * An expression statement, i.e., a statement consisting of a single expression.
       */
    
      exports.ExpressionStatement = ExpressionStatement = (function(superClass) {
        extend(ExpressionStatement, superClass);
    
        function ExpressionStatement() {
          ExpressionStatement.__super__.constructor.call(this);
        }
    
        return ExpressionStatement;
    
      })(Statement);
    
      JavaScriptVisitor.prototype.ExpressionStatement = function(node) {
        node = this.Statement(node);
        return node;
      };
    
    
      /*
       * An if statement.
       */
    
      exports.IfStatement = IfStatement = (function(superClass) {
        extend(IfStatement, superClass);
    
    
        /*
         * @test: Expression
         * @consequent: Statement
         * @alternate: Statement | null
         */
    
        function IfStatement(test, consequent, alternate) {
          this.test = test;
          this.consequent = consequent;
          this.alternate = alternate;
          IfStatement.__super__.constructor.call(this);
        }
    
        return IfStatement;
    
      })(Statement);
    
      JavaScriptVisitor.prototype.IfStatement = function(node) {
        node = this.Statement(node);
        node.test = this.visit(node.test);
        node.consequent = this.visit(node.consequent);
        node.alternate = this.visit(node.alternate);
        return node;
      };
    
    
      /*
       * A labeled statement, i.e., a statement prefixed by a break/continue label.
       */
    
      exports.LabeledStatement = LabeledStatement = (function(superClass) {
        extend(LabeledStatement, superClass);
    
    
        /*
         * @label: Identifier
         * @body: Statement
         */
    
        function LabeledStatement(label, body) {
          this.label = label;
          this.body = body;
          LabeledStatement.__super__.constructor.call(this);
        }
    
        return LabeledStatement;
    
      })(Statement);
    
      JavaScriptVisitor.prototype.LabeledStatement = function(node) {
        node = this.Statement(node);
        node.label = this.visit(node.label);
        node.body = this.visit(node.body);
        return node;
      };
    
    
      /*
       * A break statement.
       */
    
      exports.BreakStatement = BreakStatement = (function(superClass) {
        extend(BreakStatement, superClass);
    
    
        /*
         * @label: Identifier | null
         */
    
        function BreakStatement(label) {
          this.label = label;
          BreakStatement.__super__.constructor.call(this);
        }
    
        return BreakStatement;
    
      })(Statement);
    
      JavaScriptVisitor.prototype.BreakStatement = function(node) {
        node = this.Statement(node);
        node.label = this.visit(node.label);
        return node;
      };
    
    
      /*
      A continue statement.
       */
    
      exports.ContinueStatement = ContinueStatement = (function(superClass) {
        extend(ContinueStatement, superClass);
    
    
        /*
        @label: Identifier | null
         */
    
        function ContinueStatement(label) {
          this.label = label;
          ContinueStatement.__super__.constructor.call(this);
        }
    
        return ContinueStatement;
    
      })(Statement);
    
      JavaScriptVisitor.prototype.ContinueStatement = function(node) {
        node = this.Statement(node);
        node.label = this.visit(node.label);
        return node;
      };
    
    
      /*
       * A with statement.
       */
    
      exports.WithStatement = WithStatement = (function(superClass) {
        extend(WithStatement, superClass);
    
    
        /*
         * @object: Expression
         * @body: Statement
         */
    
        function WithStatement(object, body) {
          this.object = object;
          this.body = body;
          WithStatement.__super__.constructor.call(this);
        }
    
        return WithStatement;
    
      })(Statement);
    
      JavaScriptVisitor.prototype.WithStatement = function(node) {
        node = this.Statement(node);
        node.object = this.visit(node.object);
        node.body = this.visit(node.body);
        return node;
      };
    
    
      /*
       * A switch statement.
       */
    
      exports.SwitchStatement = SwitchStatement = (function(superClass) {
        extend(SwitchStatement, superClass);
    
    
        /*
         * @discriminant: Expression
         * @cases: [SwitchCase]
         */
    
        function SwitchStatement(discriminant, cases) {
          this.discriminant = discriminant;
          this.cases = cases;
          SwitchStatement.__super__.constructor.call(this);
        }
    
        return SwitchStatement;
    
      })(Statement);
    
      JavaScriptVisitor.prototype.SwitchStatement = function(node) {
        node = this.Statement(node);
        node.discriminant = this.visit(node.discriminant);
        node.cases = this.visit(node.cases);
        return node;
      };
    
    
      /*
       * A return statement.
       */
    
      exports.ReturnStatement = ReturnStatement = (function(superClass) {
        extend(ReturnStatement, superClass);
    
    
        /*
         * @argument: Expression | null
         */
    
        function ReturnStatement(argument) {
          this.argument = argument;
          ReturnStatement.__super__.constructor.call(this);
        }
    
        return ReturnStatement;
    
      })(Statement);
    
      JavaScriptVisitor.prototype.ReturnStatement = function(node) {
        node = this.Statement(node);
        node.argument = this.visit(node.argument);
        return node;
      };
    
    
      /*
       * A throw statement.
       */
    
      exports.ThrowStatement = ThrowStatement = (function(superClass) {
        extend(ThrowStatement, superClass);
    
    
        /*
         * @argument: Expression
         */
    
        function ThrowStatement(argument) {
          this.argument = argument;
          ThrowStatement.__super__.constructor.call(this);
        }
    
        return ThrowStatement;
    
      })(Statement);
    
      JavaScriptVisitor.prototype.ThrowStatement = function(node) {
        node = this.Statement(node);
        node.argument = this.visit(node.argument);
        return node;
      };
    
    
      /*
       * A try statement.
       */
    
      exports.TryStatement = TryStatement = (function(superClass) {
        extend(TryStatement, superClass);
    
    
        /*
         * @block: BlockStatement
         * @handlers: [CatchClause]
         * @finalizer: BlockStatement | null
         */
    
        function TryStatement(block, handlers, finalizer) {
          this.block = block;
          this.handlers = handlers;
          this.finalizer = finalizer;
          TryStatement.__super__.constructor.call(this);
        }
    
        return TryStatement;
    
      })(Statement);
    
      JavaScriptVisitor.prototype.TryStatement = function(node) {
        node = this.Statement(node);
        node.block = this.visit(node.block);
        node.handlers = this.visit(node.handlers);
        node.finalizer = this.visit(node.finalizer);
        return node;
      };
    
    
      /*
       * A while statement.
       */
    
      exports.WhileStatement = WhileStatement = (function(superClass) {
        extend(WhileStatement, superClass);
    
    
        /*
         * @test: Expression
         * @body: Statement
         */
    
        function WhileStatement(test, body) {
          this.test = test;
          this.body = body;
          WhileStatement.__super__.constructor.call(this);
        }
    
        return WhileStatement;
    
      })(Statement);
    
      JavaScriptVisitor.prototype.WhileStatement = function(node) {
        node = this.Statement(node);
        node.test = this.visit(node.test);
        node.body = this.visit(node.body);
        return node;
      };
    
    
      /*
       * A do/while statement.
       */
    
      exports.DoWhileStatement = DoWhileStatement = (function(superClass) {
        extend(DoWhileStatement, superClass);
    
    
        /*
         * @body: Statement
         * @test: Expression
         */
    
        function DoWhileStatement(body, test) {
          this.body = body;
          this.test = test;
          DoWhileStatement.__super__.constructor.call(this);
        }
    
        return DoWhileStatement;
    
      })(Statement);
    
      JavaScriptVisitor.prototype.DoWhileStatement = function(node) {
        node = this.Statement(node);
        node.body = this.visit(node.body);
        node.test = this.visit(node.test);
        return node;
      };
    
    
      /*
       * A for statement.
       */
    
      exports.ForStatement = ForStatement = (function(superClass) {
        extend(ForStatement, superClass);
    
    
        /*
         * @init: VariableDeclaration | Expression | null
         * @test: Expression | null
         * @update: Expression | null
         * @body: Statement
         */
    
        function ForStatement(init, test, update, body) {
          this.init = init;
          this.test = test;
          this.update = update;
          this.body = body;
          ForStatement.__super__.constructor.call(this);
        }
    
        return ForStatement;
    
      })(Statement);
    
      JavaScriptVisitor.prototype.ForStatement = function(node) {
        node = this.Statement(node);
        node.init = this.visit(node.init);
        node.test = this.visit(node.test);
        node.update = this.visit(node.update);
        node.body = this.visit(node.body);
        return node;
      };
    
    
      /*
       * A for/in statement, or, if each is true, a for each/in statement.
       */
    
      exports.ForInStatement = ForInStatement = (function(superClass) {
        extend(ForInStatement, superClass);
    
    
        /*
         * @left: VariableDeclaration |  Expression
         * @right: Expression
         * @body: Statement
         */
    
        function ForInStatement(left, right, body) {
          this.left = left;
          this.right = right;
          this.body = body;
          ForInStatement.__super__.constructor.call(this);
        }
    
        return ForInStatement;
    
      })(Statement);
    
      JavaScriptVisitor.prototype.ForInStatement = function(node) {
        node = this.Statement(node);
        node.left = this.visit(node.left);
        node.right = this.visit(node.right);
        node.body = this.visit(node.body);
        return node;
      };
    
    
      /*
       * A debugger statement.
       */
    
      exports.DebuggerStatement = DebuggerStatement = (function(superClass) {
        extend(DebuggerStatement, superClass);
    
        function DebuggerStatement() {
          DebuggerStatement.__super__.constructor.call(this);
        }
    
        return DebuggerStatement;
    
      })(Statement);
    
      JavaScriptVisitor.prototype.DebuggerStatement = function(node) {
        node = this.Statement(node);
        return node;
      };
    
    
      /*
       * Any declaration node. Note that declarations are considered statements; this
       * is because declarations can appear in any statement context in the language.
       */
    
      exports.Declaration = Declaration = (function(superClass) {
        extend(Declaration, superClass);
    
        function Declaration() {
          Declaration.__super__.constructor.call(this);
        }
    
        return Declaration;
    
      })(Statement);
    
      JavaScriptVisitor.prototype.Declaration = function(node) {
        node = this.Statement(node);
        return node;
      };
    
    
      /*
       * A function declaration.  Note: The id field cannot be null.
       */
    
      exports.FunctionDeclaration = FunctionDeclaration = (function(superClass) {
        extend(FunctionDeclaration, superClass);
    
    
        /*
         * @id: Identifier
         * @params: [ Pattern ]
         * @body: BlockStatement | Expression
         */
    
        function FunctionDeclaration(id, params, body) {
          this.id = id;
          this.params = params;
          this.body = body;
          FunctionDeclaration.__super__.constructor.call(this);
        }
    
        return FunctionDeclaration;
    
      })(Declaration);
    
      JavaScriptVisitor.prototype.FunctionDeclaration = function(node) {
        node = this.Declaration(node);
        node.id = this.visit(node.id);
        node.params = this.visit(node.params);
        node.body = this.visit(node.body);
        return node;
      };
    
    
      /*
       * A variable declaration, via one of var, let, or const.
       */
    
      exports.VariableDeclaration = VariableDeclaration = (function(superClass) {
        extend(VariableDeclaration, superClass);
    
    
        /*
         * @declarations: [ VariableDeclarator ]
         * @kind: "var"
         */
    
        function VariableDeclaration(declarations, kind) {
          this.declarations = declarations;
          this.kind = kind;
          VariableDeclaration.__super__.constructor.call(this);
        }
    
        return VariableDeclaration;
    
      })(Declaration);
    
      JavaScriptVisitor.prototype.VariableDeclaration = function(node) {
        node = this.Declaration(node);
        node.declarations = this.visit(node.declarations);
        return node;
      };
    
    
      /*
       * A variable declarator.  Note: The id field cannot be null.
       */
    
      exports.VariableDeclarator = VariableDeclarator = (function(superClass) {
        extend(VariableDeclarator, superClass);
    
    
        /*
         * @id: Pattern
         * @init: Expression | null
         */
    
        function VariableDeclarator(id, init) {
          this.id = id;
          this.init = init;
          VariableDeclarator.__super__.constructor.call(this);
        }
    
        return VariableDeclarator;
    
      })(JavaScriptNode);
    
      JavaScriptVisitor.prototype.VariableDeclarator = function(node) {
        node = this.JavaScriptNode(node);
        node.id = this.visit(node.id);
        node.init = this.visit(node.init);
        return node;
      };
    
    
      /*
       * Any expression node. Since the left-hand side of an assignment may be any
       * expression in general, an expression can also be a pattern.
       */
    
      exports.Expression = Expression = (function(superClass) {
        extend(Expression, superClass);
    
        function Expression() {
          return Expression.__super__.constructor.apply(this, arguments);
        }
    
        Expression.prototype.constuctor = function() {
          return Expression.__super__.constuctor.call(this);
        };
    
        return Expression;
    
      })(JavaScriptNode);
    
      JavaScriptVisitor.prototype.Expression = function(node) {
        node = this.JavaScriptNode(node);
        return node;
      };
    
    
      /*
       * A this expression.
       */
    
      exports.ThisExpression = ThisExpression = (function(superClass) {
        extend(ThisExpression, superClass);
    
        function ThisExpression() {
          ThisExpression.__super__.constructor.call(this);
        }
    
        return ThisExpression;
    
      })(Expression);
    
      JavaScriptVisitor.prototype.ThisExpression = function(node) {
        node = this.Expression(node);
        return node;
      };
    
    
      /*
       * An array expression.
       */
    
      exports.ArrayExpression = ArrayExpression = (function(superClass) {
        extend(ArrayExpression, superClass);
    
    
        /*
         * @elements: [ Expression | null ]
         */
    
        function ArrayExpression(elements) {
          this.elements = elements;
          ArrayExpression.__super__.constructor.call(this);
        }
    
        return ArrayExpression;
    
      })(Expression);
    
      JavaScriptVisitor.prototype.ArrayExpression = function(node) {
        node = this.Expression(node);
        node.elements = this.visit(node.elements);
        return node;
      };
    
    
      /*
       * An object expression. A literal property in an object expression can have
       * either a string or number as its value.  Ordinary property initializers have a
       * kind value "init"; getters and setters have the kind values "get" and "set",
       * respectively.
       */
    
      exports.ObjectExpression = ObjectExpression = (function(superClass) {
        extend(ObjectExpression, superClass);
    
    
        /*
         * @properties: [ { key: Literal | Identifier,
         *                 value: Expression,
         *                 kind: "init" | "get" | "set" } ];
         */
    
        function ObjectExpression(properties) {
          this.properties = properties;
          ObjectExpression.__super__.constructor.call(this);
        }
    
        return ObjectExpression;
    
      })(Expression);
    
      JavaScriptVisitor.prototype.ObjectExpression = function(node) {
        var i, len, ref1, setter;
        node = this.Expression(node);
        ref1 = node.properties;
        for (i = 0, len = ref1.length; i < len; i++) {
          setter = ref1[i];
          setter.key = this.visit(setter.key);
          setter.value = this.visit(setter.value);
        }
        return node;
      };
    
    
      /*
       * A function expression.
       */
    
      exports.FunctionExpression = FunctionExpression = (function(superClass) {
        extend(FunctionExpression, superClass);
    
    
        /*
         * @id: Identifier | null
         * @params: [ Pattern ]
         * @body: BlockStatement | Expression
         */
    
        function FunctionExpression(id, params, body) {
          this.id = id;
          this.params = params;
          this.body = body;
          FunctionExpression.__super__.constructor.call(this);
        }
    
        return FunctionExpression;
    
      })(Expression);
    
      JavaScriptVisitor.prototype.FunctionExpression = function(node) {
        node = this.Expression(node);
        node.id = this.visit(node.id);
        node.params = this.visit(node.params);
        node.body = this.visit(node.body);
        return node;
      };
    
    
      /*
       * A sequence expression, i.e., a comma-separated sequence of expressions.
       */
    
      exports.SequenceExpression = SequenceExpression = (function(superClass) {
        extend(SequenceExpression, superClass);
    
    
        /*
         * @expressions: [ Expression ]
         */
    
        function SequenceExpression(expressions) {
          this.expressions = expressions;
          SequenceExpression.__super__.constructor.call(this);
        }
    
        return SequenceExpression;
    
      })(Expression);
    
      JavaScriptVisitor.prototype.SequenceExpression = function(node) {
        node = this.Expression(node);
        node.expressions = this.visit(node.expressions);
        return node;
      };
    
    
      /*
       * A unary operator expression.
       */
    
      exports.UnaryExpression = UnaryExpression = (function(superClass) {
        extend(UnaryExpression, superClass);
    
    
        /*
         * @operator: "-" | "+" | "!" | "~" | "typeof" | "void" | "delete"
         * @prefix: boolean
         * @argument: Expression
         */
    
        function UnaryExpression(operator, prefix, argument) {
          this.operator = operator;
          this.prefix = prefix;
          this.argument = argument;
          UnaryExpression.__super__.constructor.call(this);
        }
    
        return UnaryExpression;
    
      })(Expression);
    
      JavaScriptVisitor.prototype.UnaryExpression = function(node) {
        node = this.Expression(node);
        node.argument = this.visit(node.argument);
        return node;
      };
    
    
      /*
       * A binary operator expression.
       */
    
      exports.BinaryExpression = BinaryExpression = (function(superClass) {
        extend(BinaryExpression, superClass);
    
    
        /*
         * @operator: "==" | "!=" | "===" | "!==" | "<" | "<=" | ">" | ">="
         *     | "<<" | ">>" | ">>>" | "+" | "-" | "*" | "/" | "%"
         *     | "|" | "&" | "^" | "in" | "instanceof" | ".."
         * @left: Expression
         * @right: Expression
         */
    
        function BinaryExpression(operator, left, right) {
          this.operator = operator;
          this.left = left;
          this.right = right;
          BinaryExpression.__super__.constructor.call(this);
        }
    
        return BinaryExpression;
    
      })(Expression);
    
      JavaScriptVisitor.prototype.BinaryExpression = function(node) {
        node = this.Expression(node);
        node.left = this.visit(node.left);
        node.right = this.visit(node.right);
        return node;
      };
    
    
      /*
       * An assignment operator expression.
       */
    
      exports.AssignmentExpression = AssignmentExpression = (function(superClass) {
        extend(AssignmentExpression, superClass);
    
    
        /*
         * @operator: "=" | "+=" | "-=" | "*=" | "/=" | "%="
         *     | "<<=" | ">>=" | ">>>=" | "|=" | "^=" | "&=";
         * @left: Expression
         * @right: Expression
         */
    
        function AssignmentExpression(operator, left, right) {
          this.operator = operator;
          this.left = left;
          this.right = right;
          AssignmentExpression.__super__.constructor.call(this);
        }
    
        return AssignmentExpression;
    
      })(Expression);
    
      JavaScriptVisitor.prototype.AssignmentExpression = function(node) {
        node = this.Expression(node);
        node.left = this.visit(node.left);
        node.right = this.visit(node.right);
        return node;
      };
    
    
      /*
       * An update (increment or decrement) operator expression.
       */
    
      exports.UpdateExpression = UpdateExpression = (function(superClass) {
        extend(UpdateExpression, superClass);
    
    
        /*
         * @operator: "++" | "--"
         * @argument: Expression
         * @prefix: boolean
         */
    
        function UpdateExpression(operator, argument, prefix) {
          this.operator = operator;
          this.argument = argument;
          this.prefix = prefix;
          UpdateExpression.__super__.constructor.call(this);
        }
    
        return UpdateExpression;
    
      })(Expression);
    
      JavaScriptVisitor.prototype.UpdateExpression = function(node) {
        node = this.Expression(node);
        node.argument = this.visit(node.argument);
        return node;
      };
    
    
      /*
       * A logical operator expression.
       */
    
      exports.LogicalExpression = LogicalExpression = (function(superClass) {
        extend(LogicalExpression, superClass);
    
    
        /*
         * @operator: "||" | "&&"
         * @left: Expression
         * @right: Expression
         */
    
        function LogicalExpression(operator, left, right) {
          this.operator = operator;
          this.left = left;
          this.right = right;
          LogicalExpression.__super__.constructor.call(this);
        }
    
        return LogicalExpression;
    
      })(Expression);
    
      JavaScriptVisitor.prototype.LogicalExpression = function(node) {
        node = this.Expression(node);
        node.left = this.visit(node.left);
        node.right = this.visit(node.right);
        return node;
      };
    
    
      /*
       * A conditional expression, i.e., a ternary ?/: expression.
       */
    
      exports.ConditionalExpression = ConditionalExpression = (function(superClass) {
        extend(ConditionalExpression, superClass);
    
    
        /*
         * @test: Expression
         * @alternate: Expression
         * @consequent: Expression
         */
    
        function ConditionalExpression(test, alternate, consequent) {
          this.test = test;
          this.alternate = alternate;
          this.consequent = consequent;
          ConditionalExpression.__super__.constructor.call(this);
        }
    
        return ConditionalExpression;
    
      })(Expression);
    
      JavaScriptVisitor.prototype.ConditionalExpression = function(node) {
        node = this.Expression(node);
        node.test = this.visit(node.test);
        node.alternate = this.visit(node.alternate);
        node.consequent = this.visit(node.consequent);
        return node;
      };
    
    
      /*
       * A new expression.
       */
    
      exports.NewExpression = NewExpression = (function(superClass) {
        extend(NewExpression, superClass);
    
    
        /*
         * @callee: Expression
         * @arguments: [ Expression ] | null
         */
    
        function NewExpression(callee, _arguments) {
          this.callee = callee;
          this["arguments"] = _arguments;
          NewExpression.__super__.constructor.call(this);
        }
    
        return NewExpression;
    
      })(Expression);
    
      JavaScriptVisitor.prototype.NewExpression = function(node) {
        node = this.Expression(node);
        node.callee = this.visit(node.callee);
        node["arguments"] = this.visit(node["arguments"]);
        return node;
      };
    
    
      /*
       * A function or method call expression.
       */
    
      exports.CallExpression = CallExpression = (function(superClass) {
        extend(CallExpression, superClass);
    
    
        /*
         * @callee: Expression
         * @arguments: [ Expression ]
         */
    
        function CallExpression(callee, _arguments) {
          this.callee = callee;
          this["arguments"] = _arguments;
          CallExpression.__super__.constructor.call(this);
        }
    
        return CallExpression;
    
      })(Expression);
    
      JavaScriptVisitor.prototype.CallExpression = function(node) {
        node = this.Expression(node);
        node.callee = this.visit(node.callee);
        node["arguments"] = this.visit(node["arguments"]);
        return node;
      };
    
    
      /*
       * A member expression. If computed === true, the node corresponds to a computed
       * e1[e2] expression and property is an Expression. If computed === false, the
       * node corresponds to a static e1.x expression and property is an Identifier.
       */
    
      exports.MemberExpression = MemberExpression = (function(superClass) {
        extend(MemberExpression, superClass);
    
    
        /*
         * @object: Expression
         * @property: Identifier | Expression
         * @computed : boolean
         */
    
        function MemberExpression(object, property, computed) {
          this.object = object;
          this.property = property;
          this.computed = computed;
          MemberExpression.__super__.constructor.call(this);
        }
    
        return MemberExpression;
    
      })(Expression);
    
      JavaScriptVisitor.prototype.MemberExpression = function(node) {
        node = this.Expression(node);
        node.object = this.visit(node.object);
        node.property = this.visit(node.property);
        return node;
      };
    
    
      /*
       * JavaScript 1.7 introduced destructuring assignment and binding forms.  All
       * binding forms (such as function parameters, variable declarations, and catch
       * block headers), accept array and object destructuring patterns in addition to
       * plain identifiers. The left-hand sides of assignment expressions can be
       * arbitrary expressions, but in the case where the expression is an object or
       * array literal, it is interpreted by SpiderMonkey as a destructuring pattern.
       *
       * Since the left-hand side of an assignment can in general be any expression, in
       * an assignment context, a pattern can be any expression. In binding positions
       * (such as function parameters, variable declarations, and catch headers),
       * patterns can only be identifiers in the base case, not arbitrary expressions.
       */
    
      exports.Pattern = Pattern = (function(superClass) {
        extend(Pattern, superClass);
    
        function Pattern() {
          Pattern.__super__.constructor.call(this);
        }
    
        return Pattern;
    
      })(JavaScriptNode);
    
      JavaScriptVisitor.prototype.Pattern = function(node) {
        node = this.JavaScriptNode(node);
        return node;
      };
    
    
      /*
       * An object-destructuring pattern. A literal property in an object pattern can
       * have either a string or number as its value.
       */
    
      exports.ObjectPattern = ObjectPattern = (function(superClass) {
        extend(ObjectPattern, superClass);
    
    
        /*
         * @properties: [ { key: Literal | Identifier, value: Pattern } ]
         */
    
        function ObjectPattern(properties) {
          this.properties = properties;
          ObjectPattern.__super__.constructor.call(this);
        }
    
        return ObjectPattern;
    
      })(Pattern);
    
      JavaScriptVisitor.prototype.ObjectPattern = function(node) {
        var i, len, ref1, setter;
        node = this.Pattern(node);
        ref1 = node.properties;
        for (i = 0, len = ref1.length; i < len; i++) {
          setter = ref1[i];
          setter.key = this.visit(setter.key);
          setter.value = this.visit(setter.value);
        }
        return node;
      };
    
    
      /*
       * An array-destructuring pattern.
       */
    
      exports.ArrayPattern = ArrayPattern = (function(superClass) {
        extend(ArrayPattern, superClass);
    
    
        /*
         * @elements: [ Pattern | null ]
         */
    
        function ArrayPattern(elements) {
          this.elements = elements;
          ArrayPattern.__super__.constructor.call(this);
        }
    
        return ArrayPattern;
    
      })(Pattern);
    
      JavaScriptVisitor.prototype.ArrayPattern = function(node) {
        node = this.Pattern(node);
        node.elements = this.visit(node.elements);
        return node;
      };
    
    
      /*
       * A case (if test is an Expression) or default (if test === null) clause in the
       * body of a switch statement.
       */
    
      exports.SwitchCase = SwitchCase = (function(superClass) {
        extend(SwitchCase, superClass);
    
    
        /*
         * @test: Expression | null
         * @consequent: [ Statement ]
         */
    
        function SwitchCase(test, consequent) {
          this.test = test;
          this.consequent = consequent;
          SwitchCase.__super__.constructor.call(this);
        }
    
        return SwitchCase;
    
      })(JavaScriptNode);
    
      JavaScriptVisitor.prototype.SwitchCase = function(node) {
        node = this.JavaScriptNode(node);
        node.test = this.visit(node.test);
        node.consequent = this.visit(node.consequent);
        return node;
      };
    
    
      /*
       * A catch clause following a try block. The optional guard property corresponds
       * to the optional expression guard on the bound variable.
       */
    
      exports.CatchClause = CatchClause = (function(superClass) {
        extend(CatchClause, superClass);
    
    
        /*
         * @param: Pattern
         * @body: BlockStatement
         */
    
        function CatchClause(param, body) {
          this.param = param;
          this.body = body;
          CatchClause.__super__.constructor.call(this);
        }
    
        return CatchClause;
    
      })(JavaScriptNode);
    
      JavaScriptVisitor.prototype.CatchClause = function(node) {
        node = this.JavaScriptNode(node);
        node.param = this.visit(node.param);
        node.body = this.visit(node.body);
        return node;
      };
    
    
      /*
       * An identifier. Note that an identifier may be an expression or a destructuring
       * pattern.
       */
    
      exports.Identifier = Identifier = (function(superClass) {
        extend(Identifier, superClass);
    
    
        /*
         * @name: string
         */
    
        function Identifier(name) {
          this.name = name;
          Identifier.__super__.constructor.call(this);
        }
    
        return Identifier;
    
      })(JavaScriptNode);
    
      JavaScriptVisitor.prototype.Identifier = function(node) {
        node = this.JavaScriptNode(node);
        return node;
      };
    
    
      /*
       * A literal token. Note that a literal can be an expression.
       */
    
      exports.Literal = Literal = (function(superClass) {
        extend(Literal, superClass);
    
    
        /*
         * @value: string | boolean | null | number | RegExp
         */
    
        function Literal(value) {
          this.value = value;
          Literal.__super__.constructor.call(this);
        }
    
        return Literal;
    
      })(Expression);
    
      JavaScriptVisitor.prototype.Literal = function(node) {
        node = this.Expression(node);
        return node;
      };
    
    }).call(this);
    
    },{"./Node":271}],270:[function(require,module,exports){
    // Generated by CoffeeScript 1.10.0
    
    /*
     * ----------------------------------------------------------------------------
     * Copyright (c) Microsoft Corporation. All rights reserved.
     * ----------------------------------------------------------------------------
     */
    
    (function() {
      var JS, JavaScriptToQueryVisitor, Q, _,
        extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
        hasProp = {}.hasOwnProperty;
    
      _ = require('./Utilities');
    
      JS = require('./JavaScriptNodes');
    
      Q = require('./QueryNodes');
    
    
      /*
       * Walk the JavaScriptExpression tree and convert its nodes into QueryExpression
       * trees
       */
    
      exports.JavaScriptToQueryVisitor = JavaScriptToQueryVisitor = (function(superClass) {
        extend(JavaScriptToQueryVisitor, superClass);
    
        function JavaScriptToQueryVisitor(context) {
          this.context = context;
        }
    
    
        /* Get the source code for a given node */
    
        JavaScriptToQueryVisitor.prototype.getSource = function(node) {
          var ref, ref1;
          return this.context.source.slice(node != null ? (ref = node.range) != null ? ref[0] : void 0 : void 0, +((node != null ? (ref1 = node.range) != null ? ref1[1] : void 0 : void 0) - 1) + 1 || 9e9);
        };
    
    
        /* Throw an exception for an invalid node. */
    
        JavaScriptToQueryVisitor.prototype.invalid = function(node) {
          throw "The expression '" + (this.getSource(node)) + "'' is not supported.";
        };
    
    
        /* Unary expressions just map operators */
    
        JavaScriptToQueryVisitor.prototype.translateUnary = function(node, mapping) {
          var op, value;
          op = mapping[node.operator];
          if (op) {
            value = this.visit(node.argument);
            return new Q.UnaryExpression(op, value);
          } else {
            return null;
          }
        };
    
    
        /* Binary expressions just map operators */
    
        JavaScriptToQueryVisitor.prototype.translateBinary = function(node, mapping) {
          var left, op, right;
          op = mapping[node.operator];
          if (op) {
            left = this.visit(node.left);
            right = this.visit(node.right);
            return new Q.BinaryExpression(op, left, right);
          } else {
            return null;
          }
        };
    
    
        /*
         * The base visit method will throw exceptions for any nodes that remain
         * untransformed (which allows us to only bother defining meaningful
         * translations)
         */
    
        JavaScriptToQueryVisitor.prototype.visit = function(node) {
          var visited;
          visited = JavaScriptToQueryVisitor.__super__.visit.call(this, node);
          if (node === visited) {
            this.invalid(node);
          }
          return visited;
        };
    
        JavaScriptToQueryVisitor.prototype.MemberExpression = function(node) {
          var expr;
          expr = (function() {
            var ref, ref1, ref2, ref3;
            if ((node != null ? (ref = node.object) != null ? ref.type : void 0 : void 0) === 'ThisExpression' && (node != null ? (ref1 = node.property) != null ? ref1.type : void 0 : void 0) === 'Identifier') {
    
              /* Simple member access */
              return new Q.MemberExpression(node.property.name);
            } else if ((node != null ? (ref2 = node.object) != null ? ref2.type : void 0 : void 0) === 'MemberExpression' && ((ref3 = node.object.object) != null ? ref3.type : void 0) === 'ThisExpression' && node.property.type === 'Identifier') {
    
              /* Methods that look like properties */
              if (node.property.name === 'length') {
                return new Q.InvocationExpression(Q.Methods.Length, new Q.MemberExpression(node.object.property.name));
              }
            }
          })();
          return expr != null ? expr : JavaScriptToQueryVisitor.__super__.MemberExpression.call(this, node);
        };
    
        JavaScriptToQueryVisitor.prototype.Literal = function(node) {
          return new Q.ConstantExpression(node.value);
        };
    
        JavaScriptToQueryVisitor.prototype.UnaryExpression = function(node) {
          var mapping, ref;
          if (node.operator === '+') {
    
            /* Ignore the + in '+52' */
            return this.visit(node.argument);
          } else {
            mapping = {
              '!': Q.UnaryOperators.Not,
              '-': Q.UnaryOperators.Negate
            };
            return (ref = this.translateUnary(node, mapping)) != null ? ref : JavaScriptToQueryVisitor.__super__.UnaryExpression.call(this, node);
          }
        };
    
        JavaScriptToQueryVisitor.prototype.UpdateExpression = function(node) {
          var mapping, ref;
          mapping = {
            '++': Q.UnaryOperators.Increment,
            '--': Q.UnaryOperators.Decrement
          };
          return (ref = this.translateUnary(node, mapping)) != null ? ref : JavaScriptToQueryVisitor.__super__.UpdateExpression.call(this, node);
        };
    
        JavaScriptToQueryVisitor.prototype.LogicalExpression = function(node) {
          var mapping, ref;
          mapping = {
            '&&': Q.BinaryOperators.And,
            '||': Q.BinaryOperators.Or
          };
          return (ref = this.translateBinary(node, mapping)) != null ? ref : JavaScriptToQueryVisitor.__super__.LogicalExpression.call(this, node);
        };
    
        JavaScriptToQueryVisitor.prototype.BinaryExpression = function(node) {
          var k, left, mapping, properties, ref, v, value;
          mapping = {
            '+': Q.BinaryOperators.Add,
            '-': Q.BinaryOperators.Subtract,
            '*': Q.BinaryOperators.Multiply,
            '/': Q.BinaryOperators.Divide,
            '%': Q.BinaryOperators.Modulo,
            '>': Q.BinaryOperators.GreaterThan,
            '>=': Q.BinaryOperators.GreaterThanOrEqual,
            '<': Q.BinaryOperators.LessThan,
            '<=': Q.BinaryOperators.LessThanOrEqual,
            '!=': Q.BinaryOperators.NotEqual,
            '!==': Q.BinaryOperators.NotEqual,
            '==': Q.BinaryOperators.Equal,
            '===': Q.BinaryOperators.Equal
          };
          return (function() {
            var ref1, ref2;
            if ((ref = this.translateBinary(node, mapping)) != null) {
              return ref;
            } else if (node.operator === 'in' && ((ref1 = node.right) != null ? ref1.type : void 0) === 'Literal' && _.isArray((ref2 = node.right) != null ? ref2.value : void 0)) {
    
              /*
               * Transform the 'varName in [x, y, z]' operator into a series of
               * comparisons like varName == x || varName == y || varName == z.
               */
              if (node.right.value.length > 0) {
                left = this.visit(node.left);
                return Q.QueryExpression.groupClauses(Q.BinaryOperators.Or, (function() {
                  var i, len, ref3, results;
                  ref3 = node.right.value;
                  results = [];
                  for (i = 0, len = ref3.length; i < len; i++) {
                    value = ref3[i];
    
                    /*
                     * If we've got an array of objects who each have
                     * a single property, we'll use the value of that
                     * property.  Otherwise we'll throw an exception.
                     */
                    if (_.isObject(value)) {
                      properties = (function() {
                        var results1;
                        results1 = [];
                        for (k in value) {
                          v = value[k];
                          results1.push(v);
                        }
                        return results1;
                      })();
                      if ((properties != null ? properties.length : void 0) !== 1) {
                        throw "in operator requires comparison objects with a single field, not " + value + " (" + (JSON.stringify(value)) + "), for expression '" + (this.getSource(node)) + "'";
                      }
                      value = properties[0];
                    }
                    results.push(new Q.BinaryExpression(Q.BinaryOperators.Equal, left, new Q.ConstantExpression(value)));
                  }
                  return results;
                }).call(this));
              } else {
    
                /*
                 * If the array of values is empty, change the query to
                 * true == false since it can't be satisfied.
                 */
                return new Q.BinaryExpression(Q.BinaryOperators.Equal, new Q.ConstantExpression(true), new Q.ConstantExpression(false));
              }
            } else {
              return JavaScriptToQueryVisitor.__super__.BinaryExpression.call(this, node);
            }
          }).call(this);
        };
    
        JavaScriptToQueryVisitor.prototype.CallExpression = function(node) {
          var expr, func, getSingleArg, getTwoArgs, member, method, ref;
          getSingleArg = (function(_this) {
            return function(name) {
              var ref;
              if (((ref = node["arguments"]) != null ? ref.length : void 0) !== 1) {
                throw "Function " + name + " expects one argument in expression '" + (_this.getSource(node)) + "'";
              }
              return _this.visit(node["arguments"][0]);
            };
          })(this);
          getTwoArgs = (function(_this) {
            return function(member, name) {
              var ref;
              if (((ref = node["arguments"]) != null ? ref.length : void 0) !== 2) {
                throw "Function " + name + " expects two arguments in expression '" + (_this.getSource(node)) + "'";
              }
              return [member, _this.visit(node["arguments"][0]), _this.visit(node["arguments"][1])];
            };
          })(this);
    
          /*
           * Translate known method calls that aren't attached to an instance.
           * Note that we can compare against the actual method because the
           * partial evaluator will have converted it into a literal for us.
           */
          func = node != null ? (ref = node.callee) != null ? ref.value : void 0 : void 0;
          expr = (function() {
            var ref1, ref2, ref3, ref4, ref5, ref6, ref7;
            if (func === Math.floor) {
              return new Q.InvocationExpression(Q.Methods.Floor, [getSingleArg('floor')]);
            } else if (func === Math.ceil) {
              return new Q.InvocationExpression(Q.Methods.Ceiling, [getSingleArg('ceil')]);
            } else if (func === Math.round) {
              return new Q.InvocationExpression(Q.Methods.Round, [getSingleArg('round')]);
            } else {
    
              /*
               * Translate methods dangling off an instance
               */
              if (node.callee.type === 'MemberExpression' && ((ref1 = node.callee.object) != null ? ref1.__hasThisExp : void 0) === true) {
                if ((node != null ? (ref2 = node.callee) != null ? (ref3 = ref2.object) != null ? ref3.type : void 0 : void 0 : void 0) === 'CallExpression') {
                  member = this.visit(node.callee.object);
                } else {
                  member = new Q.MemberExpression((ref4 = node.callee.object) != null ? (ref5 = ref4.property) != null ? ref5.name : void 0 : void 0);
                }
                method = (ref6 = node.callee) != null ? (ref7 = ref6.property) != null ? ref7.name : void 0 : void 0;
                if (method === 'toUpperCase') {
                  return new Q.InvocationExpression(Q.Methods.ToUpperCase, [member]);
                } else if (method === 'toLowerCase') {
                  return new Q.InvocationExpression(Q.Methods.ToLowerCase, [member]);
                } else if (method === 'trim') {
                  return new Q.InvocationExpression(Q.Methods.Trim, [member]);
                } else if (method === 'indexOf') {
                  return new Q.InvocationExpression(Q.Methods.IndexOf, [member, getSingleArg('indexOf')]);
                } else if (method === 'concat') {
                  return new Q.InvocationExpression(Q.Methods.Concat, [member, getSingleArg('concat')]);
                } else if (method === 'substring' || method === 'substr') {
                  return new Q.InvocationExpression(Q.Methods.Substring, getTwoArgs(member, 'substring'));
                } else if (method === 'replace') {
                  return new Q.InvocationExpression(Q.Methods.Replace, getTwoArgs(member, 'replace'));
                } else if (method === 'getFullYear' || method === 'getUTCFullYear') {
                  return new Q.InvocationExpression(Q.Methods.Year, [member]);
                } else if (method === 'getYear') {
                  return new Q.BinaryExpression(Q.BinaryOperators.Subtract, new Q.InvocationExpression(Q.Methods.Year, [member]), new Q.ConstantExpression(1900));
                } else if (method === 'getMonth' || method === 'getUTCMonth') {
    
                  /* getMonth is 0 indexed in JavaScript */
                  return new Q.BinaryExpression(Q.BinaryOperators.Subtract, new Q.InvocationExpression(Q.Methods.Month, [member]), new Q.ConstantExpression(1));
                } else if (method === 'getDate' || method === 'getUTCDate') {
                  return new Q.InvocationExpression(Q.Methods.Day, [member]);
                }
              }
            }
          }).call(this);
          return expr != null ? expr : JavaScriptToQueryVisitor.__super__.CallExpression.call(this, node);
        };
    
        return JavaScriptToQueryVisitor;
    
      })(JS.JavaScriptVisitor);
    
    }).call(this);
    
    },{"./JavaScriptNodes":269,"./QueryNodes":275,"./Utilities":276}],271:[function(require,module,exports){
    // Generated by CoffeeScript 1.10.0
    
    /*
     * ----------------------------------------------------------------------------
     * Copyright (c) Microsoft Corporation. All rights reserved.
     * ----------------------------------------------------------------------------
     */
    
    (function() {
      var Node, Visitor, _;
    
      _ = require('./Utilities');
    
    
      /*
       * The base Node class for all expressions used for analysis and translation by
       * visitors.  It's designed to interop with other modules that create expression
       * trees using object literals with a type tag.
       */
    
      exports.Node = Node = (function() {
    
        /*
         * Type tag of the node that allows for eash dispatch in visitors.  This is
         * automatically set in the constructor (so it's important to call super() in
         * derived Node classes).
         */
        Node.prototype.type = 'Node';
    
    
        /*
         * Initializes a new instance of the Node class and sets its type tag.
         */
    
        function Node() {
          this.type = _.functionName(this.constructor);
        }
    
        return Node;
    
      })();
    
    
      /*
       * Base class for all visitors
       */
    
      exports.Visitor = Visitor = (function() {
        function Visitor() {}
    
    
        /*
         * Visit a node.
         */
    
        Visitor.prototype.visit = function(node) {
          var element, i, len, results;
          if (_.isArray(node)) {
            results = [];
            for (i = 0, len = node.length; i < len; i++) {
              element = node[i];
              results.push(this.visit(element));
            }
            return results;
          } else if (!(node != null ? node.type : void 0)) {
            return node;
          } else if (!_.isFunction(this[node.type])) {
            throw "Unsupported expression " + (this.getSource(node));
          } else {
            return this[node.type](node);
          }
        };
    
    
        /*
         * Get the source code corresponding to a node.
         */
    
        Visitor.prototype.getSource = function(node) {
    
          /* It is expected this will be overridden in derived visitors. */
          return null;
        };
    
        return Visitor;
    
      })();
    
    }).call(this);
    
    },{"./Utilities":276}],272:[function(require,module,exports){
    // Generated by CoffeeScript 1.10.0
    
    /*
     * ----------------------------------------------------------------------------
     * Copyright (c) Microsoft Corporation. All rights reserved.
     * ----------------------------------------------------------------------------
     */
    
    (function() {
      var ODataFilterQueryVisitor, ODataProvider, Q, Query, _,
        extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
        hasProp = {}.hasOwnProperty;
    
      _ = require('./Utilities');
    
      Q = require('./QueryNodes');
    
      Query = require('./Query').Query;
    
      exports.ODataProvider = ODataProvider = (function() {
        function ODataProvider() {}
    
    
        /*
         * Convert a query into an OData URI.
         */
    
        ODataProvider.prototype.toQuery = function(query) {
          var odata, s, url;
          odata = this.toOData(query, true);
          url = "/" + odata.table;
          s = '?';
          if (odata.filters) {
            url += s + "$filter=" + odata.filters;
            s = '&';
          }
          if (odata.orderClauses) {
            url += s + "$orderby=" + odata.orderClauses;
            s = '&';
          }
          if (odata.skip) {
            url += s + "$skip=" + odata.skip;
            s = '&';
          }
          if (odata.take || odata.take === 0) {
            url += s + "$top=" + odata.take;
            s = '&';
          }
          if (odata.selections) {
            url += s + "$select=" + odata.selections;
            s = '&';
          }
          if (odata.includeTotalCount) {
            url += s + "$inlinecount=allpages";
          }
          if (odata.includeDeleted) {
            url += s + "__includeDeleted=true";
          }
          return url;
        };
    
    
        /*
         * Translate the query components into OData strings
         */
    
        ODataProvider.prototype.toOData = function(query, encodeForUri) {
          var asc, components, name, odata, order, orderClauses, ordering, ref, ref1;
          if (encodeForUri == null) {
            encodeForUri = false;
          }
          components = (ref = query != null ? query.getComponents() : void 0) != null ? ref : {};
          ordering = (function() {
            var ref1, results;
            ref1 = components != null ? components.ordering : void 0;
            results = [];
            for (name in ref1) {
              asc = ref1[name];
              results.push(asc ? name : name + " desc");
            }
            return results;
          })();
          orderClauses = (function() {
            var i, len, ref1, results;
            ref1 = components != null ? components.orderClauses : void 0;
            results = [];
            for (i = 0, len = ref1.length; i < len; i++) {
              order = ref1[i];
              results.push(order.ascending ? order.name : order.name + " desc");
            }
            return results;
          })();
          return odata = {
            table: components != null ? components.table : void 0,
            filters: ODataFilterQueryVisitor.convert(components.filters, encodeForUri),
            ordering: ordering != null ? ordering.toString() : void 0,
            orderClauses: orderClauses != null ? orderClauses.toString() : void 0,
            skip: components != null ? components.skip : void 0,
            take: components != null ? components.take : void 0,
            selections: components != null ? (ref1 = components.selections) != null ? ref1.toString() : void 0 : void 0,
            includeTotalCount: components != null ? components.includeTotalCount : void 0,
            includeDeleted: components != null ? components.includeDeleted : void 0
          };
        };
    
    
        /*
         * Convert OData components into a query object
         */
    
        ODataProvider.prototype.fromOData = function(table, filters, ordering, skip, take, selections, includeTotalCount, includeDeleted) {
          var direction, field, i, item, j, len, len1, query, ref, ref1, ref2, ref3;
          query = new Query(table);
          if (filters) {
            query.where(filters);
          }
          if (skip || skip === 0) {
            query.skip(skip);
          }
          if (take || take === 0) {
            query.take(take);
          }
          if (includeTotalCount) {
            query.includeTotalCount();
          }
          if (includeDeleted) {
            query.includeDeleted();
          }
          ref1 = (ref = selections != null ? selections.split(',') : void 0) != null ? ref : [];
          for (i = 0, len = ref1.length; i < len; i++) {
            field = ref1[i];
            query.select(field.trim());
          }
          ref2 = (function() {
            var k, len1, ref2, ref3, results;
            ref3 = (ref2 = ordering != null ? ordering.split(',') : void 0) != null ? ref2 : [];
            results = [];
            for (k = 0, len1 = ref3.length; k < len1; k++) {
              item = ref3[k];
              results.push(item.trim().split(' '));
            }
            return results;
          })();
          for (j = 0, len1 = ref2.length; j < len1; j++) {
            ref3 = ref2[j], field = ref3[0], direction = ref3[1];
            if ((direction != null ? direction.toUpperCase() : void 0) !== 'DESC') {
              query.orderBy(field);
            } else {
              query.orderByDescending(field);
            }
          }
          return query;
        };
    
        return ODataProvider;
    
      })();
    
    
      /*
       * Visitor that converts query expression trees into OData filter statements.
       */
    
      ODataFilterQueryVisitor = (function(superClass) {
        extend(ODataFilterQueryVisitor, superClass);
    
        function ODataFilterQueryVisitor(encodeForUri1) {
          this.encodeForUri = encodeForUri1;
        }
    
        ODataFilterQueryVisitor.convert = function(filters, encodeForUri) {
          var ref, visitor;
          visitor = new ODataFilterQueryVisitor(encodeForUri);
          return (ref = (filters ? visitor.visit(filters) : void 0)) != null ? ref : null;
        };
    
        ODataFilterQueryVisitor.prototype.toOData = function(value) {
          var text;
          if ((_.isNumber(value)) || (_.isBoolean(value))) {
            return value.toString();
          } else if (_.isString(value)) {
            value = value.replace(/'/g, "''");
            if ((this.encodeForUri != null) && this.encodeForUri === true) {
              value = encodeURIComponent(value);
            }
            return "'" + value + "'";
          } else if (_.isDate(value)) {
    
            /*
             * Dates are expected in the format
             *   "datetime'yyyy-mm-ddThh:mm[:ss[.fffffff]]'"
             * which JSON.stringify gives us by default
             */
            text = JSON.stringify(value);
            if (text.length > 2) {
              text = text.slice(1, +(text.length - 2) + 1 || 9e9);
            }
            text = text.replace(/(T\d{2}:\d{2}:\d{2})Z$/, function(all, time) {
              var msec;
              msec = String(value.getMilliseconds() + 1000).substring(1);
              return time + "." + msec + "Z";
            });
            return "datetime'" + text + "'";
          } else if (!value) {
            return "null";
          } else {
            throw "Unsupported literal value " + value;
          }
        };
    
        ODataFilterQueryVisitor.prototype.ConstantExpression = function(node) {
          return this.toOData(node.value);
        };
    
        ODataFilterQueryVisitor.prototype.MemberExpression = function(node) {
          return node.member;
        };
    
        ODataFilterQueryVisitor.prototype.UnaryExpression = function(node) {
          if (node.operator === Q.UnaryOperators.Not) {
            return "not " + (this.visit(node.operand));
          } else if (node.operator === Q.UnaryOperators.Negate) {
            return "(0 sub " + (this.visit(node.operand)) + ")";
          } else {
            throw "Unsupported operator " + node.operator;
          }
        };
    
        ODataFilterQueryVisitor.prototype.BinaryExpression = function(node) {
          var mapping, op;
          mapping = {
            And: 'and',
            Or: 'or',
            Add: 'add',
            Subtract: 'sub',
            Multiply: 'mul',
            Divide: 'div',
            Modulo: 'mod',
            GreaterThan: 'gt',
            GreaterThanOrEqual: 'ge',
            LessThan: 'lt',
            LessThanOrEqual: 'le',
            NotEqual: 'ne',
            Equal: 'eq'
          };
          op = mapping[node.operator];
          if (op) {
            return "(" + (this.visit(node.left)) + " " + op + " " + (this.visit(node.right)) + ")";
          } else {
            throw "Unsupported operator " + node.operator;
          }
        };
    
        ODataFilterQueryVisitor.prototype.InvocationExpression = function(node) {
          var mapping, method;
          mapping = {
            Length: 'length',
            ToUpperCase: 'toupper',
            ToLowerCase: 'tolower',
            Trim: 'trim',
            IndexOf: 'indexof',
            Replace: 'replace',
            Substring: 'substring',
            Concat: 'concat',
            Day: 'day',
            Month: 'month',
            Year: 'year',
            Floor: 'floor',
            Ceiling: 'ceiling',
            Round: 'round'
          };
          method = mapping[node.method];
          if (method) {
            return method + "(" + (this.visit(node.args)) + ")";
          } else {
            throw "Invocation of unsupported method " + node.method;
          }
        };
    
        ODataFilterQueryVisitor.prototype.LiteralExpression = function(node) {
          var ch, i, inString, len, literal, parenBalance, ref;
          literal = '';
          parenBalance = 0;
          inString = false;
          ref = node.queryString;
          for (i = 0, len = ref.length; i < len; i++) {
            ch = ref[i];
            if (parenBalance < 0) {
              break;
            } else if (inString) {
              literal += ch;
              inString = ch !== "'";
            } else if (ch === '?') {
              if ((!node.args) || (node.args.length <= 0)) {
                throw "Too few arguments for " + node.queryString + ".";
              }
              literal += this.toOData(node.args.shift());
            } else if (ch === "'") {
              literal += ch;
              inString = true;
            } else if (ch === '(') {
              parenBalance += 1;
              literal += ch;
            } else if (ch === ')') {
              parenBalance -= 1;
              literal += ch;
            } else {
              literal += ch;
            }
          }
          if (node.args && node.args.length > 0) {
            throw "Too many arguments for " + node.queryString;
          }
          if (parenBalance !== 0) {
            throw "Unbalanced parentheses in " + node.queryString;
          }
          if (literal.trim().length > 0) {
            return "(" + literal + ")";
          } else {
            return literal;
          }
        };
    
        return ODataFilterQueryVisitor;
    
      })(Q.QueryExpressionVisitor);
    
    }).call(this);
    
    },{"./Query":274,"./QueryNodes":275,"./Utilities":276}],273:[function(require,module,exports){
    // Generated by CoffeeScript 1.10.0
    
    /*
     * ----------------------------------------------------------------------------
     * Copyright (c) Microsoft Corporation. All rights reserved.
     * ----------------------------------------------------------------------------
     */
    
    (function() {
      var IndependenceNominator, JS, PartialEvaluator, _,
        extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
        hasProp = {}.hasOwnProperty;
    
      _ = require('./Utilities');
    
      JS = require('./JavaScriptNodes');
    
    
      /*
       * Partially evaluate a complex expression in the context of its environment.
       * This allows us to support arbitrary JavaScript expressions even though we
       * only explicitly transform a subset of expressions into QueryExpressions.
       *
       * For example, assuming we have an expression like (x) -> @id == x + 1 with an
       * environment where x == 12, then the entire right hand side of the comparison
       * is independent of any values computed by the query and could be replaced with
       * the literal value 13.
       */
    
      exports.PartialEvaluator = PartialEvaluator = (function(superClass) {
        extend(PartialEvaluator, superClass);
    
        function PartialEvaluator(context1) {
          this.context = context1;
        }
    
        PartialEvaluator.prototype.visit = function(node) {
          var key, params, ref, ref1, ref2, ref3, source, thunk, value, values;
          if (!node.__independent || node.type === 'Literal' || (!node.type)) {
    
            /*
             * If the node isn't independent or it's already a literal, then
             * just keep walking the tree
             */
            return PartialEvaluator.__super__.visit.call(this, node);
          } else {
    
            /*
             * Otherwse we'll evaluate the node in the context of the
             * environment by either looking up identifiers directly or
             * evaluating whole sub expressions
             */
            if (node.type === 'Identifier' && this.context.environment[node.name]) {
              return new JS.Literal(this.context.environment[node.name]);
            } else {
    
              /*
               * Evaluate the source of the sub expression in the context
               * of the environment
               */
              source = this.context.source.slice(node != null ? (ref = node.range) != null ? ref[0] : void 0 : void 0, +((node != null ? (ref1 = node.range) != null ? ref1[1] : void 0 : void 0) - 1) + 1 || 9e9);
              params = (ref2 = (function() {
                var ref3, results;
                ref3 = this.context.environment;
                results = [];
                for (key in ref3) {
                  value = ref3[key];
                  results.push(key);
                }
                return results;
              }).call(this)) != null ? ref2 : [];
              values = (ref3 = (function() {
                var ref4, results;
                ref4 = this.context.environment;
                results = [];
                for (key in ref4) {
                  value = ref4[key];
                  results.push(JSON.stringify(value));
                }
                return results;
              }).call(this)) != null ? ref3 : [];
              thunk = "(function(" + params + ") { return " + source + "; })(" + values + ")";
              value = eval(thunk);
              return new JS.Literal(value);
            }
          }
        };
    
        PartialEvaluator.evaluate = function(context) {
          var evaluator, nominator;
          nominator = new IndependenceNominator(context);
          nominator.visit(context.expression);
          evaluator = new PartialEvaluator(context);
          return evaluator.visit(context.expression);
        };
    
        return PartialEvaluator;
    
      })(JS.JavaScriptVisitor);
    
    
      /*
       * Nominate independent nodes in an expression tree that don't depend on any
       * server side values.
       */
    
      exports.IndependenceNominator = IndependenceNominator = (function(superClass) {
        extend(IndependenceNominator, superClass);
    
        function IndependenceNominator(context1) {
          this.context = context1;
        }
    
        IndependenceNominator.prototype.Literal = function(node) {
          IndependenceNominator.__super__.Literal.call(this, node);
          node.__independent = true;
          node.__hasThisExp = false;
          return node;
        };
    
        IndependenceNominator.prototype.ThisExpression = function(node) {
          IndependenceNominator.__super__.ThisExpression.call(this, node);
          node.__independent = false;
          node.__hasThisExp = true;
          return node;
        };
    
        IndependenceNominator.prototype.Identifier = function(node) {
          IndependenceNominator.__super__.Identifier.call(this, node);
          node.__independent = true;
          node.__hasThisExp = false;
          return node;
        };
    
        IndependenceNominator.prototype.MemberExpression = function(node) {
          var ref;
          IndependenceNominator.__super__.MemberExpression.call(this, node);
    
          /*
           * Undo independence of identifiers when they're members of this.* or
           * this.member.* (the latter allows for member functions)
           */
          node.__hasThisExp = (ref = node.object) != null ? ref.__hasThisExp : void 0;
          if (node.__hasThisExp) {
            node.__independent = false;
            if (node != null) {
              node.property.__independent = false;
            }
          }
          return node;
        };
    
        IndependenceNominator.prototype.CallExpression = function(node) {
          IndependenceNominator.__super__.CallExpression.call(this, node);
          node.__hasThisExp = node.callee.__hasThisExp;
          return node;
        };
    
        IndependenceNominator.prototype.ObjectExpression = function(node) {
          var i, independence, j, len, len1, ref, ref1, setter;
          IndependenceNominator.__super__.ObjectExpression.call(this, node);
    
          /*
           * Prevent literal key identifiers from being evaluated out of
           * context
           */
          ref = node.properties;
          for (i = 0, len = ref.length; i < len; i++) {
            setter = ref[i];
            setter.key.__independent = false;
          }
    
          /*
           * An object literal is independent if all of its values are
           * independent
           */
          independence = true;
          ref1 = node.properties;
          for (j = 0, len1 = ref1.length; j < len1; j++) {
            setter = ref1[j];
            independence &= setter.value.__independent;
          }
          node.__independent = independence ? true : false;
          return node;
        };
    
        IndependenceNominator.prototype.visit = function(node) {
    
          /*
           * Call the base visit method which will both visit all of our
           * subexpressions and also call the couple of overrides above which
           * handle the base independence cases
           */
          var i, independence, isIndependent, len, name, v, value;
          IndependenceNominator.__super__.visit.call(this, node);
    
          /*
           * If the node's independence wasn't determined automatically by the
           * base cases above, then it's independence is determined by checking
           * all of its values and aggregating their independence
           */
          if (!(Object.prototype.hasOwnProperty.call(node, '__independent'))) {
            independence = true;
            isIndependent = function(node) {
              var ref;
              if (_.isObject(node)) {
                return (ref = value.__independent) != null ? ref : false;
              } else {
                return true;
              }
            };
            for (name in node) {
              value = node[name];
              if (_.isArray(value)) {
                for (i = 0, len = value.length; i < len; i++) {
                  v = value[i];
                  independence &= isIndependent(v);
                }
              } else if (_.isObject(value)) {
                independence &= isIndependent(value);
              }
            }
    
            /* &= will turn true/false into 1/0 so we'll turn it back */
            node.__independent = independence ? true : false;
          }
          return node;
        };
    
        return IndependenceNominator;
    
      })(JS.JavaScriptVisitor);
    
    }).call(this);
    
    },{"./JavaScriptNodes":269,"./Utilities":276}],274:[function(require,module,exports){
    // Generated by CoffeeScript 1.10.0
    
    /*
     * ----------------------------------------------------------------------------
     * Copyright (c) Microsoft Corporation. All rights reserved.
     * ----------------------------------------------------------------------------
     */
    
    
    /* Pull in references */
    
    (function() {
      var JavaScript, ODataProvider, Q, Query, _,
        slice = [].slice;
    
      _ = require('./Utilities');
    
      Q = require('./QueryNodes');
    
      JavaScript = require('./JavaScript').JavaScript;
    
    
      /*
       * Define a query that can be translated into a desired query language and
       * executed remotely.
       */
    
      exports.Query = Query = (function() {
        function Query(table, context) {
          var _context, _filters, _includeDeleted, _includeTotalCount, _orderClauses, _ordering, _projection, _selections, _skip, _table, _take, _version;
          if (!table || !(_.isString(table))) {
            throw 'Expected the name of a table!';
          }
    
          /* Store the table name and any extra context */
          _table = table;
          _context = context;
    
          /* Private Query component members */
          _filters = null;
          _projection = null;
          _selections = [];
          _ordering = {};
          _orderClauses = [];
          _skip = null;
          _take = null;
          _includeTotalCount = false;
          _includeDeleted = false;
    
          /*
           * Keep a version flag that's updated on each mutation so we can
           * track whether changes have been made.  This is to enable caching
           * of compiled queries without reevaluating unless necessary.
           */
          _version = 0;
    
          /* Get the individual components of the query */
          this.getComponents = function() {
            return {
              filters: _filters,
              selections: _selections,
              projection: _projection,
              ordering: _ordering,
              orderClauses: _orderClauses,
              skip: _skip,
              take: _take,
              table: _table,
              context: _context,
              includeTotalCount: _includeTotalCount,
              includeDeleted: _includeDeleted,
              version: _version
            };
          };
    
          /*
           * Set the individual components of the query (this is primarily
           * meant to be used for rehydrating a query).
           */
          this.setComponents = function(components) {
            var ascending, i, len, name, property, ref, ref1, ref10, ref11, ref2, ref3, ref4, ref5, ref6, ref7, ref8, ref9;
            _version++;
            _filters = (ref = components != null ? components.filters : void 0) != null ? ref : null;
            _selections = (ref1 = components != null ? components.selections : void 0) != null ? ref1 : [];
            _projection = (ref2 = components != null ? components.projection : void 0) != null ? ref2 : null;
            _skip = (ref3 = components != null ? components.skip : void 0) != null ? ref3 : null;
            _take = (ref4 = components != null ? components.take : void 0) != null ? ref4 : null;
            _includeTotalCount = (ref5 = components != null ? components.includeTotalCount : void 0) != null ? ref5 : false;
            _includeDeleted = (ref6 = components != null ? components.includeDeleted : void 0) != null ? ref6 : false;
            _table = (ref7 = components != null ? components.table : void 0) != null ? ref7 : null;
            _context = (ref8 = components != null ? components.context : void 0) != null ? ref8 : null;
            if (components != null ? components.orderClauses : void 0) {
              _orderClauses = (ref9 = components != null ? components.orderClauses : void 0) != null ? ref9 : [];
              _ordering = {};
              for (i = 0, len = _orderClauses.length; i < len; i++) {
                ref10 = _orderClauses[i], name = ref10.name, ascending = ref10.ascending;
                _ordering[name] = ascending;
              }
            } else {
              _ordering = (ref11 = components != null ? components.ordering : void 0) != null ? ref11 : {};
              _orderClauses = [];
              for (property in _ordering) {
                _orderClauses.push({
                  name: property,
                  ascending: !!_ordering[property]
                });
              }
            }
            return this;
          };
    
          /*
           * Add a constraint to a query.  Constraints can take the form of
           * a function with a single return statement, key/value pairs of
           * equality comparisons, or provider-specific literal strings (note
           * that not all providers support literals).
           */
          this.where = function() {
            var args, constraint, expr, name, value;
            constraint = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : [];
            _version++;
    
            /*
             * Translate the constraint from its high level form into a
             * QueryExpression tree that can be manipulated by a query
             * provider
             */
            expr = (function() {
              if (_.isFunction(constraint)) {
                return JavaScript.transformConstraint(constraint, args);
              } else if (_.isObject(constraint)) {
    
                /*
                 * Turn an object of key value pairs into a series of
                 * equality expressions that are and'ed together to form
                 * a single expression
                 */
                return Q.QueryExpression.groupClauses(Q.BinaryOperators.And, (function() {
                  var results;
                  results = [];
                  for (name in constraint) {
                    value = constraint[name];
                    results.push(expr = new Q.BinaryExpression(Q.BinaryOperators.Equal, new Q.MemberExpression(name), new Q.ConstantExpression(value)));
                  }
                  return results;
                })());
              } else if (_.isString(constraint)) {
    
                /*
                 * Store the literal query along with any arguments for
                 * providers that support basic string replacement (i.e.,
                 * something like where('name eq ?', 'Steve'))
                 */
                return new Q.LiteralExpression(constraint, args);
              } else {
                throw "Expected a function, object, or string, not " + constraint;
              }
            })();
    
            /* Merge the new filters with any existing filters */
            _filters = Q.QueryExpression.groupClauses(Q.BinaryOperators.And, [_filters, expr]);
            return this;
          };
    
          /*
           * Project the query results.  A projection can either be defined as
           * a set of fields that we'll pull back (instead of the entire row)
           * or a function that will transform a row into a new type.  If a
           * function is used, we'll analyze the function to pull back the
           * minimal number of fields required.
           */
          this.select = function() {
            var i, len, param, parameters, projectionOrParameter;
            projectionOrParameter = arguments[0], parameters = 2 <= arguments.length ? slice.call(arguments, 1) : [];
            _version++;
            if (_.isString(projectionOrParameter)) {
    
              /* Add all the literal string parameters */
              _selections.push(projectionOrParameter);
              for (i = 0, len = parameters.length; i < len; i++) {
                param = parameters[i];
                if (!(_.isString(param))) {
                  throw "Expected string parameters, not " + param;
                }
                _selections.push(param);
              }
            } else if (_.isFunction(projectionOrParameter)) {
    
              /* Set the projection and calculate the fields it uses */
              _projection = projectionOrParameter;
              _selections = JavaScript.getProjectedFields(_projection);
            } else {
              throw "Expected a string or a function, not " + projectionOrParameter;
            }
            return this;
          };
          this.orderBy = function() {
            var i, j, len, len1, order, param, parameters, replacement;
            parameters = 1 <= arguments.length ? slice.call(arguments, 0) : [];
            _version++;
            for (i = 0, len = parameters.length; i < len; i++) {
              param = parameters[i];
              if (!(_.isString(param))) {
                throw "Expected string parameters, not " + param;
              }
              _ordering[param] = true;
              replacement = false;
              for (j = 0, len1 = _orderClauses.length; j < len1; j++) {
                order = _orderClauses[j];
                if (order.name === param) {
                  replacement = true;
                  order.ascending = true;
                }
              }
              if (!replacement) {
                _orderClauses.push({
                  name: param,
                  ascending: true
                });
              }
            }
            return this;
          };
          this.orderByDescending = function() {
            var i, j, len, len1, order, param, parameters, replacement;
            parameters = 1 <= arguments.length ? slice.call(arguments, 0) : [];
            _version++;
            for (i = 0, len = parameters.length; i < len; i++) {
              param = parameters[i];
              if (!(_.isString(param))) {
                throw "Expected string parameters, not " + param;
              }
              _ordering[param] = false;
              replacement = false;
              for (j = 0, len1 = _orderClauses.length; j < len1; j++) {
                order = _orderClauses[j];
                if (order.name === param) {
                  replacement = true;
                  order.ascending = false;
                }
              }
              if (!replacement) {
                _orderClauses.push({
                  name: param,
                  ascending: false
                });
              }
            }
            return this;
          };
          this.skip = function(count) {
            _version++;
            if (!(_.isNumber(count))) {
              throw "Expected a number, not " + count;
            }
            _skip = count;
            return this;
          };
          this.take = function(count) {
            _version++;
            if (!(_.isNumber(count))) {
              throw "Expected a number, not " + count;
            }
            _take = count;
            return this;
          };
    
          /*
           * Indicate that the query should include the total count for all the
           * records that would have been returned ignoring any take paging
           * limit clause specified by client or server.
           */
          this.includeTotalCount = function() {
            _version++;
            _includeTotalCount = true;
            return this;
          };
    
          /*
           * Indicate that the query should include soft deleted records.
           */
          this.includeDeleted = function() {
            _version++;
            _includeDeleted = true;
            return this;
          };
        }
    
    
        /*
         * Static method to register custom provider types.  A custom provider is
         * an object with a toQuery method that takes a Query instance and
         * returns a compiled query for that provider.
         */
    
        Query.registerProvider = function(name, provider) {
          Query.Providers[name] = provider;
          return Query.prototype["to" + name] = function() {
            return provider != null ? typeof provider.toQuery === "function" ? provider.toQuery(this) : void 0 : void 0;
          };
        };
    
    
        /*
         * Expose the registered providers via the Query.Providers namespace.
         */
    
        Query.Providers = {};
    
    
        /*
         * Expose the query expressions and visitors externally via a
         * Query.Expressions namespace.
         */
    
        Query.Expressions = Q;
    
        return Query;
    
      })();
    
    
      /* Register the built in OData provider */
    
      ODataProvider = require('./ODataProvider').ODataProvider;
    
      Query.registerProvider('OData', new ODataProvider);
    
    }).call(this);
    
    },{"./JavaScript":268,"./ODataProvider":272,"./QueryNodes":275,"./Utilities":276}],275:[function(require,module,exports){
    // Generated by CoffeeScript 1.10.0
    
    /*
     * ----------------------------------------------------------------------------
     * Copyright (c) Microsoft Corporation. All rights reserved.
     * ----------------------------------------------------------------------------
     */
    
    
    /*
     * Define a low level intermediate query expression language that we can
     * translate other expressions languages (like JavaScript) into.
     */
    
    
    /* Get the base Node class. */
    
    (function() {
      var BinaryExpression, ConstantExpression, InvocationExpression, LiteralExpression, MemberExpression, Node, QueryExpression, QueryExpressionVisitor, UnaryExpression, Visitor, ref,
        extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
        hasProp = {}.hasOwnProperty;
    
      ref = require('./Node'), Node = ref.Node, Visitor = ref.Visitor;
    
    
      /*
       * Provides the base class from which the classes that represent expression tree
       * nodes are derived.
       */
    
      exports.QueryExpression = QueryExpression = (function(superClass) {
        extend(QueryExpression, superClass);
    
        function QueryExpression() {
          QueryExpression.__super__.constructor.call(this);
        }
    
    
        /*
         * Group a sequence of clauses together with a given operator (like And
         * or Or).
         */
    
        QueryExpression.groupClauses = function(operator, clauses) {
          var combine;
          combine = function(left, right) {
            if (!left) {
              return right;
            } else if (!right) {
              return left;
            } else {
              return new BinaryExpression(operator, left, right);
            }
          };
          return clauses.reduce(combine, null);
        };
    
        return QueryExpression;
    
      })(Node);
    
      exports.QueryExpressionVisitor = QueryExpressionVisitor = (function(superClass) {
        extend(QueryExpressionVisitor, superClass);
    
        function QueryExpressionVisitor() {
          QueryExpressionVisitor.__super__.constructor.call(this);
        }
    
        QueryExpressionVisitor.prototype.QueryExpression = function(node) {
          return node;
        };
    
        return QueryExpressionVisitor;
    
      })(Visitor);
    
    
      /*
       * Represents an expression that has a constant value.
       */
    
      exports.ConstantExpression = ConstantExpression = (function(superClass) {
        extend(ConstantExpression, superClass);
    
    
        /*
         * @value: The value of the constant expression.
         */
    
        function ConstantExpression(value) {
          this.value = value;
          ConstantExpression.__super__.constructor.call(this);
        }
    
        return ConstantExpression;
    
      })(QueryExpression);
    
      QueryExpressionVisitor.prototype.ConstantExpression = function(node) {
        return this.QueryExpression(node);
      };
    
    
      /*
       * Represents accessing a field.
       */
    
      exports.MemberExpression = MemberExpression = (function(superClass) {
        extend(MemberExpression, superClass);
    
    
        /*
         * @member: Gets the field to be accessed.
         */
    
        function MemberExpression(member) {
          this.member = member;
          MemberExpression.__super__.constructor.call(this);
        }
    
        return MemberExpression;
    
      })(QueryExpression);
    
      QueryExpressionVisitor.prototype.MemberExpression = function(node) {
        return this.QueryExpression(node);
      };
    
    
      /*
       * Represents an expression that has a binary operator.
       */
    
      exports.BinaryExpression = BinaryExpression = (function(superClass) {
        extend(BinaryExpression, superClass);
    
    
        /*
         * @operator: The operator of the binary expression.
         * @left: The left operand of the binary operation.
         * @right: The right operand of the binary operation.
         */
    
        function BinaryExpression(operator1, left1, right1) {
          this.operator = operator1;
          this.left = left1;
          this.right = right1;
          BinaryExpression.__super__.constructor.call(this);
        }
    
        return BinaryExpression;
    
      })(QueryExpression);
    
      QueryExpressionVisitor.prototype.BinaryExpression = function(node) {
        node = this.QueryExpression(node);
        node.left = this.visit(node.left);
        node.right = this.visit(node.right);
        return node;
      };
    
    
      /*
       * Represents the known binary operators.
       */
    
      exports.BinaryOperators = {
        And: 'And',
        Or: 'Or',
        Add: 'Add',
        Subtract: 'Subtract',
        Multiply: 'Multiply',
        Divide: 'Divide',
        Modulo: 'Modulo',
        GreaterThan: 'GreaterThan',
        GreaterThanOrEqual: 'GreaterThanOrEqual',
        LessThan: 'LessThan',
        LessThanOrEqual: 'LessThanOrEqual',
        NotEqual: 'NotEqual',
        Equal: 'Equal'
      };
    
    
      /*
       * Represents the known unary operators.
       */
    
      exports.UnaryExpression = UnaryExpression = (function(superClass) {
        extend(UnaryExpression, superClass);
    
    
        /*
         * @operator: The operator of the unary expression.
         * @operand: The operand of the unary expression.
         */
    
        function UnaryExpression(operator1, operand) {
          this.operator = operator1;
          this.operand = operand;
          UnaryExpression.__super__.constructor.call(this);
        }
    
        return UnaryExpression;
    
      })(QueryExpression);
    
      QueryExpressionVisitor.prototype.UnaryExpression = function(node) {
        node = this.QueryExpression(node);
        node.operand = this.visit(node.operand);
        return node;
      };
    
    
      /*
       * Represents the known unary operators.
       */
    
      exports.UnaryOperators = {
        Not: 'Not',
        Negate: 'Negate',
        Increment: 'Increment',
        Decrement: 'Decrement'
      };
    
    
      /*
       * Represents a method invocation.
       */
    
      exports.InvocationExpression = InvocationExpression = (function(superClass) {
        extend(InvocationExpression, superClass);
    
    
        /*
         * @method: The name of the method to invoke.
         * @args: The arguments to the method.
         */
    
        function InvocationExpression(method, args) {
          this.method = method;
          this.args = args;
          InvocationExpression.__super__.constructor.call(this);
        }
    
        return InvocationExpression;
    
      })(QueryExpression);
    
      QueryExpressionVisitor.prototype.InvocationExpression = function(node) {
        node = this.QueryExpression(node);
        node.args = this.visit(node.args);
        return node;
      };
    
    
      /*
       * Represents the known unary operators.
       */
    
      exports.Methods = {
        Length: 'Length',
        ToUpperCase: 'ToUpperCase',
        ToLowerCase: 'ToLowerCase',
        Trim: 'Trim',
        IndexOf: 'IndexOf',
        Replace: 'Replace',
        Substring: 'Substring',
        Concat: 'Concat',
        Day: 'Day',
        Month: 'Month',
        Year: 'Year',
        Floor: 'Floor',
        Ceiling: 'Ceiling',
        Round: 'Round'
      };
    
    
      /*
       * Represents a literal string in the query language.
       */
    
      exports.LiteralExpression = LiteralExpression = (function(superClass) {
        extend(LiteralExpression, superClass);
    
    
        /*
         * @queryString
         * @args
         */
    
        function LiteralExpression(queryString, args) {
          this.queryString = queryString;
          this.args = args != null ? args : [];
          LiteralExpression.__super__.constructor.call(this);
        }
    
        return LiteralExpression;
    
      })(QueryExpression);
    
      QueryExpressionVisitor.prototype.LiteralExpression = function(node) {
        return this.QueryExpression(node);
      };
    
    }).call(this);
    
    },{"./Node":271}],276:[function(require,module,exports){
    // Generated by CoffeeScript 1.10.0
    
    /*
     * ----------------------------------------------------------------------------
     * Copyright (c) Microsoft Corporation. All rights reserved.
     * ----------------------------------------------------------------------------
     */
    
    (function() {
      var classOf,
        slice = [].slice;
    
      classOf = function(obj) {
        return Object.prototype.toString.call(obj).slice(8, -1).toLowerCase();
      };
    
      if (Array.prototype.reduce == null) {
        Array.prototype.reduce = function() {
          var accumulator, array, arrayLength, currentIndex, currentValue, moreArgs;
          accumulator = arguments[0], moreArgs = 2 <= arguments.length ? slice.call(arguments, 1) : [];
          array = this;
          arrayLength = array.length;
          currentIndex = 0;
          currentValue = void 0;
          if (array == null) {
            throw new TypeError("Object is null or undefined");
          }
          if (typeof accumulator !== "function") {
            throw new TypeError("First argument is not callable");
          }
          if (moreArgs.length === 0) {
            if (arrayLength === 0) {
              throw new TypeError("Array length is 0 and no second argument");
            } else {
              currentValue = array[0];
              currentIndex = 1;
            }
          } else {
            currentValue = moreArgs[0];
          }
          while (currentIndex < arrayLength) {
            if (currentIndex in array) {
              currentValue = accumulator.call(void 0, currentValue, array[currentIndex], array);
            }
            ++currentIndex;
          }
          return currentValue;
        };
      }
    
      if (Array.prototype.map == null) {
        Array.prototype.map = function(callback, thisArg) {
          var elem, i, index, inputArray, len, len1, outputArray;
          if (typeof this === "undefined" || this === null) {
            throw new TypeError("this is null or not defined");
          }
          if (typeof callback !== "function") {
            throw new TypeError(callback + " is not a function");
          }
          thisArg = thisArg ? thisArg : void 0;
          inputArray = Object(this);
          len = inputArray.length >>> 0;
          outputArray = new Array(len);
          for (index = i = 0, len1 = inputArray.length; i < len1; index = ++i) {
            elem = inputArray[index];
            if (index in inputArray) {
              outputArray[index] = callback.call(thisArg, elem, index, inputArray);
            }
          }
          return outputArray;
        };
      }
    
      if (Array.isArray == null) {
        Array.isArray = function(vArg) {
          return Object.prototype.toString.call(vArg) === "[object Array]";
        };
      }
    
      exports.isObject = function(obj) {
        return Object.prototype.toString.call(obj).slice(8, -1).toLowerCase() === 'object';
      };
    
      exports.isString = function(obj) {
        return typeof obj === 'string';
      };
    
      exports.isFunction = function(obj) {
        return typeof obj === 'function';
      };
    
      exports.isArray = Array.isArray;
    
      exports.isNumber = function(obj) {
        return typeof obj === 'number';
      };
    
      exports.isBoolean = function(obj) {
        return typeof obj === 'boolean';
      };
    
      exports.isDate = function(obj) {
        return classOf(obj) === 'date';
      };
    
      exports.functionName = function(fn) {
        var index, prefix, source;
        if (typeof Function.prototype.name === 'function') {
          return Function.prototype.name.call(fn);
        } else {
          source = fn.toString();
          prefix = 'function ';
          if (source.slice(0, +(prefix.length - 1) + 1 || 9e9) === prefix) {
            index = source.indexOf('(', prefix.length);
            if (index > prefix.length) {
              return source.slice(prefix.length, +(index - 1) + 1 || 9e9);
            }
          }
          return null;
        }
      };
    
    }).call(this);
    
    },{}],277:[function(require,module,exports){
    (function (Buffer){(function (){
    // Copyright Joyent, Inc. and other Node contributors.
    //
    // Permission is hereby granted, free of charge, to any person obtaining a
    // copy of this software and associated documentation files (the
    // "Software"), to deal in the Software without restriction, including
    // without limitation the rights to use, copy, modify, merge, publish,
    // distribute, sublicense, and/or sell copies of the Software, and to permit
    // persons to whom the Software is furnished to do so, subject to the
    // following conditions:
    //
    // The above copyright notice and this permission notice shall be included
    // in all copies or substantial portions of the Software.
    //
    // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
    // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
    // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
    // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
    // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
    // USE OR OTHER DEALINGS IN THE SOFTWARE.
    
    // NOTE: These type checking functions intentionally don't use `instanceof`
    // because it is fragile and can be easily faked with `Object.create()`.
    
    function isArray(arg) {
      if (Array.isArray) {
        return Array.isArray(arg);
      }
      return objectToString(arg) === '[object Array]';
    }
    exports.isArray = isArray;
    
    function isBoolean(arg) {
      return typeof arg === 'boolean';
    }
    exports.isBoolean = isBoolean;
    
    function isNull(arg) {
      return arg === null;
    }
    exports.isNull = isNull;
    
    function isNullOrUndefined(arg) {
      return arg == null;
    }
    exports.isNullOrUndefined = isNullOrUndefined;
    
    function isNumber(arg) {
      return typeof arg === 'number';
    }
    exports.isNumber = isNumber;
    
    function isString(arg) {
      return typeof arg === 'string';
    }
    exports.isString = isString;
    
    function isSymbol(arg) {
      return typeof arg === 'symbol';
    }
    exports.isSymbol = isSymbol;
    
    function isUndefined(arg) {
      return arg === void 0;
    }
    exports.isUndefined = isUndefined;
    
    function isRegExp(re) {
      return objectToString(re) === '[object RegExp]';
    }
    exports.isRegExp = isRegExp;
    
    function isObject(arg) {
      return typeof arg === 'object' && arg !== null;
    }
    exports.isObject = isObject;
    
    function isDate(d) {
      return objectToString(d) === '[object Date]';
    }
    exports.isDate = isDate;
    
    function isError(e) {
      return (objectToString(e) === '[object Error]' || e instanceof Error);
    }
    exports.isError = isError;
    
    function isFunction(arg) {
      return typeof arg === 'function';
    }
    exports.isFunction = isFunction;
    
    function isPrimitive(arg) {
      return arg === null ||
             typeof arg === 'boolean' ||
             typeof arg === 'number' ||
             typeof arg === 'string' ||
             typeof arg === 'symbol' ||  // ES6 symbol
             typeof arg === 'undefined';
    }
    exports.isPrimitive = isPrimitive;
    
    exports.isBuffer = Buffer.isBuffer;
    
    function objectToString(o) {
      return Object.prototype.toString.call(o);
    }
    
    }).call(this)}).call(this,{"isBuffer":require("../../../AppData/Roaming/npm/node_modules/browserify/node_modules/is-buffer/index.js")})
    },{"../../../AppData/Roaming/npm/node_modules/browserify/node_modules/is-buffer/index.js":151}],278:[function(require,module,exports){
    /*
      Copyright (c) jQuery Foundation, Inc. and Contributors, All Rights Reserved.
    
      Redistribution and use in source and binary forms, with or without
      modification, are permitted provided that the following conditions are met:
    
        * Redistributions of source code must retain the above copyright
          notice, this list of conditions and the following disclaimer.
        * Redistributions in binary form must reproduce the above copyright
          notice, this list of conditions and the following disclaimer in the
          documentation and/or other materials provided with the distribution.
    
      THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
      AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
      DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
      (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
      LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
      ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
      THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    */
    
    (function (root, factory) {
        'use strict';
    
        // Universal Module Definition (UMD) to support AMD, CommonJS/Node.js,
        // Rhino, and plain browser loading.
    
        /* istanbul ignore next */
        if (typeof define === 'function' && define.amd) {
            define(['exports'], factory);
        } else if (typeof exports !== 'undefined') {
            factory(exports);
        } else {
            factory((root.esprima = {}));
        }
    }(this, function (exports) {
        'use strict';
    
        var Token,
            TokenName,
            FnExprTokens,
            Syntax,
            PlaceHolders,
            Messages,
            Regex,
            source,
            strict,
            index,
            lineNumber,
            lineStart,
            hasLineTerminator,
            lastIndex,
            lastLineNumber,
            lastLineStart,
            startIndex,
            startLineNumber,
            startLineStart,
            scanning,
            length,
            lookahead,
            state,
            extra,
            isBindingElement,
            isAssignmentTarget,
            firstCoverInitializedNameError;
    
        Token = {
            BooleanLiteral: 1,
            EOF: 2,
            Identifier: 3,
            Keyword: 4,
            NullLiteral: 5,
            NumericLiteral: 6,
            Punctuator: 7,
            StringLiteral: 8,
            RegularExpression: 9,
            Template: 10
        };
    
        TokenName = {};
        TokenName[Token.BooleanLiteral] = 'Boolean';
        TokenName[Token.EOF] = '<end>';
        TokenName[Token.Identifier] = 'Identifier';
        TokenName[Token.Keyword] = 'Keyword';
        TokenName[Token.NullLiteral] = 'Null';
        TokenName[Token.NumericLiteral] = 'Numeric';
        TokenName[Token.Punctuator] = 'Punctuator';
        TokenName[Token.StringLiteral] = 'String';
        TokenName[Token.RegularExpression] = 'RegularExpression';
        TokenName[Token.Template] = 'Template';
    
        // A function following one of those tokens is an expression.
        FnExprTokens = ['(', '{', '[', 'in', 'typeof', 'instanceof', 'new',
                        'return', 'case', 'delete', 'throw', 'void',
                        // assignment operators
                        '=', '+=', '-=', '*=', '/=', '%=', '<<=', '>>=', '>>>=',
                        '&=', '|=', '^=', ',',
                        // binary/unary operators
                        '+', '-', '*', '/', '%', '++', '--', '<<', '>>', '>>>', '&',
                        '|', '^', '!', '~', '&&', '||', '?', ':', '===', '==', '>=',
                        '<=', '<', '>', '!=', '!=='];
    
        Syntax = {
            AssignmentExpression: 'AssignmentExpression',
            AssignmentPattern: 'AssignmentPattern',
            ArrayExpression: 'ArrayExpression',
            ArrayPattern: 'ArrayPattern',
            ArrowFunctionExpression: 'ArrowFunctionExpression',
            BlockStatement: 'BlockStatement',
            BinaryExpression: 'BinaryExpression',
            BreakStatement: 'BreakStatement',
            CallExpression: 'CallExpression',
            CatchClause: 'CatchClause',
            ClassBody: 'ClassBody',
            ClassDeclaration: 'ClassDeclaration',
            ClassExpression: 'ClassExpression',
            ConditionalExpression: 'ConditionalExpression',
            ContinueStatement: 'ContinueStatement',
            DoWhileStatement: 'DoWhileStatement',
            DebuggerStatement: 'DebuggerStatement',
            EmptyStatement: 'EmptyStatement',
            ExportAllDeclaration: 'ExportAllDeclaration',
            ExportDefaultDeclaration: 'ExportDefaultDeclaration',
            ExportNamedDeclaration: 'ExportNamedDeclaration',
            ExportSpecifier: 'ExportSpecifier',
            ExpressionStatement: 'ExpressionStatement',
            ForStatement: 'ForStatement',
            ForOfStatement: 'ForOfStatement',
            ForInStatement: 'ForInStatement',
            FunctionDeclaration: 'FunctionDeclaration',
            FunctionExpression: 'FunctionExpression',
            Identifier: 'Identifier',
            IfStatement: 'IfStatement',
            ImportDeclaration: 'ImportDeclaration',
            ImportDefaultSpecifier: 'ImportDefaultSpecifier',
            ImportNamespaceSpecifier: 'ImportNamespaceSpecifier',
            ImportSpecifier: 'ImportSpecifier',
            Literal: 'Literal',
            LabeledStatement: 'LabeledStatement',
            LogicalExpression: 'LogicalExpression',
            MemberExpression: 'MemberExpression',
            MetaProperty: 'MetaProperty',
            MethodDefinition: 'MethodDefinition',
            NewExpression: 'NewExpression',
            ObjectExpression: 'ObjectExpression',
            ObjectPattern: 'ObjectPattern',
            Program: 'Program',
            Property: 'Property',
            RestElement: 'RestElement',
            ReturnStatement: 'ReturnStatement',
            SequenceExpression: 'SequenceExpression',
            SpreadElement: 'SpreadElement',
            Super: 'Super',
            SwitchCase: 'SwitchCase',
            SwitchStatement: 'SwitchStatement',
            TaggedTemplateExpression: 'TaggedTemplateExpression',
            TemplateElement: 'TemplateElement',
            TemplateLiteral: 'TemplateLiteral',
            ThisExpression: 'ThisExpression',
            ThrowStatement: 'ThrowStatement',
            TryStatement: 'TryStatement',
            UnaryExpression: 'UnaryExpression',
            UpdateExpression: 'UpdateExpression',
            VariableDeclaration: 'VariableDeclaration',
            VariableDeclarator: 'VariableDeclarator',
            WhileStatement: 'WhileStatement',
            WithStatement: 'WithStatement',
            YieldExpression: 'YieldExpression'
        };
    
        PlaceHolders = {
            ArrowParameterPlaceHolder: 'ArrowParameterPlaceHolder'
        };
    
        // Error messages should be identical to V8.
        Messages = {
            UnexpectedToken: 'Unexpected token %0',
            UnexpectedNumber: 'Unexpected number',
            UnexpectedString: 'Unexpected string',
            UnexpectedIdentifier: 'Unexpected identifier',
            UnexpectedReserved: 'Unexpected reserved word',
            UnexpectedTemplate: 'Unexpected quasi %0',
            UnexpectedEOS: 'Unexpected end of input',
            NewlineAfterThrow: 'Illegal newline after throw',
            InvalidRegExp: 'Invalid regular expression',
            UnterminatedRegExp: 'Invalid regular expression: missing /',
            InvalidLHSInAssignment: 'Invalid left-hand side in assignment',
            InvalidLHSInForIn: 'Invalid left-hand side in for-in',
            InvalidLHSInForLoop: 'Invalid left-hand side in for-loop',
            MultipleDefaultsInSwitch: 'More than one default clause in switch statement',
            NoCatchOrFinally: 'Missing catch or finally after try',
            UnknownLabel: 'Undefined label \'%0\'',
            Redeclaration: '%0 \'%1\' has already been declared',
            IllegalContinue: 'Illegal continue statement',
            IllegalBreak: 'Illegal break statement',
            IllegalReturn: 'Illegal return statement',
            StrictModeWith: 'Strict mode code may not include a with statement',
            StrictCatchVariable: 'Catch variable may not be eval or arguments in strict mode',
            StrictVarName: 'Variable name may not be eval or arguments in strict mode',
            StrictParamName: 'Parameter name eval or arguments is not allowed in strict mode',
            StrictParamDupe: 'Strict mode function may not have duplicate parameter names',
            StrictFunctionName: 'Function name may not be eval or arguments in strict mode',
            StrictOctalLiteral: 'Octal literals are not allowed in strict mode.',
            StrictDelete: 'Delete of an unqualified identifier in strict mode.',
            StrictLHSAssignment: 'Assignment to eval or arguments is not allowed in strict mode',
            StrictLHSPostfix: 'Postfix increment/decrement may not have eval or arguments operand in strict mode',
            StrictLHSPrefix: 'Prefix increment/decrement may not have eval or arguments operand in strict mode',
            StrictReservedWord: 'Use of future reserved word in strict mode',
            TemplateOctalLiteral: 'Octal literals are not allowed in template strings.',
            ParameterAfterRestParameter: 'Rest parameter must be last formal parameter',
            DefaultRestParameter: 'Unexpected token =',
            ObjectPatternAsRestParameter: 'Unexpected token {',
            DuplicateProtoProperty: 'Duplicate __proto__ fields are not allowed in object literals',
            ConstructorSpecialMethod: 'Class constructor may not be an accessor',
            DuplicateConstructor: 'A class may only have one constructor',
            StaticPrototype: 'Classes may not have static property named prototype',
            MissingFromClause: 'Unexpected token',
            NoAsAfterImportNamespace: 'Unexpected token',
            InvalidModuleSpecifier: 'Unexpected token',
            IllegalImportDeclaration: 'Unexpected token',
            IllegalExportDeclaration: 'Unexpected token',
            DuplicateBinding: 'Duplicate binding %0'
        };
    
        // See also tools/generate-unicode-regex.js.
        Regex = {
            // ECMAScript 6/Unicode v7.0.0 NonAsciiIdentifierStart:
            NonAsciiIdentifierStart: /[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0-\u08B2\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58\u0C59\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D60\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19C1-\u19C7\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2118-\u211D\u2124\u2126\u2128\u212A-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309B-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA7AD\uA7B0\uA7B1\uA7F7-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uA9E0-\uA9E4\uA9E6-\uA9EF\uA9FA-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB5F\uAB64\uAB65\uABC0-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD40-\uDD74\uDE80-\uDE9C\uDEA0-\uDED0\uDF00-\uDF1F\uDF30-\uDF4A\uDF50-\uDF75\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD801[\uDC00-\uDC9D\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00\uDE10-\uDE13\uDE15-\uDE17\uDE19-\uDE33\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE4\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48]|\uD804[\uDC03-\uDC37\uDC83-\uDCAF\uDCD0-\uDCE8\uDD03-\uDD26\uDD50-\uDD72\uDD76\uDD83-\uDDB2\uDDC1-\uDDC4\uDDDA\uDE00-\uDE11\uDE13-\uDE2B\uDEB0-\uDEDE\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3D\uDF5D-\uDF61]|\uD805[\uDC80-\uDCAF\uDCC4\uDCC5\uDCC7\uDD80-\uDDAE\uDE00-\uDE2F\uDE44\uDE80-\uDEAA]|\uD806[\uDCA0-\uDCDF\uDCFF\uDEC0-\uDEF8]|\uD808[\uDC00-\uDF98]|\uD809[\uDC00-\uDC6E]|[\uD80C\uD840-\uD868\uD86A-\uD86C][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDED0-\uDEED\uDF00-\uDF2F\uDF40-\uDF43\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDF00-\uDF44\uDF50\uDF93-\uDF9F]|\uD82C[\uDC00\uDC01]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB]|\uD83A[\uDC00-\uDCC4]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D]|\uD87E[\uDC00-\uDE1D]/,
    
            // ECMAScript 6/Unicode v7.0.0 NonAsciiIdentifierPart:
            NonAsciiIdentifierPart: /[\xAA\xB5\xB7\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0300-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u0483-\u0487\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u05D0-\u05EA\u05F0-\u05F2\u0610-\u061A\u0620-\u0669\u066E-\u06D3\u06D5-\u06DC\u06DF-\u06E8\u06EA-\u06FC\u06FF\u0710-\u074A\u074D-\u07B1\u07C0-\u07F5\u07FA\u0800-\u082D\u0840-\u085B\u08A0-\u08B2\u08E4-\u0963\u0966-\u096F\u0971-\u0983\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BC-\u09C4\u09C7\u09C8\u09CB-\u09CE\u09D7\u09DC\u09DD\u09DF-\u09E3\u09E6-\u09F1\u0A01-\u0A03\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A59-\u0A5C\u0A5E\u0A66-\u0A75\u0A81-\u0A83\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABC-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AD0\u0AE0-\u0AE3\u0AE6-\u0AEF\u0B01-\u0B03\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3C-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B5C\u0B5D\u0B5F-\u0B63\u0B66-\u0B6F\u0B71\u0B82\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD0\u0BD7\u0BE6-\u0BEF\u0C00-\u0C03\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C58\u0C59\u0C60-\u0C63\u0C66-\u0C6F\u0C81-\u0C83\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBC-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CDE\u0CE0-\u0CE3\u0CE6-\u0CEF\u0CF1\u0CF2\u0D01-\u0D03\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D-\u0D44\u0D46-\u0D48\u0D4A-\u0D4E\u0D57\u0D60-\u0D63\u0D66-\u0D6F\u0D7A-\u0D7F\u0D82\u0D83\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DE6-\u0DEF\u0DF2\u0DF3\u0E01-\u0E3A\u0E40-\u0E4E\u0E50-\u0E59\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB9\u0EBB-\u0EBD\u0EC0-\u0EC4\u0EC6\u0EC8-\u0ECD\u0ED0-\u0ED9\u0EDC-\u0EDF\u0F00\u0F18\u0F19\u0F20-\u0F29\u0F35\u0F37\u0F39\u0F3E-\u0F47\u0F49-\u0F6C\u0F71-\u0F84\u0F86-\u0F97\u0F99-\u0FBC\u0FC6\u1000-\u1049\u1050-\u109D\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u135D-\u135F\u1369-\u1371\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176C\u176E-\u1770\u1772\u1773\u1780-\u17D3\u17D7\u17DC\u17DD\u17E0-\u17E9\u180B-\u180D\u1810-\u1819\u1820-\u1877\u1880-\u18AA\u18B0-\u18F5\u1900-\u191E\u1920-\u192B\u1930-\u193B\u1946-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u19D0-\u19DA\u1A00-\u1A1B\u1A20-\u1A5E\u1A60-\u1A7C\u1A7F-\u1A89\u1A90-\u1A99\u1AA7\u1AB0-\u1ABD\u1B00-\u1B4B\u1B50-\u1B59\u1B6B-\u1B73\u1B80-\u1BF3\u1C00-\u1C37\u1C40-\u1C49\u1C4D-\u1C7D\u1CD0-\u1CD2\u1CD4-\u1CF6\u1CF8\u1CF9\u1D00-\u1DF5\u1DFC-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u200C\u200D\u203F\u2040\u2054\u2071\u207F\u2090-\u209C\u20D0-\u20DC\u20E1\u20E5-\u20F0\u2102\u2107\u210A-\u2113\u2115\u2118-\u211D\u2124\u2126\u2128\u212A-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D7F-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2DE0-\u2DFF\u3005-\u3007\u3021-\u302F\u3031-\u3035\u3038-\u303C\u3041-\u3096\u3099-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA62B\uA640-\uA66F\uA674-\uA67D\uA67F-\uA69D\uA69F-\uA6F1\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA7AD\uA7B0\uA7B1\uA7F7-\uA827\uA840-\uA873\uA880-\uA8C4\uA8D0-\uA8D9\uA8E0-\uA8F7\uA8FB\uA900-\uA92D\uA930-\uA953\uA960-\uA97C\uA980-\uA9C0\uA9CF-\uA9D9\uA9E0-\uA9FE\uAA00-\uAA36\uAA40-\uAA4D\uAA50-\uAA59\uAA60-\uAA76\uAA7A-\uAAC2\uAADB-\uAADD\uAAE0-\uAAEF\uAAF2-\uAAF6\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB5F\uAB64\uAB65\uABC0-\uABEA\uABEC\uABED\uABF0-\uABF9\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE00-\uFE0F\uFE20-\uFE2D\uFE33\uFE34\uFE4D-\uFE4F\uFE70-\uFE74\uFE76-\uFEFC\uFF10-\uFF19\uFF21-\uFF3A\uFF3F\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD40-\uDD74\uDDFD\uDE80-\uDE9C\uDEA0-\uDED0\uDEE0\uDF00-\uDF1F\uDF30-\uDF4A\uDF50-\uDF7A\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD801[\uDC00-\uDC9D\uDCA0-\uDCA9\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00-\uDE03\uDE05\uDE06\uDE0C-\uDE13\uDE15-\uDE17\uDE19-\uDE33\uDE38-\uDE3A\uDE3F\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE6\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48]|\uD804[\uDC00-\uDC46\uDC66-\uDC6F\uDC7F-\uDCBA\uDCD0-\uDCE8\uDCF0-\uDCF9\uDD00-\uDD34\uDD36-\uDD3F\uDD50-\uDD73\uDD76\uDD80-\uDDC4\uDDD0-\uDDDA\uDE00-\uDE11\uDE13-\uDE37\uDEB0-\uDEEA\uDEF0-\uDEF9\uDF01-\uDF03\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3C-\uDF44\uDF47\uDF48\uDF4B-\uDF4D\uDF57\uDF5D-\uDF63\uDF66-\uDF6C\uDF70-\uDF74]|\uD805[\uDC80-\uDCC5\uDCC7\uDCD0-\uDCD9\uDD80-\uDDB5\uDDB8-\uDDC0\uDE00-\uDE40\uDE44\uDE50-\uDE59\uDE80-\uDEB7\uDEC0-\uDEC9]|\uD806[\uDCA0-\uDCE9\uDCFF\uDEC0-\uDEF8]|\uD808[\uDC00-\uDF98]|\uD809[\uDC00-\uDC6E]|[\uD80C\uD840-\uD868\uD86A-\uD86C][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDE60-\uDE69\uDED0-\uDEED\uDEF0-\uDEF4\uDF00-\uDF36\uDF40-\uDF43\uDF50-\uDF59\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDF00-\uDF44\uDF50-\uDF7E\uDF8F-\uDF9F]|\uD82C[\uDC00\uDC01]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99\uDC9D\uDC9E]|\uD834[\uDD65-\uDD69\uDD6D-\uDD72\uDD7B-\uDD82\uDD85-\uDD8B\uDDAA-\uDDAD\uDE42-\uDE44]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB\uDFCE-\uDFFF]|\uD83A[\uDC00-\uDCC4\uDCD0-\uDCD6]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D]|\uD87E[\uDC00-\uDE1D]|\uDB40[\uDD00-\uDDEF]/
        };
    
        // Ensure the condition is true, otherwise throw an error.
        // This is only to have a better contract semantic, i.e. another safety net
        // to catch a logic error. The condition shall be fulfilled in normal case.
        // Do NOT use this to enforce a certain condition on any user input.
    
        function assert(condition, message) {
            /* istanbul ignore if */
            if (!condition) {
                throw new Error('ASSERT: ' + message);
            }
        }
    
        function isDecimalDigit(ch) {
            return (ch >= 0x30 && ch <= 0x39);   // 0..9
        }
    
        function isHexDigit(ch) {
            return '0123456789abcdefABCDEF'.indexOf(ch) >= 0;
        }
    
        function isOctalDigit(ch) {
            return '01234567'.indexOf(ch) >= 0;
        }
    
        function octalToDecimal(ch) {
            // \0 is not octal escape sequence
            var octal = (ch !== '0'), code = '01234567'.indexOf(ch);
    
            if (index < length && isOctalDigit(source[index])) {
                octal = true;
                code = code * 8 + '01234567'.indexOf(source[index++]);
    
                // 3 digits are only allowed when string starts
                // with 0, 1, 2, 3
                if ('0123'.indexOf(ch) >= 0 &&
                        index < length &&
                        isOctalDigit(source[index])) {
                    code = code * 8 + '01234567'.indexOf(source[index++]);
                }
            }
    
            return {
                code: code,
                octal: octal
            };
        }
    
        // ECMA-262 11.2 White Space
    
        function isWhiteSpace(ch) {
            return (ch === 0x20) || (ch === 0x09) || (ch === 0x0B) || (ch === 0x0C) || (ch === 0xA0) ||
                (ch >= 0x1680 && [0x1680, 0x180E, 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007, 0x2008, 0x2009, 0x200A, 0x202F, 0x205F, 0x3000, 0xFEFF].indexOf(ch) >= 0);
        }
    
        // ECMA-262 11.3 Line Terminators
    
        function isLineTerminator(ch) {
            return (ch === 0x0A) || (ch === 0x0D) || (ch === 0x2028) || (ch === 0x2029);
        }
    
        // ECMA-262 11.6 Identifier Names and Identifiers
    
        function fromCodePoint(cp) {
            return (cp < 0x10000) ? String.fromCharCode(cp) :
                String.fromCharCode(0xD800 + ((cp - 0x10000) >> 10)) +
                String.fromCharCode(0xDC00 + ((cp - 0x10000) & 1023));
        }
    
        function isIdentifierStart(ch) {
            return (ch === 0x24) || (ch === 0x5F) ||  // $ (dollar) and _ (underscore)
                (ch >= 0x41 && ch <= 0x5A) ||         // A..Z
                (ch >= 0x61 && ch <= 0x7A) ||         // a..z
                (ch === 0x5C) ||                      // \ (backslash)
                ((ch >= 0x80) && Regex.NonAsciiIdentifierStart.test(fromCodePoint(ch)));
        }
    
        function isIdentifierPart(ch) {
            return (ch === 0x24) || (ch === 0x5F) ||  // $ (dollar) and _ (underscore)
                (ch >= 0x41 && ch <= 0x5A) ||         // A..Z
                (ch >= 0x61 && ch <= 0x7A) ||         // a..z
                (ch >= 0x30 && ch <= 0x39) ||         // 0..9
                (ch === 0x5C) ||                      // \ (backslash)
                ((ch >= 0x80) && Regex.NonAsciiIdentifierPart.test(fromCodePoint(ch)));
        }
    
        // ECMA-262 11.6.2.2 Future Reserved Words
    
        function isFutureReservedWord(id) {
            switch (id) {
            case 'enum':
            case 'export':
            case 'import':
            case 'super':
                return true;
            default:
                return false;
            }
        }
    
        function isStrictModeReservedWord(id) {
            switch (id) {
            case 'implements':
            case 'interface':
            case 'package':
            case 'private':
            case 'protected':
            case 'public':
            case 'static':
            case 'yield':
            case 'let':
                return true;
            default:
                return false;
            }
        }
    
        function isRestrictedWord(id) {
            return id === 'eval' || id === 'arguments';
        }
    
        // ECMA-262 11.6.2.1 Keywords
    
        function isKeyword(id) {
            switch (id.length) {
            case 2:
                return (id === 'if') || (id === 'in') || (id === 'do');
            case 3:
                return (id === 'var') || (id === 'for') || (id === 'new') ||
                    (id === 'try') || (id === 'let');
            case 4:
                return (id === 'this') || (id === 'else') || (id === 'case') ||
                    (id === 'void') || (id === 'with') || (id === 'enum');
            case 5:
                return (id === 'while') || (id === 'break') || (id === 'catch') ||
                    (id === 'throw') || (id === 'const') || (id === 'yield') ||
                    (id === 'class') || (id === 'super');
            case 6:
                return (id === 'return') || (id === 'typeof') || (id === 'delete') ||
                    (id === 'switch') || (id === 'export') || (id === 'import');
            case 7:
                return (id === 'default') || (id === 'finally') || (id === 'extends');
            case 8:
                return (id === 'function') || (id === 'continue') || (id === 'debugger');
            case 10:
                return (id === 'instanceof');
            default:
                return false;
            }
        }
    
        // ECMA-262 11.4 Comments
    
        function addComment(type, value, start, end, loc) {
            var comment;
    
            assert(typeof start === 'number', 'Comment must have valid position');
    
            state.lastCommentStart = start;
    
            comment = {
                type: type,
                value: value
            };
            if (extra.range) {
                comment.range = [start, end];
            }
            if (extra.loc) {
                comment.loc = loc;
            }
            extra.comments.push(comment);
            if (extra.attachComment) {
                extra.leadingComments.push(comment);
                extra.trailingComments.push(comment);
            }
            if (extra.tokenize) {
                comment.type = comment.type + 'Comment';
                if (extra.delegate) {
                    comment = extra.delegate(comment);
                }
                extra.tokens.push(comment);
            }
        }
    
        function skipSingleLineComment(offset) {
            var start, loc, ch, comment;
    
            start = index - offset;
            loc = {
                start: {
                    line: lineNumber,
                    column: index - lineStart - offset
                }
            };
    
            while (index < length) {
                ch = source.charCodeAt(index);
                ++index;
                if (isLineTerminator(ch)) {
                    hasLineTerminator = true;
                    if (extra.comments) {
                        comment = source.slice(start + offset, index - 1);
                        loc.end = {
                            line: lineNumber,
                            column: index - lineStart - 1
                        };
                        addComment('Line', comment, start, index - 1, loc);
                    }
                    if (ch === 13 && source.charCodeAt(index) === 10) {
                        ++index;
                    }
                    ++lineNumber;
                    lineStart = index;
                    return;
                }
            }
    
            if (extra.comments) {
                comment = source.slice(start + offset, index);
                loc.end = {
                    line: lineNumber,
                    column: index - lineStart
                };
                addComment('Line', comment, start, index, loc);
            }
        }
    
        function skipMultiLineComment() {
            var start, loc, ch, comment;
    
            if (extra.comments) {
                start = index - 2;
                loc = {
                    start: {
                        line: lineNumber,
                        column: index - lineStart - 2
                    }
                };
            }
    
            while (index < length) {
                ch = source.charCodeAt(index);
                if (isLineTerminator(ch)) {
                    if (ch === 0x0D && source.charCodeAt(index + 1) === 0x0A) {
                        ++index;
                    }
                    hasLineTerminator = true;
                    ++lineNumber;
                    ++index;
                    lineStart = index;
                } else if (ch === 0x2A) {
                    // Block comment ends with '*/'.
                    if (source.charCodeAt(index + 1) === 0x2F) {
                        ++index;
                        ++index;
                        if (extra.comments) {
                            comment = source.slice(start + 2, index - 2);
                            loc.end = {
                                line: lineNumber,
                                column: index - lineStart
                            };
                            addComment('Block', comment, start, index, loc);
                        }
                        return;
                    }
                    ++index;
                } else {
                    ++index;
                }
            }
    
            // Ran off the end of the file - the whole thing is a comment
            if (extra.comments) {
                loc.end = {
                    line: lineNumber,
                    column: index - lineStart
                };
                comment = source.slice(start + 2, index);
                addComment('Block', comment, start, index, loc);
            }
            tolerateUnexpectedToken();
        }
    
        function skipComment() {
            var ch, start;
            hasLineTerminator = false;
    
            start = (index === 0);
            while (index < length) {
                ch = source.charCodeAt(index);
    
                if (isWhiteSpace(ch)) {
                    ++index;
                } else if (isLineTerminator(ch)) {
                    hasLineTerminator = true;
                    ++index;
                    if (ch === 0x0D && source.charCodeAt(index) === 0x0A) {
                        ++index;
                    }
                    ++lineNumber;
                    lineStart = index;
                    start = true;
                } else if (ch === 0x2F) { // U+002F is '/'
                    ch = source.charCodeAt(index + 1);
                    if (ch === 0x2F) {
                        ++index;
                        ++index;
                        skipSingleLineComment(2);
                        start = true;
                    } else if (ch === 0x2A) {  // U+002A is '*'
                        ++index;
                        ++index;
                        skipMultiLineComment();
                    } else {
                        break;
                    }
                } else if (start && ch === 0x2D) { // U+002D is '-'
                    // U+003E is '>'
                    if ((source.charCodeAt(index + 1) === 0x2D) && (source.charCodeAt(index + 2) === 0x3E)) {
                        // '-->' is a single-line comment
                        index += 3;
                        skipSingleLineComment(3);
                    } else {
                        break;
                    }
                } else if (ch === 0x3C) { // U+003C is '<'
                    if (source.slice(index + 1, index + 4) === '!--') {
                        ++index; // `<`
                        ++index; // `!`
                        ++index; // `-`
                        ++index; // `-`
                        skipSingleLineComment(4);
                    } else {
                        break;
                    }
                } else {
                    break;
                }
            }
        }
    
        function scanHexEscape(prefix) {
            var i, len, ch, code = 0;
    
            len = (prefix === 'u') ? 4 : 2;
            for (i = 0; i < len; ++i) {
                if (index < length && isHexDigit(source[index])) {
                    ch = source[index++];
                    code = code * 16 + '0123456789abcdef'.indexOf(ch.toLowerCase());
                } else {
                    return '';
                }
            }
            return String.fromCharCode(code);
        }
    
        function scanUnicodeCodePointEscape() {
            var ch, code;
    
            ch = source[index];
            code = 0;
    
            // At least, one hex digit is required.
            if (ch === '}') {
                throwUnexpectedToken();
            }
    
            while (index < length) {
                ch = source[index++];
                if (!isHexDigit(ch)) {
                    break;
                }
                code = code * 16 + '0123456789abcdef'.indexOf(ch.toLowerCase());
            }
    
            if (code > 0x10FFFF || ch !== '}') {
                throwUnexpectedToken();
            }
    
            return fromCodePoint(code);
        }
    
        function codePointAt(i) {
            var cp, first, second;
    
            cp = source.charCodeAt(i);
            if (cp >= 0xD800 && cp <= 0xDBFF) {
                second = source.charCodeAt(i + 1);
                if (second >= 0xDC00 && second <= 0xDFFF) {
                    first = cp;
                    cp = (first - 0xD800) * 0x400 + second - 0xDC00 + 0x10000;
                }
            }
    
            return cp;
        }
    
        function getComplexIdentifier() {
            var cp, ch, id;
    
            cp = codePointAt(index);
            id = fromCodePoint(cp);
            index += id.length;
    
            // '\u' (U+005C, U+0075) denotes an escaped character.
            if (cp === 0x5C) {
                if (source.charCodeAt(index) !== 0x75) {
                    throwUnexpectedToken();
                }
                ++index;
                if (source[index] === '{') {
                    ++index;
                    ch = scanUnicodeCodePointEscape();
                } else {
                    ch = scanHexEscape('u');
                    cp = ch.charCodeAt(0);
                    if (!ch || ch === '\\' || !isIdentifierStart(cp)) {
                        throwUnexpectedToken();
                    }
                }
                id = ch;
            }
    
            while (index < length) {
                cp = codePointAt(index);
                if (!isIdentifierPart(cp)) {
                    break;
                }
                ch = fromCodePoint(cp);
                id += ch;
                index += ch.length;
    
                // '\u' (U+005C, U+0075) denotes an escaped character.
                if (cp === 0x5C) {
                    id = id.substr(0, id.length - 1);
                    if (source.charCodeAt(index) !== 0x75) {
                        throwUnexpectedToken();
                    }
                    ++index;
                    if (source[index] === '{') {
                        ++index;
                        ch = scanUnicodeCodePointEscape();
                    } else {
                        ch = scanHexEscape('u');
                        cp = ch.charCodeAt(0);
                        if (!ch || ch === '\\' || !isIdentifierPart(cp)) {
                            throwUnexpectedToken();
                        }
                    }
                    id += ch;
                }
            }
    
            return id;
        }
    
        function getIdentifier() {
            var start, ch;
    
            start = index++;
            while (index < length) {
                ch = source.charCodeAt(index);
                if (ch === 0x5C) {
                    // Blackslash (U+005C) marks Unicode escape sequence.
                    index = start;
                    return getComplexIdentifier();
                } else if (ch >= 0xD800 && ch < 0xDFFF) {
                    // Need to handle surrogate pairs.
                    index = start;
                    return getComplexIdentifier();
                }
                if (isIdentifierPart(ch)) {
                    ++index;
                } else {
                    break;
                }
            }
    
            return source.slice(start, index);
        }
    
        function scanIdentifier() {
            var start, id, type;
    
            start = index;
    
            // Backslash (U+005C) starts an escaped character.
            id = (source.charCodeAt(index) === 0x5C) ? getComplexIdentifier() : getIdentifier();
    
            // There is no keyword or literal with only one character.
            // Thus, it must be an identifier.
            if (id.length === 1) {
                type = Token.Identifier;
            } else if (isKeyword(id)) {
                type = Token.Keyword;
            } else if (id === 'null') {
                type = Token.NullLiteral;
            } else if (id === 'true' || id === 'false') {
                type = Token.BooleanLiteral;
            } else {
                type = Token.Identifier;
            }
    
            return {
                type: type,
                value: id,
                lineNumber: lineNumber,
                lineStart: lineStart,
                start: start,
                end: index
            };
        }
    
    
        // ECMA-262 11.7 Punctuators
    
        function scanPunctuator() {
            var token, str;
    
            token = {
                type: Token.Punctuator,
                value: '',
                lineNumber: lineNumber,
                lineStart: lineStart,
                start: index,
                end: index
            };
    
            // Check for most common single-character punctuators.
            str = source[index];
            switch (str) {
    
            case '(':
                if (extra.tokenize) {
                    extra.openParenToken = extra.tokenValues.length;
                }
                ++index;
                break;
    
            case '{':
                if (extra.tokenize) {
                    extra.openCurlyToken = extra.tokenValues.length;
                }
                state.curlyStack.push('{');
                ++index;
                break;
    
            case '.':
                ++index;
                if (source[index] === '.' && source[index + 1] === '.') {
                    // Spread operator: ...
                    index += 2;
                    str = '...';
                }
                break;
    
            case '}':
                ++index;
                state.curlyStack.pop();
                break;
            case ')':
            case ';':
            case ',':
            case '[':
            case ']':
            case ':':
            case '?':
            case '~':
                ++index;
                break;
    
            default:
                // 4-character punctuator.
                str = source.substr(index, 4);
                if (str === '>>>=') {
                    index += 4;
                } else {
    
                    // 3-character punctuators.
                    str = str.substr(0, 3);
                    if (str === '===' || str === '!==' || str === '>>>' ||
                        str === '<<=' || str === '>>=') {
                        index += 3;
                    } else {
    
                        // 2-character punctuators.
                        str = str.substr(0, 2);
                        if (str === '&&' || str === '||' || str === '==' || str === '!=' ||
                            str === '+=' || str === '-=' || str === '*=' || str === '/=' ||
                            str === '++' || str === '--' || str === '<<' || str === '>>' ||
                            str === '&=' || str === '|=' || str === '^=' || str === '%=' ||
                            str === '<=' || str === '>=' || str === '=>') {
                            index += 2;
                        } else {
    
                            // 1-character punctuators.
                            str = source[index];
                            if ('<>=!+-*%&|^/'.indexOf(str) >= 0) {
                                ++index;
                            }
                        }
                    }
                }
            }
    
            if (index === token.start) {
                throwUnexpectedToken();
            }
    
            token.end = index;
            token.value = str;
            return token;
        }
    
        // ECMA-262 11.8.3 Numeric Literals
    
        function scanHexLiteral(start) {
            var number = '';
    
            while (index < length) {
                if (!isHexDigit(source[index])) {
                    break;
                }
                number += source[index++];
            }
    
            if (number.length === 0) {
                throwUnexpectedToken();
            }
    
            if (isIdentifierStart(source.charCodeAt(index))) {
                throwUnexpectedToken();
            }
    
            return {
                type: Token.NumericLiteral,
                value: parseInt('0x' + number, 16),
                lineNumber: lineNumber,
                lineStart: lineStart,
                start: start,
                end: index
            };
        }
    
        function scanBinaryLiteral(start) {
            var ch, number;
    
            number = '';
    
            while (index < length) {
                ch = source[index];
                if (ch !== '0' && ch !== '1') {
                    break;
                }
                number += source[index++];
            }
    
            if (number.length === 0) {
                // only 0b or 0B
                throwUnexpectedToken();
            }
    
            if (index < length) {
                ch = source.charCodeAt(index);
                /* istanbul ignore else */
                if (isIdentifierStart(ch) || isDecimalDigit(ch)) {
                    throwUnexpectedToken();
                }
            }
    
            return {
                type: Token.NumericLiteral,
                value: parseInt(number, 2),
                lineNumber: lineNumber,
                lineStart: lineStart,
                start: start,
                end: index
            };
        }
    
        function scanOctalLiteral(prefix, start) {
            var number, octal;
    
            if (isOctalDigit(prefix)) {
                octal = true;
                number = '0' + source[index++];
            } else {
                octal = false;
                ++index;
                number = '';
            }
    
            while (index < length) {
                if (!isOctalDigit(source[index])) {
                    break;
                }
                number += source[index++];
            }
    
            if (!octal && number.length === 0) {
                // only 0o or 0O
                throwUnexpectedToken();
            }
    
            if (isIdentifierStart(source.charCodeAt(index)) || isDecimalDigit(source.charCodeAt(index))) {
                throwUnexpectedToken();
            }
    
            return {
                type: Token.NumericLiteral,
                value: parseInt(number, 8),
                octal: octal,
                lineNumber: lineNumber,
                lineStart: lineStart,
                start: start,
                end: index
            };
        }
    
        function isImplicitOctalLiteral() {
            var i, ch;
    
            // Implicit octal, unless there is a non-octal digit.
            // (Annex B.1.1 on Numeric Literals)
            for (i = index + 1; i < length; ++i) {
                ch = source[i];
                if (ch === '8' || ch === '9') {
                    return false;
                }
                if (!isOctalDigit(ch)) {
                    return true;
                }
            }
    
            return true;
        }
    
        function scanNumericLiteral() {
            var number, start, ch;
    
            ch = source[index];
            assert(isDecimalDigit(ch.charCodeAt(0)) || (ch === '.'),
                'Numeric literal must start with a decimal digit or a decimal point');
    
            start = index;
            number = '';
            if (ch !== '.') {
                number = source[index++];
                ch = source[index];
    
                // Hex number starts with '0x'.
                // Octal number starts with '0'.
                // Octal number in ES6 starts with '0o'.
                // Binary number in ES6 starts with '0b'.
                if (number === '0') {
                    if (ch === 'x' || ch === 'X') {
                        ++index;
                        return scanHexLiteral(start);
                    }
                    if (ch === 'b' || ch === 'B') {
                        ++index;
                        return scanBinaryLiteral(start);
                    }
                    if (ch === 'o' || ch === 'O') {
                        return scanOctalLiteral(ch, start);
                    }
    
                    if (isOctalDigit(ch)) {
                        if (isImplicitOctalLiteral()) {
                            return scanOctalLiteral(ch, start);
                        }
                    }
                }
    
                while (isDecimalDigit(source.charCodeAt(index))) {
                    number += source[index++];
                }
                ch = source[index];
            }
    
            if (ch === '.') {
                number += source[index++];
                while (isDecimalDigit(source.charCodeAt(index))) {
                    number += source[index++];
                }
                ch = source[index];
            }
    
            if (ch === 'e' || ch === 'E') {
                number += source[index++];
    
                ch = source[index];
                if (ch === '+' || ch === '-') {
                    number += source[index++];
                }
                if (isDecimalDigit(source.charCodeAt(index))) {
                    while (isDecimalDigit(source.charCodeAt(index))) {
                        number += source[index++];
                    }
                } else {
                    throwUnexpectedToken();
                }
            }
    
            if (isIdentifierStart(source.charCodeAt(index))) {
                throwUnexpectedToken();
            }
    
            return {
                type: Token.NumericLiteral,
                value: parseFloat(number),
                lineNumber: lineNumber,
                lineStart: lineStart,
                start: start,
                end: index
            };
        }
    
        // ECMA-262 11.8.4 String Literals
    
        function scanStringLiteral() {
            var str = '', quote, start, ch, unescaped, octToDec, octal = false;
    
            quote = source[index];
            assert((quote === '\'' || quote === '"'),
                'String literal must starts with a quote');
    
            start = index;
            ++index;
    
            while (index < length) {
                ch = source[index++];
    
                if (ch === quote) {
                    quote = '';
                    break;
                } else if (ch === '\\') {
                    ch = source[index++];
                    if (!ch || !isLineTerminator(ch.charCodeAt(0))) {
                        switch (ch) {
                        case 'u':
                        case 'x':
                            if (source[index] === '{') {
                                ++index;
                                str += scanUnicodeCodePointEscape();
                            } else {
                                unescaped = scanHexEscape(ch);
                                if (!unescaped) {
                                    throw throwUnexpectedToken();
                                }
                                str += unescaped;
                            }
                            break;
                        case 'n':
                            str += '\n';
                            break;
                        case 'r':
                            str += '\r';
                            break;
                        case 't':
                            str += '\t';
                            break;
                        case 'b':
                            str += '\b';
                            break;
                        case 'f':
                            str += '\f';
                            break;
                        case 'v':
                            str += '\x0B';
                            break;
                        case '8':
                        case '9':
                            str += ch;
                            tolerateUnexpectedToken();
                            break;
    
                        default:
                            if (isOctalDigit(ch)) {
                                octToDec = octalToDecimal(ch);
    
                                octal = octToDec.octal || octal;
                                str += String.fromCharCode(octToDec.code);
                            } else {
                                str += ch;
                            }
                            break;
                        }
                    } else {
                        ++lineNumber;
                        if (ch === '\r' && source[index] === '\n') {
                            ++index;
                        }
                        lineStart = index;
                    }
                } else if (isLineTerminator(ch.charCodeAt(0))) {
                    break;
                } else {
                    str += ch;
                }
            }
    
            if (quote !== '') {
                index = start;
                throwUnexpectedToken();
            }
    
            return {
                type: Token.StringLiteral,
                value: str,
                octal: octal,
                lineNumber: startLineNumber,
                lineStart: startLineStart,
                start: start,
                end: index
            };
        }
    
        // ECMA-262 11.8.6 Template Literal Lexical Components
    
        function scanTemplate() {
            var cooked = '', ch, start, rawOffset, terminated, head, tail, restore, unescaped;
    
            terminated = false;
            tail = false;
            start = index;
            head = (source[index] === '`');
            rawOffset = 2;
    
            ++index;
    
            while (index < length) {
                ch = source[index++];
                if (ch === '`') {
                    rawOffset = 1;
                    tail = true;
                    terminated = true;
                    break;
                } else if (ch === '$') {
                    if (source[index] === '{') {
                        state.curlyStack.push('${');
                        ++index;
                        terminated = true;
                        break;
                    }
                    cooked += ch;
                } else if (ch === '\\') {
                    ch = source[index++];
                    if (!isLineTerminator(ch.charCodeAt(0))) {
                        switch (ch) {
                        case 'n':
                            cooked += '\n';
                            break;
                        case 'r':
                            cooked += '\r';
                            break;
                        case 't':
                            cooked += '\t';
                            break;
                        case 'u':
                        case 'x':
                            if (source[index] === '{') {
                                ++index;
                                cooked += scanUnicodeCodePointEscape();
                            } else {
                                restore = index;
                                unescaped = scanHexEscape(ch);
                                if (unescaped) {
                                    cooked += unescaped;
                                } else {
                                    index = restore;
                                    cooked += ch;
                                }
                            }
                            break;
                        case 'b':
                            cooked += '\b';
                            break;
                        case 'f':
                            cooked += '\f';
                            break;
                        case 'v':
                            cooked += '\v';
                            break;
    
                        default:
                            if (ch === '0') {
                                if (isDecimalDigit(source.charCodeAt(index))) {
                                    // Illegal: \01 \02 and so on
                                    throwError(Messages.TemplateOctalLiteral);
                                }
                                cooked += '\0';
                            } else if (isOctalDigit(ch)) {
                                // Illegal: \1 \2
                                throwError(Messages.TemplateOctalLiteral);
                            } else {
                                cooked += ch;
                            }
                            break;
                        }
                    } else {
                        ++lineNumber;
                        if (ch === '\r' && source[index] === '\n') {
                            ++index;
                        }
                        lineStart = index;
                    }
                } else if (isLineTerminator(ch.charCodeAt(0))) {
                    ++lineNumber;
                    if (ch === '\r' && source[index] === '\n') {
                        ++index;
                    }
                    lineStart = index;
                    cooked += '\n';
                } else {
                    cooked += ch;
                }
            }
    
            if (!terminated) {
                throwUnexpectedToken();
            }
    
            if (!head) {
                state.curlyStack.pop();
            }
    
            return {
                type: Token.Template,
                value: {
                    cooked: cooked,
                    raw: source.slice(start + 1, index - rawOffset)
                },
                head: head,
                tail: tail,
                lineNumber: lineNumber,
                lineStart: lineStart,
                start: start,
                end: index
            };
        }
    
        // ECMA-262 11.8.5 Regular Expression Literals
    
        function testRegExp(pattern, flags) {
            // The BMP character to use as a replacement for astral symbols when
            // translating an ES6 "u"-flagged pattern to an ES5-compatible
            // approximation.
            // Note: replacing with '\uFFFF' enables false positives in unlikely
            // scenarios. For example, `[\u{1044f}-\u{10440}]` is an invalid
            // pattern that would not be detected by this substitution.
            var astralSubstitute = '\uFFFF',
                tmp = pattern;
    
            if (flags.indexOf('u') >= 0) {
                tmp = tmp
                    // Replace every Unicode escape sequence with the equivalent
                    // BMP character or a constant ASCII code point in the case of
                    // astral symbols. (See the above note on `astralSubstitute`
                    // for more information.)
                    .replace(/\\u\{([0-9a-fA-F]+)\}|\\u([a-fA-F0-9]{4})/g, function ($0, $1, $2) {
                        var codePoint = parseInt($1 || $2, 16);
                        if (codePoint > 0x10FFFF) {
                            throwUnexpectedToken(null, Messages.InvalidRegExp);
                        }
                        if (codePoint <= 0xFFFF) {
                            return String.fromCharCode(codePoint);
                        }
                        return astralSubstitute;
                    })
                    // Replace each paired surrogate with a single ASCII symbol to
                    // avoid throwing on regular expressions that are only valid in
                    // combination with the "u" flag.
                    .replace(
                        /[\uD800-\uDBFF][\uDC00-\uDFFF]/g,
                        astralSubstitute
                    );
            }
    
            // First, detect invalid regular expressions.
            try {
                RegExp(tmp);
            } catch (e) {
                throwUnexpectedToken(null, Messages.InvalidRegExp);
            }
    
            // Return a regular expression object for this pattern-flag pair, or
            // `null` in case the current environment doesn't support the flags it
            // uses.
            try {
                return new RegExp(pattern, flags);
            } catch (exception) {
                /* istanbul ignore next */
                return null;
            }
        }
    
        function scanRegExpBody() {
            var ch, str, classMarker, terminated, body;
    
            ch = source[index];
            assert(ch === '/', 'Regular expression literal must start with a slash');
            str = source[index++];
    
            classMarker = false;
            terminated = false;
            while (index < length) {
                ch = source[index++];
                str += ch;
                if (ch === '\\') {
                    ch = source[index++];
                    // ECMA-262 7.8.5
                    if (isLineTerminator(ch.charCodeAt(0))) {
                        throwUnexpectedToken(null, Messages.UnterminatedRegExp);
                    }
                    str += ch;
                } else if (isLineTerminator(ch.charCodeAt(0))) {
                    throwUnexpectedToken(null, Messages.UnterminatedRegExp);
                } else if (classMarker) {
                    if (ch === ']') {
                        classMarker = false;
                    }
                } else {
                    if (ch === '/') {
                        terminated = true;
                        break;
                    } else if (ch === '[') {
                        classMarker = true;
                    }
                }
            }
    
            if (!terminated) {
                throwUnexpectedToken(null, Messages.UnterminatedRegExp);
            }
    
            // Exclude leading and trailing slash.
            body = str.substr(1, str.length - 2);
            return {
                value: body,
                literal: str
            };
        }
    
        function scanRegExpFlags() {
            var ch, str, flags, restore;
    
            str = '';
            flags = '';
            while (index < length) {
                ch = source[index];
                if (!isIdentifierPart(ch.charCodeAt(0))) {
                    break;
                }
    
                ++index;
                if (ch === '\\' && index < length) {
                    ch = source[index];
                    if (ch === 'u') {
                        ++index;
                        restore = index;
                        ch = scanHexEscape('u');
                        if (ch) {
                            flags += ch;
                            for (str += '\\u'; restore < index; ++restore) {
                                str += source[restore];
                            }
                        } else {
                            index = restore;
                            flags += 'u';
                            str += '\\u';
                        }
                        tolerateUnexpectedToken();
                    } else {
                        str += '\\';
                        tolerateUnexpectedToken();
                    }
                } else {
                    flags += ch;
                    str += ch;
                }
            }
    
            return {
                value: flags,
                literal: str
            };
        }
    
        function scanRegExp() {
            var start, body, flags, value;
            scanning = true;
    
            lookahead = null;
            skipComment();
            start = index;
    
            body = scanRegExpBody();
            flags = scanRegExpFlags();
            value = testRegExp(body.value, flags.value);
            scanning = false;
            if (extra.tokenize) {
                return {
                    type: Token.RegularExpression,
                    value: value,
                    regex: {
                        pattern: body.value,
                        flags: flags.value
                    },
                    lineNumber: lineNumber,
                    lineStart: lineStart,
                    start: start,
                    end: index
                };
            }
    
            return {
                literal: body.literal + flags.literal,
                value: value,
                regex: {
                    pattern: body.value,
                    flags: flags.value
                },
                start: start,
                end: index
            };
        }
    
        function collectRegex() {
            var pos, loc, regex, token;
    
            skipComment();
    
            pos = index;
            loc = {
                start: {
                    line: lineNumber,
                    column: index - lineStart
                }
            };
    
            regex = scanRegExp();
    
            loc.end = {
                line: lineNumber,
                column: index - lineStart
            };
    
            /* istanbul ignore next */
            if (!extra.tokenize) {
                // Pop the previous token, which is likely '/' or '/='
                if (extra.tokens.length > 0) {
                    token = extra.tokens[extra.tokens.length - 1];
                    if (token.range[0] === pos && token.type === 'Punctuator') {
                        if (token.value === '/' || token.value === '/=') {
                            extra.tokens.pop();
                        }
                    }
                }
    
                extra.tokens.push({
                    type: 'RegularExpression',
                    value: regex.literal,
                    regex: regex.regex,
                    range: [pos, index],
                    loc: loc
                });
            }
    
            return regex;
        }
    
        function isIdentifierName(token) {
            return token.type === Token.Identifier ||
                token.type === Token.Keyword ||
                token.type === Token.BooleanLiteral ||
                token.type === Token.NullLiteral;
        }
    
        // Using the following algorithm:
        // https://github.com/mozilla/sweet.js/wiki/design
    
        function advanceSlash() {
            var regex, previous, check;
    
            function testKeyword(value) {
                return value && (value.length > 1) && (value[0] >= 'a') && (value[0] <= 'z');
            }
    
            previous = extra.tokenValues[extra.tokenValues.length - 1];
            regex = (previous !== null);
    
            switch (previous) {
            case 'this':
            case ']':
                regex = false;
                break;
    
            case ')':
                check = extra.tokenValues[extra.openParenToken - 1];
                regex = (check === 'if' || check === 'while' || check === 'for' || check === 'with');
                break;
    
            case '}':
                // Dividing a function by anything makes little sense,
                // but we have to check for that.
                regex = false;
                if (testKeyword(extra.tokenValues[extra.openCurlyToken - 3])) {
                    // Anonymous function, e.g. function(){} /42
                    check = extra.tokenValues[extra.openCurlyToken - 4];
                    regex = check ? (FnExprTokens.indexOf(check) < 0) : false;
                } else if (testKeyword(extra.tokenValues[extra.openCurlyToken - 4])) {
                    // Named function, e.g. function f(){} /42/
                    check = extra.tokenValues[extra.openCurlyToken - 5];
                    regex = check ? (FnExprTokens.indexOf(check) < 0) : true;
                }
            }
    
            return regex ? collectRegex() : scanPunctuator();
        }
    
        function advance() {
            var cp, token;
    
            if (index >= length) {
                return {
                    type: Token.EOF,
                    lineNumber: lineNumber,
                    lineStart: lineStart,
                    start: index,
                    end: index
                };
            }
    
            cp = source.charCodeAt(index);
    
            if (isIdentifierStart(cp)) {
                token = scanIdentifier();
                if (strict && isStrictModeReservedWord(token.value)) {
                    token.type = Token.Keyword;
                }
                return token;
            }
    
            // Very common: ( and ) and ;
            if (cp === 0x28 || cp === 0x29 || cp === 0x3B) {
                return scanPunctuator();
            }
    
            // String literal starts with single quote (U+0027) or double quote (U+0022).
            if (cp === 0x27 || cp === 0x22) {
                return scanStringLiteral();
            }
    
            // Dot (.) U+002E can also start a floating-point number, hence the need
            // to check the next character.
            if (cp === 0x2E) {
                if (isDecimalDigit(source.charCodeAt(index + 1))) {
                    return scanNumericLiteral();
                }
                return scanPunctuator();
            }
    
            if (isDecimalDigit(cp)) {
                return scanNumericLiteral();
            }
    
            // Slash (/) U+002F can also start a regex.
            if (extra.tokenize && cp === 0x2F) {
                return advanceSlash();
            }
    
            // Template literals start with ` (U+0060) for template head
            // or } (U+007D) for template middle or template tail.
            if (cp === 0x60 || (cp === 0x7D && state.curlyStack[state.curlyStack.length - 1] === '${')) {
                return scanTemplate();
            }
    
            // Possible identifier start in a surrogate pair.
            if (cp >= 0xD800 && cp < 0xDFFF) {
                cp = codePointAt(index);
                if (isIdentifierStart(cp)) {
                    return scanIdentifier();
                }
            }
    
            return scanPunctuator();
        }
    
        function collectToken() {
            var loc, token, value, entry;
    
            loc = {
                start: {
                    line: lineNumber,
                    column: index - lineStart
                }
            };
    
            token = advance();
            loc.end = {
                line: lineNumber,
                column: index - lineStart
            };
    
            if (token.type !== Token.EOF) {
                value = source.slice(token.start, token.end);
                entry = {
                    type: TokenName[token.type],
                    value: value,
                    range: [token.start, token.end],
                    loc: loc
                };
                if (token.regex) {
                    entry.regex = {
                        pattern: token.regex.pattern,
                        flags: token.regex.flags
                    };
                }
                if (extra.tokenValues) {
                    extra.tokenValues.push((entry.type === 'Punctuator' || entry.type === 'Keyword') ? entry.value : null);
                }
                if (extra.tokenize) {
                    if (!extra.range) {
                        delete entry.range;
                    }
                    if (!extra.loc) {
                        delete entry.loc;
                    }
                    if (extra.delegate) {
                        entry = extra.delegate(entry);
                    }
                }
                extra.tokens.push(entry);
            }
    
            return token;
        }
    
        function lex() {
            var token;
            scanning = true;
    
            lastIndex = index;
            lastLineNumber = lineNumber;
            lastLineStart = lineStart;
    
            skipComment();
    
            token = lookahead;
    
            startIndex = index;
            startLineNumber = lineNumber;
            startLineStart = lineStart;
    
            lookahead = (typeof extra.tokens !== 'undefined') ? collectToken() : advance();
            scanning = false;
            return token;
        }
    
        function peek() {
            scanning = true;
    
            skipComment();
    
            lastIndex = index;
            lastLineNumber = lineNumber;
            lastLineStart = lineStart;
    
            startIndex = index;
            startLineNumber = lineNumber;
            startLineStart = lineStart;
    
            lookahead = (typeof extra.tokens !== 'undefined') ? collectToken() : advance();
            scanning = false;
        }
    
        function Position() {
            this.line = startLineNumber;
            this.column = startIndex - startLineStart;
        }
    
        function SourceLocation() {
            this.start = new Position();
            this.end = null;
        }
    
        function WrappingSourceLocation(startToken) {
            this.start = {
                line: startToken.lineNumber,
                column: startToken.start - startToken.lineStart
            };
            this.end = null;
        }
    
        function Node() {
            if (extra.range) {
                this.range = [startIndex, 0];
            }
            if (extra.loc) {
                this.loc = new SourceLocation();
            }
        }
    
        function WrappingNode(startToken) {
            if (extra.range) {
                this.range = [startToken.start, 0];
            }
            if (extra.loc) {
                this.loc = new WrappingSourceLocation(startToken);
            }
        }
    
        WrappingNode.prototype = Node.prototype = {
    
            processComment: function () {
                var lastChild,
                    innerComments,
                    leadingComments,
                    trailingComments,
                    bottomRight = extra.bottomRightStack,
                    i,
                    comment,
                    last = bottomRight[bottomRight.length - 1];
    
                if (this.type === Syntax.Program) {
                    if (this.body.length > 0) {
                        return;
                    }
                }
                /**
                 * patch innnerComments for properties empty block
                 * `function a() {/** comments **\/}`
                 */
    
                if (this.type === Syntax.BlockStatement && this.body.length === 0) {
                    innerComments = [];
                    for (i = extra.leadingComments.length - 1; i >= 0; --i) {
                        comment = extra.leadingComments[i];
                        if (this.range[1] >= comment.range[1]) {
                            innerComments.unshift(comment);
                            extra.leadingComments.splice(i, 1);
                            extra.trailingComments.splice(i, 1);
                        }
                    }
                    if (innerComments.length) {
                        this.innerComments = innerComments;
                        //bottomRight.push(this);
                        return;
                    }
                }
    
                if (extra.trailingComments.length > 0) {
                    trailingComments = [];
                    for (i = extra.trailingComments.length - 1; i >= 0; --i) {
                        comment = extra.trailingComments[i];
                        if (comment.range[0] >= this.range[1]) {
                            trailingComments.unshift(comment);
                            extra.trailingComments.splice(i, 1);
                        }
                    }
                    extra.trailingComments = [];
                } else {
                    if (last && last.trailingComments && last.trailingComments[0].range[0] >= this.range[1]) {
                        trailingComments = last.trailingComments;
                        delete last.trailingComments;
                    }
                }
    
                // Eating the stack.
                while (last && last.range[0] >= this.range[0]) {
                    lastChild = bottomRight.pop();
                    last = bottomRight[bottomRight.length - 1];
                }
    
                if (lastChild) {
                    if (lastChild.leadingComments) {
                        leadingComments = [];
                        for (i = lastChild.leadingComments.length - 1; i >= 0; --i) {
                            comment = lastChild.leadingComments[i];
                            if (comment.range[1] <= this.range[0]) {
                                leadingComments.unshift(comment);
                                lastChild.leadingComments.splice(i, 1);
                            }
                        }
    
                        if (!lastChild.leadingComments.length) {
                            lastChild.leadingComments = undefined;
                        }
                    }
                } else if (extra.leadingComments.length > 0) {
                    leadingComments = [];
                    for (i = extra.leadingComments.length - 1; i >= 0; --i) {
                        comment = extra.leadingComments[i];
                        if (comment.range[1] <= this.range[0]) {
                            leadingComments.unshift(comment);
                            extra.leadingComments.splice(i, 1);
                        }
                    }
                }
    
    
                if (leadingComments && leadingComments.length > 0) {
                    this.leadingComments = leadingComments;
                }
                if (trailingComments && trailingComments.length > 0) {
                    this.trailingComments = trailingComments;
                }
    
                bottomRight.push(this);
            },
    
            finish: function () {
                if (extra.range) {
                    this.range[1] = lastIndex;
                }
                if (extra.loc) {
                    this.loc.end = {
                        line: lastLineNumber,
                        column: lastIndex - lastLineStart
                    };
                    if (extra.source) {
                        this.loc.source = extra.source;
                    }
                }
    
                if (extra.attachComment) {
                    this.processComment();
                }
            },
    
            finishArrayExpression: function (elements) {
                this.type = Syntax.ArrayExpression;
                this.elements = elements;
                this.finish();
                return this;
            },
    
            finishArrayPattern: function (elements) {
                this.type = Syntax.ArrayPattern;
                this.elements = elements;
                this.finish();
                return this;
            },
    
            finishArrowFunctionExpression: function (params, defaults, body, expression) {
                this.type = Syntax.ArrowFunctionExpression;
                this.id = null;
                this.params = params;
                this.defaults = defaults;
                this.body = body;
                this.generator = false;
                this.expression = expression;
                this.finish();
                return this;
            },
    
            finishAssignmentExpression: function (operator, left, right) {
                this.type = Syntax.AssignmentExpression;
                this.operator = operator;
                this.left = left;
                this.right = right;
                this.finish();
                return this;
            },
    
            finishAssignmentPattern: function (left, right) {
                this.type = Syntax.AssignmentPattern;
                this.left = left;
                this.right = right;
                this.finish();
                return this;
            },
    
            finishBinaryExpression: function (operator, left, right) {
                this.type = (operator === '||' || operator === '&&') ? Syntax.LogicalExpression : Syntax.BinaryExpression;
                this.operator = operator;
                this.left = left;
                this.right = right;
                this.finish();
                return this;
            },
    
            finishBlockStatement: function (body) {
                this.type = Syntax.BlockStatement;
                this.body = body;
                this.finish();
                return this;
            },
    
            finishBreakStatement: function (label) {
                this.type = Syntax.BreakStatement;
                this.label = label;
                this.finish();
                return this;
            },
    
            finishCallExpression: function (callee, args) {
                this.type = Syntax.CallExpression;
                this.callee = callee;
                this.arguments = args;
                this.finish();
                return this;
            },
    
            finishCatchClause: function (param, body) {
                this.type = Syntax.CatchClause;
                this.param = param;
                this.body = body;
                this.finish();
                return this;
            },
    
            finishClassBody: function (body) {
                this.type = Syntax.ClassBody;
                this.body = body;
                this.finish();
                return this;
            },
    
            finishClassDeclaration: function (id, superClass, body) {
                this.type = Syntax.ClassDeclaration;
                this.id = id;
                this.superClass = superClass;
                this.body = body;
                this.finish();
                return this;
            },
    
            finishClassExpression: function (id, superClass, body) {
                this.type = Syntax.ClassExpression;
                this.id = id;
                this.superClass = superClass;
                this.body = body;
                this.finish();
                return this;
            },
    
            finishConditionalExpression: function (test, consequent, alternate) {
                this.type = Syntax.ConditionalExpression;
                this.test = test;
                this.consequent = consequent;
                this.alternate = alternate;
                this.finish();
                return this;
            },
    
            finishContinueStatement: function (label) {
                this.type = Syntax.ContinueStatement;
                this.label = label;
                this.finish();
                return this;
            },
    
            finishDebuggerStatement: function () {
                this.type = Syntax.DebuggerStatement;
                this.finish();
                return this;
            },
    
            finishDoWhileStatement: function (body, test) {
                this.type = Syntax.DoWhileStatement;
                this.body = body;
                this.test = test;
                this.finish();
                return this;
            },
    
            finishEmptyStatement: function () {
                this.type = Syntax.EmptyStatement;
                this.finish();
                return this;
            },
    
            finishExpressionStatement: function (expression) {
                this.type = Syntax.ExpressionStatement;
                this.expression = expression;
                this.finish();
                return this;
            },
    
            finishForStatement: function (init, test, update, body) {
                this.type = Syntax.ForStatement;
                this.init = init;
                this.test = test;
                this.update = update;
                this.body = body;
                this.finish();
                return this;
            },
    
            finishForOfStatement: function (left, right, body) {
                this.type = Syntax.ForOfStatement;
                this.left = left;
                this.right = right;
                this.body = body;
                this.finish();
                return this;
            },
    
            finishForInStatement: function (left, right, body) {
                this.type = Syntax.ForInStatement;
                this.left = left;
                this.right = right;
                this.body = body;
                this.each = false;
                this.finish();
                return this;
            },
    
            finishFunctionDeclaration: function (id, params, defaults, body, generator) {
                this.type = Syntax.FunctionDeclaration;
                this.id = id;
                this.params = params;
                this.defaults = defaults;
                this.body = body;
                this.generator = generator;
                this.expression = false;
                this.finish();
                return this;
            },
    
            finishFunctionExpression: function (id, params, defaults, body, generator) {
                this.type = Syntax.FunctionExpression;
                this.id = id;
                this.params = params;
                this.defaults = defaults;
                this.body = body;
                this.generator = generator;
                this.expression = false;
                this.finish();
                return this;
            },
    
            finishIdentifier: function (name) {
                this.type = Syntax.Identifier;
                this.name = name;
                this.finish();
                return this;
            },
    
            finishIfStatement: function (test, consequent, alternate) {
                this.type = Syntax.IfStatement;
                this.test = test;
                this.consequent = consequent;
                this.alternate = alternate;
                this.finish();
                return this;
            },
    
            finishLabeledStatement: function (label, body) {
                this.type = Syntax.LabeledStatement;
                this.label = label;
                this.body = body;
                this.finish();
                return this;
            },
    
            finishLiteral: function (token) {
                this.type = Syntax.Literal;
                this.value = token.value;
                this.raw = source.slice(token.start, token.end);
                if (token.regex) {
                    this.regex = token.regex;
                }
                this.finish();
                return this;
            },
    
            finishMemberExpression: function (accessor, object, property) {
                this.type = Syntax.MemberExpression;
                this.computed = accessor === '[';
                this.object = object;
                this.property = property;
                this.finish();
                return this;
            },
    
            finishMetaProperty: function (meta, property) {
                this.type = Syntax.MetaProperty;
                this.meta = meta;
                this.property = property;
                this.finish();
                return this;
            },
    
            finishNewExpression: function (callee, args) {
                this.type = Syntax.NewExpression;
                this.callee = callee;
                this.arguments = args;
                this.finish();
                return this;
            },
    
            finishObjectExpression: function (properties) {
                this.type = Syntax.ObjectExpression;
                this.properties = properties;
                this.finish();
                return this;
            },
    
            finishObjectPattern: function (properties) {
                this.type = Syntax.ObjectPattern;
                this.properties = properties;
                this.finish();
                return this;
            },
    
            finishPostfixExpression: function (operator, argument) {
                this.type = Syntax.UpdateExpression;
                this.operator = operator;
                this.argument = argument;
                this.prefix = false;
                this.finish();
                return this;
            },
    
            finishProgram: function (body, sourceType) {
                this.type = Syntax.Program;
                this.body = body;
                this.sourceType = sourceType;
                this.finish();
                return this;
            },
    
            finishProperty: function (kind, key, computed, value, method, shorthand) {
                this.type = Syntax.Property;
                this.key = key;
                this.computed = computed;
                this.value = value;
                this.kind = kind;
                this.method = method;
                this.shorthand = shorthand;
                this.finish();
                return this;
            },
    
            finishRestElement: function (argument) {
                this.type = Syntax.RestElement;
                this.argument = argument;
                this.finish();
                return this;
            },
    
            finishReturnStatement: function (argument) {
                this.type = Syntax.ReturnStatement;
                this.argument = argument;
                this.finish();
                return this;
            },
    
            finishSequenceExpression: function (expressions) {
                this.type = Syntax.SequenceExpression;
                this.expressions = expressions;
                this.finish();
                return this;
            },
    
            finishSpreadElement: function (argument) {
                this.type = Syntax.SpreadElement;
                this.argument = argument;
                this.finish();
                return this;
            },
    
            finishSwitchCase: function (test, consequent) {
                this.type = Syntax.SwitchCase;
                this.test = test;
                this.consequent = consequent;
                this.finish();
                return this;
            },
    
            finishSuper: function () {
                this.type = Syntax.Super;
                this.finish();
                return this;
            },
    
            finishSwitchStatement: function (discriminant, cases) {
                this.type = Syntax.SwitchStatement;
                this.discriminant = discriminant;
                this.cases = cases;
                this.finish();
                return this;
            },
    
            finishTaggedTemplateExpression: function (tag, quasi) {
                this.type = Syntax.TaggedTemplateExpression;
                this.tag = tag;
                this.quasi = quasi;
                this.finish();
                return this;
            },
    
            finishTemplateElement: function (value, tail) {
                this.type = Syntax.TemplateElement;
                this.value = value;
                this.tail = tail;
                this.finish();
                return this;
            },
    
            finishTemplateLiteral: function (quasis, expressions) {
                this.type = Syntax.TemplateLiteral;
                this.quasis = quasis;
                this.expressions = expressions;
                this.finish();
                return this;
            },
    
            finishThisExpression: function () {
                this.type = Syntax.ThisExpression;
                this.finish();
                return this;
            },
    
            finishThrowStatement: function (argument) {
                this.type = Syntax.ThrowStatement;
                this.argument = argument;
                this.finish();
                return this;
            },
    
            finishTryStatement: function (block, handler, finalizer) {
                this.type = Syntax.TryStatement;
                this.block = block;
                this.guardedHandlers = [];
                this.handlers = handler ? [handler] : [];
                this.handler = handler;
                this.finalizer = finalizer;
                this.finish();
                return this;
            },
    
            finishUnaryExpression: function (operator, argument) {
                this.type = (operator === '++' || operator === '--') ? Syntax.UpdateExpression : Syntax.UnaryExpression;
                this.operator = operator;
                this.argument = argument;
                this.prefix = true;
                this.finish();
                return this;
            },
    
            finishVariableDeclaration: function (declarations) {
                this.type = Syntax.VariableDeclaration;
                this.declarations = declarations;
                this.kind = 'var';
                this.finish();
                return this;
            },
    
            finishLexicalDeclaration: function (declarations, kind) {
                this.type = Syntax.VariableDeclaration;
                this.declarations = declarations;
                this.kind = kind;
                this.finish();
                return this;
            },
    
            finishVariableDeclarator: function (id, init) {
                this.type = Syntax.VariableDeclarator;
                this.id = id;
                this.init = init;
                this.finish();
                return this;
            },
    
            finishWhileStatement: function (test, body) {
                this.type = Syntax.WhileStatement;
                this.test = test;
                this.body = body;
                this.finish();
                return this;
            },
    
            finishWithStatement: function (object, body) {
                this.type = Syntax.WithStatement;
                this.object = object;
                this.body = body;
                this.finish();
                return this;
            },
    
            finishExportSpecifier: function (local, exported) {
                this.type = Syntax.ExportSpecifier;
                this.exported = exported || local;
                this.local = local;
                this.finish();
                return this;
            },
    
            finishImportDefaultSpecifier: function (local) {
                this.type = Syntax.ImportDefaultSpecifier;
                this.local = local;
                this.finish();
                return this;
            },
    
            finishImportNamespaceSpecifier: function (local) {
                this.type = Syntax.ImportNamespaceSpecifier;
                this.local = local;
                this.finish();
                return this;
            },
    
            finishExportNamedDeclaration: function (declaration, specifiers, src) {
                this.type = Syntax.ExportNamedDeclaration;
                this.declaration = declaration;
                this.specifiers = specifiers;
                this.source = src;
                this.finish();
                return this;
            },
    
            finishExportDefaultDeclaration: function (declaration) {
                this.type = Syntax.ExportDefaultDeclaration;
                this.declaration = declaration;
                this.finish();
                return this;
            },
    
            finishExportAllDeclaration: function (src) {
                this.type = Syntax.ExportAllDeclaration;
                this.source = src;
                this.finish();
                return this;
            },
    
            finishImportSpecifier: function (local, imported) {
                this.type = Syntax.ImportSpecifier;
                this.local = local || imported;
                this.imported = imported;
                this.finish();
                return this;
            },
    
            finishImportDeclaration: function (specifiers, src) {
                this.type = Syntax.ImportDeclaration;
                this.specifiers = specifiers;
                this.source = src;
                this.finish();
                return this;
            },
    
            finishYieldExpression: function (argument, delegate) {
                this.type = Syntax.YieldExpression;
                this.argument = argument;
                this.delegate = delegate;
                this.finish();
                return this;
            }
        };
    
    
        function recordError(error) {
            var e, existing;
    
            for (e = 0; e < extra.errors.length; e++) {
                existing = extra.errors[e];
                // Prevent duplicated error.
                /* istanbul ignore next */
                if (existing.index === error.index && existing.message === error.message) {
                    return;
                }
            }
    
            extra.errors.push(error);
        }
    
        function constructError(msg, column) {
            var error = new Error(msg);
            try {
                throw error;
            } catch (base) {
                /* istanbul ignore else */
                if (Object.create && Object.defineProperty) {
                    error = Object.create(base);
                    Object.defineProperty(error, 'column', { value: column });
                }
            } finally {
                return error;
            }
        }
    
        function createError(line, pos, description) {
            var msg, column, error;
    
            msg = 'Line ' + line + ': ' + description;
            column = pos - (scanning ? lineStart : lastLineStart) + 1;
            error = constructError(msg, column);
            error.lineNumber = line;
            error.description = description;
            error.index = pos;
            return error;
        }
    
        // Throw an exception
    
        function throwError(messageFormat) {
            var args, msg;
    
            args = Array.prototype.slice.call(arguments, 1);
            msg = messageFormat.replace(/%(\d)/g,
                function (whole, idx) {
                    assert(idx < args.length, 'Message reference must be in range');
                    return args[idx];
                }
            );
    
            throw createError(lastLineNumber, lastIndex, msg);
        }
    
        function tolerateError(messageFormat) {
            var args, msg, error;
    
            args = Array.prototype.slice.call(arguments, 1);
            /* istanbul ignore next */
            msg = messageFormat.replace(/%(\d)/g,
                function (whole, idx) {
                    assert(idx < args.length, 'Message reference must be in range');
                    return args[idx];
                }
            );
    
            error = createError(lineNumber, lastIndex, msg);
            if (extra.errors) {
                recordError(error);
            } else {
                throw error;
            }
        }
    
        // Throw an exception because of the token.
    
        function unexpectedTokenError(token, message) {
            var value, msg = message || Messages.UnexpectedToken;
    
            if (token) {
                if (!message) {
                    msg = (token.type === Token.EOF) ? Messages.UnexpectedEOS :
                        (token.type === Token.Identifier) ? Messages.UnexpectedIdentifier :
                        (token.type === Token.NumericLiteral) ? Messages.UnexpectedNumber :
                        (token.type === Token.StringLiteral) ? Messages.UnexpectedString :
                        (token.type === Token.Template) ? Messages.UnexpectedTemplate :
                        Messages.UnexpectedToken;
    
                    if (token.type === Token.Keyword) {
                        if (isFutureReservedWord(token.value)) {
                            msg = Messages.UnexpectedReserved;
                        } else if (strict && isStrictModeReservedWord(token.value)) {
                            msg = Messages.StrictReservedWord;
                        }
                    }
                }
    
                value = (token.type === Token.Template) ? token.value.raw : token.value;
            } else {
                value = 'ILLEGAL';
            }
    
            msg = msg.replace('%0', value);
    
            return (token && typeof token.lineNumber === 'number') ?
                createError(token.lineNumber, token.start, msg) :
                createError(scanning ? lineNumber : lastLineNumber, scanning ? index : lastIndex, msg);
        }
    
        function throwUnexpectedToken(token, message) {
            throw unexpectedTokenError(token, message);
        }
    
        function tolerateUnexpectedToken(token, message) {
            var error = unexpectedTokenError(token, message);
            if (extra.errors) {
                recordError(error);
            } else {
                throw error;
            }
        }
    
        // Expect the next token to match the specified punctuator.
        // If not, an exception will be thrown.
    
        function expect(value) {
            var token = lex();
            if (token.type !== Token.Punctuator || token.value !== value) {
                throwUnexpectedToken(token);
            }
        }
    
        /**
         * @name expectCommaSeparator
         * @description Quietly expect a comma when in tolerant mode, otherwise delegates
         * to <code>expect(value)</code>
         * @since 2.0
         */
        function expectCommaSeparator() {
            var token;
    
            if (extra.errors) {
                token = lookahead;
                if (token.type === Token.Punctuator && token.value === ',') {
                    lex();
                } else if (token.type === Token.Punctuator && token.value === ';') {
                    lex();
                    tolerateUnexpectedToken(token);
                } else {
                    tolerateUnexpectedToken(token, Messages.UnexpectedToken);
                }
            } else {
                expect(',');
            }
        }
    
        // Expect the next token to match the specified keyword.
        // If not, an exception will be thrown.
    
        function expectKeyword(keyword) {
            var token = lex();
            if (token.type !== Token.Keyword || token.value !== keyword) {
                throwUnexpectedToken(token);
            }
        }
    
        // Return true if the next token matches the specified punctuator.
    
        function match(value) {
            return lookahead.type === Token.Punctuator && lookahead.value === value;
        }
    
        // Return true if the next token matches the specified keyword
    
        function matchKeyword(keyword) {
            return lookahead.type === Token.Keyword && lookahead.value === keyword;
        }
    
        // Return true if the next token matches the specified contextual keyword
        // (where an identifier is sometimes a keyword depending on the context)
    
        function matchContextualKeyword(keyword) {
            return lookahead.type === Token.Identifier && lookahead.value === keyword;
        }
    
        // Return true if the next token is an assignment operator
    
        function matchAssign() {
            var op;
    
            if (lookahead.type !== Token.Punctuator) {
                return false;
            }
            op = lookahead.value;
            return op === '=' ||
                op === '*=' ||
                op === '/=' ||
                op === '%=' ||
                op === '+=' ||
                op === '-=' ||
                op === '<<=' ||
                op === '>>=' ||
                op === '>>>=' ||
                op === '&=' ||
                op === '^=' ||
                op === '|=';
        }
    
        function consumeSemicolon() {
            // Catch the very common case first: immediately a semicolon (U+003B).
            if (source.charCodeAt(startIndex) === 0x3B || match(';')) {
                lex();
                return;
            }
    
            if (hasLineTerminator) {
                return;
            }
    
            // FIXME(ikarienator): this is seemingly an issue in the previous location info convention.
            lastIndex = startIndex;
            lastLineNumber = startLineNumber;
            lastLineStart = startLineStart;
    
            if (lookahead.type !== Token.EOF && !match('}')) {
                throwUnexpectedToken(lookahead);
            }
        }
    
        // Cover grammar support.
        //
        // When an assignment expression position starts with an left parenthesis, the determination of the type
        // of the syntax is to be deferred arbitrarily long until the end of the parentheses pair (plus a lookahead)
        // or the first comma. This situation also defers the determination of all the expressions nested in the pair.
        //
        // There are three productions that can be parsed in a parentheses pair that needs to be determined
        // after the outermost pair is closed. They are:
        //
        //   1. AssignmentExpression
        //   2. BindingElements
        //   3. AssignmentTargets
        //
        // In order to avoid exponential backtracking, we use two flags to denote if the production can be
        // binding element or assignment target.
        //
        // The three productions have the relationship:
        //
        //   BindingElements ⊆ AssignmentTargets ⊆ AssignmentExpression
        //
        // with a single exception that CoverInitializedName when used directly in an Expression, generates
        // an early error. Therefore, we need the third state, firstCoverInitializedNameError, to track the
        // first usage of CoverInitializedName and report it when we reached the end of the parentheses pair.
        //
        // isolateCoverGrammar function runs the given parser function with a new cover grammar context, and it does not
        // effect the current flags. This means the production the parser parses is only used as an expression. Therefore
        // the CoverInitializedName check is conducted.
        //
        // inheritCoverGrammar function runs the given parse function with a new cover grammar context, and it propagates
        // the flags outside of the parser. This means the production the parser parses is used as a part of a potential
        // pattern. The CoverInitializedName check is deferred.
        function isolateCoverGrammar(parser) {
            var oldIsBindingElement = isBindingElement,
                oldIsAssignmentTarget = isAssignmentTarget,
                oldFirstCoverInitializedNameError = firstCoverInitializedNameError,
                result;
            isBindingElement = true;
            isAssignmentTarget = true;
            firstCoverInitializedNameError = null;
            result = parser();
            if (firstCoverInitializedNameError !== null) {
                throwUnexpectedToken(firstCoverInitializedNameError);
            }
            isBindingElement = oldIsBindingElement;
            isAssignmentTarget = oldIsAssignmentTarget;
            firstCoverInitializedNameError = oldFirstCoverInitializedNameError;
            return result;
        }
    
        function inheritCoverGrammar(parser) {
            var oldIsBindingElement = isBindingElement,
                oldIsAssignmentTarget = isAssignmentTarget,
                oldFirstCoverInitializedNameError = firstCoverInitializedNameError,
                result;
            isBindingElement = true;
            isAssignmentTarget = true;
            firstCoverInitializedNameError = null;
            result = parser();
            isBindingElement = isBindingElement && oldIsBindingElement;
            isAssignmentTarget = isAssignmentTarget && oldIsAssignmentTarget;
            firstCoverInitializedNameError = oldFirstCoverInitializedNameError || firstCoverInitializedNameError;
            return result;
        }
    
        // ECMA-262 13.3.3 Destructuring Binding Patterns
    
        function parseArrayPattern(params, kind) {
            var node = new Node(), elements = [], rest, restNode;
            expect('[');
    
            while (!match(']')) {
                if (match(',')) {
                    lex();
                    elements.push(null);
                } else {
                    if (match('...')) {
                        restNode = new Node();
                        lex();
                        params.push(lookahead);
                        rest = parseVariableIdentifier(kind);
                        elements.push(restNode.finishRestElement(rest));
                        break;
                    } else {
                        elements.push(parsePatternWithDefault(params, kind));
                    }
                    if (!match(']')) {
                        expect(',');
                    }
                }
    
            }
    
            expect(']');
    
            return node.finishArrayPattern(elements);
        }
    
        function parsePropertyPattern(params, kind) {
            var node = new Node(), key, keyToken, computed = match('['), init;
            if (lookahead.type === Token.Identifier) {
                keyToken = lookahead;
                key = parseVariableIdentifier();
                if (match('=')) {
                    params.push(keyToken);
                    lex();
                    init = parseAssignmentExpression();
    
                    return node.finishProperty(
                        'init', key, false,
                        new WrappingNode(keyToken).finishAssignmentPattern(key, init), false, true);
                } else if (!match(':')) {
                    params.push(keyToken);
                    return node.finishProperty('init', key, false, key, false, true);
                }
            } else {
                key = parseObjectPropertyKey();
            }
            expect(':');
            init = parsePatternWithDefault(params, kind);
            return node.finishProperty('init', key, computed, init, false, false);
        }
    
        function parseObjectPattern(params, kind) {
            var node = new Node(), properties = [];
    
            expect('{');
    
            while (!match('}')) {
                properties.push(parsePropertyPattern(params, kind));
                if (!match('}')) {
                    expect(',');
                }
            }
    
            lex();
    
            return node.finishObjectPattern(properties);
        }
    
        function parsePattern(params, kind) {
            if (match('[')) {
                return parseArrayPattern(params, kind);
            } else if (match('{')) {
                return parseObjectPattern(params, kind);
            } else if (matchKeyword('let')) {
                if (kind === 'const' || kind === 'let') {
                    tolerateUnexpectedToken(lookahead, Messages.UnexpectedToken);
                }
            }
    
            params.push(lookahead);
            return parseVariableIdentifier(kind);
        }
    
        function parsePatternWithDefault(params, kind) {
            var startToken = lookahead, pattern, previousAllowYield, right;
            pattern = parsePattern(params, kind);
            if (match('=')) {
                lex();
                previousAllowYield = state.allowYield;
                state.allowYield = true;
                right = isolateCoverGrammar(parseAssignmentExpression);
                state.allowYield = previousAllowYield;
                pattern = new WrappingNode(startToken).finishAssignmentPattern(pattern, right);
            }
            return pattern;
        }
    
        // ECMA-262 12.2.5 Array Initializer
    
        function parseArrayInitializer() {
            var elements = [], node = new Node(), restSpread;
    
            expect('[');
    
            while (!match(']')) {
                if (match(',')) {
                    lex();
                    elements.push(null);
                } else if (match('...')) {
                    restSpread = new Node();
                    lex();
                    restSpread.finishSpreadElement(inheritCoverGrammar(parseAssignmentExpression));
    
                    if (!match(']')) {
                        isAssignmentTarget = isBindingElement = false;
                        expect(',');
                    }
                    elements.push(restSpread);
                } else {
                    elements.push(inheritCoverGrammar(parseAssignmentExpression));
    
                    if (!match(']')) {
                        expect(',');
                    }
                }
            }
    
            lex();
    
            return node.finishArrayExpression(elements);
        }
    
        // ECMA-262 12.2.6 Object Initializer
    
        function parsePropertyFunction(node, paramInfo, isGenerator) {
            var previousStrict, body;
    
            isAssignmentTarget = isBindingElement = false;
    
            previousStrict = strict;
            body = isolateCoverGrammar(parseFunctionSourceElements);
    
            if (strict && paramInfo.firstRestricted) {
                tolerateUnexpectedToken(paramInfo.firstRestricted, paramInfo.message);
            }
            if (strict && paramInfo.stricted) {
                tolerateUnexpectedToken(paramInfo.stricted, paramInfo.message);
            }
    
            strict = previousStrict;
            return node.finishFunctionExpression(null, paramInfo.params, paramInfo.defaults, body, isGenerator);
        }
    
        function parsePropertyMethodFunction() {
            var params, method, node = new Node(),
                previousAllowYield = state.allowYield;
    
            state.allowYield = false;
            params = parseParams();
            state.allowYield = previousAllowYield;
    
            state.allowYield = false;
            method = parsePropertyFunction(node, params, false);
            state.allowYield = previousAllowYield;
    
            return method;
        }
    
        function parseObjectPropertyKey() {
            var token, node = new Node(), expr;
    
            token = lex();
    
            // Note: This function is called only from parseObjectProperty(), where
            // EOF and Punctuator tokens are already filtered out.
    
            switch (token.type) {
            case Token.StringLiteral:
            case Token.NumericLiteral:
                if (strict && token.octal) {
                    tolerateUnexpectedToken(token, Messages.StrictOctalLiteral);
                }
                return node.finishLiteral(token);
            case Token.Identifier:
            case Token.BooleanLiteral:
            case Token.NullLiteral:
            case Token.Keyword:
                return node.finishIdentifier(token.value);
            case Token.Punctuator:
                if (token.value === '[') {
                    expr = isolateCoverGrammar(parseAssignmentExpression);
                    expect(']');
                    return expr;
                }
                break;
            }
            throwUnexpectedToken(token);
        }
    
        function lookaheadPropertyName() {
            switch (lookahead.type) {
            case Token.Identifier:
            case Token.StringLiteral:
            case Token.BooleanLiteral:
            case Token.NullLiteral:
            case Token.NumericLiteral:
            case Token.Keyword:
                return true;
            case Token.Punctuator:
                return lookahead.value === '[';
            }
            return false;
        }
    
        // This function is to try to parse a MethodDefinition as defined in 14.3. But in the case of object literals,
        // it might be called at a position where there is in fact a short hand identifier pattern or a data property.
        // This can only be determined after we consumed up to the left parentheses.
        //
        // In order to avoid back tracking, it returns `null` if the position is not a MethodDefinition and the caller
        // is responsible to visit other options.
        function tryParseMethodDefinition(token, key, computed, node) {
            var value, options, methodNode, params,
                previousAllowYield = state.allowYield;
    
            if (token.type === Token.Identifier) {
                // check for `get` and `set`;
    
                if (token.value === 'get' && lookaheadPropertyName()) {
                    computed = match('[');
                    key = parseObjectPropertyKey();
                    methodNode = new Node();
                    expect('(');
                    expect(')');
    
                    state.allowYield = false;
                    value = parsePropertyFunction(methodNode, {
                        params: [],
                        defaults: [],
                        stricted: null,
                        firstRestricted: null,
                        message: null
                    }, false);
                    state.allowYield = previousAllowYield;
    
                    return node.finishProperty('get', key, computed, value, false, false);
                } else if (token.value === 'set' && lookaheadPropertyName()) {
                    computed = match('[');
                    key = parseObjectPropertyKey();
                    methodNode = new Node();
                    expect('(');
    
                    options = {
                        params: [],
                        defaultCount: 0,
                        defaults: [],
                        firstRestricted: null,
                        paramSet: {}
                    };
                    if (match(')')) {
                        tolerateUnexpectedToken(lookahead);
                    } else {
                        state.allowYield = false;
                        parseParam(options);
                        state.allowYield = previousAllowYield;
                        if (options.defaultCount === 0) {
                            options.defaults = [];
                        }
                    }
                    expect(')');
    
                    state.allowYield = false;
                    value = parsePropertyFunction(methodNode, options, false);
                    state.allowYield = previousAllowYield;
    
                    return node.finishProperty('set', key, computed, value, false, false);
                }
            } else if (token.type === Token.Punctuator && token.value === '*' && lookaheadPropertyName()) {
                computed = match('[');
                key = parseObjectPropertyKey();
                methodNode = new Node();
    
                state.allowYield = true;
                params = parseParams();
                state.allowYield = previousAllowYield;
    
                state.allowYield = false;
                value = parsePropertyFunction(methodNode, params, true);
                state.allowYield = previousAllowYield;
    
                return node.finishProperty('init', key, computed, value, true, false);
            }
    
            if (key && match('(')) {
                value = parsePropertyMethodFunction();
                return node.finishProperty('init', key, computed, value, true, false);
            }
    
            // Not a MethodDefinition.
            return null;
        }
    
        function parseObjectProperty(hasProto) {
            var token = lookahead, node = new Node(), computed, key, maybeMethod, proto, value;
    
            computed = match('[');
            if (match('*')) {
                lex();
            } else {
                key = parseObjectPropertyKey();
            }
            maybeMethod = tryParseMethodDefinition(token, key, computed, node);
            if (maybeMethod) {
                return maybeMethod;
            }
    
            if (!key) {
                throwUnexpectedToken(lookahead);
            }
    
            // Check for duplicated __proto__
            if (!computed) {
                proto = (key.type === Syntax.Identifier && key.name === '__proto__') ||
                    (key.type === Syntax.Literal && key.value === '__proto__');
                if (hasProto.value && proto) {
                    tolerateError(Messages.DuplicateProtoProperty);
                }
                hasProto.value |= proto;
            }
    
            if (match(':')) {
                lex();
                value = inheritCoverGrammar(parseAssignmentExpression);
                return node.finishProperty('init', key, computed, value, false, false);
            }
    
            if (token.type === Token.Identifier) {
                if (match('=')) {
                    firstCoverInitializedNameError = lookahead;
                    lex();
                    value = isolateCoverGrammar(parseAssignmentExpression);
                    return node.finishProperty('init', key, computed,
                        new WrappingNode(token).finishAssignmentPattern(key, value), false, true);
                }
                return node.finishProperty('init', key, computed, key, false, true);
            }
    
            throwUnexpectedToken(lookahead);
        }
    
        function parseObjectInitializer() {
            var properties = [], hasProto = {value: false}, node = new Node();
    
            expect('{');
    
            while (!match('}')) {
                properties.push(parseObjectProperty(hasProto));
    
                if (!match('}')) {
                    expectCommaSeparator();
                }
            }
    
            expect('}');
    
            return node.finishObjectExpression(properties);
        }
    
        function reinterpretExpressionAsPattern(expr) {
            var i;
            switch (expr.type) {
            case Syntax.Identifier:
            case Syntax.MemberExpression:
            case Syntax.RestElement:
            case Syntax.AssignmentPattern:
                break;
            case Syntax.SpreadElement:
                expr.type = Syntax.RestElement;
                reinterpretExpressionAsPattern(expr.argument);
                break;
            case Syntax.ArrayExpression:
                expr.type = Syntax.ArrayPattern;
                for (i = 0; i < expr.elements.length; i++) {
                    if (expr.elements[i] !== null) {
                        reinterpretExpressionAsPattern(expr.elements[i]);
                    }
                }
                break;
            case Syntax.ObjectExpression:
                expr.type = Syntax.ObjectPattern;
                for (i = 0; i < expr.properties.length; i++) {
                    reinterpretExpressionAsPattern(expr.properties[i].value);
                }
                break;
            case Syntax.AssignmentExpression:
                expr.type = Syntax.AssignmentPattern;
                reinterpretExpressionAsPattern(expr.left);
                break;
            default:
                // Allow other node type for tolerant parsing.
                break;
            }
        }
    
        // ECMA-262 12.2.9 Template Literals
    
        function parseTemplateElement(option) {
            var node, token;
    
            if (lookahead.type !== Token.Template || (option.head && !lookahead.head)) {
                throwUnexpectedToken();
            }
    
            node = new Node();
            token = lex();
    
            return node.finishTemplateElement({ raw: token.value.raw, cooked: token.value.cooked }, token.tail);
        }
    
        function parseTemplateLiteral() {
            var quasi, quasis, expressions, node = new Node();
    
            quasi = parseTemplateElement({ head: true });
            quasis = [quasi];
            expressions = [];
    
            while (!quasi.tail) {
                expressions.push(parseExpression());
                quasi = parseTemplateElement({ head: false });
                quasis.push(quasi);
            }
    
            return node.finishTemplateLiteral(quasis, expressions);
        }
    
        // ECMA-262 12.2.10 The Grouping Operator
    
        function parseGroupExpression() {
            var expr, expressions, startToken, i, params = [];
    
            expect('(');
    
            if (match(')')) {
                lex();
                if (!match('=>')) {
                    expect('=>');
                }
                return {
                    type: PlaceHolders.ArrowParameterPlaceHolder,
                    params: [],
                    rawParams: []
                };
            }
    
            startToken = lookahead;
            if (match('...')) {
                expr = parseRestElement(params);
                expect(')');
                if (!match('=>')) {
                    expect('=>');
                }
                return {
                    type: PlaceHolders.ArrowParameterPlaceHolder,
                    params: [expr]
                };
            }
    
            isBindingElement = true;
            expr = inheritCoverGrammar(parseAssignmentExpression);
    
            if (match(',')) {
                isAssignmentTarget = false;
                expressions = [expr];
    
                while (startIndex < length) {
                    if (!match(',')) {
                        break;
                    }
                    lex();
    
                    if (match('...')) {
                        if (!isBindingElement) {
                            throwUnexpectedToken(lookahead);
                        }
                        expressions.push(parseRestElement(params));
                        expect(')');
                        if (!match('=>')) {
                            expect('=>');
                        }
                        isBindingElement = false;
                        for (i = 0; i < expressions.length; i++) {
                            reinterpretExpressionAsPattern(expressions[i]);
                        }
                        return {
                            type: PlaceHolders.ArrowParameterPlaceHolder,
                            params: expressions
                        };
                    }
    
                    expressions.push(inheritCoverGrammar(parseAssignmentExpression));
                }
    
                expr = new WrappingNode(startToken).finishSequenceExpression(expressions);
            }
    
    
            expect(')');
    
            if (match('=>')) {
                if (expr.type === Syntax.Identifier && expr.name === 'yield') {
                    return {
                        type: PlaceHolders.ArrowParameterPlaceHolder,
                        params: [expr]
                    };
                }
    
                if (!isBindingElement) {
                    throwUnexpectedToken(lookahead);
                }
    
                if (expr.type === Syntax.SequenceExpression) {
                    for (i = 0; i < expr.expressions.length; i++) {
                        reinterpretExpressionAsPattern(expr.expressions[i]);
                    }
                } else {
                    reinterpretExpressionAsPattern(expr);
                }
    
                expr = {
                    type: PlaceHolders.ArrowParameterPlaceHolder,
                    params: expr.type === Syntax.SequenceExpression ? expr.expressions : [expr]
                };
            }
            isBindingElement = false;
            return expr;
        }
    
    
        // ECMA-262 12.2 Primary Expressions
    
        function parsePrimaryExpression() {
            var type, token, expr, node;
    
            if (match('(')) {
                isBindingElement = false;
                return inheritCoverGrammar(parseGroupExpression);
            }
    
            if (match('[')) {
                return inheritCoverGrammar(parseArrayInitializer);
            }
    
            if (match('{')) {
                return inheritCoverGrammar(parseObjectInitializer);
            }
    
            type = lookahead.type;
            node = new Node();
    
            if (type === Token.Identifier) {
                if (state.sourceType === 'module' && lookahead.value === 'await') {
                    tolerateUnexpectedToken(lookahead);
                }
                expr = node.finishIdentifier(lex().value);
            } else if (type === Token.StringLiteral || type === Token.NumericLiteral) {
                isAssignmentTarget = isBindingElement = false;
                if (strict && lookahead.octal) {
                    tolerateUnexpectedToken(lookahead, Messages.StrictOctalLiteral);
                }
                expr = node.finishLiteral(lex());
            } else if (type === Token.Keyword) {
                if (!strict && state.allowYield && matchKeyword('yield')) {
                    return parseNonComputedProperty();
                }
                if (!strict && matchKeyword('let')) {
                    return node.finishIdentifier(lex().value);
                }
                isAssignmentTarget = isBindingElement = false;
                if (matchKeyword('function')) {
                    return parseFunctionExpression();
                }
                if (matchKeyword('this')) {
                    lex();
                    return node.finishThisExpression();
                }
                if (matchKeyword('class')) {
                    return parseClassExpression();
                }
                throwUnexpectedToken(lex());
            } else if (type === Token.BooleanLiteral) {
                isAssignmentTarget = isBindingElement = false;
                token = lex();
                token.value = (token.value === 'true');
                expr = node.finishLiteral(token);
            } else if (type === Token.NullLiteral) {
                isAssignmentTarget = isBindingElement = false;
                token = lex();
                token.value = null;
                expr = node.finishLiteral(token);
            } else if (match('/') || match('/=')) {
                isAssignmentTarget = isBindingElement = false;
                index = startIndex;
    
                if (typeof extra.tokens !== 'undefined') {
                    token = collectRegex();
                } else {
                    token = scanRegExp();
                }
                lex();
                expr = node.finishLiteral(token);
            } else if (type === Token.Template) {
                expr = parseTemplateLiteral();
            } else {
                throwUnexpectedToken(lex());
            }
    
            return expr;
        }
    
        // ECMA-262 12.3 Left-Hand-Side Expressions
    
        function parseArguments() {
            var args = [], expr;
    
            expect('(');
    
            if (!match(')')) {
                while (startIndex < length) {
                    if (match('...')) {
                        expr = new Node();
                        lex();
                        expr.finishSpreadElement(isolateCoverGrammar(parseAssignmentExpression));
                    } else {
                        expr = isolateCoverGrammar(parseAssignmentExpression);
                    }
                    args.push(expr);
                    if (match(')')) {
                        break;
                    }
                    expectCommaSeparator();
                }
            }
    
            expect(')');
    
            return args;
        }
    
        function parseNonComputedProperty() {
            var token, node = new Node();
    
            token = lex();
    
            if (!isIdentifierName(token)) {
                throwUnexpectedToken(token);
            }
    
            return node.finishIdentifier(token.value);
        }
    
        function parseNonComputedMember() {
            expect('.');
    
            return parseNonComputedProperty();
        }
    
        function parseComputedMember() {
            var expr;
    
            expect('[');
    
            expr = isolateCoverGrammar(parseExpression);
    
            expect(']');
    
            return expr;
        }
    
        // ECMA-262 12.3.3 The new Operator
    
        function parseNewExpression() {
            var callee, args, node = new Node();
    
            expectKeyword('new');
    
            if (match('.')) {
                lex();
                if (lookahead.type === Token.Identifier && lookahead.value === 'target') {
                    if (state.inFunctionBody) {
                        lex();
                        return node.finishMetaProperty('new', 'target');
                    }
                }
                throwUnexpectedToken(lookahead);
            }
    
            callee = isolateCoverGrammar(parseLeftHandSideExpression);
            args = match('(') ? parseArguments() : [];
    
            isAssignmentTarget = isBindingElement = false;
    
            return node.finishNewExpression(callee, args);
        }
    
        // ECMA-262 12.3.4 Function Calls
    
        function parseLeftHandSideExpressionAllowCall() {
            var quasi, expr, args, property, startToken, previousAllowIn = state.allowIn;
    
            startToken = lookahead;
            state.allowIn = true;
    
            if (matchKeyword('super') && state.inFunctionBody) {
                expr = new Node();
                lex();
                expr = expr.finishSuper();
                if (!match('(') && !match('.') && !match('[')) {
                    throwUnexpectedToken(lookahead);
                }
            } else {
                expr = inheritCoverGrammar(matchKeyword('new') ? parseNewExpression : parsePrimaryExpression);
            }
    
            for (;;) {
                if (match('.')) {
                    isBindingElement = false;
                    isAssignmentTarget = true;
                    property = parseNonComputedMember();
                    expr = new WrappingNode(startToken).finishMemberExpression('.', expr, property);
                } else if (match('(')) {
                    isBindingElement = false;
                    isAssignmentTarget = false;
                    args = parseArguments();
                    expr = new WrappingNode(startToken).finishCallExpression(expr, args);
                } else if (match('[')) {
                    isBindingElement = false;
                    isAssignmentTarget = true;
                    property = parseComputedMember();
                    expr = new WrappingNode(startToken).finishMemberExpression('[', expr, property);
                } else if (lookahead.type === Token.Template && lookahead.head) {
                    quasi = parseTemplateLiteral();
                    expr = new WrappingNode(startToken).finishTaggedTemplateExpression(expr, quasi);
                } else {
                    break;
                }
            }
            state.allowIn = previousAllowIn;
    
            return expr;
        }
    
        // ECMA-262 12.3 Left-Hand-Side Expressions
    
        function parseLeftHandSideExpression() {
            var quasi, expr, property, startToken;
            assert(state.allowIn, 'callee of new expression always allow in keyword.');
    
            startToken = lookahead;
    
            if (matchKeyword('super') && state.inFunctionBody) {
                expr = new Node();
                lex();
                expr = expr.finishSuper();
                if (!match('[') && !match('.')) {
                    throwUnexpectedToken(lookahead);
                }
            } else {
                expr = inheritCoverGrammar(matchKeyword('new') ? parseNewExpression : parsePrimaryExpression);
            }
    
            for (;;) {
                if (match('[')) {
                    isBindingElement = false;
                    isAssignmentTarget = true;
                    property = parseComputedMember();
                    expr = new WrappingNode(startToken).finishMemberExpression('[', expr, property);
                } else if (match('.')) {
                    isBindingElement = false;
                    isAssignmentTarget = true;
                    property = parseNonComputedMember();
                    expr = new WrappingNode(startToken).finishMemberExpression('.', expr, property);
                } else if (lookahead.type === Token.Template && lookahead.head) {
                    quasi = parseTemplateLiteral();
                    expr = new WrappingNode(startToken).finishTaggedTemplateExpression(expr, quasi);
                } else {
                    break;
                }
            }
            return expr;
        }
    
        // ECMA-262 12.4 Postfix Expressions
    
        function parsePostfixExpression() {
            var expr, token, startToken = lookahead;
    
            expr = inheritCoverGrammar(parseLeftHandSideExpressionAllowCall);
    
            if (!hasLineTerminator && lookahead.type === Token.Punctuator) {
                if (match('++') || match('--')) {
                    // ECMA-262 11.3.1, 11.3.2
                    if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) {
                        tolerateError(Messages.StrictLHSPostfix);
                    }
    
                    if (!isAssignmentTarget) {
                        tolerateError(Messages.InvalidLHSInAssignment);
                    }
    
                    isAssignmentTarget = isBindingElement = false;
    
                    token = lex();
                    expr = new WrappingNode(startToken).finishPostfixExpression(token.value, expr);
                }
            }
    
            return expr;
        }
    
        // ECMA-262 12.5 Unary Operators
    
        function parseUnaryExpression() {
            var token, expr, startToken;
    
            if (lookahead.type !== Token.Punctuator && lookahead.type !== Token.Keyword) {
                expr = parsePostfixExpression();
            } else if (match('++') || match('--')) {
                startToken = lookahead;
                token = lex();
                expr = inheritCoverGrammar(parseUnaryExpression);
                // ECMA-262 11.4.4, 11.4.5
                if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) {
                    tolerateError(Messages.StrictLHSPrefix);
                }
    
                if (!isAssignmentTarget) {
                    tolerateError(Messages.InvalidLHSInAssignment);
                }
                expr = new WrappingNode(startToken).finishUnaryExpression(token.value, expr);
                isAssignmentTarget = isBindingElement = false;
            } else if (match('+') || match('-') || match('~') || match('!')) {
                startToken = lookahead;
                token = lex();
                expr = inheritCoverGrammar(parseUnaryExpression);
                expr = new WrappingNode(startToken).finishUnaryExpression(token.value, expr);
                isAssignmentTarget = isBindingElement = false;
            } else if (matchKeyword('delete') || matchKeyword('void') || matchKeyword('typeof')) {
                startToken = lookahead;
                token = lex();
                expr = inheritCoverGrammar(parseUnaryExpression);
                expr = new WrappingNode(startToken).finishUnaryExpression(token.value, expr);
                if (strict && expr.operator === 'delete' && expr.argument.type === Syntax.Identifier) {
                    tolerateError(Messages.StrictDelete);
                }
                isAssignmentTarget = isBindingElement = false;
            } else {
                expr = parsePostfixExpression();
            }
    
            return expr;
        }
    
        function binaryPrecedence(token, allowIn) {
            var prec = 0;
    
            if (token.type !== Token.Punctuator && token.type !== Token.Keyword) {
                return 0;
            }
    
            switch (token.value) {
            case '||':
                prec = 1;
                break;
    
            case '&&':
                prec = 2;
                break;
    
            case '|':
                prec = 3;
                break;
    
            case '^':
                prec = 4;
                break;
    
            case '&':
                prec = 5;
                break;
    
            case '==':
            case '!=':
            case '===':
            case '!==':
                prec = 6;
                break;
    
            case '<':
            case '>':
            case '<=':
            case '>=':
            case 'instanceof':
                prec = 7;
                break;
    
            case 'in':
                prec = allowIn ? 7 : 0;
                break;
    
            case '<<':
            case '>>':
            case '>>>':
                prec = 8;
                break;
    
            case '+':
            case '-':
                prec = 9;
                break;
    
            case '*':
            case '/':
            case '%':
                prec = 11;
                break;
    
            default:
                break;
            }
    
            return prec;
        }
    
        // ECMA-262 12.6 Multiplicative Operators
        // ECMA-262 12.7 Additive Operators
        // ECMA-262 12.8 Bitwise Shift Operators
        // ECMA-262 12.9 Relational Operators
        // ECMA-262 12.10 Equality Operators
        // ECMA-262 12.11 Binary Bitwise Operators
        // ECMA-262 12.12 Binary Logical Operators
    
        function parseBinaryExpression() {
            var marker, markers, expr, token, prec, stack, right, operator, left, i;
    
            marker = lookahead;
            left = inheritCoverGrammar(parseUnaryExpression);
    
            token = lookahead;
            prec = binaryPrecedence(token, state.allowIn);
            if (prec === 0) {
                return left;
            }
            isAssignmentTarget = isBindingElement = false;
            token.prec = prec;
            lex();
    
            markers = [marker, lookahead];
            right = isolateCoverGrammar(parseUnaryExpression);
    
            stack = [left, token, right];
    
            while ((prec = binaryPrecedence(lookahead, state.allowIn)) > 0) {
    
                // Reduce: make a binary expression from the three topmost entries.
                while ((stack.length > 2) && (prec <= stack[stack.length - 2].prec)) {
                    right = stack.pop();
                    operator = stack.pop().value;
                    left = stack.pop();
                    markers.pop();
                    expr = new WrappingNode(markers[markers.length - 1]).finishBinaryExpression(operator, left, right);
                    stack.push(expr);
                }
    
                // Shift.
                token = lex();
                token.prec = prec;
                stack.push(token);
                markers.push(lookahead);
                expr = isolateCoverGrammar(parseUnaryExpression);
                stack.push(expr);
            }
    
            // Final reduce to clean-up the stack.
            i = stack.length - 1;
            expr = stack[i];
            markers.pop();
            while (i > 1) {
                expr = new WrappingNode(markers.pop()).finishBinaryExpression(stack[i - 1].value, stack[i - 2], expr);
                i -= 2;
            }
    
            return expr;
        }
    
    
        // ECMA-262 12.13 Conditional Operator
    
        function parseConditionalExpression() {
            var expr, previousAllowIn, consequent, alternate, startToken;
    
            startToken = lookahead;
    
            expr = inheritCoverGrammar(parseBinaryExpression);
            if (match('?')) {
                lex();
                previousAllowIn = state.allowIn;
                state.allowIn = true;
                consequent = isolateCoverGrammar(parseAssignmentExpression);
                state.allowIn = previousAllowIn;
                expect(':');
                alternate = isolateCoverGrammar(parseAssignmentExpression);
    
                expr = new WrappingNode(startToken).finishConditionalExpression(expr, consequent, alternate);
                isAssignmentTarget = isBindingElement = false;
            }
    
            return expr;
        }
    
        // ECMA-262 14.2 Arrow Function Definitions
    
        function parseConciseBody() {
            if (match('{')) {
                return parseFunctionSourceElements();
            }
            return isolateCoverGrammar(parseAssignmentExpression);
        }
    
        function checkPatternParam(options, param) {
            var i;
            switch (param.type) {
            case Syntax.Identifier:
                validateParam(options, param, param.name);
                break;
            case Syntax.RestElement:
                checkPatternParam(options, param.argument);
                break;
            case Syntax.AssignmentPattern:
                checkPatternParam(options, param.left);
                break;
            case Syntax.ArrayPattern:
                for (i = 0; i < param.elements.length; i++) {
                    if (param.elements[i] !== null) {
                        checkPatternParam(options, param.elements[i]);
                    }
                }
                break;
            case Syntax.YieldExpression:
                break;
            default:
                assert(param.type === Syntax.ObjectPattern, 'Invalid type');
                for (i = 0; i < param.properties.length; i++) {
                    checkPatternParam(options, param.properties[i].value);
                }
                break;
            }
        }
        function reinterpretAsCoverFormalsList(expr) {
            var i, len, param, params, defaults, defaultCount, options, token;
    
            defaults = [];
            defaultCount = 0;
            params = [expr];
    
            switch (expr.type) {
            case Syntax.Identifier:
                break;
            case PlaceHolders.ArrowParameterPlaceHolder:
                params = expr.params;
                break;
            default:
                return null;
            }
    
            options = {
                paramSet: {}
            };
    
            for (i = 0, len = params.length; i < len; i += 1) {
                param = params[i];
                switch (param.type) {
                case Syntax.AssignmentPattern:
                    params[i] = param.left;
                    if (param.right.type === Syntax.YieldExpression) {
                        if (param.right.argument) {
                            throwUnexpectedToken(lookahead);
                        }
                        param.right.type = Syntax.Identifier;
                        param.right.name = 'yield';
                        delete param.right.argument;
                        delete param.right.delegate;
                    }
                    defaults.push(param.right);
                    ++defaultCount;
                    checkPatternParam(options, param.left);
                    break;
                default:
                    checkPatternParam(options, param);
                    params[i] = param;
                    defaults.push(null);
                    break;
                }
            }
    
            if (strict || !state.allowYield) {
                for (i = 0, len = params.length; i < len; i += 1) {
                    param = params[i];
                    if (param.type === Syntax.YieldExpression) {
                        throwUnexpectedToken(lookahead);
                    }
                }
            }
    
            if (options.message === Messages.StrictParamDupe) {
                token = strict ? options.stricted : options.firstRestricted;
                throwUnexpectedToken(token, options.message);
            }
    
            if (defaultCount === 0) {
                defaults = [];
            }
    
            return {
                params: params,
                defaults: defaults,
                stricted: options.stricted,
                firstRestricted: options.firstRestricted,
                message: options.message
            };
        }
    
        function parseArrowFunctionExpression(options, node) {
            var previousStrict, previousAllowYield, body;
    
            if (hasLineTerminator) {
                tolerateUnexpectedToken(lookahead);
            }
            expect('=>');
    
            previousStrict = strict;
            previousAllowYield = state.allowYield;
            state.allowYield = true;
    
            body = parseConciseBody();
    
            if (strict && options.firstRestricted) {
                throwUnexpectedToken(options.firstRestricted, options.message);
            }
            if (strict && options.stricted) {
                tolerateUnexpectedToken(options.stricted, options.message);
            }
    
            strict = previousStrict;
            state.allowYield = previousAllowYield;
    
            return node.finishArrowFunctionExpression(options.params, options.defaults, body, body.type !== Syntax.BlockStatement);
        }
    
        // ECMA-262 14.4 Yield expression
    
        function parseYieldExpression() {
            var argument, expr, delegate, previousAllowYield;
    
            argument = null;
            expr = new Node();
            delegate = false;
    
            expectKeyword('yield');
    
            if (!hasLineTerminator) {
                previousAllowYield = state.allowYield;
                state.allowYield = false;
                delegate = match('*');
                if (delegate) {
                    lex();
                    argument = parseAssignmentExpression();
                } else {
                    if (!match(';') && !match('}') && !match(')') && lookahead.type !== Token.EOF) {
                        argument = parseAssignmentExpression();
                    }
                }
                state.allowYield = previousAllowYield;
            }
    
            return expr.finishYieldExpression(argument, delegate);
        }
    
        // ECMA-262 12.14 Assignment Operators
    
        function parseAssignmentExpression() {
            var token, expr, right, list, startToken;
    
            startToken = lookahead;
            token = lookahead;
    
            if (!state.allowYield && matchKeyword('yield')) {
                return parseYieldExpression();
            }
    
            expr = parseConditionalExpression();
    
            if (expr.type === PlaceHolders.ArrowParameterPlaceHolder || match('=>')) {
                isAssignmentTarget = isBindingElement = false;
                list = reinterpretAsCoverFormalsList(expr);
    
                if (list) {
                    firstCoverInitializedNameError = null;
                    return parseArrowFunctionExpression(list, new WrappingNode(startToken));
                }
    
                return expr;
            }
    
            if (matchAssign()) {
                if (!isAssignmentTarget) {
                    tolerateError(Messages.InvalidLHSInAssignment);
                }
    
                // ECMA-262 12.1.1
                if (strict && expr.type === Syntax.Identifier) {
                    if (isRestrictedWord(expr.name)) {
                        tolerateUnexpectedToken(token, Messages.StrictLHSAssignment);
                    }
                    if (isStrictModeReservedWord(expr.name)) {
                        tolerateUnexpectedToken(token, Messages.StrictReservedWord);
                    }
                }
    
                if (!match('=')) {
                    isAssignmentTarget = isBindingElement = false;
                } else {
                    reinterpretExpressionAsPattern(expr);
                }
    
                token = lex();
                right = isolateCoverGrammar(parseAssignmentExpression);
                expr = new WrappingNode(startToken).finishAssignmentExpression(token.value, expr, right);
                firstCoverInitializedNameError = null;
            }
    
            return expr;
        }
    
        // ECMA-262 12.15 Comma Operator
    
        function parseExpression() {
            var expr, startToken = lookahead, expressions;
    
            expr = isolateCoverGrammar(parseAssignmentExpression);
    
            if (match(',')) {
                expressions = [expr];
    
                while (startIndex < length) {
                    if (!match(',')) {
                        break;
                    }
                    lex();
                    expressions.push(isolateCoverGrammar(parseAssignmentExpression));
                }
    
                expr = new WrappingNode(startToken).finishSequenceExpression(expressions);
            }
    
            return expr;
        }
    
        // ECMA-262 13.2 Block
    
        function parseStatementListItem() {
            if (lookahead.type === Token.Keyword) {
                switch (lookahead.value) {
                case 'export':
                    if (state.sourceType !== 'module') {
                        tolerateUnexpectedToken(lookahead, Messages.IllegalExportDeclaration);
                    }
                    return parseExportDeclaration();
                case 'import':
                    if (state.sourceType !== 'module') {
                        tolerateUnexpectedToken(lookahead, Messages.IllegalImportDeclaration);
                    }
                    return parseImportDeclaration();
                case 'const':
                    return parseLexicalDeclaration({inFor: false});
                case 'function':
                    return parseFunctionDeclaration(new Node());
                case 'class':
                    return parseClassDeclaration();
                }
            }
    
            if (matchKeyword('let') && isLexicalDeclaration()) {
                return parseLexicalDeclaration({inFor: false});
            }
    
            return parseStatement();
        }
    
        function parseStatementList() {
            var list = [];
            while (startIndex < length) {
                if (match('}')) {
                    break;
                }
                list.push(parseStatementListItem());
            }
    
            return list;
        }
    
        function parseBlock() {
            var block, node = new Node();
    
            expect('{');
    
            block = parseStatementList();
    
            expect('}');
    
            return node.finishBlockStatement(block);
        }
    
        // ECMA-262 13.3.2 Variable Statement
    
        function parseVariableIdentifier(kind) {
            var token, node = new Node();
    
            token = lex();
    
            if (token.type === Token.Keyword && token.value === 'yield') {
                if (strict) {
                    tolerateUnexpectedToken(token, Messages.StrictReservedWord);
                } if (!state.allowYield) {
                    throwUnexpectedToken(token);
                }
            } else if (token.type !== Token.Identifier) {
                if (strict && token.type === Token.Keyword && isStrictModeReservedWord(token.value)) {
                    tolerateUnexpectedToken(token, Messages.StrictReservedWord);
                } else {
                    if (strict || token.value !== 'let' || kind !== 'var') {
                        throwUnexpectedToken(token);
                    }
                }
            } else if (state.sourceType === 'module' && token.type === Token.Identifier && token.value === 'await') {
                tolerateUnexpectedToken(token);
            }
    
            return node.finishIdentifier(token.value);
        }
    
        function parseVariableDeclaration(options) {
            var init = null, id, node = new Node(), params = [];
    
            id = parsePattern(params, 'var');
    
            // ECMA-262 12.2.1
            if (strict && isRestrictedWord(id.name)) {
                tolerateError(Messages.StrictVarName);
            }
    
            if (match('=')) {
                lex();
                init = isolateCoverGrammar(parseAssignmentExpression);
            } else if (id.type !== Syntax.Identifier && !options.inFor) {
                expect('=');
            }
    
            return node.finishVariableDeclarator(id, init);
        }
    
        function parseVariableDeclarationList(options) {
            var opt, list;
    
            opt = { inFor: options.inFor };
            list = [parseVariableDeclaration(opt)];
    
            while (match(',')) {
                lex();
                list.push(parseVariableDeclaration(opt));
            }
    
            return list;
        }
    
        function parseVariableStatement(node) {
            var declarations;
    
            expectKeyword('var');
    
            declarations = parseVariableDeclarationList({ inFor: false });
    
            consumeSemicolon();
    
            return node.finishVariableDeclaration(declarations);
        }
    
        // ECMA-262 13.3.1 Let and Const Declarations
    
        function parseLexicalBinding(kind, options) {
            var init = null, id, node = new Node(), params = [];
    
            id = parsePattern(params, kind);
    
            // ECMA-262 12.2.1
            if (strict && id.type === Syntax.Identifier && isRestrictedWord(id.name)) {
                tolerateError(Messages.StrictVarName);
            }
    
            if (kind === 'const') {
                if (!matchKeyword('in') && !matchContextualKeyword('of')) {
                    expect('=');
                    init = isolateCoverGrammar(parseAssignmentExpression);
                }
            } else if ((!options.inFor && id.type !== Syntax.Identifier) || match('=')) {
                expect('=');
                init = isolateCoverGrammar(parseAssignmentExpression);
            }
    
            return node.finishVariableDeclarator(id, init);
        }
    
        function parseBindingList(kind, options) {
            var list = [parseLexicalBinding(kind, options)];
    
            while (match(',')) {
                lex();
                list.push(parseLexicalBinding(kind, options));
            }
    
            return list;
        }
    
    
        function tokenizerState() {
            return {
                index: index,
                lineNumber: lineNumber,
                lineStart: lineStart,
                hasLineTerminator: hasLineTerminator,
                lastIndex: lastIndex,
                lastLineNumber: lastLineNumber,
                lastLineStart: lastLineStart,
                startIndex: startIndex,
                startLineNumber: startLineNumber,
                startLineStart: startLineStart,
                lookahead: lookahead,
                tokenCount: extra.tokens ? extra.tokens.length : 0
            };
        }
    
        function resetTokenizerState(ts) {
            index = ts.index;
            lineNumber = ts.lineNumber;
            lineStart = ts.lineStart;
            hasLineTerminator = ts.hasLineTerminator;
            lastIndex = ts.lastIndex;
            lastLineNumber = ts.lastLineNumber;
            lastLineStart = ts.lastLineStart;
            startIndex = ts.startIndex;
            startLineNumber = ts.startLineNumber;
            startLineStart = ts.startLineStart;
            lookahead = ts.lookahead;
            if (extra.tokens) {
                extra.tokens.splice(ts.tokenCount, extra.tokens.length);
            }
        }
    
        function isLexicalDeclaration() {
            var lexical, ts;
    
            ts = tokenizerState();
    
            lex();
            lexical = (lookahead.type === Token.Identifier) || match('[') || match('{') ||
                matchKeyword('let') || matchKeyword('yield');
    
            resetTokenizerState(ts);
    
            return lexical;
        }
    
        function parseLexicalDeclaration(options) {
            var kind, declarations, node = new Node();
    
            kind = lex().value;
            assert(kind === 'let' || kind === 'const', 'Lexical declaration must be either let or const');
    
            declarations = parseBindingList(kind, options);
    
            consumeSemicolon();
    
            return node.finishLexicalDeclaration(declarations, kind);
        }
    
        function parseRestElement(params) {
            var param, node = new Node();
    
            lex();
    
            if (match('{')) {
                throwError(Messages.ObjectPatternAsRestParameter);
            }
    
            params.push(lookahead);
    
            param = parseVariableIdentifier();
    
            if (match('=')) {
                throwError(Messages.DefaultRestParameter);
            }
    
            if (!match(')')) {
                throwError(Messages.ParameterAfterRestParameter);
            }
    
            return node.finishRestElement(param);
        }
    
        // ECMA-262 13.4 Empty Statement
    
        function parseEmptyStatement(node) {
            expect(';');
            return node.finishEmptyStatement();
        }
    
        // ECMA-262 12.4 Expression Statement
    
        function parseExpressionStatement(node) {
            var expr = parseExpression();
            consumeSemicolon();
            return node.finishExpressionStatement(expr);
        }
    
        // ECMA-262 13.6 If statement
    
        function parseIfStatement(node) {
            var test, consequent, alternate;
    
            expectKeyword('if');
    
            expect('(');
    
            test = parseExpression();
    
            expect(')');
    
            consequent = parseStatement();
    
            if (matchKeyword('else')) {
                lex();
                alternate = parseStatement();
            } else {
                alternate = null;
            }
    
            return node.finishIfStatement(test, consequent, alternate);
        }
    
        // ECMA-262 13.7 Iteration Statements
    
        function parseDoWhileStatement(node) {
            var body, test, oldInIteration;
    
            expectKeyword('do');
    
            oldInIteration = state.inIteration;
            state.inIteration = true;
    
            body = parseStatement();
    
            state.inIteration = oldInIteration;
    
            expectKeyword('while');
    
            expect('(');
    
            test = parseExpression();
    
            expect(')');
    
            if (match(';')) {
                lex();
            }
    
            return node.finishDoWhileStatement(body, test);
        }
    
        function parseWhileStatement(node) {
            var test, body, oldInIteration;
    
            expectKeyword('while');
    
            expect('(');
    
            test = parseExpression();
    
            expect(')');
    
            oldInIteration = state.inIteration;
            state.inIteration = true;
    
            body = parseStatement();
    
            state.inIteration = oldInIteration;
    
            return node.finishWhileStatement(test, body);
        }
    
        function parseForStatement(node) {
            var init, forIn, initSeq, initStartToken, test, update, left, right, kind, declarations,
                body, oldInIteration, previousAllowIn = state.allowIn;
    
            init = test = update = null;
            forIn = true;
    
            expectKeyword('for');
    
            expect('(');
    
            if (match(';')) {
                lex();
            } else {
                if (matchKeyword('var')) {
                    init = new Node();
                    lex();
    
                    state.allowIn = false;
                    declarations = parseVariableDeclarationList({ inFor: true });
                    state.allowIn = previousAllowIn;
    
                    if (declarations.length === 1 && matchKeyword('in')) {
                        init = init.finishVariableDeclaration(declarations);
                        lex();
                        left = init;
                        right = parseExpression();
                        init = null;
                    } else if (declarations.length === 1 && declarations[0].init === null && matchContextualKeyword('of')) {
                        init = init.finishVariableDeclaration(declarations);
                        lex();
                        left = init;
                        right = parseAssignmentExpression();
                        init = null;
                        forIn = false;
                    } else {
                        init = init.finishVariableDeclaration(declarations);
                        expect(';');
                    }
                } else if (matchKeyword('const') || matchKeyword('let')) {
                    init = new Node();
                    kind = lex().value;
    
                    if (!strict && lookahead.value === 'in') {
                        init = init.finishIdentifier(kind);
                        lex();
                        left = init;
                        right = parseExpression();
                        init = null;
                    } else {
                        state.allowIn = false;
                        declarations = parseBindingList(kind, {inFor: true});
                        state.allowIn = previousAllowIn;
    
                        if (declarations.length === 1 && declarations[0].init === null && matchKeyword('in')) {
                            init = init.finishLexicalDeclaration(declarations, kind);
                            lex();
                            left = init;
                            right = parseExpression();
                            init = null;
                        } else if (declarations.length === 1 && declarations[0].init === null && matchContextualKeyword('of')) {
                            init = init.finishLexicalDeclaration(declarations, kind);
                            lex();
                            left = init;
                            right = parseAssignmentExpression();
                            init = null;
                            forIn = false;
                        } else {
                            consumeSemicolon();
                            init = init.finishLexicalDeclaration(declarations, kind);
                        }
                    }
                } else {
                    initStartToken = lookahead;
                    state.allowIn = false;
                    init = inheritCoverGrammar(parseAssignmentExpression);
                    state.allowIn = previousAllowIn;
    
                    if (matchKeyword('in')) {
                        if (!isAssignmentTarget) {
                            tolerateError(Messages.InvalidLHSInForIn);
                        }
    
                        lex();
                        reinterpretExpressionAsPattern(init);
                        left = init;
                        right = parseExpression();
                        init = null;
                    } else if (matchContextualKeyword('of')) {
                        if (!isAssignmentTarget) {
                            tolerateError(Messages.InvalidLHSInForLoop);
                        }
    
                        lex();
                        reinterpretExpressionAsPattern(init);
                        left = init;
                        right = parseAssignmentExpression();
                        init = null;
                        forIn = false;
                    } else {
                        if (match(',')) {
                            initSeq = [init];
                            while (match(',')) {
                                lex();
                                initSeq.push(isolateCoverGrammar(parseAssignmentExpression));
                            }
                            init = new WrappingNode(initStartToken).finishSequenceExpression(initSeq);
                        }
                        expect(';');
                    }
                }
            }
    
            if (typeof left === 'undefined') {
    
                if (!match(';')) {
                    test = parseExpression();
                }
                expect(';');
    
                if (!match(')')) {
                    update = parseExpression();
                }
            }
    
            expect(')');
    
            oldInIteration = state.inIteration;
            state.inIteration = true;
    
            body = isolateCoverGrammar(parseStatement);
    
            state.inIteration = oldInIteration;
    
            return (typeof left === 'undefined') ?
                    node.finishForStatement(init, test, update, body) :
                    forIn ? node.finishForInStatement(left, right, body) :
                        node.finishForOfStatement(left, right, body);
        }
    
        // ECMA-262 13.8 The continue statement
    
        function parseContinueStatement(node) {
            var label = null, key;
    
            expectKeyword('continue');
    
            // Optimize the most common form: 'continue;'.
            if (source.charCodeAt(startIndex) === 0x3B) {
                lex();
    
                if (!state.inIteration) {
                    throwError(Messages.IllegalContinue);
                }
    
                return node.finishContinueStatement(null);
            }
    
            if (hasLineTerminator) {
                if (!state.inIteration) {
                    throwError(Messages.IllegalContinue);
                }
    
                return node.finishContinueStatement(null);
            }
    
            if (lookahead.type === Token.Identifier) {
                label = parseVariableIdentifier();
    
                key = '$' + label.name;
                if (!Object.prototype.hasOwnProperty.call(state.labelSet, key)) {
                    throwError(Messages.UnknownLabel, label.name);
                }
            }
    
            consumeSemicolon();
    
            if (label === null && !state.inIteration) {
                throwError(Messages.IllegalContinue);
            }
    
            return node.finishContinueStatement(label);
        }
    
        // ECMA-262 13.9 The break statement
    
        function parseBreakStatement(node) {
            var label = null, key;
    
            expectKeyword('break');
    
            // Catch the very common case first: immediately a semicolon (U+003B).
            if (source.charCodeAt(lastIndex) === 0x3B) {
                lex();
    
                if (!(state.inIteration || state.inSwitch)) {
                    throwError(Messages.IllegalBreak);
                }
    
                return node.finishBreakStatement(null);
            }
    
            if (hasLineTerminator) {
                if (!(state.inIteration || state.inSwitch)) {
                    throwError(Messages.IllegalBreak);
                }
            } else if (lookahead.type === Token.Identifier) {
                label = parseVariableIdentifier();
    
                key = '$' + label.name;
                if (!Object.prototype.hasOwnProperty.call(state.labelSet, key)) {
                    throwError(Messages.UnknownLabel, label.name);
                }
            }
    
            consumeSemicolon();
    
            if (label === null && !(state.inIteration || state.inSwitch)) {
                throwError(Messages.IllegalBreak);
            }
    
            return node.finishBreakStatement(label);
        }
    
        // ECMA-262 13.10 The return statement
    
        function parseReturnStatement(node) {
            var argument = null;
    
            expectKeyword('return');
    
            if (!state.inFunctionBody) {
                tolerateError(Messages.IllegalReturn);
            }
    
            // 'return' followed by a space and an identifier is very common.
            if (source.charCodeAt(lastIndex) === 0x20) {
                if (isIdentifierStart(source.charCodeAt(lastIndex + 1))) {
                    argument = parseExpression();
                    consumeSemicolon();
                    return node.finishReturnStatement(argument);
                }
            }
    
            if (hasLineTerminator) {
                // HACK
                return node.finishReturnStatement(null);
            }
    
            if (!match(';')) {
                if (!match('}') && lookahead.type !== Token.EOF) {
                    argument = parseExpression();
                }
            }
    
            consumeSemicolon();
    
            return node.finishReturnStatement(argument);
        }
    
        // ECMA-262 13.11 The with statement
    
        function parseWithStatement(node) {
            var object, body;
    
            if (strict) {
                tolerateError(Messages.StrictModeWith);
            }
    
            expectKeyword('with');
    
            expect('(');
    
            object = parseExpression();
    
            expect(')');
    
            body = parseStatement();
    
            return node.finishWithStatement(object, body);
        }
    
        // ECMA-262 13.12 The switch statement
    
        function parseSwitchCase() {
            var test, consequent = [], statement, node = new Node();
    
            if (matchKeyword('default')) {
                lex();
                test = null;
            } else {
                expectKeyword('case');
                test = parseExpression();
            }
            expect(':');
    
            while (startIndex < length) {
                if (match('}') || matchKeyword('default') || matchKeyword('case')) {
                    break;
                }
                statement = parseStatementListItem();
                consequent.push(statement);
            }
    
            return node.finishSwitchCase(test, consequent);
        }
    
        function parseSwitchStatement(node) {
            var discriminant, cases, clause, oldInSwitch, defaultFound;
    
            expectKeyword('switch');
    
            expect('(');
    
            discriminant = parseExpression();
    
            expect(')');
    
            expect('{');
    
            cases = [];
    
            if (match('}')) {
                lex();
                return node.finishSwitchStatement(discriminant, cases);
            }
    
            oldInSwitch = state.inSwitch;
            state.inSwitch = true;
            defaultFound = false;
    
            while (startIndex < length) {
                if (match('}')) {
                    break;
                }
                clause = parseSwitchCase();
                if (clause.test === null) {
                    if (defaultFound) {
                        throwError(Messages.MultipleDefaultsInSwitch);
                    }
                    defaultFound = true;
                }
                cases.push(clause);
            }
    
            state.inSwitch = oldInSwitch;
    
            expect('}');
    
            return node.finishSwitchStatement(discriminant, cases);
        }
    
        // ECMA-262 13.14 The throw statement
    
        function parseThrowStatement(node) {
            var argument;
    
            expectKeyword('throw');
    
            if (hasLineTerminator) {
                throwError(Messages.NewlineAfterThrow);
            }
    
            argument = parseExpression();
    
            consumeSemicolon();
    
            return node.finishThrowStatement(argument);
        }
    
        // ECMA-262 13.15 The try statement
    
        function parseCatchClause() {
            var param, params = [], paramMap = {}, key, i, body, node = new Node();
    
            expectKeyword('catch');
    
            expect('(');
            if (match(')')) {
                throwUnexpectedToken(lookahead);
            }
    
            param = parsePattern(params);
            for (i = 0; i < params.length; i++) {
                key = '$' + params[i].value;
                if (Object.prototype.hasOwnProperty.call(paramMap, key)) {
                    tolerateError(Messages.DuplicateBinding, params[i].value);
                }
                paramMap[key] = true;
            }
    
            // ECMA-262 12.14.1
            if (strict && isRestrictedWord(param.name)) {
                tolerateError(Messages.StrictCatchVariable);
            }
    
            expect(')');
            body = parseBlock();
            return node.finishCatchClause(param, body);
        }
    
        function parseTryStatement(node) {
            var block, handler = null, finalizer = null;
    
            expectKeyword('try');
    
            block = parseBlock();
    
            if (matchKeyword('catch')) {
                handler = parseCatchClause();
            }
    
            if (matchKeyword('finally')) {
                lex();
                finalizer = parseBlock();
            }
    
            if (!handler && !finalizer) {
                throwError(Messages.NoCatchOrFinally);
            }
    
            return node.finishTryStatement(block, handler, finalizer);
        }
    
        // ECMA-262 13.16 The debugger statement
    
        function parseDebuggerStatement(node) {
            expectKeyword('debugger');
    
            consumeSemicolon();
    
            return node.finishDebuggerStatement();
        }
    
        // 13 Statements
    
        function parseStatement() {
            var type = lookahead.type,
                expr,
                labeledBody,
                key,
                node;
    
            if (type === Token.EOF) {
                throwUnexpectedToken(lookahead);
            }
    
            if (type === Token.Punctuator && lookahead.value === '{') {
                return parseBlock();
            }
            isAssignmentTarget = isBindingElement = true;
            node = new Node();
    
            if (type === Token.Punctuator) {
                switch (lookahead.value) {
                case ';':
                    return parseEmptyStatement(node);
                case '(':
                    return parseExpressionStatement(node);
                default:
                    break;
                }
            } else if (type === Token.Keyword) {
                switch (lookahead.value) {
                case 'break':
                    return parseBreakStatement(node);
                case 'continue':
                    return parseContinueStatement(node);
                case 'debugger':
                    return parseDebuggerStatement(node);
                case 'do':
                    return parseDoWhileStatement(node);
                case 'for':
                    return parseForStatement(node);
                case 'function':
                    return parseFunctionDeclaration(node);
                case 'if':
                    return parseIfStatement(node);
                case 'return':
                    return parseReturnStatement(node);
                case 'switch':
                    return parseSwitchStatement(node);
                case 'throw':
                    return parseThrowStatement(node);
                case 'try':
                    return parseTryStatement(node);
                case 'var':
                    return parseVariableStatement(node);
                case 'while':
                    return parseWhileStatement(node);
                case 'with':
                    return parseWithStatement(node);
                default:
                    break;
                }
            }
    
            expr = parseExpression();
    
            // ECMA-262 12.12 Labelled Statements
            if ((expr.type === Syntax.Identifier) && match(':')) {
                lex();
    
                key = '$' + expr.name;
                if (Object.prototype.hasOwnProperty.call(state.labelSet, key)) {
                    throwError(Messages.Redeclaration, 'Label', expr.name);
                }
    
                state.labelSet[key] = true;
                labeledBody = parseStatement();
                delete state.labelSet[key];
                return node.finishLabeledStatement(expr, labeledBody);
            }
    
            consumeSemicolon();
    
            return node.finishExpressionStatement(expr);
        }
    
        // ECMA-262 14.1 Function Definition
    
        function parseFunctionSourceElements() {
            var statement, body = [], token, directive, firstRestricted,
                oldLabelSet, oldInIteration, oldInSwitch, oldInFunctionBody,
                node = new Node();
    
            expect('{');
    
            while (startIndex < length) {
                if (lookahead.type !== Token.StringLiteral) {
                    break;
                }
                token = lookahead;
    
                statement = parseStatementListItem();
                body.push(statement);
                if (statement.expression.type !== Syntax.Literal) {
                    // this is not directive
                    break;
                }
                directive = source.slice(token.start + 1, token.end - 1);
                if (directive === 'use strict') {
                    strict = true;
                    if (firstRestricted) {
                        tolerateUnexpectedToken(firstRestricted, Messages.StrictOctalLiteral);
                    }
                } else {
                    if (!firstRestricted && token.octal) {
                        firstRestricted = token;
                    }
                }
            }
    
            oldLabelSet = state.labelSet;
            oldInIteration = state.inIteration;
            oldInSwitch = state.inSwitch;
            oldInFunctionBody = state.inFunctionBody;
    
            state.labelSet = {};
            state.inIteration = false;
            state.inSwitch = false;
            state.inFunctionBody = true;
    
            while (startIndex < length) {
                if (match('}')) {
                    break;
                }
                body.push(parseStatementListItem());
            }
    
            expect('}');
    
            state.labelSet = oldLabelSet;
            state.inIteration = oldInIteration;
            state.inSwitch = oldInSwitch;
            state.inFunctionBody = oldInFunctionBody;
    
            return node.finishBlockStatement(body);
        }
    
        function validateParam(options, param, name) {
            var key = '$' + name;
            if (strict) {
                if (isRestrictedWord(name)) {
                    options.stricted = param;
                    options.message = Messages.StrictParamName;
                }
                if (Object.prototype.hasOwnProperty.call(options.paramSet, key)) {
                    options.stricted = param;
                    options.message = Messages.StrictParamDupe;
                }
            } else if (!options.firstRestricted) {
                if (isRestrictedWord(name)) {
                    options.firstRestricted = param;
                    options.message = Messages.StrictParamName;
                } else if (isStrictModeReservedWord(name)) {
                    options.firstRestricted = param;
                    options.message = Messages.StrictReservedWord;
                } else if (Object.prototype.hasOwnProperty.call(options.paramSet, key)) {
                    options.stricted = param;
                    options.message = Messages.StrictParamDupe;
                }
            }
            options.paramSet[key] = true;
        }
    
        function parseParam(options) {
            var token, param, params = [], i, def;
    
            token = lookahead;
            if (token.value === '...') {
                param = parseRestElement(params);
                validateParam(options, param.argument, param.argument.name);
                options.params.push(param);
                options.defaults.push(null);
                return false;
            }
    
            param = parsePatternWithDefault(params);
            for (i = 0; i < params.length; i++) {
                validateParam(options, params[i], params[i].value);
            }
    
            if (param.type === Syntax.AssignmentPattern) {
                def = param.right;
                param = param.left;
                ++options.defaultCount;
            }
    
            options.params.push(param);
            options.defaults.push(def);
    
            return !match(')');
        }
    
        function parseParams(firstRestricted) {
            var options;
    
            options = {
                params: [],
                defaultCount: 0,
                defaults: [],
                firstRestricted: firstRestricted
            };
    
            expect('(');
    
            if (!match(')')) {
                options.paramSet = {};
                while (startIndex < length) {
                    if (!parseParam(options)) {
                        break;
                    }
                    expect(',');
                }
            }
    
            expect(')');
    
            if (options.defaultCount === 0) {
                options.defaults = [];
            }
    
            return {
                params: options.params,
                defaults: options.defaults,
                stricted: options.stricted,
                firstRestricted: options.firstRestricted,
                message: options.message
            };
        }
    
        function parseFunctionDeclaration(node, identifierIsOptional) {
            var id = null, params = [], defaults = [], body, token, stricted, tmp, firstRestricted, message, previousStrict,
                isGenerator, previousAllowYield;
    
            previousAllowYield = state.allowYield;
    
            expectKeyword('function');
    
            isGenerator = match('*');
            if (isGenerator) {
                lex();
            }
    
            if (!identifierIsOptional || !match('(')) {
                token = lookahead;
                id = parseVariableIdentifier();
                if (strict) {
                    if (isRestrictedWord(token.value)) {
                        tolerateUnexpectedToken(token, Messages.StrictFunctionName);
                    }
                } else {
                    if (isRestrictedWord(token.value)) {
                        firstRestricted = token;
                        message = Messages.StrictFunctionName;
                    } else if (isStrictModeReservedWord(token.value)) {
                        firstRestricted = token;
                        message = Messages.StrictReservedWord;
                    }
                }
            }
    
            state.allowYield = !isGenerator;
            tmp = parseParams(firstRestricted);
            params = tmp.params;
            defaults = tmp.defaults;
            stricted = tmp.stricted;
            firstRestricted = tmp.firstRestricted;
            if (tmp.message) {
                message = tmp.message;
            }
    
    
            previousStrict = strict;
            body = parseFunctionSourceElements();
            if (strict && firstRestricted) {
                throwUnexpectedToken(firstRestricted, message);
            }
            if (strict && stricted) {
                tolerateUnexpectedToken(stricted, message);
            }
    
            strict = previousStrict;
            state.allowYield = previousAllowYield;
    
            return node.finishFunctionDeclaration(id, params, defaults, body, isGenerator);
        }
    
        function parseFunctionExpression() {
            var token, id = null, stricted, firstRestricted, message, tmp,
                params = [], defaults = [], body, previousStrict, node = new Node(),
                isGenerator, previousAllowYield;
    
            previousAllowYield = state.allowYield;
    
            expectKeyword('function');
    
            isGenerator = match('*');
            if (isGenerator) {
                lex();
            }
    
            state.allowYield = !isGenerator;
            if (!match('(')) {
                token = lookahead;
                id = (!strict && !isGenerator && matchKeyword('yield')) ? parseNonComputedProperty() : parseVariableIdentifier();
                if (strict) {
                    if (isRestrictedWord(token.value)) {
                        tolerateUnexpectedToken(token, Messages.StrictFunctionName);
                    }
                } else {
                    if (isRestrictedWord(token.value)) {
                        firstRestricted = token;
                        message = Messages.StrictFunctionName;
                    } else if (isStrictModeReservedWord(token.value)) {
                        firstRestricted = token;
                        message = Messages.StrictReservedWord;
                    }
                }
            }
    
            tmp = parseParams(firstRestricted);
            params = tmp.params;
            defaults = tmp.defaults;
            stricted = tmp.stricted;
            firstRestricted = tmp.firstRestricted;
            if (tmp.message) {
                message = tmp.message;
            }
    
            previousStrict = strict;
            body = parseFunctionSourceElements();
            if (strict && firstRestricted) {
                throwUnexpectedToken(firstRestricted, message);
            }
            if (strict && stricted) {
                tolerateUnexpectedToken(stricted, message);
            }
            strict = previousStrict;
            state.allowYield = previousAllowYield;
    
            return node.finishFunctionExpression(id, params, defaults, body, isGenerator);
        }
    
        // ECMA-262 14.5 Class Definitions
    
        function parseClassBody() {
            var classBody, token, isStatic, hasConstructor = false, body, method, computed, key;
    
            classBody = new Node();
    
            expect('{');
            body = [];
            while (!match('}')) {
                if (match(';')) {
                    lex();
                } else {
                    method = new Node();
                    token = lookahead;
                    isStatic = false;
                    computed = match('[');
                    if (match('*')) {
                        lex();
                    } else {
                        key = parseObjectPropertyKey();
                        if (key.name === 'static' && (lookaheadPropertyName() || match('*'))) {
                            token = lookahead;
                            isStatic = true;
                            computed = match('[');
                            if (match('*')) {
                                lex();
                            } else {
                                key = parseObjectPropertyKey();
                            }
                        }
                    }
                    method = tryParseMethodDefinition(token, key, computed, method);
                    if (method) {
                        method['static'] = isStatic; // jscs:ignore requireDotNotation
                        if (method.kind === 'init') {
                            method.kind = 'method';
                        }
                        if (!isStatic) {
                            if (!method.computed && (method.key.name || method.key.value.toString()) === 'constructor') {
                                if (method.kind !== 'method' || !method.method || method.value.generator) {
                                    throwUnexpectedToken(token, Messages.ConstructorSpecialMethod);
                                }
                                if (hasConstructor) {
                                    throwUnexpectedToken(token, Messages.DuplicateConstructor);
                                } else {
                                    hasConstructor = true;
                                }
                                method.kind = 'constructor';
                            }
                        } else {
                            if (!method.computed && (method.key.name || method.key.value.toString()) === 'prototype') {
                                throwUnexpectedToken(token, Messages.StaticPrototype);
                            }
                        }
                        method.type = Syntax.MethodDefinition;
                        delete method.method;
                        delete method.shorthand;
                        body.push(method);
                    } else {
                        throwUnexpectedToken(lookahead);
                    }
                }
            }
            lex();
            return classBody.finishClassBody(body);
        }
    
        function parseClassDeclaration(identifierIsOptional) {
            var id = null, superClass = null, classNode = new Node(), classBody, previousStrict = strict;
            strict = true;
    
            expectKeyword('class');
    
            if (!identifierIsOptional || lookahead.type === Token.Identifier) {
                id = parseVariableIdentifier();
            }
    
            if (matchKeyword('extends')) {
                lex();
                superClass = isolateCoverGrammar(parseLeftHandSideExpressionAllowCall);
            }
            classBody = parseClassBody();
            strict = previousStrict;
    
            return classNode.finishClassDeclaration(id, superClass, classBody);
        }
    
        function parseClassExpression() {
            var id = null, superClass = null, classNode = new Node(), classBody, previousStrict = strict;
            strict = true;
    
            expectKeyword('class');
    
            if (lookahead.type === Token.Identifier) {
                id = parseVariableIdentifier();
            }
    
            if (matchKeyword('extends')) {
                lex();
                superClass = isolateCoverGrammar(parseLeftHandSideExpressionAllowCall);
            }
            classBody = parseClassBody();
            strict = previousStrict;
    
            return classNode.finishClassExpression(id, superClass, classBody);
        }
    
        // ECMA-262 15.2 Modules
    
        function parseModuleSpecifier() {
            var node = new Node();
    
            if (lookahead.type !== Token.StringLiteral) {
                throwError(Messages.InvalidModuleSpecifier);
            }
            return node.finishLiteral(lex());
        }
    
        // ECMA-262 15.2.3 Exports
    
        function parseExportSpecifier() {
            var exported, local, node = new Node(), def;
            if (matchKeyword('default')) {
                // export {default} from 'something';
                def = new Node();
                lex();
                local = def.finishIdentifier('default');
            } else {
                local = parseVariableIdentifier();
            }
            if (matchContextualKeyword('as')) {
                lex();
                exported = parseNonComputedProperty();
            }
            return node.finishExportSpecifier(local, exported);
        }
    
        function parseExportNamedDeclaration(node) {
            var declaration = null,
                isExportFromIdentifier,
                src = null, specifiers = [];
    
            // non-default export
            if (lookahead.type === Token.Keyword) {
                // covers:
                // export var f = 1;
                switch (lookahead.value) {
                    case 'let':
                    case 'const':
                        declaration = parseLexicalDeclaration({inFor: false});
                        return node.finishExportNamedDeclaration(declaration, specifiers, null);
                    case 'var':
                    case 'class':
                    case 'function':
                        declaration = parseStatementListItem();
                        return node.finishExportNamedDeclaration(declaration, specifiers, null);
                }
            }
    
            expect('{');
            while (!match('}')) {
                isExportFromIdentifier = isExportFromIdentifier || matchKeyword('default');
                specifiers.push(parseExportSpecifier());
                if (!match('}')) {
                    expect(',');
                    if (match('}')) {
                        break;
                    }
                }
            }
            expect('}');
    
            if (matchContextualKeyword('from')) {
                // covering:
                // export {default} from 'foo';
                // export {foo} from 'foo';
                lex();
                src = parseModuleSpecifier();
                consumeSemicolon();
            } else if (isExportFromIdentifier) {
                // covering:
                // export {default}; // missing fromClause
                throwError(lookahead.value ?
                        Messages.UnexpectedToken : Messages.MissingFromClause, lookahead.value);
            } else {
                // cover
                // export {foo};
                consumeSemicolon();
            }
            return node.finishExportNamedDeclaration(declaration, specifiers, src);
        }
    
        function parseExportDefaultDeclaration(node) {
            var declaration = null,
                expression = null;
    
            // covers:
            // export default ...
            expectKeyword('default');
    
            if (matchKeyword('function')) {
                // covers:
                // export default function foo () {}
                // export default function () {}
                declaration = parseFunctionDeclaration(new Node(), true);
                return node.finishExportDefaultDeclaration(declaration);
            }
            if (matchKeyword('class')) {
                declaration = parseClassDeclaration(true);
                return node.finishExportDefaultDeclaration(declaration);
            }
    
            if (matchContextualKeyword('from')) {
                throwError(Messages.UnexpectedToken, lookahead.value);
            }
    
            // covers:
            // export default {};
            // export default [];
            // export default (1 + 2);
            if (match('{')) {
                expression = parseObjectInitializer();
            } else if (match('[')) {
                expression = parseArrayInitializer();
            } else {
                expression = parseAssignmentExpression();
            }
            consumeSemicolon();
            return node.finishExportDefaultDeclaration(expression);
        }
    
        function parseExportAllDeclaration(node) {
            var src;
    
            // covers:
            // export * from 'foo';
            expect('*');
            if (!matchContextualKeyword('from')) {
                throwError(lookahead.value ?
                        Messages.UnexpectedToken : Messages.MissingFromClause, lookahead.value);
            }
            lex();
            src = parseModuleSpecifier();
            consumeSemicolon();
    
            return node.finishExportAllDeclaration(src);
        }
    
        function parseExportDeclaration() {
            var node = new Node();
            if (state.inFunctionBody) {
                throwError(Messages.IllegalExportDeclaration);
            }
    
            expectKeyword('export');
    
            if (matchKeyword('default')) {
                return parseExportDefaultDeclaration(node);
            }
            if (match('*')) {
                return parseExportAllDeclaration(node);
            }
            return parseExportNamedDeclaration(node);
        }
    
        // ECMA-262 15.2.2 Imports
    
        function parseImportSpecifier() {
            // import {<foo as bar>} ...;
            var local, imported, node = new Node();
    
            imported = parseNonComputedProperty();
            if (matchContextualKeyword('as')) {
                lex();
                local = parseVariableIdentifier();
            }
    
            return node.finishImportSpecifier(local, imported);
        }
    
        function parseNamedImports() {
            var specifiers = [];
            // {foo, bar as bas}
            expect('{');
            while (!match('}')) {
                specifiers.push(parseImportSpecifier());
                if (!match('}')) {
                    expect(',');
                    if (match('}')) {
                        break;
                    }
                }
            }
            expect('}');
            return specifiers;
        }
    
        function parseImportDefaultSpecifier() {
            // import <foo> ...;
            var local, node = new Node();
    
            local = parseNonComputedProperty();
    
            return node.finishImportDefaultSpecifier(local);
        }
    
        function parseImportNamespaceSpecifier() {
            // import <* as foo> ...;
            var local, node = new Node();
    
            expect('*');
            if (!matchContextualKeyword('as')) {
                throwError(Messages.NoAsAfterImportNamespace);
            }
            lex();
            local = parseNonComputedProperty();
    
            return node.finishImportNamespaceSpecifier(local);
        }
    
        function parseImportDeclaration() {
            var specifiers = [], src, node = new Node();
    
            if (state.inFunctionBody) {
                throwError(Messages.IllegalImportDeclaration);
            }
    
            expectKeyword('import');
    
            if (lookahead.type === Token.StringLiteral) {
                // import 'foo';
                src = parseModuleSpecifier();
            } else {
    
                if (match('{')) {
                    // import {bar}
                    specifiers = specifiers.concat(parseNamedImports());
                } else if (match('*')) {
                    // import * as foo
                    specifiers.push(parseImportNamespaceSpecifier());
                } else if (isIdentifierName(lookahead) && !matchKeyword('default')) {
                    // import foo
                    specifiers.push(parseImportDefaultSpecifier());
                    if (match(',')) {
                        lex();
                        if (match('*')) {
                            // import foo, * as foo
                            specifiers.push(parseImportNamespaceSpecifier());
                        } else if (match('{')) {
                            // import foo, {bar}
                            specifiers = specifiers.concat(parseNamedImports());
                        } else {
                            throwUnexpectedToken(lookahead);
                        }
                    }
                } else {
                    throwUnexpectedToken(lex());
                }
    
                if (!matchContextualKeyword('from')) {
                    throwError(lookahead.value ?
                            Messages.UnexpectedToken : Messages.MissingFromClause, lookahead.value);
                }
                lex();
                src = parseModuleSpecifier();
            }
    
            consumeSemicolon();
            return node.finishImportDeclaration(specifiers, src);
        }
    
        // ECMA-262 15.1 Scripts
    
        function parseScriptBody() {
            var statement, body = [], token, directive, firstRestricted;
    
            while (startIndex < length) {
                token = lookahead;
                if (token.type !== Token.StringLiteral) {
                    break;
                }
    
                statement = parseStatementListItem();
                body.push(statement);
                if (statement.expression.type !== Syntax.Literal) {
                    // this is not directive
                    break;
                }
                directive = source.slice(token.start + 1, token.end - 1);
                if (directive === 'use strict') {
                    strict = true;
                    if (firstRestricted) {
                        tolerateUnexpectedToken(firstRestricted, Messages.StrictOctalLiteral);
                    }
                } else {
                    if (!firstRestricted && token.octal) {
                        firstRestricted = token;
                    }
                }
            }
    
            while (startIndex < length) {
                statement = parseStatementListItem();
                /* istanbul ignore if */
                if (typeof statement === 'undefined') {
                    break;
                }
                body.push(statement);
            }
            return body;
        }
    
        function parseProgram() {
            var body, node;
    
            peek();
            node = new Node();
    
            body = parseScriptBody();
            return node.finishProgram(body, state.sourceType);
        }
    
        function filterTokenLocation() {
            var i, entry, token, tokens = [];
    
            for (i = 0; i < extra.tokens.length; ++i) {
                entry = extra.tokens[i];
                token = {
                    type: entry.type,
                    value: entry.value
                };
                if (entry.regex) {
                    token.regex = {
                        pattern: entry.regex.pattern,
                        flags: entry.regex.flags
                    };
                }
                if (extra.range) {
                    token.range = entry.range;
                }
                if (extra.loc) {
                    token.loc = entry.loc;
                }
                tokens.push(token);
            }
    
            extra.tokens = tokens;
        }
    
        function tokenize(code, options, delegate) {
            var toString,
                tokens;
    
            toString = String;
            if (typeof code !== 'string' && !(code instanceof String)) {
                code = toString(code);
            }
    
            source = code;
            index = 0;
            lineNumber = (source.length > 0) ? 1 : 0;
            lineStart = 0;
            startIndex = index;
            startLineNumber = lineNumber;
            startLineStart = lineStart;
            length = source.length;
            lookahead = null;
            state = {
                allowIn: true,
                allowYield: true,
                labelSet: {},
                inFunctionBody: false,
                inIteration: false,
                inSwitch: false,
                lastCommentStart: -1,
                curlyStack: []
            };
    
            extra = {};
    
            // Options matching.
            options = options || {};
    
            // Of course we collect tokens here.
            options.tokens = true;
            extra.tokens = [];
            extra.tokenValues = [];
            extra.tokenize = true;
            extra.delegate = delegate;
    
            // The following two fields are necessary to compute the Regex tokens.
            extra.openParenToken = -1;
            extra.openCurlyToken = -1;
    
            extra.range = (typeof options.range === 'boolean') && options.range;
            extra.loc = (typeof options.loc === 'boolean') && options.loc;
    
            if (typeof options.comment === 'boolean' && options.comment) {
                extra.comments = [];
            }
            if (typeof options.tolerant === 'boolean' && options.tolerant) {
                extra.errors = [];
            }
    
            try {
                peek();
                if (lookahead.type === Token.EOF) {
                    return extra.tokens;
                }
    
                lex();
                while (lookahead.type !== Token.EOF) {
                    try {
                        lex();
                    } catch (lexError) {
                        if (extra.errors) {
                            recordError(lexError);
                            // We have to break on the first error
                            // to avoid infinite loops.
                            break;
                        } else {
                            throw lexError;
                        }
                    }
                }
    
                tokens = extra.tokens;
                if (typeof extra.errors !== 'undefined') {
                    tokens.errors = extra.errors;
                }
            } catch (e) {
                throw e;
            } finally {
                extra = {};
            }
            return tokens;
        }
    
        function parse(code, options) {
            var program, toString;
    
            toString = String;
            if (typeof code !== 'string' && !(code instanceof String)) {
                code = toString(code);
            }
    
            source = code;
            index = 0;
            lineNumber = (source.length > 0) ? 1 : 0;
            lineStart = 0;
            startIndex = index;
            startLineNumber = lineNumber;
            startLineStart = lineStart;
            length = source.length;
            lookahead = null;
            state = {
                allowIn: true,
                allowYield: true,
                labelSet: {},
                inFunctionBody: false,
                inIteration: false,
                inSwitch: false,
                lastCommentStart: -1,
                curlyStack: [],
                sourceType: 'script'
            };
            strict = false;
    
            extra = {};
            if (typeof options !== 'undefined') {
                extra.range = (typeof options.range === 'boolean') && options.range;
                extra.loc = (typeof options.loc === 'boolean') && options.loc;
                extra.attachComment = (typeof options.attachComment === 'boolean') && options.attachComment;
    
                if (extra.loc && options.source !== null && options.source !== undefined) {
                    extra.source = toString(options.source);
                }
    
                if (typeof options.tokens === 'boolean' && options.tokens) {
                    extra.tokens = [];
                }
                if (typeof options.comment === 'boolean' && options.comment) {
                    extra.comments = [];
                }
                if (typeof options.tolerant === 'boolean' && options.tolerant) {
                    extra.errors = [];
                }
                if (extra.attachComment) {
                    extra.range = true;
                    extra.comments = [];
                    extra.bottomRightStack = [];
                    extra.trailingComments = [];
                    extra.leadingComments = [];
                }
                if (options.sourceType === 'module') {
                    // very restrictive condition for now
                    state.sourceType = options.sourceType;
                    strict = true;
                }
            }
    
            try {
                program = parseProgram();
                if (typeof extra.comments !== 'undefined') {
                    program.comments = extra.comments;
                }
                if (typeof extra.tokens !== 'undefined') {
                    filterTokenLocation();
                    program.tokens = extra.tokens;
                }
                if (typeof extra.errors !== 'undefined') {
                    program.errors = extra.errors;
                }
            } catch (e) {
                throw e;
            } finally {
                extra = {};
            }
    
            return program;
        }
    
        // Sync with *.json manifests.
        exports.version = '2.7.3';
    
        exports.tokenize = tokenize;
    
        exports.parse = parse;
    
        // Deep copy.
        /* istanbul ignore next */
        exports.Syntax = (function () {
            var name, types = {};
    
            if (typeof Object.create === 'function') {
                types = Object.create(null);
            }
    
            for (name in Syntax) {
                if (Syntax.hasOwnProperty(name)) {
                    types[name] = Syntax[name];
                }
            }
    
            if (typeof Object.freeze === 'function') {
                Object.freeze(types);
            }
    
            return types;
        }());
    
    }));
    /* vim: set sw=4 ts=4 et tw=80 : */
    
    },{}],279:[function(require,module,exports){
    (function (process){(function (){
    /*
     * extsprintf.js: extended POSIX-style sprintf
     */
    
    var mod_assert = require('assert');
    var mod_util = require('util');
    
    /*
     * Public interface
     */
    exports.sprintf = jsSprintf;
    exports.printf = jsPrintf;
    exports.fprintf = jsFprintf;
    
    /*
     * Stripped down version of s[n]printf(3c).  We make a best effort to throw an
     * exception when given a format string we don't understand, rather than
     * ignoring it, so that we won't break existing programs if/when we go implement
     * the rest of this.
     *
     * This implementation currently supports specifying
     *	- field alignment ('-' flag),
     * 	- zero-pad ('0' flag)
     *	- always show numeric sign ('+' flag),
     *	- field width
     *	- conversions for strings, decimal integers, and floats (numbers).
     *	- argument size specifiers.  These are all accepted but ignored, since
     *	  Javascript has no notion of the physical size of an argument.
     *
     * Everything else is currently unsupported, most notably precision, unsigned
     * numbers, non-decimal numbers, and characters.
     */
    function jsSprintf(ofmt)
    {
        var regex = [
            '([^%]*)',				/* normal text */
            '%',				/* start of format */
            '([\'\\-+ #0]*?)',			/* flags (optional) */
            '([1-9]\\d*)?',			/* width (optional) */
            '(\\.([1-9]\\d*))?',		/* precision (optional) */
            '[lhjztL]*?',			/* length mods (ignored) */
            '([diouxXfFeEgGaAcCsSp%jr])'	/* conversion */
        ].join('');
    
        var re = new RegExp(regex);
    
        /* variadic arguments used to fill in conversion specifiers */
        var args = Array.prototype.slice.call(arguments, 1);
        /* remaining format string */
        var fmt = ofmt;
    
        /* components of the current conversion specifier */
        var flags, width, precision, conversion;
        var left, pad, sign, arg, match;
    
        /* return value */
        var ret = '';
    
        /* current variadic argument (1-based) */
        var argn = 1;
        /* 0-based position in the format string that we've read */
        var posn = 0;
        /* 1-based position in the format string of the current conversion */
        var convposn;
        /* current conversion specifier */
        var curconv;
    
        mod_assert.equal('string', typeof (fmt),
            'first argument must be a format string');
    
        while ((match = re.exec(fmt)) !== null) {
            ret += match[1];
            fmt = fmt.substring(match[0].length);
    
            /*
             * Update flags related to the current conversion specifier's
             * position so that we can report clear error messages.
             */
            curconv = match[0].substring(match[1].length);
            convposn = posn + match[1].length + 1;
            posn += match[0].length;
    
            flags = match[2] || '';
            width = match[3] || 0;
            precision = match[4] || '';
            conversion = match[6];
            left = false;
            sign = false;
            pad = ' ';
    
            if (conversion == '%') {
                ret += '%';
                continue;
            }
    
            if (args.length === 0) {
                throw (jsError(ofmt, convposn, curconv,
                    'has no matching argument ' +
                    '(too few arguments passed)'));
            }
    
            arg = args.shift();
            argn++;
    
            if (flags.match(/[\' #]/)) {
                throw (jsError(ofmt, convposn, curconv,
                    'uses unsupported flags'));
            }
    
            if (precision.length > 0) {
                throw (jsError(ofmt, convposn, curconv,
                    'uses non-zero precision (not supported)'));
            }
    
            if (flags.match(/-/))
                left = true;
    
            if (flags.match(/0/))
                pad = '0';
    
            if (flags.match(/\+/))
                sign = true;
    
            switch (conversion) {
            case 's':
                if (arg === undefined || arg === null) {
                    throw (jsError(ofmt, convposn, curconv,
                        'attempted to print undefined or null ' +
                        'as a string (argument ' + argn + ' to ' +
                        'sprintf)'));
                }
                ret += doPad(pad, width, left, arg.toString());
                break;
    
            case 'd':
                arg = Math.floor(arg);
                /*jsl:fallthru*/
            case 'f':
                sign = sign && arg > 0 ? '+' : '';
                ret += sign + doPad(pad, width, left,
                    arg.toString());
                break;
    
            case 'x':
                ret += doPad(pad, width, left, arg.toString(16));
                break;
    
            case 'j': /* non-standard */
                if (width === 0)
                    width = 10;
                ret += mod_util.inspect(arg, false, width);
                break;
    
            case 'r': /* non-standard */
                ret += dumpException(arg);
                break;
    
            default:
                throw (jsError(ofmt, convposn, curconv,
                    'is not supported'));
            }
        }
    
        ret += fmt;
        return (ret);
    }
    
    function jsError(fmtstr, convposn, curconv, reason) {
        mod_assert.equal(typeof (fmtstr), 'string');
        mod_assert.equal(typeof (curconv), 'string');
        mod_assert.equal(typeof (convposn), 'number');
        mod_assert.equal(typeof (reason), 'string');
        return (new Error('format string "' + fmtstr +
            '": conversion specifier "' + curconv + '" at character ' +
            convposn + ' ' + reason));
    }
    
    function jsPrintf() {
        var args = Array.prototype.slice.call(arguments);
        args.unshift(process.stdout);
        jsFprintf.apply(null, args);
    }
    
    function jsFprintf(stream) {
        var args = Array.prototype.slice.call(arguments, 1);
        return (stream.write(jsSprintf.apply(this, args)));
    }
    
    function doPad(chr, width, left, str)
    {
        var ret = str;
    
        while (ret.length < width) {
            if (left)
                ret += chr;
            else
                ret = chr + ret;
        }
    
        return (ret);
    }
    
    /*
     * This function dumps long stack traces for exceptions having a cause() method.
     * See node-verror for an example.
     */
    function dumpException(ex)
    {
        var ret;
    
        if (!(ex instanceof Error))
            throw (new Error(jsSprintf('invalid type for %%r: %j', ex)));
    
        /* Note that V8 prepends "ex.stack" with ex.toString(). */
        ret = 'EXCEPTION: ' + ex.constructor.name + ': ' + ex.stack;
    
        if (ex.cause && typeof (ex.cause) === 'function') {
            var cex = ex.cause();
            if (cex) {
                ret += '\nCaused by: ' + dumpException(cex);
            }
        }
    
        return (ret);
    }
    
    }).call(this)}).call(this,require('_process'))
    },{"_process":176,"assert":16,"util":216}],280:[function(require,module,exports){
    (function (Buffer){(function (){
    //     uuid.js
    //
    //     Copyright (c) 2010-2012 Robert Kieffer
    //     MIT License - http://opensource.org/licenses/mit-license.php
    
    /*global window, require, define */
    (function(_window) {
      'use strict';
    
      // Unique ID creation requires a high quality random # generator.  We feature
      // detect to determine the best RNG source, normalizing to a function that
      // returns 128-bits of randomness, since that's what's usually required
      var _rng, _mathRNG, _nodeRNG, _whatwgRNG, _previousRoot;
    
      function setupBrowser() {
        // Allow for MSIE11 msCrypto
        var _crypto = _window.crypto || _window.msCrypto;
    
        if (!_rng && _crypto && _crypto.getRandomValues) {
          // WHATWG crypto-based RNG - http://wiki.whatwg.org/wiki/Crypto
          //
          // Moderately fast, high quality
          try {
            var _rnds8 = new Uint8Array(16);
            _whatwgRNG = _rng = function whatwgRNG() {
              _crypto.getRandomValues(_rnds8);
              return _rnds8;
            };
            _rng();
          } catch(e) {}
        }
    
        if (!_rng) {
          // Math.random()-based (RNG)
          //
          // If all else fails, use Math.random().  It's fast, but is of unspecified
          // quality.
          var  _rnds = new Array(16);
          _mathRNG = _rng = function() {
            for (var i = 0, r; i < 16; i++) {
              if ((i & 0x03) === 0) { r = Math.random() * 0x100000000; }
              _rnds[i] = r >>> ((i & 0x03) << 3) & 0xff;
            }
    
            return _rnds;
          };
          if ('undefined' !== typeof console && console.warn) {
            console.warn("[SECURITY] node-uuid: crypto not usable, falling back to insecure Math.random()");
          }
        }
      }
    
      function setupNode() {
        // Node.js crypto-based RNG - http://nodejs.org/docs/v0.6.2/api/crypto.html
        //
        // Moderately fast, high quality
        if ('function' === typeof require) {
          try {
            var _rb = require('crypto').randomBytes;
            _nodeRNG = _rng = _rb && function() {return _rb(16);};
            _rng();
          } catch(e) {}
        }
      }
    
      if (_window) {
        setupBrowser();
      } else {
        setupNode();
      }
    
      // Buffer class to use
      var BufferClass = ('function' === typeof Buffer) ? Buffer : Array;
    
      // Maps for number <-> hex string conversion
      var _byteToHex = [];
      var _hexToByte = {};
      for (var i = 0; i < 256; i++) {
        _byteToHex[i] = (i + 0x100).toString(16).substr(1);
        _hexToByte[_byteToHex[i]] = i;
      }
    
      // **`parse()` - Parse a UUID into it's component bytes**
      function parse(s, buf, offset) {
        var i = (buf && offset) || 0, ii = 0;
    
        buf = buf || [];
        s.toLowerCase().replace(/[0-9a-f]{2}/g, function(oct) {
          if (ii < 16) { // Don't overflow!
            buf[i + ii++] = _hexToByte[oct];
          }
        });
    
        // Zero out remaining bytes if string was short
        while (ii < 16) {
          buf[i + ii++] = 0;
        }
    
        return buf;
      }
    
      // **`unparse()` - Convert UUID byte array (ala parse()) into a string**
      function unparse(buf, offset) {
        var i = offset || 0, bth = _byteToHex;
        return  bth[buf[i++]] + bth[buf[i++]] +
                bth[buf[i++]] + bth[buf[i++]] + '-' +
                bth[buf[i++]] + bth[buf[i++]] + '-' +
                bth[buf[i++]] + bth[buf[i++]] + '-' +
                bth[buf[i++]] + bth[buf[i++]] + '-' +
                bth[buf[i++]] + bth[buf[i++]] +
                bth[buf[i++]] + bth[buf[i++]] +
                bth[buf[i++]] + bth[buf[i++]];
      }
    
      // **`v1()` - Generate time-based UUID**
      //
      // Inspired by https://github.com/LiosK/UUID.js
      // and http://docs.python.org/library/uuid.html
    
      // random #'s we need to init node and clockseq
      var _seedBytes = _rng();
    
      // Per 4.5, create and 48-bit node id, (47 random bits + multicast bit = 1)
      var _nodeId = [
        _seedBytes[0] | 0x01,
        _seedBytes[1], _seedBytes[2], _seedBytes[3], _seedBytes[4], _seedBytes[5]
      ];
    
      // Per 4.2.2, randomize (14 bit) clockseq
      var _clockseq = (_seedBytes[6] << 8 | _seedBytes[7]) & 0x3fff;
    
      // Previous uuid creation time
      var _lastMSecs = 0, _lastNSecs = 0;
    
      // See https://github.com/broofa/node-uuid for API details
      function v1(options, buf, offset) {
        var i = buf && offset || 0;
        var b = buf || [];
    
        options = options || {};
    
        var clockseq = (options.clockseq != null) ? options.clockseq : _clockseq;
    
        // UUID timestamps are 100 nano-second units since the Gregorian epoch,
        // (1582-10-15 00:00).  JSNumbers aren't precise enough for this, so
        // time is handled internally as 'msecs' (integer milliseconds) and 'nsecs'
        // (100-nanoseconds offset from msecs) since unix epoch, 1970-01-01 00:00.
        var msecs = (options.msecs != null) ? options.msecs : new Date().getTime();
    
        // Per 4.2.1.2, use count of uuid's generated during the current clock
        // cycle to simulate higher resolution clock
        var nsecs = (options.nsecs != null) ? options.nsecs : _lastNSecs + 1;
    
        // Time since last uuid creation (in msecs)
        var dt = (msecs - _lastMSecs) + (nsecs - _lastNSecs)/10000;
    
        // Per 4.2.1.2, Bump clockseq on clock regression
        if (dt < 0 && options.clockseq == null) {
          clockseq = clockseq + 1 & 0x3fff;
        }
    
        // Reset nsecs if clock regresses (new clockseq) or we've moved onto a new
        // time interval
        if ((dt < 0 || msecs > _lastMSecs) && options.nsecs == null) {
          nsecs = 0;
        }
    
        // Per 4.2.1.2 Throw error if too many uuids are requested
        if (nsecs >= 10000) {
          throw new Error('uuid.v1(): Can\'t create more than 10M uuids/sec');
        }
    
        _lastMSecs = msecs;
        _lastNSecs = nsecs;
        _clockseq = clockseq;
    
        // Per 4.1.4 - Convert from unix epoch to Gregorian epoch
        msecs += 12219292800000;
    
        // `time_low`
        var tl = ((msecs & 0xfffffff) * 10000 + nsecs) % 0x100000000;
        b[i++] = tl >>> 24 & 0xff;
        b[i++] = tl >>> 16 & 0xff;
        b[i++] = tl >>> 8 & 0xff;
        b[i++] = tl & 0xff;
    
        // `time_mid`
        var tmh = (msecs / 0x100000000 * 10000) & 0xfffffff;
        b[i++] = tmh >>> 8 & 0xff;
        b[i++] = tmh & 0xff;
    
        // `time_high_and_version`
        b[i++] = tmh >>> 24 & 0xf | 0x10; // include version
        b[i++] = tmh >>> 16 & 0xff;
    
        // `clock_seq_hi_and_reserved` (Per 4.2.2 - include variant)
        b[i++] = clockseq >>> 8 | 0x80;
    
        // `clock_seq_low`
        b[i++] = clockseq & 0xff;
    
        // `node`
        var node = options.node || _nodeId;
        for (var n = 0; n < 6; n++) {
          b[i + n] = node[n];
        }
    
        return buf ? buf : unparse(b);
      }
    
      // **`v4()` - Generate random UUID**
    
      // See https://github.com/broofa/node-uuid for API details
      function v4(options, buf, offset) {
        // Deprecated - 'format' argument, as supported in v1.2
        var i = buf && offset || 0;
    
        if (typeof(options) === 'string') {
          buf = (options === 'binary') ? new BufferClass(16) : null;
          options = null;
        }
        options = options || {};
    
        var rnds = options.random || (options.rng || _rng)();
    
        // Per 4.4, set bits for version and `clock_seq_hi_and_reserved`
        rnds[6] = (rnds[6] & 0x0f) | 0x40;
        rnds[8] = (rnds[8] & 0x3f) | 0x80;
    
        // Copy bytes to buffer, if provided
        if (buf) {
          for (var ii = 0; ii < 16; ii++) {
            buf[i + ii] = rnds[ii];
          }
        }
    
        return buf || unparse(rnds);
      }
    
      // Export public API
      var uuid = v4;
      uuid.v1 = v1;
      uuid.v4 = v4;
      uuid.parse = parse;
      uuid.unparse = unparse;
      uuid.BufferClass = BufferClass;
      uuid._rng = _rng;
      uuid._mathRNG = _mathRNG;
      uuid._nodeRNG = _nodeRNG;
      uuid._whatwgRNG = _whatwgRNG;
    
      if (('undefined' !== typeof module) && module.exports) {
        // Publish as node.js module
        module.exports = uuid;
      } else if (typeof define === 'function' && define.amd) {
        // Publish as AMD module
        define(function() {return uuid;});
    
    
      } else {
        // Publish as global (in browsers)
        _previousRoot = _window.uuid;
    
        // **`noConflict()` - (browser only) to reset global 'uuid' var**
        uuid.noConflict = function() {
          _window.uuid = _previousRoot;
          return uuid;
        };
    
        _window.uuid = uuid;
      }
    })('undefined' !== typeof window ? window : null);
    
    }).call(this)}).call(this,require("buffer").Buffer)
    },{"buffer":68,"crypto":78}],281:[function(require,module,exports){
    /*
     * verror.js: richer JavaScript errors
     */
    
    var mod_assertplus = require('assert-plus');
    var mod_util = require('util');
    
    var mod_extsprintf = require('extsprintf');
    var mod_isError = require('core-util-is').isError;
    var sprintf = mod_extsprintf.sprintf;
    
    /*
     * Public interface
     */
    
    /* So you can 'var VError = require('verror')' */
    module.exports = VError;
    /* For compatibility */
    VError.VError = VError;
    /* Other exported classes */
    VError.SError = SError;
    VError.WError = WError;
    VError.MultiError = MultiError;
    
    /*
     * Common function used to parse constructor arguments for VError, WError, and
     * SError.  Named arguments to this function:
     *
     *     strict		force strict interpretation of sprintf arguments, even
     *     			if the options in "argv" don't say so
     *
     *     argv		error's constructor arguments, which are to be
     *     			interpreted as described in README.md.  For quick
     *     			reference, "argv" has one of the following forms:
     *
     *          [ sprintf_args... ]           (argv[0] is a string)
     *          [ cause, sprintf_args... ]    (argv[0] is an Error)
     *          [ options, sprintf_args... ]  (argv[0] is an object)
     *
     * This function normalizes these forms, producing an object with the following
     * properties:
     *
     *    options           equivalent to "options" in third form.  This will never
     *    			be a direct reference to what the caller passed in
     *    			(i.e., it may be a shallow copy), so it can be freely
     *    			modified.
     *
     *    shortmessage      result of sprintf(sprintf_args), taking options.strict
     *    			into account as described in README.md.
     */
    function parseConstructorArguments(args)
    {
        var argv, options, sprintf_args, shortmessage, k;
    
        mod_assertplus.object(args, 'args');
        mod_assertplus.bool(args.strict, 'args.strict');
        mod_assertplus.array(args.argv, 'args.argv');
        argv = args.argv;
    
        /*
         * First, figure out which form of invocation we've been given.
         */
        if (argv.length === 0) {
            options = {};
            sprintf_args = [];
        } else if (mod_isError(argv[0])) {
            options = { 'cause': argv[0] };
            sprintf_args = argv.slice(1);
        } else if (typeof (argv[0]) === 'object') {
            options = {};
            for (k in argv[0]) {
                options[k] = argv[0][k];
            }
            sprintf_args = argv.slice(1);
        } else {
            mod_assertplus.string(argv[0],
                'first argument to VError, SError, or WError ' +
                'constructor must be a string, object, or Error');
            options = {};
            sprintf_args = argv;
        }
    
        /*
         * Now construct the error's message.
         *
         * extsprintf (which we invoke here with our caller's arguments in order
         * to construct this Error's message) is strict in its interpretation of
         * values to be processed by the "%s" specifier.  The value passed to
         * extsprintf must actually be a string or something convertible to a
         * String using .toString().  Passing other values (notably "null" and
         * "undefined") is considered a programmer error.  The assumption is
         * that if you actually want to print the string "null" or "undefined",
         * then that's easy to do that when you're calling extsprintf; on the
         * other hand, if you did NOT want that (i.e., there's actually a bug
         * where the program assumes some variable is non-null and tries to
         * print it, which might happen when constructing a packet or file in
         * some specific format), then it's better to stop immediately than
         * produce bogus output.
         *
         * However, sometimes the bug is only in the code calling VError, and a
         * programmer might prefer to have the error message contain "null" or
         * "undefined" rather than have the bug in the error path crash the
         * program (making the first bug harder to identify).  For that reason,
         * by default VError converts "null" or "undefined" arguments to their
         * string representations and passes those to extsprintf.  Programmers
         * desiring the strict behavior can use the SError class or pass the
         * "strict" option to the VError constructor.
         */
        mod_assertplus.object(options);
        if (!options.strict && !args.strict) {
            sprintf_args = sprintf_args.map(function (a) {
                return (a === null ? 'null' :
                    a === undefined ? 'undefined' : a);
            });
        }
    
        if (sprintf_args.length === 0) {
            shortmessage = '';
        } else {
            shortmessage = sprintf.apply(null, sprintf_args);
        }
    
        return ({
            'options': options,
            'shortmessage': shortmessage
        });
    }
    
    /*
     * See README.md for reference documentation.
     */
    function VError()
    {
        var args, obj, parsed, cause, ctor, message, k;
    
        args = Array.prototype.slice.call(arguments, 0);
    
        /*
         * This is a regrettable pattern, but JavaScript's built-in Error class
         * is defined to work this way, so we allow the constructor to be called
         * without "new".
         */
        if (!(this instanceof VError)) {
            obj = Object.create(VError.prototype);
            VError.apply(obj, arguments);
            return (obj);
        }
    
        /*
         * For convenience and backwards compatibility, we support several
         * different calling forms.  Normalize them here.
         */
        parsed = parseConstructorArguments({
            'argv': args,
            'strict': false
        });
    
        /*
         * If we've been given a name, apply it now.
         */
        if (parsed.options.name) {
            mod_assertplus.string(parsed.options.name,
                'error\'s "name" must be a string');
            this.name = parsed.options.name;
        }
    
        /*
         * For debugging, we keep track of the original short message (attached
         * this Error particularly) separately from the complete message (which
         * includes the messages of our cause chain).
         */
        this.jse_shortmsg = parsed.shortmessage;
        message = parsed.shortmessage;
    
        /*
         * If we've been given a cause, record a reference to it and update our
         * message appropriately.
         */
        cause = parsed.options.cause;
        if (cause) {
            mod_assertplus.ok(mod_isError(cause), 'cause is not an Error');
            this.jse_cause = cause;
    
            if (!parsed.options.skipCauseMessage) {
                message += ': ' + cause.message;
            }
        }
    
        /*
         * If we've been given an object with properties, shallow-copy that
         * here.  We don't want to use a deep copy in case there are non-plain
         * objects here, but we don't want to use the original object in case
         * the caller modifies it later.
         */
        this.jse_info = {};
        if (parsed.options.info) {
            for (k in parsed.options.info) {
                this.jse_info[k] = parsed.options.info[k];
            }
        }
    
        this.message = message;
        Error.call(this, message);
    
        if (Error.captureStackTrace) {
            ctor = parsed.options.constructorOpt || this.constructor;
            Error.captureStackTrace(this, ctor);
        }
    
        return (this);
    }
    
    mod_util.inherits(VError, Error);
    VError.prototype.name = 'VError';
    
    VError.prototype.toString = function ve_toString()
    {
        var str = (this.hasOwnProperty('name') && this.name ||
            this.constructor.name || this.constructor.prototype.name);
        if (this.message)
            str += ': ' + this.message;
    
        return (str);
    };
    
    /*
     * This method is provided for compatibility.  New callers should use
     * VError.cause() instead.  That method also uses the saner `null` return value
     * when there is no cause.
     */
    VError.prototype.cause = function ve_cause()
    {
        var cause = VError.cause(this);
        return (cause === null ? undefined : cause);
    };
    
    /*
     * Static methods
     *
     * These class-level methods are provided so that callers can use them on
     * instances of Errors that are not VErrors.  New interfaces should be provided
     * only using static methods to eliminate the class of programming mistake where
     * people fail to check whether the Error object has the corresponding methods.
     */
    
    VError.cause = function (err)
    {
        mod_assertplus.ok(mod_isError(err), 'err must be an Error');
        return (mod_isError(err.jse_cause) ? err.jse_cause : null);
    };
    
    VError.info = function (err)
    {
        var rv, cause, k;
    
        mod_assertplus.ok(mod_isError(err), 'err must be an Error');
        cause = VError.cause(err);
        if (cause !== null) {
            rv = VError.info(cause);
        } else {
            rv = {};
        }
    
        if (typeof (err.jse_info) == 'object' && err.jse_info !== null) {
            for (k in err.jse_info) {
                rv[k] = err.jse_info[k];
            }
        }
    
        return (rv);
    };
    
    VError.findCauseByName = function (err, name)
    {
        var cause;
    
        mod_assertplus.ok(mod_isError(err), 'err must be an Error');
        mod_assertplus.string(name, 'name');
        mod_assertplus.ok(name.length > 0, 'name cannot be empty');
    
        for (cause = err; cause !== null; cause = VError.cause(cause)) {
            mod_assertplus.ok(mod_isError(cause));
            if (cause.name == name) {
                return (cause);
            }
        }
    
        return (null);
    };
    
    VError.hasCauseWithName = function (err, name)
    {
        return (VError.findCauseByName(err, name) !== null);
    };
    
    VError.fullStack = function (err)
    {
        mod_assertplus.ok(mod_isError(err), 'err must be an Error');
    
        var cause = VError.cause(err);
    
        if (cause) {
            return (err.stack + '\ncaused by: ' + VError.fullStack(cause));
        }
    
        return (err.stack);
    };
    
    VError.errorFromList = function (errors)
    {
        mod_assertplus.arrayOfObject(errors, 'errors');
    
        if (errors.length === 0) {
            return (null);
        }
    
        errors.forEach(function (e) {
            mod_assertplus.ok(mod_isError(e));
        });
    
        if (errors.length == 1) {
            return (errors[0]);
        }
    
        return (new MultiError(errors));
    };
    
    VError.errorForEach = function (err, func)
    {
        mod_assertplus.ok(mod_isError(err), 'err must be an Error');
        mod_assertplus.func(func, 'func');
    
        if (err instanceof MultiError) {
            err.errors().forEach(function iterError(e) { func(e); });
        } else {
            func(err);
        }
    };
    
    
    /*
     * SError is like VError, but stricter about types.  You cannot pass "null" or
     * "undefined" as string arguments to the formatter.
     */
    function SError()
    {
        var args, obj, parsed, options;
    
        args = Array.prototype.slice.call(arguments, 0);
        if (!(this instanceof SError)) {
            obj = Object.create(SError.prototype);
            SError.apply(obj, arguments);
            return (obj);
        }
    
        parsed = parseConstructorArguments({
            'argv': args,
            'strict': true
        });
    
        options = parsed.options;
        VError.call(this, options, '%s', parsed.shortmessage);
    
        return (this);
    }
    
    /*
     * We don't bother setting SError.prototype.name because once constructed,
     * SErrors are just like VErrors.
     */
    mod_util.inherits(SError, VError);
    
    
    /*
     * Represents a collection of errors for the purpose of consumers that generally
     * only deal with one error.  Callers can extract the individual errors
     * contained in this object, but may also just treat it as a normal single
     * error, in which case a summary message will be printed.
     */
    function MultiError(errors)
    {
        mod_assertplus.array(errors, 'list of errors');
        mod_assertplus.ok(errors.length > 0, 'must be at least one error');
        this.ase_errors = errors;
    
        VError.call(this, {
            'cause': errors[0]
        }, 'first of %d error%s', errors.length, errors.length == 1 ? '' : 's');
    }
    
    mod_util.inherits(MultiError, VError);
    MultiError.prototype.name = 'MultiError';
    
    MultiError.prototype.errors = function me_errors()
    {
        return (this.ase_errors.slice(0));
    };
    
    
    /*
     * See README.md for reference details.
     */
    function WError()
    {
        var args, obj, parsed, options;
    
        args = Array.prototype.slice.call(arguments, 0);
        if (!(this instanceof WError)) {
            obj = Object.create(WError.prototype);
            WError.apply(obj, args);
            return (obj);
        }
    
        parsed = parseConstructorArguments({
            'argv': args,
            'strict': false
        });
    
        options = parsed.options;
        options['skipCauseMessage'] = true;
        VError.call(this, options, '%s', parsed.shortmessage);
    
        return (this);
    }
    
    mod_util.inherits(WError, VError);
    WError.prototype.name = 'WError';
    
    WError.prototype.toString = function we_toString()
    {
        var str = (this.hasOwnProperty('name') && this.name ||
            this.constructor.name || this.constructor.prototype.name);
        if (this.message)
            str += ': ' + this.message;
        if (this.jse_cause && this.jse_cause.message)
            str += '; caused by ' + this.jse_cause.toString();
    
        return (str);
    };
    
    /*
     * For purely historical reasons, WError's cause() function allows you to set
     * the cause.
     */
    WError.prototype.cause = function we_cause(c)
    {
        if (mod_isError(c))
            this.jse_cause = c;
    
        return (this.jse_cause);
    };
    
    },{"assert-plus":219,"core-util-is":277,"extsprintf":279,"util":216}]},{},[218]);
    