UNPKG

blinktrade

Version:

BlinkTrade client for node.js

6,167 lines 173 kB
import child_process from 'child_process';
import os from 'os';
import buffer from 'buffer';
import dgram from 'dgram';
import WS from 'ws';

var BROKERS = {
  VBTC: 3,
  TESTNET: 5,
  URDUBIT: 8,
  CHILEBIT: 9,
  BITCAMBIO: 11
};

function _typeof(obj) {
  if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
    _typeof = function (obj) {
      return typeof obj;
    };
  } else {
    _typeof = function (obj) {
      return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
    };
  }

  return _typeof(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, descriptor.key, descriptor);
  }
}

function _createClass(Constructor, protoProps, staticProps) {
  if (protoProps) _defineProperties(Constructor.prototype, protoProps);
  if (staticProps) _defineProperties(Constructor, staticProps);
  return Constructor;
}

function _defineProperty(obj, key, value) {
  if (key in obj) {
    Object.defineProperty(obj, key, {
      value: value,
      enumerable: true,
      configurable: true,
      writable: true
    });
  } else {
    obj[key] = value;
  }

  return obj;
}

function _objectSpread(target) {
  for (var i = 1; i < arguments.length; i++) {
    var source = arguments[i] != null ? arguments[i] : {};
    var ownKeys = Object.keys(source);

    if (typeof Object.getOwnPropertySymbols === 'function') {
      ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) {
        return Object.getOwnPropertyDescriptor(source, sym).enumerable;
      }));
    }

    ownKeys.forEach(function (key) {
      _defineProperty(target, key, source[key]);
    });
  }

  return target;
}

function _inherits(subClass, superClass) {
  if (typeof superClass !== "function" && superClass !== null) {
    throw new TypeError("Super expression must either be null or a function");
  }

  subClass.prototype = Object.create(superClass && superClass.prototype, {
    constructor: {
      value: subClass,
      writable: true,
      configurable: true
    }
  });
  if (superClass) _setPrototypeOf(subClass, superClass);
}

function _getPrototypeOf(o) {
  _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) {
    return o.__proto__ || Object.getPrototypeOf(o);
  };
  return _getPrototypeOf(o);
}

function _setPrototypeOf(o, p) {
  _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {
    o.__proto__ = p;
    return o;
  };

  return _setPrototypeOf(o, p);
}

function _objectWithoutPropertiesLoose(source, excluded) {
  if (source == null) return {};
  var target = {};
  var sourceKeys = Object.keys(source);
  var key, i;

  for (i = 0; i < sourceKeys.length; i++) {
    key = sourceKeys[i];
    if (excluded.indexOf(key) >= 0) continue;
    target[key] = source[key];
  }

  return target;
}

function _objectWithoutProperties(source, excluded) {
  if (source == null) return {};

  var target = _objectWithoutPropertiesLoose(source, excluded);

  var key, i;

  if (Object.getOwnPropertySymbols) {
    var sourceSymbolKeys = Object.getOwnPropertySymbols(source);

    for (i = 0; i < sourceSymbolKeys.length; i++) {
      key = sourceSymbolKeys[i];
      if (excluded.indexOf(key) >= 0) continue;
      if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
      target[key] = source[key];
    }
  }

  return target;
}

function _assertThisInitialized(self) {
  if (self === void 0) {
    throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
  }

  return self;
}

function _possibleConstructorReturn(self, call) {
  if (call && (typeof call === "object" || typeof call === "function")) {
    return call;
  }

  return _assertThisInitialized(self);
}

function _superPropBase(object, property) {
  while (!Object.prototype.hasOwnProperty.call(object, property)) {
    object = _getPrototypeOf(object);
    if (object === null) break;
  }

  return object;
}

function _get(target, property, receiver) {
  if (typeof Reflect !== "undefined" && Reflect.get) {
    _get = Reflect.get;
  } else {
    _get = function _get(target, property, receiver) {
      var base = _superPropBase(target, property);

      if (!base) return;
      var desc = Object.getOwnPropertyDescriptor(base, property);

      if (desc.get) {
        return desc.get.call(receiver);
      }

      return desc.value;
    };
  }

  return _get(target, property, receiver || target);
}

function _slicedToArray(arr, i) {
  return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest();
}

function _arrayWithHoles(arr) {
  if (Array.isArray(arr)) return arr;
}

function _iterableToArrayLimit(arr, i) {
  var _arr = [];
  var _n = true;
  var _d = false;
  var _e = undefined;

  try {
    for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {
      _arr.push(_s.value);

      if (i && _arr.length === i) break;
    }
  } catch (err) {
    _d = true;
    _e = err;
  } finally {
    try {
      if (!_n && _i["return"] != null) _i["return"]();
    } finally {
      if (_d) throw _e;
    }
  }

  return _arr;
}

function _nonIterableRest() {
  throw new TypeError("Invalid attempt to destructure non-iterable instance");
}

var isPromise_1 = isPromise;

function isPromise(obj) {
  return obj && typeof obj.then === 'function';
}

var nextTick;
if (typeof setImediate === 'function') nextTick = setImediate;else if ((typeof process === "undefined" ? "undefined" : _typeof(process)) === 'object' && process && process.nextTick) nextTick = process.nextTick;else nextTick = function nextTick(cb) {
  setTimeout(cb, 0);
};
var extensions = [];
var promise = Promise$1;

function Promise$1(fn) {
  if (!(this instanceof Promise$1)) {
    return typeof fn === 'function' ? new Promise$1(fn) : defer();
  }

  var isResolved = false;
  var isFulfilled = false;
  var value;
  var waiting = [];
  var running = false;

  function next(skipTimeout) {
    if (waiting.length) {
      running = true;
      waiting.shift()(skipTimeout || false);
    } else {
      running = false;
    }
  }

  this.then = then;

  function then(cb, eb) {
    return new Promise$1(function (resolver) {
      function done(skipTimeout) {
        var callback = isFulfilled ? cb : eb;

        if (typeof callback === 'function') {
          var timeoutDone = function timeoutDone() {
            var val;

            try {
              val = callback(value);
            } catch (ex) {
              resolver.reject(ex);
              return next();
            }

            resolver.fulfill(val);
            next(true);
          };

          if (skipTimeout) timeoutDone();else nextTick(timeoutDone);
        } else if (isFulfilled) {
          resolver.fulfill(value);
          next(skipTimeout);
        } else {
          resolver.reject(value);
          next(skipTimeout);
        }
      }

      waiting.push(done);
      if (isResolved && !running) next();
    });
  }

  (function () {
    function fulfill(val) {
      if (isResolved) return;
      if (isPromise_1(val)) val.then(fulfill, reject);else {
        isResolved = isFulfilled = true;
        value = val;
        next();
      }
    }

    function reject(err) {
      if (isResolved) return;
      isResolved = true;
      isFulfilled = false;
      value = err;
      next();
    }

    var resolver = {
      fulfill: fulfill,
      reject: reject
    };

    for (var i = 0; i < extensions.length; i++) {
      extensions[i](this, resolver);
    }

    if (typeof fn === 'function') {
      try {
        fn(resolver);
      } catch (ex) {
        resolver.reject(ex);
      }
    }
  })();
}

function defer() {
  var resolver;
  var promise = new Promise$1(function (res) {
    resolver = res;
  });
  return {
    resolver: resolver,
    promise: promise
  };
}

Promise$1.use = function (extension) {
  extensions.push(extension);
};

var nextTick$1;
if (typeof setImmediate === 'function') nextTick$1 = setImmediate;else if ((typeof process === "undefined" ? "undefined" : _typeof(process)) === 'object' && process && process.nextTick) nextTick$1 = process.nextTick;else nextTick$1 = function nextTick(cb) {
  setTimeout(cb, 0);
};
var nodeify_1 = nodeify;

function nodeify(promise$$1, cb) {
  if (typeof cb !== 'function') return promise$$1;
  return promise$$1.then(function (res) {
    nextTick$1(function () {
      cb(null, res);
    });
  }, function (err) {
    nextTick$1(function () {
      cb(err);
    });
  });
}

function nodeifyThis(cb) {
  return nodeify(this, cb);
}

nodeify.extend = extend;
nodeify.Promise = NodeifyPromise;

function extend(prom) {
  if (prom && isPromise_1(prom)) {
    prom.nodeify = nodeifyThis;
    var then = prom.then;

    prom.then = function () {
      return extend(then.apply(this, arguments));
    };

    return prom;
  } else if (typeof prom === 'function') {
    prom.prototype.nodeify = nodeifyThis;
  } else {
    promise.prototype.nodeify = nodeifyThis;
  }
}

function NodeifyPromise(fn) {
  if (!(this instanceof NodeifyPromise)) {
    return new NodeifyPromise(fn);
  }

  promise.call(this, fn);
  extend(this);
}

NodeifyPromise.prototype = Object.create(promise.prototype);
NodeifyPromise.prototype.constructor = NodeifyPromise;

var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};

function createCommonjsModule(fn, module) {
	return module = { exports: {} }, fn(module, module.exports), module.exports;
}

var eventemitter2 = createCommonjsModule(function (module, exports) {
  !function (undefined) {
    var isArray = Array.isArray ? Array.isArray : function _isArray(obj) {
      return Object.prototype.toString.call(obj) === "[object Array]";
    };
    var defaultMaxListeners = 10;

    function init() {
      this._events = {};

      if (this._conf) {
        configure.call(this, this._conf);
      }
    }

    function configure(conf) {
      if (conf) {
        this._conf = conf;
        conf.delimiter && (this.delimiter = conf.delimiter);
        this._maxListeners = conf.maxListeners !== undefined ? conf.maxListeners : defaultMaxListeners;
        conf.wildcard && (this.wildcard = conf.wildcard);
        conf.newListener && (this._newListener = conf.newListener);
        conf.removeListener && (this._removeListener = conf.removeListener);
        conf.verboseMemoryLeak && (this.verboseMemoryLeak = conf.verboseMemoryLeak);

        if (this.wildcard) {
          this.listenerTree = {};
        }
      } else {
        this._maxListeners = defaultMaxListeners;
      }
    }

    function logPossibleMemoryLeak(count, eventName) {
      var errorMsg = '(node) warning: possible EventEmitter memory ' + 'leak detected. ' + count + ' listeners added. ' + 'Use emitter.setMaxListeners() to increase limit.';

      if (this.verboseMemoryLeak) {
        errorMsg += ' Event name: ' + eventName + '.';
      }

      if (typeof process !== 'undefined' && process.emitWarning) {
        var e = new Error(errorMsg);
        e.name = 'MaxListenersExceededWarning';
        e.emitter = this;
        e.count = count;
        process.emitWarning(e);
      } else {
        console.error(errorMsg);

        if (console.trace) {
          console.trace();
        }
      }
    }

    function EventEmitter(conf) {
      this._events = {};
      this._newListener = false;
      this._removeListener = false;
      this.verboseMemoryLeak = false;
      configure.call(this, conf);
    }

    EventEmitter.EventEmitter2 = EventEmitter; // backwards compatibility for exporting EventEmitter property
    //
    // Attention, function return type now is array, always !
    // It has zero elements if no any matches found and one or more
    // elements (leafs) if there are matches
    //

    function searchListenerTree(handlers, type, tree, i) {
      if (!tree) {
        return [];
      }

      var listeners = [],
          leaf,
          len,
          branch,
          xTree,
          xxTree,
          isolatedBranch,
          endReached,
          typeLength = type.length,
          currentType = type[i],
          nextType = type[i + 1];

      if (i === typeLength && tree._listeners) {
        //
        // If at the end of the event(s) list and the tree has listeners
        // invoke those listeners.
        //
        if (typeof tree._listeners === 'function') {
          handlers && handlers.push(tree._listeners);
          return [tree];
        } else {
          for (leaf = 0, len = tree._listeners.length; leaf < len; leaf++) {
            handlers && handlers.push(tree._listeners[leaf]);
          }

          return [tree];
        }
      }

      if (currentType === '*' || currentType === '**' || tree[currentType]) {
        //
        // If the event emitted is '*' at this part
        // or there is a concrete match at this patch
        //
        if (currentType === '*') {
          for (branch in tree) {
            if (branch !== '_listeners' && tree.hasOwnProperty(branch)) {
              listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], i + 1));
            }
          }

          return listeners;
        } else if (currentType === '**') {
          endReached = i + 1 === typeLength || i + 2 === typeLength && nextType === '*';

          if (endReached && tree._listeners) {
            // The next element has a _listeners, add it to the handlers.
            listeners = listeners.concat(searchListenerTree(handlers, type, tree, typeLength));
          }

          for (branch in tree) {
            if (branch !== '_listeners' && tree.hasOwnProperty(branch)) {
              if (branch === '*' || branch === '**') {
                if (tree[branch]._listeners && !endReached) {
                  listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], typeLength));
                }

                listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], i));
              } else if (branch === nextType) {
                listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], i + 2));
              } else {
                // No match on this one, shift into the tree but not in the type array.
                listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], i));
              }
            }
          }

          return listeners;
        }

        listeners = listeners.concat(searchListenerTree(handlers, type, tree[currentType], i + 1));
      }

      xTree = tree['*'];

      if (xTree) {
        //
        // If the listener tree will allow any match for this part,
        // then recursively explore all branches of the tree
        //
        searchListenerTree(handlers, type, xTree, i + 1);
      }

      xxTree = tree['**'];

      if (xxTree) {
        if (i < typeLength) {
          if (xxTree._listeners) {
            // If we have a listener on a '**', it will catch all, so add its handler.
            searchListenerTree(handlers, type, xxTree, typeLength);
          } // Build arrays of matching next branches and others.


          for (branch in xxTree) {
            if (branch !== '_listeners' && xxTree.hasOwnProperty(branch)) {
              if (branch === nextType) {
                // We know the next element will match, so jump twice.
                searchListenerTree(handlers, type, xxTree[branch], i + 2);
              } else if (branch === currentType) {
                // Current node matches, move into the tree.
                searchListenerTree(handlers, type, xxTree[branch], i + 1);
              } else {
                isolatedBranch = {};
                isolatedBranch[branch] = xxTree[branch];
                searchListenerTree(handlers, type, {
                  '**': isolatedBranch
                }, i + 1);
              }
            }
          }
        } else if (xxTree._listeners) {
          // We have reached the end and still on a '**'
          searchListenerTree(handlers, type, xxTree, typeLength);
        } else if (xxTree['*'] && xxTree['*']._listeners) {
          searchListenerTree(handlers, type, xxTree['*'], typeLength);
        }
      }

      return listeners;
    }

    function growListenerTree(type, listener) {
      type = typeof type === 'string' ? type.split(this.delimiter) : type.slice(); //
      // Looks for two consecutive '**', if so, don't add the event at all.
      //

      for (var i = 0, len = type.length; i + 1 < len; i++) {
        if (type[i] === '**' && type[i + 1] === '**') {
          return;
        }
      }

      var tree = this.listenerTree;
      var name = type.shift();

      while (name !== undefined) {
        if (!tree[name]) {
          tree[name] = {};
        }

        tree = tree[name];

        if (type.length === 0) {
          if (!tree._listeners) {
            tree._listeners = listener;
          } else {
            if (typeof tree._listeners === 'function') {
              tree._listeners = [tree._listeners];
            }

            tree._listeners.push(listener);

            if (!tree._listeners.warned && this._maxListeners > 0 && tree._listeners.length > this._maxListeners) {
              tree._listeners.warned = true;
              logPossibleMemoryLeak.call(this, tree._listeners.length, name);
            }
          }

          return true;
        }

        name = type.shift();
      }

      return true;
    } // 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.
    //
    // Obviously not all Emitters should be limited to 10. This function allows
    // that to be increased. Set to zero for unlimited.


    EventEmitter.prototype.delimiter = '.';

    EventEmitter.prototype.setMaxListeners = function (n) {
      if (n !== undefined) {
        this._maxListeners = n;
        if (!this._conf) this._conf = {};
        this._conf.maxListeners = n;
      }
    };

    EventEmitter.prototype.event = '';

    EventEmitter.prototype.once = function (event, fn) {
      return this._once(event, fn, false);
    };

    EventEmitter.prototype.prependOnceListener = function (event, fn) {
      return this._once(event, fn, true);
    };

    EventEmitter.prototype._once = function (event, fn, prepend) {
      this._many(event, 1, fn, prepend);

      return this;
    };

    EventEmitter.prototype.many = function (event, ttl, fn) {
      return this._many(event, ttl, fn, false);
    };

    EventEmitter.prototype.prependMany = function (event, ttl, fn) {
      return this._many(event, ttl, fn, true);
    };

    EventEmitter.prototype._many = function (event, ttl, fn, prepend) {
      var self = this;

      if (typeof fn !== 'function') {
        throw new Error('many only accepts instances of Function');
      }

      function listener() {
        if (--ttl === 0) {
          self.off(event, listener);
        }

        return fn.apply(this, arguments);
      }

      listener._origin = fn;

      this._on(event, listener, prepend);

      return self;
    };

    EventEmitter.prototype.emit = function () {
      this._events || init.call(this);
      var type = arguments[0];

      if (type === 'newListener' && !this._newListener) {
        if (!this._events.newListener) {
          return false;
        }
      }

      var al = arguments.length;
      var args, l, i, j;
      var handler;

      if (this._all && this._all.length) {
        handler = this._all.slice();

        if (al > 3) {
          args = new Array(al);

          for (j = 0; j < al; j++) {
            args[j] = arguments[j];
          }
        }

        for (i = 0, l = handler.length; i < l; i++) {
          this.event = type;

          switch (al) {
            case 1:
              handler[i].call(this, type);
              break;

            case 2:
              handler[i].call(this, type, arguments[1]);
              break;

            case 3:
              handler[i].call(this, type, arguments[1], arguments[2]);
              break;

            default:
              handler[i].apply(this, args);
          }
        }
      }

      if (this.wildcard) {
        handler = [];
        var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice();
        searchListenerTree.call(this, handler, ns, this.listenerTree, 0);
      } else {
        handler = this._events[type];

        if (typeof handler === 'function') {
          this.event = type;

          switch (al) {
            case 1:
              handler.call(this);
              break;

            case 2:
              handler.call(this, arguments[1]);
              break;

            case 3:
              handler.call(this, arguments[1], arguments[2]);
              break;

            default:
              args = new Array(al - 1);

              for (j = 1; j < al; j++) {
                args[j - 1] = arguments[j];
              }

              handler.apply(this, args);
          }

          return true;
        } else if (handler) {
          // need to make copy of handlers because list can change in the middle
          // of emit call
          handler = handler.slice();
        }
      }

      if (handler && handler.length) {
        if (al > 3) {
          args = new Array(al - 1);

          for (j = 1; j < al; j++) {
            args[j - 1] = arguments[j];
          }
        }

        for (i = 0, l = handler.length; i < l; i++) {
          this.event = type;

          switch (al) {
            case 1:
              handler[i].call(this);
              break;

            case 2:
              handler[i].call(this, arguments[1]);
              break;

            case 3:
              handler[i].call(this, arguments[1], arguments[2]);
              break;

            default:
              handler[i].apply(this, args);
          }
        }

        return true;
      } else if (!this._all && type === 'error') {
        if (arguments[1] instanceof Error) {
          throw arguments[1]; // Unhandled 'error' event
        } else {
          throw new Error("Uncaught, unspecified 'error' event.");
        }

        return false;
      }

      return !!this._all;
    };

    EventEmitter.prototype.emitAsync = function () {
      this._events || init.call(this);
      var type = arguments[0];

      if (type === 'newListener' && !this._newListener) {
        if (!this._events.newListener) {
          return Promise.resolve([false]);
        }
      }

      var promises = [];
      var al = arguments.length;
      var args, l, i, j;
      var handler;

      if (this._all) {
        if (al > 3) {
          args = new Array(al);

          for (j = 1; j < al; j++) {
            args[j] = arguments[j];
          }
        }

        for (i = 0, l = this._all.length; i < l; i++) {
          this.event = type;

          switch (al) {
            case 1:
              promises.push(this._all[i].call(this, type));
              break;

            case 2:
              promises.push(this._all[i].call(this, type, arguments[1]));
              break;

            case 3:
              promises.push(this._all[i].call(this, type, arguments[1], arguments[2]));
              break;

            default:
              promises.push(this._all[i].apply(this, args));
          }
        }
      }

      if (this.wildcard) {
        handler = [];
        var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice();
        searchListenerTree.call(this, handler, ns, this.listenerTree, 0);
      } else {
        handler = this._events[type];
      }

      if (typeof handler === 'function') {
        this.event = type;

        switch (al) {
          case 1:
            promises.push(handler.call(this));
            break;

          case 2:
            promises.push(handler.call(this, arguments[1]));
            break;

          case 3:
            promises.push(handler.call(this, arguments[1], arguments[2]));
            break;

          default:
            args = new Array(al - 1);

            for (j = 1; j < al; j++) {
              args[j - 1] = arguments[j];
            }

            promises.push(handler.apply(this, args));
        }
      } else if (handler && handler.length) {
        handler = handler.slice();

        if (al > 3) {
          args = new Array(al - 1);

          for (j = 1; j < al; j++) {
            args[j - 1] = arguments[j];
          }
        }

        for (i = 0, l = handler.length; i < l; i++) {
          this.event = type;

          switch (al) {
            case 1:
              promises.push(handler[i].call(this));
              break;

            case 2:
              promises.push(handler[i].call(this, arguments[1]));
              break;

            case 3:
              promises.push(handler[i].call(this, arguments[1], arguments[2]));
              break;

            default:
              promises.push(handler[i].apply(this, args));
          }
        }
      } else if (!this._all && type === 'error') {
        if (arguments[1] instanceof Error) {
          return Promise.reject(arguments[1]); // Unhandled 'error' event
        } else {
          return Promise.reject("Uncaught, unspecified 'error' event.");
        }
      }

      return Promise.all(promises);
    };

    EventEmitter.prototype.on = function (type, listener) {
      return this._on(type, listener, false);
    };

    EventEmitter.prototype.prependListener = function (type, listener) {
      return this._on(type, listener, true);
    };

    EventEmitter.prototype.onAny = function (fn) {
      return this._onAny(fn, false);
    };

    EventEmitter.prototype.prependAny = function (fn) {
      return this._onAny(fn, true);
    };

    EventEmitter.prototype.addListener = EventEmitter.prototype.on;

    EventEmitter.prototype._onAny = function (fn, prepend) {
      if (typeof fn !== 'function') {
        throw new Error('onAny only accepts instances of Function');
      }

      if (!this._all) {
        this._all = [];
      } // Add the function to the event listener collection.


      if (prepend) {
        this._all.unshift(fn);
      } else {
        this._all.push(fn);
      }

      return this;
    };

    EventEmitter.prototype._on = function (type, listener, prepend) {
      if (typeof type === 'function') {
        this._onAny(type, listener);

        return this;
      }

      if (typeof listener !== 'function') {
        throw new Error('on only accepts instances of Function');
      }

      this._events || init.call(this); // To avoid recursion in the case that type == "newListeners"! Before
      // adding it to the listeners, first emit "newListeners".

      if (this._newListener) this.emit('newListener', type, listener);

      if (this.wildcard) {
        growListenerTree.call(this, type, listener);
        return this;
      }

      if (!this._events[type]) {
        // Optimize the case of one listener. Don't need the extra array object.
        this._events[type] = listener;
      } else {
        if (typeof this._events[type] === 'function') {
          // Change to array.
          this._events[type] = [this._events[type]];
        } // If we've already got an array, just add


        if (prepend) {
          this._events[type].unshift(listener);
        } else {
          this._events[type].push(listener);
        } // Check for listener leak


        if (!this._events[type].warned && this._maxListeners > 0 && this._events[type].length > this._maxListeners) {
          this._events[type].warned = true;
          logPossibleMemoryLeak.call(this, this._events[type].length, type);
        }
      }

      return this;
    };

    EventEmitter.prototype.off = function (type, listener) {
      if (typeof listener !== 'function') {
        throw new Error('removeListener only takes instances of Function');
      }

      var handlers,
          leafs = [];

      if (this.wildcard) {
        var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice();
        leafs = searchListenerTree.call(this, null, ns, this.listenerTree, 0);
      } else {
        // does not use listeners(), so no side effect of creating _events[type]
        if (!this._events[type]) return this;
        handlers = this._events[type];
        leafs.push({
          _listeners: handlers
        });
      }

      for (var iLeaf = 0; iLeaf < leafs.length; iLeaf++) {
        var leaf = leafs[iLeaf];
        handlers = leaf._listeners;

        if (isArray(handlers)) {
          var position = -1;

          for (var i = 0, length = handlers.length; i < length; i++) {
            if (handlers[i] === listener || handlers[i].listener && handlers[i].listener === listener || handlers[i]._origin && handlers[i]._origin === listener) {
              position = i;
              break;
            }
          }

          if (position < 0) {
            continue;
          }

          if (this.wildcard) {
            leaf._listeners.splice(position, 1);
          } else {
            this._events[type].splice(position, 1);
          }

          if (handlers.length === 0) {
            if (this.wildcard) {
              delete leaf._listeners;
            } else {
              delete this._events[type];
            }
          }

          if (this._removeListener) this.emit("removeListener", type, listener);
          return this;
        } else if (handlers === listener || handlers.listener && handlers.listener === listener || handlers._origin && handlers._origin === listener) {
          if (this.wildcard) {
            delete leaf._listeners;
          } else {
            delete this._events[type];
          }

          if (this._removeListener) this.emit("removeListener", type, listener);
        }
      }

      function recursivelyGarbageCollect(root) {
        if (root === undefined) {
          return;
        }

        var keys = Object.keys(root);

        for (var i in keys) {
          var key = keys[i];
          var obj = root[key];
          if (obj instanceof Function || _typeof(obj) !== "object" || obj === null) continue;

          if (Object.keys(obj).length > 0) {
            recursivelyGarbageCollect(root[key]);
          }

          if (Object.keys(obj).length === 0) {
            delete root[key];
          }
        }
      }

      recursivelyGarbageCollect(this.listenerTree);
      return this;
    };

    EventEmitter.prototype.offAny = function (fn) {
      var i = 0,
          l = 0,
          fns;

      if (fn && this._all && this._all.length > 0) {
        fns = this._all;

        for (i = 0, l = fns.length; i < l; i++) {
          if (fn === fns[i]) {
            fns.splice(i, 1);
            if (this._removeListener) this.emit("removeListenerAny", fn);
            return this;
          }
        }
      } else {
        fns = this._all;

        if (this._removeListener) {
          for (i = 0, l = fns.length; i < l; i++) {
            this.emit("removeListenerAny", fns[i]);
          }
        }

        this._all = [];
      }

      return this;
    };

    EventEmitter.prototype.removeListener = EventEmitter.prototype.off;

    EventEmitter.prototype.removeAllListeners = function (type) {
      if (type === undefined) {
        !this._events || init.call(this);
        return this;
      }

      if (this.wildcard) {
        var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice();
        var leafs = searchListenerTree.call(this, null, ns, this.listenerTree, 0);

        for (var iLeaf = 0; iLeaf < leafs.length; iLeaf++) {
          var leaf = leafs[iLeaf];
          leaf._listeners = null;
        }
      } else if (this._events) {
        this._events[type] = null;
      }

      return this;
    };

    EventEmitter.prototype.listeners = function (type) {
      if (this.wildcard) {
        var handlers = [];
        var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice();
        searchListenerTree.call(this, handlers, ns, this.listenerTree, 0);
        return handlers;
      }

      this._events || init.call(this);
      if (!this._events[type]) this._events[type] = [];

      if (!isArray(this._events[type])) {
        this._events[type] = [this._events[type]];
      }

      return this._events[type];
    };

    EventEmitter.prototype.eventNames = function () {
      return Object.keys(this._events);
    };

    EventEmitter.prototype.listenerCount = function (type) {
      return this.listeners(type).length;
    };

    EventEmitter.prototype.listenersAny = function () {
      if (this._all) {
        return this._all;
      } else {
        return [];
      }
    };

    if (typeof undefined === 'function' && undefined.amd) {
      // AMD. Register as an anonymous module.
      undefined(function () {
        return EventEmitter;
      });
    } else {
      // CommonJS
      module.exports = EventEmitter;
    }
  }();
});

