bitcoind-regtest
Version:
Run bitcoind in regtest mode for your own blockchain
479 lines (374 loc) • 29.9 kB
JavaScript
;
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==