UNPKG

bitcoind-regtest

Version:

Run bitcoind in regtest mode for your own blockchain

479 lines (374 loc) 29.9 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 _regeneratorRuntime = require('babel-runtime/regenerator')['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 _bitcoreLib = require('bitcore-lib'); var _bitcoreLib2 = _interopRequireDefault(_bitcoreLib); var _makeConcurrent = require('make-concurrent'); var _makeConcurrent2 = _interopRequireDefault(_makeConcurrent); var _promiseUsefulUtils = require('promise-useful-utils'); var _promiseUsefulUtils2 = _interopRequireDefault(_promiseUsefulUtils); _bitcoreLib2['default'].Networks.add({ name: 'regtest', alias: 'regtest', pubkeyhash: 0x6f, privatekey: 0xef, scripthash: 0xc4, xpubkey: 0x043587cf, xprivkey: 0x04358394, networkMagic: 0xFABFB5DA, port: 18444, dnsSeeds: [] }); /** * @event Wallet#error * @param {Error} error /** * @class Wallet */ var Wallet = (function (_EventEmitter) { _inherits(Wallet, _EventEmitter); /** * @constructor * @param {Bitcoind} bitcoind */ function Wallet(bitcoind) { var _this = this; _classCallCheck(this, _Wallet); _get(Object.getPrototypeOf(_Wallet.prototype), 'constructor', this).call(this); this._bitcoind = bitcoind; this._preloadsPool = []; // create addresses _promiseUsefulUtils2['default']['try'](function callee$2$0() { var poolSize, ret; return _regeneratorRuntime.async(function callee$2$0$(context$3$0) { while (1) switch (context$3$0.prev = context$3$0.next) { case 0: poolSize = this._getWalletOption('keysPoolSize'); context$3$0.next = 3; return _regeneratorRuntime.awrap(this._bitcoind.rpc.getAddressesByAccount('')); case 3: ret = context$3$0.sent; context$3$0.next = 6; return _regeneratorRuntime.awrap(this._bitcoind.rpc.batch(_lodash2['default'].times(poolSize - ret.result.length).map(function () { return { method: 'getnewaddress', params: [''] }; }))); case 6: case 'end': return context$3$0.stop(); } }, null, _this); }).then(function () { _this._ready(null); }, function (err) { _this._ready(err); }); // loop for creating new addresses 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 = 13; break; } context$3$0.prev = 1; context$3$0.next = 4; return _regeneratorRuntime.awrap(_promiseUsefulUtils2['default'].delay(this._getWalletOption('newKeyTimeout'))); case 4: context$3$0.next = 6; return _regeneratorRuntime.awrap(this._bitcoind.rpc.getNewAddress('')); case 6: context$3$0.next = 11; break; case 8: context$3$0.prev = 8; context$3$0.t0 = context$3$0['catch'](1); this.emit(context$3$0.t0); case 11: context$3$0.next = 0; break; case 13: case 'end': return context$3$0.stop(); } }, null, _this, [[1, 8]]); }); // update preloads on new block this.ready.then(function () { _this._bitcoind.on('block', _this._updatePreloads.bind(_this)); }); } /** * @param {string} name * @return {*} */ _createDecoratedClass(Wallet, [{ key: '_getWalletOption', value: function _getWalletOption(name) { return this._bitcoind.getOption('wallet.' + name)(); } /** * @return {Promise.<Bitcoind~PreloadObject>} */ }, { key: 'getPreload', decorators: [(0, _makeConcurrent2['default'])({ concurrency: 1 })], value: function getPreload() { var preload; return _regeneratorRuntime.async(function getPreload$(context$2$0) { while (1) switch (context$2$0.prev = context$2$0.next) { case 0: if (!(this._preloadsPool.length === 0)) { context$2$0.next = 5; break; } context$2$0.next = 3; return _regeneratorRuntime.awrap(_promiseUsefulUtils2['default'].delay(50)); case 3: context$2$0.next = 0; break; case 5: preload = this._preloadsPool.shift(); this._updatePreloads(); return context$2$0.abrupt('return', preload); case 8: case 'end': return context$2$0.stop(); } }, null, this); } /** * @param {Array.<Object>} utxo * @param {Array.<Object>} outs * @param {boolean} [change=false] * @return {Promise.<bitcore.Transaction>} */ }, { key: '_createTx', value: function _createTx(utxo, outs) { var change = arguments.length <= 2 || arguments[2] === undefined ? false : arguments[2]; var tx, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, out, _ret, changeAddress, ret, privKeys; return _regeneratorRuntime.async(function _createTx$(context$2$0) { while (1) switch (context$2$0.prev = context$2$0.next) { case 0: tx = _bitcoreLib2['default'].Transaction().from(utxo.map(function (row) { return { txId: row.txid, outputIndex: row.vout, satoshis: Math.floor(row.amount * 1e8), script: row.scriptPubKey }; })); _iteratorNormalCompletion = true; _didIteratorError = false; _iteratorError = undefined; context$2$0.prev = 4; for (_iterator = _getIterator(outs); !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { out = _step.value; tx = tx.to(out.address, out.amount); } context$2$0.next = 12; break; case 8: context$2$0.prev = 8; context$2$0.t0 = context$2$0['catch'](4); _didIteratorError = true; _iteratorError = context$2$0.t0; case 12: context$2$0.prev = 12; context$2$0.prev = 13; if (!_iteratorNormalCompletion && _iterator['return']) { _iterator['return'](); } case 15: context$2$0.prev = 15; if (!_didIteratorError) { context$2$0.next = 18; break; } throw _iteratorError; case 18: return context$2$0.finish(15); case 19: return context$2$0.finish(12); case 20: if (!change) { context$2$0.next = 26; break; } context$2$0.next = 23; return _regeneratorRuntime.awrap(this._bitcoind.rpc.getAddressesByAccount('')); case 23: _ret = context$2$0.sent; changeAddress = _lodash2['default'].sample(_ret.result); tx = tx.change(changeAddress); case 26: context$2$0.next = 28; return _regeneratorRuntime.awrap(this._bitcoind.rpc.batch(utxo.map(function (row) { return { method: 'dumpprivkey', params: [row.address] }; }))); case 28: ret = context$2$0.sent; privKeys = _lodash2['default'].pluck(ret, 'result').map(function (raw) { return _bitcoreLib2['default'].PrivateKey(raw); }); return context$2$0.abrupt('return', tx.sign(privKeys)); case 31: case 'end': return context$2$0.stop(); } }, null, this, [[4, 8, 12, 20], [13,, 15, 19]]); } /** * @private * @return {Promise} */ }, { key: '_updatePreloads', value: function _updatePreloads() { var _this2 = this; return this._bitcoind.withLock(function callee$2$0() { var ret, utxo, preloadPrivKey, tx; 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.prev = 0; if (!(this._preloadsPool.length >= this._getWalletOption('preloadsPoolSize'))) { context$3$0.next = 3; break; } return context$3$0.abrupt('return'); case 3: context$3$0.next = 5; return _regeneratorRuntime.awrap(this._bitcoind.rpc.listUnspent(0)); case 5: ret = context$3$0.sent; utxo = _lodash2['default'].chain(ret.result).sortBy('amount').reverse().reduce(function (result, row) { if (result.total < 10) { result.list.push(row); result.total += row.amount; } return result; }, { list: [], total: 0 }).value(); if (!(utxo.total < 10)) { context$3$0.next = 9; break; } return context$3$0.abrupt('return'); case 9: preloadPrivKey = _bitcoreLib2['default'].PrivateKey.fromRandom('regtest'); context$3$0.next = 12; return _regeneratorRuntime.awrap(this._createTx(utxo.list, [{ address: preloadPrivKey.toAddress(), amount: 10 * 1e8 }], true)); case 12: tx = context$3$0.sent; context$3$0.next = 15; return _regeneratorRuntime.awrap(this._bitcoind.rpc.sendRawTransaction(tx.toString())); case 15: ret = context$3$0.sent; if (!(ret.result !== tx.id)) { context$3$0.next = 18; break; } throw new Error(JSON.stringify(ret)); case 18: this._preloadsPool.push({ txId: tx.id, outIndex: 0, value: 10 * 1e8, script: _bitcoreLib2['default'].Script.buildPublicKeyHashOut(preloadPrivKey.toAddress()), privKey: preloadPrivKey }); setImmediate(this._updatePreloads.bind(this)); context$3$0.next = 25; break; case 22: context$3$0.prev = 22; context$3$0.t0 = context$3$0['catch'](0); this.emit('error', context$3$0.t0); case 25: case 'end': return context$3$0.stop(); } }, null, _this2, [[0, 22]]); }); } /** * @return {Promise.<?string>} */ }, { key: 'generateTx', value: function generateTx() { var _this3 = this; return this._bitcoind.withLock(function callee$2$0() { var ret, utxo, utxoTotalAmount, addresses, values, valuesSum, outs, tx; 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._bitcoind.rpc.listUnspent(0)); case 2: ret = context$3$0.sent; utxo = _lodash2['default'].sample(ret.result, this._getWalletOption('inputsCount')); utxoTotalAmount = _lodash2['default'].sum(_lodash2['default'].pluck(utxo, 'amount')) * 1e8 - 1e4; if (!(utxo.length === 0 || utxoTotalAmount < 1e7)) { context$3$0.next = 7; break; } return context$3$0.abrupt('return', null); case 7: context$3$0.next = 9; return _regeneratorRuntime.awrap(this._bitcoind.rpc.getAddressesByAccount('')); case 9: ret = context$3$0.sent; addresses = _lodash2['default'].sample(ret.result, this._getWalletOption('outputsCount')); values = _lodash2['default'].times(addresses.length).map(function () { return _lodash2['default'].random(0, 1, true); }); valuesSum = _lodash2['default'].sum(values); outs = addresses.map(function (address, index) { return { address: address, amount: Math.floor(utxoTotalAmount * values[index] / valuesSum) }; }); context$3$0.next = 16; return _regeneratorRuntime.awrap(this._createTx(utxo, outs)); case 16: tx = context$3$0.sent; context$3$0.next = 19; return _regeneratorRuntime.awrap(this._bitcoind.rpc.sendRawTransaction(tx.toString())); case 19: ret = context$3$0.sent; if (!(ret.result !== tx.id)) { context$3$0.next = 22; break; } throw new Error(JSON.stringify(ret)); case 22: return context$3$0.abrupt('return', tx.id); case 23: case 'end': return context$3$0.stop(); } }, null, _this3); }); } }]); var _Wallet = Wallet; Wallet = (0, _coreDecorators.mixin)(_readyMixin2['default'])(Wallet) || Wallet; return Wallet; })(_events.EventEmitter); exports['default'] = Wallet; module.exports = exports['default']; //# sourceMappingURL=data:application/json;base64,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Q0FBQyxLQUFLLENBQUMsR0FBRyxTQUFTLENBQUMsRUFBQyxDQUFBO2VBQzNGLENBQUM7OytDQUVhLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQzs7O0FBQXJDLGdCQUFFOzsrQ0FFTSxJQUFJLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyxrQkFBa0IsQ0FBQyxFQUFFLENBQUMsUUFBUSxFQUFFLENBQUM7OztBQUFoRSxpQkFBRzs7b0JBQ0MsR0FBRyxDQUFDLE1BQU0sS0FBSyxFQUFFLENBQUMsRUFBRSxDQUFBOzs7OztvQkFDaEIsSUFBSSxLQUFLLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxHQUFHLENBQUMsQ0FBQzs7O2tEQUcvQixFQUFFLENBQUMsRUFBRTs7Ozs7OztPQUNiLENBQUMsQ0FBQTtLQUNIOzs7Z0JBckxrQixNQUFNO0FBQU4sUUFBTSxHQUQxQixtREFBaUIsQ0FDRyxNQUFNLEtBQU4sTUFBTTtTQUFOLE1BQU07OztxQkFBTixNQUFNIiwiZmlsZSI6IndhbGxldC5qcyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBfIGZyb20gJ2xvZGFzaCdcbmltcG9ydCB7IEV2ZW50RW1pdHRlciB9IGZyb20gJ2V2ZW50cydcbmltcG9ydCB7IG1peGluIH0gZnJvbSAnY29yZS1kZWNvcmF0b3JzJ1xuaW1wb3J0IFJlYWR5TWl4aW4gZnJvbSAncmVhZHktbWl4aW4nXG5pbXBvcnQgYml0Y29yZSBmcm9tICdiaXRjb3JlLWxpYidcbmltcG9ydCBtYWtlQ29uY3VycmVudCBmcm9tICdtYWtlLWNvbmN1cnJlbnQnXG5pbXBvcnQgUFV0aWxzIGZyb20gJ3Byb21pc2UtdXNlZnVsLXV0aWxzJ1xuXG5iaXRjb3JlLk5ldHdvcmtzLmFkZCh7XG4gIG5hbWU6ICdyZWd0ZXN0JyxcbiAgYWxpYXM6ICdyZWd0ZXN0JyxcbiAgcHVia2V5aGFzaDogMHg2ZixcbiAgcHJpdmF0ZWtleTogMHhlZixcbiAgc2NyaXB0aGFzaDogMHhjNCxcbiAgeHB1YmtleTogMHgwNDM1ODdjZixcbiAgeHByaXZrZXk6IDB4MDQzNTgzOTQsXG4gIG5ldHdvcmtNYWdpYzogMHhGQUJGQjVEQSxcbiAgcG9ydDogMTg0NDQsXG4gIGRuc1NlZWRzOiBbXVxufSlcblxuLyoqXG4gKiBAZXZlbnQgV2FsbGV0I2Vycm9yXG4gKiBAcGFyYW0ge0Vycm9yfSBlcnJvclxuXG4vKipcbiAqIEBjbGFzcyBXYWxsZXRcbiAqL1xuQG1peGluKFJlYWR5TWl4aW4pXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBXYWxsZXQgZXh0ZW5kcyBFdmVudEVtaXR0ZXIge1xuICAvKipcbiAgICogQGNvbnN0cnVjdG9yXG4gICAqIEBwYXJhbSB7Qml0Y29pbmR9IGJpdGNvaW5kXG4gICAqL1xuICBjb25zdHJ1Y3RvciAoYml0Y29pbmQpIHtcbiAgICBzdXBlcigpXG5cbiAgICB0aGlzLl9iaXRjb2luZCA9IGJpdGNvaW5kXG4gICAgdGhpcy5fcHJlbG9hZHNQb29sID0gW11cblxuICAgIC8vIGNyZWF0ZSBhZGRyZXNzZXNcbiAgICBQVXRpbHMudHJ5KGFzeW5jICgpID0+IHtcbiAgICAgIGxldCBwb29sU2l6ZSA9IHRoaXMuX2dldFdhbGxldE9wdGlvbigna2V5c1Bvb2xTaXplJylcbiAgICAgIGxldCByZXQgPSBhd2FpdCB0aGlzLl9iaXRjb2luZC5ycGMuZ2V0QWRkcmVzc2VzQnlBY2NvdW50KCcnKVxuXG4gICAgICBhd2FpdCB0aGlzLl9iaXRjb2luZC5ycGMuYmF0Y2goXy50aW1lcyhwb29sU2l6ZSAtIHJldC5yZXN1bHQubGVuZ3RoKS5tYXAoKCkgPT4ge1xuICAgICAgICByZXR1cm4ge21ldGhvZDogJ2dldG5ld2FkZHJlc3MnLCBwYXJhbXM6IFsnJ119XG4gICAgICB9KSlcbiAgICB9KVxuICAgIC50aGVuKCgpID0+IHsgdGhpcy5fcmVhZHkobnVsbCkgfSwgKGVycikgPT4geyB0aGlzLl9yZWFkeShlcnIpIH0pXG5cbiAgICAvLyBsb29wIGZvciBjcmVhdGluZyBuZXcgYWRkcmVzc2VzXG4gICAgdGhpcy5yZWFkeS50aGVuKGFzeW5jICgpID0+IHtcbiAgICAgIHdoaWxlICh0cnVlKSB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgYXdhaXQgUFV0aWxzLmRlbGF5KHRoaXMuX2dldFdhbGxldE9wdGlvbignbmV3S2V5VGltZW91dCcpKVxuICAgICAgICAgIGF3YWl0IHRoaXMuX2JpdGNvaW5kLnJwYy5nZXROZXdBZGRyZXNzKCcnKVxuICAgICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgICB0aGlzLmVtaXQoZXJyKVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfSlcblxuICAgIC8vIHVwZGF0ZSBwcmVsb2FkcyBvbiBuZXcgYmxvY2tcbiAgICB0aGlzLnJlYWR5LnRoZW4oKCkgPT4ge1xuICAgICAgdGhpcy5fYml0Y29pbmQub24oJ2Jsb2NrJywgOjp0aGlzLl91cGRhdGVQcmVsb2FkcylcbiAgICB9KVxuICB9XG5cbiAgLyoqXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBuYW1lXG4gICAqIEByZXR1cm4geyp9XG4gICAqL1xuICBfZ2V0V2FsbGV0T3B0aW9uIChuYW1lKSB7XG4gICAgcmV0dXJuIHRoaXMuX2JpdGNvaW5kLmdldE9wdGlvbihgd2FsbGV0LiR7bmFtZX1gKSgpXG4gIH1cblxuICAvKipcbiAgICogQHJldHVybiB7UHJvbWlzZS48Qml0Y29pbmR+UHJlbG9hZE9iamVjdD59XG4gICAqL1xuICBAbWFrZUNvbmN1cnJlbnQoe2NvbmN1cnJlbmN5OiAxfSlcbiAgYXN5bmMgZ2V0UHJlbG9hZCAoKSB7XG4gICAgd2hpbGUgKHRoaXMuX3ByZWxvYWRzUG9vbC5sZW5ndGggPT09IDApIHtcbiAgICAgIGF3YWl0IFBVdGlscy5kZWxheSg1MClcbiAgICB9XG5cbiAgICBsZXQgcHJlbG9hZCA9IHRoaXMuX3ByZWxvYWRzUG9vbC5zaGlmdCgpXG4gICAgdGhpcy5fdXBkYXRlUHJlbG9hZHMoKVxuICAgIHJldHVybiBwcmVsb2FkXG4gIH1cblxuICAvKipcbiAgICogQHBhcmFtIHtBcnJheS48T2JqZWN0Pn0gdXR4b1xuICAgKiBAcGFyYW0ge0FycmF5LjxPYmplY3Q+fSBvdXRzXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gW2NoYW5nZT1mYWxzZV1cbiAgICogQHJldHVybiB7UHJvbWlzZS48Yml0Y29yZS5UcmFuc2FjdGlvbj59XG4gICAqL1xuICBhc3luYyBfY3JlYXRlVHggKHV0eG8sIG91dHMsIGNoYW5nZSA9IGZhbHNlKSB7XG4gICAgbGV0IHR4ID0gYml0Y29yZS5UcmFuc2FjdGlvbigpXG4gICAgICAuZnJvbSh1dHhvLm1hcCgocm93KSA9PiB7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgdHhJZDogcm93LnR4aWQsXG4gICAgICAgICAgb3V0cHV0SW5kZXg6IHJvdy52b3V0LFxuICAgICAgICAgIHNhdG9zaGlzOiBNYXRoLmZsb29yKHJvdy5hbW91bnQgKiAxZTgpLFxuICAgICAgICAgIHNjcmlwdDogcm93LnNjcmlwdFB1YktleVxuICAgICAgICB9XG4gICAgICB9KSlcblxuICAgIGZvciAobGV0IG91dCBvZiBvdXRzKSB7XG4gICAgICB0eCA9IHR4LnRvKG91dC5hZGRyZXNzLCBvdXQuYW1vdW50KVxuICAgIH1cblxuICAgIGlmIChjaGFuZ2UpIHtcbiAgICAgIGxldCByZXQgPSBhd2FpdCB0aGlzLl9iaXRjb2luZC5ycGMuZ2V0QWRkcmVzc2VzQnlBY2NvdW50KCcnKVxuICAgICAgbGV0IGNoYW5nZUFkZHJlc3MgPSBfLnNhbXBsZShyZXQucmVzdWx0KVxuICAgICAgdHggPSB0eC5jaGFuZ2UoY2hhbmdlQWRkcmVzcylcbiAgICB9XG5cbiAgICBsZXQgcmV0ID0gYXdhaXQgdGhpcy5fYml0Y29pbmQucnBjLmJhdGNoKHV0eG8ubWFwKChyb3cpID0+IHtcbiAgICAgIHJldHVybiB7bWV0aG9kOiAnZHVtcHByaXZrZXknLCBwYXJhbXM6IFtyb3cuYWRkcmVzc119XG4gICAgfSkpXG4gICAgbGV0IHByaXZLZXlzID0gXy5wbHVjayhyZXQsICdyZXN1bHQnKS5tYXAoKHJhdykgPT4ge1xuICAgICAgcmV0dXJuIGJpdGNvcmUuUHJpdmF0ZUtleShyYXcpXG4gICAgfSlcblxuICAgIHJldHVybiB0eC5zaWduKHByaXZLZXlzKVxuICB9XG5cbiAgLyoqXG4gICAqIEBwcml2YXRlXG4gICAqIEByZXR1cm4ge1Byb21pc2V9XG4gICAqL1xuICBfdXBkYXRlUHJlbG9hZHMgKCkge1xuICAgIHJldHVybiB0aGlzLl9iaXRjb2luZC53aXRoTG9jayhhc3luYyAoKSA9PiB7XG4gICAgICB0cnkge1xuICAgICAgICBpZiAodGhpcy5fcHJlbG9hZHNQb29sLmxlbmd0aCA+PSB0aGlzLl9nZXRXYWxsZXRPcHRpb24oJ3ByZWxvYWRzUG9vbFNpemUnKSkge1xuICAgICAgICAgIHJldHVyblxuICAgICAgICB9XG5cbiAgICAgICAgbGV0IHJldCA9IGF3YWl0IHRoaXMuX2JpdGNvaW5kLnJwYy5saXN0VW5zcGVudCgwKVxuICAgICAgICBsZXQgdXR4byA9IF8uY2hhaW4ocmV0LnJlc3VsdClcbiAgICAgICAgICAuc29ydEJ5KCdhbW91bnQnKVxuICAgICAgICAgIC5yZXZlcnNlKClcbiAgICAgICAgICAucmVkdWNlKChyZXN1bHQsIHJvdykgPT4ge1xuICAgICAgICAgICAgaWYgKHJlc3VsdC50b3RhbCA8IDEwKSB7XG4gICAgICAgICAgICAgIHJlc3VsdC5saXN0LnB1c2gocm93KVxuICAgICAgICAgICAgICByZXN1bHQudG90YWwgKz0gcm93LmFtb3VudFxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gcmVzdWx0XG4gICAgICAgICAgfSwge2xpc3Q6IFtdLCB0b3RhbDogMH0pXG4gICAgICAgICAgLnZhbHVlKClcblxuICAgICAgICBpZiAodXR4by50b3RhbCA8IDEwKSB7XG4gICAgICAgICAgcmV0dXJuXG4gICAgICAgIH1cblxuICAgICAgICBsZXQgcHJlbG9hZFByaXZLZXkgPSBiaXRjb3JlLlByaXZhdGVLZXkuZnJvbVJhbmRvbSgncmVndGVzdCcpXG4gICAgICAgIGxldCB0eCA9IGF3YWl0IHRoaXMuX2NyZWF0ZVR4KFxuICAgICAgICAgIHV0eG8ubGlzdCwgW3thZGRyZXNzOiBwcmVsb2FkUHJpdktleS50b0FkZHJlc3MoKSwgYW1vdW50OiAxMCAqIDFlOH1dLCB0cnVlKVxuXG4gICAgICAgIHJldCA9IGF3YWl0IHRoaXMuX2JpdGNvaW5kLnJwYy5zZW5kUmF3VHJhbnNhY3Rpb24odHgudG9TdHJpbmcoKSlcbiAgICAgICAgaWYgKHJldC5yZXN1bHQgIT09IHR4LmlkKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKEpTT04uc3RyaW5naWZ5KHJldCkpXG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLl9wcmVsb2Fkc1Bvb2wucHVzaCh7XG4gICAgICAgICAgdHhJZDogdHguaWQsXG4gICAgICAgICAgb3V0SW5kZXg6IDAsXG4gICAgICAgICAgdmFsdWU6IDEwICogMWU4LFxuICAgICAgICAgIHNjcmlwdDogYml0Y29yZS5TY3JpcHQuYnVpbGRQdWJsaWNLZXlIYXNoT3V0KHByZWxvYWRQcml2S2V5LnRvQWRkcmVzcygpKSxcbiAgICAgICAgICBwcml2S2V5OiBwcmVsb2FkUHJpdktleVxuICAgICAgICB9KVxuXG4gICAgICAgIHNldEltbWVkaWF0ZSg6OnRoaXMuX3VwZGF0ZVByZWxvYWRzKVxuICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgIHRoaXMuZW1pdCgnZXJyb3InLCBlcnIpXG4gICAgICB9XG4gICAgfSlcbiAgfVxuXG4gIC8qKlxuICAgKiBAcmV0dXJuIHtQcm9taXNlLjw/c3RyaW5nPn1cbiAgICovXG4gIGdlbmVyYXRlVHggKCkge1xuICAgIHJldHVybiB0aGlzLl9iaXRjb2luZC53aXRoTG9jayhhc3luYyAoKSA9PiB7XG4gICAgICBsZXQgcmV0ID0gYXdhaXQgdGhpcy5fYml0Y29pbmQucnBjLmxpc3RVbnNwZW50KDApXG4gICAgICBsZXQgdXR4byA9IF8uc2FtcGxlKHJldC5yZXN1bHQsIHRoaXMuX2dldFdhbGxldE9wdGlvbignaW5wdXRzQ291bnQnKSlcbiAgICAgIGxldCB1dHhvVG90YWxBbW91bnQgPSBfLnN1bShfLnBsdWNrKHV0eG8sICdhbW91bnQnKSkgKiAxZTggLSAxZTRcbiAgICAgIGlmICh1dHhvLmxlbmd0aCA9PT0gMCB8fCB1dHhvVG90YWxBbW91bnQgPCAxZTcpIHtcbiAgICAgICAgcmV0dXJuIG51bGxcbiAgICAgIH1cblxuICAgICAgcmV0ID0gYXdhaXQgdGhpcy5fYml0Y29pbmQucnBjLmdldEFkZHJlc3Nlc0J5QWNjb3VudCgnJylcbiAgICAgIGxldCBhZGRyZXNzZXMgPSBfLnNhbXBsZShyZXQucmVzdWx0LCB0aGlzLl9nZXRXYWxsZXRPcHRpb24oJ291dHB1dHNDb3VudCcpKVxuICAgICAgbGV0IHZhbHVlcyA9IF8udGltZXMoYWRkcmVzc2VzLmxlbmd0aCkubWFwKCgpID0+IF8ucmFuZG9tKDAsIDEsIHRydWUpKVxuICAgICAgbGV0IHZhbHVlc1N1bSA9IF8uc3VtKHZhbHVlcylcbiAgICAgIGxldCBvdXRzID0gYWRkcmVzc2VzLm1hcCgoYWRkcmVzcywgaW5kZXgpID0+IHtcbiAgICAgICAgcmV0dXJuIHthZGRyZXNzOiBhZGRyZXNzLCBhbW91bnQ6IE1hdGguZmxvb3IodXR4b1RvdGFsQW1vdW50ICogdmFsdWVzW2luZGV4XSAvIHZhbHVlc1N1bSl9XG4gICAgICB9KVxuXG4gICAgICBsZXQgdHggPSBhd2FpdCB0aGlzLl9jcmVhdGVUeCh1dHhvLCBvdXRzKVxuXG4gICAgICByZXQgPSBhd2FpdCB0aGlzLl9iaXRjb2luZC5ycGMuc2VuZFJhd1RyYW5zYWN0aW9uKHR4LnRvU3RyaW5nKCkpXG4gICAgICBpZiAocmV0LnJlc3VsdCAhPT0gdHguaWQpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKEpTT04uc3RyaW5naWZ5KHJldCkpXG4gICAgICB9XG5cbiAgICAgIHJldHVybiB0eC5pZFxuICAgIH0pXG4gIH1cbn1cbiJdfQ==