var TestReqID = 'TestReqID';
var UserReqID = 'UserReqID';
var SecurityReqID = 'SecurityReqID';
var DepositReqID = 'DepositReqID';
var WithdrawReqID = 'WithdrawReqID';
var BalanceReqID = 'BalanceReqID';
var OrdersReqID = 'OrdersReqID';
var DepositMethodReqID = 'DepositMethodReqID';
var WithdrawListReqID = 'WithdrawListReqID';
var WithdrawCancelReqID = 'WithdrawCancelReqID';
var BrokerListReqID = 'BrokerListReqID';
var DepositListReqID = 'DepositListReqID';
var TradeHistoryReqID = 'TradeHistoryReqID';
var LedgerListReqID = 'LedgerListReqID';
var PositionReqID = 'PositionReqID';
var SecurityStatusReqID = 'SecurityStatusReqID';
var ProcessDepositReqID = 'ProcessDepositReqID';
var CustomerListReqID = 'CustomerListReqID';
var CustomerReqID = 'CustomerReqID';
var ProcessWithdrawReqID = 'ProcessWithdrawReqID';
var VerifyCustomerReqID = 'VerifyCustomerReqID';
var MDReqID = 'MDReqID';
var ClOrdID = 'ClOrdID';

var HEARTBEAT = 'HEARTBEAT';
var BROKER_LIST = 'BROKER_LIST';
var SECURITY_LIST = 'SECURITY_LIST';
var SECURITY_STATUS_SUBSCRIBE = 'SECURITY_STATUS_SUBSCRIBE';
var MD_INCREMENT = 'MD_INCREMENT';
var MD_FULL_REFRESH = 'MD_FULL_REFRESH';
var EXECUTION_REPORT = 'EXECUTION_REPORT';
var ORDER_HISTORY = 'ORDER_HISTORY';
var ORDER_SEND = 'ORDER_SEND';
var ORDER_CANCEL = 'ORDER_CANCEL';
var TRADE_HISTORY = 'TRADE_HISTORY';
var LOGIN = 'LOGIN';
var BALANCE = 'BALANCE';
var POSITIONS = 'POSITIONS';
var CUSTOMER_LIST = 'CUSTOMER_LIST';
var CUSTOMER_REFRESH = 'CUSTOMER_REFRESH';
var KYC_VERIFY = 'KYC_VERIFY';
var KYC_REQUEST = 'KYC_REQUEST';
var WITHDRAW_LIST = 'WITHDRAW_LIST';
var WITHDRAW_CANCEL = 'WITHDRAW_CANCEL';
var WITHDRAW_REFRESH = 'WITHDRAW_REFRESH';
var WITHDRAW_PROCESS = 'WITHDRAW_PROCESS';
var WITHDRAW_CONFIRM = 'WITHDRAW_CONFIRM';
var WITHDRAW_COMMENT = 'WITHDRAW_COMMENT';
var WITHDRAW_REQUEST = 'WITHDRAW_REQUEST';
var DEPOSIT_LIST = 'DEPOSIT_LIST';
var DEPOSIT_REFRESH = 'DEPOSIT_REFRESH';
var DEPOSIT_PROCESS = 'DEPOSIT_PROCESS';
var DEPOSIT_REQUEST = 'DEPOSIT_REQUEST';
var DEPOSIT_METHODS = 'DEPOSIT_METHODS';
var LEDGER_LIST = 'LEDGER_LIST';

/*       */

/* eslint-disable no-param-reassign */
var zipColumns = function zipColumns(arr, columns) {
  return arr.reduce(function (prev, val, i) {
    prev[columns[i]] = val;
    return prev;
  }, {});
};

var msgToAction = function msgToAction(messages) {
  return Object.entries(messages).reduce(function (prev, val) {
    // $FlowFixMe Fixed entries mixed type
    prev[val[1][0]] = val[0];
    return prev;
  }, {});
};
var formatColumns = function formatColumns(field, level) {
  return function (data) {
    if (level === 2) {
      var list = data[field].map(function (row) {
        return zipColumns(row, data.Columns);
      });
      return Promise.resolve(_objectSpread({}, data, _defineProperty({}, field, list)));
    }

    return Promise.resolve(data);
  };
};
var formatBrokerList = function formatBrokerList(level) {
  return function (data) {
    if (level === 2) {
      var BrokerListGrp = data.BrokerListGrp.map(function (row) {
        return zipColumns(row, data.Columns);
      }).reduce(function (prev, val) {
        prev[val.BrokerID] = val;
        return prev;
      }, {});
      return Promise.resolve(_objectSpread({}, data, {
        BrokerListGrp: BrokerListGrp
      }));
    }

    return Promise.resolve(data);
  };
};
var formatTradeHistory = function formatTradeHistory(level) {
  return function (data) {
    if (level === 2) {
      var TradeHistoryGrp = data.TradeHistoryGrp.map(function (row) {
        return zipColumns(row, data.Columns);
      }).reduce(function (prev, val) {
        (prev[val.Market] = prev[val.Market] || []).push(val);
        return prev;
      }, {});
      return Promise.resolve(_objectSpread({}, data, {
        TradeHistoryGrp: TradeHistoryGrp
      }));
    }

    return Promise.resolve(data);
  };
};
var formatOrderBook = function formatOrderBook(data, level) {
  if (level === 2) {
    var _data$MDFullGrp$filte = data.MDFullGrp.filter(function (order) {
      return order.MDEntryType === '0' || order.MDEntryType === '1';
    }).reduce(function (prev, order) {
      var side = order.MDEntryType === '0' ? 'bids' : 'asks';
      (prev[side] || (prev[side] = [])).push(order);
      return prev;
    }, []),
        bids = _data$MDFullGrp$filte.bids,
        asks = _data$MDFullGrp$filte.asks;

    return _objectSpread({}, data, {
      MDFullGrp: _defineProperty({}, data.Symbol, {
        bids: bids || [],
        asks: asks || []
      })
    });
  }

  return data;
};

var MsgActionReq = {
  1: [HEARTBEAT, TestReqID],
  BE: [LOGIN, UserReqID],
  V: [MD_FULL_REFRESH, MDReqID],
  x: [SECURITY_LIST, SecurityReqID],
  e: [SECURITY_STATUS_SUBSCRIBE, SecurityStatusReqID],
  D: [ORDER_SEND, ClOrdID],
  F: [ORDER_CANCEL, ClOrdID],
  U2: [BALANCE, BalanceReqID],
  U6: [WITHDRAW_REQUEST, WithdrawReqID],
  U4: [ORDER_HISTORY, OrdersReqID],
  U18: [DEPOSIT_REQUEST, DepositReqID],
  U20: [DEPOSIT_METHODS, DepositMethodReqID],
  U24: [WITHDRAW_CONFIRM, WithdrawReqID],
  U26: [WITHDRAW_LIST, WithdrawListReqID],
  U28: [BROKER_LIST, BrokerListReqID],
  U30: [DEPOSIT_LIST, DepositListReqID],
  U32: [TRADE_HISTORY, TradeHistoryReqID],
  U34: [LEDGER_LIST, LedgerListReqID],
  U42: [POSITIONS, PositionReqID],
  U70: [WITHDRAW_CANCEL, WithdrawCancelReqID],
  B0: [DEPOSIT_PROCESS, ProcessDepositReqID],
  B2: [CUSTOMER_LIST, CustomerListReqID],
  B4: [KYC_REQUEST, CustomerReqID],
  B6: [WITHDRAW_PROCESS, ProcessWithdrawReqID],
  B8: [KYC_VERIFY, VerifyCustomerReqID]
};
var MsgActionRes = {
  0: [HEARTBEAT, TestReqID],
  BF: [LOGIN, UserReqID],
  W: [MD_FULL_REFRESH, MDReqID],
  X: [MD_INCREMENT, MDReqID],
  8: [EXECUTION_REPORT, ClOrdID],
  y: [SECURITY_LIST, SecurityReqID],
  f: [SECURITY_STATUS_SUBSCRIBE, SecurityStatusReqID],
  U3: [BALANCE, BalanceReqID],
  U7: [WITHDRAW_REQUEST, WithdrawReqID],
  U5: [ORDER_HISTORY, OrdersReqID],
  U9: [WITHDRAW_REFRESH, ClOrdID],
  U19: [DEPOSIT_REQUEST, DepositReqID],
  U21: [DEPOSIT_METHODS, DepositMethodReqID],
  U23: [DEPOSIT_REFRESH, ClOrdID],
  U25: [WITHDRAW_CONFIRM, WithdrawReqID],
  U27: [WITHDRAW_LIST, WithdrawListReqID],
  U29: [BROKER_LIST, BrokerListReqID],
  U31: [DEPOSIT_LIST, DepositListReqID],
  U33: [TRADE_HISTORY, TradeHistoryReqID],
  U35: [LEDGER_LIST, LedgerListReqID],
  U43: [POSITIONS, PositionReqID],
  U71: [WITHDRAW_CANCEL, WithdrawCancelReqID],
  U79: [WITHDRAW_COMMENT, WithdrawReqID],
  B1: [DEPOSIT_PROCESS, ProcessDepositReqID],
  B3: [CUSTOMER_LIST, CustomerListReqID],
  B5: [KYC_REQUEST, CustomerReqID],
  B9: [KYC_VERIFY, VerifyCustomerReqID],
  B7: [WITHDRAW_PROCESS, ProcessWithdrawReqID],
  B11: [CUSTOMER_REFRESH, '']
};
var ActionMsgReq = msgToAction(MsgActionReq);
var ActionMsgRes = msgToAction(MsgActionRes);

/**
 * BlinkTradeJS SDK
 * (c) 2016-present BlinkTrade, Inc.
 *
 * This file is part of BlinkTradeJS
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *      
 */
var reqs = new Map();
function generateRequestId() {
  return parseInt(String(1e7 * Math.random()), 10);
}

function getKey(messages, msg) {
  var key = messages[msg.MsgType][1];
  var value = msg[key];
  return key + ':' + value;
}

function getRequest(msg) {
  return reqs.get(getKey(MsgActionRes, msg));
}
function setRequest(msg, promise) {
  reqs.set(getKey(MsgActionReq, msg), promise);
}
function deleteRequest(msg) {
  reqs.delete(getKey(MsgActionRes, msg));
}

var ORDER_BOOK_TRADE_NEW = 'TRADE_NEW';
var ORDER_BOOK_NEW_ORDER = 'NEW_ORDER';
var ORDER_BOOK_UPDATE_ORDER = 'UPDATE_ORDER';
var ORDER_BOOK_DELETE_ORDER = 'DELETE_ORDER';
var ORDER_BOOK_DELETE_ORDERS_THRU = 'DELETE_ORDERS_THRU';
var EXECUTION_REPORT_NEW$1 = 'NEW';
var EXECUTION_REPORT_PARTIAL$1 = 'PARTIAL';
var EXECUTION_REPORT_EXECUTION$1 = 'EXECUTION';
var EXECUTION_REPORT_CANCELED$1 = 'CANCELED';
var EXECUTION_REPORT_REJECTED$1 = 'REJECTED';
/* eslint-disable quote-props */

var EVENTS = {
  ORDERBOOK: {
    '0': ORDER_BOOK_NEW_ORDER,
    '1': ORDER_BOOK_UPDATE_ORDER,
    '2': ORDER_BOOK_DELETE_ORDER,
    '3': ORDER_BOOK_DELETE_ORDERS_THRU
  },
  TRADES: {
    '0': ORDER_BOOK_TRADE_NEW
  },
  EXECUTION_REPORT: {
    '0': EXECUTION_REPORT_NEW$1,
    '1': EXECUTION_REPORT_PARTIAL$1,
    '2': EXECUTION_REPORT_EXECUTION$1,
    '4': EXECUTION_REPORT_CANCELED$1,
    '8': EXECUTION_REPORT_REJECTED$1
  }
};
var ORDER_TYPE = {
  MARKET: '1',
  LIMIT: '2',
  STOP: '3',
  STOP_LIMIT: '4'
};
var ORDER_SIDE = {
  BUY: '1',
  SELL: '2'
};

