UNPKG

bitcoind-regtest

Version:

Run bitcoind in regtest mode for your own blockchain

893 lines 58.4 kB
'use strict';

var _get = require('babel-runtime/helpers/get')['default'];

var _inherits = require('babel-runtime/helpers/inherits')['default'];

var _createDecoratedClass = require('babel-runtime/helpers/create-decorated-class')['default'];

var _classCallCheck = require('babel-runtime/helpers/class-call-check')['default'];

var _slicedToArray = require('babel-runtime/helpers/sliced-to-array')['default'];

var _regeneratorRuntime = require('babel-runtime/regenerator')['default'];

var _Promise = require('babel-runtime/core-js/promise')['default'];

var _getIterator = require('babel-runtime/core-js/get-iterator')['default'];

var _interopRequireDefault = require('babel-runtime/helpers/interop-require-default')['default'];

Object.defineProperty(exports, '__esModule', {
  value: true
});

var _lodash = require('lodash');

var _lodash2 = _interopRequireDefault(_lodash);

var _events = require('events');

var _coreDecorators = require('core-decorators');

var _readyMixin = require('ready-mixin');

var _readyMixin2 = _interopRequireDefault(_readyMixin);

var _tmp = require('tmp');

var _tmp2 = _interopRequireDefault(_tmp);

var _rimraf2 = require('rimraf');

var _rimraf3 = _interopRequireDefault(_rimraf2);

var _crypto = require('crypto');

var _crypto2 = _interopRequireDefault(_crypto);

var _child_process = require('child_process');

var _bitcoreLib = require('bitcore-lib');

var _bitcoreLib2 = _interopRequireDefault(_bitcoreLib);

var _bitcoreP2p = require('bitcore-p2p');

var _bitcoreP2p2 = _interopRequireDefault(_bitcoreP2p);

var _bitcoindRpcClient = require('bitcoind-rpc-client');

var _bitcoindRpcClient2 = _interopRequireDefault(_bitcoindRpcClient);

var _makeConcurrent = require('make-concurrent');

var _makeConcurrent2 = _interopRequireDefault(_makeConcurrent);

var _promiseUsefulUtils = require('promise-useful-utils');

var _promiseUsefulUtils2 = _interopRequireDefault(_promiseUsefulUtils);

var _wallet = require('./wallet');

var _wallet2 = _interopRequireDefault(_wallet);

var tmpfs = _promiseUsefulUtils2['default'].promisifyAll(_tmp2['default']);
var rimraf = _promiseUsefulUtils2['default'].promisify(_rimraf3['default']);

var encode = function encode(s) {
  return Array.prototype.reverse.call(new Buffer(s)).toString('hex');
};

/**
 * @event Bitcoind#error
 * @param {Error} err
 */

/**
 * @event Bitcoind#data
 * @param {string} data
 */

/**
 * @event Bitcoind#exit
 * @param {number} code
 * @param {string} signal
 */

/**
 * @event Bitcoind#block
 * @param {string} hash
 */

/**
 * @event Bitcoind#tx
 * @param {string} txid
 */

/**
 * @class Bitcoind
 */