var TradeBase =
/*#__PURE__*/
function () {
  function TradeBase() {
    var params = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};

    _classCallCheck(this, TradeBase);

    this.level = params.level === undefined ? 2 : params.level;
    this.brokerId = params.brokerId || 4;
  }

  _createClass(TradeBase, [{
    key: "changeBrokerId",
    value: function changeBrokerId(brokerId) {
      this.brokerId = brokerId;
    }
  }, {
    key: "balance",
    value: function balance(clientId, callback) {
      var msg = {
        MsgType: ActionMsgReq.BALANCE,
        BalanceReqID: generateRequestId()
      };

      if (clientId) {
        msg.ClientID = clientId;
      }

      return nodeify_1.extend(this.send(msg)).nodeify(callback);
    }
  }, {
    key: "myOrders",
    value: function myOrders() {
      var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
          _ref$page = _ref.page,
          Page = _ref$page === void 0 ? 0 : _ref$page,
          _ref$pageSize = _ref.pageSize,
          PageSize = _ref$pageSize === void 0 ? 40 : _ref$pageSize,
          filter = _ref.filter;

      var callback = arguments.length > 1 ? arguments[1] : undefined;
      var msg = {
        MsgType: ActionMsgReq.ORDER_HISTORY,
        OrdersReqID: generateRequestId(),
        Page: Page,
        PageSize: PageSize
      };

      if (filter && filter !== 'all') {
        msg.Filter = filter === 'open' ? ['has_leaves_qty eq 1'] : filter === 'filled' ? ['has_cum_qty eq 1'] : filter === 'cancelled' ? ['has_cxl_qty eq 1'] : filter;
      }

      var format = formatColumns('OrdListGrp', this.level);
      return nodeify_1.extend(this.send(msg).then(format)).nodeify(callback);
    }
  }, {
    key: "sendOrder",
    value: function sendOrder(_ref2, callback) {
      var type = _ref2.type,
          side = _ref2.side,
          amount = _ref2.amount,
          price = _ref2.price,
          stopPrice = _ref2.stopPrice,
          symbol = _ref2.symbol,
          postOnly = _ref2.postOnly,
          clientId = _ref2.clientId;
      var msg = {
        MsgType: ActionMsgReq.ORDER_SEND,
        ClOrdID: clientId || generateRequestId().toString(),
        Side: ORDER_SIDE[side] || side,
        OrdType: ORDER_TYPE[type] || ORDER_TYPE.LIMIT,
        Symbol: symbol,
        OrderQty: amount,
        BrokerID: this.brokerId
      };

      if (price) {
        msg.Price = price;
      }

      if (stopPrice) {
        msg.StopPx = stopPrice;
      }

      if (postOnly) {
        msg.ExecInst = '6';
      }

      return nodeify_1.extend(this.send(msg)).nodeify(callback);
    }
  }, {
    key: "cancelOrder",
    value: function cancelOrder() {
      var param = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
      var callback = arguments.length > 1 ? arguments[1] : undefined;
      var orderId = param.orderId ? param.orderId : param;
      var msg = {
        MsgType: ActionMsgReq.ORDER_CANCEL
      };

      if (param.clientId) {
        msg.ClOrdID = param.clientId;
      }

      if (param.orderId) {
        msg.OrderID = orderId;
      }

      return nodeify_1.extend(this.send(msg)).nodeify(callback);
    }
    /**
     * status: 1-Pending, 2-In Progress, 4-Completed, 8-Cancelled
     */

  }, {
    key: "requestWithdrawList",
    value: function requestWithdrawList() {
      var _ref3 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
          filter = _ref3.filter,
          clientId = _ref3.clientId,
          _ref3$page = _ref3.page,
          Page = _ref3$page === void 0 ? 0 : _ref3$page,
          _ref3$pageSize = _ref3.pageSize,
          PageSize = _ref3$pageSize === void 0 ? 20 : _ref3$pageSize,
          _ref3$status = _ref3.status,
          StatusList = _ref3$status === void 0 ? ['1', '2', '4', '8'] : _ref3$status;

      var callback = arguments.length > 1 ? arguments[1] : undefined;
      var msg = {
        MsgType: ActionMsgReq.WITHDRAW_LIST,
        WithdrawListReqID: generateRequestId(),
        Page: Page,
        PageSize: PageSize,
        StatusList: StatusList
      };

      if (filter && filter.length) {
        msg.Filter = filter;
      }

      if (clientId) {
        msg.ClientID = clientId;
      }

      var format = formatColumns('WithdrawListGrp', this.level);
      return nodeify_1.extend(this.send(msg).then(format)).nodeify(callback);
    }
  }, {
    key: "requestWithdraw",
    value: function requestWithdraw(_ref4, callback) {
      var amount = _ref4.amount,
          data = _ref4.data,
          _ref4$currency = _ref4.currency,
          currency = _ref4$currency === void 0 ? 'BTC' : _ref4$currency,
          _ref4$method = _ref4.method,
          method = _ref4$method === void 0 ? 'bitcoin' : _ref4$method;
      var reqId = generateRequestId();
      var msg = {
        MsgType: ActionMsgReq.WITHDRAW_REQUEST,
        WithdrawReqID: reqId,
        ClOrdID: reqId,
        Method: method,
        Amount: amount,
        Currency: currency,
        Data: data
      };
      return nodeify_1.extend(this.send(msg)).nodeify(callback);
    }
  }, {
    key: "confirmWithdraw",
    value: function confirmWithdraw(_ref5, callback) {
      var WithdrawID = _ref5.withdrawId,
          confirmationToken = _ref5.confirmationToken,
          secondFactor = _ref5.secondFactor;
      var msg = {
        MsgType: ActionMsgReq.WITHDRAW_CONFIRM,
        WithdrawReqID: generateRequestId(),
        WithdrawID: WithdrawID
      };

      if (confirmationToken) {
        msg.ConfirmationToken = confirmationToken;
      }

      if (secondFactor) {
        msg.SecondFactor = secondFactor;
      }

      return nodeify_1.extend(this.send(msg)).nodeify(callback);
    }
  }, {
    key: "cancelWithdraw",
    value: function cancelWithdraw(withdrawId, callback) {
      var reqId = generateRequestId();
      var msg = {
        MsgType: ActionMsgReq.WITHDRAW_CANCEL,
        WithdrawCancelReqID: reqId,
        ClOrdID: reqId,
        WithdrawID: withdrawId
      };
      return nodeify_1.extend(this.send(msg)).nodeify(callback);
    }
  }, {
    key: "requestDepositList",
    value: function requestDepositList() {
      var _ref6 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
          _ref6$page = _ref6.page,
          Page = _ref6$page === void 0 ? 0 : _ref6$page,
          _ref6$pageSize = _ref6.pageSize,
          PageSize = _ref6$pageSize === void 0 ? 20 : _ref6$pageSize,
          _ref6$status = _ref6.status,
          StatusList = _ref6$status === void 0 ? ['1', '2', '4', '8'] : _ref6$status,
          filter = _ref6.filter,
          clientId = _ref6.clientId;

      var callback = arguments.length > 1 ? arguments[1] : undefined;
      var msg = {
        MsgType: ActionMsgReq.DEPOSIT_LIST,
        DepositListReqID: generateRequestId(),
        Page: Page,
        PageSize: PageSize,
        StatusList: StatusList
      };

      if (filter && filter.length) {
        msg.Filter = filter;
      }

      if (clientId) {
        msg.ClientID = clientId;
      }

      var format = formatColumns('DepositListGrp', this.level);
      return nodeify_1.extend(this.send(msg).then(format)).nodeify(callback);
    }
  }, {
    key: "requestDeposit",
    value: function requestDeposit() {
      var _ref7 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
          _ref7$currency = _ref7.currency,
          currency = _ref7$currency === void 0 ? 'BTC' : _ref7$currency,
          value = _ref7.value,
          depositMethodId = _ref7.depositMethodId;

      var callback = arguments.length > 1 ? arguments[1] : undefined;
      var reqId = generateRequestId();
      var msg = {
        MsgType: ActionMsgReq.DEPOSIT_REQUEST,
        DepositReqID: reqId,
        ClOrdID: reqId,
        Currency: currency,
        BrokerID: this.brokerId
      };

      if (currency !== 'BTC') {
        msg.DepositMethodID = depositMethodId;
        msg.Value = value;
      }

      return nodeify_1.extend(this.send(msg)).nodeify(callback);
    }
  }, {
    key: "requestDepositMethods",
    value: function requestDepositMethods(callback) {
      var msg = {
        MsgType: ActionMsgReq.DEPOSIT_METHODS,
        DepositMethodReqID: generateRequestId(),
        BrokerID: this.brokerId
      };
      return nodeify_1.extend(this.send(msg)).nodeify(callback);
    }
  }, {
    key: "requestBrokerList",
    value: function requestBrokerList(callback) {
      var msg = {
        MsgType: ActionMsgReq.BROKER_LIST,
        BrokerListReqID: generateRequestId(),
        Page: 0,
        PageSize: 20,
        StatusList: ['1']
      };
      var format = formatBrokerList(this.level);
      return nodeify_1.extend(this.send(msg).then(format)).nodeify(callback);
    }
  }, {
    key: "requestLedger",
    value: function requestLedger() {
      var _ref8 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
          _ref8$page = _ref8.page,
          Page = _ref8$page === void 0 ? 0 : _ref8$page,
          _ref8$pageSize = _ref8.pageSize,
          PageSize = _ref8$pageSize === void 0 ? 20 : _ref8$pageSize,
          brokerId = _ref8.brokerId,
          clientId = _ref8.clientId,
          currency = _ref8.currency;

      var callback = arguments.length > 1 ? arguments[1] : undefined;
      var msg = {
        MsgType: ActionMsgReq.LEDGER_LIST,
        LedgerListReqID: generateRequestId(),
        BrokerID: this.brokerId,
        Page: Page,
        PageSize: PageSize
      };

      if (brokerId) {
        msg.BrokerID = brokerId;
      }

      if (currency) {
        msg.Currency = currency;
      }

      if (clientId) {
        msg.ClientID = clientId;
      }

      var format = formatColumns('LedgerListGrp', this.level);
      return nodeify_1.extend(this.send(msg).then(format)).nodeify(callback);
    }
  }]);

  return TradeBase;
}();

var execFile = child_process.execFile;
var regexRegex = /[-\/\\^$*+?.()|[\]{}]/g;

function escape(string) {
  return string.replace(regexRegex, '\\$&');
}

var windows = function windows(iface, callback) {
  execFile("ipconfig", ["/all"], function (err, out) {
    if (err) {
      callback(err, null);
      return;
    }

    var match = new RegExp(escape(iface)).exec(out);

    if (!match) {
      callback("did not find interface in `ipconfig /all`", null);
      return;
    }

    out = out.substring(match.index + iface.length);
    match = /[A-Fa-f0-9]{2}(\-[A-Fa-f0-9]{2}){5}/.exec(out);

    if (!match) {
      callback("did not find a mac address", null);
      return;
    }

    callback(null, match[0].toLowerCase().replace(/\-/g, ':'));
  });
};

var execFile$1 = child_process.execFile;

var linux = function linux(iface, callback) {
  execFile$1("cat", ["/sys/class/net/" + iface + "/address"], function (err, out) {
    if (err) {
      callback(err, null);
      return;
    }

    callback(null, out.trim().toLowerCase());
  });
};

var execFile$2 = child_process.execFile;

var unix = function unix(iface, callback) {
  execFile$2("ifconfig", [iface], function (err, out) {
    if (err) {
      callback(err, null);
      return;
    }

    var match = /[a-f0-9]{2}(:[a-f0-9]{2}){5}/.exec(out.toLowerCase());

    if (!match) {
      callback("did not find a mac address", null);
      return;
    }

    callback(null, match[0].toLowerCase());
  });
};

var lib = {};

function parallel(tasks, done) {
  var results = [];
  var errs = [];
  var length = 0;
  var doneLength = 0;

  function doneIt(ix, err, result) {
    if (err) {
      errs[ix] = err;
    } else {
      results[ix] = result;
    }

    doneLength += 1;

    if (doneLength >= length) {
      done(errs.length > 0 ? errs : errs, results);
    }
  }

  Object.keys(tasks).forEach(function (key) {
    length += 1;
    var task = tasks[key];
    (process.nextTick || commonjsGlobal.setImmediate || commonjsGlobal.setTimeout)(function () {
      task(doneIt.bind(null, key), 1);
    });
  });
}

lib.networkInterfaces = function () {
  var ifaces = os.networkInterfaces();
  var allAddresses = {};
  Object.keys(ifaces).forEach(function (iface) {
    var addresses = {};
    var hasAddresses = false;
    ifaces[iface].forEach(function (address) {
      if (!address.internal) {
        addresses[(address.family || "").toLowerCase()] = address.address;
        hasAddresses = true;

        if (address.mac) {
          addresses.mac = address.mac;
        }
      }
    });

    if (hasAddresses) {
      allAddresses[iface] = addresses;
    }
  });
  return allAddresses;
};

var _getMacAddress;

switch (os.platform()) {
  case 'win32':
    _getMacAddress = windows;
    break;

  case 'linux':
    _getMacAddress = linux;
    break;

  case 'darwin':
  case 'sunos':
    _getMacAddress = unix;
    break;

  default:
    console.warn("node-macaddress: Unkown os.platform(), defaulting to `unix'.");
    _getMacAddress = unix;
    break;
}

lib.one = function (iface, callback) {
  if (typeof iface === 'function') {
    callback = iface;
    var ifaces = lib.networkInterfaces();
    var alleged = ['eth0', 'eth1', 'en0', 'en1'];
    iface = Object.keys(ifaces)[0];

    for (var i = 0; i < alleged.length; i++) {
      if (ifaces[alleged[i]]) {
        iface = alleged[i];
        break;
      }
    }

    if (!ifaces[iface]) {
      if (typeof callback === 'function') {
        process.nextTick(function () {
          callback(new Error("no interfaces found"), null);
        });
      }

      return null;
    }

    if (ifaces[iface].mac) {
      if (typeof callback === 'function') {
        process.nextTick(function () {
          callback(null, ifaces[iface].mac);
        });
      }

      return ifaces[iface].mac;
    }
  }

  if (typeof callback === 'function') {
    _getMacAddress(iface, callback);
  }

  return null;
};

lib.all = function (callback) {
  var ifaces = lib.networkInterfaces();
  var resolve = {};
  Object.keys(ifaces).forEach(function (iface) {
    if (!ifaces[iface].mac) {
      resolve[iface] = _getMacAddress.bind(null, iface);
    }
  });

  if (Object.keys(resolve).length === 0) {
    if (typeof callback === 'function') {
      process.nextTick(function () {
        callback(null, ifaces);
      });
    }

    return ifaces;
  }

  parallel(resolve, function (err, result) {
    Object.keys(result).forEach(function (iface) {
      ifaces[iface].mac = result[iface];
    });

    if (typeof callback === 'function') {
      callback(null, ifaces);
    }
  });
  return null;
};

var macaddressSecure = lib;

/**
 * BlinkTradeJS SDK
 * (c) 2016-present BlinkTrade, Inc.
 *
 * This file is part of BlinkTradeJS
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *      
 */
function getMac(callback) {
  macaddressSecure.all(function (err, all) {
    var hashCode = function hashCode(str) {
      var hash = 0;
      if (str.length === 0) return hash;

      for (var i = 0; i < str.length; i++) {
        hash = (hash << 5) - hash + str.charCodeAt(i);
        hash = hash & hash; // Convert to 32bit integer
      }

      return hash;
    };

    var macAddresses = '';
    Object.keys(all).forEach(function (iface) {
      macAddresses += all[iface].mac;
    });
    var fingerPrint = hashCode(macAddresses);

    if (fingerPrint < 0) {
      fingerPrint *= -1;
    }

    callback(fingerPrint);
  });
}

var sha256 = createCommonjsModule(function (module) {
  /**
   * [js-sha256]{@link https://github.com/emn178/js-sha256}
   *
   * @version 0.9.0
   * @author Chen, Yi-Cyuan [emn178@gmail.com]
   * @copyright Chen, Yi-Cyuan 2014-2017
   * @license MIT
   */

  /*jslint bitwise: true */
  (function () {

    var ERROR = 'input is invalid type';
    var WINDOW = (typeof window === "undefined" ? "undefined" : _typeof(window)) === 'object';
    var root = WINDOW ? window : {};

    if (root.JS_SHA256_NO_WINDOW) {
      WINDOW = false;
    }

    var WEB_WORKER = !WINDOW && (typeof self === "undefined" ? "undefined" : _typeof(self)) === 'object';
    var NODE_JS = !root.JS_SHA256_NO_NODE_JS && (typeof process === "undefined" ? "undefined" : _typeof(process)) === 'object' && process.versions && process.versions.node;

    if (NODE_JS) {
      root = commonjsGlobal;
    } else if (WEB_WORKER) {
      root = self;
    }

    var COMMON_JS = !root.JS_SHA256_NO_COMMON_JS && 'object' === 'object' && module.exports;
    var ARRAY_BUFFER = !root.JS_SHA256_NO_ARRAY_BUFFER && typeof ArrayBuffer !== 'undefined';
    var HEX_CHARS = '0123456789abcdef'.split('');
    var EXTRA = [-2147483648, 8388608, 32768, 128];
    var SHIFT = [24, 16, 8, 0];
    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 OUTPUT_TYPES = ['hex', 'array', 'digest', 'arrayBuffer'];
    var blocks = [];

    if (root.JS_SHA256_NO_NODE_JS || !Array.isArray) {
      Array.isArray = function (obj) {
        return Object.prototype.toString.call(obj) === '[object Array]';
      };
    }

    if (ARRAY_BUFFER && (root.JS_SHA256_NO_ARRAY_BUFFER_IS_VIEW || !ArrayBuffer.isView)) {
      ArrayBuffer.isView = function (obj) {
        return _typeof(obj) === 'object' && obj.buffer && obj.buffer.constructor === ArrayBuffer;
      };
    }

    var createOutputMethod = function createOutputMethod(outputType, is224) {
      return function (message) {
        return new Sha256(is224, true).update(message)[outputType]();
      };
    };

    var createMethod = function createMethod(is224) {
      var method = createOutputMethod('hex', is224);

      if (NODE_JS) {
        method = nodeWrap(method, is224);
      }

      method.create = function () {
        return new Sha256(is224);
      };

      method.update = function (message) {
        return method.create().update(message);
      };

      for (var i = 0; i < OUTPUT_TYPES.length; ++i) {
        var type = OUTPUT_TYPES[i];
        method[type] = createOutputMethod(type, is224);
      }

      return method;
    };

    var nodeWrap = function nodeWrap(method, is224) {
      var crypto = eval("require('crypto')");
      var Buffer = eval("require('buffer').Buffer");
      var algorithm = is224 ? 'sha224' : 'sha256';

      var nodeMethod = function nodeMethod(message) {
        if (typeof message === 'string') {
          return crypto.createHash(algorithm).update(message, 'utf8').digest('hex');
        } else {
          if (message === null || message === undefined) {
            throw new Error(ERROR);
          } else if (message.constructor === ArrayBuffer) {
            message = new Uint8Array(message);
          }
        }

        if (Array.isArray(message) || ArrayBuffer.isView(message) || message.constructor === Buffer) {
          return crypto.createHash(algorithm).update(new Buffer(message)).digest('hex');
        } else {
          return method(message);
        }
      };

      return nodeMethod;
    };

    var createHmacOutputMethod = function createHmacOutputMethod(outputType, is224) {
      return function (key, message) {
        return new HmacSha256(key, is224, true).update(message)[outputType]();
      };
    };

    var createHmacMethod = function createHmacMethod(is224) {
      var method = createHmacOutputMethod('hex', is224);

      method.create = function (key) {
        return new HmacSha256(key, is224);
      };

      method.update = function (key, message) {
        return method.create(key).update(message);
      };

      for (var i = 0; i < OUTPUT_TYPES.length; ++i) {
        var type = OUTPUT_TYPES[i];
        method[type] = createHmacOutputMethod(type, is224);
      }

      return method;
    };

    function Sha256(is224, sharedMemory) {
      if (sharedMemory) {
        blocks[0] = blocks[16] = blocks[1] = blocks[2] = blocks[3] = blocks[4] = blocks[5] = blocks[6] = blocks[7] = blocks[8] = blocks[9] = blocks[10] = blocks[11] = blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0;
        this.blocks = blocks;
      } else {
        this.blocks = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
      }

      if (is224) {
        this.h0 = 0xc1059ed8;
        this.h1 = 0x367cd507;
        this.h2 = 0x3070dd17;
        this.h3 = 0xf70e5939;
        this.h4 = 0xffc00b31;
        this.h5 = 0x68581511;
        this.h6 = 0x64f98fa7;
        this.h7 = 0xbefa4fa4;
      } else {
        // 256
        this.h0 = 0x6a09e667;
        this.h1 = 0xbb67ae85;
        this.h2 = 0x3c6ef372;
        this.h3 = 0xa54ff53a;
        this.h4 = 0x510e527f;
        this.h5 = 0x9b05688c;
        this.h6 = 0x1f83d9ab;
        this.h7 = 0x5be0cd19;
      }

      this.block = this.start = this.bytes = this.hBytes = 0;
      this.finalized = this.hashed = false;
      this.first = true;
      this.is224 = is224;
    }

    Sha256.prototype.update = function (message) {
      if (this.finalized) {
        return;
      }

      var notString,
          type = _typeof(message);

      if (type !== 'string') {
        if (type === 'object') {
          if (message === null) {
            throw new Error(ERROR);
          } else if (ARRAY_BUFFER && message.constructor === ArrayBuffer) {
            message = new Uint8Array(message);
          } else if (!Array.isArray(message)) {
            if (!ARRAY_BUFFER || !ArrayBuffer.isView(message)) {
              throw new Error(ERROR);
            }
          }
        } else {
          throw new Error(ERROR);
        }

        notString = true;
      }

      var code,
          index = 0,
          i,
          length = message.length,
          blocks = this.blocks;

      while (index < length) {
        if (this.hashed) {
          this.hashed = false;
          blocks[0] = this.block;
          blocks[16] = blocks[1] = blocks[2] = blocks[3] = blocks[4] = blocks[5] = blocks[6] = blocks[7] = blocks[8] = blocks[9] = blocks[10] = blocks[11] = blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0;
        }

        if (notString) {
          for (i = this.start; index < length && i < 64; ++index) {
            blocks[i >> 2] |= message[index] << SHIFT[i++ & 3];
          }
        } else {
          for (i = this.start; index < length && i < 64; ++index) {
            code = message.charCodeAt(index);

            if (code < 0x80) {
              blocks[i >> 2] |= code << SHIFT[i++ & 3];
            } else if (code < 0x800) {
              blocks[i >> 2] |= (0xc0 | code >> 6) << SHIFT[i++ & 3];
              blocks[i >> 2] |= (0x80 | code & 0x3f) << SHIFT[i++ & 3];
            } else if (code < 0xd800 || code >= 0xe000) {
              blocks[i >> 2] |= (0xe0 | code >> 12) << SHIFT[i++ & 3];
              blocks[i >> 2] |= (0x80 | code >> 6 & 0x3f) << SHIFT[i++ & 3];
              blocks[i >> 2] |= (0x80 | code & 0x3f) << SHIFT[i++ & 3];
            } else {
              code = 0x10000 + ((code & 0x3ff) << 10 | message.charCodeAt(++index) & 0x3ff);
              blocks[i >> 2] |= (0xf0 | code >> 18) << SHIFT[i++ & 3];
              blocks[i >> 2] |= (0x80 | code >> 12 & 0x3f) << SHIFT[i++ & 3];
              blocks[i >> 2] |= (0x80 | code >> 6 & 0x3f) << SHIFT[i++ & 3];
              blocks[i >> 2] |= (0x80 | code & 0x3f) << SHIFT[i++ & 3];
            }
          }
        }

        this.lastByteIndex = i;
        this.bytes += i - this.start;

        if (i >= 64) {
          this.block = blocks[16];
          this.start = i - 64;
          this.hash();
          this.hashed = true;
        } else {
          this.start = i;
        }
      }

      if (this.bytes > 4294967295) {
        this.hBytes += this.bytes / 4294967296 << 0;
        this.bytes = this.bytes % 4294967296;
      }

      return this;
    };

    Sha256.prototype.finalize = function () {
      if (this.finalized) {
        return;
      }

      this.finalized = true;
      var blocks = this.blocks,
          i = this.lastByteIndex;
      blocks[16] = this.block;
      blocks[i >> 2] |= EXTRA[i & 3];
      this.block = blocks[16];

      if (i >= 56) {
        if (!this.hashed) {
          this.hash();
        }

        blocks[0] = this.block;
        blocks[16] = blocks[1] = blocks[2] = blocks[3] = blocks[4] = blocks[5] = blocks[6] = blocks[7] = blocks[8] = blocks[9] = blocks[10] = blocks[11] = blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0;
      }

      blocks[14] = this.hBytes << 3 | this.bytes >>> 29;
      blocks[15] = this.bytes << 3;
      this.hash();
    };

    Sha256.prototype.hash = function () {
      var a = this.h0,
          b = this.h1,
          c = this.h2,
          d = this.h3,
          e = this.h4,
          f = this.h5,
          g = this.h6,
          h = this.h7,
          blocks = this.blocks,
          j,
          s0,
          s1,
          maj,
          t1,
          t2,
          ch,
          ab,
          da,
          cd,
          bc;

      for (j = 16; j < 64; ++j) {
        // rightrotate
        t1 = blocks[j - 15];
        s0 = (t1 >>> 7 | t1 << 25) ^ (t1 >>> 18 | t1 << 14) ^ t1 >>> 3;
        t1 = blocks[j - 2];
        s1 = (t1 >>> 17 | t1 << 15) ^ (t1 >>> 19 | t1 << 13) ^ t1 >>> 10;
        blocks[j] = blocks[j - 16] + s0 + blocks[j - 7] + s1 << 0;
      }

      bc = b & c;

      for (j = 0; j < 64; j += 4) {
        if (this.first) {
          if (this.is224) {
            ab = 300032;
            t1 = blocks[0] - 1413257819;
            h = t1 - 150054599 << 0;
            d = t1 + 24177077 << 0;
          } else {
            ab = 704751109;
            t1 = blocks[0] - 210244248;
            h = t1 - 1521486534 << 0;
            d = t1 + 143694565 << 0;
          }

          this.first = false;
        } else {
          s0 = (a >>> 2 | a << 30) ^ (a >>> 13 | a << 19) ^ (a >>> 22 | a << 10);
          s1 = (e >>> 6 | e << 26) ^ (e >>> 11 | e << 21) ^ (e >>> 25 | e << 7);
          ab = a & b;
          maj = ab ^ a & c ^ bc;
          ch = e & f ^ ~e & g;
          t1 = h + s1 + ch + K[j] + blocks[j];
          t2 = s0 + maj;
          h = d + t1 << 0;
          d = t1 + t2 << 0;
        }

        s0 = (d >>> 2 | d << 30) ^ (d >>> 13 | d << 19) ^ (d >>> 22 | d << 10);
        s1 = (h >>> 6 | h << 26) ^ (h >>> 11 | h << 21) ^ (h >>> 25 | h << 7);
        da = d & a;
        maj = da ^ d & b ^ ab;
        ch = h & e ^ ~h & f;
        t1 = g + s1 + ch + K[j + 1] + blocks[j + 1];
        t2 = s0 + maj;
        g = c + t1 << 0;
        c = t1 + t2 << 0;
        s0 = (c >>> 2 | c << 30) ^ (c >>> 13 | c << 19) ^ (c >>> 22 | c << 10);
        s1 = (g >>> 6 | g << 26) ^ (g >>> 11 | g << 21) ^ (g >>> 25 | g << 7);
        cd = c & d;
        maj = cd ^ c & a ^ da;
        ch = g & h ^ ~g & e;
        t1 = f + s1 + ch + K[j + 2] + blocks[j + 2];
        t2 = s0 + maj;
        f = b + t1 << 0;
        b = t1 + t2 << 0;
        s0 = (b >>> 2 | b << 30) ^ (b >>> 13 | b << 19) ^ (b >>> 22 | b << 10);
        s1 = (f >>> 6 | f << 26) ^ (f >>> 11 | f << 21) ^ (f >>> 25 | f << 7);
        bc = b & c;
        maj = bc ^ b & d ^ cd;
        ch = f & g ^ ~f & h;
        t1 = e + s1 + ch + K[j + 3] + blocks[j + 3];
        t2 = s0 + maj;
        e = a + t1 << 0;
        a = t1 + t2 << 0;
      }

      this.h0 = this.h0 + a << 0;
      this.h1 = this.h1 + b << 0;
      this.h2 = this.h2 + c << 0;
      this.h3 = this.h3 + d << 0;
      this.h4 = this.h4 + e << 0;
      this.h5 = this.h5 + f << 0;
      this.h6 = this.h6 + g << 0;
      this.h7 = this.h7 + h << 0;
    };

    Sha256.prototype.hex = function () {
      this.finalize();
      var h0 = this.h0,
          h1 = this.h1,
          h2 = this.h2,
          h3 = this.h3,
          h4 = this.h4,
          h5 = this.h5,
          h6 = this.h6,
          h7 = this.h7;
      var hex = HEX_CHARS[h0 >> 28 & 0x0F] + HEX_CHARS[h0 >> 24 & 0x0F] + HEX_CHARS[h0 >> 20 & 0x0F] + HEX_CHARS[h0 >> 16 & 0x0F] + HEX_CHARS[h0 >> 12 & 0x0F] + HEX_CHARS[h0 >> 8 & 0x0F] + HEX_CHARS[h0 >> 4 & 0x0F] + HEX_CHARS[h0 & 0x0F] + HEX_CHARS[h1 >> 28 & 0x0F] + HEX_CHARS[h1 >> 24 & 0x0F] + HEX_CHARS[h1 >> 20 & 0x0F] + HEX_CHARS[h1 >> 16 & 0x0F] + HEX_CHARS[h1 >> 12 & 0x0F] + HEX_CHARS[h1 >> 8 & 0x0F] + HEX_CHARS[h1 >> 4 & 0x0F] + HEX_CHARS[h1 & 0x0F] + HEX_CHARS[h2 >> 28 & 0x0F] + HEX_CHARS[h2 >> 24 & 0x0F] + HEX_CHARS[h2 >> 20 & 0x0F] + HEX_CHARS[h2 >> 16 & 0x0F] + HEX_CHARS[h2 >> 12 & 0x0F] + HEX_CHARS[h2 >> 8 & 0x0F] + HEX_CHARS[h2 >> 4 & 0x0F] + HEX_CHARS[h2 & 0x0F] + HEX_CHARS[h3 >> 28 & 0x0F] + HEX_CHARS[h3 >> 24 & 0x0F] + HEX_CHARS[h3 >> 20 & 0x0F] + HEX_CHARS[h3 >> 16 & 0x0F] + HEX_CHARS[h3 >> 12 & 0x0F] + HEX_CHARS[h3 >> 8 & 0x0F] + HEX_CHARS[h3 >> 4 & 0x0F] + HEX_CHARS[h3 & 0x0F] + HEX_CHARS[h4 >> 28 & 0x0F] + HEX_CHARS[h4 >> 24 & 0x0F] + HEX_CHARS[h4 >> 20 & 0x0F] + HEX_CHARS[h4 >> 16 & 0x0F] + HEX_CHARS[h4 >> 12 & 0x0F] + HEX_CHARS[h4 >> 8 & 0x0F] + HEX_CHARS[h4 >> 4 & 0x0F] + HEX_CHARS[h4 & 0x0F] + HEX_CHARS[h5 >> 28 & 0x0F] + HEX_CHARS[h5 >> 24 & 0x0F] + HEX_CHARS[h5 >> 20 & 0x0F] + HEX_CHARS[h5 >> 16 & 0x0F] + HEX_CHARS[h5 >> 12 & 0x0F] + HEX_CHARS[h5 >> 8 & 0x0F] + HEX_CHARS[h5 >> 4 & 0x0F] + HEX_CHARS[h5 & 0x0F] + HEX_CHARS[h6 >> 28 & 0x0F] + HEX_CHARS[h6 >> 24 & 0x0F] + HEX_CHARS[h6 >> 20 & 0x0F] + HEX_CHARS[h6 >> 16 & 0x0F] + HEX_CHARS[h6 >> 12 & 0x0F] + HEX_CHARS[h6 >> 8 & 0x0F] + HEX_CHARS[h6 >> 4 & 0x0F] + HEX_CHARS[h6 & 0x0F];

      if (!this.is224) {
        hex += HEX_CHARS[h7 >> 28 & 0x0F] + HEX_CHARS[h7 >> 24 & 0x0F] + HEX_CHARS[h7 >> 20 & 0x0F] + HEX_CHARS[h7 >> 16 & 0x0F] + HEX_CHARS[h7 >> 12 & 0x0F] + HEX_CHARS[h7 >> 8 & 0x0F] + HEX_CHARS[h7 >> 4 & 0x0F] + HEX_CHARS[h7 & 0x0F];
      }

      return hex;
    };

    Sha256.prototype.toString = Sha256.prototype.hex;

    Sha256.prototype.digest = function () {
      this.finalize();
      var h0 = this.h0,
          h1 = this.h1,
          h2 = this.h2,
          h3 = this.h3,
          h4 = this.h4,
          h5 = this.h5,
          h6 = this.h6,
          h7 = this.h7;
      var arr = [h0 >> 24 & 0xFF, h0 >> 16 & 0xFF, h0 >> 8 & 0xFF, h0 & 0xFF, h1 >> 24 & 0xFF, h1 >> 16 & 0xFF, h1 >> 8 & 0xFF, h1 & 0xFF, h2 >> 24 & 0xFF, h2 >> 16 & 0xFF, h2 >> 8 & 0xFF, h2 & 0xFF, h3 >> 24 & 0xFF, h3 >> 16 & 0xFF, h3 >> 8 & 0xFF, h3 & 0xFF, h4 >> 24 & 0xFF, h4 >> 16 & 0xFF, h4 >> 8 & 0xFF, h4 & 0xFF, h5 >> 24 & 0xFF, h5 >> 16 & 0xFF, h5 >> 8 & 0xFF, h5 & 0xFF, h6 >> 24 & 0xFF, h6 >> 16 & 0xFF, h6 >> 8 & 0xFF, h6 & 0xFF];

      if (!this.is224) {
        arr.push(h7 >> 24 & 0xFF, h7 >> 16 & 0xFF, h7 >> 8 & 0xFF, h7 & 0xFF);
      }

      return arr;
    };

    Sha256.prototype.array = Sha256.prototype.digest;

    Sha256.prototype.arrayBuffer = function () {
      this.finalize();
      var buffer$$1 = new ArrayBuffer(this.is224 ? 28 : 32);
      var dataView = new DataView(buffer$$1);
      dataView.setUint32(0, this.h0);
      dataView.setUint32(4, this.h1);
      dataView.setUint32(8, this.h2);
      dataView.setUint32(12, this.h3);
      dataView.setUint32(16, this.h4);
      dataView.setUint32(20, this.h5);
      dataView.setUint32(24, this.h6);

      if (!this.is224) {
        dataView.setUint32(28, this.h7);
      }

      return buffer$$1;
    };

    function HmacSha256(key, is224, sharedMemory) {
      var i,
          type = _typeof(key);

      if (type === 'string') {
        var bytes = [],
            length = key.length,
            index = 0,
            code;

        for (i = 0; i < length; ++i) {
          code = key.charCodeAt(i);

          if (code < 0x80) {
            bytes[index++] = code;
          } else if (code < 0x800) {
            bytes[index++] = 0xc0 | code >> 6;
            bytes[index++] = 0x80 | code & 0x3f;
          } else if (code < 0xd800 || code >= 0xe000) {
            bytes[index++] = 0xe0 | code >> 12;
            bytes[index++] = 0x80 | code >> 6 & 0x3f;
            bytes[index++] = 0x80 | code & 0x3f;
          } else {
            code = 0x10000 + ((code & 0x3ff) << 10 | key.charCodeAt(++i) & 0x3ff);
            bytes[index++] = 0xf0 | code >> 18;
            bytes[index++] = 0x80 | code >> 12 & 0x3f;
            bytes[index++] = 0x80 | code >> 6 & 0x3f;
            bytes[index++] = 0x80 | code & 0x3f;
          }
        }

        key = bytes;
      } else {
        if (type === 'object') {
          if (key === null) {
            throw new Error(ERROR);
          } else if (ARRAY_BUFFER && key.constructor === ArrayBuffer) {
            key = new Uint8Array(key);
          } else if (!Array.isArray(key)) {
            if (!ARRAY_BUFFER || !ArrayBuffer.isView(key)) {
              throw new Error(ERROR);
            }
          }
        } else {
          throw new Error(ERROR);
        }
      }

      if (key.length > 64) {
        key = new Sha256(is224, true).update(key).array();
      }

      var oKeyPad = [],
          iKeyPad = [];

      for (i = 0; i < 64; ++i) {
        var b = key[i] || 0;
        oKeyPad[i] = 0x5c ^ b;
        iKeyPad[i] = 0x36 ^ b;
      }

      Sha256.call(this, is224, sharedMemory);
      this.update(iKeyPad);
      this.oKeyPad = oKeyPad;
      this.inner = true;
      this.sharedMemory = sharedMemory;
    }

    HmacSha256.prototype = new Sha256();

    HmacSha256.prototype.finalize = function () {
      Sha256.prototype.finalize.call(this);

      if (this.inner) {
        this.inner = false;
        var innerHash = this.array();
        Sha256.call(this, this.is224, this.sharedMemory);
        this.update(this.oKeyPad);
        this.update(innerHash);
        Sha256.prototype.finalize.call(this);
      }
    };

    var exports = createMethod();
    exports.sha256 = exports;
    exports.sha224 = createMethod(true);
    exports.sha256.hmac = createHmacMethod();
    exports.sha224.hmac = createHmacMethod(true);

    if (COMMON_JS) {
      module.exports = exports;
    } else {
      root.sha256 = exports.sha256;
      root.sha224 = exports.sha224;
    }
  })();
});

/* eslint-disable no-var */

/* eslint-disable no-bitwise */

/* eslint-disable no-param-reassign */

/* eslint-disable no-fallthrough */

/* eslint-disable no-underscore-dangle */

/* eslint-disable default-case */

/* eslint-disable prefer-destructuring */

/*
 * ByteArray enconding from google-closure-library
 */
var SEED32 = 314159265;
var CONSTANT32 = -1640531527;
/**
 * Performs an inplace mix of an object with the integer properties (a, b, c)
 * and returns the final value of c.
 * @param {Object} mix Object with properties, a, b, and c.
 * @return {number} The end c-value for the mixing.
 * @private
 */

var mix32_ = function mix32_(mix) {
  var a = mix.a;
  var b = mix.b;
  var c = mix.c;
  a -= b;
  a -= c;
  a ^= c >>> 13;
  b -= c;
  b -= a;
  b ^= a << 8;
  c -= a;
  c -= b;
  c ^= b >>> 13;
  a -= b;
  a -= c;
  a ^= c >>> 12;
  b -= c;
  b -= a;
  b ^= a << 16;
  c -= a;
  c -= b;
  c ^= b >>> 5;
  a -= b;
  a -= c;
  a ^= c >>> 3;
  b -= c;
  b -= a;
  b ^= a << 10;
  c -= a;
  c -= b;
  c ^= b >>> 15;
  mix.a = a;
  mix.b = b;
  mix.c = c;
  return c;
};
/**
 * Converts an unsigned "byte" to signed, that is, convert a value in the range
 * (0, 2^8-1) to (-2^7, 2^7-1) in order to be compatible with Java's byte type.
 * @param {number} n Unsigned "byte" value.
 * @return {number} Signed "byte" value.
 * @private
 */


var toSigned_ = function toSigned_(n) {
  return n > 127 ? n - 256 : n;
};

var wordAt_ = function wordAt_(bytes, offset) {
  var a = toSigned_(bytes[offset + 0]);
  var b = toSigned_(bytes[offset + 1]);
  var c = toSigned_(bytes[offset + 2]);
  var d = toSigned_(bytes[offset + 3]);
  return a + (b << 8) + (c << 16) + (d << 24);
};
/**
 * Hashes a "byte" array to a 32-bit value using the supplied seed.
 */


function encodeByteArray(bytes) {
  var offset = 0;
  var length = bytes.length;
  var seed = SEED32;
  var mix = {
    a: CONSTANT32,
    b: CONSTANT32,
    c: seed
  };
  var keylen;

  for (keylen = length; keylen >= 12; keylen -= 12, offset += 12) {
    mix.a += wordAt_(bytes, offset);
    mix.b += wordAt_(bytes, offset + 4);
    mix.c += wordAt_(bytes, offset + 8);
    mix32_(mix);
  } // Hash any remaining bytes


  mix.c += length;

  switch (keylen) {
    // deal with rest.  Some cases fall through
    case 11:
      mix.c += bytes[offset + 10] << 24;

    case 10:
      mix.c += (bytes[offset + 9] & 0xff) << 16;

    case 9:
      mix.c += (bytes[offset + 8] & 0xff) << 8;
    // the first byte of c is reserved for the length

    case 8:
      mix.b += wordAt_(bytes, offset + 4);
      mix.a += wordAt_(bytes, offset);
      break;

    case 7:
      mix.b += (bytes[offset + 6] & 0xff) << 16;

    case 6:
      mix.b += (bytes[offset + 5] & 0xff) << 8;

    case 5:
      mix.b += bytes[offset + 4] & 0xff;

    case 4:
      mix.a += wordAt_(bytes, offset);
      break;

    case 3:
      mix.a += (bytes[offset + 2] & 0xff) << 16;

    case 2:
      mix.a += (bytes[offset + 1] & 0xff) << 8;

    case 1:
      mix.a += bytes[offset + 0] & 0xff;
    // case 0 : nothing left to add
  }

  return mix32_(mix);
}

function getFingerPrint() {
  var keys = [];
  keys.push(window.navigator.userAgent);
  keys.push(window.screen.colorDepth);
  keys.push(window.navigator.language);

  if (Array.isArray(window.navigator.languages)) {
    keys.push(window.navigator.languages.join('x'));
  } else {
    keys.push("undefined");
  }

  var resolution = window.screen.height > window.screen.width ? [window.screen.height, window.screen.width] : [window.screen.width, window.screen.height];
  keys.push(resolution.join('x'));
  keys.push(new Date().getTimezoneOffset());
  keys.push(typeof window.sessionStorage !== 'undefined');
  keys.push(typeof window.localStorage !== 'undefined');
  keys.push(!!window.indexedDB);

  if (document.body) {
    keys.push(_typeof(window.document.body.addBehavior));
  } else {
    keys.push("undefined");
  }

  keys.push(_typeof(window.openDatabase));
  keys.push(window.navigator.cpuClass);
  keys.push(window.navigator.platform);
  keys.push(window.navigator.doNotTrack);
  var pluginKeyList = [];
  Array.from(window.navigator.plugins).forEach(function (p) {
    var mimeTypes = [];
    Object.values(p).forEach(function (mt) {
      mimeTypes.push([mt.type, mt.suffixes].join('~'));
    });
    pluginKeyList.push([p.name, p.description, mimeTypes.join(',')].join('::'));
  });
  keys.push(pluginKeyList.join(';'));
  var canvasEl = document.createElement('canvas');

  if (canvasEl.getContext && canvasEl.getContext('2d')) {
    var ctx = canvasEl.getContext('2d');
    var txt = 'http://valve.github.io';
    ctx.textBaseline = 'top';
    ctx.font = "14px 'Arial'";
    ctx.textBaseline = 'alphabetic';
    ctx.fillStyle = '#f60';
    ctx.fillRect(125, 1, 62, 20);
    ctx.fillStyle = '#069';
    ctx.fillText(txt, 2, 15);
    ctx.fillStyle = 'rgba(102, 204, 0, 0.7)';
    ctx.fillText(txt, 4, 17);
    keys.push(canvasEl.toDataURL());
  }

  var digest = sha256.digest(keys.join('###'));
  var fingerPrint = parseInt(encodeByteArray(digest));

  if (fingerPrint < 0) {
    fingerPrint *= -1;
  }

  return fingerPrint;
}