var Bitcoind = (function (_EventEmitter) {
  _inherits(Bitcoind, _EventEmitter);

  /**
   * @constructor
   * @param {Object} [opts]
   * @param {Object} [opts.wallet] Wallet options
   * @param {function} [opts.wallet.preloadsPoolSize=_.constant(10)] Preload pool size
   * @param {function} [opts.wallet.keysPoolSize=() => _.random(80, 100)]
   * @param {function} [opts.wallet.newKeyTimeout=() => _.random(60, 90) * 1000]
   * @param {function} [opts.wallet.inputsCount=() => _.random(2, 3)]
   * @param {function} [opts.wallet.outputsCount=() => _.random(3, 5)]
   * @param {Object} [opts.generate] Generate options
   * @param {Object} [opts.generate.txs]
   * @param {function} [opts.generate.txs.background=_.constant(true)]
   * @param {function} [opts.generate.txs.timeout=() => _.random(6, 9, true) * 1000]
   * @param {function} [opts.generate.txs.minInBlock=_.constant(5)]
   * @param {Object} [opts.generate.blocks]
   * @param {function} [opts.generate.blocks.background=_.constant(true)]
   * @param {function} [opts.generate.blocks.timeout=() => _.random(60, 90, true) * 1000]
   * @param {Object} [opts.bitcoind]
   * @param {function} [opts.bitcoind.path=() => '../bitcoind/bitcoind-rev-3224936']
   * @param {function} [opts.bitcoind.datadir=async () => _.first(tmpfs.dir({prefix: 'bitcoind-regtest-'}))]
   * @param {function} [opts.bitcoind.port=() => _.random(20000, 30000)]
   * @param {function} [opts.bitcoind.rpcport=() => _.random(20000, 30000)]
   * @param {function} [opts.bitcoind.rpcuser=() => crypto.randomBytes(10).toString('hex')]
   * @param {function} [opts.bitcoind.rpcpassword=() => crypto.randomBytes(10).toString('hex')]
   */

  function Bitcoind(opts) {
    var _this2 = this;

    _classCallCheck(this, _Bitcoind);

    _get(Object.getPrototypeOf(_Bitcoind.prototype), 'constructor', this).call(this);

    _promiseUsefulUtils2['default']['try'](function callee$2$0() {
      var onErrorExit;
      return _regeneratorRuntime.async(function callee$2$0$(context$3$0) {
        var _this = this;

        while (1) switch (context$3$0.prev = context$3$0.next) {
          case 0:
            this._opts = _lodash2['default'].defaultsDeep(_lodash2['default'].cloneDeep(opts) || {}, {
              wallet: {
                preloadsPoolSize: _lodash2['default'].constant(10),
                keysPoolSize: function keysPoolSize() {
                  return _lodash2['default'].random(80, 100);
                },
                newKeyTimeout: function newKeyTimeout() {
                  return _lodash2['default'].random(60, 90) * 1000;
                },
                inputsCount: function inputsCount() {
                  return _lodash2['default'].random(2, 2);
                },
                outputsCount: function outputsCount() {
                  return _lodash2['default'].random(3, 5);
                }
              },
              generate: {
                txs: {
                  background: _lodash2['default'].constant(true),
                  timeout: function timeout() {
                    return _lodash2['default'].random(6, 9, true) * 1000;
                  },
                  minInBlock: _lodash2['default'].constant(5)
                },
                blocks: {
                  background: _lodash2['default'].constant(true),
                  timeout: function timeout() {
                    return _lodash2['default'].random(60, 90, true) * 1000;
                  }
                }
              },
              bitcoind: {
                path: function path() {
                  return '../bitcoind/bitcoind-rev-3224936';
                },
                datadir: function datadir() {
                  return _regeneratorRuntime.async(function datadir$(context$4$0) {
                    while (1) switch (context$4$0.prev = context$4$0.next) {
                      case 0:
                        context$4$0.t0 = _lodash2['default'];
                        context$4$0.next = 3;
                        return _regeneratorRuntime.awrap(tmpfs.dirAsync({
                          prefix: 'bitcoind-regtest-',
                          keep: false,
                          unsafeCleanup: true
                        }));

                      case 3:
                        context$4$0.t1 = context$4$0.sent;
                        return context$4$0.abrupt('return', context$4$0.t0.first.call(context$4$0.t0, context$4$0.t1));

                      case 5:
                      case 'end':
                        return context$4$0.stop();
                    }
                  }, null, _this);
                },
                port: function port() {
                  return _lodash2['default'].random(20000, 30000);
                },
                rpcport: function rpcport() {
                  return _lodash2['default'].random(20000, 30000);
                },
                rpcuser: function rpcuser() {
                  return _crypto2['default'].randomBytes(10).toString('hex');
                },
                rpcpassword: function rpcpassword() {
                  return _crypto2['default'].randomBytes(10).toString('hex');
                }
              }
            });

            // process options
            context$3$0.t0 = this._opts.bitcoind.path();
            context$3$0.next = 4;
            return _regeneratorRuntime.awrap(this._opts.bitcoind.datadir());

          case 4:
            context$3$0.t1 = context$3$0.sent;
            context$3$0.t2 = this._opts.bitcoind.port();
            context$3$0.t3 = this._opts.bitcoind.rpcport();
            context$3$0.t4 = this._opts.bitcoind.rpcuser();
            context$3$0.t5 = this._opts.bitcoind.rpcpassword();
            this._processOpts = {
              path: context$3$0.t0,
              datadir: context$3$0.t1,
              port: context$3$0.t2,
              rpcport: context$3$0.t3,
              rpcuser: context$3$0.t4,
              rpcpassword: context$3$0.t5
            };

            // init bitcoind process
            this._process = (0, _child_process.spawn)(this._opts.bitcoind.path(), ['-regtest', '-txindex=1', '-server', '-datadir=' + this._processOpts.datadir, '-port=' + this._processOpts.port, '-rpcport=' + this._processOpts.rpcport, '-rpcuser=' + this._processOpts.rpcuser, '-rpcpassword=' + this._processOpts.rpcpassword, '-printtoconsole'], {
              cwd: __dirname,
              stdio: ['ignore', 'pipe', 'pipe']
            });
            this._process.on('error', function (err) {
              _this.emit('error', err);
            });
            this._process.on('exit', function (code, signal) {
              _this.emit('exit', code, signal);
            });
            this._process.stdout.on('error', function (err) {
              _this.emit('error', err);
            });
            this._process.stdout.on('data', function (data) {
              _this.emit('data', data);
            });
            this._process.stderr.on('error', function (err) {
              _this.emit('error', err);
            });
            this._process.stderr.on('data', function (data) {
              _this.emit('data', data);
            });

            // await running bitcoind
            onErrorExit = undefined;
            context$3$0.prev = 18;
            context$3$0.next = 21;
            return _regeneratorRuntime.awrap(new _Promise(function (resolve, reject) {
              setTimeout(resolve, 1000);

              onErrorExit = function (code, signal) {
                if (code instanceof Error && signal === undefined) {
                  reject(code);
                }

                reject(new Error('Exit with code = ' + code + ' on signal = ' + signal));
              };

              _this._process.on('error', onErrorExit);
              _this._process.on('exit', onErrorExit);
            }));

          case 21:
            context$3$0.prev = 21;

            this._process.removeListener('error', onErrorExit);
            this._process.removeListener('exit', onErrorExit);
            return context$3$0.finish(21);

          case 25:

            // initialize peer
            this._peer = new _bitcoreP2p2['default'].Peer({
              host: '127.0.0.1',
              port: this._processOpts.port,
              network: _bitcoreLib2['default'].Networks.get('regtest')
            });

            this._peer.on('inv', function (message) {
              var names = [];

              var _iteratorNormalCompletion = true;
              var _didIteratorError = false;
              var _iteratorError = undefined;

              try {
                for (var _iterator = _getIterator(message.inventory), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
                  var inv = _step.value;

                  // store inv type name
                  names.push(_bitcoreP2p2['default'].Inventory.TYPE_NAME[inv.type]);

                  // store inv if tx type
                  if (inv.type === _bitcoreP2p2['default'].Inventory.TYPE.TX) {
                    _this.emit('tx', encode(inv.hash));
                  }

                  // emit block if block type
                  if (inv.type === _bitcoreP2p2['default'].Inventory.TYPE.BLOCK) {
                    _this.emit('block', encode(inv.hash));
                  }
                }
              } catch (err) {
                _didIteratorError = true;
                _iteratorError = err;
              } finally {
                try {
                  if (!_iteratorNormalCompletion && _iterator['return']) {
                    _iterator['return']();
                  }
                } finally {
                  if (_didIteratorError) {
                    throw _iteratorError;
                  }
                }
              }
            });

            context$3$0.next = 29;
            return _regeneratorRuntime.awrap(new _Promise(function (resolve) {
              _this._peer.once('ready', resolve);
              _this._peer.connect();
            }));

          case 29:

            // wait wallet initialization
            this._wallet = new _wallet2['default'](this);
            this._wallet.on('error', this.emit.bind(this, 'error'));
            context$3$0.next = 33;
            return _regeneratorRuntime.awrap(this._wallet.ready);

          case 33:
          case 'end':
            return context$3$0.stop();
        }
      }, null, _this2, [[18,, 21, 25]]);
    }).then(function () {
      _this2._ready(null);
    }, function (err) {
      _this2._ready(err);
    });

    // loop for creating new transactions in background
    this.ready.then(function callee$2$0() {
      return _regeneratorRuntime.async(function callee$2$0$(context$3$0) {
        while (1) switch (context$3$0.prev = context$3$0.next) {
          case 0:
            if (!true) {
              context$3$0.next = 14;
              break;
            }

            context$3$0.prev = 1;
            context$3$0.next = 4;
            return _regeneratorRuntime.awrap(_promiseUsefulUtils2['default'].delay(this._opts.generate.txs.timeout()));

          case 4:
            if (!this._opts.generate.txs.background()) {
              context$3$0.next = 7;
              break;
            }

            context$3$0.next = 7;
            return _regeneratorRuntime.awrap(this.generateTxs(1));

          case 7:
            context$3$0.next = 12;
            break;

          case 9:
            context$3$0.prev = 9;
            context$3$0.t0 = context$3$0['catch'](1);

            this.emit(context$3$0.t0);

          case 12:
            context$3$0.next = 0;
            break;

          case 14:
          case 'end':
            return context$3$0.stop();
        }
      }, null, _this2, [[1, 9]]);
    });

    // loop for creating new blocks in background
    this.ready.then(function callee$2$0() {
      return _regeneratorRuntime.async(function callee$2$0$(context$3$0) {
        while (1) switch (context$3$0.prev = context$3$0.next) {
          case 0:
            if (!true) {
              context$3$0.next = 14;
              break;
            }

            context$3$0.prev = 1;
            context$3$0.next = 4;
            return _regeneratorRuntime.awrap(_promiseUsefulUtils2['default'].delay(this._opts.generate.blocks.timeout()));

          case 4:
            if (!this._opts.generate.blocks.background()) {
              context$3$0.next = 7;
              break;
            }

            context$3$0.next = 7;
            return _regeneratorRuntime.awrap(this.generateBlocks(1));

          case 7:
            context$3$0.next = 12;
            break;

          case 9:
            context$3$0.prev = 9;
            context$3$0.t0 = context$3$0['catch'](1);

            this.emit(context$3$0.t0);

          case 12:
            context$3$0.next = 0;
            break;

          case 14:
          case 'end':
            return context$3$0.stop();
        }
      }, null, _this2, [[1, 9]]);
    });
  }

  /**
   * Return value for given option `name`
   * @param {string} name
   * @return {*}
   */

  _createDecoratedClass(Bitcoind, [{
    key: 'getOption',
    value: function getOption(name) {
      return _lodash2['default'].get(this._opts, name);
    }

    /**
     * @param {string} name
     * @param {*}
     */
  }, {
    key: 'setOption',
    value: function setOption(name, value) {
      _lodash2['default'].set(this._opts, name, value);
    }

    /**
     * Return instance of `RpcClient`
     * @return {RpcClient}
     */
  }, {
    key: 'getRpcClient',
    value: function getRpcClient() {
      return new _bitcoindRpcClient2['default']({
        host: '127.0.0.1',
        port: this._processOpts.rpcport,
        user: this._processOpts.rpcuser,
        pass: this._processOpts.rpcpassword
      });
    }

    /**
     * Same as func getRpcClient
     */
  }, {
    key: 'withLock',
    decorators: [(0, _makeConcurrent2['default'])({ concurrency: 1 })],
    value: function withLock(fn) {
      return fn();
    }

    /**
     * Generate `count` blocks
     * @param {number} count
     * @return {Promise.<Array.<string>>}
     */
  }, {
    key: 'generateBlocks',
    decorators: [(0, _makeConcurrent2['default'])({ concurrency: 1 })],
    value: function generateBlocks(count) {
      var hashes, requiredMemPoolSize, memPoolSize;
      return _regeneratorRuntime.async(function generateBlocks$(context$2$0) {
        var _this3 = this;

        while (1) switch (context$2$0.prev = context$2$0.next) {
          case 0:
            context$2$0.next = 2;
            return _regeneratorRuntime.awrap(this.ready);

          case 2:
            hashes = [];

          case 3:
            if (!(count > 0)) {
              context$2$0.next = 15;
              break;
            }

            requiredMemPoolSize = this._opts.generate.txs.minInBlock();
            context$2$0.next = 7;
            return _regeneratorRuntime.awrap(this.rpc.getMemPoolInfo());

          case 7:
            memPoolSize = context$2$0.sent.result.size;
            context$2$0.next = 10;
            return _regeneratorRuntime.awrap(this.generateTxs(requiredMemPoolSize - memPoolSize));

          case 10:
            context$2$0.next = 12;
            return _regeneratorRuntime.awrap(this.withLock(function callee$2$0() {
              var ret;
              return _regeneratorRuntime.async(function callee$2$0$(context$3$0) {
                while (1) switch (context$3$0.prev = context$3$0.next) {
                  case 0:
                    context$3$0.next = 2;
                    return _regeneratorRuntime.awrap(this.rpc.generate(1));

                  case 2:
                    ret = context$3$0.sent;

                    hashes.push(ret.result[0]);

                  case 4:
                  case 'end':
                    return context$3$0.stop();
                }
              }, null, _this3);
            }));

          case 12:
            count -= 1;
            context$2$0.next = 3;
            break;

          case 15:
            return context$2$0.abrupt('return', hashes);

          case 16:
          case 'end':
            return context$2$0.stop();
        }
      }, null, this);
    }

    /**
     * Generate `count` transactions
     * @param {number} count
     * @return {Promise.<Array.<?string>>}
     */
  }, {
    key: 'generateTxs',
    value: function generateTxs(count) {
      return _regeneratorRuntime.async(function generateTxs$(context$2$0) {
        var _this4 = this;

        while (1) switch (context$2$0.prev = context$2$0.next) {
          case 0:
            context$2$0.next = 2;
            return _regeneratorRuntime.awrap(this.ready);

          case 2:
            context$2$0.next = 4;
            return _regeneratorRuntime.awrap(_Promise.all(_lodash2['default'].times(count).map(function () {
              return _this4._wallet.generateTx();
            })));

          case 4:
            return context$2$0.abrupt('return', context$2$0.sent);

          case 5:
          case 'end':
            return context$2$0.stop();
        }
      }, null, this);
    }

    /**
     * @typedef {Object} Bitcoind~PreloadObject
     * @property {string} txId
     * @property {number} outIndex
     * @property {number} value
     * @property {bitcore.Script} script
     * @property {bitcore.PrivateKey} privKey
     */

    /**
     * Return Object with utxo data and with private key (balance is 10btc)
     * @return {Promise.<Bitcoind~PreloadObject>}
     */
  }, {
    key: 'getPreload',
    value: function getPreload() {
      return _regeneratorRuntime.async(function getPreload$(context$2$0) {
        while (1) switch (context$2$0.prev = context$2$0.next) {
          case 0:
            context$2$0.next = 2;
            return _regeneratorRuntime.awrap(this.ready);

          case 2:
            context$2$0.next = 4;
            return _regeneratorRuntime.awrap(this._wallet.getPreload());

          case 4:
            return context$2$0.abrupt('return', context$2$0.sent);

          case 5:
          case 'end':
            return context$2$0.stop();
        }
      }, null, this);
    }

    /**
     * Return instance of `Bitcoind` that have same blockchain
     * @param {Object} [opts]
     * @param {boolean} [opts.connected=true]
     * @return {Promise.<Bitcoind>}
     */
  }, {
    key: 'fork',
    value: function fork(opts) {
      var bopts, other, _ref, _ref2, mhash, ohash;

      return _regeneratorRuntime.async(function fork$(context$2$0) {
        while (1) switch (context$2$0.prev = context$2$0.next) {
          case 0:
            bopts = _lodash2['default'].cloneDeep(this._opts);

            bopts.generate.txs.background = _lodash2['default'].constant(false);
            bopts.generate.blocks.background = _lodash2['default'].constant(false);
            other = new Bitcoind(bopts);
            context$2$0.next = 6;
            return _regeneratorRuntime.awrap(other.ready);

          case 6:
            context$2$0.next = 8;
            return _regeneratorRuntime.awrap(this.connect(other));

          case 8:
            context$2$0.next = 10;
            return _regeneratorRuntime.awrap(this.rpc.getBlockCount());

          case 10:
            context$2$0.t0 = context$2$0.sent.result;

            if (!(context$2$0.t0 > 0)) {
              context$2$0.next = 27;
              break;
            }

            context$2$0.next = 14;
            return _regeneratorRuntime.awrap(other.generateBlocks(1));

          case 14:
            if (!true) {
              context$2$0.next = 27;
              break;
            }

            context$2$0.next = 17;
            return _regeneratorRuntime.awrap(_Promise.all([this.rpc.getBestBlockHash(), other.rpc.getBestBlockHash()]));

          case 17:
            _ref = context$2$0.sent;
            _ref2 = _slicedToArray(_ref, 2);
            mhash = _ref2[0];
            ohash = _ref2[1];

            if (!(mhash.result === ohash.result)) {
              context$2$0.next = 23;
              break;
            }

            return context$2$0.abrupt('break', 27);

          case 23:
            context$2$0.next = 25;
            return _regeneratorRuntime.awrap(_promiseUsefulUtils2['default'].delay(500));

          case 25:
            context$2$0.next = 14;
            break;

          case 27:

            other.setOption('generate.txs.background', this._opts.generate.txs.background);
            other.setOption('generate.blocks.background', this._opts.generate.blocks.background);

            if (Object(opts).connected) {
              context$2$0.next = 32;
              break;
            }

            context$2$0.next = 32;
            return _regeneratorRuntime.awrap(this.disconnect(other));

          case 32:
            return context$2$0.abrupt('return', other);

          case 33:
          case 'end':
            return context$2$0.stop();
        }
      }, null, this);
    }

    /**
     * @param {Bitcoind}
     * @return {Promise}
     */
  }, {
    key: 'connect',
    value: function connect(other) {
      var node;
      return _regeneratorRuntime.async(function connect$(context$2$0) {
        while (1) switch (context$2$0.prev = context$2$0.next) {
          case 0:
            node = '127.0.0.1:' + other._processOpts.port;
            context$2$0.next = 3;
            return _regeneratorRuntime.awrap(this.rpc.addNode(node, 'onetry'));

          case 3:
          case 'end':
            return context$2$0.stop();
        }
      }, null, this);
    }

    /**
     * @param {Bitcoind}
     * @return {Promise}
     */
  }, {
    key: 'disconnect',
    value: function disconnect(other) {
      var node;
      return _regeneratorRuntime.async(function disconnect$(context$2$0) {
        while (1) switch (context$2$0.prev = context$2$0.next) {
          case 0:
            node = '127.0.0.1:' + other._processOpts.port;
            context$2$0.next = 3;
            return _regeneratorRuntime.awrap(this.rpc.disconnectNode(node));

          case 3:
          case 'end':
            return context$2$0.stop();
        }
      }, null, this);
    }

    /**
     * @return {Promise}
     */
  }, {
    key: 'terminate',
    decorators: [(0, _makeConcurrent2['default'])({ concurrency: 1 })],
    value: function terminate() {
      var onError, onExit;
      return _regeneratorRuntime.async(function terminate$(context$2$0) {
        var _this5 = this;

        while (1) switch (context$2$0.prev = context$2$0.next) {
          case 0:
            onError = undefined;
            onExit = undefined;

            if (!(this._process === null)) {
              context$2$0.next = 4;
              break;
            }

            throw new Error('Child process already terminated');

          case 4:
            context$2$0.prev = 4;
            context$2$0.next = 7;
            return _regeneratorRuntime.awrap(new _Promise(function (resolve, reject) {
              onError = reject;
              onExit = function callee$3$0(code, signal) {
                return _regeneratorRuntime.async(function callee$3$0$(context$4$0) {
                  while (1) switch (context$4$0.prev = context$4$0.next) {
                    case 0:
                      if (code === 0 && signal === null) {
                        context$4$0.next = 2;
                        break;
                      }

                      return context$4$0.abrupt('return', reject(new Error('Exit with code = ' + code + ' on signal = ' + signal)));

                    case 2:
                      context$4$0.prev = 2;

                      this._wallet.removeAllListeners();
                      this._peer.removeAllListeners();
                      this._process.removeAllListeners();
                      this._process = null;
                      context$4$0.next = 9;
                      return _regeneratorRuntime.awrap(rimraf(this._processOpts.datadir));

                    case 9:
                      resolve();
                      context$4$0.next = 15;
                      break;

                    case 12:
                      context$4$0.prev = 12;
                      context$4$0.t0 = context$4$0['catch'](2);

                      reject(context$4$0.t0);

                    case 15:
                    case 'end':
                      return context$4$0.stop();
                  }
                }, null, _this5, [[2, 12]]);
              };

              _this5._process.on('error', onError);
              _this5._process.on('exit', onExit);

              _this5._process.kill('SIGTERM');
            }));

          case 7:
            context$2$0.prev = 7;

            if (this._process !== null) {
              this._process.removeListener('error', onError);
              this._process.removeListener('exit', onExit);
            }
            return context$2$0.finish(7);

          case 10:
          case 'end':
            return context$2$0.stop();
        }
      }, null, this, [[4,, 7, 10]]);
    }
  }, {
    key: 'rpc',
    get: function get() {
      return this.getRpcClient();
    }

    /**
     * @param {function} fn
     * @return {Promise}
     */
  }]);

  var _Bitcoind = Bitcoind;
  Bitcoind = (0, _coreDecorators.mixin)(_readyMixin2['default'])(Bitcoind) || Bitcoind;
  return Bitcoind;
})(_events.EventEmitter);