var ip_1 = createCommonjsModule(function (module, exports) {

  var ip = exports;
  var Buffer = buffer.Buffer;

  ip.toBuffer = function (ip, buff, offset) {
    offset = ~~offset;
    var result;

    if (this.isV4Format(ip)) {
      result = buff || new Buffer(offset + 4);
      ip.split(/\./g).map(function (byte) {
        result[offset++] = parseInt(byte, 10) & 0xff;
      });
    } else if (this.isV6Format(ip)) {
      var sections = ip.split(':', 8);
      var i;

      for (i = 0; i < sections.length; i++) {
        var isv4 = this.isV4Format(sections[i]);
        var v4Buffer;

        if (isv4) {
          v4Buffer = this.toBuffer(sections[i]);
          sections[i] = v4Buffer.slice(0, 2).toString('hex');
        }

        if (v4Buffer && ++i < 8) {
          sections.splice(i, 0, v4Buffer.slice(2, 4).toString('hex'));
        }
      }

      if (sections[0] === '') {
        while (sections.length < 8) {
          sections.unshift('0');
        }
      } else if (sections[sections.length - 1] === '') {
        while (sections.length < 8) {
          sections.push('0');
        }
      } else if (sections.length < 8) {
        for (i = 0; i < sections.length && sections[i] !== ''; i++) {
        }

        var argv = [i, 1];

        for (i = 9 - sections.length; i > 0; i--) {
          argv.push('0');
        }

        sections.splice.apply(sections, argv);
      }

      result = buff || new Buffer(offset + 16);

      for (i = 0; i < sections.length; i++) {
        var word = parseInt(sections[i], 16);
        result[offset++] = word >> 8 & 0xff;
        result[offset++] = word & 0xff;
      }
    }

    if (!result) {
      throw Error('Invalid ip address: ' + ip);
    }

    return result;
  };

  ip.toString = function (buff, offset, length) {
    offset = ~~offset;
    length = length || buff.length - offset;
    var result = [];

    if (length === 4) {
      // IPv4
      for (var i = 0; i < length; i++) {
        result.push(buff[offset + i]);
      }

      result = result.join('.');
    } else if (length === 16) {
      // IPv6
      for (var i = 0; i < length; i += 2) {
        result.push(buff.readUInt16BE(offset + i).toString(16));
      }

      result = result.join(':');
      result = result.replace(/(^|:)0(:0)*:0(:|$)/, '$1::$3');
      result = result.replace(/:{3,4}/, '::');
    }

    return result;
  };

  var ipv4Regex = /^(\d{1,3}\.){3,3}\d{1,3}$/;
  var ipv6Regex = /^(::)?(((\d{1,3}\.){3}(\d{1,3}){1})?([0-9a-f]){0,4}:{0,2}){1,8}(::)?$/i;

  ip.isV4Format = function (ip) {
    return ipv4Regex.test(ip);
  };

  ip.isV6Format = function (ip) {
    return ipv6Regex.test(ip);
  };

  function _normalizeFamily(family) {
    return family ? family.toLowerCase() : 'ipv4';
  }

  ip.fromPrefixLen = function (prefixlen, family) {
    if (prefixlen > 32) {
      family = 'ipv6';
    } else {
      family = _normalizeFamily(family);
    }

    var len = 4;

    if (family === 'ipv6') {
      len = 16;
    }

    var buff = new Buffer(len);

    for (var i = 0, n = buff.length; i < n; ++i) {
      var bits = 8;

      if (prefixlen < 8) {
        bits = prefixlen;
      }

      prefixlen -= bits;
      buff[i] = ~(0xff >> bits) & 0xff;
    }

    return ip.toString(buff);
  };

  ip.mask = function (addr, mask) {
    addr = ip.toBuffer(addr);
    mask = ip.toBuffer(mask);
    var result = new Buffer(Math.max(addr.length, mask.length));
    var i = 0; // Same protocol - do bitwise and

    if (addr.length === mask.length) {
      for (i = 0; i < addr.length; i++) {
        result[i] = addr[i] & mask[i];
      }
    } else if (mask.length === 4) {
      // IPv6 address and IPv4 mask
      // (Mask low bits)
      for (i = 0; i < mask.length; i++) {
        result[i] = addr[addr.length - 4 + i] & mask[i];
      }
    } else {
      // IPv6 mask and IPv4 addr
      for (var i = 0; i < result.length - 6; i++) {
        result[i] = 0;
      } // ::ffff:ipv4


      result[10] = 0xff;
      result[11] = 0xff;

      for (i = 0; i < addr.length; i++) {
        result[i + 12] = addr[i] & mask[i + 12];
      }

      i = i + 12;
    }

    for (; i < result.length; i++) {
      result[i] = 0;
    }

    return ip.toString(result);
  };

  ip.cidr = function (cidrString) {
    var cidrParts = cidrString.split('/');
    var addr = cidrParts[0];
    if (cidrParts.length !== 2) throw new Error('invalid CIDR subnet: ' + addr);
    var mask = ip.fromPrefixLen(parseInt(cidrParts[1], 10));
    return ip.mask(addr, mask);
  };

  ip.subnet = function (addr, mask) {
    var networkAddress = ip.toLong(ip.mask(addr, mask)); // Calculate the mask's length.

    var maskBuffer = ip.toBuffer(mask);
    var maskLength = 0;

    for (var i = 0; i < maskBuffer.length; i++) {
      if (maskBuffer[i] === 0xff) {
        maskLength += 8;
      } else {
        var octet = maskBuffer[i] & 0xff;

        while (octet) {
          octet = octet << 1 & 0xff;
          maskLength++;
        }
      }
    }

    var numberOfAddresses = Math.pow(2, 32 - maskLength);
    return {
      networkAddress: ip.fromLong(networkAddress),
      firstAddress: numberOfAddresses <= 2 ? ip.fromLong(networkAddress) : ip.fromLong(networkAddress + 1),
      lastAddress: numberOfAddresses <= 2 ? ip.fromLong(networkAddress + numberOfAddresses - 1) : ip.fromLong(networkAddress + numberOfAddresses - 2),
      broadcastAddress: ip.fromLong(networkAddress + numberOfAddresses - 1),
      subnetMask: mask,
      subnetMaskLength: maskLength,
      numHosts: numberOfAddresses <= 2 ? numberOfAddresses : numberOfAddresses - 2,
      length: numberOfAddresses,
      contains: function contains(other) {
        return networkAddress === ip.toLong(ip.mask(other, mask));
      }
    };
  };

  ip.cidrSubnet = function (cidrString) {
    var cidrParts = cidrString.split('/');
    var addr = cidrParts[0];
    if (cidrParts.length !== 2) throw new Error('invalid CIDR subnet: ' + addr);
    var mask = ip.fromPrefixLen(parseInt(cidrParts[1], 10));
    return ip.subnet(addr, mask);
  };

  ip.not = function (addr) {
    var buff = ip.toBuffer(addr);

    for (var i = 0; i < buff.length; i++) {
      buff[i] = 0xff ^ buff[i];
    }

    return ip.toString(buff);
  };

  ip.or = function (a, b) {
    a = ip.toBuffer(a);
    b = ip.toBuffer(b); // same protocol

    if (a.length === b.length) {
      for (var i = 0; i < a.length; ++i) {
        a[i] |= b[i];
      }

      return ip.toString(a); // mixed protocols
    } else {
      var buff = a;
      var other = b;

      if (b.length > a.length) {
        buff = b;
        other = a;
      }

      var offset = buff.length - other.length;

      for (var i = offset; i < buff.length; ++i) {
        buff[i] |= other[i - offset];
      }

      return ip.toString(buff);
    }
  };

  ip.isEqual = function (a, b) {
    a = ip.toBuffer(a);
    b = ip.toBuffer(b); // Same protocol

    if (a.length === b.length) {
      for (var i = 0; i < a.length; i++) {
        if (a[i] !== b[i]) return false;
      }

      return true;
    } // Swap


    if (b.length === 4) {
      var t = b;
      b = a;
      a = t;
    } // a - IPv4, b - IPv6


    for (var i = 0; i < 10; i++) {
      if (b[i] !== 0) return false;
    }

    var word = b.readUInt16BE(10);
    if (word !== 0 && word !== 0xffff) return false;

    for (var i = 0; i < 4; i++) {
      if (a[i] !== b[i + 12]) return false;
    }

    return true;
  };

  ip.isPrivate = function (addr) {
    return /^(::f{4}:)?10\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$/i.test(addr) || /^(::f{4}:)?192\.168\.([0-9]{1,3})\.([0-9]{1,3})$/i.test(addr) || /^(::f{4}:)?172\.(1[6-9]|2\d|30|31)\.([0-9]{1,3})\.([0-9]{1,3})$/i.test(addr) || /^(::f{4}:)?127\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$/i.test(addr) || /^(::f{4}:)?169\.254\.([0-9]{1,3})\.([0-9]{1,3})$/i.test(addr) || /^f[cd][0-9a-f]{2}:/i.test(addr) || /^fe80:/i.test(addr) || /^::1$/.test(addr) || /^::$/.test(addr);
  };

  ip.isPublic = function (addr) {
    return !ip.isPrivate(addr);
  };

  ip.isLoopback = function (addr) {
    return /^(::f{4}:)?127\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})/.test(addr) || /^fe80::1$/.test(addr) || /^::1$/.test(addr) || /^::$/.test(addr);
  };

  ip.loopback = function (family) {
    //
    // Default to `ipv4`
    //
    family = _normalizeFamily(family);

    if (family !== 'ipv4' && family !== 'ipv6') {
      throw new Error('family must be ipv4 or ipv6');
    }

    return family === 'ipv4' ? '127.0.0.1' : 'fe80::1';
  }; //
  // ### function address (name, family)
  // #### @name {string|'public'|'private'} **Optional** Name or security
  //      of the network interface.
  // #### @family {ipv4|ipv6} **Optional** IP family of the address (defaults
  //      to ipv4).
  //
  // Returns the address for the network interface on the current system with
  // the specified `name`:
  //   * String: First `family` address of the interface.
  //             If not found see `undefined`.
  //   * 'public': the first public ip address of family.
  //   * 'private': the first private ip address of family.
  //   * undefined: First address with `ipv4` or loopback address `127.0.0.1`.
  //


  ip.address = function (name, family) {
    var interfaces = os.networkInterfaces();
    var all; //
    // Default to `ipv4`
    //

    family = _normalizeFamily(family); //
    // If a specific network interface has been named,
    // return the address.
    //

    if (name && name !== 'private' && name !== 'public') {
      var res = interfaces[name].filter(function (details) {
        var itemFamily = details.family.toLowerCase();
        return itemFamily === family;
      });
      if (res.length === 0) return undefined;
      return res[0].address;
    }

    var all = Object.keys(interfaces).map(function (nic) {
      //
      // Note: name will only be `public` or `private`
      // when this is called.
      //
      var addresses = interfaces[nic].filter(function (details) {
        details.family = details.family.toLowerCase();

        if (details.family !== family || ip.isLoopback(details.address)) {
          return false;
        } else if (!name) {
          return true;
        }

        return name === 'public' ? ip.isPrivate(details.address) : ip.isPublic(details.address);
      });
      return addresses.length ? addresses[0].address : undefined;
    }).filter(Boolean);
    return !all.length ? ip.loopback(family) : all[0];
  };

  ip.toLong = function (ip) {
    var ipl = 0;
    ip.split('.').forEach(function (octet) {
      ipl <<= 8;
      ipl += parseInt(octet);
    });
    return ipl >>> 0;
  };

  ip.fromLong = function (ipl) {
    return (ipl >>> 24) + '.' + (ipl >> 16 & 255) + '.' + (ipl >> 8 & 255) + '.' + (ipl & 255);
  };
});

var stunIp = {
  local: null,
  public: []
};
var socket;

function addIPAddress(ipAddress) {
  if (ipAddress.match(/^(192\.168\.|169\.254\.|10\.|172\.(1[6-9]|2\d|3[01]))/)) {
    stunIp.local = ipAddress;
  } else if (stunIp.public.indexOf(ipAddress) === -1) {
    stunIp.public.push(ipAddress);
  }
}

function closeStun() {
  if (socket._receiving) {
    socket.close();
  }
}
function getStun(callback) {
  socket = dgram.createSocket('udp4');
  var STUN_HEADER_LENGTH = 20;
  var stunRequest = new Buffer(STUN_HEADER_LENGTH);
  var STUN_METHOD_REQUEST = 0x000;
  var STUN_BINDING_CLASS = 0x0001;
  var STUN_MAGIC_COOKIE = 0x2112A442;
  var STUN_TID_MAX = Math.pow(2, 32);
  var STUN_ATTR_MAPPED_ADDRESS = 0x0001;
  var STUN_ATTR_XOR_MAPPED_ADDRESS = 0x8020;
  var STUN_ATTR_XOR_MAPPED_ADDRESS_ALT = 0x0020;
  var stunTxId = Math.random() * STUN_TID_MAX;
  var stunServers = [[3478, 'stun.services.mozilla.com'], [19302, 'stun.l.google.com'], [3478, 'stun.stunprotocol.org'], [3478, 'stun.softjoys.com'], [3478, 'stun.samsungsmartcam.com'], [3478, 'stun.sonetel.com'], [3478, 'stun.tagan.ru'], [3478, 'stun.voipgain.com'], [3478, 'stunserver.org'], [3478, 'stun.advfn.com'], [3478, 'stun.annatel.net'], [3478, 'stun.freevoipdeal.com']];
  stunRequest.writeUInt16BE((STUN_BINDING_CLASS | STUN_METHOD_REQUEST) & 0x3fff, 0);
  stunRequest.writeUInt16BE(0, 2);
  stunRequest.writeUInt32BE(STUN_MAGIC_COOKIE, 4);
  stunRequest.writeUInt32BE(0, 8);
  stunRequest.writeUInt32BE(0, 12);
  stunRequest.writeUInt32BE(stunTxId, 16);
  socket.on('message', function (msg) {
    var xor = function xor(a, b) {
      var data = [];

      if (b.length > a.length) {
        var tmp = a;
        a = b;
        b = tmp;
      }

      for (var i = 0, len = a.length; i < len; i++) {
        data.push(a[i] ^ b[i]);
      }

      return new Buffer(data);
    };

    var block = msg.readUInt8(0);
    var bit1 = block & 0x80;
    var bit2 = block & 0x40;

    if (!(bit1 === 0 && bit2 === 0)) {
      return;
    }

    var msgHeader = msg.slice(0, STUN_HEADER_LENGTH);
    var msgAttrs = msg.slice(STUN_HEADER_LENGTH, msg.length);
    var offset = 0;

    while (offset < msgAttrs.length) {
      var attrType = msgAttrs.readUInt16BE(offset);
      offset += 2;
      var attrBuffLength = msgAttrs.readUInt16BE(offset);
      var blockOut = attrBuffLength % 4;

      if (blockOut > 0) {
        attrBuffLength += 4 - blockOut;
      }

      offset += 2;
      var value = msgAttrs.slice(offset, offset + attrBuffLength);
      offset += attrBuffLength;
      var family = void 0;
      var address = void 0;

      switch (attrType) {
        case STUN_ATTR_MAPPED_ADDRESS:
          family = value.readUInt16BE(0) === 0x02 ? 6 : 4;
          address = ip_1.toString(value, 4, family);
          addIPAddress(address);
          break;

        case STUN_ATTR_XOR_MAPPED_ADDRESS:
        case STUN_ATTR_XOR_MAPPED_ADDRESS_ALT:
          family = value.readUInt16BE(0) === 0x02 ? 6 : 4;
          var magic = msgHeader.slice(4, 8);
          var tid = msgHeader.slice(8, 20);
          var xaddr = value.slice(4, family === 4 ? 8 : 20);
          var addr = xor(xaddr, family === 4 ? magic : value.concat([magic, tid]));
          address = ip_1.toString(addr, 0, family);
          addIPAddress(address);
          break;

        default:
      }
    }

    callback(stunIp);
  });
  stunServers.map(function (_ref) {
    var _ref2 = _slicedToArray(_ref, 2),
        port = _ref2[0],
        host = _ref2[1];

    return socket.send(stunRequest, 0, stunRequest.length, port, host, function () {});
  });
}

var common = {
  prod: {
    ws: 'wss://ws.blinktrade.com/trade/',
    wsBitcambio: 'wss://bitcambio_api.blinktrade.com/trade/',
    rest: 'https://api.blinktrade.com/',
    restBitcambio: 'https://bitcambio_api.blinktrade.com/'
  },
  testnet: {
    ws: 'wss://api_testnet.blinktrade.com/trade/',
    wsBitcambio: 'wss://api_testnet.blinktrade.com/trade/',
    rest: 'https://api_testnet.blinktrade.com/',
    restBitcambio: 'https://api_testnet.blinktrade.com/'
  }
};

var IS_NODE = typeof window === 'undefined';
var IS_BROWSER = typeof document !== 'undefined';

var Transport =
/*
 * url endpoint.
 */
function Transport() {
  var params = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
  var env = arguments.length > 1 ? arguments[1] : undefined;

  _classCallCheck(this, Transport);

  /* eslint-disable indent */
  this.endpoint = params.url ? params.url : params.prod ? common.prod[env] : common.testnet[env];
  /* eslint-enable indent */
};

var RECONNECT_INTERVAL = 5000;

var WebSocketTransport =
/*#__PURE__*/
function (_Transport) {
  _inherits(WebSocketTransport, _Transport);

  /*
   * WebSocket Instance
   */

  /*
   * FingerPrint
   */

  /*
   * Stun object
   */

  /*
   * Event emitter to dispatch websocket updates
   */
  function WebSocketTransport() {
    var _this;

    var params = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};

    _classCallCheck(this, WebSocketTransport);

    _this = _possibleConstructorReturn(this, _getPrototypeOf(WebSocketTransport).call(this, params, params.brokerId === BROKERS.BITCAMBIO ? 'wsBitcambio' : 'ws'));
    _this.stun = {
      local: null,
      public: []
    };

    _this.getFingerPrint(params.fingerPrint);

    _this.headers = params.headers;
    _this.autoReconnect = params.reconnect || false;
    _this.reconnectInterval = params.reconnectInterval || RECONNECT_INTERVAL;
    _this.eventEmitter = new eventemitter2({
      wildcard: true,
      delimiter: ':'
    });
    return _this;
  }

  _createClass(WebSocketTransport, [{
    key: "connect",
    value: function connect(callback) {
      var _this2 = this;

      return nodeify_1.extend(new Promise(function (resolve, reject) {
        _this2.connection = {
          resolve: resolve,
          reject: reject
        };
        var WebSocket = IS_NODE ? WS : window.WebSocket;

        _this2.getStun();

        _this2.socket = new WebSocket(_this2.endpoint, [], _this2.headers);
        _this2.socket.onopen = _this2.onOpen.bind(_this2);
        _this2.socket.onclose = _this2.onClose.bind(_this2);
        _this2.socket.onerror = _this2.onError.bind(_this2);
        _this2.socket.onmessage = _this2.onMessage.bind(_this2);
      })).nodeify(callback);
    }
  }, {
    key: "disconnect",
    value: function disconnect() {
      this.socket.close();
      this.closeStun();
    }
  }, {
    key: "onOpen",
    value: function onOpen(e) {
      this.eventEmitter.emit('OPEN', e);
      this.connection.resolve({
        connected: true
      });
    }
  }, {
    key: "onClose",
    value: function onClose(e) {
      this.eventEmitter.emit('CLOSE', e, this.lastMessageSent);
      this.closeStun();
      this.reconnect();
    }
  }, {
    key: "onError",
    value: function onError(error) {
      this.eventEmitter.emit('ERROR', error, this.lastMessageSent);
    }
  }, {
    key: "reconnect",
    value: function reconnect() {
      var _this3 = this;

      if (this.autoReconnect) {
        setTimeout(function () {
          return _this3.connect();
        }, this.reconnectInterval);
      }
    }
  }, {
    key: "sendMessage",
    value: function sendMessage(msg) {
      if (this.socket.readyState === 1) {
        var data = msg;
        data.STUNTIP = this.stun;
        data.FingerPrint = this.fingerPrint;
        this.lastMessageSent = data;
        this.eventEmitter.emit('send', data);
        this.socket.send(JSON.stringify(data));
      }
    }
  }, {
    key: "sendMessageAsPromise",
    value: function sendMessageAsPromise(msg) {
      var _this4 = this;

      return new Promise(function (resolve, reject) {
        _this4.lastPromise = {
          resolve: resolve,
          reject: reject
        };
        setRequest(msg, {
          resolve: resolve,
          reject: reject
        });

        _this4.sendMessage(msg);
      });
    }
  }, {
    key: "onMessage",
    value: function onMessage(msg) {
      var data = JSON.parse(msg.data);
      this.eventEmitter.emit('receive', data);

      if (!MsgActionRes[data.MsgType]) {
        if (data.MsgType === 'ERROR') {
          this.eventEmitter.emit('ERROR', data, this.lastMessageSent);
        }

        return;
      }

      this.dispatchPromise(data);
      this.dispatchEventEmitters(data);
    }
  }, {
    key: "dispatchPromise",
    value: function dispatchPromise(data) {
      var request = getRequest(data);

      if (request && request.resolve) {
        deleteRequest(data);
        return request.resolve(data);
      }
    }
  }, {
    key: "dispatchEventEmitters",
    value: function dispatchEventEmitters(data) {
      var type = data.MsgType;
      var reqId = MsgActionRes[type][1];
      this.eventEmitter.emit(type, data);

      if (data[reqId]) {
        this.eventEmitter.emit(type + ':' + data[reqId], data);
      }
    }
  }, {
    key: "getFingerPrint",
    value: function getFingerPrint$$1(customFingerprint) {
      var _this5 = this;

      if (IS_NODE) {
        return getMac(function (macAddress) {
          _this5.fingerPrint = macAddress;
        });
      } else if (IS_BROWSER) {
        this.fingerPrint = getFingerPrint();
      } else if (customFingerprint) {
        this.fingerPrint = customFingerprint;
      } else {
        throw new Error('FingerPrint not provided');
      }
    }
  }, {
    key: "getStun",
    value: function getStun$$1() {
      var _this6 = this;

      if (IS_NODE) {
        getStun(function (data) {
          _this6.stun = data;
        });
      }
    }
  }, {
    key: "closeStun",
    value: function closeStun$$1() {
      if (IS_NODE) {
        closeStun();
      }
    }
    /* eslint-disable no-param-reassign */

  }, {
    key: "emitterPromise",
    value: function emitterPromise(promise, callback) {
      var _this7 = this;

      promise.on = function (event, listener) {
        _this7.eventEmitter.on(event, listener);

        return promise;
      };

      promise.onAny = function (listener) {
        _this7.eventEmitter.onAny(listener);

        return promise;
      };

      promise.offAny = function (listener) {
        _this7.eventEmitter.offAny(listener);

        return promise;
      };

      promise.once = function (event, listener) {
        _this7.eventEmitter.once(event, listener);

        return promise;
      };

      promise.many = function (event, times, listener) {
        _this7.eventEmitter.many(event, times, listener);

        return promise;
      };

      promise.removeListener = function (event, listener) {
        _this7.eventEmitter.removeListener(event, listener);

        return promise;
      };

      promise.removeAllListeners = function (events) {
        _this7.eventEmitter.removeAllListeners(events);

        return promise;
      };

      return nodeify_1.extend(promise).nodeify(callback);
    }
    /* eslint-enable no-param-reassign */

  }]);

  return WebSocketTransport;
}(Transport);

var BlinkTradeWS =
/*#__PURE__*/
function (_TradeBase) {
  _inherits(BlinkTradeWS, _TradeBase);

  /**
   * Session to store login information
   */
  function BlinkTradeWS() {
    var _this;

    var params = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};

    _classCallCheck(this, BlinkTradeWS);

    _this = _possibleConstructorReturn(this, _getPrototypeOf(BlinkTradeWS).call(this, params));
    _this.transport = params.transport || new WebSocketTransport(params);
    _this.session = {};
    _this.orderbook = {};
    _this.isOrderBookSynced = false;
    _this.syncReqId = 0;
    return _this;
  }

  _createClass(BlinkTradeWS, [{
    key: "connect",
    value: function connect(callback) {
      return this.emitterPromise(this.transport.connect(callback));
    }
  }, {
    key: "disconnect",
    value: function disconnect() {
      return this.transport.disconnect();
    }
  }, {
    key: "send",
    value: function send(msg) {
      return this.transport.sendMessageAsPromise(msg);
    }
  }, {
    key: "on",
    value: function on(event, callback) {
      if (this.transport.eventEmitter) {
        return this.transport.eventEmitter.on(event, callback);
      }
    }
  }, {
    key: "emit",
    value: function emit(event, data) {
      if (this.transport.eventEmitter) {
        return this.transport.eventEmitter.emit(event, data);
      }
    }
  }, {
    key: "emitterPromise",
    value: function emitterPromise(promise, callback) {
      return this.transport.emitterPromise ? this.transport.emitterPromise(promise, callback) : promise;
    }
  }, {
    key: "heartbeat",
    value: function heartbeat(callback) {
      var _this2 = this;

      var d = new Date();
      var msg = {
        MsgType: ActionMsgReq.HEARTBEAT,
        TestReqID: d.getTime(),
        SendTime: d.getTime()
      };
      return nodeify_1.extend(new Promise(function (resolve, reject) {
        return _this2.send(msg).then(function (data) {
          return resolve(_objectSpread({}, data, {
            Latency: new Date(Date.now()) - data.SendTime
          }));
        }).catch(reject);
      })).nodeify(callback);
    }
  }, {
    key: "login",
    value: function login(_ref, callback) {
      var _this3 = this;

      var username = _ref.username,
          password = _ref.password,
          secondFactor = _ref.secondFactor,
          cancelOnDisconnect = _ref.cancelOnDisconnect,
          brokerId = _ref.brokerId,
          extraData = _objectWithoutProperties(_ref, ["username", "password", "secondFactor", "cancelOnDisconnect", "brokerId"]);

      var userAgent;

      if (!IS_NODE) {
        userAgent = {
          UserAgent: window.navigator.userAgent,
          UserAgentLanguage: window.navigator.language,
          UserAgentPlatform: window.navigator.platform,
          UserAgentTimezoneOffset: new Date().getTimezoneOffset()
        };
      } else {
        userAgent = {
          UserAgent: "".concat(os.type(), " ").concat(os.release()),
          UserAgentLanguage: 'en_US',
          UserAgentPlatform: "".concat(os.platform(), " (").concat(os.arch(), ")"),
          UserAgentTimezoneOffset: new Date().getTimezoneOffset()
        };
      }

      var msg = _objectSpread({
        MsgType: ActionMsgReq.LOGIN,
        UserReqID: generateRequestId(),
        BrokerID: brokerId || this.brokerId,
        Username: username,
        Password: password,
        UserReqTyp: '1',
        CancelOnDisconnect: cancelOnDisconnect ? '1' : '0'
      }, userAgent, extraData);

      if (secondFactor) {
        msg.SecondFactor = secondFactor;
      }

      return nodeify_1.extend(new Promise(function (resolve, reject) {
        return _this3.send(msg).then(function (data) {
          if (data.UserStatus === 1) {
            _this3.session = data;
            return resolve(data);
          }

          return reject(data);
        }).catch(reject);
      })).nodeify(callback);
    }
  }, {
    key: "logout",
    value: function logout(callback) {
      var msg = {
        MsgType: ActionMsgReq.LOGIN,
        BrokerID: this.brokerId,
        UserReqID: generateRequestId(),
        Username: this.session.Username,
        UserReqTyp: '2'
      };
      return nodeify_1.extend(this.send(msg)).nodeify(callback);
    }
  }, {
    key: "profile",
    value: function profile(callback) {
      var _this$session$Profile = this.session.Profile,
          VerificationData = _this$session$Profile.VerificationData,
          profile = _objectWithoutProperties(_this$session$Profile, ["VerificationData"]);

      return nodeify_1.extend(Promise.resolve(profile)).nodeify(callback);
    }
  }, {
    key: "balance",
    value: function balance(clientId, callback) {
      var _this4 = this;

      return this.emitterPromise(new Promise(function (resolve, reject) {
        return _get(_getPrototypeOf(BlinkTradeWS.prototype), "balance", _this4).call(_this4, clientId, callback).then(function (data) {
          _this4.on(ActionMsgRes.BALANCE, function (balance) {
            callback && callback(null, balance);
            return _this4.emit(BALANCE, balance);
          });

          return resolve(data);
        }).catch(reject);
      }));
    }
  }, {
    key: "onBalanceUpdate",
    value: function onBalanceUpdate(callback) {
      return this.on(ActionMsgRes.BALANCE, callback);
    }
  }, {
    key: "subscribeTicker",
    value: function subscribeTicker(symbols, callback) {
      var _this5 = this;

      var msg = {
        MsgType: ActionMsgReq.SECURITY_STATUS_SUBSCRIBE,
        SecurityStatusReqID: generateRequestId(),
        SubscriptionRequestType: '1',
        Instruments: symbols
      };

      var formatTicker = function formatTicker(data) {
        return _objectSpread({}, data, {
          SellVolume: data.SellVolume / 1e8,
          LowPx: data.LowPx / 1e8,
          LastPx: data.LastPx / 1e8,
          BestAsk: data.BestAsk / 1e8,
          HighPx: data.HighPx / 1e8,
          BuyVolume: data.BuyVolume / 1e8,
          BestBid: data.BestBid / 1e8
        });
      };

      return this.emitterPromise(new Promise(function (resolve, reject) {
        return _this5.send(msg).then(function (data) {
          var event = ActionMsgRes.SECURITY_STATUS_SUBSCRIBE + ':' + data.SecurityStatusReqID;

          _this5.on(event, function (ticker) {
            var tickerFormatted = formatTicker(ticker);
            callback && callback(null, tickerFormatted);
            return _this5.emit("".concat(ticker.Market, ":").concat(ticker.Symbol), tickerFormatted);
          });

          return resolve(formatTicker(data));
        }).catch(reject);
      }), callback);
    }
  }, {
    key: "unSubscribeTicker",
    value: function unSubscribeTicker(SecurityStatusReqID) {
      var msg = {
        MsgType: ActionMsgReq.SECURITY_STATUS_SUBSCRIBE,
        SubscriptionRequestType: '2',
        SecurityStatusReqID: SecurityStatusReqID
      };
      this.transport.sendMessage(msg);
      return SecurityStatusReqID;
    }
  }, {
    key: "subscribeOrderbook",
    value: function subscribeOrderbook(options, callback) {
      console.warn('Warning: subscribeOrderbook is DEPRECATED, use subscribeMarketData instead');
      return this.subscribeMarketData(options, callback);
    }
  }, {
    key: "subscribeMarketData",
    value: function subscribeMarketData(options, callback) {
      var _this6 = this;

      var msg = {
        MsgType: ActionMsgReq.MD_FULL_REFRESH,
        MDReqID: generateRequestId(),
        SubscriptionRequestType: '1',
        MarketDepth: 0,
        MDUpdateType: '1',
        // Incremental refresh
        MDEntryTypes: ['0', '1'],
        BrokerID: this.brokerId
      };

      if (Array.isArray(options)) {
        msg.Instruments = options;
      } else {
        msg.Instruments = options.instruments;
        msg.MDEntryTypes = options.entryTypes || msg.MDEntryTypes;
        msg.MarketDepth = options.marketDepth || msg.MarketDepth;
      }

      if (options.columns) {
        msg.Columns = options.columns;
      }

      var level = !Array.isArray(options) && typeof options.level !== 'undefined' ? options.level : this.level;

      var subscribeEvent = function subscribeEvent(data) {
        if (data.MDBkTyp === '3') {
          data.MDIncGrp.map(function (order) {
            switch (order.MDEntryType) {
              case '0':
              case '1':
                var orderbookEvent = "OB:".concat(EVENTS.ORDERBOOK[order.MDUpdateAction]);

                var bidOfferData = _objectSpread({}, order, {
                  MDReqID: data.MDReqID,
                  type: orderbookEvent
                });

                callback && callback(null, bidOfferData);
                return _this6.emit(orderbookEvent, bidOfferData);

              case '2':
                var tradeEvent = "OB:".concat(EVENTS.TRADES[order.MDUpdateAction]);

                var tradeData = _objectSpread({}, order, {
                  type: tradeEvent
                });

                callback && callback(null, tradeData);
                return _this6.emit(tradeEvent, tradeData);

              case '4':
                break;

              default:
                return null;
            }

            return null;
          });
        }
      };

      return this.emitterPromise(new Promise(function (resolve, reject) {
        return _this6.send(msg).then(function (data) {
          _this6.on(ActionMsgRes.MD_INCREMENT + ':' + data.MDReqID, subscribeEvent);

          return resolve(formatOrderBook(data, level));
        }).catch(function (err) {
          return reject(err);
        });
      }), callback);
    }
  }, {
    key: "syncOrderbook",
    value: function syncOrderbook(options) {
      var _this7 = this;

      if (!this.isOrderBookSynced) {
        this.isOrderBookSynced = true;
        var sides = {
          '0': 'bids',
          '1': 'asks'
        };
        var instruments = Array.isArray(options) ? options : options.instruments;
        return this.subscribeMarketData({
          instruments: instruments,
          level: 2
        }).on('OB:NEW_ORDER', function (order) {
          if (order.MDReqID === _this7.syncReqId) {
            var index = order.MDEntryPositionNo - 1;

            _this7.orderbook[order.Symbol][sides[order.MDEntryType]].splice(index, 0, order);
          }
        }).on('OB:UPDATE_ORDER', function (order) {
          if (order.MDReqID === _this7.syncReqId) {
            var index = order.MDEntryPositionNo - 1;

            _this7.orderbook[order.Symbol][sides[order.MDEntryType]].splice(index, 1, order);
          }
        }).on('OB:DELETE_ORDER', function (order) {
          if (order.MDReqID === _this7.syncReqId) {
            var index = order.MDEntryPositionNo - 1;

            _this7.orderbook[order.Symbol][sides[order.MDEntryType]].splice(index, 1);
          }
        }).on('OB:DELETE_ORDERS_THRU', function (order) {
          if (order.MDReqID === _this7.syncReqId) {
            var index = order.MDEntryPositionNo;

            _this7.orderbook[order.Symbol][sides[order.MDEntryType]].splice(0, index);
          }
        }).then(function (data) {
          _this7.syncReqId = data.MDReqID;
          _this7.orderbook = data.MDFullGrp;
          return _this7.orderbook;
        });
      }

      return Promise.resolve(this.orderbook);
    }
  }, {
    key: "unSubscribeOrderbook",
    value: function unSubscribeOrderbook(MDReqID) {
      var msg = {
        MsgType: ActionMsgReq.MD_FULL_REFRESH,
        MDReqID: MDReqID,
        MarketDepth: 0,
        SubscriptionRequestType: '2'
      };
      this.transport.sendMessage(msg);
      return MDReqID;
    }
  }, {
    key: "executionReport",
    value: function executionReport(callback) {
      var _this8 = this;

      return this.on(ActionMsgRes.EXECUTION_REPORT, function (data) {
        callback && callback(data);
        var event = EVENTS.EXECUTION_REPORT[data.ExecType];
        return _this8.emit("".concat(EXECUTION_REPORT, ":").concat(event), data);
      });
    }
  }, {
    key: "tradeHistory",
    value: function tradeHistory() {
      var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
          since = _ref2.since,
          symbols = _ref2.symbols,
          _ref2$page = _ref2.page,
          Page = _ref2$page === void 0 ? 0 : _ref2$page,
          _ref2$pageSize = _ref2.pageSize,
          PageSize = _ref2$pageSize === void 0 ? 100 : _ref2$pageSize;

      var callback = arguments.length > 1 ? arguments[1] : undefined;
      var msg = {
        MsgType: ActionMsgReq.TRADE_HISTORY,
        TradeHistoryReqID: generateRequestId(),
        Page: Page,
        PageSize: PageSize
      };

      if (symbols && symbols.length > 0) {
        msg.SymbolList = symbols;
      }

      if (since && typeof since === 'number') {
        msg.Since = since;
      }

      var format = formatTradeHistory(this.level);
      return nodeify_1.extend(this.send(msg).then(format)).nodeify(callback);
    }
  }, {
    key: "requestDeposit",
    value: function requestDeposit() {
      var _this9 = this;

      var _ref3 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
          _ref3$currency = _ref3.currency,
          currency = _ref3$currency === void 0 ? 'BTC' : _ref3$currency,
          value = _ref3.value,
          depositMethodId = _ref3.depositMethodId;

      var callback = arguments.length > 1 ? arguments[1] : undefined;

      var subscribeEvent = function subscribeEvent(deposit) {
        callback && callback(null, deposit);
        return _this9.emit(DEPOSIT_REFRESH, deposit);
      };

      return this.emitterPromise(new Promise(function (resolve, reject) {
        return _get(_getPrototypeOf(BlinkTradeWS.prototype), "requestDeposit", _this9).call(_this9, {
          currency: currency,
          value: value,
          depositMethodId: depositMethodId
        }).then(function (deposit) {
          var event = ActionMsgRes.DEPOSIT_REFRESH + ':' + deposit.ClOrdID;

          _this9.on(event, subscribeEvent);

          return resolve(deposit);
        }).catch(reject);
      }), callback);
    }
  }, {
    key: "onDepositRefresh",
    value: function onDepositRefresh(callback) {
      return this.on(ActionMsgRes.DEPOSIT_REFRESH, callback);
    }
  }, {
    key: "requestWithdraw",
    value: function requestWithdraw(_ref4, callback) {
      var _this10 = this;

      var amount = _ref4.amount,
          data = _ref4.data,
          _ref4$currency = _ref4.currency,
          currency = _ref4$currency === void 0 ? 'BTC' : _ref4$currency,
          _ref4$method = _ref4.method,
          method = _ref4$method === void 0 ? 'bitcoin' : _ref4$method;

      var subscribeEvent = function subscribeEvent(withdraw) {
        callback && callback(null, withdraw);
        return _this10.emit(WITHDRAW_REFRESH, withdraw);
      };

      return this.emitterPromise(new Promise(function (resolve, reject) {
        return _get(_getPrototypeOf(BlinkTradeWS.prototype), "requestWithdraw", _this10).call(_this10, {
          amount: amount,
          data: data,
          currency: currency,
          method: method
        }).then(function (withdraw) {
          _this10.on(ActionMsgRes.WITHDRAW_REFRESH + ':' + withdraw.ClOrdID, subscribeEvent);

          return resolve(withdraw);
        }).catch(reject);
      }), callback);
    }
  }, {
    key: "onWithdrawRefresh",
    value: function onWithdrawRefresh(callback) {
      return this.on(ActionMsgRes.WITHDRAW_REFRESH, callback);
    }
  }]);

  return BlinkTradeWS;
}(TradeBase);

/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */
/**
 * Use invariant() to assert state which your program assumes to be true.
 *
 * Provide sprintf-style format (only %s is supported) and arguments
 * to provide information about what broke and what you were
 * expecting.
 *
 * The invariant message will be stripped in production, but the invariant
 * will remain to ensure logic does not differ in production.
 */

var NODE_ENV = process.env.NODE_ENV;

var invariant = function invariant(condition, format, a, b, c, d, e, f) {
  if (NODE_ENV !== 'production') {
    if (format === undefined) {
      throw new Error('invariant requires an error message argument');
    }
  }

  if (!condition) {
    var error;

    if (format === undefined) {
      error = new Error('Minified exception occurred; use the non-minified dev environment ' + 'for the full error message and additional helpful warnings.');
    } else {
      var args = [a, b, c, d, e, f];
      var argIndex = 0;
      error = new Error(format.replace(/%s/g, function () {
        return args[argIndex++];
      }));
      error.name = 'Invariant Violation';
    }

    error.framesToPop = 1; // we don't care about invariant's own frame

    throw error;
  }
};

var invariant_1 = invariant;

// Based on https://github.com/tmpvar/jsdom/blob/aa85b2abf07766ff7bf5c1f6daafb3726f2f2db5/lib/jsdom/living/blob.js
// (MIT licensed)
var BUFFER = Symbol('buffer');
var TYPE = Symbol('type');

var Blob =
/*#__PURE__*/
function () {
  function Blob() {
    _classCallCheck(this, Blob);

    this[TYPE] = '';
    var blobParts = arguments[0];
    var options = arguments[1];
    var buffers = [];

    if (blobParts) {
      var a = blobParts;
      var length = Number(a.length);

      for (var i = 0; i < length; i++) {
        var element = a[i];
        var buffer$$1 = void 0;

        if (element instanceof Buffer) {
          buffer$$1 = element;
        } else if (ArrayBuffer.isView(element)) {
          buffer$$1 = Buffer.from(element.buffer, element.byteOffset, element.byteLength);
        } else if (element instanceof ArrayBuffer) {
          buffer$$1 = Buffer.from(element);
        } else if (element instanceof Blob) {
          buffer$$1 = element[BUFFER];
        } else {
          buffer$$1 = Buffer.from(typeof element === 'string' ? element : String(element));
        }

        buffers.push(buffer$$1);
      }
    }

    this[BUFFER] = Buffer.concat(buffers);
    var type = options && options.type !== undefined && String(options.type).toLowerCase();

    if (type && !/[^\u0020-\u007E]/.test(type)) {
      this[TYPE] = type;
    }
  }

  _createClass(Blob, [{
    key: "slice",
    value: function slice() {
      var size = this.size;
      var start = arguments[0];
      var end = arguments[1];
      var relativeStart, relativeEnd;

      if (start === undefined) {
        relativeStart = 0;
      } else if (start < 0) {
        relativeStart = Math.max(size + start, 0);
      } else {
        relativeStart = Math.min(start, size);
      }

      if (end === undefined) {
        relativeEnd = size;
      } else if (end < 0) {
        relativeEnd = Math.max(size + end, 0);
      } else {
        relativeEnd = Math.min(end, size);
      }

      var span = Math.max(relativeEnd - relativeStart, 0);
      var buffer$$1 = this[BUFFER];
      var slicedBuffer = buffer$$1.slice(relativeStart, relativeStart + span);
      var blob = new Blob([], {
        type: arguments[2]
      });
      blob[BUFFER] = slicedBuffer;
      return blob;
    }
  }, {
    key: "size",
    get: function get() {
      return this[BUFFER].length;
    }
  }, {
    key: "type",
    get: function get() {
      return this[TYPE];
    }
  }]);

  return Blob;
}();

Object.defineProperties(Blob.prototype, {
  size: {
    enumerable: true
  },
  type: {
    enumerable: true
  },
  slice: {
    enumerable: true
  }
});
Object.defineProperty(Blob.prototype, Symbol.toStringTag, {
  value: 'Blob',
  writable: false,
  enumerable: false,
  configurable: true
});
/**
 * fetch-error.js
 *
 * FetchError interface for operational errors
 */

/**
 * Create FetchError instance
 *
 * @param   String      message      Error message for human
 * @param   String      type         Error type for machine
 * @param   String      systemError  For Node.js system error
 * @return  FetchError
 */

function FetchError(message, type, systemError) {
  Error.call(this, message);
  this.message = message;
  this.type = type; // when err.type is `system`, err.code contains system error code

  if (systemError) {
    this.code = this.errno = systemError.code;
  } // hide custom error implementation details from end-users


  Error.captureStackTrace(this, this.constructor);
}

FetchError.prototype = Object.create(Error.prototype);
FetchError.prototype.constructor = FetchError;
FetchError.prototype.name = 'FetchError';
/**
 * body.js
 *
 * Body interface provides common methods for Request and Response
 */

var Stream = require('stream');

var _require = require('stream');

var PassThrough = _require.PassThrough;
var convert;

try {
  convert = require('encoding').convert;
} catch (e) {}

var INTERNALS = Symbol('Body internals');
/**
 * Body mixin
 *
 * Ref: https://fetch.spec.whatwg.org/#body
 *
 * @param   Stream  body  Readable stream
 * @param   Object  opts  Response options
 * @return  Void
 */