exports['default'] = Bitcoind;
module.exports = exports['default'];
//# sourceMappingURL=data:application/json;base64,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QUFHLENBQUM7Ozs7O0FBSTlELDBCQUFJLENBQUMsT0FBTyxDQUFDLGtCQUFrQixFQUFFLENBQUE7QUFDakMsMEJBQUksQ0FBQyxLQUFLLENBQUMsa0JBQWtCLEVBQUUsQ0FBQTtBQUMvQiwwQkFBSSxDQUFDLFFBQVEsQ0FBQyxrQkFBa0IsRUFBRSxDQUFBO0FBQ2xDLDBCQUFJLENBQUMsUUFBUSxHQUFHLElBQUksQ0FBQTs7dURBQ2QsTUFBTSxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsT0FBTyxDQUFDOzs7QUFDdkMsNkJBQU8sRUFBRSxDQUFBOzs7Ozs7OztBQUVULDRCQUFNLGdCQUFLLENBQUE7Ozs7Ozs7ZUFFZCxDQUFBOztBQUVELHFCQUFLLFFBQVEsQ0FBQyxFQUFFLENBQUMsT0FBTyxFQUFFLE9BQU8sQ0FBQyxDQUFBO0FBQ2xDLHFCQUFLLFFBQVEsQ0FBQyxFQUFFLENBQUMsTUFBTSxFQUFFLE1BQU0sQ0FBQyxDQUFBOztBQUVoQyxxQkFBSyxRQUFRLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFBO2FBQzlCLENBQUM7Ozs7O0FBRUYsZ0JBQUksSUFBSSxDQUFDLFFBQVEsS0FBSyxJQUFJLEVBQUU7QUFDMUIsa0JBQUksQ0FBQyxRQUFRLENBQUMsY0FBYyxDQUFDLE9BQU8sRUFBRSxPQUFPLENBQUMsQ0FBQTtBQUM5QyxrQkFBSSxDQUFDLFFBQVEsQ0FBQyxjQUFjLENBQUMsTUFBTSxFQUFFLE1BQU0sQ0FBQyxDQUFBO2FBQzdDOzs7Ozs7OztLQUVKOzs7U0FsS08sZUFBRztBQUFFLGFBQU8sSUFBSSxDQUFDLFlBQVksRUFBRSxDQUFBO0tBQUU7Ozs7Ozs7O2tCQXJOdEIsUUFBUTtBQUFSLFVBQVEsR0FENUIsbURBQWlCLENBQ0csUUFBUSxLQUFSLFFBQVE7U0FBUixRQUFROzs7cUJBQVIsUUFBUSIsImZpbGUiOiJpbmRleC5qcyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBfIGZyb20gJ2xvZGFzaCdcbmltcG9ydCB7IEV2ZW50RW1pdHRlciB9IGZyb20gJ2V2ZW50cydcbmltcG9ydCB7IG1peGluIH0gZnJvbSAnY29yZS1kZWNvcmF0b3JzJ1xuaW1wb3J0IFJlYWR5TWl4aW4gZnJvbSAncmVhZHktbWl4aW4nXG5pbXBvcnQgX3RtcGZzIGZyb20gJ3RtcCdcbmltcG9ydCBfcmltcmFmIGZyb20gJ3JpbXJhZidcbmltcG9ydCBjcnlwdG8gZnJvbSAnY3J5cHRvJ1xuaW1wb3J0IHsgc3Bhd24gfSBmcm9tICdjaGlsZF9wcm9jZXNzJ1xuaW1wb3J0IGJpdGNvcmUgZnJvbSAnYml0Y29yZS1saWInXG5pbXBvcnQgcDJwIGZyb20gJ2JpdGNvcmUtcDJwJ1xuaW1wb3J0IFJwY0NsaWVudCBmcm9tICdiaXRjb2luZC1ycGMtY2xpZW50J1xuaW1wb3J0IG1ha2VDb25jdXJyZW50IGZyb20gJ21ha2UtY29uY3VycmVudCdcbmltcG9ydCBQVXRpbHMgZnJvbSAncHJvbWlzZS11c2VmdWwtdXRpbHMnXG5cbmltcG9ydCBXYWxsZXQgZnJvbSAnLi93YWxsZXQnXG5cbmxldCB0bXBmcyA9IFBVdGlscy5wcm9taXNpZnlBbGwoX3RtcGZzKVxubGV0IHJpbXJhZiA9IFBVdGlscy5wcm9taXNpZnkoX3JpbXJhZilcblxubGV0IGVuY29kZSA9IChzKSA9PiB7XG4gIHJldHVybiBBcnJheS5wcm90b3R5cGUucmV2ZXJzZS5jYWxsKG5ldyBCdWZmZXIocykpLnRvU3RyaW5nKCdoZXgnKVxufVxuXG4vKipcbiAqIEBldmVudCBCaXRjb2luZCNlcnJvclxuICogQHBhcmFtIHtFcnJvcn0gZXJyXG4gKi9cblxuLyoqXG4gKiBAZXZlbnQgQml0Y29pbmQjZGF0YVxuICogQHBhcmFtIHtzdHJpbmd9IGRhdGFcbiAqL1xuXG4vKipcbiAqIEBldmVudCBCaXRjb2luZCNleGl0XG4gKiBAcGFyYW0ge251bWJlcn0gY29kZVxuICogQHBhcmFtIHtzdHJpbmd9IHNpZ25hbFxuICovXG5cbi8qKlxuICogQGV2ZW50IEJpdGNvaW5kI2Jsb2NrXG4gKiBAcGFyYW0ge3N0cmluZ30gaGFzaFxuICovXG5cbi8qKlxuICogQGV2ZW50IEJpdGNvaW5kI3R4XG4gKiBAcGFyYW0ge3N0cmluZ30gdHhpZFxuICovXG5cbi8qKlxuICogQGNsYXNzIEJpdGNvaW5kXG4gKi9cbkBtaXhpbihSZWFkeU1peGluKVxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgQml0Y29pbmQgZXh0ZW5kcyBFdmVudEVtaXR0ZXIge1xuICAvKipcbiAgICogQGNvbnN0cnVjdG9yXG4gICAqIEBwYXJhbSB7T2JqZWN0fSBbb3B0c11cbiAgICogQHBhcmFtIHtPYmplY3R9IFtvcHRzLndhbGxldF0gV2FsbGV0IG9wdGlvbnNcbiAgICogQHBhcmFtIHtmdW5jdGlvbn0gW29wdHMud2FsbGV0LnByZWxvYWRzUG9vbFNpemU9Xy5jb25zdGFudCgxMCldIFByZWxvYWQgcG9vbCBzaXplXG4gICAqIEBwYXJhbSB7ZnVuY3Rpb259IFtvcHRzLndhbGxldC5rZXlzUG9vbFNpemU9KCkgPT4gXy5yYW5kb20oODAsIDEwMCldXG4gICAqIEBwYXJhbSB7ZnVuY3Rpb259IFtvcHRzLndhbGxldC5uZXdLZXlUaW1lb3V0PSgpID0+IF8ucmFuZG9tKDYwLCA5MCkgKiAxMDAwXVxuICAgKiBAcGFyYW0ge2Z1bmN0aW9ufSBbb3B0cy53YWxsZXQuaW5wdXRzQ291bnQ9KCkgPT4gXy5yYW5kb20oMiwgMyldXG4gICAqIEBwYXJhbSB7ZnVuY3Rpb259IFtvcHRzLndhbGxldC5vdXRwdXRzQ291bnQ9KCkgPT4gXy5yYW5kb20oMywgNSldXG4gICAqIEBwYXJhbSB7T2JqZWN0fSBbb3B0cy5nZW5lcmF0ZV0gR2VuZXJhdGUgb3B0aW9uc1xuICAgKiBAcGFyYW0ge09iamVjdH0gW29wdHMuZ2VuZXJhdGUudHhzXVxuICAgKiBAcGFyYW0ge2Z1bmN0aW9ufSBbb3B0cy5nZW5lcmF0ZS50eHMuYmFja2dyb3VuZD1fLmNvbnN0YW50KHRydWUpXVxuICAgKiBAcGFyYW0ge2Z1bmN0aW9ufSBbb3B0cy5nZW5lcmF0ZS50eHMudGltZW91dD0oKSA9PiBfLnJhbmRvbSg2LCA5LCB0cnVlKSAqIDEwMDBdXG4gICAqIEBwYXJhbSB7ZnVuY3Rpb259IFtvcHRzLmdlbmVyYXRlLnR4cy5taW5JbkJsb2NrPV8uY29uc3RhbnQoNSldXG4gICAqIEBwYXJhbSB7T2JqZWN0fSBbb3B0cy5nZW5lcmF0ZS5ibG9ja3NdXG4gICAqIEBwYXJhbSB7ZnVuY3Rpb259IFtvcHRzLmdlbmVyYXRlLmJsb2Nrcy5iYWNrZ3JvdW5kPV8uY29uc3RhbnQodHJ1ZSldXG4gICAqIEBwYXJhbSB7ZnVuY3Rpb259IFtvcHRzLmdlbmVyYXRlLmJsb2Nrcy50aW1lb3V0PSgpID0+IF8ucmFuZG9tKDYwLCA5MCwgdHJ1ZSkgKiAxMDAwXVxuICAgKiBAcGFyYW0ge09iamVjdH0gW29wdHMuYml0Y29pbmRdXG4gICAqIEBwYXJhbSB7ZnVuY3Rpb259IFtvcHRzLmJpdGNvaW5kLnBhdGg9KCkgPT4gJy4uL2JpdGNvaW5kL2JpdGNvaW5kLXJldi0zMjI0OTM2J11cbiAgICogQHBhcmFtIHtmdW5jdGlvbn0gW29wdHMuYml0Y29pbmQuZGF0YWRpcj1hc3luYyAoKSA9PiBfLmZpcnN0KHRtcGZzLmRpcih7cHJlZml4OiAnYml0Y29pbmQtcmVndGVzdC0nfSkpXVxuICAgKiBAcGFyYW0ge2Z1bmN0aW9ufSBbb3B0cy5iaXRjb2luZC5wb3J0PSgpID0+IF8ucmFuZG9tKDIwMDAwLCAzMDAwMCldXG4gICAqIEBwYXJhbSB7ZnVuY3Rpb259IFtvcHRzLmJpdGNvaW5kLnJwY3BvcnQ9KCkgPT4gXy5yYW5kb20oMjAwMDAsIDMwMDAwKV1cbiAgICogQHBhcmFtIHtmdW5jdGlvbn0gW29wdHMuYml0Y29pbmQucnBjdXNlcj0oKSA9PiBjcnlwdG8ucmFuZG9tQnl0ZXMoMTApLnRvU3RyaW5nKCdoZXgnKV1cbiAgICogQHBhcmFtIHtmdW5jdGlvbn0gW29wdHMuYml0Y29pbmQucnBjcGFzc3dvcmQ9KCkgPT4gY3J5cHRvLnJhbmRvbUJ5dGVzKDEwKS50b1N0cmluZygnaGV4JyldXG4gICAqL1xuICBjb25zdHJ1Y3RvciAob3B0cykge1xuICAgIHN1cGVyKClcblxuICAgIFBVdGlscy50cnkoYXN5bmMgKCkgPT4ge1xuICAgICAgdGhpcy5fb3B0cyA9IF8uZGVmYXVsdHNEZWVwKF8uY2xvbmVEZWVwKG9wdHMpIHx8IHt9LCB7XG4gICAgICAgIHdhbGxldDoge1xuICAgICAgICAgIHByZWxvYWRzUG9vbFNpemU6IF8uY29uc3RhbnQoMTApLFxuICAgICAgICAgIGtleXNQb29sU2l6ZTogKCkgPT4gXy5yYW5kb20oODAsIDEwMCksXG4gICAgICAgICAgbmV3S2V5VGltZW91dDogKCkgPT4gXy5yYW5kb20oNjAsIDkwKSAqIDEwMDAsXG4gICAgICAgICAgaW5wdXRzQ291bnQ6ICgpID0+IF8ucmFuZG9tKDIsIDIpLFxuICAgICAgICAgIG91dHB1dHNDb3VudDogKCkgPT4gXy5yYW5kb20oMywgNSlcbiAgICAgICAgfSxcbiAgICAgICAgZ2VuZXJhdGU6IHtcbiAgICAgICAgICB0eHM6IHtcbiAgICAgICAgICAgIGJhY2tncm91bmQ6IF8uY29uc3RhbnQodHJ1ZSksXG4gICAgICAgICAgICB0aW1lb3V0OiAoKSA9PiBfLnJhbmRvbSg2LCA5LCB0cnVlKSAqIDEwMDAsXG4gICAgICAgICAgICBtaW5JbkJsb2NrOiBfLmNvbnN0YW50KDUpXG4gICAgICAgICAgfSxcbiAgICAgICAgICBibG9ja3M6IHtcbiAgICAgICAgICAgIGJhY2tncm91bmQ6IF8uY29uc3RhbnQodHJ1ZSksXG4gICAgICAgICAgICB0aW1lb3V0OiAoKSA9PiBfLnJhbmRvbSg2MCwgOTAsIHRydWUpICogMTAwMFxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAgYml0Y29pbmQ6IHtcbiAgICAgICAgICBwYXRoOiAoKSA9PiAnLi4vYml0Y29pbmQvYml0Y29pbmQtcmV2LTMyMjQ5MzYnLFxuICAgICAgICAgIGRhdGFkaXI6IGFzeW5jICgpID0+IF8uZmlyc3QoYXdhaXQgdG1wZnMuZGlyQXN5bmMoe1xuICAgICAgICAgICAgcHJlZml4OiAnYml0Y29pbmQtcmVndGVzdC0nLFxuICAgICAgICAgICAga2VlcDogZmFsc2UsXG4gICAgICAgICAgICB1bnNhZmVDbGVhbnVwOiB0cnVlXG4gICAgICAgICAgfSkpLFxuICAgICAgICAgIHBvcnQ6ICgpID0+IF8ucmFuZG9tKDIwMDAwLCAzMDAwMCksXG4gICAgICAgICAgcnBjcG9ydDogKCkgPT4gXy5yYW5kb20oMjAwMDAsIDMwMDAwKSxcbiAgICAgICAgICBycGN1c2VyOiAoKSA9PiBjcnlwdG8ucmFuZG9tQnl0ZXMoMTApLnRvU3RyaW5nKCdoZXgnKSxcbiAgICAgICAgICBycGNwYXNzd29yZDogKCkgPT4gY3J5cHRvLnJhbmRvbUJ5dGVzKDEwKS50b1N0cmluZygnaGV4JylcbiAgICAgICAgfVxuICAgICAgfSlcblxuICAgICAgLy8gcHJvY2VzcyBvcHRpb25zXG4gICAgICB0aGlzLl9wcm9jZXNzT3B0cyA9IHtcbiAgICAgICAgcGF0aDogdGhpcy5fb3B0cy5iaXRjb2luZC5wYXRoKCksXG4gICAgICAgIGRhdGFkaXI6IGF3YWl0IHRoaXMuX29wdHMuYml0Y29pbmQuZGF0YWRpcigpLFxuICAgICAgICBwb3J0OiB0aGlzLl9vcHRzLmJpdGNvaW5kLnBvcnQoKSxcbiAgICAgICAgcnBjcG9ydDogdGhpcy5fb3B0cy5iaXRjb2luZC5ycGNwb3J0KCksXG4gICAgICAgIHJwY3VzZXI6IHRoaXMuX29wdHMuYml0Y29pbmQucnBjdXNlcigpLFxuICAgICAgICBycGNwYXNzd29yZDogdGhpcy5fb3B0cy5iaXRjb2luZC5ycGNwYXNzd29yZCgpXG4gICAgICB9XG5cbiAgICAgIC8vIGluaXQgYml0Y29pbmQgcHJvY2Vzc1xuICAgICAgdGhpcy5fcHJvY2VzcyA9IHNwYXduKHRoaXMuX29wdHMuYml0Y29pbmQucGF0aCgpLCBbXG4gICAgICAgIGAtcmVndGVzdGAsXG4gICAgICAgIGAtdHhpbmRleD0xYCxcbiAgICAgICAgYC1zZXJ2ZXJgLFxuICAgICAgICBgLWRhdGFkaXI9JHt0aGlzLl9wcm9jZXNzT3B0cy5kYXRhZGlyfWAsXG4gICAgICAgIGAtcG9ydD0ke3RoaXMuX3Byb2Nlc3NPcHRzLnBvcnR9YCxcbiAgICAgICAgYC1ycGNwb3J0PSR7dGhpcy5fcHJvY2Vzc09wdHMucnBjcG9ydH1gLFxuICAgICAgICBgLXJwY3VzZXI9JHt0aGlzLl9wcm9jZXNzT3B0cy5ycGN1c2VyfWAsXG4gICAgICAgIGAtcnBjcGFzc3dvcmQ9JHt0aGlzLl9wcm9jZXNzT3B0cy5ycGNwYXNzd29yZH1gLFxuICAgICAgICBgLXByaW50dG9jb25zb2xlYFxuICAgICAgXSwge1xuICAgICAgICBjd2Q6IF9fZGlybmFtZSxcbiAgICAgICAgc3RkaW86IFsnaWdub3JlJywgJ3BpcGUnLCAncGlwZSddXG4gICAgICB9KVxuICAgICAgdGhpcy5fcHJvY2Vzcy5vbignZXJyb3InLCAoZXJyKSA9PiB7IHRoaXMuZW1pdCgnZXJyb3InLCBlcnIpIH0pXG4gICAgICB0aGlzLl9wcm9jZXNzLm9uKCdleGl0JywgKGNvZGUsIHNpZ25hbCkgPT4geyB0aGlzLmVtaXQoJ2V4aXQnLCBjb2RlLCBzaWduYWwpIH0pXG4gICAgICB0aGlzLl9wcm9jZXNzLnN0ZG91dC5vbignZXJyb3InLCAoZXJyKSA9PiB7IHRoaXMuZW1pdCgnZXJyb3InLCBlcnIpIH0pXG4gICAgICB0aGlzLl9wcm9jZXNzLnN0ZG91dC5vbignZGF0YScsIChkYXRhKSA9PiB7IHRoaXMuZW1pdCgnZGF0YScsIGRhdGEpIH0pXG4gICAgICB0aGlzLl9wcm9jZXNzLnN0ZGVyci5vbignZXJyb3InLCAoZXJyKSA9PiB7IHRoaXMuZW1pdCgnZXJyb3InLCBlcnIpIH0pXG4gICAgICB0aGlzLl9wcm9jZXNzLnN0ZGVyci5vbignZGF0YScsIChkYXRhKSA9PiB7IHRoaXMuZW1pdCgnZGF0YScsIGRhdGEpIH0pXG5cbiAgICAgIC8vIGF3YWl0IHJ1bm5pbmcgYml0Y29pbmRcbiAgICAgIGxldCBvbkVycm9yRXhpdFxuICAgICAgdHJ5IHtcbiAgICAgICAgYXdhaXQgbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICAgIHNldFRpbWVvdXQocmVzb2x2ZSwgMTAwMClcblxuICAgICAgICAgIG9uRXJyb3JFeGl0ID0gKGNvZGUsIHNpZ25hbCkgPT4ge1xuICAgICAgICAgICAgaWYgKGNvZGUgaW5zdGFuY2VvZiBFcnJvciAmJiBzaWduYWwgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgICByZWplY3QoY29kZSlcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcmVqZWN0KG5ldyBFcnJvcihgRXhpdCB3aXRoIGNvZGUgPSAke2NvZGV9IG9uIHNpZ25hbCA9ICR7c2lnbmFsfWApKVxuICAgICAgICAgIH1cblxuICAgICAgICAgIHRoaXMuX3Byb2Nlc3Mub24oJ2Vycm9yJywgb25FcnJvckV4aXQpXG4gICAgICAgICAgdGhpcy5fcHJvY2Vzcy5vbignZXhpdCcsIG9uRXJyb3JFeGl0KVxuICAgICAgICB9KVxuICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgdGhpcy5fcHJvY2Vzcy5yZW1vdmVMaXN0ZW5lcignZXJyb3InLCBvbkVycm9yRXhpdClcbiAgICAgICAgdGhpcy5fcHJvY2Vzcy5yZW1vdmVMaXN0ZW5lcignZXhpdCcsIG9uRXJyb3JFeGl0KVxuICAgICAgfVxuXG4gICAgICAvLyBpbml0aWFsaXplIHBlZXJcbiAgICAgIHRoaXMuX3BlZXIgPSBuZXcgcDJwLlBlZXIoe1xuICAgICAgICBob3N0OiAnMTI3LjAuMC4xJyxcbiAgICAgICAgcG9ydDogdGhpcy5fcHJvY2Vzc09wdHMucG9ydCxcbiAgICAgICAgbmV0d29yazogYml0Y29yZS5OZXR3b3Jrcy5nZXQoJ3JlZ3Rlc3QnKVxuICAgICAgfSlcblxuICAgICAgdGhpcy5fcGVlci5vbignaW52JywgKG1lc3NhZ2UpID0+IHtcbiAgICAgICAgbGV0IG5hbWVzID0gW11cblxuICAgICAgICBmb3IgKGxldCBpbnYgb2YgbWVzc2FnZS5pbnZlbnRvcnkpIHtcbiAgICAgICAgICAvLyBzdG9yZSBpbnYgdHlwZSBuYW1lXG4gICAgICAgICAgbmFtZXMucHVzaChwMnAuSW52ZW50b3J5LlRZUEVfTkFNRVtpbnYudHlwZV0pXG5cbiAgICAgICAgICAvLyBzdG9yZSBpbnYgaWYgdHggdHlwZVxuICAgICAgICAgIGlmIChpbnYudHlwZSA9PT0gcDJwLkludmVudG9yeS5UWVBFLlRYKSB7XG4gICAgICAgICAgICB0aGlzLmVtaXQoJ3R4JywgZW5jb2RlKGludi5oYXNoKSlcbiAgICAgICAgICB9XG5cbiAgICAgICAgICAvLyBlbWl0IGJsb2NrIGlmIGJsb2NrIHR5cGVcbiAgICAgICAgICBpZiAoaW52LnR5cGUgPT09IHAycC5JbnZlbnRvcnkuVFlQRS5CTE9DSykge1xuICAgICAgICAgICAgdGhpcy5lbWl0KCdibG9jaycsIGVuY29kZShpbnYuaGFzaCkpXG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9KVxuXG4gICAgICBhd2FpdCBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4ge1xuICAgICAgICB0aGlzLl9wZWVyLm9uY2UoJ3JlYWR5JywgcmVzb2x2ZSlcbiAgICAgICAgdGhpcy5fcGVlci5jb25uZWN0KClcbiAgICAgIH0pXG5cbiAgICAgIC8vIHdhaXQgd2FsbGV0IGluaXRpYWxpemF0aW9uXG4gICAgICB0aGlzLl93YWxsZXQgPSBuZXcgV2FsbGV0KHRoaXMpXG4gICAgICB0aGlzLl93YWxsZXQub24oJ2Vycm9yJywgdGhpcy5lbWl0LmJpbmQodGhpcywgJ2Vycm9yJykpXG4gICAgICBhd2FpdCB0aGlzLl93YWxsZXQucmVhZHlcbiAgICB9KVxuICAgIC50aGVuKCgpID0+IHsgdGhpcy5fcmVhZHkobnVsbCkgfSwgKGVycikgPT4geyB0aGlzLl9yZWFkeShlcnIpIH0pXG5cbiAgICAvLyBsb29wIGZvciBjcmVhdGluZyBuZXcgdHJhbnNhY3Rpb25zIGluIGJhY2tncm91bmRcbiAgICB0aGlzLnJlYWR5LnRoZW4oYXN5bmMgKCkgPT4ge1xuICAgICAgd2hpbGUgKHRydWUpIHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBhd2FpdCBQVXRpbHMuZGVsYXkodGhpcy5fb3B0cy5nZW5lcmF0ZS50eHMudGltZW91dCgpKVxuICAgICAgICAgIGlmICh0aGlzLl9vcHRzLmdlbmVyYXRlLnR4cy5iYWNrZ3JvdW5kKCkpIHtcbiAgICAgICAgICAgIGF3YWl0IHRoaXMuZ2VuZXJhdGVUeHMoMSlcbiAgICAgICAgICB9XG4gICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgIHRoaXMuZW1pdChlcnIpXG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9KVxuXG4gICAgLy8gbG9vcCBmb3IgY3JlYXRpbmcgbmV3IGJsb2NrcyBpbiBiYWNrZ3JvdW5kXG4gICAgdGhpcy5yZWFkeS50aGVuKGFzeW5jICgpID0+IHtcbiAgICAgIHdoaWxlICh0cnVlKSB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgYXdhaXQgUFV0aWxzLmRlbGF5KHRoaXMuX29wdHMuZ2VuZXJhdGUuYmxvY2tzLnRpbWVvdXQoKSlcbiAgICAgICAgICBpZiAodGhpcy5fb3B0cy5nZW5lcmF0ZS5ibG9ja3MuYmFja2dyb3VuZCgpKSB7XG4gICAgICAgICAgICBhd2FpdCB0aGlzLmdlbmVyYXRlQmxvY2tzKDEpXG4gICAgICAgICAgfVxuICAgICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgICB0aGlzLmVtaXQoZXJyKVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfSlcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm4gdmFsdWUgZm9yIGdpdmVuIG9wdGlvbiBgbmFtZWBcbiAgICogQHBhcmFtIHtzdHJpbmd9IG5hbWVcbiAgICogQHJldHVybiB7Kn1cbiAgICovXG4gIGdldE9wdGlvbiAobmFtZSkgeyByZXR1cm4gXy5nZXQodGhpcy5fb3B0cywgbmFtZSkgfVxuXG4gIC8qKlxuICAgKiBAcGFyYW0ge3N0cmluZ30gbmFtZVxuICAgKiBAcGFyYW0geyp9XG4gICAqL1xuICBzZXRPcHRpb24gKG5hbWUsIHZhbHVlKSB7IF8uc2V0KHRoaXMuX29wdHMsIG5hbWUsIHZhbHVlKSB9XG5cbiAgLyoqXG4gICAqIFJldHVybiBpbnN0YW5jZSBvZiBgUnBjQ2xpZW50YFxuICAgKiBAcmV0dXJuIHtScGNDbGllbnR9XG4gICAqL1xuICBnZXRScGNDbGllbnQgKCkge1xuICAgIHJldHVybiBuZXcgUnBjQ2xpZW50KHtcbiAgICAgIGhvc3Q6ICcxMjcuMC4wLjEnLFxuICAgICAgcG9ydDogdGhpcy5fcHJvY2Vzc09wdHMucnBjcG9ydCxcbiAgICAgIHVzZXI6IHRoaXMuX3Byb2Nlc3NPcHRzLnJwY3VzZXIsXG4gICAgICBwYXNzOiB0aGlzLl9wcm9jZXNzT3B0cy5ycGNwYXNzd29yZFxuICAgIH0pXG4gIH1cblxuICAvKipcbiAgICogU2FtZSBhcyBmdW5jIGdldFJwY0NsaWVudFxuICAgKi9cbiAgZ2V0IHJwYyAoKSB7IHJldHVybiB0aGlzLmdldFJwY0NsaWVudCgpIH1cblxuICAvKipcbiAgICogQHBhcmFtIHtmdW5jdGlvbn0gZm5cbiAgICogQHJldHVybiB7UHJvbWlzZX1cbiAgICovXG4gIEBtYWtlQ29uY3VycmVudCh7Y29uY3VycmVuY3k6IDF9KVxuICB3aXRoTG9jayAoZm4pIHsgcmV0dXJuIGZuKCkgfVxuXG4gIC8qKlxuICAgKiBHZW5lcmF0ZSBgY291bnRgIGJsb2Nrc1xuICAgKiBAcGFyYW0ge251bWJlcn0gY291bnRcbiAgICogQHJldHVybiB7UHJvbWlzZS48QXJyYXkuPHN0cmluZz4+fVxuICAgKi9cbiAgQG1ha2VDb25jdXJyZW50KHtjb25jdXJyZW5jeTogMX0pXG4gIGFzeW5jIGdlbmVyYXRlQmxvY2tzIChjb3VudCkge1xuICAgIGF3YWl0IHRoaXMucmVhZHlcblxuICAgIGxldCBoYXNoZXMgPSBbXVxuICAgIGZvciAoOyBjb3VudCA+IDA7IGNvdW50IC09IDEpIHtcbiAgICAgIGxldCByZXF1aXJlZE1lbVBvb2xTaXplID0gdGhpcy5fb3B0cy5nZW5lcmF0ZS50eHMubWluSW5CbG9jaygpXG4gICAgICBsZXQgbWVtUG9vbFNpemUgPSAoYXdhaXQgdGhpcy5ycGMuZ2V0TWVtUG9vbEluZm8oKSkucmVzdWx0LnNpemVcbiAgICAgIGF3YWl0IHRoaXMuZ2VuZXJhdGVUeHMocmVxdWlyZWRNZW1Qb29sU2l6ZSAtIG1lbVBvb2xTaXplKVxuICAgICAgYXdhaXQgdGhpcy53aXRoTG9jayhhc3luYyAoKSA9PiB7XG4gICAgICAgIGxldCByZXQgPSBhd2FpdCB0aGlzLnJwYy5nZW5lcmF0ZSgxKVxuICAgICAgICBoYXNoZXMucHVzaChyZXQucmVzdWx0WzBdKVxuICAgICAgfSlcbiAgICB9XG5cbiAgICByZXR1cm4gaGFzaGVzXG4gIH1cblxuICAvKipcbiAgICogR2VuZXJhdGUgYGNvdW50YCB0cmFuc2FjdGlvbnNcbiAgICogQHBhcmFtIHtudW1iZXJ9IGNvdW50XG4gICAqIEByZXR1cm4ge1Byb21pc2UuPEFycmF5Ljw/c3RyaW5nPj59XG4gICAqL1xuICBhc3luYyBnZW5lcmF0ZVR4cyAoY291bnQpIHtcbiAgICBhd2FpdCB0aGlzLnJlYWR5XG4gICAgcmV0dXJuIGF3YWl0KiBfLnRpbWVzKGNvdW50KS5tYXAoKCkgPT4ge1xuICAgICAgcmV0dXJuIHRoaXMuX3dhbGxldC5nZW5lcmF0ZVR4KClcbiAgICB9KVxuICB9XG5cbiAgLyoqXG4gICAqIEB0eXBlZGVmIHtPYmplY3R9IEJpdGNvaW5kflByZWxvYWRPYmplY3RcbiAgICogQHByb3BlcnR5IHtzdHJpbmd9IHR4SWRcbiAgICogQHByb3BlcnR5IHtudW1iZXJ9IG91dEluZGV4XG4gICAqIEBwcm9wZXJ0eSB7bnVtYmVyfSB2YWx1ZVxuICAgKiBAcHJvcGVydHkge2JpdGNvcmUuU2NyaXB0fSBzY3JpcHRcbiAgICogQHByb3BlcnR5IHtiaXRjb3JlLlByaXZhdGVLZXl9IHByaXZLZXlcbiAgICovXG5cbiAgLyoqXG4gICAqIFJldHVybiBPYmplY3Qgd2l0aCB1dHhvIGRhdGEgYW5kIHdpdGggcHJpdmF0ZSBrZXkgKGJhbGFuY2UgaXMgMTBidGMpXG4gICAqIEByZXR1cm4ge1Byb21pc2UuPEJpdGNvaW5kflByZWxvYWRPYmplY3Q+fVxuICAgKi9cbiAgYXN5bmMgZ2V0UHJlbG9hZCAoKSB7XG4gICAgYXdhaXQgdGhpcy5yZWFkeVxuICAgIHJldHVybiBhd2FpdCB0aGlzLl93YWxsZXQuZ2V0UHJlbG9hZCgpXG4gIH1cblxuICAvKipcbiAgICogUmV0dXJuIGluc3RhbmNlIG9mIGBCaXRjb2luZGAgdGhhdCBoYXZlIHNhbWUgYmxvY2tjaGFpblxuICAgKiBAcGFyYW0ge09iamVjdH0gW29wdHNdXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gW29wdHMuY29ubmVjdGVkPXRydWVdXG4gICAqIEByZXR1cm4ge1Byb21pc2UuPEJpdGNvaW5kPn1cbiAgICovXG4gIGFzeW5jIGZvcmsgKG9wdHMpIHtcbiAgICBsZXQgYm9wdHMgPSBfLmNsb25lRGVlcCh0aGlzLl9vcHRzKVxuICAgIGJvcHRzLmdlbmVyYXRlLnR4cy5iYWNrZ3JvdW5kID0gXy5jb25zdGFudChmYWxzZSlcbiAgICBib3B0cy5nZW5lcmF0ZS5ibG9ja3MuYmFja2dyb3VuZCA9IF8uY29uc3RhbnQoZmFsc2UpXG4gICAgbGV0IG90aGVyID0gbmV3IEJpdGNvaW5kKGJvcHRzKVxuXG4gICAgYXdhaXQgb3RoZXIucmVhZHlcbiAgICBhd2FpdCB0aGlzLmNvbm5lY3Qob3RoZXIpXG5cbiAgICBpZiAoKGF3YWl0IHRoaXMucnBjLmdldEJsb2NrQ291bnQoKSkucmVzdWx0ID4gMCkge1xuICAgICAgYXdhaXQgb3RoZXIuZ2VuZXJhdGVCbG9ja3MoMSlcblxuICAgICAgd2hpbGUgKHRydWUpIHtcbiAgICAgICAgbGV0IFttaGFzaCwgb2hhc2hdID0gYXdhaXQqIFt0aGlzLnJwYy5nZXRCZXN0QmxvY2tIYXNoKCksIG90aGVyLnJwYy5nZXRCZXN0QmxvY2tIYXNoKCldXG4gICAgICAgIGlmIChtaGFzaC5yZXN1bHQgPT09IG9oYXNoLnJlc3VsdCkge1xuICAgICAgICAgIGJyZWFrXG4gICAgICAgIH1cblxuICAgICAgICBhd2FpdCBQVXRpbHMuZGVsYXkoNTAwKVxuICAgICAgfVxuICAgIH1cblxuICAgIG90aGVyLnNldE9wdGlvbignZ2VuZXJhdGUudHhzLmJhY2tncm91bmQnLCB0aGlzLl9vcHRzLmdlbmVyYXRlLnR4cy5iYWNrZ3JvdW5kKVxuICAgIG90aGVyLnNldE9wdGlvbignZ2VuZXJhdGUuYmxvY2tzLmJhY2tncm91bmQnLCB0aGlzLl9vcHRzLmdlbmVyYXRlLmJsb2Nrcy5iYWNrZ3JvdW5kKVxuXG4gICAgaWYgKCFPYmplY3Qob3B0cykuY29ubmVjdGVkKSB7XG4gICAgICBhd2FpdCB0aGlzLmRpc2Nvbm5lY3Qob3RoZXIpXG4gICAgfVxuXG4gICAgcmV0dXJuIG90aGVyXG4gIH1cblxuICAvKipcbiAgICogQHBhcmFtIHtCaXRjb2luZH1cbiAgICogQHJldHVybiB7UHJvbWlzZX1cbiAgICovXG4gIGFzeW5jIGNvbm5lY3QgKG90aGVyKSB7XG4gICAgbGV0IG5vZGUgPSBgMTI3LjAuMC4xOiR7b3RoZXIuX3Byb2Nlc3NPcHRzLnBvcnR9YFxuICAgIGF3YWl0IHRoaXMucnBjLmFkZE5vZGUobm9kZSwgJ29uZXRyeScpXG4gIH1cblxuICAvKipcbiAgICogQHBhcmFtIHtCaXRjb2luZH1cbiAgICogQHJldHVybiB7UHJvbWlzZX1cbiAgICovXG4gIGFzeW5jIGRpc2Nvbm5lY3QgKG90aGVyKSB7XG4gICAgbGV0IG5vZGUgPSBgMTI3LjAuMC4xOiR7b3RoZXIuX3Byb2Nlc3NPcHRzLnBvcnR9YFxuICAgIGF3YWl0IHRoaXMucnBjLmRpc2Nvbm5lY3ROb2RlKG5vZGUpXG4gIH1cblxuICAvKipcbiAgICogQHJldHVybiB7UHJvbWlzZX1cbiAgICovXG4gIEBtYWtlQ29uY3VycmVudCh7Y29uY3VycmVuY3k6IDF9KVxuICBhc3luYyB0ZXJtaW5hdGUgKCkge1xuICAgIGxldCBvbkVycm9yXG4gICAgbGV0IG9uRXhpdFxuXG4gICAgaWYgKHRoaXMuX3Byb2Nlc3MgPT09IG51bGwpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignQ2hpbGQgcHJvY2VzcyBhbHJlYWR5IHRlcm1pbmF0ZWQnKVxuICAgIH1cblxuICAgIHRyeSB7XG4gICAgICBhd2FpdCBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICAgIG9uRXJyb3IgPSByZWplY3RcbiAgICAgICAgb25FeGl0ID0gYXN5bmMgKGNvZGUsIHNpZ25hbCkgPT4ge1xuICAgICAgICAgIGlmICghKGNvZGUgPT09IDAgJiYgc2lnbmFsID09PSBudWxsKSkge1xuICAgICAgICAgICAgcmV0dXJuIHJlamVjdChcbiAgICAgICAgICAgICAgbmV3IEVycm9yKGBFeGl0IHdpdGggY29kZSA9ICR7Y29kZX0gb24gc2lnbmFsID0gJHtzaWduYWx9YCkpXG4gICAgICAgICAgfVxuXG4gICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIHRoaXMuX3dhbGxldC5yZW1vdmVBbGxMaXN0ZW5lcnMoKVxuICAgICAgICAgICAgdGhpcy5fcGVlci5yZW1vdmVBbGxMaXN0ZW5lcnMoKVxuICAgICAgICAgICAgdGhpcy5fcHJvY2Vzcy5yZW1vdmVBbGxMaXN0ZW5lcnMoKVxuICAgICAgICAgICAgdGhpcy5fcHJvY2VzcyA9IG51bGxcbiAgICAgICAgICAgIGF3YWl0IHJpbXJhZih0aGlzLl9wcm9jZXNzT3B0cy5kYXRhZGlyKVxuICAgICAgICAgICAgcmVzb2x2ZSgpXG4gICAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgICByZWplY3QoZXJyKVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuX3Byb2Nlc3Mub24oJ2Vycm9yJywgb25FcnJvcilcbiAgICAgICAgdGhpcy5fcHJvY2Vzcy5vbignZXhpdCcsIG9uRXhpdClcblxuICAgICAgICB0aGlzLl9wcm9jZXNzLmtpbGwoJ1NJR1RFUk0nKVxuICAgICAgfSlcbiAgICB9IGZpbmFsbHkge1xuICAgICAgaWYgKHRoaXMuX3Byb2Nlc3MgIT09IG51bGwpIHtcbiAgICAgICAgdGhpcy5fcHJvY2Vzcy5yZW1vdmVMaXN0ZW5lcignZXJyb3InLCBvbkVycm9yKVxuICAgICAgICB0aGlzLl9wcm9jZXNzLnJlbW92ZUxpc3RlbmVyKCdleGl0Jywgb25FeGl0KVxuICAgICAgfVxuICAgIH1cbiAgfVxufVxuIl19