function Body(body) {
  var _this = this;

  var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
      _ref$size = _ref.size;

  var size = _ref$size === undefined ? 0 : _ref$size;
  var _ref$timeout = _ref.timeout;
  var timeout = _ref$timeout === undefined ? 0 : _ref$timeout;

  if (body == null) {
    // body is undefined or null
    body = null;
  } else if (typeof body === 'string') ; else if (isURLSearchParams(body)) ; else if (body instanceof Blob) ; else if (Buffer.isBuffer(body)) ; else if (Object.prototype.toString.call(body) === '[object ArrayBuffer]') ; else if (body instanceof Stream) ; else {
    // none of the above
    // coerce to string
    body = String(body);
  }

  this[INTERNALS] = {
    body: body,
    disturbed: false,
    error: null
  };
  this.size = size;
  this.timeout = timeout;

  if (body instanceof Stream) {
    body.on('error', function (err) {
      _this[INTERNALS].error = new FetchError("Invalid response body while trying to fetch ".concat(_this.url, ": ").concat(err.message), 'system', err);
    });
  }
}

Body.prototype = {
  get body() {
    return this[INTERNALS].body;
  },

  get bodyUsed() {
    return this[INTERNALS].disturbed;
  },

  /**
   * Decode response as ArrayBuffer
   *
   * @return  Promise
   */
  arrayBuffer: function arrayBuffer() {
    return consumeBody.call(this).then(function (buf) {
      return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength);
    });
  },

  /**
   * Return raw response as Blob
   *
   * @return Promise
   */
  blob: function blob() {
    var ct = this.headers && this.headers.get('content-type') || '';
    return consumeBody.call(this).then(function (buf) {
      return Object.assign( // Prevent copying
      new Blob([], {
        type: ct.toLowerCase()
      }), _defineProperty({}, BUFFER, buf));
    });
  },

  /**
   * Decode response as json
   *
   * @return  Promise
   */
  json: function json() {
    var _this2 = this;

    return consumeBody.call(this).then(function (buffer$$1) {
      try {
        return JSON.parse(buffer$$1.toString());
      } catch (err) {
        return Body.Promise.reject(new FetchError("invalid json response body at ".concat(_this2.url, " reason: ").concat(err.message), 'invalid-json'));
      }
    });
  },

  /**
   * Decode response as text
   *
   * @return  Promise
   */
  text: function text() {
    return consumeBody.call(this).then(function (buffer$$1) {
      return buffer$$1.toString();
    });
  },

  /**
   * Decode response as buffer (non-spec api)
   *
   * @return  Promise
   */
  buffer: function buffer$$1() {
    return consumeBody.call(this);
  },

  /**
   * Decode response as text, while automatically detecting the encoding and
   * trying to decode to UTF-8 (non-spec api)
   *
   * @return  Promise
   */
  textConverted: function textConverted() {
    var _this3 = this;

    return consumeBody.call(this).then(function (buffer$$1) {
      return convertBody(buffer$$1, _this3.headers);
    });
  }
}; // In browsers, all properties are enumerable.

Object.defineProperties(Body.prototype, {
  body: {
    enumerable: true
  },
  bodyUsed: {
    enumerable: true
  },
  arrayBuffer: {
    enumerable: true
  },
  blob: {
    enumerable: true
  },
  json: {
    enumerable: true
  },
  text: {
    enumerable: true
  }
});

Body.mixIn = function (proto) {
  var _iteratorNormalCompletion = true;
  var _didIteratorError = false;
  var _iteratorError = undefined;

  try {
    for (var _iterator = Object.getOwnPropertyNames(Body.prototype)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
      var name = _step.value;

      // istanbul ignore else: future proof
      if (!(name in proto)) {
        var desc = Object.getOwnPropertyDescriptor(Body.prototype, name);
        Object.defineProperty(proto, name, desc);
      }
    }
  } catch (err) {
    _didIteratorError = true;
    _iteratorError = err;
  } finally {
    try {
      if (!_iteratorNormalCompletion && _iterator.return != null) {
        _iterator.return();
      }
    } finally {
      if (_didIteratorError) {
        throw _iteratorError;
      }
    }
  }
};
/**
 * Consume and convert an entire Body to a Buffer.
 *
 * Ref: https://fetch.spec.whatwg.org/#concept-body-consume-body
 *
 * @return  Promise
 */


function consumeBody() {
  var _this4 = this;

  if (this[INTERNALS].disturbed) {
    return Body.Promise.reject(new TypeError("body used already for: ".concat(this.url)));
  }

  this[INTERNALS].disturbed = true;

  if (this[INTERNALS].error) {
    return Body.Promise.reject(this[INTERNALS].error);
  } // body is null


  if (this.body === null) {
    return Body.Promise.resolve(Buffer.alloc(0));
  } // body is string


  if (typeof this.body === 'string') {
    return Body.Promise.resolve(Buffer.from(this.body));
  } // body is blob


  if (this.body instanceof Blob) {
    return Body.Promise.resolve(this.body[BUFFER]);
  } // body is buffer


  if (Buffer.isBuffer(this.body)) {
    return Body.Promise.resolve(this.body);
  } // body is buffer


  if (Object.prototype.toString.call(this.body) === '[object ArrayBuffer]') {
    return Body.Promise.resolve(Buffer.from(this.body));
  } // istanbul ignore if: should never happen


  if (!(this.body instanceof Stream)) {
    return Body.Promise.resolve(Buffer.alloc(0));
  } // body is stream
  // get ready to actually consume the body


  var accum = [];
  var accumBytes = 0;
  var abort = false;
  return new Body.Promise(function (resolve, reject) {
    var resTimeout; // allow timeout on slow response body

    if (_this4.timeout) {
      resTimeout = setTimeout(function () {
        abort = true;
        reject(new FetchError("Response timeout while trying to fetch ".concat(_this4.url, " (over ").concat(_this4.timeout, "ms)"), 'body-timeout'));
      }, _this4.timeout);
    } // handle stream error, such as incorrect content-encoding


    _this4.body.on('error', function (err) {
      reject(new FetchError("Invalid response body while trying to fetch ".concat(_this4.url, ": ").concat(err.message), 'system', err));
    });

    _this4.body.on('data', function (chunk) {
      if (abort || chunk === null) {
        return;
      }

      if (_this4.size && accumBytes + chunk.length > _this4.size) {
        abort = true;
        reject(new FetchError("content size at ".concat(_this4.url, " over limit: ").concat(_this4.size), 'max-size'));
        return;
      }

      accumBytes += chunk.length;
      accum.push(chunk);
    });

    _this4.body.on('end', function () {
      if (abort) {
        return;
      }

      clearTimeout(resTimeout);

      try {
        resolve(Buffer.concat(accum));
      } catch (err) {
        // handle streams that have accumulated too much data (issue #414)
        reject(new FetchError("Could not create Buffer from response body for ".concat(_this4.url, ": ").concat(err.message), 'system', err));
      }
    });
  });
}
/**
 * Detect buffer encoding and convert to target encoding
 * ref: http://www.w3.org/TR/2011/WD-html5-20110113/parsing.html#determining-the-character-encoding
 *
 * @param   Buffer  buffer    Incoming buffer
 * @param   String  encoding  Target encoding
 * @return  String
 */


function convertBody(buffer$$1, headers) {
  if (typeof convert !== 'function') {
    throw new Error('The package `encoding` must be installed to use the textConverted() function');
  }

  var ct = headers.get('content-type');
  var charset = 'utf-8';
  var res, str; // header

  if (ct) {
    res = /charset=([^;]*)/i.exec(ct);
  } // no charset in content type, peek at response body for at most 1024 bytes


  str = buffer$$1.slice(0, 1024).toString(); // html5

  if (!res && str) {
    res = /<meta.+?charset=(['"])(.+?)\1/i.exec(str);
  } // html4


  if (!res && str) {
    res = /<meta[\s]+?http-equiv=(['"])content-type\1[\s]+?content=(['"])(.+?)\2/i.exec(str);

    if (res) {
      res = /charset=(.*)/i.exec(res.pop());
    }
  } // xml


  if (!res && str) {
    res = /<\?xml.+?encoding=(['"])(.+?)\1/i.exec(str);
  } // found charset


  if (res) {
    charset = res.pop(); // prevent decode issues when sites use incorrect encoding
    // ref: https://hsivonen.fi/encoding-menu/

    if (charset === 'gb2312' || charset === 'gbk') {
      charset = 'gb18030';
    }
  } // turn raw buffers into a single utf-8 buffer


  return convert(buffer$$1, 'UTF-8', charset).toString();
}
/**
 * Detect a URLSearchParams object
 * ref: https://github.com/bitinn/node-fetch/issues/296#issuecomment-307598143
 *
 * @param   Object  obj     Object to detect by type or brand
 * @return  String
 */


function isURLSearchParams(obj) {
  // Duck-typing as a necessary condition.
  if (_typeof(obj) !== 'object' || typeof obj.append !== 'function' || typeof obj.delete !== 'function' || typeof obj.get !== 'function' || typeof obj.getAll !== 'function' || typeof obj.has !== 'function' || typeof obj.set !== 'function') {
    return false;
  } // Brand-checking and more duck-typing as optional condition.


  return obj.constructor.name === 'URLSearchParams' || Object.prototype.toString.call(obj) === '[object URLSearchParams]' || typeof obj.sort === 'function';
}
/**
 * Clone body given Res/Req instance
 *
 * @param   Mixed  instance  Response or Request instance
 * @return  Mixed
 */


function _clone(instance) {
  var p1, p2;
  var body = instance.body; // don't allow cloning a used body

  if (instance.bodyUsed) {
    throw new Error('cannot clone body after it is used');
  } // check that body is a stream and not form-data object
  // note: we can't clone the form-data object without having it as a dependency


  if (body instanceof Stream && typeof body.getBoundary !== 'function') {
    // tee instance body
    p1 = new PassThrough();
    p2 = new PassThrough();
    body.pipe(p1);
    body.pipe(p2); // set instance body to teed body and return the other teed body

    instance[INTERNALS].body = p1;
    body = p2;
  }

  return body;
}
/**
 * Performs the operation "extract a `Content-Type` value from |object|" as
 * specified in the specification:
 * https://fetch.spec.whatwg.org/#concept-bodyinit-extract
 *
 * This function assumes that instance.body is present.
 *
 * @param   Mixed  instance  Response or Request instance
 */


function extractContentType(instance) {
  var body = instance.body; // istanbul ignore if: Currently, because of a guard in Request, body
  // can never be null. Included here for completeness.

  if (body === null) {
    // body is null
    return null;
  } else if (typeof body === 'string') {
    // body is string
    return 'text/plain;charset=UTF-8';
  } else if (isURLSearchParams(body)) {
    // body is a URLSearchParams
    return 'application/x-www-form-urlencoded;charset=UTF-8';
  } else if (body instanceof Blob) {
    // body is blob
    return body.type || null;
  } else if (Buffer.isBuffer(body)) {
    // body is buffer
    return null;
  } else if (Object.prototype.toString.call(body) === '[object ArrayBuffer]') {
    // body is array buffer
    return null;
  } else if (typeof body.getBoundary === 'function') {
    // detect form data input from form-data module
    return "multipart/form-data;boundary=".concat(body.getBoundary());
  } else {
    // body is stream
    // can't really do much about this
    return null;
  }
}
/**
 * The Fetch Standard treats this as if "total bytes" is a property on the body.
 * For us, we have to explicitly get it with a function.
 *
 * ref: https://fetch.spec.whatwg.org/#concept-body-total-bytes
 *
 * @param   Body    instance   Instance of Body
 * @return  Number?            Number of bytes, or null if not possible
 */


function getTotalBytes(instance) {
  var body = instance.body; // istanbul ignore if: included for completion

  if (body === null) {
    // body is null
    return 0;
  } else if (typeof body === 'string') {
    // body is string
    return Buffer.byteLength(body);
  } else if (isURLSearchParams(body)) {
    // body is URLSearchParams
    return Buffer.byteLength(String(body));
  } else if (body instanceof Blob) {
    // body is blob
    return body.size;
  } else if (Buffer.isBuffer(body)) {
    // body is buffer
    return body.length;
  } else if (Object.prototype.toString.call(body) === '[object ArrayBuffer]') {
    // body is array buffer
    return body.byteLength;
  } else if (body && typeof body.getLengthSync === 'function') {
    // detect form data input from form-data module
    if (body._lengthRetrievers && body._lengthRetrievers.length == 0 || // 1.x
    body.hasKnownLength && body.hasKnownLength()) {
      // 2.x
      return body.getLengthSync();
    }

    return null;
  } else {
    // body is stream
    // can't really do much about this
    return null;
  }
}
/**
 * Write a Body to a Node.js WritableStream (e.g. http.Request) object.
 *
 * @param   Body    instance   Instance of Body
 * @return  Void
 */


function writeToStream(dest, instance) {
  var body = instance.body;

  if (body === null) {
    // body is null
    dest.end();
  } else if (typeof body === 'string') {
    // body is string
    dest.write(body);
    dest.end();
  } else if (isURLSearchParams(body)) {
    // body is URLSearchParams
    dest.write(Buffer.from(String(body)));
    dest.end();
  } else if (body instanceof Blob) {
    // body is blob
    dest.write(body[BUFFER]);
    dest.end();
  } else if (Buffer.isBuffer(body)) {
    // body is buffer
    dest.write(body);
    dest.end();
  } else if (Object.prototype.toString.call(body) === '[object ArrayBuffer]') {
    // body is array buffer
    dest.write(Buffer.from(body));
    dest.end();
  } else {
    // body is stream
    body.pipe(dest);
  }
} // expose Promise


Body.Promise = global.Promise;
/**
 * headers.js
 *
 * Headers class offers convenient helpers
 */

var invalidTokenRegex = /[^\^_`a-zA-Z\-0-9!#$%&'*+.|~]/;
var invalidHeaderCharRegex = /[^\t\x20-\x7e\x80-\xff]/;

function validateName(name) {
  name = "".concat(name);

  if (invalidTokenRegex.test(name)) {
    throw new TypeError("".concat(name, " is not a legal HTTP header name"));
  }
}

function validateValue(value) {
  value = "".concat(value);

  if (invalidHeaderCharRegex.test(value)) {
    throw new TypeError("".concat(value, " is not a legal HTTP header value"));
  }
}
/**
 * Find the key in the map object given a header name.
 *
 * Returns undefined if not found.
 *
 * @param   String  name  Header name
 * @return  String|Undefined
 */


function find(map, name) {
  name = name.toLowerCase();

  for (var key in map) {
    if (key.toLowerCase() === name) {
      return key;
    }
  }

  return undefined;
}

var MAP = Symbol('map');

var Headers =
/*#__PURE__*/
function () {
  /**
   * Headers class
   *
   * @param   Object  headers  Response headers
   * @return  Void
   */
  function Headers() {
    _classCallCheck(this, Headers);

    var init = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : undefined;
    this[MAP] = Object.create(null);

    if (init instanceof Headers) {
      var rawHeaders = init.raw();
      var headerNames = Object.keys(rawHeaders);

      for (var _i = 0; _i < headerNames.length; _i++) {
        var headerName = headerNames[_i];
        var _iteratorNormalCompletion2 = true;
        var _didIteratorError2 = false;
        var _iteratorError2 = undefined;

        try {
          for (var _iterator2 = rawHeaders[headerName][Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
            var value = _step2.value;
            this.append(headerName, value);
          }
        } catch (err) {
          _didIteratorError2 = true;
          _iteratorError2 = err;
        } finally {
          try {
            if (!_iteratorNormalCompletion2 && _iterator2.return != null) {
              _iterator2.return();
            }
          } finally {
            if (_didIteratorError2) {
              throw _iteratorError2;
            }
          }
        }
      }

      return;
    } // We don't worry about converting prop to ByteString here as append()
    // will handle it.


    if (init == null) ; else if (_typeof(init) === 'object') {
      var method = init[Symbol.iterator];

      if (method != null) {
        if (typeof method !== 'function') {
          throw new TypeError('Header pairs must be iterable');
        } // sequence<sequence<ByteString>>
        // Note: per spec we have to first exhaust the lists then process them


        var pairs = [];
        var _iteratorNormalCompletion3 = true;
        var _didIteratorError3 = false;
        var _iteratorError3 = undefined;

        try {
          for (var _iterator3 = init[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
            var pair = _step3.value;

            if (_typeof(pair) !== 'object' || typeof pair[Symbol.iterator] !== 'function') {
              throw new TypeError('Each header pair must be iterable');
            }

            pairs.push(Array.from(pair));
          }
        } catch (err) {
          _didIteratorError3 = true;
          _iteratorError3 = err;
        } finally {
          try {
            if (!_iteratorNormalCompletion3 && _iterator3.return != null) {
              _iterator3.return();
            }
          } finally {
            if (_didIteratorError3) {
              throw _iteratorError3;
            }
          }
        }

        for (var _i2 = 0; _i2 < pairs.length; _i2++) {
          var _pair = pairs[_i2];

          if (_pair.length !== 2) {
            throw new TypeError('Each header pair must be a name/value tuple');
          }

          this.append(_pair[0], _pair[1]);
        }
      } else {
        // record<ByteString, ByteString>
        var _arr = Object.keys(init);

        for (var _i3 = 0; _i3 < _arr.length; _i3++) {
          var key = _arr[_i3];
          var _value = init[key];
          this.append(key, _value);
        }
      }
    } else {
      throw new TypeError('Provided initializer must be an object');
    }
  }
  /**
   * Return combined header value given name
   *
   * @param   String  name  Header name
   * @return  Mixed
   */


  _createClass(Headers, [{
    key: "get",
    value: function get(name) {
      name = "".concat(name);
      validateName(name);
      var key = find(this[MAP], name);

      if (key === undefined) {
        return null;
      }

      return this[MAP][key].join(', ');
    }
    /**
     * Iterate over all headers
     *
     * @param   Function  callback  Executed for each item with parameters (value, name, thisArg)
     * @param   Boolean   thisArg   `this` context for callback function
     * @return  Void
     */

  }, {
    key: "forEach",
    value: function forEach(callback) {
      var thisArg = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : undefined;
      var pairs = getHeaders(this);
      var i = 0;

      while (i < pairs.length) {
        var _pairs$i = pairs[i];
        var name = _pairs$i[0],
            value = _pairs$i[1];
        callback.call(thisArg, value, name, this);
        pairs = getHeaders(this);
        i++;
      }
    }
    /**
     * Overwrite header values given name
     *
     * @param   String  name   Header name
     * @param   String  value  Header value
     * @return  Void
     */

  }, {
    key: "set",
    value: function set(name, value) {
      name = "".concat(name);
      value = "".concat(value);
      validateName(name);
      validateValue(value);
      var key = find(this[MAP], name);
      this[MAP][key !== undefined ? key : name] = [value];
    }
    /**
     * Append a value onto existing header
     *
     * @param   String  name   Header name
     * @param   String  value  Header value
     * @return  Void
     */

  }, {
    key: "append",
    value: function append(name, value) {
      name = "".concat(name);
      value = "".concat(value);
      validateName(name);
      validateValue(value);
      var key = find(this[MAP], name);

      if (key !== undefined) {
        this[MAP][key].push(value);
      } else {
        this[MAP][name] = [value];
      }
    }
    /**
     * Check for header name existence
     *
     * @param   String   name  Header name
     * @return  Boolean
     */

  }, {
    key: "has",
    value: function has(name) {
      name = "".concat(name);
      validateName(name);
      return find(this[MAP], name) !== undefined;
    }
    /**
     * Delete all header values given name
     *
     * @param   String  name  Header name
     * @return  Void
     */

  }, {
    key: "delete",
    value: function _delete(name) {
      name = "".concat(name);
      validateName(name);
      var key = find(this[MAP], name);

      if (key !== undefined) {
        delete this[MAP][key];
      }
    }
    /**
     * Return raw headers (non-spec api)
     *
     * @return  Object
     */

  }, {
    key: "raw",
    value: function raw() {
      return this[MAP];
    }
    /**
     * Get an iterator on keys.
     *
     * @return  Iterator
     */

  }, {
    key: "keys",
    value: function keys() {
      return createHeadersIterator(this, 'key');
    }
    /**
     * Get an iterator on values.
     *
     * @return  Iterator
     */

  }, {
    key: "values",
    value: function values() {
      return createHeadersIterator(this, 'value');
    }
    /**
     * Get an iterator on entries.
     *
     * This is the default iterator of the Headers object.
     *
     * @return  Iterator
     */

  }, {
    key: Symbol.iterator,
    value: function value() {
      return createHeadersIterator(this, 'key+value');
    }
  }]);

  return Headers;
}();

Headers.prototype.entries = Headers.prototype[Symbol.iterator];
Object.defineProperty(Headers.prototype, Symbol.toStringTag, {
  value: 'Headers',
  writable: false,
  enumerable: false,
  configurable: true
});
Object.defineProperties(Headers.prototype, {
  get: {
    enumerable: true
  },
  forEach: {
    enumerable: true
  },
  set: {
    enumerable: true
  },
  append: {
    enumerable: true
  },
  has: {
    enumerable: true
  },
  delete: {
    enumerable: true
  },
  keys: {
    enumerable: true
  },
  values: {
    enumerable: true
  },
  entries: {
    enumerable: true
  }
});

function getHeaders(headers) {
  var kind = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'key+value';
  var keys = Object.keys(headers[MAP]).sort();
  return keys.map(kind === 'key' ? function (k) {
    return k.toLowerCase();
  } : kind === 'value' ? function (k) {
    return headers[MAP][k].join(', ');
  } : function (k) {
    return [k.toLowerCase(), headers[MAP][k].join(', ')];
  });
}

var INTERNAL = Symbol('internal');

function createHeadersIterator(target, kind) {
  var iterator = Object.create(HeadersIteratorPrototype);
  iterator[INTERNAL] = {
    target: target,
    kind: kind,
    index: 0
  };
  return iterator;
}

var HeadersIteratorPrototype = Object.setPrototypeOf({
  next: function next() {
    // istanbul ignore if
    if (!this || Object.getPrototypeOf(this) !== HeadersIteratorPrototype) {
      throw new TypeError('Value of `this` is not a HeadersIterator');
    }

    var _INTERNAL = this[INTERNAL];
    var target = _INTERNAL.target,
        kind = _INTERNAL.kind,
        index = _INTERNAL.index;
    var values = getHeaders(target, kind);
    var len = values.length;

    if (index >= len) {
      return {
        value: undefined,
        done: true
      };
    }

    this[INTERNAL].index = index + 1;
    return {
      value: values[index],
      done: false
    };
  }
}, Object.getPrototypeOf(Object.getPrototypeOf([][Symbol.iterator]())));
Object.defineProperty(HeadersIteratorPrototype, Symbol.toStringTag, {
  value: 'HeadersIterator',
  writable: false,
  enumerable: false,
  configurable: true
});
/**
 * Export the Headers object in a form that Node.js can consume.
 *
 * @param   Headers  headers
 * @return  Object
 */

function exportNodeCompatibleHeaders(headers) {
  var obj = Object.assign({
    __proto__: null
  }, headers[MAP]); // http.request() only supports string as Host header. This hack makes
  // specifying custom Host header possible.

  var hostHeaderKey = find(headers[MAP], 'Host');

  if (hostHeaderKey !== undefined) {
    obj[hostHeaderKey] = obj[hostHeaderKey][0];
  }

  return obj;
}
/**
 * Create a Headers object from an object of headers, ignoring those that do
 * not conform to HTTP grammar productions.
 *
 * @param   Object  obj  Object of headers
 * @return  Headers
 */


function createHeadersLenient(obj) {
  var headers = new Headers();

  var _arr2 = Object.keys(obj);

  for (var _i4 = 0; _i4 < _arr2.length; _i4++) {
    var name = _arr2[_i4];

    if (invalidTokenRegex.test(name)) {
      continue;
    }

    if (Array.isArray(obj[name])) {
      var _iteratorNormalCompletion4 = true;
      var _didIteratorError4 = false;
      var _iteratorError4 = undefined;

      try {
        for (var _iterator4 = obj[name][Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
          var val = _step4.value;

          if (invalidHeaderCharRegex.test(val)) {
            continue;
          }

          if (headers[MAP][name] === undefined) {
            headers[MAP][name] = [val];
          } else {
            headers[MAP][name].push(val);
          }
        }
      } catch (err) {
        _didIteratorError4 = true;
        _iteratorError4 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion4 && _iterator4.return != null) {
            _iterator4.return();
          }
        } finally {
          if (_didIteratorError4) {
            throw _iteratorError4;
          }
        }
      }
    } else if (!invalidHeaderCharRegex.test(obj[name])) {
      headers[MAP][name] = [obj[name]];
    }
  }

  return headers;
}
/**
 * response.js
 *
 * Response class provides content decoding
 */


var _require$1 = require('http');

var STATUS_CODES = _require$1.STATUS_CODES;
var INTERNALS$1 = Symbol('Response internals');
/**
 * Response class
 *
 * @param   Stream  body  Readable stream
 * @param   Object  opts  Response options
 * @return  Void
 */

var Response =
/*#__PURE__*/
function () {
  function Response() {
    _classCallCheck(this, Response);

    var body = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
    var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
    Body.call(this, body, opts);
    var status = opts.status || 200;
    this[INTERNALS$1] = {
      url: opts.url,
      status: status,
      statusText: opts.statusText || STATUS_CODES[status],
      headers: new Headers(opts.headers)
    };
  }

  _createClass(Response, [{
    key: "clone",

    /**
     * Clone this response
     *
     * @return  Response
     */
    value: function clone() {
      return new Response(_clone(this), {
        url: this.url,
        status: this.status,
        statusText: this.statusText,
        headers: this.headers,
        ok: this.ok
      });
    }
  }, {
    key: "url",
    get: function get() {
      return this[INTERNALS$1].url;
    }
  }, {
    key: "status",
    get: function get() {
      return this[INTERNALS$1].status;
    }
    /**
     * Convenience property representing if the request ended normally
     */

  }, {
    key: "ok",
    get: function get() {
      return this[INTERNALS$1].status >= 200 && this[INTERNALS$1].status < 300;
    }
  }, {
    key: "statusText",
    get: function get() {
      return this[INTERNALS$1].statusText;
    }
  }, {
    key: "headers",
    get: function get() {
      return this[INTERNALS$1].headers;
    }
  }]);

  return Response;
}();

Body.mixIn(Response.prototype);
Object.defineProperties(Response.prototype, {
  url: {
    enumerable: true
  },
  status: {
    enumerable: true
  },
  ok: {
    enumerable: true
  },
  statusText: {
    enumerable: true
  },
  headers: {
    enumerable: true
  },
  clone: {
    enumerable: true
  }
});
Object.defineProperty(Response.prototype, Symbol.toStringTag, {
  value: 'Response',
  writable: false,
  enumerable: false,
  configurable: true
});
/**
 * request.js
 *
 * Request class contains server only options
 *
 * All spec algorithm step numbers are based on https://fetch.spec.whatwg.org/commit-snapshots/ae716822cb3a61843226cd090eefc6589446c1d2/.
 */

var _require$2 = require('url');

var format_url = _require$2.format;
var parse_url = _require$2.parse;
var INTERNALS$2 = Symbol('Request internals');
/**
 * Check if a value is an instance of Request.
 *
 * @param   Mixed   input
 * @return  Boolean
 */

function isRequest(input) {
  return _typeof(input) === 'object' && _typeof(input[INTERNALS$2]) === 'object';
}
/**
 * Request class
 *
 * @param   Mixed   input  Url or Request instance
 * @param   Object  init   Custom options
 * @return  Void
 */


var Request =
/*#__PURE__*/
function () {
  function Request(input) {
    _classCallCheck(this, Request);

    var init = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
    var parsedURL; // normalize input

    if (!isRequest(input)) {
      if (input && input.href) {
        // in order to support Node.js' Url objects; though WHATWG's URL objects
        // will fall into this branch also (since their `toString()` will return
        // `href` property anyway)
        parsedURL = parse_url(input.href);
      } else {
        // coerce input to a string before attempting to parse
        parsedURL = parse_url("".concat(input));
      }

      input = {};
    } else {
      parsedURL = parse_url(input.url);
    }

    var method = init.method || input.method || 'GET';
    method = method.toUpperCase();

    if ((init.body != null || isRequest(input) && input.body !== null) && (method === 'GET' || method === 'HEAD')) {
      throw new TypeError('Request with GET/HEAD method cannot have body');
    }

    var inputBody = init.body != null ? init.body : isRequest(input) && input.body !== null ? _clone(input) : null;
    Body.call(this, inputBody, {
      timeout: init.timeout || input.timeout || 0,
      size: init.size || input.size || 0
    });
    var headers = new Headers(init.headers || input.headers || {});

    if (init.body != null) {
      var contentType = extractContentType(this);

      if (contentType !== null && !headers.has('Content-Type')) {
        headers.append('Content-Type', contentType);
      }
    }

    this[INTERNALS$2] = {
      method: method,
      redirect: init.redirect || input.redirect || 'follow',
      headers: headers,
      parsedURL: parsedURL
    }; // node-fetch-only options

    this.follow = init.follow !== undefined ? init.follow : input.follow !== undefined ? input.follow : 20;
    this.compress = init.compress !== undefined ? init.compress : input.compress !== undefined ? input.compress : true;
    this.counter = init.counter || input.counter || 0;
    this.agent = init.agent || input.agent;
  }

  _createClass(Request, [{
    key: "clone",

    /**
     * Clone this request
     *
     * @return  Request
     */
    value: function clone() {
      return new Request(this);
    }
  }, {
    key: "method",
    get: function get() {
      return this[INTERNALS$2].method;
    }
  }, {
    key: "url",
    get: function get() {
      return format_url(this[INTERNALS$2].parsedURL);
    }
  }, {
    key: "headers",
    get: function get() {
      return this[INTERNALS$2].headers;
    }
  }, {
    key: "redirect",
    get: function get() {
      return this[INTERNALS$2].redirect;
    }
  }]);

  return Request;
}();

Body.mixIn(Request.prototype);
Object.defineProperty(Request.prototype, Symbol.toStringTag, {
  value: 'Request',
  writable: false,
  enumerable: false,
  configurable: true
});
Object.defineProperties(Request.prototype, {
  method: {
    enumerable: true
  },
  url: {
    enumerable: true
  },
  headers: {
    enumerable: true
  },
  redirect: {
    enumerable: true
  },
  clone: {
    enumerable: true
  }
});
/**
 * Convert a Request to Node.js http request options.
 *
 * @param   Request  A Request instance
 * @return  Object   The options object to be passed to http.request
 */

function getNodeRequestOptions(request) {
  var parsedURL = request[INTERNALS$2].parsedURL;
  var headers = new Headers(request[INTERNALS$2].headers); // fetch step 1.3

  if (!headers.has('Accept')) {
    headers.set('Accept', '*/*');
  } // Basic fetch


  if (!parsedURL.protocol || !parsedURL.hostname) {
    throw new TypeError('Only absolute URLs are supported');
  }

  if (!/^https?:$/.test(parsedURL.protocol)) {
    throw new TypeError('Only HTTP(S) protocols are supported');
  } // HTTP-network-or-cache fetch steps 2.4-2.7


  var contentLengthValue = null;

  if (request.body == null && /^(POST|PUT)$/i.test(request.method)) {
    contentLengthValue = '0';
  }

  if (request.body != null) {
    var totalBytes = getTotalBytes(request);

    if (typeof totalBytes === 'number') {
      contentLengthValue = String(totalBytes);
    }
  }

  if (contentLengthValue) {
    headers.set('Content-Length', contentLengthValue);
  } // HTTP-network-or-cache fetch step 2.11


  if (!headers.has('User-Agent')) {
    headers.set('User-Agent', 'node-fetch/1.0 (+https://github.com/bitinn/node-fetch)');
  } // HTTP-network-or-cache fetch step 2.15


  if (request.compress) {
    headers.set('Accept-Encoding', 'gzip,deflate');
  }

  if (!headers.has('Connection') && !request.agent) {
    headers.set('Connection', 'close');
  } // HTTP-network fetch step 4.2
  // chunked encoding is handled by Node.js


  return Object.assign({}, parsedURL, {
    method: request.method,
    headers: exportNodeCompatibleHeaders(headers),
    agent: request.agent
  });
}
/**
 * index.js
 *
 * a request API compatible with window.fetch
 *
 * All spec algorithm step numbers are based on https://fetch.spec.whatwg.org/commit-snapshots/ae716822cb3a61843226cd090eefc6589446c1d2/.
 */


var http = require('http');

var https = require('https');

var _require$3 = require('stream');

var PassThrough$1 = _require$3.PassThrough;

var _require2 = require('url');

var resolve_url = _require2.resolve;

var zlib = require('zlib');
/**
 * Fetch function
 *
 * @param   Mixed    url   Absolute url or Request instance
 * @param   Object   opts  Fetch options
 * @return  Promise
 */


function fetch(url, opts) {
  // allow custom promise
  if (!fetch.Promise) {
    throw new Error('native promise missing, set fetch.Promise to your favorite alternative');
  }

  Body.Promise = fetch.Promise; // wrap http.request into fetch

  return new fetch.Promise(function (resolve, reject) {
    // build request object
    var request = new Request(url, opts);
    var options = getNodeRequestOptions(request);
    var send = (options.protocol === 'https:' ? https : http).request; // send request

    var req = send(options);
    var reqTimeout;

    function finalize() {
      req.abort();
      clearTimeout(reqTimeout);
    }

    if (request.timeout) {
      req.once('socket', function (socket) {
        reqTimeout = setTimeout(function () {
          reject(new FetchError("network timeout at: ".concat(request.url), 'request-timeout'));
          finalize();
        }, request.timeout);
      });
    }

    req.on('error', function (err) {
      reject(new FetchError("request to ".concat(request.url, " failed, reason: ").concat(err.message), 'system', err));
      finalize();
    });
    req.on('response', function (res) {
      clearTimeout(reqTimeout);
      var headers = createHeadersLenient(res.headers); // HTTP fetch step 5

      if (fetch.isRedirect(res.statusCode)) {
        // HTTP fetch step 5.2
        var location = headers.get('Location'); // HTTP fetch step 5.3

        var locationURL = location === null ? null : resolve_url(request.url, location); // HTTP fetch step 5.5

        switch (request.redirect) {
          case 'error':
            reject(new FetchError("redirect mode is set to error: ".concat(request.url), 'no-redirect'));
            finalize();
            return;

          case 'manual':
            // node-fetch-specific step: make manual redirect a bit easier to use by setting the Location header value to the resolved URL.
            if (locationURL !== null) {
              headers.set('Location', locationURL);
            }

            break;

          case 'follow':
            // HTTP-redirect fetch step 2
            if (locationURL === null) {
              break;
            } // HTTP-redirect fetch step 5


            if (request.counter >= request.follow) {
              reject(new FetchError("maximum redirect reached at: ".concat(request.url), 'max-redirect'));
              finalize();
              return;
            } // HTTP-redirect fetch step 6 (counter increment)
            // Create a new Request object.


            var requestOpts = {
              headers: new Headers(request.headers),
              follow: request.follow,
              counter: request.counter + 1,
              agent: request.agent,
              compress: request.compress,
              method: request.method,
              body: request.body
            }; // HTTP-redirect fetch step 9

            if (res.statusCode !== 303 && request.body && getTotalBytes(request) === null) {
              reject(new FetchError('Cannot follow redirect with body being a readable stream', 'unsupported-redirect'));
              finalize();
              return;
            } // HTTP-redirect fetch step 11


            if (res.statusCode === 303 || (res.statusCode === 301 || res.statusCode === 302) && request.method === 'POST') {
              requestOpts.method = 'GET';
              requestOpts.body = undefined;
              requestOpts.headers.delete('content-length');
            } // HTTP-redirect fetch step 15


            resolve(fetch(new Request(locationURL, requestOpts)));
            finalize();
            return;
        }
      } // prepare response


      var body = res.pipe(new PassThrough$1());
      var response_options = {
        url: request.url,
        status: res.statusCode,
        statusText: res.statusMessage,
        headers: headers,
        size: request.size,
        timeout: request.timeout
      }; // HTTP-network fetch step 12.1.1.3

      var codings = headers.get('Content-Encoding'); // HTTP-network fetch step 12.1.1.4: handle content codings
      // in following scenarios we ignore compression support
      // 1. compression support is disabled
      // 2. HEAD request
      // 3. no Content-Encoding header
      // 4. no content response (204)
      // 5. content not modified response (304)

      if (!request.compress || request.method === 'HEAD' || codings === null || res.statusCode === 204 || res.statusCode === 304) {
        resolve(new Response(body, response_options));
        return;
      } // For Node v6+
      // Be less strict when decoding compressed responses, since sometimes
      // servers send slightly invalid responses that are still accepted
      // by common browsers.
      // Always using Z_SYNC_FLUSH is what cURL does.


      var zlibOptions = {
        flush: zlib.Z_SYNC_FLUSH,
        finishFlush: zlib.Z_SYNC_FLUSH
      }; // for gzip

      if (codings == 'gzip' || codings == 'x-gzip') {
        body = body.pipe(zlib.createGunzip(zlibOptions));
        resolve(new Response(body, response_options));
        return;
      } // for deflate


      if (codings == 'deflate' || codings == 'x-deflate') {
        // handle the infamous raw deflate response from old servers
        // a hack for old IIS and Apache servers
        var raw = res.pipe(new PassThrough$1());
        raw.once('data', function (chunk) {
          // see http://stackoverflow.com/questions/37519828
          if ((chunk[0] & 0x0F) === 0x08) {
            body = body.pipe(zlib.createInflate());
          } else {
            body = body.pipe(zlib.createInflateRaw());
          }

          resolve(new Response(body, response_options));
        });
        return;
      } // otherwise, use response as-is


      resolve(new Response(body, response_options));
    });
    writeToStream(req, request);
  });
}
/**
 * Redirect code matching
 *
 * @param   Number   code  Status code
 * @return  Boolean
 */


fetch.isRedirect = function (code) {
  return code === 301 || code === 302 || code === 303 || code === 307 || code === 308;
}; // Needed for TypeScript.


fetch.default = fetch; // expose Promise

fetch.Promise = global.Promise;

var index_es = /*#__PURE__*/Object.freeze({
  default: fetch,
  Headers: Headers,
  Request: Request,
  Response: Response,
  FetchError: FetchError
});

var fetch$1 = ( index_es && fetch ) || index_es;

function wrapFetchForNode(fetch) {
  // Support schemaless URIs on the server for parity with the browser.
  // https://github.com/matthew-andrews/isomorphic-fetch/pull/10
  return function (u, options) {
    if (typeof u === 'string' && u.slice(0, 2) === '//') {
      return fetch('https:' + u, options);
    }

    return fetch(u, options);
  };
}

var fetchNode = function fetchNode(context) {
  // This modifies the global `node-fetch` object, which isn't great, since
  // different callers to `fetch-ponyfill` which pass a different Promise
  // implementation would each expect to have their implementation used. But,
  // given the way `node-fetch` is implemented, this is the only way to make
  // it work at all.
  if (context && context.Promise) {
    fetch$1.Promise = context.Promise;
  }

  return {
    fetch: wrapFetchForNode(fetch$1),
    Headers: fetch$1.Headers,
    Request: fetch$1.Request,
    Response: fetch$1.Response
  };
};

var _fetchPonyfill = fetchNode({
  Promise: Promise
}),
    _fetch = _fetchPonyfill.fetch;

var RestTransport =
/*#__PURE__*/
function (_Transport) {
  _inherits(RestTransport, _Transport);

  /**
   * APIKey
   */

  /**
   * APISecret
   */

  /**
   * Exchanges currencies available.
   */
  function RestTransport() {
    var _this;

    var params = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};

    _classCallCheck(this, RestTransport);

    _this = _possibleConstructorReturn(this, _getPrototypeOf(RestTransport).call(this, params, params.brokerId === BROKERS.BITCAMBIO ? 'restBitcambio' : 'rest'));
    _this.key = params.key;
    _this.secret = params.secret;
    _this.currency = params.currency || 'BRL';
    return _this;
  }

  _createClass(RestTransport, [{
    key: "headers",
    value: function headers(method, body) {
      var timeStamp = Date.now().toString();
      var Signature = sha256.hmac.create(this.secret).update(timeStamp).hex();
      return {
        method: method,
        headers: {
          'Content-Type': 'application/json',
          Nonce: timeStamp,
          APIKey: this.key,
          Signature: Signature
        },
        body: JSON.stringify(body)
      };
    }
  }, {
    key: "fetch",
    value: function fetch(api) {
      var headers = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      return _fetch(this.endpoint + api, headers).then(function (response) {
        return response.json();
      });
    }
  }, {
    key: "fetchPublic",
    value: function fetchPublic(api) {
      return this.fetch("api/v1/".concat(this.currency, "/").concat(api));
    }
  }, {
    key: "fetchTrade",
    value: function fetchTrade(msg) {
      invariant_1(this.key && this.secret, 'Key or Secret not provided');
      var headers = this.headers('POST', msg);
      return this.fetch('tapi/v1/message', headers).then(function (response) {
        return response.Status === 500 ? Promise.reject(response) : response.Responses;
      }).then(function (response) {
        return response.length === 1 ? response[0] : response;
      });
    }
  }]);

  return RestTransport;
}(Transport);

var BlinkTradeRest =
/*#__PURE__*/
function (_TradeBase) {
  _inherits(BlinkTradeRest, _TradeBase);

  function BlinkTradeRest() {
    var _this;

    var params = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};

    _classCallCheck(this, BlinkTradeRest);

    _this = _possibleConstructorReturn(this, _getPrototypeOf(BlinkTradeRest).call(this, params));
    _this.transport = params.transport || new RestTransport(params);
    return _this;
  }

  _createClass(BlinkTradeRest, [{
    key: "send",
    value: function send(msg) {
      return this.transport.fetchTrade(msg);
    }
  }, {
    key: "fetchPublic",
    value: function fetchPublic(path) {
      return this.transport.fetchPublic(path);
    }
  }, {
    key: "ticker",
    value: function ticker(callback) {
      return nodeify_1.extend(this.fetchPublic('ticker')).nodeify(callback);
    }
  }, {
    key: "trades",
    value: function trades() {
      var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
          _ref$limit = _ref.limit,
          limit = _ref$limit === void 0 ? 100 : _ref$limit,
          _ref$since = _ref.since,
          since = _ref$since === void 0 ? 0 : _ref$since;

      var callback = arguments.length > 1 ? arguments[1] : undefined;
      return nodeify_1.extend(this.fetchPublic("trades?limit=".concat(limit, "&since=").concat(since))).nodeify(callback);
    }
  }, {
    key: "orderbook",
    value: function orderbook(callback) {
      return nodeify_1.extend(this.fetchPublic('orderbook')).nodeify(callback);
    }
  }]);

  return BlinkTradeRest;
}(TradeBase);

/**
 * BlinkTradeJS SDK
 * (c) 2016-present BlinkTrade, Inc.
 *
 * This file is part of BlinkTradeJS
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *      
 */

export { BROKERS as Brokers, BlinkTradeWS, BlinkTradeRest };